All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ipvs 1/2] ipvs: Do tcp/udp checksumming prior to tunnel xmit
@ 2014-07-23  6:37 Alex Gartrell
  2014-07-23  6:37 ` [PATCH ipvs 2/2] ipvs: only perform slow checksum on NF_INET_LOCAL_OUT Alex Gartrell
  2014-07-23  8:25 ` [PATCH ipvs 1/2] ipvs: Do tcp/udp checksumming prior to tunnel xmit Julian Anastasov
  0 siblings, 2 replies; 10+ messages in thread
From: Alex Gartrell @ 2014-07-23  6:37 UTC (permalink / raw)
  To: horms; +Cc: ja, lvs-devel, agartrell, kernel-team

The combination of NF_INET_LOCAL_OUT and hardware checksum offload results
in picking the packet out of the send path before it gets proper checksums.
Our NICs (most NICs?) cannot do the checksumming in ipip packets, so these
faulty tcp/udp headers arrive at their destination and are discarded.

Instead, checksum the tcp/udp packets in the tunnel transmit path.  Right
now we do this for all packets, but a subsequent patch will limit this to
the NF_INET_LOCAL_OUT hook.

Signed-off-by: Alex Gartrell <agartrell@fb.com>
---
 net/netfilter/ipvs/ip_vs_xmit.c | 49 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c
index 6f70bdd..e9b5e6e 100644
--- a/net/netfilter/ipvs/ip_vs_xmit.c
+++ b/net/netfilter/ipvs/ip_vs_xmit.c
@@ -37,6 +37,7 @@
 #include <net/icmp.h>                   /* for icmp_send */
 #include <net/route.h>                  /* for ip_route_output */
 #include <net/ipv6.h>
+#include <net/ip6_checksum.h>
 #include <net/ip6_route.h>
 #include <net/addrconf.h>
 #include <linux/icmpv6.h>
@@ -824,6 +825,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 	struct iphdr  *iph;			/* Our new IP header */
 	unsigned int max_headroom;		/* The extra header space needed */
 	int ret, local;
+	unsigned int l4_len = 0;
 
 	EnterFunction(10);
 
@@ -862,6 +864,29 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
 		old_iph = ip_hdr(skb);
 	}
 
+	{
+		/* ipip breaks layer 4 checksumming on many (all?) NICs, so
+		 * we must do it ourselves instead of relying upon checksum
+		 * offload */
+		l4_len = ntohs(old_iph->tot_len) - (old_iph->ihl * 4);
+		switch (old_iph->protocol) {
+		case IPPROTO_TCP:
+			tcp_hdr(skb)->check = 0;
+			tcp_hdr(skb)->check = tcp_v4_check(
+				l4_len, old_iph->saddr, old_iph->daddr,
+				csum_partial(tcp_hdr(skb), l4_len, 0));
+			break;
+		case IPPROTO_UDP:
+			udp_hdr(skb)->check = 0;
+			udp_hdr(skb)->check = udp_v4_check(
+				l4_len, old_iph->saddr, old_iph->daddr,
+				csum_partial(udp_hdr(skb), l4_len, 0));
+			break;
+		default:
+			break;
+		}
+	}
+
 	skb->transport_header = skb->network_header;
 
 	/* fix old IP header checksum */
@@ -918,6 +943,7 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 	struct ipv6hdr  *iph;		/* Our new IP header */
 	unsigned int max_headroom;	/* The extra header space needed */
 	int ret, local;
+	unsigned int l4_len = 0;
 
 	EnterFunction(10);
 
@@ -953,6 +979,29 @@ ip_vs_tunnel_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
 		old_iph = ipv6_hdr(skb);
 	}
 
+	{
+		/* ipip breaks layer 4 checksumming on many (all?) NICs, so
+		 * we must do it ourselves instead of relying upon checksum
+		 * offload */
+		l4_len = ntohs(old_iph->payload_len);
+		switch (old_iph->nexthdr) {
+		case IPPROTO_TCP:
+			tcp_hdr(skb)->check = 0;
+			tcp_hdr(skb)->check = tcp_v6_check(
+				l4_len, &old_iph->saddr, &old_iph->daddr,
+				csum_partial(tcp_hdr(skb), l4_len, 0));
+			break;
+		case IPPROTO_UDP:
+			udp_hdr(skb)->check = 0;
+			udp_hdr(skb)->check = udp_v6_check(
+				l4_len, &old_iph->saddr, &old_iph->daddr,
+				csum_partial(udp_hdr(skb), l4_len, 0));
+			break;
+		default:
+			break;
+		}
+	}
+
 	skb->transport_header = skb->network_header;
 
 	skb_push(skb, sizeof(struct ipv6hdr));
-- 
1.8.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2014-07-25  8:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-07-23  6:37 [PATCH ipvs 1/2] ipvs: Do tcp/udp checksumming prior to tunnel xmit Alex Gartrell
2014-07-23  6:37 ` [PATCH ipvs 2/2] ipvs: only perform slow checksum on NF_INET_LOCAL_OUT Alex Gartrell
2014-07-23  8:25 ` [PATCH ipvs 1/2] ipvs: Do tcp/udp checksumming prior to tunnel xmit Julian Anastasov
2014-07-23 19:16   ` Alex Gartrell
2014-07-23 22:54     ` Julian Anastasov
2014-07-24  6:22       ` Julian Anastasov
2014-07-24 22:29         ` Alex Gartrell
2014-07-25  4:30           ` Julian Anastasov
2014-07-25  7:40             ` Alex Gartrell
2014-07-25  8:53               ` Julian Anastasov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.