Signed-off-by: Tom Herbert <thomasfherb...@gmail.com> --- NEWS | 1 + datapath/actions.c | 16 ++++++++++++---- datapath/flow_netlink.c | 15 +++++++++++++-- include/linux/openvswitch.h | 12 ++++++------ lib/odp-execute.c | 2 +- lib/odp-util.c | 2 +- lib/ofp-parse.c | 3 ++- lib/packets.c | 5 +++-- 8 files changed, 39 insertions(+), 17 deletions(-)
diff --git a/NEWS b/NEWS index 7925598..efd079c 100644 --- a/NEWS +++ b/NEWS @@ -16,6 +16,7 @@ Post-v2.1.0 - Support for Linux kernels up to 3.13. From Kernel 3.12 onwards OVS uses tunnel API for GRE and VXLAN. - Added DPDK support. + - Added support for 802.1qad v2.1.0 - xx xxx xxxx diff --git a/datapath/actions.c b/datapath/actions.c index 0b66e7c..771a444 100644 --- a/datapath/actions.c +++ b/datapath/actions.c @@ -84,8 +84,9 @@ static int pop_vlan(struct sk_buff *skb) if (likely(vlan_tx_tag_present(skb))) { vlan_set_tci(skb, 0); } else { - if (unlikely(skb->protocol != htons(ETH_P_8021Q) || - skb->len < VLAN_ETH_HLEN)) + if (unlikely(((skb->protocol != htons(ETH_P_8021Q)) && + (skb->protocol != htons(ETH_P_8021AD))) || + (skb->len < VLAN_ETH_HLEN))) return 0; err = __pop_vlan_tci(skb, &tci); @@ -101,7 +102,11 @@ static int pop_vlan(struct sk_buff *skb) if (unlikely(err)) return err; - __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci)); + if (unlikely(skb->protocol == htons(ETH_P_8021AD))) + __vlan_put_tag(skb, htons(ETH_P_8021AD), ntohs(tci)); + else + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(tci)); + return 0; } @@ -121,7 +126,10 @@ static int push_vlan(struct sk_buff *skb, const struct ovs_action_push_vlan *vla + (2 * ETH_ALEN), VLAN_HLEN, 0)); } - __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); + if (likely(vlan->vlan_tpid == htons(ETH_P_8021Q))) + __vlan_hwaccel_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); + else + __vlan_put_tag(skb, vlan->vlan_tpid, ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); return 0; } diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index 5c32cd0..22cfa65 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -748,7 +748,8 @@ int ovs_nla_get_match(struct sw_flow_match *match, if ((key_attrs & (1ULL << OVS_KEY_ATTR_ETHERNET)) && (key_attrs & (1ULL << OVS_KEY_ATTR_ETHERTYPE)) && - (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q))) { + ((nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021Q)) || + (nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]) == htons(ETH_P_8021AD)))) { __be16 tci; if (!((key_attrs & (1ULL << OVS_KEY_ATTR_VLAN)) && @@ -922,6 +923,15 @@ int ovs_nla_put_flow(const struct sw_flow_key *swkey, encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP); if (!swkey->eth.tci) goto unencap; + } else if (swkey->eth.tci || swkey->eth.type == htons(ETH_P_8021AD)) { + __be16 eth_type; + eth_type = !is_mask ? htons(ETH_P_8021AD) : htons(0xffff); + if (nla_put_be16(skb, OVS_KEY_ATTR_ETHERTYPE, eth_type) || + nla_put_be16(skb, OVS_KEY_ATTR_VLAN, output->eth.tci)) + goto nla_put_failure; + encap = nla_nest_start(skb, OVS_KEY_ATTR_ENCAP); + if (!swkey->eth.tci) + goto unencap; } else encap = NULL; @@ -1455,7 +1465,8 @@ int ovs_nla_copy_actions(const struct nlattr *attr, case OVS_ACTION_ATTR_PUSH_VLAN: vlan = nla_data(a); - if (vlan->vlan_tpid != htons(ETH_P_8021Q)) + if ((vlan->vlan_tpid != htons(ETH_P_8021Q)) && + (vlan->vlan_tpid != htons(ETH_P_8021AD))) return -EINVAL; if (!(vlan->vlan_tci & htons(VLAN_TAG_PRESENT))) return -EINVAL; diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h index a88f6f1..5a82970 100644 --- a/include/linux/openvswitch.h +++ b/include/linux/openvswitch.h @@ -525,14 +525,14 @@ struct ovs_action_push_mpls { * @vlan_tci: Tag control identifier (TCI) to push. The CFI bit must be set * (but it will not be set in the 802.1Q header that is pushed). * - * The @vlan_tpid value is typically %ETH_P_8021Q. The only acceptable TPID - * values are those that the kernel module also parses as 802.1Q headers, to + * The @vlan_tpid value is typically %ETH_P_8021Q or %ETH_P_8021AD. The only acceptable + * TPID values are those that the kernel module also parses as 802.1Q headers, to * prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by %OVS_ACTION_ATTR_POP_VLAN * from having surprising results. */ struct ovs_action_push_vlan { - __be16 vlan_tpid; /* 802.1Q TPID. */ - __be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */ + __be16 vlan_tpid; /* 802.1Q or 802.1ad TPID. */ + __be16 vlan_tci; /* 802.1Q or 802.1ad TCI (VLAN ID and priority). */ }; /* Data path hash algorithm for computing Datapath hash. @@ -565,9 +565,9 @@ struct ovs_action_recirc { * @OVS_ACTION_ATTR_OUTPUT: Output packet to port. * @OVS_ACTION_ATTR_USERSPACE: Send packet to userspace according to nested * %OVS_USERSPACE_ATTR_* attributes. - * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the + * @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q or 802.1ad header onto the * packet. - * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet. + * @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q or 802.1ad header off the packet. * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in * the nested %OVS_SAMPLE_ATTR_* attributes. * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header. The diff --git a/lib/odp-execute.c b/lib/odp-execute.c index 37e44e3..c9c101a 100644 --- a/lib/odp-execute.c +++ b/lib/odp-execute.c @@ -220,7 +220,7 @@ odp_execute_actions__(void *dp, struct ofpbuf *packet, bool steal, case OVS_ACTION_ATTR_PUSH_VLAN: { const struct ovs_action_push_vlan *vlan = nl_attr_get(a); - eth_push_vlan(packet, htons(ETH_TYPE_VLAN), vlan->vlan_tci); + eth_push_vlan(packet, vlan->vlan_tpid, vlan->vlan_tci); break; } diff --git a/lib/odp-util.c b/lib/odp-util.c index b58f1c0..dd32b09 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -432,7 +432,7 @@ format_odp_action(struct ds *ds, const struct nlattr *a) case OVS_ACTION_ATTR_PUSH_VLAN: vlan = nl_attr_get(a); ds_put_cstr(ds, "push_vlan("); - if (vlan->vlan_tpid != htons(ETH_TYPE_VLAN)) { + if (vlan->vlan_tpid != htons(ETH_TYPE_VLAN_8021Q)) { ds_put_format(ds, "tpid=0x%04"PRIx16",", ntohs(vlan->vlan_tpid)); } format_vlan_tci(ds, vlan->vlan_tci); diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index d250042..27bf0f0 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -704,7 +704,8 @@ parse_named_action(enum ofputil_action_code code, return error; } - if (ethertype != ETH_TYPE_VLAN_8021Q) { + if ((ethertype != ETH_TYPE_VLAN_8021Q) && + (ethertype != ETH_TYPE_VLAN_8021AD)) { /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */ return xasprintf("%s: not a valid VLAN ethertype", arg); } diff --git a/lib/packets.c b/lib/packets.c index 6244c3f..997bac6 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -198,8 +198,9 @@ eth_pop_vlan(struct ofpbuf *packet) { struct vlan_eth_header *veh = ofpbuf_l2(packet); - if (veh && ofpbuf_size(packet) >= sizeof *veh - && veh->veth_type == htons(ETH_TYPE_VLAN)) { + if (veh && ofpbuf_size(packet) >= sizeof *veh && + ((veh->veth_type == htons(ETH_TYPE_VLAN_8021Q)) || + ((veh->veth_type == htons(ETH_TYPE_VLAN_8021AD))))) { memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN); ofpbuf_resize_l2(packet, -VLAN_HEADER_LEN); -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev