On Thu, Mar 16, 2017 at 03:23:38PM -0700, Ben Pfaff wrote: > On Wed, Mar 01, 2017 at 05:47:59PM -0500, Eric Garver wrote: > > Flow key handling changes: > > - Add VLAN header array in struct flow, to record multiple 802.1q VLAN > > headers. > > - Add dpif multi-VLAN capability probing. If datapath supports > > multi-VLAN, increase the maximum depth of nested OVS_KEY_ATTR_ENCAP. > > > > Refactor VLAN handling in dpif-xlate: > > - Introduce 'xvlan' to track VLAN stack during flow processing. > > - Input and output VLAN translation according to the xbundle type. > > > > Push VLAN action support: > > - Allow ethertype 0x88a8 in VLAN headers and push_vlan action. > > - Support push_vlan on dot1q packets. > > > > Use other_config:vlan-limit in table Open_vSwitch to limit maximum VLANs > > that can be matched. This allows us to preserve backwards compatibility. > > > > Add test cases for VLAN depth limit, Multi-VLAN actions and QinQ VLAN > > handling > > > > Co-authored-by: Thomas F Herbert <thomasfherb...@gmail.com> > > Signed-off-by: Thomas F Herbert <thomasfherb...@gmail.com> > > Co-authored-by: Xiao Liang <shaw.l...@gmail.com> > > Signed-off-by: Xiao Liang <shaw.l...@gmail.com> > > Signed-off-by: Eric Garver <e...@erig.me> > > Thanks for all the iteration on this patch. > > I've folded in the following incremental and applied this to master.
Great! Thanks for the feedback and clean ups. Do you intend to take the tests as well? The macro OVS_CHECK_8021AD() probably needs adjusted due the incremental below. The dot1q-tunnel patches should stand on their own and can be re-spun if needed. > > Some reasoning for my changes: > > - I changed the ROUND_UP in struct flow to a build assertion that > FLOW_MAX_VLAN_HEADERS is a multiple of 2 because we have a fair > number of cases where we memcpy an array of FLOW_MAX_VLAN_HEADERS > elements to or from vlans[]. That was going to be risky if we ever > used "sizeof" on the vlans[] member and FLOW_MAX_VLAN_HEADERS was > not a multiple of 2, because it would copy too many bytes. So, on > balance, it seemed safer this way. Understood. Thanks for the cleanup. > (Maybe we should do the same thing for mpls_lse.) > > - Some style improvements, mostly related to ?: and to moving variable > declarations closer to first use. > > - I reverted the change to vswitch.ovsschema since it only updated the > version without any other changes. I think that was remnant of when the dot1q-tunnel was part of this patch. I guess I missed that when I split them. > - I made the documentation more explicit. > > It seems that I made a few other minor changes while I was fixing up > rebase conflicts, most notably making the NEWS item shorter. Those > aren't in the diff below (sorry about that). > > --8<--------------------------cut here-------------------------->8-- > > diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h > index e7622af8f4ae..188467dc42d5 100644 > --- a/include/openvswitch/flow.h > +++ b/include/openvswitch/flow.h > @@ -23,7 +23,7 @@ > /* 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 37 > +#define FLOW_WC_SEQ 38 > > /* Number of Open vSwitch extension 32-bit registers. */ > #define FLOW_N_REGS 16 > @@ -64,8 +64,12 @@ const char *flow_tun_flag_to_string(uint32_t flags); > /* Maximum number of supported SAMPLE action nesting. */ > #define FLOW_MAX_SAMPLE_NESTING 10 > > -/* Maximum number of supported VLAN headers. */ > +/* Maximum number of supported VLAN headers. > + * > + * We require this to be a multiple of 2 so that vlans[] in struct flow is a > + * multiple of 64 bits. */ > #define FLOW_MAX_VLAN_HEADERS 2 > +BUILD_ASSERT_DECL(FLOW_MAX_VLAN_HEADERS % 2 == 0); > > /* Legacy maximum VLAN headers */ > #define LEGACY_MAX_VLAN_HEADERS 1 > @@ -114,7 +118,7 @@ struct flow { > struct eth_addr dl_src; /* Ethernet source address. */ > ovs_be16 dl_type; /* Ethernet frame type. */ > uint8_t pad2[2]; /* Pad to 64 bits. */ > - union flow_vlan_hdr vlans[ROUND_UP(FLOW_MAX_VLAN_HEADERS, 2)]; /* VLANs > */ > + union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; /* VLANs */ > ovs_be32 mpls_lse[ROUND_UP(FLOW_MAX_MPLS_LABELS, 2)]; /* MPLS label stack > (with padding). > */ > /* L3 (64-bit aligned) */ > @@ -154,7 +158,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow_tnl) % > 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) + 300 > - && FLOW_WC_SEQ == 37); > + && FLOW_WC_SEQ == 38); > > /* Incremental points at which flow classification may be performed in > * segments. > diff --git a/lib/flow.c b/lib/flow.c > index 35693f830e45..f628526657de 100644 > --- a/lib/flow.c > +++ b/lib/flow.c > @@ -125,7 +125,7 @@ struct mf_ctx { > * away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are > * defined as macros. */ > > -#if (FLOW_WC_SEQ != 37) > +#if (FLOW_WC_SEQ != 38) > #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 " > @@ -337,7 +337,6 @@ parse_mpls(const void **datap, size_t *sizep) > static inline ALWAYS_INLINE size_t > parse_vlan(const void **datap, size_t *sizep, union flow_vlan_hdr *vlan_hdrs) > { > - size_t encaps; > const ovs_be16 *eth_type; > > memset(vlan_hdrs, 0, sizeof(union flow_vlan_hdr) * > FLOW_MAX_VLAN_HEADERS); > @@ -345,20 +344,18 @@ parse_vlan(const void **datap, size_t *sizep, union > flow_vlan_hdr *vlan_hdrs) > > eth_type = *datap; > > - for (encaps = 0; > - eth_type_vlan(*eth_type) && encaps < flow_vlan_limit; > - encaps++) { > - const ovs_16aligned_be32 *qp; > - > + size_t n; > + for (n = 0; eth_type_vlan(*eth_type) && n < flow_vlan_limit; n++) { > if (OVS_UNLIKELY(*sizep < sizeof(ovs_be32) + sizeof(ovs_be16))) { > break; > } > - qp = data_pull(datap, sizep, sizeof *qp); > - vlan_hdrs[encaps].qtag = get_16aligned_be32(qp); > - vlan_hdrs[encaps].tci |= htons(VLAN_CFI); > + > + const ovs_16aligned_be32 *qp = data_pull(datap, sizep, sizeof *qp); > + vlan_hdrs[n].qtag = get_16aligned_be32(qp); > + vlan_hdrs[n].tci |= htons(VLAN_CFI); > eth_type = *datap; > } > - return encaps; > + return n; > } > > static inline ALWAYS_INLINE ovs_be16 > @@ -636,14 +633,14 @@ miniflow_extract(struct dp_packet *packet, struct > miniflow *dst) > if (OVS_UNLIKELY(size < sizeof(struct eth_header))) { > goto out; > } else { > - union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; > - size_t num_vlans; > - > /* Link layer. */ > ASSERT_SEQUENTIAL(dl_dst, dl_src); > miniflow_push_macs(mf, dl_dst, data); > + > /* VLAN */ > - num_vlans = parse_vlan(&data, &size, vlans); > + union flow_vlan_hdr vlans[FLOW_MAX_VLAN_HEADERS]; > + size_t num_vlans = parse_vlan(&data, &size, vlans); > + > /* dl_type */ > dl_type = parse_ethertype(&data, &size); > miniflow_push_be16(mf, dl_type, dl_type); > @@ -930,7 +927,7 @@ flow_get_metadata(const struct flow *flow, struct match > *flow_metadata) > { > int i; > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > match_init_catchall(flow_metadata); > if (flow->tunnel.tun_id != htonll(0)) { > @@ -1357,13 +1354,14 @@ flow_wildcards_init_catchall(struct flow_wildcards > *wc) > * the packet headers extracted to 'flow'. It will not set the mask for > fields > * that do not make sense for the packet type. OpenFlow-only metadata is > * wildcarded, but other metadata is unconditionally exact-matched. */ > -void flow_wildcards_init_for_packet(struct flow_wildcards *wc, > - const struct flow *flow) > +void > +flow_wildcards_init_for_packet(struct flow_wildcards *wc, > + const struct flow *flow) > { > memset(&wc->masks, 0x0, sizeof wc->masks); > > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > if (flow_tnl_dst_is_set(&flow->tunnel)) { > if (flow->tunnel.flags & FLOW_TNL_F_KEY) { > @@ -1498,7 +1496,7 @@ void > flow_wc_map(const struct flow *flow, struct flowmap *map) > { > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > flowmap_init(map); > > @@ -1592,7 +1590,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 == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > memset(&wc->masks.metadata, 0, sizeof wc->masks.metadata); > memset(&wc->masks.regs, 0, sizeof wc->masks.regs); > @@ -1736,7 +1734,7 @@ flow_wildcards_set_xxreg_mask(struct flow_wildcards > *wc, int idx, > uint32_t > miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis) > { > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > uint32_t hash = basis; > > if (flow) { > @@ -1783,7 +1781,7 @@ ASSERT_SEQUENTIAL(ipv6_src, ipv6_dst); > uint32_t > flow_hash_5tuple(const struct flow *flow, uint32_t basis) > { > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > uint32_t hash = basis; > > if (flow) { > @@ -1919,9 +1917,9 @@ flow_random_hash_fields(struct flow *flow) > eth_addr_random(&flow->dl_dst); > > for (i = 0; i < FLOW_MAX_VLAN_HEADERS; i++) { > + uint16_t vlan = random_uint16() & VLAN_VID_MASK; > flow->vlans[i].tpid = htons(ETH_TYPE_VLAN_8021Q); > - flow->vlans[i].tci = htons((random_uint16() & VLAN_VID_MASK) | > - VLAN_CFI); > + flow->vlans[i].tci = htons(vlan | VLAN_CFI); > } > > /* Make most of the random flows IPv4, some IPv6, and rest random. */ > @@ -2184,8 +2182,8 @@ flow_pop_vlan(struct flow *flow, struct flow_wildcards > *wc) > void > flow_push_vlan_uninit(struct flow *flow, struct flow_wildcards *wc) > { > - int n = flow_count_vlan_headers(flow); > if (wc) { > + int n = flow_count_vlan_headers(flow); > memset(wc->masks.vlans, 0xff, sizeof(union flow_vlan_hdr) * n); > } > memmove(&flow->vlans[1], &flow->vlans[0], > @@ -2331,7 +2329,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16 > mpls_eth_type, > > if (clear_flow_L3) { > /* Clear all L3 and L4 fields and dp_hash. */ > - BUILD_ASSERT(FLOW_WC_SEQ == 37); > + BUILD_ASSERT(FLOW_WC_SEQ == 38); > memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0, > sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT); > flow->dp_hash = 0; > @@ -2552,7 +2550,6 @@ flow_compose(struct dp_packet *p, const struct flow > *flow) > { > uint32_t pseudo_hdr_csum; > size_t l4_len; > - int encaps; > > /* eth_compose() sets l3 pointer and makes sure it is 32-bit aligned. */ > eth_compose(p, flow->dl_dst, flow->dl_src, ntohs(flow->dl_type), 0); > @@ -2562,7 +2559,7 @@ flow_compose(struct dp_packet *p, const struct flow > *flow) > return; > } > > - for (encaps = FLOW_MAX_VLAN_HEADERS - 1; encaps >= 0; encaps--) { > + for (int encaps = FLOW_MAX_VLAN_HEADERS - 1; encaps >= 0; encaps--) { > if (flow->vlans[encaps].tci & htons(VLAN_CFI)) { > eth_push_vlan(p, flow->vlans[encaps].tpid, > flow->vlans[encaps].tci); > @@ -2893,7 +2890,7 @@ flow_limit_vlans(int vlan_limit) > { > if (vlan_limit <= 0) { > flow_vlan_limit = FLOW_MAX_VLAN_HEADERS; > - } else if (vlan_limit > 0) { > + } else { > flow_vlan_limit = MIN(vlan_limit, FLOW_MAX_VLAN_HEADERS); > } > } > diff --git a/lib/flow.h b/lib/flow.h > index 2047fe872961..86b52584b1de 100644 > --- a/lib/flow.h > +++ b/lib/flow.h > @@ -905,7 +905,7 @@ static inline void > pkt_metadata_from_flow(struct pkt_metadata *md, const struct flow *flow) > { > /* Update this function whenever struct flow changes. */ > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > md->recirc_id = flow->recirc_id; > md->dp_hash = flow->dp_hash; > diff --git a/lib/match.c b/lib/match.c > index 5440fc6e8fa2..4a8db187b72e 100644 > --- a/lib/match.c > +++ b/lib/match.c > @@ -1169,7 +1169,7 @@ match_format(const struct match *match, struct ds *s, > int priority) > > int i; > > - BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > if (priority != OFP_DEFAULT_PRIORITY) { > ds_put_format(s, "%spriority=%s%d,", > diff --git a/lib/nx-match.c b/lib/nx-match.c > index 6a27e57a841a..8fcae977cfa1 100644 > --- a/lib/nx-match.c > +++ b/lib/nx-match.c > @@ -986,7 +986,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 == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > /* Metadata. */ > if (match->wc.masks.dp_hash) { > diff --git a/lib/odp-util.c b/lib/odp-util.c > index 4a1b6915792f..a7b14ed720f9 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -4424,7 +4424,6 @@ odp_flow_key_from_flow__(const struct > odp_flow_key_parms *parms, > { > struct ovs_key_ethernet *eth_key; > size_t encap[FLOW_MAX_VLAN_HEADERS] = {0}; > - int encaps = 0; > size_t max_vlans; > const struct flow *flow = parms->flow; > const struct flow *data = export_mask ? parms->mask : parms->flow; > @@ -4495,7 +4494,7 @@ odp_flow_key_from_flow__(const struct > odp_flow_key_parms *parms, > } else { > max_vlans = MIN(parms->support.max_vlan_headers, flow_vlan_limit); > } > - for (encaps = 0; encaps < max_vlans; encaps++) { > + for (int encaps = 0; encaps < max_vlans; encaps++) { > ovs_be16 tpid = flow->vlans[encaps].tpid; > > if (flow->vlans[encaps].tci == htons(0)) { > @@ -4636,7 +4635,7 @@ odp_flow_key_from_flow__(const struct > odp_flow_key_parms *parms, > } > > unencap: > - for (encaps = max_vlans-1; encaps >= 0; encaps--) { > + for (int encaps = max_vlans - 1; encaps >= 0; encaps--) { > if (encap[encaps]) { > nl_msg_end_nested(buf, encap[encaps]); > } > @@ -5239,12 +5238,12 @@ parse_8021q_onward(const struct nlattr > *attrs[OVS_KEY_ATTR_MAX + 1], > int encaps = 0; > > while (encaps < flow_vlan_limit && > - (is_mask ? > - (src_flow->vlans[encaps].tci & htons(VLAN_CFI)) != 0 : > - eth_type_vlan(flow->dl_type))) { > + (is_mask > + ? (src_flow->vlans[encaps].tci & htons(VLAN_CFI)) != 0 > + : eth_type_vlan(flow->dl_type))) { > > encap = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_ENCAP) > - ? attrs[OVS_KEY_ATTR_ENCAP] : NULL); > + ? attrs[OVS_KEY_ATTR_ENCAP] : NULL); > > /* Calculate fitness of outer attributes. */ > if (!is_mask) { > @@ -5700,10 +5699,8 @@ static void > commit_vlan_action(const struct flow* flow, struct flow *base, > struct ofpbuf *odp_actions, struct flow_wildcards *wc) > { > - int flow_n, base_n; > - > - base_n = flow_count_vlan_headers(base); > - flow_n = flow_count_vlan_headers(flow); > + int base_n = flow_count_vlan_headers(base); > + int flow_n = flow_count_vlan_headers(flow); > flow_skip_common_vlan_headers(base, &base_n, flow, &flow_n); > > /* Pop all mismatching vlan of base, push those of flow */ > diff --git a/lib/odp-util.h b/lib/odp-util.h > index dc0fef177fd7..50fa1d133e1f 100644 > --- a/lib/odp-util.h > +++ b/lib/odp-util.h > @@ -143,7 +143,7 @@ void odp_portno_names_destroy(struct hmap *portno_names); > * add another field and forget to adjust this value. > */ > #define ODPUTIL_FLOW_KEY_BYTES 640 > -BUILD_ASSERT_DECL(FLOW_WC_SEQ == 37); > +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > /* 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-util.c b/lib/ofp-util.c > index 5ee47ebb2970..02ee95fadb20 100644 > --- a/lib/ofp-util.c > +++ b/lib/ofp-util.c > @@ -101,7 +101,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 == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > /* Initialize most of wc. */ > flow_wildcards_init_catchall(wc); > diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h > index dfe54ff3296f..2c05c36077d6 100644 > --- a/ofproto/ofproto-dpif-rid.h > +++ b/ofproto/ofproto-dpif-rid.h > @@ -99,7 +99,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 == 37); > +BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > > struct frozen_metadata { > /* Metadata in struct flow. */ > diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c > index 19e81543ef49..940ed269af4b 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -3206,7 +3206,7 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > struct flow_wildcards *wc = ctx->wc; > struct flow *flow = &ctx->xin->flow; > struct flow_tnl flow_tnl; > - ovs_be16 flow_vlan_tci; > + union flow_vlan_hdr flow_vlans[FLOW_MAX_VLAN_HEADERS]; > uint32_t flow_pkt_mark; > uint8_t flow_nw_tos; > odp_port_t out_port, odp_port; > @@ -3215,7 +3215,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 == 37); > + BUILD_ASSERT_DECL(FLOW_WC_SEQ == 38); > memset(&flow_tnl, 0, sizeof flow_tnl); > > if (!xport) { > @@ -3401,7 +3401,7 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > return; > } > > - flow_vlan_tci = flow->vlans[0].tci; > + memcpy(flow_vlans, flow->vlans, sizeof flow_vlans); > flow_pkt_mark = flow->pkt_mark; > flow_nw_tos = flow->nw_tos; > > @@ -3529,7 +3529,7 @@ compose_output_action__(struct xlate_ctx *ctx, > ofp_port_t ofp_port, > > out: > /* Restore flow */ > - flow->vlans[0].tci = flow_vlan_tci; > + memcpy(flow->vlans, flow_vlans, sizeof flow->vlans); > flow->pkt_mark = flow_pkt_mark; > flow->nw_tos = flow_nw_tos; > } > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index 1af0bded4089..1c4c80469d0c 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -974,12 +974,12 @@ check_max_vlan_headers(struct dpif_backer *backer) > > ofpbuf_use_stack(&key, &keybuf, sizeof keybuf); > odp_flow_key_from_flow(&odp_parms, &key); > - if (!dpif_probe_feature(backer->dpif, "VLAN", &key, NULL)) { > + if (!dpif_probe_feature(backer->dpif, "VLAN", &key, NULL, NULL)) { > break; > } > } > > - VLOG_INFO("%s: VLAN label stack length probed as %d", > + VLOG_INFO("%s: VLAN header stack length probed as %d", > dpif_name(backer->dpif), n); > return n; > } > diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c > index 2a85c0f8c763..09594f1010e1 100644 > --- a/ofproto/ofproto.c > +++ b/ofproto/ofproto.c > @@ -8616,4 +8616,3 @@ ofproto_set_vlan_limit(int vlan_limit) > { > flow_limit_vlans(vlan_limit); > } > - > diff --git a/tests/test-classifier.c b/tests/test-classifier.c > index 774a9be22f89..37baad2a4bab 100644 > --- a/tests/test-classifier.c > +++ b/tests/test-classifier.c > @@ -58,7 +58,7 @@ static bool versioned = false; > CLS_FIELD(nw_src, NW_SRC) \ > CLS_FIELD(nw_dst, NW_DST) \ > CLS_FIELD(in_port.ofp_port, IN_PORT) \ > - CLS_FIELD(vlans[0].tci, VLAN_TCI) \ > + CLS_FIELD(vlans[0].tci, VLAN_TCI) \ > CLS_FIELD(dl_type, DL_TYPE) \ > CLS_FIELD(tp_src, TP_SRC) \ > CLS_FIELD(tp_dst, TP_DST) \ > diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema > index de78dfd26d2c..b04d360d604e 100644 > --- a/vswitchd/vswitch.ovsschema > +++ b/vswitchd/vswitch.ovsschema > @@ -1,6 +1,6 @@ > {"name": "Open_vSwitch", > - "version": "7.15.0", > - "cksum": "2264024465 22987", > + "version": "7.14.0", > + "cksum": "3374030633 22987", > "tables": { > "Open_vSwitch": { > "columns": { > diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml > index 8ef675f5cc17..464a211ad0f5 100644 > --- a/vswitchd/vswitch.xml > +++ b/vswitchd/vswitch.xml > @@ -354,18 +354,23 @@ > <column name="other_config" key="vlan-limit" > type='{"type": "integer", "minInteger": 0}'> > <p> > - Limit the maxmium of VLAN headers that can be matched. Further VLAN > - headers will be treated as payload, e.g. a packet with more 802.1q > - headers will match eth_type 0x8100. > + Limits the number of VLAN headers that can be matched to the > + specified number. Further VLAN headers will be treated as payload, > + e.g. a packet with more 802.1q headers will match Ethernet type > + 0x8100. > </p> > <p> > - Value <code>0</code> means unlimited. The actual value of max VLAN > - headers is the minumium of <code>vlan-limit</code>, the max VLANs > - supported by Open vSwitch userspace (currently 2), and that > supported > - by datapath. > + Value <code>0</code> means unlimited. The actual number of > supported > + VLAN headers is the smallest of <code>vlan-limit</code>, the number > + of VLANs supported by Open vSwitch userspace (currently 2), and the > + number supported by the datapath. > </p> > + > <p> > - The default value is 1, to keep backward compatibility. > + If this value is absent, the default is currently 1. This > maintains > + backward compatibility with controllers that were designed for use > + with Open vSwitch versions earlier than 2.8, which only supported > one > + VLAN. > </p> > </column> > </group> This incremental looks good to me. Thanks again! Eric. _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev