From f80d052433f9cebd0bd4ef0af50e5cdc4b1a3af6 Mon Sep 17 00:00:00 2001 From: "Yang, Yi Y" Date: Mon, 6 Feb 2017 21:04:37 +0800 Subject: [PATCH] datapath: pass mac_proto to ovs_vport_send Upstream commit: commit e2d9d8358cb961340ef88620b6a25ba4557033d5 Author: Jiri Benc Date: Thu Nov 10 16:28:19 2016 +0100 openvswitch: pass mac_proto to ovs_vport_send We'll need it to alter packets sent to ARPHRD_NONE interfaces. Change do_output() to use the actual L2 header size of the packet when deciding on the minimum cutlen. The assumption here is that what matters is not the output interface hard_header_len but rather the L2 header of the particular packet. For example, ARPHRD_NONE tunnels that encapsulate Ethernet should get at least the Ethernet header. Signed-off-by: Jiri Benc Acked-by: Pravin B Shelar Signed-off-by: David S. Miller [Committer notes] This is not identical to upstream, because the OVS tree is missing upstream commit c66549ffd666 ("openvswitch: correctly fragment packet with mpls headers") Signed-off-by: Yi Yang Signed-off-by: Joe Stringer --- datapath/actions.c | 29 +++++++++++++++++------------ datapath/vport.c | 2 +- datapath/vport.h | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/datapath/actions.c b/datapath/actions.c index c47aa3de3e1..c5b5b0ee86e 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -64,6 +64,7 @@ struct ovs_frag_data { __u16 vlan_tci; __be16 vlan_proto; unsigned int l2_len; + u8 mac_proto; u8 l2_data[MAX_L2_LEN]; }; @@ -661,7 +662,7 @@ static int ovs_vport_output(OVS_VPORT_OUTPUT_PARAMS) skb_postpush_rcsum(skb, skb->data, data->l2_len); skb_reset_mac_header(skb); - ovs_vport_send(vport, skb); + ovs_vport_send(vport, skb, data->mac_proto); return 0; } @@ -679,7 +680,8 @@ static struct dst_ops ovs_dst_ops = { /* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is * ovs_vport_output(), which is called once per fragmented packet. */ -static void prepare_frag(struct vport *vport, struct sk_buff *skb) +static void prepare_frag(struct vport *vport, struct sk_buff *skb, + u8 mac_proto) { unsigned int hlen = skb_network_offset(skb); struct ovs_frag_data *data; @@ -691,6 +693,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb) data->inner_protocol = ovs_skb_get_inner_protocol(skb); data->vlan_tci = skb->vlan_tci; data->vlan_proto = skb->vlan_proto; + data->mac_proto = mac_proto; data->l2_len = hlen; memcpy(&data->l2_data, skb->data, hlen); @@ -699,18 +702,19 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb) } static void ovs_fragment(struct net *net, struct vport *vport, - struct sk_buff *skb, u16 mru, __be16 ethertype) + struct sk_buff *skb, u16 mru, + struct sw_flow_key *key) { if (skb_network_offset(skb) > MAX_L2_LEN) { OVS_NLERR(1, "L2 header too long to fragment"); goto err; } - if (ethertype == htons(ETH_P_IP)) { + if (key->eth.type == htons(ETH_P_IP)) { struct dst_entry ovs_dst; unsigned long orig_dst; - prepare_frag(vport, skb); + prepare_frag(vport, skb, ovs_key_mac_proto(key)); dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_NOCOUNT); ovs_dst.dev = vport->dev; @@ -721,7 +725,7 @@ static void ovs_fragment(struct net *net, struct vport *vport, ip_do_fragment(net, skb->sk, skb, ovs_vport_output); refdst_drop(orig_dst); - } else if (ethertype == htons(ETH_P_IPV6)) { + } else if (key->eth.type == htons(ETH_P_IPV6)) { const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops(); unsigned long orig_dst; struct rt6_info ovs_rt; @@ -730,7 +734,8 @@ static void ovs_fragment(struct net *net, struct vport *vport, goto err; } - prepare_frag(vport, skb); + prepare_frag(vport, skb, + ovs_key_mac_proto(key)); memset(&ovs_rt, 0, sizeof(ovs_rt)); dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_NOCOUNT); @@ -747,7 +752,7 @@ static void ovs_fragment(struct net *net, struct vport *vport, refdst_drop(orig_dst); } else { WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", - ovs_vport_name(vport), ntohs(ethertype), mru, + ovs_vport_name(vport), ntohs(key->eth.type), mru, vport->dev->mtu); goto err; } @@ -767,19 +772,19 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, u32 cutlen = OVS_CB(skb)->cutlen; if (unlikely(cutlen > 0)) { - if (skb->len - cutlen > ETH_HLEN) + if (skb->len - cutlen > ovs_mac_header_len(key)) pskb_trim(skb, skb->len - cutlen); else - pskb_trim(skb, ETH_HLEN); + pskb_trim(skb, ovs_mac_header_len(key)); } if (likely(!mru || (skb->len <= mru + vport->dev->hard_header_len))) { - ovs_vport_send(vport, skb); + ovs_vport_send(vport, skb, ovs_key_mac_proto(key)); } else if (mru <= vport->dev->mtu) { struct net *net = ovs_dp_get_net(dp); - ovs_fragment(net, vport, skb, mru, key->eth.type); + ovs_fragment(net, vport, skb, mru, key); } else { OVS_NLERR(true, "Cannot fragment IP frames"); kfree_skb(skb); diff --git a/datapath/vport.c b/datapath/vport.c index adec447d86d..6169c2369fb 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -525,7 +525,7 @@ static unsigned int packet_length(const struct sk_buff *skb, return length; } -void ovs_vport_send(struct vport *vport, struct sk_buff *skb) +void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto) { int mtu = vport->dev->mtu; diff --git a/datapath/vport.h b/datapath/vport.h index d14908fe8da..d630c34bc8a 100644 --- a/datapath/vport.h +++ b/datapath/vport.h @@ -200,6 +200,6 @@ int __ovs_vport_ops_register(struct vport_ops *ops); }) void ovs_vport_ops_unregister(struct vport_ops *ops); -void ovs_vport_send(struct vport *vport, struct sk_buff *skb); +void ovs_vport_send(struct vport *vport, struct sk_buff *skb, u8 mac_proto); #endif /* vport.h */