History

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.

Jesse Gross committed 14 years ago

Commit 81e5d411 parent 651a68e1 file · +32 −12Browse files

Unified · Split

net/openvswitch/actions.c+32−12
@@ -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/or4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of version 2 of the GNU General Public5 * 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, · 139 unmodified lines
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, · 43 unmodified lines
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, · 5 unmodified lines
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, · 102 unmodified lines
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