From: "Thomas F. Herbert" <[email protected]> The flow structure is updated to hold the customer tci. Flow key extraction is changed to add support for ctci and both TPIDs. Parsing to support pushing and popping with both single and double tagged vlans. In response to reviewers comments on V6, all changes affected by the flow structure are gathered in this patch.
Signed-off-by: Thomas F Herbert <[email protected]> --- lib/flow.c | 22 +++--- lib/flow.h | 17 ++-- lib/match.c | 2 +- lib/nx-match.c | 2 +- lib/odp-util.c | 180 +++++++++++++++++++++++++++++++++---------- lib/odp-util.h | 2 +- lib/ofp-actions.c | 32 ++++---- lib/ofp-actions.h | 14 +++- lib/ofp-util.c | 2 +- ofproto/ofproto-dpif-rid.h | 2 +- ofproto/ofproto-dpif-xlate.c | 13 +++- 11 files changed, 213 insertions(+), 75 deletions(-) diff --git a/lib/flow.c b/lib/flow.c index e54280a..bebf496 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -119,7 +119,7 @@ struct mf_ctx { * away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are * defined as macros. */ -#if (FLOW_WC_SEQ != 31) +#if (FLOW_WC_SEQ != 32) #define MINIFLOW_ASSERT(X) ovs_assert(X) BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " "assertions enabled. Consider updating FLOW_WC_SEQ after " @@ -287,7 +287,7 @@ parse_vlan(void **datap, size_t *sizep) data_pull(datap, sizep, ETH_ADDR_LEN * 2); - if (eth->eth_type == htons(ETH_TYPE_VLAN)) { + if (eth_type_vlan(eth->eth_type)) { if (OVS_LIKELY(*sizep >= sizeof(struct qtag_prefix) + sizeof(ovs_be16))) { const struct qtag_prefix *qp = data_pull(datap, sizep, sizeof *qp); @@ -762,7 +762,7 @@ flow_unwildcard_tp_ports(const struct flow *flow, struct flow_wildcards *wc) void flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); fmd->dp_hash = flow->dp_hash; fmd->recirc_id = flow->recirc_id; @@ -918,7 +918,7 @@ void flow_wildcards_init_for_packet(struct flow_wildcards *wc, memset(&wc->masks, 0x0, sizeof wc->masks); /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); if (flow->tunnel.ip_dst) { if (flow->tunnel.flags & FLOW_TNL_F_KEY) { @@ -1017,7 +1017,7 @@ uint64_t flow_wc_map(const struct flow *flow) { /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); uint64_t map = (flow->tunnel.ip_dst) ? MINIFLOW_MAP(tunnel) : 0; @@ -1069,7 +1069,7 @@ void flow_wildcards_clear_non_packet_fields(struct flow_wildcards *wc) { /* Update this function whenever struct flow changes. */ - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata); memset(&wc->masks.regs, 0, sizeof wc->masks.regs); @@ -1628,7 +1628,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 mpls_eth_type, flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label)); /* Clear all L3 and L4 fields and dp_hash. */ - BUILD_ASSERT(FLOW_WC_SEQ == 31); + BUILD_ASSERT(FLOW_WC_SEQ == 32); memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0, sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT); flow->dp_hash = 0; @@ -1815,8 +1815,12 @@ flow_compose(struct dp_packet *p, const struct flow *flow) return; } - if (flow->vlan_tci & htons(VLAN_CFI)) { - eth_push_vlan(p, htons(ETH_TYPE_VLAN), flow->vlan_tci); + if (flow->vlan_tci & htons(VLAN_CFI) && + (flow->vlan_ctci & htons(VLAN_CFI))) { + eth_push_vlan(p, htons(ETH_TYPE_VLAN_8021Q), flow->vlan_ctci); + eth_push_vlan(p, htons(ETH_TYPE_VLAN_8021AD), flow->vlan_tci); + } else if (flow->vlan_tci & htons(VLAN_CFI)) { + eth_push_vlan(p, htons(ETH_TYPE_VLAN_8021Q), flow->vlan_tci); } if (flow->dl_type == htons(ETH_TYPE_IP)) { diff --git a/lib/flow.h b/lib/flow.h index dcb5bb0..ffe2a87 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -38,7 +38,7 @@ struct pkt_metadata; /* This sequence number should be incremented whenever anything involving flows * or the wildcarding of flows changes. This will cause build assertion * failures in places which likely need to be updated. */ -#define FLOW_WC_SEQ 31 +#define FLOW_WC_SEQ 32 /* Number of Open vSwitch extension 32-bit registers. */ #define FLOW_N_REGS 8 @@ -113,9 +113,16 @@ struct flow { uint8_t dl_dst[ETH_ADDR_LEN]; /* Ethernet destination address. */ uint8_t dl_src[ETH_ADDR_LEN]; /* Ethernet source address. */ ovs_be16 dl_type; /* Ethernet frame type. */ - ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */ + ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; If 802.1ad, + * outer tag, otherwise 0. */ + ovs_be16 vlan_ctci; /* If 802.1ad, Customer TCI | VLAN_CFI, + * inner tag, otherwise 0. */ + ovs_be16 vlan_tpid; /* Vlan protocol type, + * either 802.1ad or 802.1q. */ + uint32_t pad2; /* Pad to 64 bits. */ ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack (with padding). */ + /* L3 (64-bit aligned) */ ovs_be32 nw_src; /* IPv4 source address. */ ovs_be32 nw_dst; /* IPv4 destination address. */ @@ -130,7 +137,7 @@ struct flow { uint8_t arp_sha[ETH_ADDR_LEN]; /* ARP/ND source hardware address. */ uint8_t arp_tha[ETH_ADDR_LEN]; /* ARP/ND target hardware address. */ ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching L4. */ - ovs_be16 pad2; /* Pad to 64 bits. */ + ovs_be16 pad3; /* Pad to 64 bits. */ /* L4 (64-bit aligned) */ ovs_be16 tp_src; /* TCP/UDP/SCTP source port. */ @@ -155,8 +162,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % sizeof(uint64_t) == 0); /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */ BUILD_ASSERT_DECL(offsetof(struct flow, igmp_group_ip4) + sizeof(uint32_t) - == sizeof(struct flow_tnl) + 192 - && FLOW_WC_SEQ == 31); + == sizeof(struct flow_tnl) + 200 + && FLOW_WC_SEQ == 32); /* Incremental points at which flow classification may be performed in * segments. diff --git a/lib/match.c b/lib/match.c index 7d0b409..cab70e8 100644 --- a/lib/match.c +++ b/lib/match.c @@ -912,7 +912,7 @@ match_format(const struct match *match, struct ds *s, int priority) int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); if (priority != OFP_DEFAULT_PRIORITY) { ds_put_format(s, "priority=%d,", priority); diff --git a/lib/nx-match.c b/lib/nx-match.c index 21f291c..aed283c 100644 --- a/lib/nx-match.c +++ b/lib/nx-match.c @@ -865,7 +865,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const struct match *match, int match_len; int i; - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); /* Metadata. */ if (match->wc.masks.dp_hash) { diff --git a/lib/odp-util.c b/lib/odp-util.c index b82edb7..3f642a8 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -2939,7 +2939,7 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *flow, size_t max_mpls_depth, bool recirc, bool export_mask) { struct ovs_key_ethernet *eth_key; - size_t encap; + size_t encap = 0; const struct flow *data = export_mask ? mask : flow; nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority); @@ -2965,19 +2965,29 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const struct flow *flow, sizeof *eth_key); get_ethernet_key(data, eth_key); - if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) { - if (export_mask) { - nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX); + if (flow->vlan_tci != htons(0) || flow->vlan_ctci != htons(0) || + eth_type_vlan(flow->dl_type)) { + if (flow->vlan_tci != htons(0) || + flow->dl_type == htons(ETH_TYPE_VLAN_8021Q)) { + if (export_mask) { + nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX); + } else { + nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, + htons(ETH_TYPE_VLAN_8021Q)); + } + nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci); + encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP); + if (flow->vlan_tci == htons(0)) { + goto unencap; + } + /* Add "customer" tci if it exists at this level of nesting. */ + if (flow->vlan_ctci != htons(0) || flow->dl_type == + htons(ETH_TYPE_VLAN_8021AD)) { + nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_ctci); + } } else { - nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN)); - } - nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci); - encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP); - if (flow->vlan_tci == htons(0)) { - goto unencap; + encap = 0; } - } else { - encap = 0; } if (ntohs(flow->dl_type) < ETH_TYPE_MIN) { @@ -3626,13 +3636,13 @@ done: key, key_len); } -/* Parse 802.1Q header then encapsulated L3 attributes. */ +/* Parse 802.1AD or Q header then parse encapsulated Customer Vlan. */ static enum odp_key_fitness -parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], - uint64_t present_attrs, int out_of_range_attr, - uint64_t expected_attrs, struct flow *flow, - const struct nlattr *key, size_t key_len, - const struct flow *src_flow) +parse_8021ad_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], + uint64_t present_attrs, int out_of_range_attr, + uint64_t expected_attrs, struct flow *flow, + const struct nlattr *key, size_t key_len, + const struct flow *src_flow) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); bool is_mask = src_flow != flow; @@ -3642,6 +3652,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], ? attrs[OVS_KEY_ATTR_ENCAP] : NULL); enum odp_key_fitness encap_fitness; enum odp_key_fitness fitness; + uint16_t dl_type; /* Calculate fitness of outer attributes. */ if (!is_mask) { @@ -3658,12 +3669,18 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], fitness = check_expectations(present_attrs, out_of_range_attr, expected_attrs, key, key_len); - /* Set vlan_tci. + /* Set outertag, vlan_tci. * Remove the TPID from dl_type since it's not the real Ethertype. */ flow->dl_type = htons(0); flow->vlan_tci = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN) ? nl_attr_get_be16(attrs[OVS_KEY_ATTR_VLAN]) : htons(0)); + /* Save a copy of the TPID though. If it is 802.1AD, we know to look for + * inner ctci in encapsulated attributes. + */ + dl_type = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ETHERTYPE) + ? nl_attr_get_be16(attrs[OVS_KEY_ATTR_ETHERTYPE]) + : htons(0)); if (!is_mask) { if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN))) { return ODP_FIT_TOO_LITTLE; @@ -3674,7 +3691,7 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } return fitness; } else if (!(flow->vlan_tci & htons(VLAN_CFI))) { - VLOG_ERR_RL(&rl, "OVS_KEY_ATTR_VLAN 0x%04"PRIx16" is nonzero " + VLOG_ERR_RL(&rl, "Outer OVS_KEY_ATTR_VLAN 0x%04"PRIx16" is nonzero " "but CFI bit is not set", ntohs(flow->vlan_tci)); return ODP_FIT_ERROR; } @@ -3691,6 +3708,13 @@ parse_8021q_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1], } expected_attrs = 0; + if (dl_type == htons(ETH_TYPE_VLAN_8021AD)) { + /* Get inner vlan tag from the encapsulated attributes. */ + flow->vlan_ctci = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN) + ? nl_attr_get_be16(attrs[OVS_KEY_ATTR_VLAN]) + : htons(0)); + } + if (!parse_ethertype(attrs, present_attrs, &expected_attrs, flow, src_flow)) { return ODP_FIT_ERROR; } @@ -3777,7 +3801,7 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ETHERNET; } - /* Get Ethertype or 802.1Q TPID or FLOW_DL_TYPE_NONE. */ + /* Get Ethertype or VLAN TPID or FLOW_DL_TYPE_NONE. */ if (!parse_ethertype(attrs, present_attrs, &expected_attrs, flow, src_flow)) { return ODP_FIT_ERROR; @@ -3785,9 +3809,9 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t key_len, if (is_mask ? (src_flow->vlan_tci & htons(VLAN_CFI)) != 0 - : src_flow->dl_type == htons(ETH_TYPE_VLAN)) { - return parse_8021q_onward(attrs, present_attrs, out_of_range_attr, - expected_attrs, flow, key, key_len, src_flow); + : eth_type_vlan(src_flow->dl_type)) { + return parse_8021ad_onward(attrs, present_attrs, out_of_range_attr, + expected_attrs, flow, key, key_len, src_flow); } if (is_mask) { flow->vlan_tci = htons(0xffff); @@ -4025,37 +4049,115 @@ commit_set_ether_addr_action(const struct flow *flow, struct flow *base_flow, put_ethernet_key(&mask, &wc->masks); } } - +static int +flow_get_vlan_depth(const struct flow *flow) +{ + int n = 0; + if (flow->vlan_tci & htons(VLAN_CFI)) + n++; + if (flow->vlan_ctci & htons(VLAN_CFI)) + n++; + return n; +} static void pop_vlan(struct flow *base, struct ofpbuf *odp_actions, struct flow_wildcards *wc) { + int base_n = flow_get_vlan_depth(base); + + if (base_n == 0) + return; + memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); - if (base->vlan_tci & htons(VLAN_CFI)) { - nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN); + if (base_n == 1) { + base->vlan_tci = 0; + base->vlan_tpid = 0; + base->vlan_ctci = 0; + + } else if (base_n ==2) { + + base->vlan_tci = base->vlan_ctci; + base->vlan_ctci = 0; + base->vlan_tpid = htons(ETH_TYPE_VLAN_8021Q); } + nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN); } static void -commit_vlan_action(ovs_be16 vlan_tci, struct flow *base, - struct ofpbuf *odp_actions, struct flow_wildcards *wc) +push_vlan(struct flow *base, ovs_be16 vlan_tci, ovs_be16 vlan_tpid, + struct ofpbuf *odp_actions, struct flow_wildcards *wc) { - if (base->vlan_tci == vlan_tci) { + struct ovs_action_push_vlan vlan; + int base_n; + ovs_be16 tpid = htons(ETH_TYPE_VLAN_8021Q); + + if (!(vlan_tci & htons(VLAN_CFI))) return; - } - pop_vlan(base, odp_actions, wc); - if (vlan_tci & htons(VLAN_CFI)) { - struct ovs_action_push_vlan vlan; + memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci); - vlan.vlan_tpid = htons(ETH_TYPE_VLAN); - vlan.vlan_tci = vlan_tci; - nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN, - &vlan, sizeof vlan); + + base_n = flow_get_vlan_depth(base); + + if (base_n == 2) { + return; + } else if (base_n == 1) { + if (!vlan_tpid) { + tpid = htons(ETH_TYPE_VLAN_8021AD); + } else { + tpid = vlan_tpid; + } + base->vlan_ctci = base->vlan_tci; + } else if (base_n == 0) { + if (!vlan_tpid) { + tpid = htons(ETH_TYPE_VLAN_8021Q); + } else { + tpid = vlan_tpid; + } + base->vlan_ctci = 0; } base->vlan_tci = vlan_tci; + base->vlan_tpid = tpid; + + vlan.vlan_tpid = tpid; + vlan.vlan_tci = vlan_tci; + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN, + &vlan, sizeof vlan); +} + +static void +commit_vlan_action(const struct flow *flow, struct flow *base, + struct ofpbuf *odp_actions, struct flow_wildcards *wc) +{ + ovs_be16 vlan_tci = flow->vlan_tci; + ovs_be16 vlan_tpid = flow->vlan_tpid; + int base_n; + int flow_n; + + + if ((base->vlan_tci == vlan_tci) && (base->vlan_ctci == vlan_tci)) + return; + + base_n = flow_get_vlan_depth(base); + flow_n = flow_get_vlan_depth(flow); + + + if (flow_n == base_n) { + if (vlan_tci == base->vlan_tci) { + return; + } else { + pop_vlan(base, odp_actions, wc); + push_vlan(base, vlan_tci, vlan_tpid, odp_actions, wc); + } + } + else if (flow_n > base_n) { + push_vlan(base, vlan_tci, vlan_tpid, odp_actions, wc); + } + else if (flow_n < base_n) { + pop_vlan(base, odp_actions, wc); + } } /* Wildcarding already done at action translation time. */ @@ -4444,7 +4546,7 @@ commit_odp_actions(const struct flow *flow, struct flow *base, slow = commit_set_nw_action(flow, base, odp_actions, wc, use_masked); commit_set_port_action(flow, base, odp_actions, wc, use_masked); commit_mpls_action(flow, base, odp_actions); - commit_vlan_action(flow->vlan_tci, base, odp_actions, wc); + commit_vlan_action(flow, base, odp_actions, wc); commit_set_priority_action(flow, base, odp_actions, wc, use_masked); commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked); diff --git a/lib/odp-util.h b/lib/odp-util.h index 4f0e794..94c1d41 100644 --- a/lib/odp-util.h +++ b/lib/odp-util.h @@ -135,7 +135,7 @@ void odp_portno_names_destroy(struct hmap *portno_names); * add another field and forget to adjust this value. */ #define ODPUTIL_FLOW_KEY_BYTES 512 -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow * key. An array of "struct nlattr" might not, in theory, be sufficiently diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index 2240b86..906ce8f 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -1269,16 +1269,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) { @@ -1286,7 +1290,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); } } @@ -1298,25 +1302,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. */ @@ -5474,8 +5478,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. */ @@ -6113,6 +6118,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 785c814..0314da3 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") \ @@ -395,7 +395,15 @@ struct ofpact_set_field { union mf_value mask; }; -/* OFPACT_PUSH_VLAN/MPLS/PBB +/* OFPACT_PUSH_VLAN + * + * Used for OFPAT11_PUSH_VLAN. */ +struct ofpact_push_vlan { + struct ofpact ofpact; + ovs_be16 ethertype; +}; + +/* OFPACT_PUSH_MPLS * * Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */ struct ofpact_push_mpls { @@ -405,7 +413,7 @@ struct ofpact_push_mpls { /* OFPACT_POP_MPLS * - * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */ + * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS. */ struct ofpact_pop_mpls { struct ofpact ofpact; ovs_be16 ethertype; diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 277fdfe..f5c28b1 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -195,7 +195,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask) void ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc) { - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); /* Initialize most of wc. */ flow_wildcards_init_catchall(wc); diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h index 81a61a2..dc533ce 100644 --- a/ofproto/ofproto-dpif-rid.h +++ b/ofproto/ofproto-dpif-rid.h @@ -91,7 +91,7 @@ struct rule; /* Metadata for restoring pipeline context after recirculation. Helpers * are inlined below to keep them together with the definition for easier * updates. */ -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 31); +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); struct recirc_metadata { /* Metadata in struct flow. */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 55ae683..528b509 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -2749,6 +2749,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; @@ -2757,7 +2758,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 == 31); + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 32); memset(&flow_tnl, 0, sizeof flow_tnl); if (!xport) { @@ -2892,6 +2893,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; @@ -3010,6 +3012,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; } @@ -4169,6 +4172,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: -- 2.1.0 _______________________________________________ dev mailing list [email protected] http://openvswitch.org/mailman/listinfo/dev
