/* SPDX-License-Identifier: GPL-2.0 */
/* IP Virtual Server
* data structure and functionality definitions
*/
#ifndef _NET_IP_VS_H
#define _NET_IP_VS_H
#include <linux/ip_vs.h> /* definitions shared with userland */
#include <asm/types.h> /* for __uXX types */
#include <linux/list.h> /* for struct list_head */
#include <linux/spinlock.h> /* for struct rwlock_t */
#include <linux/atomic.h> /* for struct atomic_t */
#include <linux/refcount.h> /* for struct refcount_t */
#include <linux/compiler.h>
#include <linux/timer.h>
#include <linux/bug.h>
#include <net/checksum.h>
#include <linux/netfilter.h> /* for union nf_inet_addr */
#include <linux/ip.h>
#include <linux/ipv6.h> /* for struct ipv6hdr */
#include <net/ipv6.h>
#if IS_ENABLED(CONFIG_IP_VS_IPV6)
#include <linux/netfilter_ipv6/ip6_tables.h>
#endif
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
#include <net/netfilter/nf_conntrack.h>
#endif
#include <net/net_namespace.h> /* Netw namespace */
#define IP_VS_HDR_INVERSE 1
#define IP_VS_HDR_ICMP 2
/* Generic access of ipvs struct */
static inline struct netns_ipvs *net_ipvs(struct net* net)
{
return net->ipvs;
}
/* This one needed for single_open_net since net is stored directly in
* private not as a struct i.e. seq_file_net can't be used.
*/
static inline struct net *seq_file_single_net(struct seq_file *seq)
{
#ifdef CONFIG_NET_NS
return (struct net *)seq->private;
#else
return &init_net;
#endif
}
/* Connections' size value needed by ip_vs_ctl.c */
extern int ip_vs_conn_tab_size;
struct ip_vs_iphdr {
int hdr_flags; /* ipvs flags */
__u32 off; /* Where IP or IPv4 header starts */
__u32 len; /* IPv4 simply where L4 starts
* IPv6 where L4 Transport Header starts */
__u16 fragoffs; /* IPv6 fragment offset, 0 if first frag (or not frag)*/
__s16 protocol;
__s32 flags;
union nf_inet_addr saddr;
union nf_inet_addr daddr;
};
static inline void *frag_safe_skb_hp(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
return skb_header_pointer(skb, offset, len, buffer);
}
/* This function handles filling *ip_vs_iphdr, both for IPv4 and IPv6.
* IPv6 requires some extra work, as finding proper header position,
* depend on the IPv6 extension headers.
*/
static inline int
ip_vs_fill_iph_skb_off(int af, const struct sk_buff *skb, int offset,
int hdr_flags, struct ip_vs_iphdr *iphdr)
{
iphdr->hdr_flags = hdr_flags;
iphdr->off = offset;
#ifdef CONFIG_IP_VS_IPV6
if (af == AF_INET6) {
struct ipv6hdr _iph;
const struct ipv6hdr *iph = skb_header_pointer(
skb, offset, sizeof(_iph), &_iph);
if (!iph)
return 0;
iphdr->saddr.in6 = iph->saddr;
iphdr->daddr.in6 = iph->daddr;
/* ipv6_find_hdr() updates len, flags */
iphdr->len = offset;
iphdr->flags = 0;
iphdr->protocol = ipv6_find_hdr(skb, &iphdr->len, -1,
&iphdr->fragoffs,
&iphdr->flags);
if (iphdr->protocol < 0)
return 0;
} else
#endif
{
struct iphdr _iph;
const struct iphdr *iph = skb_header_pointer(
skb, offset, sizeof(_iph), &_iph);
if (!iph)
return 0;
iphdr->len = offset + iph->ihl * 4;
iphdr->fragoffs = 0;
iphdr->protocol = iph->protocol;
iphdr->saddr.ip = iph->saddr;
iphdr->daddr.ip = iph->daddr;
}
return 1;
}
static inline int
ip_vs_fill_iph_skb_icmp(int af, const struct sk_buff *skb, int offset,
bool inverse, struct ip_vs_iphdr *iphdr)
{
int hdr_flags = IP_VS_HDR_ICMP;
if (inverse)
hdr_flags |= IP_VS_HDR_INVERSE;
return ip_
|