[ovs-dev] [PATCH 1/7] Add support for 802.1ad (QinQ tunneling)

Eric Garver e at erig.me
Fri Mar 17 01:18:00 UTC 2017


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 <thomasfherbert at gmail.com>
> > Signed-off-by: Thomas F Herbert <thomasfherbert at gmail.com>
> > Co-authored-by: Xiao Liang <shaw.leon at gmail.com>
> > Signed-off-by: Xiao Liang <shaw.leon at gmail.com>
> > Signed-off-by: Eric Garver <e at 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.


More information about the dev mailing list