In order to know when we may need to tcp checksum, we need to propagate the hooknum through packet_xmit as well as through conn_schedule (as it may call ip_vs_leave, which itself invokes packet_xmit). Signed-off-by: Alex Gartrell <agartrell@xxxxxx> --- include/net/ip_vs.h | 36 ++++++++++++++++++++++----------- net/netfilter/ipvs/ip_vs_core.c | 10 +++++---- net/netfilter/ipvs/ip_vs_proto_ah_esp.c | 2 +- net/netfilter/ipvs/ip_vs_proto_sctp.c | 5 +++-- net/netfilter/ipvs/ip_vs_proto_tcp.c | 5 +++-- net/netfilter/ipvs/ip_vs_proto_udp.c | 5 +++-- net/netfilter/ipvs/ip_vs_xmit.c | 35 ++++++++++++++++++++------------ 7 files changed, 62 insertions(+), 36 deletions(-) diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 624a8a5..a31b435 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -448,7 +448,8 @@ struct ip_vs_protocol { int (*conn_schedule)(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, - struct ip_vs_iphdr *iph); + struct ip_vs_iphdr *iph, + int hooknum); struct ip_vs_conn * (*conn_in_get)(int af, @@ -566,7 +567,8 @@ struct ip_vs_conn { NF_ACCEPT can be returned when destination is local. */ int (*packet_xmit)(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); /* Note: we can group the following members into a structure, in order to save more space, and the following members are @@ -1371,7 +1373,8 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *ignored, struct ip_vs_iphdr *iph); int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, - struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph); + struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph, + int hooknum); void ip_vs_scheduler_err(struct ip_vs_service *svc, const char *msg); @@ -1439,15 +1442,20 @@ void ip_vs_read_estimator(struct ip_vs_stats_user *dst, * Various IPVS packet transmitters (from ip_vs_xmit.c) */ int ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset, unsigned int hooknum, struct ip_vs_iphdr *iph); @@ -1455,13 +1463,17 @@ void ip_vs_dest_dst_rcu_free(struct rcu_head *head); #ifdef CONFIG_IP_VS_IPV6 int ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph); + struct ip_vs_protocol *pp, struct ip_vs_iphdr *iph, + int hooknum); int ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, struct ip_vs_protocol *pp, int offset, unsigned int hooknum, struct ip_vs_iphdr *iph); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index e683675..613a125 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -507,7 +507,8 @@ ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb, * no destination is available for a new connection. */ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, - struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph) + struct ip_vs_proto_data *pd, struct ip_vs_iphdr *iph, + int hooknum) { __be16 _ports[2], *pptr; #ifdef CONFIG_SYSCTL @@ -564,7 +565,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); /* transmit the first SYN packet */ - ret = cp->packet_xmit(skb, cp, pd->pp, iph); + ret = cp->packet_xmit(skb, cp, pd->pp, iph, hooknum); /* do not touch skb anymore */ atomic_inc(&cp->in_pkts); @@ -1635,6 +1636,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) pd = ip_vs_proto_data_get(net, iph.protocol); if (unlikely(!pd)) return NF_ACCEPT; + pp = pd->pp; /* * Check if the packet belongs to an existing connection entry @@ -1656,7 +1658,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) int v; /* Schedule and create new connection entry into &cp */ - if (!pp->conn_schedule(af, skb, pd, &v, &cp, &iph)) + if (!pp->conn_schedule(af, skb, pd, &v, &cp, &iph, hooknum)) return v; } @@ -1692,7 +1694,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) ip_vs_in_stats(cp, skb); ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); if (cp->packet_xmit) - ret = cp->packet_xmit(skb, cp, pp, &iph); + ret = cp->packet_xmit(skb, cp, pp, &iph, hooknum); /* do not touch skb anymore */ else { IP_VS_DBG_RL("warning: packet_xmit is null"); diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c index 5de3dd3..169eaa3 100644 --- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c +++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c @@ -109,7 +109,7 @@ ah_esp_conn_out_get(int af, const struct sk_buff *skb, static int ah_esp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, - struct ip_vs_iphdr *iph) + struct ip_vs_iphdr *iph, int hooknum) { /* * AH/ESP is only related traffic. Pass the packet to IP stack. diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index 2f7ea75..aec76c9 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -11,7 +11,7 @@ static int sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, - struct ip_vs_iphdr *iph) + struct ip_vs_iphdr *iph, int hooknum) { struct net *net; struct ip_vs_service *svc; @@ -56,7 +56,8 @@ sctp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); if (!*cpp && ignored <= 0) { if (!ignored) - *verdict = ip_vs_leave(svc, skb, pd, iph); + *verdict = ip_vs_leave(svc, skb, pd, iph, + hooknum); else *verdict = NF_DROP; rcu_read_unlock(); diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index e3a6972..1baf90d 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -34,7 +34,7 @@ static int tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, - struct ip_vs_iphdr *iph) + struct ip_vs_iphdr *iph, int hooknum) { struct net *net; struct ip_vs_service *svc; @@ -72,7 +72,8 @@ tcp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); if (!*cpp && ignored <= 0) { if (!ignored) - *verdict = ip_vs_leave(svc, skb, pd, iph); + *verdict = ip_vs_leave(svc, skb, pd, iph, + hooknum); else *verdict = NF_DROP; rcu_read_unlock(); diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index b62a3c0..9eeb752 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -31,7 +31,7 @@ static int udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, int *verdict, struct ip_vs_conn **cpp, - struct ip_vs_iphdr *iph) + struct ip_vs_iphdr *iph, int hooknum) { struct net *net; struct ip_vs_service *svc; @@ -67,7 +67,8 @@ udp_conn_schedule(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, *cpp = ip_vs_schedule(svc, skb, pd, &ignored, iph); if (!*cpp && ignored <= 0) { if (!ignored) - *verdict = ip_vs_leave(svc, skb, pd, iph); + *verdict = ip_vs_leave(svc, skb, pd, iph, + hooknum); else *verdict = NF_DROP; rcu_read_unlock(); diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index e9b5e6e..91bf1d5 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -535,7 +535,8 @@ static inline int ip_vs_send_or_cont(int pf, struct sk_buff *skb, */ int ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { /* we do not touch skb and do not need pskb ptr */ return ip_vs_send_or_cont(NFPROTO_IPV4, skb, cp, 1); @@ -549,7 +550,8 @@ ip_vs_null_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, */ int ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { struct iphdr *iph = ip_hdr(skb); @@ -581,7 +583,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #ifdef CONFIG_IP_VS_IPV6 int ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { EnterFunction(10); @@ -613,7 +616,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, */ int ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { struct rtable *rt; /* Route to the other host */ int local, rc, was_input; @@ -703,7 +707,8 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #ifdef CONFIG_IP_VS_IPV6 int ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { struct rt6_info *rt; /* Route to the other host */ int local, rc; @@ -813,7 +818,8 @@ tx_error: */ int ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { struct netns_ipvs *ipvs = net_ipvs(skb_net(skb)); struct rtable *rt; /* Route to the other host */ @@ -864,7 +870,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, old_iph = ip_hdr(skb); } - { + if (hooknum == NF_INET_LOCAL_OUT) { /* ipip breaks layer 4 checksumming on many (all?) NICs, so * we must do it ourselves instead of relying upon checksum * offload */ @@ -934,7 +940,8 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #ifdef CONFIG_IP_VS_IPV6 int ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { struct rt6_info *rt; /* Route to the other host */ struct in6_addr saddr; /* Source for tunnel */ @@ -979,7 +986,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, old_iph = ipv6_hdr(skb); } - { + if (hooknum == NF_INET_LOCAL_OUT) { /* ipip breaks layer 4 checksumming on many (all?) NICs, so * we must do it ourselves instead of relying upon checksum * offload */ @@ -1051,7 +1058,8 @@ tx_error: */ int ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { int local; @@ -1090,7 +1098,8 @@ ip_vs_dr_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, #ifdef CONFIG_IP_VS_IPV6 int ip_vs_dr_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, - struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh) + struct ip_vs_protocol *pp, struct ip_vs_iphdr *ipvsh, + int hooknum) { int local; @@ -1147,7 +1156,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (cp->packet_xmit) - rc = cp->packet_xmit(skb, cp, pp, iph); + rc = cp->packet_xmit(skb, cp, pp, iph, hooknum); else rc = NF_ACCEPT; /* do not touch skb anymore */ @@ -1239,7 +1248,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, translate address/port back */ if (IP_VS_FWD_METHOD(cp) != IP_VS_CONN_F_MASQ) { if (cp->packet_xmit) - rc = cp->packet_xmit(skb, cp, pp, ipvsh); + rc = cp->packet_xmit(skb, cp, pp, ipvsh, hooknum); else rc = NF_ACCEPT; /* do not touch skb anymore */ -- 1.8.1 -- To unsubscribe from this list: send the line "unsubscribe lvs-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html