This patch changes the actions processing to support popping and pushing of double stacked vlans (qinq.)
Signed-off-by: Thomas F Herbert <thomasfherb...@entpnt.com> --- lib/ofp-actions.c | 32 +++++++++++++++++++------------- lib/ofp-actions.h | 9 ++++++++- lib/packets.c | 2 +- lib/packets.h | 7 +++++++ ofproto/ofproto-dpif-xlate.c | 13 ++++++++++++- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 4680d81..7414a78 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -1266,16 +1266,20 @@ format_STRIP_VLAN(const struct ofpact_null *a, struct ds *s) static enum ofperr decode_OFPAT_RAW11_PUSH_VLAN(ovs_be16 eth_type, struct ofpbuf *out) { - if (eth_type != htons(ETH_TYPE_VLAN_8021Q)) { - /* XXX 802.1AD(QinQ) isn't supported at the moment */ + struct ofpact_push_vlan *oam; + + if (!eth_type_vlan(eth_type)) { + /* XXX Only 802.1q and 802.1AD(QinQ) is supported. */ return OFPERR_OFPBAC_BAD_ARGUMENT; } - ofpact_put_PUSH_VLAN(out); + oam = ofpact_put_PUSH_VLAN(out); + oam->ethertype = eth_type; + return 0; } static void -encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED, +encode_PUSH_VLAN(const struct ofpact_push_vlan *push_vlan, enum ofp_version ofp_version, struct ofpbuf *out) { if (ofp_version == OFP10_VERSION) { @@ -1283,7 +1287,7 @@ encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED, * follow this action. */ } else { /* XXX ETH_TYPE_VLAN_8021AD case */ - put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q)); + put_OFPAT11_PUSH_VLAN(out, push_vlan->ethertype); } } @@ -1295,25 +1299,25 @@ parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts, char *error; *usable_protocols &= OFPUTIL_P_OF11_UP; - error = str_to_u16(arg, "ethertype", ðertype); + error = str_to_u16(arg, "push_vlan", ðertype); if (error) { return error; } - if (ethertype != ETH_TYPE_VLAN_8021Q) { - /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */ + if (!eth_type_vlan(htons(ethertype))) { + /* Check for valid VLAN ethertypes */ return xasprintf("%s: not a valid VLAN ethertype", arg); } - ofpact_put_PUSH_VLAN(ofpacts); + ofpact_put_PUSH_VLAN(ofpacts)->ethertype = htons(ethertype); return NULL; } static void -format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s) +format_PUSH_VLAN(const struct ofpact_push_vlan *a OVS_UNUSED, struct ds *s) { /* XXX 802.1AD case*/ - ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q); + ds_put_format(s, "push_vlan:%#"PRIx16, ntohs(a->ethertype)); } /* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */ @@ -5357,8 +5361,9 @@ ofpact_check__(enum ofputil_protocol *usable_protocols, struct ofpact *a, return 0; case OFPACT_PUSH_VLAN: - if (flow->vlan_tci & htons(VLAN_CFI)) { - /* Multiple VLAN headers not supported. */ + if (flow->vlan_tci & htons(VLAN_CFI) && + flow->vlan_ctci & htons(VLAN_CFI)) { + /* More then 2 levels of VLAN headers not supported. */ return OFPERR_OFPBAC_BAD_TAG; } /* Temporary mark that we have a vlan tag. */ @@ -5971,6 +5976,7 @@ ofpacts_get_meter(const struct ofpact ofpacts[], size_t ofpacts_len) /* Formatting ofpacts. */ + static void ofpact_format(const struct ofpact *a, struct ds *s) { diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index 8362aa8..6c55356 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -66,7 +66,7 @@ OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact, "set_vlan_vid") \ OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact, "set_vlan_pcp") \ OFPACT(STRIP_VLAN, ofpact_null, ofpact, "strip_vlan") \ - OFPACT(PUSH_VLAN, ofpact_null, ofpact, "push_vlan") \ + OFPACT(PUSH_VLAN, ofpact_push_vlan, ofpact, "push_vlan") \ OFPACT(SET_ETH_SRC, ofpact_mac, ofpact, "mod_dl_src") \ OFPACT(SET_ETH_DST, ofpact_mac, ofpact, "mod_dl_dst") \ OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact, "mod_nw_src") \ @@ -401,6 +401,13 @@ struct ofpact_push_mpls { ovs_be16 ethertype; }; +/* OFPACT_PUSH_VLAN + * + * Used for OFPAT11_PUSH_VLAN. */ +struct ofpact_push_vlan { + struct ofpact ofpact; + ovs_be16 ethertype; +}; /* OFPACT_POP_MPLS * * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */ diff --git a/lib/packets.c b/lib/packets.c index af99e3b..f5b4526 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -217,7 +217,7 @@ set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type) return; } - if (eh->eth_type == htons(ETH_TYPE_VLAN)) { + if (eth_type_vlan(eh->eth_type)) { ovs_be16 *p; char *l2_5 = ofpbuf_l2_5(packet); diff --git a/lib/packets.h b/lib/packets.h index 65d2274..b6596bd 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -252,6 +252,13 @@ static inline bool eth_type_mpls(ovs_be16 eth_type) eth_type == htons(ETH_TYPE_MPLS_MCAST); } +static inline bool eth_type_vlan(ovs_be16 eth_type) +{ + return eth_type == htons(ETH_TYPE_VLAN_8021Q) || + eth_type == htons(ETH_TYPE_VLAN_8021AD); +} + + /* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame * lengths. */ #define ETH_TYPE_MIN 0x600 diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 4a5b7fd..97ef9fe 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2627,6 +2627,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, struct flow *flow = &ctx->xin->flow; struct flow_tnl flow_tnl; ovs_be16 flow_vlan_tci; + ovs_be16 flow_vlan_ctci; uint32_t flow_pkt_mark; uint8_t flow_nw_tos; odp_port_t out_port, odp_port; @@ -2635,7 +2636,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, /* If 'struct flow' gets additional metadata, we'll need to zero it out * before traversing a patch port. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 29); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 30); memset(&flow_tnl, 0, sizeof flow_tnl); if (!xport) { @@ -2732,6 +2733,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, } flow_vlan_tci = flow->vlan_tci; + flow_vlan_ctci = flow->vlan_ctci; flow_pkt_mark = flow->pkt_mark; flow_nw_tos = flow->nw_tos; @@ -2851,6 +2853,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t ofp_port, out: /* Restore flow */ flow->vlan_tci = flow_vlan_tci; + flow->vlan_ctci = flow_vlan_ctci; flow->pkt_mark = flow_pkt_mark; flow->nw_tos = flow_nw_tos; } @@ -3877,6 +3880,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t ofpacts_len, /* XXX 802.1AD(QinQ) */ memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); flow->vlan_tci = htons(VLAN_CFI); + if (ofpact_get_PUSH_VLAN(a)->ethertype == htons(ETH_TYPE_VLAN_8021AD)) { + memset(&wc->masks.vlan_ctci, 0xff, sizeof wc->masks.vlan_ctci); + flow->vlan_ctci |= htons(VLAN_CFI); + memset(&wc->masks.vlan_tpid, 0xff, sizeof wc->masks.vlan_tpid); + flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021AD); + } else if (ofpact_get_PUSH_VLAN(a)->ethertype == htons(ETH_TYPE_VLAN_8021Q)) { + flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021Q); + } break; case OFPACT_SET_ETH_SRC: -- 1.8.3.2 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev