aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJesse Gross <jesse@nicira.com>2012-03-06 18:05:46 -0500
committerJesse Gross <jesse@nicira.com>2012-03-07 17:36:57 -0500
commit81e5d41d7ed4f6c61ba3d2414f4f9ddf6d934ebb (patch)
treec85f6f4cd07c34a633475a4667f418bf402d21a9 /net
parent651a68ea2ce9738b84e928836053b2e0fb5db2ba (diff)
openvswitch: Fix checksum update for actions on UDP packets.
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. Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net')
-rw-r--r--net/openvswitch/actions.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 2725d1bdf291..48badffaafc1 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007-2011 Nicira Networks. 2 * Copyright (c) 2007-2012 Nicira Networks.
3 * 3 *
4 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public 5 * modify it under the terms of version 2 of the GNU General Public
@@ -145,9 +145,16 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh,
145 inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, 145 inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb,
146 *addr, new_addr, 1); 146 *addr, new_addr, 1);
147 } else if (nh->protocol == IPPROTO_UDP) { 147 } else if (nh->protocol == IPPROTO_UDP) {
148 if (likely(transport_len >= sizeof(struct udphdr))) 148 if (likely(transport_len >= sizeof(struct udphdr))) {
149 inet_proto_csum_replace4(&udp_hdr(skb)->check, skb, 149 struct udphdr *uh = udp_hdr(skb);
150 *addr, new_addr, 1); 150
151 if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) {
152 inet_proto_csum_replace4(&uh->check, skb,
153 *addr, new_addr, 1);
154 if (!uh->check)
155 uh->check = CSUM_MANGLED_0;
156 }
157 }
151 } 158 }
152 159
153 csum_replace4(&nh->check, *addr, new_addr); 160 csum_replace4(&nh->check, *addr, new_addr);
@@ -197,8 +204,22 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port,
197 skb->rxhash = 0; 204 skb->rxhash = 0;
198} 205}
199 206
200static int set_udp_port(struct sk_buff *skb, 207static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port)
201 const struct ovs_key_udp *udp_port_key) 208{
209 struct udphdr *uh = udp_hdr(skb);
210
211 if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) {
212 set_tp_port(skb, port, new_port, &uh->check);
213
214 if (!uh->check)
215 uh->check = CSUM_MANGLED_0;
216 } else {
217 *port = new_port;
218 skb->rxhash = 0;
219 }
220}
221
222static int set_udp(struct sk_buff *skb, const struct ovs_key_udp *udp_port_key)
202{ 223{
203 struct udphdr *uh; 224 struct udphdr *uh;
204 int err; 225 int err;
@@ -210,16 +231,15 @@ static int set_udp_port(struct sk_buff *skb,
210 231
211 uh = udp_hdr(skb); 232 uh = udp_hdr(skb);
212 if (udp_port_key->udp_src != uh->source) 233 if (udp_port_key->udp_src != uh->source)
213 set_tp_port(skb, &uh->source, udp_port_key->udp_src, &uh->check); 234 set_udp_port(skb, &uh->source, udp_port_key->udp_src);
214 235
215 if (udp_port_key->udp_dst != uh->dest) 236 if (udp_port_key->udp_dst != uh->dest)
216 set_tp_port(skb, &uh->dest, udp_port_key->udp_dst, &uh->check); 237 set_udp_port(skb, &uh->dest, udp_port_key->udp_dst);
217 238
218 return 0; 239 return 0;
219} 240}
220 241
221static int set_tcp_port(struct sk_buff *skb, 242static int set_tcp(struct sk_buff *skb, const struct ovs_key_tcp *tcp_port_key)
222 const struct ovs_key_tcp *tcp_port_key)
223{ 243{
224 struct tcphdr *th; 244 struct tcphdr *th;
225 int err; 245 int err;
@@ -328,11 +348,11 @@ static int execute_set_action(struct sk_buff *skb,
328 break; 348 break;
329 349
330 case OVS_KEY_ATTR_TCP: 350 case OVS_KEY_ATTR_TCP:
331 err = set_tcp_port(skb, nla_data(nested_attr)); 351 err = set_tcp(skb, nla_data(nested_attr));
332 break; 352 break;
333 353
334 case OVS_KEY_ATTR_UDP: 354 case OVS_KEY_ATTR_UDP:
335 err = set_udp_port(skb, nla_data(nested_attr)); 355 err = set_udp(skb, nla_data(nested_attr));
336 break; 356 break;
337 } 357 }
338 358