ipvs: optimize dst usage for real server
Currently when forwarding requests to real servers we use dst_lock and atomic operations when cloning the dst_cache value. As the dst_cache value does not change most of the time it is better to use RCU and to lock dst_lock only when we need to replace the obsoleted dst. For this to work we keep dst_cache in new structure protected by RCU. For packets to remote real servers we will use noref version of dst_cache, it will be valid while we are in RCU read-side critical section because now dst_release for replaced dsts will be invoked after the grace period. Packets to local real servers that are passed to local stack with NF_ACCEPT need a dst clone. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off by: Hans Schillstrom <hans@schillstrom.com> Signed-off-by: Simon Horman <horms@verge.net.au>
This commit is contained in:
parent
4115ded131
commit
026ace060d
@ -724,6 +724,13 @@ struct ip_vs_service {
|
|||||||
struct ip_vs_pe *pe;
|
struct ip_vs_pe *pe;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Information for cached dst */
|
||||||
|
struct ip_vs_dest_dst {
|
||||||
|
struct dst_entry *dst_cache; /* destination cache entry */
|
||||||
|
u32 dst_cookie;
|
||||||
|
union nf_inet_addr dst_saddr;
|
||||||
|
struct rcu_head rcu_head;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The real server destination forwarding entry
|
* The real server destination forwarding entry
|
||||||
@ -752,9 +759,7 @@ struct ip_vs_dest {
|
|||||||
|
|
||||||
/* for destination cache */
|
/* for destination cache */
|
||||||
spinlock_t dst_lock; /* lock of dst_cache */
|
spinlock_t dst_lock; /* lock of dst_cache */
|
||||||
struct dst_entry *dst_cache; /* destination cache entry */
|
struct ip_vs_dest_dst __rcu *dest_dst; /* cached dst info */
|
||||||
u32 dst_cookie;
|
|
||||||
union nf_inet_addr dst_saddr;
|
|
||||||
|
|
||||||
/* for virtual service */
|
/* for virtual service */
|
||||||
struct ip_vs_service *svc; /* service it belongs to */
|
struct ip_vs_service *svc; /* service it belongs to */
|
||||||
@ -1427,6 +1432,7 @@ extern int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
extern int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
extern int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
struct ip_vs_protocol *pp, int offset,
|
struct ip_vs_protocol *pp, int offset,
|
||||||
unsigned int hooknum, struct ip_vs_iphdr *iph);
|
unsigned int hooknum, struct ip_vs_iphdr *iph);
|
||||||
|
extern void ip_vs_dest_dst_rcu_free(struct rcu_head *head);
|
||||||
|
|
||||||
#ifdef CONFIG_IP_VS_IPV6
|
#ifdef CONFIG_IP_VS_IPV6
|
||||||
extern int ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
extern int ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
||||||
|
@ -1395,10 +1395,13 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum)
|
|||||||
goto ignore_ipip;
|
goto ignore_ipip;
|
||||||
/* Prefer the resulting PMTU */
|
/* Prefer the resulting PMTU */
|
||||||
if (dest) {
|
if (dest) {
|
||||||
spin_lock(&dest->dst_lock);
|
struct ip_vs_dest_dst *dest_dst;
|
||||||
if (dest->dst_cache)
|
|
||||||
mtu = dst_mtu(dest->dst_cache);
|
rcu_read_lock();
|
||||||
spin_unlock(&dest->dst_lock);
|
dest_dst = rcu_dereference(dest->dest_dst);
|
||||||
|
if (dest_dst)
|
||||||
|
mtu = dst_mtu(dest_dst->dst_cache);
|
||||||
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
if (mtu > 68 + sizeof(struct iphdr))
|
if (mtu > 68 + sizeof(struct iphdr))
|
||||||
mtu -= sizeof(struct iphdr);
|
mtu -= sizeof(struct iphdr);
|
||||||
|
@ -641,15 +641,26 @@ struct ip_vs_dest *ip_vs_find_dest(struct net *net, int af,
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release dst_cache for dest in user context */
|
void ip_vs_dest_dst_rcu_free(struct rcu_head *head)
|
||||||
|
{
|
||||||
|
struct ip_vs_dest_dst *dest_dst = container_of(head,
|
||||||
|
struct ip_vs_dest_dst,
|
||||||
|
rcu_head);
|
||||||
|
|
||||||
|
dst_release(dest_dst->dst_cache);
|
||||||
|
kfree(dest_dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release dest_dst and dst_cache for dest in user context */
|
||||||
static void __ip_vs_dst_cache_reset(struct ip_vs_dest *dest)
|
static void __ip_vs_dst_cache_reset(struct ip_vs_dest *dest)
|
||||||
{
|
{
|
||||||
struct dst_entry *old_dst;
|
struct ip_vs_dest_dst *old;
|
||||||
|
|
||||||
old_dst = dest->dst_cache;
|
old = rcu_dereference_protected(dest->dest_dst, 1);
|
||||||
dest->dst_cache = NULL;
|
if (old) {
|
||||||
dst_release(old_dst);
|
RCU_INIT_POINTER(dest->dest_dst, NULL);
|
||||||
dest->dst_saddr.ip = 0;
|
call_rcu(&old->rcu_head, ip_vs_dest_dst_rcu_free);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1513,7 +1524,7 @@ static inline void
|
|||||||
ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
|
ip_vs_forget_dev(struct ip_vs_dest *dest, struct net_device *dev)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&dest->dst_lock);
|
spin_lock_bh(&dest->dst_lock);
|
||||||
if (dest->dst_cache && dest->dst_cache->dev == dev) {
|
if (dest->dest_dst && dest->dest_dst->dst_cache->dev == dev) {
|
||||||
IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n",
|
IP_VS_DBG_BUF(3, "Reset dev:%s dest %s:%u ,dest->refcnt=%d\n",
|
||||||
dev->name,
|
dev->name,
|
||||||
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
IP_VS_DBG_ADDR(dest->af, &dest->addr),
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
* - not all connections have destination server, for example,
|
* - not all connections have destination server, for example,
|
||||||
* connections in backup server when fwmark is used
|
* connections in backup server when fwmark is used
|
||||||
* - bypass connections use daddr from packet
|
* - bypass connections use daddr from packet
|
||||||
|
* - we can use dst without ref while sending in RCU section, we use
|
||||||
|
* ref when returning NF_ACCEPT for NAT-ed packet via loopback
|
||||||
* LOCAL_OUT rules:
|
* LOCAL_OUT rules:
|
||||||
* - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
|
* - skb->dev is NULL, skb->protocol is not set (both are set in POST_ROUTING)
|
||||||
* - skb->pkt_type is not set yet
|
* - skb->pkt_type is not set yet
|
||||||
@ -54,34 +56,51 @@ enum {
|
|||||||
IP_VS_RT_MODE_TUNNEL = 32,/* Tunnel mode */
|
IP_VS_RT_MODE_TUNNEL = 32,/* Tunnel mode */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct ip_vs_dest_dst *ip_vs_dest_dst_alloc(void)
|
||||||
|
{
|
||||||
|
return kmalloc(sizeof(struct ip_vs_dest_dst), GFP_ATOMIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void ip_vs_dest_dst_free(struct ip_vs_dest_dst *dest_dst)
|
||||||
|
{
|
||||||
|
kfree(dest_dst);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Destination cache to speed up outgoing route lookup
|
* Destination cache to speed up outgoing route lookup
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
__ip_vs_dst_set(struct ip_vs_dest *dest, struct dst_entry *dst, u32 dst_cookie)
|
__ip_vs_dst_set(struct ip_vs_dest *dest, struct ip_vs_dest_dst *dest_dst,
|
||||||
|
struct dst_entry *dst, u32 dst_cookie)
|
||||||
{
|
{
|
||||||
struct dst_entry *old_dst;
|
struct ip_vs_dest_dst *old;
|
||||||
|
|
||||||
old_dst = dest->dst_cache;
|
old = rcu_dereference_protected(dest->dest_dst,
|
||||||
dest->dst_cache = dst;
|
lockdep_is_held(&dest->dst_lock));
|
||||||
dest->dst_cookie = dst_cookie;
|
|
||||||
dst_release(old_dst);
|
if (dest_dst) {
|
||||||
|
dest_dst->dst_cache = dst;
|
||||||
|
dest_dst->dst_cookie = dst_cookie;
|
||||||
|
}
|
||||||
|
rcu_assign_pointer(dest->dest_dst, dest_dst);
|
||||||
|
|
||||||
|
if (old)
|
||||||
|
call_rcu(&old->rcu_head, ip_vs_dest_dst_rcu_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct dst_entry *
|
static inline struct ip_vs_dest_dst *
|
||||||
__ip_vs_dst_check(struct ip_vs_dest *dest)
|
__ip_vs_dst_check(struct ip_vs_dest *dest)
|
||||||
{
|
{
|
||||||
struct dst_entry *dst = dest->dst_cache;
|
struct ip_vs_dest_dst *dest_dst = rcu_dereference(dest->dest_dst);
|
||||||
|
struct dst_entry *dst;
|
||||||
|
|
||||||
if (!dst)
|
if (!dest_dst)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (dst->obsolete && dst->ops->check(dst, dest->dst_cookie) == NULL) {
|
dst = dest_dst->dst_cache;
|
||||||
dest->dst_cache = NULL;
|
if (dst->obsolete &&
|
||||||
dst_release(dst);
|
dst->ops->check(dst, dest_dst->dst_cookie) == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
return dest_dst;
|
||||||
dst_hold(dst);
|
|
||||||
return dst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@ -144,35 +163,48 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
{
|
{
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
struct netns_ipvs *ipvs = net_ipvs(net);
|
struct netns_ipvs *ipvs = net_ipvs(net);
|
||||||
|
struct ip_vs_dest_dst *dest_dst;
|
||||||
struct rtable *rt; /* Route to the other host */
|
struct rtable *rt; /* Route to the other host */
|
||||||
struct rtable *ort; /* Original route */
|
struct rtable *ort; /* Original route */
|
||||||
struct iphdr *iph;
|
struct iphdr *iph;
|
||||||
__be16 df;
|
__be16 df;
|
||||||
int mtu;
|
int mtu;
|
||||||
int local;
|
int local, noref = 1;
|
||||||
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
spin_lock(&dest->dst_lock);
|
dest_dst = __ip_vs_dst_check(dest);
|
||||||
rt = (struct rtable *) __ip_vs_dst_check(dest);
|
if (likely(dest_dst))
|
||||||
if (!rt) {
|
rt = (struct rtable *) dest_dst->dst_cache;
|
||||||
rt = do_output_route4(net, dest->addr.ip, rt_mode,
|
else {
|
||||||
&dest->dst_saddr.ip);
|
dest_dst = ip_vs_dest_dst_alloc();
|
||||||
if (!rt) {
|
spin_lock(&dest->dst_lock);
|
||||||
|
if (!dest_dst) {
|
||||||
|
__ip_vs_dst_set(dest, NULL, NULL, 0);
|
||||||
spin_unlock(&dest->dst_lock);
|
spin_unlock(&dest->dst_lock);
|
||||||
goto err_unreach;
|
goto err_unreach;
|
||||||
}
|
}
|
||||||
__ip_vs_dst_set(dest, dst_clone(&rt->dst), 0);
|
rt = do_output_route4(net, dest->addr.ip, rt_mode,
|
||||||
|
&dest_dst->dst_saddr.ip);
|
||||||
|
if (!rt) {
|
||||||
|
__ip_vs_dst_set(dest, NULL, NULL, 0);
|
||||||
|
spin_unlock(&dest->dst_lock);
|
||||||
|
ip_vs_dest_dst_free(dest_dst);
|
||||||
|
goto err_unreach;
|
||||||
|
}
|
||||||
|
__ip_vs_dst_set(dest, dest_dst, &rt->dst, 0);
|
||||||
|
spin_unlock(&dest->dst_lock);
|
||||||
IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d\n",
|
IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d\n",
|
||||||
&dest->addr.ip, &dest->dst_saddr.ip,
|
&dest->addr.ip, &dest_dst->dst_saddr.ip,
|
||||||
atomic_read(&rt->dst.__refcnt));
|
atomic_read(&rt->dst.__refcnt));
|
||||||
}
|
}
|
||||||
daddr = dest->addr.ip;
|
daddr = dest->addr.ip;
|
||||||
if (ret_saddr)
|
if (ret_saddr)
|
||||||
*ret_saddr = dest->dst_saddr.ip;
|
*ret_saddr = dest_dst->dst_saddr.ip;
|
||||||
spin_unlock(&dest->dst_lock);
|
|
||||||
} else {
|
} else {
|
||||||
__be32 saddr = htonl(INADDR_ANY);
|
__be32 saddr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
noref = 0;
|
||||||
|
|
||||||
/* For such unconfigured boxes avoid many route lookups
|
/* For such unconfigured boxes avoid many route lookups
|
||||||
* for performance reasons because we do not remember saddr
|
* for performance reasons because we do not remember saddr
|
||||||
*/
|
*/
|
||||||
@ -210,7 +242,8 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
goto err_put;
|
goto err_put;
|
||||||
}
|
}
|
||||||
/* skb to local stack, preserve old route */
|
/* skb to local stack, preserve old route */
|
||||||
ip_rt_put(rt);
|
if (!noref)
|
||||||
|
ip_rt_put(rt);
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,12 +273,19 @@ __ip_vs_get_out_rt(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
skb_dst_drop(skb);
|
skb_dst_drop(skb);
|
||||||
skb_dst_set(skb, &rt->dst);
|
if (noref) {
|
||||||
|
if (!local)
|
||||||
|
skb_dst_set_noref_force(skb, &rt->dst);
|
||||||
|
else
|
||||||
|
skb_dst_set(skb, dst_clone(&rt->dst));
|
||||||
|
} else
|
||||||
|
skb_dst_set(skb, &rt->dst);
|
||||||
|
|
||||||
return local;
|
return local;
|
||||||
|
|
||||||
err_put:
|
err_put:
|
||||||
ip_rt_put(rt);
|
if (!noref)
|
||||||
|
ip_rt_put(rt);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err_unreach:
|
err_unreach:
|
||||||
@ -303,36 +343,48 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
struct ip_vs_iphdr *ipvsh, int do_xfrm, int rt_mode)
|
struct ip_vs_iphdr *ipvsh, int do_xfrm, int rt_mode)
|
||||||
{
|
{
|
||||||
struct net *net = dev_net(skb_dst(skb)->dev);
|
struct net *net = dev_net(skb_dst(skb)->dev);
|
||||||
|
struct ip_vs_dest_dst *dest_dst;
|
||||||
struct rt6_info *rt; /* Route to the other host */
|
struct rt6_info *rt; /* Route to the other host */
|
||||||
struct rt6_info *ort; /* Original route */
|
struct rt6_info *ort; /* Original route */
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
int mtu;
|
int mtu;
|
||||||
int local;
|
int local, noref = 1;
|
||||||
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
spin_lock(&dest->dst_lock);
|
dest_dst = __ip_vs_dst_check(dest);
|
||||||
rt = (struct rt6_info *)__ip_vs_dst_check(dest);
|
if (likely(dest_dst))
|
||||||
if (!rt) {
|
rt = (struct rt6_info *) dest_dst->dst_cache;
|
||||||
|
else {
|
||||||
u32 cookie;
|
u32 cookie;
|
||||||
|
|
||||||
|
dest_dst = ip_vs_dest_dst_alloc();
|
||||||
|
spin_lock(&dest->dst_lock);
|
||||||
|
if (!dest_dst) {
|
||||||
|
__ip_vs_dst_set(dest, NULL, NULL, 0);
|
||||||
|
spin_unlock(&dest->dst_lock);
|
||||||
|
goto err_unreach;
|
||||||
|
}
|
||||||
dst = __ip_vs_route_output_v6(net, &dest->addr.in6,
|
dst = __ip_vs_route_output_v6(net, &dest->addr.in6,
|
||||||
&dest->dst_saddr.in6,
|
&dest_dst->dst_saddr.in6,
|
||||||
do_xfrm);
|
do_xfrm);
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
|
__ip_vs_dst_set(dest, NULL, NULL, 0);
|
||||||
spin_unlock(&dest->dst_lock);
|
spin_unlock(&dest->dst_lock);
|
||||||
|
ip_vs_dest_dst_free(dest_dst);
|
||||||
goto err_unreach;
|
goto err_unreach;
|
||||||
}
|
}
|
||||||
rt = (struct rt6_info *) dst;
|
rt = (struct rt6_info *) dst;
|
||||||
cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
|
cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
|
||||||
__ip_vs_dst_set(dest, dst_clone(&rt->dst), cookie);
|
__ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
|
||||||
|
spin_unlock(&dest->dst_lock);
|
||||||
IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
|
IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
|
||||||
&dest->addr.in6, &dest->dst_saddr.in6,
|
&dest->addr.in6, &dest_dst->dst_saddr.in6,
|
||||||
atomic_read(&rt->dst.__refcnt));
|
atomic_read(&rt->dst.__refcnt));
|
||||||
}
|
}
|
||||||
if (ret_saddr)
|
if (ret_saddr)
|
||||||
*ret_saddr = dest->dst_saddr.in6;
|
*ret_saddr = dest_dst->dst_saddr.in6;
|
||||||
spin_unlock(&dest->dst_lock);
|
|
||||||
} else {
|
} else {
|
||||||
|
noref = 0;
|
||||||
dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
|
dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm);
|
||||||
if (!dst)
|
if (!dst)
|
||||||
goto err_unreach;
|
goto err_unreach;
|
||||||
@ -367,7 +419,8 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
goto err_put;
|
goto err_put;
|
||||||
}
|
}
|
||||||
/* skb to local stack, preserve old route */
|
/* skb to local stack, preserve old route */
|
||||||
dst_release(&rt->dst);
|
if (!noref)
|
||||||
|
dst_release(&rt->dst);
|
||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,12 +452,19 @@ __ip_vs_get_out_rt_v6(struct sk_buff *skb, struct ip_vs_dest *dest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
skb_dst_drop(skb);
|
skb_dst_drop(skb);
|
||||||
skb_dst_set(skb, &rt->dst);
|
if (noref) {
|
||||||
|
if (!local)
|
||||||
|
skb_dst_set_noref_force(skb, &rt->dst);
|
||||||
|
else
|
||||||
|
skb_dst_set(skb, dst_clone(&rt->dst));
|
||||||
|
} else
|
||||||
|
skb_dst_set(skb, &rt->dst);
|
||||||
|
|
||||||
return local;
|
return local;
|
||||||
|
|
||||||
err_put:
|
err_put:
|
||||||
dst_release(&rt->dst);
|
if (!noref)
|
||||||
|
dst_release(&rt->dst);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
err_unreach:
|
err_unreach:
|
||||||
@ -494,6 +554,7 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
if (__ip_vs_get_out_rt(skb, NULL, iph->daddr, IP_VS_RT_MODE_NON_LOCAL,
|
if (__ip_vs_get_out_rt(skb, NULL, iph->daddr, IP_VS_RT_MODE_NON_LOCAL,
|
||||||
NULL) < 0)
|
NULL) < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
@ -504,12 +565,14 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
|
ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -521,6 +584,7 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
{
|
{
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
if (__ip_vs_get_out_rt_v6(skb, NULL, &ipvsh->daddr.in6, NULL,
|
if (__ip_vs_get_out_rt_v6(skb, NULL, &ipvsh->daddr.in6, NULL,
|
||||||
ipvsh, 0, IP_VS_RT_MODE_NON_LOCAL) < 0)
|
ipvsh, 0, IP_VS_RT_MODE_NON_LOCAL) < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
@ -529,12 +593,14 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
|
ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -553,6 +619,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
/* check if it is a connection of no-client-port */
|
/* check if it is a connection of no-client-port */
|
||||||
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
|
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
|
||||||
__be16 _pt, *p;
|
__be16 _pt, *p;
|
||||||
@ -620,12 +687,14 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
|
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -640,6 +709,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
/* check if it is a connection of no-client-port */
|
/* check if it is a connection of no-client-port */
|
||||||
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !ipvsh->fragoffs)) {
|
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT && !ipvsh->fragoffs)) {
|
||||||
__be16 _pt, *p;
|
__be16 _pt, *p;
|
||||||
@ -707,6 +777,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
|
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return rc;
|
return rc;
|
||||||
@ -714,6 +785,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
tx_error:
|
tx_error:
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -755,6 +827,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
|
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
|
||||||
IP_VS_RT_MODE_LOCAL |
|
IP_VS_RT_MODE_LOCAL |
|
||||||
IP_VS_RT_MODE_NON_LOCAL |
|
IP_VS_RT_MODE_NON_LOCAL |
|
||||||
@ -762,8 +835,10 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
IP_VS_RT_MODE_TUNNEL, &saddr);
|
IP_VS_RT_MODE_TUNNEL, &saddr);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
if (local)
|
if (local) {
|
||||||
|
rcu_read_unlock();
|
||||||
return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
|
return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
rt = skb_rtable(skb);
|
rt = skb_rtable(skb);
|
||||||
tdev = rt->dst.dev;
|
tdev = rt->dst.dev;
|
||||||
@ -818,6 +893,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
ip_local_out(skb);
|
ip_local_out(skb);
|
||||||
else if (ret == NF_DROP)
|
else if (ret == NF_DROP)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
|
|
||||||
@ -825,6 +901,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -844,6 +921,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
|
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6,
|
||||||
&saddr, ipvsh, 1,
|
&saddr, ipvsh, 1,
|
||||||
IP_VS_RT_MODE_LOCAL |
|
IP_VS_RT_MODE_LOCAL |
|
||||||
@ -851,8 +929,10 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
IP_VS_RT_MODE_TUNNEL);
|
IP_VS_RT_MODE_TUNNEL);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
if (local)
|
if (local) {
|
||||||
|
rcu_read_unlock();
|
||||||
return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
|
return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
rt = (struct rt6_info *) skb_dst(skb);
|
rt = (struct rt6_info *) skb_dst(skb);
|
||||||
tdev = rt->dst.dev;
|
tdev = rt->dst.dev;
|
||||||
@ -901,6 +981,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
ip6_local_out(skb);
|
ip6_local_out(skb);
|
||||||
else if (ret == NF_DROP)
|
else if (ret == NF_DROP)
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
|
|
||||||
@ -908,6 +989,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -926,14 +1008,17 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
|
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip,
|
||||||
IP_VS_RT_MODE_LOCAL |
|
IP_VS_RT_MODE_LOCAL |
|
||||||
IP_VS_RT_MODE_NON_LOCAL |
|
IP_VS_RT_MODE_NON_LOCAL |
|
||||||
IP_VS_RT_MODE_KNOWN_NH, NULL);
|
IP_VS_RT_MODE_KNOWN_NH, NULL);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
if (local)
|
if (local) {
|
||||||
|
rcu_read_unlock();
|
||||||
return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
|
return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
ip_send_check(ip_hdr(skb));
|
ip_send_check(ip_hdr(skb));
|
||||||
|
|
||||||
@ -941,12 +1026,14 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
|
ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 0);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -960,25 +1047,30 @@ ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
|
|
||||||
EnterFunction(10);
|
EnterFunction(10);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
|
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
|
||||||
ipvsh, 0,
|
ipvsh, 0,
|
||||||
IP_VS_RT_MODE_LOCAL |
|
IP_VS_RT_MODE_LOCAL |
|
||||||
IP_VS_RT_MODE_NON_LOCAL);
|
IP_VS_RT_MODE_NON_LOCAL);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
if (local)
|
if (local) {
|
||||||
|
rcu_read_unlock();
|
||||||
return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
|
return ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Another hack: avoid icmp_send in ip_fragment */
|
/* Another hack: avoid icmp_send in ip_fragment */
|
||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
|
ip_vs_send_or_cont(NFPROTO_IPV6, skb, cp, 0);
|
||||||
|
rcu_read_unlock();
|
||||||
|
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
@ -1023,6 +1115,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
rt_mode = (hooknum != NF_INET_FORWARD) ?
|
rt_mode = (hooknum != NF_INET_FORWARD) ?
|
||||||
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
|
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
|
||||||
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
|
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, rt_mode, NULL);
|
local = __ip_vs_get_out_rt(skb, cp->dest, cp->daddr.ip, rt_mode, NULL);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
goto tx_error;
|
goto tx_error;
|
||||||
@ -1067,10 +1160,12 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
|
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV4, skb, cp, local);
|
||||||
|
rcu_read_unlock();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
dev_kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
rc = NF_STOLEN;
|
rc = NF_STOLEN;
|
||||||
out:
|
out:
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
@ -1111,6 +1206,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
rt_mode = (hooknum != NF_INET_FORWARD) ?
|
rt_mode = (hooknum != NF_INET_FORWARD) ?
|
||||||
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
|
IP_VS_RT_MODE_LOCAL | IP_VS_RT_MODE_NON_LOCAL |
|
||||||
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
|
IP_VS_RT_MODE_RDR : IP_VS_RT_MODE_NON_LOCAL;
|
||||||
|
rcu_read_lock();
|
||||||
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
|
local = __ip_vs_get_out_rt_v6(skb, cp->dest, &cp->daddr.in6, NULL,
|
||||||
ipvsh, 0, rt_mode);
|
ipvsh, 0, rt_mode);
|
||||||
if (local < 0)
|
if (local < 0)
|
||||||
@ -1156,10 +1252,12 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
|
|||||||
skb->local_df = 1;
|
skb->local_df = 1;
|
||||||
|
|
||||||
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
|
rc = ip_vs_nat_send_or_cont(NFPROTO_IPV6, skb, cp, local);
|
||||||
|
rcu_read_unlock();
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tx_error:
|
tx_error:
|
||||||
dev_kfree_skb(skb);
|
kfree_skb(skb);
|
||||||
|
rcu_read_unlock();
|
||||||
rc = NF_STOLEN;
|
rc = NF_STOLEN;
|
||||||
out:
|
out:
|
||||||
LeaveFunction(10);
|
LeaveFunction(10);
|
||||||
|
Loading…
Reference in New Issue
Block a user