[ovs-dev] [PATCH] datapath: Fix checksum update for actions on UDP packets.

Jesse Gross jesse at nicira.com
Tue Mar 6 22:55:41 UTC 2012


When modifying IP addresses or ports on a UDP packet we don't
correctly follow the rules for unchecksummed packets.  This meant
that packets without a checksum can be given a incorrect new checksum
and packets with a checksum can become marked as being unchecksummed.
This fixes it to handle those requirements.

Bug #8937

Signed-off-by: Jesse Gross <jesse at nicira.com>
---
 datapath/actions.c |   38 ++++++++++++++++++++++++++++++--------
 1 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 4b07603..6f6b82d 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -147,9 +147,17 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
 			inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
 						 *addr, new_addr, 1);
 	} else if (nh->protocol == IPPROTO_UDP) {
-		if (likely(transport_len >= sizeof(struct udphdr)))
-			inet_proto_csum_replace4(&udp_hdr(skb)->check, skb,
-						 *addr, new_addr, 1);
+		if (likely(transport_len >= sizeof(struct udphdr))) {
+			struct udphdr *uh = udp_hdr(skb);
+
+			if (uh->check ||
+			    get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
+				inet_proto_csum_replace4(&uh->check, skb,
+							 *addr, new_addr, 1);
+				if (!uh->check)
+					uh->check = CSUM_MANGLED_0;
+			}
+		}
 	}
 
 	csum_replace4(&nh->check, *addr, new_addr);
@@ -199,8 +207,22 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port,
 	skb_clear_rxhash(skb);
 }
 
-static int set_udp_port(struct sk_buff *skb,
-			const struct ovs_key_udp *udp_port_key)
+static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
+{
+        struct udphdr *uh = udp_hdr(skb);
+
+	if (uh->check && get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
+		set_tp_port(skb, port, new_port, &uh->check);
+
+                if (!uh->check)
+                        uh->check = CSUM_MANGLED_0;
+	} else {
+		*port = new_port;
+		skb_clear_rxhash(skb);
+	}
+}
+
+static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key)
 {
 	struct udphdr *uh;
 	int err;
@@ -212,10 +234,10 @@ static int set_udp_port(struct sk_buff *skb,
 
 	uh = udp_hdr(skb);
 	if (udp_port_key->udp_src != uh->source)
-		set_tp_port(skb, &uh->source, udp_port_key->udp_src, &uh->check);
+		set_udp_port(skb, &uh->source, udp_port_key->udp_src);
 
 	if (udp_port_key->udp_dst != uh->dest)
-		set_tp_port(skb, &uh->dest, udp_port_key->udp_dst, &uh->check);
+		set_udp_port(skb, &uh->dest, udp_port_key->udp_dst);
 
 	return 0;
 }
@@ -338,7 +360,7 @@ static int execute_set_action(struct sk_buff *skb,
 		break;
 
 	case OVS_KEY_ATTR_UDP:
-		err = set_udp_port(skb, nla_data(nested_attr));
+		err = set_udp(skb, nla_data(nested_attr));
 		break;
 	}
 
-- 
1.7.5.4




More information about the dev mailing list