diff options
Diffstat (limited to 'net/openvswitch/actions.c')
-rw-r--r-- | net/openvswitch/actions.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 8a8c0b8b4f63..ee34f474ad14 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c | |||
@@ -273,28 +273,36 @@ static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, | |||
273 | return 0; | 273 | return 0; |
274 | } | 274 | } |
275 | 275 | ||
276 | static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, | 276 | static void update_ip_l4_checksum(struct sk_buff *skb, struct iphdr *nh, |
277 | __be32 *addr, __be32 new_addr) | 277 | __be32 addr, __be32 new_addr) |
278 | { | 278 | { |
279 | int transport_len = skb->len - skb_transport_offset(skb); | 279 | int transport_len = skb->len - skb_transport_offset(skb); |
280 | 280 | ||
281 | if (nh->frag_off & htons(IP_OFFSET)) | ||
282 | return; | ||
283 | |||
281 | if (nh->protocol == IPPROTO_TCP) { | 284 | if (nh->protocol == IPPROTO_TCP) { |
282 | if (likely(transport_len >= sizeof(struct tcphdr))) | 285 | if (likely(transport_len >= sizeof(struct tcphdr))) |
283 | inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, | 286 | inet_proto_csum_replace4(&tcp_hdr(skb)->check, skb, |
284 | *addr, new_addr, 1); | 287 | addr, new_addr, 1); |
285 | } else if (nh->protocol == IPPROTO_UDP) { | 288 | } else if (nh->protocol == IPPROTO_UDP) { |
286 | if (likely(transport_len >= sizeof(struct udphdr))) { | 289 | if (likely(transport_len >= sizeof(struct udphdr))) { |
287 | struct udphdr *uh = udp_hdr(skb); | 290 | struct udphdr *uh = udp_hdr(skb); |
288 | 291 | ||
289 | if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { | 292 | if (uh->check || skb->ip_summed == CHECKSUM_PARTIAL) { |
290 | inet_proto_csum_replace4(&uh->check, skb, | 293 | inet_proto_csum_replace4(&uh->check, skb, |
291 | *addr, new_addr, 1); | 294 | addr, new_addr, 1); |
292 | if (!uh->check) | 295 | if (!uh->check) |
293 | uh->check = CSUM_MANGLED_0; | 296 | uh->check = CSUM_MANGLED_0; |
294 | } | 297 | } |
295 | } | 298 | } |
296 | } | 299 | } |
300 | } | ||
297 | 301 | ||
302 | static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, | ||
303 | __be32 *addr, __be32 new_addr) | ||
304 | { | ||
305 | update_ip_l4_checksum(skb, nh, *addr, new_addr); | ||
298 | csum_replace4(&nh->check, *addr, new_addr); | 306 | csum_replace4(&nh->check, *addr, new_addr); |
299 | skb_clear_hash(skb); | 307 | skb_clear_hash(skb); |
300 | *addr = new_addr; | 308 | *addr = new_addr; |