Skip to content

Commit

Permalink
datapath: pass mac_proto to ovs_vport_send
Browse files Browse the repository at this point in the history
Upstream commit:
    commit e2d9d8358cb961340ef88620b6a25ba4557033d5
    Author: Jiri Benc <[email protected]>
    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 <[email protected]>
    Acked-by: Pravin B Shelar <[email protected]>
    Signed-off-by: David S. Miller <[email protected]>

[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 <[email protected]>
Signed-off-by: Joe Stringer <[email protected]>
  • Loading branch information
yi-y-yang authored and joestringer committed Mar 2, 2017
1 parent 16d7640 commit f80d052
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 14 deletions.
29 changes: 17 additions & 12 deletions datapath/actions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
};

Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand All @@ -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);

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion datapath/vport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion datapath/vport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

0 comments on commit f80d052

Please sign in to comment.