[ovs-dev] [PATCH 4/4] ofproto: dpif changes to support provider VLANs

Avinash avinashandrew at gmail.com
Tue Jun 10 13:34:28 UTC 2014


This commit includes:
1. Support for new config parameter in xbundle.
2. Changes in determining the vlan id and number of VLANs to be present
   in the output packet.

For testing purpose, planned to make changes in normalize-actions to
support stacked VLANs.

Signed-off-by: Avinash <avinashandrew at gmail.com>
---
 ofproto/ofproto-dpif-xlate.c | 130 +++++++++++++++++++++++++++++++++++++------
 ofproto/ofproto-dpif-xlate.h |   2 +-
 ofproto/ofproto-dpif.c       |   9 ++-
 ofproto/ofproto.h            |   1 +
 4 files changed, 121 insertions(+), 21 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index eded9d8..4c66779 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -120,6 +120,7 @@ struct xbundle {
     unsigned long *trunks;         /* Bitmap of trunked VLANs, if 'vlan' == -1.
                                     * NULL if all VLANs are trunked. */
     bool use_priority_tags;        /* Use 802.1p tag for frames in VLAN 0? */
+    bool support_dvlan;            /* Supports double vlan tagging */
     bool floodable;                /* No port has OFPUTIL_PC_NO_FLOOD set? */
 };

@@ -183,6 +184,7 @@ struct xlate_ctx {
     int resubmits;              /* Total number of resubmits. */
     bool in_group;              /* Currently translating ofgroup, if true. */

+    uint16_t orig_vid;          /* VLAN vid when packet arrived. */
     uint32_t orig_skb_priority; /* Priority when packet arrived. */
     uint8_t table_id;           /* OpenFlow table ID where flow was found. */
     uint32_t sflow_n_outputs;   /* Number of output ports. */
@@ -319,8 +321,9 @@ static void xlate_table_action(struct xlate_ctx *,
ofp_port_t in_port,
                                bool honor_table_miss);
 static bool input_vid_is_valid(uint16_t vid, struct xbundle *, bool warn);
 static uint16_t input_vid_to_vlan(const struct xbundle *, uint16_t vid);
+static uint16_t input_vlan_count(const struct xbundle *, uint16_t
vid, uint8_t vlan_count);
 static void output_normal(struct xlate_ctx *, const struct xbundle *,
-                          uint16_t vlan);
+                          uint16_t vlan, uint8_t vlan_count);
 static void compose_output_action(struct xlate_ctx *, ofp_port_t ofp_port);

 static struct xbridge *xbridge_lookup(struct xlate_cfg *,
@@ -359,7 +362,7 @@ static void xlate_xbundle_set(struct xbundle *xbundle,
                               enum port_vlan_mode vlan_mode, int vlan,
                               unsigned long *trunks, bool use_priority_tags,
                               const struct bond *bond, const struct lacp *lacp,
-                              bool floodable);
+                              bool floodable, bool support_dvlan);
 static void xlate_xport_set(struct xport *xport, odp_port_t odp_port,
                             const struct netdev *netdev, const struct cfm *cfm,
                             const struct bfd *bfd, int stp_port_no,
@@ -465,7 +468,7 @@ xlate_xbundle_set(struct xbundle *xbundle,
                   enum port_vlan_mode vlan_mode, int vlan,
                   unsigned long *trunks, bool use_priority_tags,
                   const struct bond *bond, const struct lacp *lacp,
-                  bool floodable)
+                  bool floodable, bool support_dvlan)
 {
     ovs_assert(xbundle->xbridge);

@@ -473,6 +476,7 @@ xlate_xbundle_set(struct xbundle *xbundle,
     xbundle->vlan = vlan;
     xbundle->trunks = trunks;
     xbundle->use_priority_tags = use_priority_tags;
+    xbundle->support_dvlan = support_dvlan;
     xbundle->floodable = floodable;

     if (xbundle->bond != bond) {
@@ -559,7 +563,7 @@ xlate_xbundle_copy(struct xbridge *xbridge, struct
xbundle *xbundle)
     xlate_xbundle_set(new_xbundle, xbundle->vlan_mode,
                       xbundle->vlan, xbundle->trunks,
                       xbundle->use_priority_tags, xbundle->bond, xbundle->lacp,
-                      xbundle->floodable);
+                      xbundle->floodable, xbundle->support_dvlan);
     LIST_FOR_EACH (xport, bundle_node, &xbundle->xports) {
         xlate_xport_copy(xbridge, new_xbundle, xport);
     }
@@ -754,7 +758,7 @@ xlate_bundle_set(struct ofproto_dpif *ofproto,
struct ofbundle *ofbundle,
                  const char *name, enum port_vlan_mode vlan_mode, int vlan,
                  unsigned long *trunks, bool use_priority_tags,
                  const struct bond *bond, const struct lacp *lacp,
-                 bool floodable)
+                 bool floodable, bool support_dvlan)
 {
     struct xbundle *xbundle;

@@ -773,7 +777,7 @@ xlate_bundle_set(struct ofproto_dpif *ofproto,
struct ofbundle *ofbundle,
     xbundle->name = xstrdup(name);

     xlate_xbundle_set(xbundle, vlan_mode, vlan, trunks,
-                      use_priority_tags, bond, lacp, floodable);
+                      use_priority_tags, bond, lacp, floodable, support_dvlan);
 }

 static void
@@ -1252,6 +1256,13 @@ xbundle_includes_vlan(const struct xbundle
*xbundle, uint16_t vlan)
     return vlan == xbundle->vlan || xbundle_trunks_vlan(xbundle, vlan);
 }

+static bool
+is_xbundle_support_qinq(const struct xbundle *xbundle, uint8_t vlan_count)
+{
+    return (vlan_count > 0 && xbundle->vlan_mode == PORT_VLAN_ACCESS
+            && !xbundle->support_dvlan);
+}
+
 static mirror_mask_t
 xbundle_mirror_out(const struct xbridge *xbridge, struct xbundle *xbundle)
 {
@@ -1328,9 +1339,11 @@ add_mirror_actions(struct xlate_ctx *ctx, const
struct flow *orig_flow)
     struct xbundle *in_xbundle;
     uint16_t vlan;
     uint16_t vid;
+    uint8_t vlan_count;

     mirrors = ctx->xout->mirrors;
     ctx->xout->mirrors = 0;
+    ctx->orig_vid = 0;

     in_xbundle = lookup_input_bundle(xbridge, orig_flow->in_port.ofp_port,
                                      ctx->xin->packet != NULL, NULL);
@@ -1357,6 +1370,12 @@ add_mirror_actions(struct xlate_ctx *ctx, const
struct flow *orig_flow)
         return;
     }
     vlan = input_vid_to_vlan(in_xbundle, vid);
+    vlan_count = input_vlan_count(in_xbundle, vid, orig_flow->vlan_count);
+
+    if (in_xbundle->vlan_mode == PORT_VLAN_ACCESS)
+    {
+        ctx->orig_vid = vid;
+    }

     if (!mirrors) {
         return;
@@ -1394,7 +1413,7 @@ add_mirror_actions(struct xlate_ctx *ctx, const
struct flow *orig_flow)
             struct xlate_cfg *xcfg = ovsrcu_get(struct xlate_cfg *, &xcfgp);
             struct xbundle *out_xbundle = xbundle_lookup(xcfg, out);
             if (out_xbundle) {
-                output_normal(ctx, out_xbundle, vlan);
+                output_normal(ctx, out_xbundle, vlan, vlan_count);
             }
         } else if (vlan != out_vlan
                    && !eth_addr_is_reserved(orig_flow->dl_dst)) {
@@ -1402,8 +1421,9 @@ add_mirror_actions(struct xlate_ctx *ctx, const
struct flow *orig_flow)

             LIST_FOR_EACH (xbundle, list_node, &xbridge->xbundles) {
                 if (xbundle_includes_vlan(xbundle, out_vlan)
+                    && !is_xbundle_support_qinq(xbundle, vlan_count)
                     && !xbundle_mirror_out(xbridge, xbundle)) {
-                    output_normal(ctx, xbundle, out_vlan);
+                    output_normal(ctx, xbundle, out_vlan, vlan_count);
                 }
             }
         }
@@ -1436,6 +1456,31 @@ input_vid_to_vlan(const struct xbundle
*in_xbundle, uint16_t vid)
     }
 }

+/* Input parameters
+ * in_xbundle:  Bundle on which the packet was received.
+ * vid       :  VID obtained from the 802.1Q header that was received as
+ *              part of a packet (specify 0 if there was no 802.1Q header).
+ * vlan_count:  Number of stacked VLANs present in the received packet.
+ *
+ * Returns the number of stacked VLANs that belong to the output packet.
+ */
+static uint16_t
+input_vlan_count(const struct xbundle *in_xbundle, uint16_t vid,
uint8_t vlan_count)
+{
+    switch (in_xbundle->vlan_mode) {
+    case PORT_VLAN_ACCESS:
+        return vid ? vlan_count : 0;
+
+    case PORT_VLAN_TRUNK:
+    case PORT_VLAN_NATIVE_UNTAGGED:
+    case PORT_VLAN_NATIVE_TAGGED:
+        return vid ? (--vlan_count) : 0;
+
+    default:
+        OVS_NOT_REACHED();
+    }
+}
+
 /* Checks whether a packet with the given 'vid' may ingress on 'in_xbundle'.
  * If so, returns true.  Otherwise, returns false and, if 'warn' is true, logs
  * a warning.
@@ -1453,7 +1498,7 @@ input_vid_is_valid(uint16_t vid, struct xbundle
*in_xbundle, bool warn)

     switch (in_xbundle->vlan_mode) {
     case PORT_VLAN_ACCESS:
-        if (vid) {
+        if (vid && !in_xbundle->support_dvlan) {
             if (warn) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_WARN_RL(&rl, "dropping VLAN %"PRIu16" tagged "
@@ -1498,11 +1543,11 @@ input_vid_is_valid(uint16_t vid, struct
xbundle *in_xbundle, bool warn)
  *
  * Both 'vlan' and the return value are in the range 0...4095. */
 static uint16_t
-output_vlan_to_vid(const struct xbundle *out_xbundle, uint16_t vlan)
+output_vlan_to_vid(const struct xbundle *out_xbundle, uint16_t vlan,
uint16_t access_vid)
 {
     switch (out_xbundle->vlan_mode) {
     case PORT_VLAN_ACCESS:
-        return 0;
+        return access_vid;

     case PORT_VLAN_TRUNK:
     case PORT_VLAN_NATIVE_TAGGED:
@@ -1516,16 +1561,46 @@ output_vlan_to_vid(const struct xbundle
*out_xbundle, uint16_t vlan)
     }
 }

+/* Input parameters
+ * out_xbundle:  Bundle on which the packet is to be output.
+ * vlan       :  VLAN that belong to the output packet.
+ * vlan_count :  Number of stacked VLANs belong to the packet.
+ *
+ * Returns the number of stacked VLANs that should present
+ * in the header of output packet.
+ */
+static uint16_t
+output_vlan_count(const struct xbundle *out_xbundle, uint16_t vlan,
uint8_t vlan_count)
+{
+    switch (out_xbundle->vlan_mode) {
+    case PORT_VLAN_ACCESS:
+        return vlan_count;
+
+    case PORT_VLAN_TRUNK:
+    case PORT_VLAN_NATIVE_TAGGED:
+        return ++vlan_count;
+
+    case PORT_VLAN_NATIVE_UNTAGGED:
+        return vlan == out_xbundle->vlan ? vlan_count : ++vlan_count;
+
+    default:
+        OVS_NOT_REACHED();
+    }
+}
+
 static void
 output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle,
-              uint16_t vlan)
+              uint16_t vlan, uint8_t vlan_count)
 {
     ovs_be16 *flow_tci = &ctx->xin->flow.vlan_tci;
+    uint8_t *flow_vlan_count = &ctx->xin->flow.vlan_count;
     uint16_t vid;
     ovs_be16 tci, old_tci;
+    uint8_t old_count, vcount;
     struct xport *xport;

-    vid = output_vlan_to_vid(out_xbundle, vlan);
+    vid = output_vlan_to_vid(out_xbundle, vlan, ctx->orig_vid);
+    vcount = output_vlan_count(out_xbundle, vlan, vlan_count);
     if (list_is_empty(&out_xbundle->xports)) {
         /* Partially configured bundle with no slaves.  Drop the packet. */
         return;
@@ -1583,17 +1658,24 @@ output_normal(struct xlate_ctx *ctx, const
struct xbundle *out_xbundle,
     }

     old_tci = *flow_tci;
+    old_count = *flow_vlan_count;
     tci = htons(vid);
     if (tci || out_xbundle->use_priority_tags) {
         tci |= *flow_tci & htons(VLAN_PCP_MASK);
         if (tci) {
             tci |= htons(VLAN_CFI);
+            /* For priority VLAN ports with vlan id zero should also be present
+             * in the packet, hence increase the vlan count */
+            if (!vid && out_xbundle->use_priority_tags)
+                ++vcount;
         }
     }
     *flow_tci = tci;
+    *flow_vlan_count = vcount;

     compose_output_action(ctx, xport->ofp_port);
     *flow_tci = old_tci;
+    *flow_vlan_count = old_count;
 }

 /* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
@@ -1801,7 +1883,7 @@ update_learning_table(const struct xbridge *xbridge,

 static void
 xlate_normal_flood(struct xlate_ctx *ctx, struct xbundle *in_xbundle,
-                   uint16_t vlan)
+                   uint16_t vlan, uint16_t vlan_count)
 {
     struct xbundle *xbundle;

@@ -1809,8 +1891,9 @@ xlate_normal_flood(struct xlate_ctx *ctx, struct
xbundle *in_xbundle,
         if (xbundle != in_xbundle
             && xbundle_includes_vlan(xbundle, vlan)
             && xbundle->floodable
+            && !is_xbundle_support_qinq(xbundle, vlan_count)
             && !xbundle_mirror_out(ctx->xbridge, xbundle)) {
-            output_normal(ctx, xbundle, vlan);
+            output_normal(ctx, xbundle, vlan, vlan_count);
         }
     }
     ctx->xout->nf_output_iface = NF_OUT_FLOOD;
@@ -1827,8 +1910,10 @@ xlate_normal(struct xlate_ctx *ctx)
     void *mac_port;
     uint16_t vlan;
     uint16_t vid;
+    uint8_t vlan_count;

     ctx->xout->has_normal = true;
+    ctx->orig_vid = 0;

     memset(&wc->masks.dl_src, 0xff, sizeof wc->masks.dl_src);
     memset(&wc->masks.dl_dst, 0xff, sizeof wc->masks.dl_dst);
@@ -1879,6 +1964,12 @@ xlate_normal(struct xlate_ctx *ctx)
         return;
     }

+    vlan_count = input_vlan_count(in_xbundle, vid, flow->vlan_count);
+    if (in_xbundle->vlan_mode == PORT_VLAN_ACCESS)
+    {
+        ctx->orig_vid = vid;
+    }
+
     /* Learn source MAC. */
     if (ctx->xin->may_learn) {
         update_learning_table(ctx->xbridge, flow, wc, vlan, in_xbundle);
@@ -1904,7 +1995,7 @@ xlate_normal(struct xlate_ctx *ctx)
         struct xbundle *mac_xbundle = xbundle_lookup(xcfg, mac_port);
         if (mac_xbundle && mac_xbundle != in_xbundle) {
             xlate_report(ctx, "forwarding to learned port");
-            output_normal(ctx, mac_xbundle, vlan);
+            output_normal(ctx, mac_xbundle, vlan, vlan_count);
         } else if (!mac_xbundle) {
             xlate_report(ctx, "learned port is unknown, dropping");
         } else {
@@ -1912,7 +2003,7 @@ xlate_normal(struct xlate_ctx *ctx)
         }
     } else {
         xlate_report(ctx, "no learned MAC for destination, flooding");
-        xlate_normal_flood(ctx, in_xbundle, vlan);
+        xlate_normal_flood(ctx, in_xbundle, vlan, vlan_count);
     }
 }

@@ -2139,7 +2230,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 == 26);
+    BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);

     if (!xport) {
         xlate_report(ctx, "Nonexistent output port");
@@ -3161,6 +3252,9 @@ do_xlate_actions(const struct ofpact *ofpacts,
size_t ofpacts_len,
                 flow->vlan_tci &= ~htons(VLAN_VID_MASK);
                 flow->vlan_tci |= (htons(ofpact_get_SET_VLAN_VID(a)->vlan_vid)
                                    | htons(VLAN_CFI));
+                if (!flow->vlan_count &&
+                    ofpact_get_SET_VLAN_VID(a)->push_vlan_if_needed)
+                    ++flow->vlan_count;
             }
             break;

diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 6065db3..98b53f5 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -152,7 +152,7 @@ void xlate_bundle_set(struct ofproto_dpif *,
struct ofbundle *,
                       const char *name, enum port_vlan_mode, int vlan,
                       unsigned long *trunks, bool use_priority_tags,
                       const struct bond *, const struct lacp *,
-                      bool floodable);
+                      bool floodable, bool support_dvlan);
 void xlate_bundle_remove(struct ofbundle *);

 void xlate_ofport_set(struct ofproto_dpif *, struct ofbundle *,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 2984e93..a722d77 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -124,6 +124,7 @@ struct ofbundle {
     struct lacp *lacp;          /* LACP if LACP is enabled, otherwise NULL. */
     struct bond *bond;          /* Nonnull iff more than one port. */
     bool use_priority_tags;     /* Use 802.1p tag for frames in VLAN 0? */
+    bool support_dvlan;         /* Supports double vlan tagging */

     /* Status. */
     bool floodable;          /* True if no port has OFPUTIL_PC_NO_FLOOD set. */
@@ -605,7 +606,7 @@ type_run(const char *type)
                                  bundle->vlan_mode, bundle->vlan,
                                  bundle->trunks, bundle->use_priority_tags,
                                  bundle->bond, bundle->lacp,
-                                 bundle->floodable);
+                                 bundle->floodable, bundle->support_dvlan);
             }

             HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
@@ -2326,6 +2327,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         bundle->vlan = -1;
         bundle->trunks = NULL;
         bundle->use_priority_tags = s->use_priority_tags;
+        bundle->support_dvlan = s->support_dvlan;
         bundle->lacp = NULL;
         bundle->bond = NULL;

@@ -2382,9 +2384,11 @@ bundle_set(struct ofproto *ofproto_, void *aux,

     /* Set VLAN tagging mode */
     if (s->vlan_mode != bundle->vlan_mode
-        || s->use_priority_tags != bundle->use_priority_tags) {
+        || s->use_priority_tags != bundle->use_priority_tags
+        || s->support_dvlan != bundle->support_dvlan) {
         bundle->vlan_mode = s->vlan_mode;
         bundle->use_priority_tags = s->use_priority_tags;
+        bundle->support_dvlan = s->support_dvlan;
         need_flush = true;
     }

@@ -4682,6 +4686,7 @@ vsp_adjust_flow(const struct ofproto_dpif
*ofproto, struct flow *flow)
      * the VLAN device's VLAN ID. */
     flow->in_port.ofp_port = realdev;
     flow->vlan_tci = htons((vid & VLAN_VID_MASK) | VLAN_CFI);
+    ++flow->vlan_count;
     return true;
 }

diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index de078b7..71cd423 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -309,6 +309,7 @@ struct ofproto_bundle_settings {
     int vlan;                   /* VLAN VID, except for PORT_VLAN_TRUNK. */
     unsigned long *trunks;      /* vlan_bitmap, except for PORT_VLAN_ACCESS. */
     bool use_priority_tags;     /* Use 802.1p tag for frames in VLAN 0? */
+    bool support_dvlan;         /* Supports double vlan tagging */

     struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */

--
1.9.0



More information about the dev mailing list