diff options
author | Yi-Hung Wei <yihung.wei@gmail.com> | 2017-05-01 10:24:33 -0700 |
---|---|---|
committer | Simon Horman <simon.horman@netronome.com> | 2017-05-03 17:49:13 +0200 |
commit | 279ecabe32f026bf15915e761c362739908e1ea1 (patch) | |
tree | 14765aeb1fdc2a7ae0de399db0178054cbdb3c7a /datapath | |
parent | 176e06ddc2ed1dd06f96e815cd82d4ec090e920b (diff) | |
download | openvswitch-279ecabe32f026bf15915e761c362739908e1ea1.tar.gz |
datapath: correctly fragment packet with mpls headers
Upstream commit:
commit c66549ffd666605831abf6cf19ce0571ad868e39
Author: Jiri Benc <jbenc@redhat.com>
Date: Wed Oct 5 15:01:57 2016 +0200
openvswitch: correctly fragment packet with mpls headers
If mpls headers were pushed to a defragmented packet, the refragmentation no
longer works correctly after 48d2ab609b6b ("net: mpls: Fixups for GSO"). The
network header has to be shifted after the mpls headers for the
fragmentation and restored afterwards.
Fixes: 48d2ab609b6b ("net: mpls: Fixups for GSO")
Signed-off-by: Jiri Benc <jbenc@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Yi-Hung Wei <yihung.wei@gmail.com>
Signed-off-by: Simon Horman <simon.horman@netronome.com>
Diffstat (limited to 'datapath')
-rw-r--r-- | datapath/actions.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/datapath/actions.c b/datapath/actions.c index 9ac02bc8e..59d91b202 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -62,7 +62,8 @@ struct ovs_frag_data { struct vport *vport; struct ovs_gso_cb cb; __be16 inner_protocol; - __u16 vlan_tci; + u16 network_offset; /* valid only for MPLS */ + u16 vlan_tci; __be16 vlan_proto; unsigned int l2_len; u8 mac_proto; @@ -740,6 +741,12 @@ static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS) skb_postpush_rcsum(skb, skb->data, data->l2_len); skb_reset_mac_header(skb); + if (eth_p_mpls(skb->protocol)) { + skb->inner_network_header = skb->network_header; + skb_set_network_header(skb, data->network_offset); + skb_reset_mac_len(skb); + } + ovs_vport_send(vport, skb, data->mac_proto); return 0; } @@ -759,7 +766,7 @@ static struct dst_ops ovs_dst_ops = { * ovs_vport_output(), which is called once per fragmented packet. */ static void prepare_frag(struct vport *vport, struct sk_buff *skb, - u8 mac_proto) + u16 orig_network_offset, u8 mac_proto) { unsigned int hlen = skb_network_offset(skb); struct ovs_frag_data *data; @@ -769,6 +776,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb, data->vport = vport; data->cb = *OVS_GSO_CB(skb); data->inner_protocol = ovs_skb_get_inner_protocol(skb); + data->network_offset = orig_network_offset; data->vlan_tci = skb->vlan_tci; data->vlan_proto = skb->vlan_proto; data->mac_proto = mac_proto; @@ -783,6 +791,13 @@ static void ovs_fragment(struct net *net, struct vport *vport, struct sk_buff *skb, u16 mru, struct sw_flow_key *key) { + u16 orig_network_offset = 0; + + if (eth_p_mpls(skb->protocol)) { + orig_network_offset = skb_network_offset(skb); + skb->network_header = skb->inner_network_header; + } + if (skb_network_offset(skb) > MAX_L2_LEN) { OVS_NLERR(1, "L2 header too long to fragment"); goto err; @@ -792,7 +807,8 @@ static void ovs_fragment(struct net *net, struct vport *vport, struct dst_entry ovs_dst; unsigned long orig_dst; - prepare_frag(vport, skb, ovs_key_mac_proto(key)); + prepare_frag(vport, skb, orig_network_offset, + ovs_key_mac_proto(key)); dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_NOCOUNT); ovs_dst.dev = vport->dev; @@ -811,7 +827,7 @@ static void ovs_fragment(struct net *net, struct vport *vport, if (!v6ops) goto err; - prepare_frag(vport, skb, + prepare_frag(vport, skb, orig_network_offset, ovs_key_mac_proto(key)); memset(&ovs_rt, 0, sizeof(ovs_rt)); dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, |