aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLance Richardson <lrichard@redhat.com>2017-01-12 19:33:18 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-04 03:47:09 -0500
commit18767acb7b67b27ec4355ca623cbaa209edc8f13 (patch)
treea16404318775f880bd834625cea8ed5ce01be668
parent3524f64224bdef1c834e2952aaa72c175621e2e3 (diff)
openvswitch: maintain correct checksum state in conntrack actions
[ Upstream commit 75f01a4c9cc291ff5cb28ca1216adb163b7a20ee ] When executing conntrack actions on skbuffs with checksum mode CHECKSUM_COMPLETE, the checksum must be updated to account for header pushes and pulls. Otherwise we get "hw csum failure" logs similar to this (ICMP packet received on geneve tunnel via ixgbe NIC): [ 405.740065] genev_sys_6081: hw csum failure [ 405.740106] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G I 4.10.0-rc3+ #1 [ 405.740108] Call Trace: [ 405.740110] <IRQ> [ 405.740113] dump_stack+0x63/0x87 [ 405.740116] netdev_rx_csum_fault+0x3a/0x40 [ 405.740118] __skb_checksum_complete+0xcf/0xe0 [ 405.740120] nf_ip_checksum+0xc8/0xf0 [ 405.740124] icmp_error+0x1de/0x351 [nf_conntrack_ipv4] [ 405.740132] nf_conntrack_in+0xe1/0x550 [nf_conntrack] [ 405.740137] ? find_bucket.isra.2+0x62/0x70 [openvswitch] [ 405.740143] __ovs_ct_lookup+0x95/0x980 [openvswitch] [ 405.740145] ? netif_rx_internal+0x44/0x110 [ 405.740149] ovs_ct_execute+0x147/0x4b0 [openvswitch] [ 405.740153] do_execute_actions+0x22e/0xa70 [openvswitch] [ 405.740157] ovs_execute_actions+0x40/0x120 [openvswitch] [ 405.740161] ovs_dp_process_packet+0x84/0x120 [openvswitch] [ 405.740166] ovs_vport_receive+0x73/0xd0 [openvswitch] [ 405.740168] ? udp_rcv+0x1a/0x20 [ 405.740170] ? ip_local_deliver_finish+0x93/0x1e0 [ 405.740172] ? ip_local_deliver+0x6f/0xe0 [ 405.740174] ? ip_rcv_finish+0x3a0/0x3a0 [ 405.740176] ? ip_rcv_finish+0xdb/0x3a0 [ 405.740177] ? ip_rcv+0x2a7/0x400 [ 405.740180] ? __netif_receive_skb_core+0x970/0xa00 [ 405.740185] netdev_frame_hook+0xd3/0x160 [openvswitch] [ 405.740187] __netif_receive_skb_core+0x1dc/0xa00 [ 405.740194] ? ixgbe_clean_rx_irq+0x46d/0xa20 [ixgbe] [ 405.740197] __netif_receive_skb+0x18/0x60 [ 405.740199] netif_receive_skb_internal+0x40/0xb0 [ 405.740201] napi_gro_receive+0xcd/0x120 [ 405.740204] gro_cell_poll+0x57/0x80 [geneve] [ 405.740206] net_rx_action+0x260/0x3c0 [ 405.740209] __do_softirq+0xc9/0x28c [ 405.740211] irq_exit+0xd9/0xf0 [ 405.740213] do_IRQ+0x51/0xd0 [ 405.740215] common_interrupt+0x93/0x93 Fixes: 7f8a436eaa2c ("openvswitch: Add conntrack action") Signed-off-by: Lance Richardson <lrichard@redhat.com> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/openvswitch/conntrack.c6
1 files changed, 4 insertions, 2 deletions
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index fecefa2dc94e..eab210bb1ef0 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -514,7 +514,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
514 int hooknum, nh_off, err = NF_ACCEPT; 514 int hooknum, nh_off, err = NF_ACCEPT;
515 515
516 nh_off = skb_network_offset(skb); 516 nh_off = skb_network_offset(skb);
517 skb_pull(skb, nh_off); 517 skb_pull_rcsum(skb, nh_off);
518 518
519 /* See HOOK2MANIP(). */ 519 /* See HOOK2MANIP(). */
520 if (maniptype == NF_NAT_MANIP_SRC) 520 if (maniptype == NF_NAT_MANIP_SRC)
@@ -579,6 +579,7 @@ static int ovs_ct_nat_execute(struct sk_buff *skb, struct nf_conn *ct,
579 err = nf_nat_packet(ct, ctinfo, hooknum, skb); 579 err = nf_nat_packet(ct, ctinfo, hooknum, skb);
580push: 580push:
581 skb_push(skb, nh_off); 581 skb_push(skb, nh_off);
582 skb_postpush_rcsum(skb, skb->data, nh_off);
582 583
583 return err; 584 return err;
584} 585}
@@ -890,7 +891,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
890 891
891 /* The conntrack module expects to be working at L3. */ 892 /* The conntrack module expects to be working at L3. */
892 nh_ofs = skb_network_offset(skb); 893 nh_ofs = skb_network_offset(skb);
893 skb_pull(skb, nh_ofs); 894 skb_pull_rcsum(skb, nh_ofs);
894 895
895 if (key->ip.frag != OVS_FRAG_TYPE_NONE) { 896 if (key->ip.frag != OVS_FRAG_TYPE_NONE) {
896 err = handle_fragments(net, key, info->zone.id, skb); 897 err = handle_fragments(net, key, info->zone.id, skb);
@@ -904,6 +905,7 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb,
904 err = ovs_ct_lookup(net, key, info, skb); 905 err = ovs_ct_lookup(net, key, info, skb);
905 906
906 skb_push(skb, nh_ofs); 907 skb_push(skb, nh_ofs);
908 skb_postpush_rcsum(skb, skb->data, nh_ofs);
907 if (err) 909 if (err)
908 kfree_skb(skb); 910 kfree_skb(skb);
909 return err; 911 return err;