Le 03/08/2011 18:30, Ben Pfaff a écrit :
> On Sat, Jul 30, 2011 at 01:41:04AM +0200, Philippe Jung wrote:
>> This patchs adds the PVID (Port VLAN ID) tagging feature to the
>> switch ports:
>> - When an untagged packet is received by a switch port from an
>>   external device, the packet is tagged with PVID;
>> - Tagged packets received by a switch port from an external device
>>   are unchanged;
>> - When a tagged packet is sent by a switch port to an external
>>   device, if the tag is egal to the PVID the packet may optionnaly
>>   be untagged
>> - In all other cases, tagged packet sent by a switch port to an
>>   external device are unchanged

Please find a new version of the patch against master branch, non word 
wrapped, with updated doc. Also fixed a typo in INSTALL.Linux still 
referencing --with-l26

Philippe

---
 INSTALL.Linux              |    2 +-
 ofproto/ofproto-dpif.c     |   83 ++++++++++++++++++++++++++++++++++++--------
 ofproto/ofproto.h          |   22 ++++++++++++
 vswitchd/bridge.c          |   25 ++++++++++++--
 vswitchd/vswitch.ovsschema |    8 +++-
 vswitchd/vswitch.xml       |   50 ++++++++++++++++++++++++--
 6 files changed, 165 insertions(+), 25 deletions(-)

diff --git a/INSTALL.Linux b/INSTALL.Linux
index 6c17ca4..4477a60 100644
--- a/INSTALL.Linux
+++ b/INSTALL.Linux
@@ -171,7 +171,7 @@ Prerequisites section, follow the procedure below to build.
 
    To build the Linux kernel module, so that you can run the
    kernel-based switch, pass the location of the kernel build
-   directory on --with-l26.  For example, to build for a running
+   directory on --with-linux.  For example, to build for a running
    instance of Linux:
 
       % ./configure --with-linux=/lib/modules/`uname -r`/build
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index cdc21bc..89ffbb7 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -131,6 +131,7 @@ struct ofbundle {
 
     /* Configuration. */
     struct list ports;          /* Contains "struct ofport"s. */
+    enum port_vlan_mode vlan_mode; /* VLAN mode */
     int vlan;                   /* -1=trunk port, else a 12-bit VLAN ID. */
     unsigned long *trunks;      /* Bitmap of trunked VLANs, if 'vlan' == -1.
                                  * NULL if all VLANs are trunked. */
@@ -993,6 +994,7 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         bundle->name = NULL;
 
         list_init(&bundle->ports);
+       bundle->vlan_mode = PORT_VLAN_EMPTY;
         bundle->vlan = -1;
         bundle->trunks = NULL;
         bundle->lacp = NULL;
@@ -1051,6 +1053,12 @@ bundle_set(struct ofproto *ofproto_, void *aux,
         return EINVAL;
     }
 
+    /* Set VLAN tagging mode */
+    if (s->vlan_mode != bundle->vlan_mode) {
+        bundle->vlan_mode = s->vlan_mode;
+        need_flush = true;
+    }
+
     /* Set VLAN tag. */
     if (s->vlan != bundle->vlan) {
         bundle->vlan = s->vlan;
@@ -3308,16 +3316,42 @@ static bool
 set_dst(struct action_xlate_ctx *ctx, struct dst *dst,
         const struct ofbundle *in_bundle, const struct ofbundle *out_bundle)
 {
-    dst->vlan = (out_bundle->vlan >= 0 ? OFP_VLAN_NONE
-                 : in_bundle->vlan >= 0 ? in_bundle->vlan
-                 : ctx->flow.vlan_tci == 0 ? OFP_VLAN_NONE
-                 : vlan_tci_to_vid(ctx->flow.vlan_tci));
-
+    // Following rules apply for traffic going out of the bundle:
+    // - if output bundle mode is empty or access, untag
+    // - if output bundle mode mode is trunk, pvid or untaged-pvid
+    //    First
+    //    - keep input bundle tag if input bundle is empty or access
+    //    - or keep existing VLAN if input bundle is trunk, (untagged-)pvid
+    //    - or use pvid for untagged frame if input bundle is (untagged-)pvid
+    //    - or leave untagged
+    //    Then
+    //    - if output bundle mode is untagged-pvid, untag if and only if
+    //      current tag = output bundle vlan id
+
+    // output is undefined or access
+    if (out_bundle->vlan_mode < PORT_VLAN_TRUNK) {
+       // Untag everything
+       dst->vlan = OFP_VLAN_NONE;
+    } else {
+       // Source based VLAN
+       int fromVlan =
+            in_bundle->vlan_mode == PORT_VLAN_ACCESS ? in_bundle->vlan
+            : ctx->flow.vlan_tci != 0 ? vlan_tci_to_vid(ctx->flow.vlan_tci)
+            : in_bundle->vlan_mode >= PORT_VLAN_TAGGED_PVID ? in_bundle->vlan
+            : OFP_VLAN_NONE;
+        // Untag only if untagged-pvid mode and vlan=tag
+        if (out_bundle->vlan_mode == PORT_VLAN_UNTAGGED_PVID
+            &&  fromVlan == out_bundle->vlan) {
+            dst->vlan = OFP_VLAN_NONE;
+        // All other cases
+        } else {
+            dst->vlan = fromVlan;
+        }
+    }
     dst->port = (!out_bundle->bond
                  ? ofbundle_get_a_port(out_bundle)
                  : bond_choose_output_slave(out_bundle->bond, &ctx->flow,
                                             dst->vlan, &ctx->tags));
-
     return dst->port != NULL;
 }
 
@@ -3597,8 +3631,15 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct 
flow *flow,
               struct ofbundle *in_bundle, bool have_packet)
 {
     int vlan = vlan_tci_to_vid(flow->vlan_tci);
-    if (in_bundle->vlan >= 0) {
-        if (vlan) {
+
+    /* First case : vlan != 0 input packet is tagged. Returns:             */
+    /* - -1 if vlan mode is access or empty                                */
+    /* - flow vlan if vlan mode is trunk or (untagged-)pvid and flow vlan  */
+    /*   is part of the trunk                                              */
+    /* - -1 if vlan mode is trunk or (untagged-)pvid and flow vlan is not  */
+    /*   part of the trunk                                                 */
+    if (vlan) {
+        if (in_bundle->vlan_mode <= PORT_VLAN_ACCESS) {
             if (have_packet) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %d tagged "
@@ -3608,10 +3649,9 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct 
flow *flow,
                              in_bundle->name, in_bundle->vlan);
             }
             return -1;
-        }
-        vlan = in_bundle->vlan;
-    } else {
-        if (!ofbundle_includes_vlan(in_bundle, vlan)) {
+        } else if (ofbundle_includes_vlan(in_bundle, vlan)) {
+            return vlan;
+        } else {
             if (have_packet) {
                 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
                 VLOG_WARN_RL(&rl, "bridge %s: dropping VLAN %d tagged "
@@ -3621,9 +3661,22 @@ flow_get_vlan(struct ofproto_dpif *ofproto, const struct 
flow *flow,
             }
             return -1;
         }
+    /* Second case : vlan=0, input packet is untagged. Returns:            */
+    /* - bundle vlan or 0 if vlan mode is empty                            */
+    /* - bundle vlan if vlan mode is access or (untagged-)pvid             */
+    /* - 0 if mode is trunk and flow vlan (0) is part of the trunk         */
+    /* - -1 if mode is trunk and flow vlan (0) is not part of the trunk    */
+    } else {
+        if (in_bundle->vlan_mode == PORT_VLAN_EMPTY ) {
+            return in_bundle->vlan >= 0 ? in_bundle->vlan : 0;
+        } else if (in_bundle->vlan_mode == PORT_VLAN_ACCESS || 
in_bundle->vlan_mode >= PORT_VLAN_TAGGED_PVID) {
+            return in_bundle->vlan;
+        } else if (ofbundle_includes_vlan(in_bundle, 0)) {
+            return 0;
+        } else {
+            return -1;
+        }
     }
-
-    return vlan;
 }
 
 /* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
@@ -3823,7 +3876,7 @@ done:
         compose_actions(ctx, vlan, in_bundle, out_bundle);
     }
 }
-

+
 static bool
 get_drop_frags(struct ofproto *ofproto_)
 {
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 4975a8d..90a5f2a 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -178,6 +178,27 @@ void ofproto_port_set_cfm(struct ofproto *, uint16_t 
ofp_port,
                           const struct cfm_settings *);
 int ofproto_port_is_lacp_current(struct ofproto *, uint16_t ofp_port);
 
+/* The behaviour of the port regarding VLAN handling */
+enum port_vlan_mode {
+    /* Same behavior as previous OpenVswitch versions, for             */
+    /* compatibility. PVID feature is disabled */
+    PORT_VLAN_EMPTY,
+    /* This port is an access port. All packets are tagged with "vlan" */
+    /* that comes from the "tag" column. The "trunk" column is ignored */
+    PORT_VLAN_ACCESS,
+    /* This port is a trunk.  The "tag" column is ignored. Packets are */
+    /* unchanged. */
+    PORT_VLAN_TRUNK,
+    /* Untagged incoming packets are tagged with "vlan" comming from   */
+    /* the "tag" column . Outgoing packets tagged with "vlan" stay     */
+    /* tagged. The "tag" and "trunks" columns are both used.           */
+    PORT_VLAN_TAGGED_PVID,
+    /* Untagged incoming packets are tagged with "vlan" comming from   */
+    /* the "tag" column. Outgoing packets tagged with "vlan" are       */
+    /* untagged. The "tag" and "trunks" columns are both used. */
+    PORT_VLAN_UNTAGGED_PVID,
+};
+
 /* Configuration of bundles. */
 struct ofproto_bundle_settings {
     char *name;                 /* For use in log messages. */
@@ -185,6 +206,7 @@ struct ofproto_bundle_settings {
     uint16_t *slaves;           /* OpenFlow port numbers for slaves. */
     size_t n_slaves;
 
+    enum port_vlan_mode vlan_mode; /* Selects mode for vlan and trunks */
     int vlan;                   /* VLAN if access port, -1 if trunk port. */
     unsigned long *trunks;      /* vlan_bitmap, NULL to trunk all VLANs. */
 
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 6a4ebe5..3753d43 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -482,6 +482,23 @@ port_configure(struct port *port)
         s.slaves[s.n_slaves++] = iface->ofp_port;
     }
 
+    /* Get VLAN mode */
+    s.vlan_mode = PORT_VLAN_EMPTY;
+    if (cfg->vlan_mode) {
+        if (!strcmp(cfg->vlan_mode, "access")) {
+            s.vlan_mode = PORT_VLAN_ACCESS;
+        } else if (!strcmp(cfg->vlan_mode, "trunk")) {
+            s.vlan_mode = PORT_VLAN_TRUNK;
+        } else if (!strcmp(cfg->vlan_mode, "pvid")) {
+            s.vlan_mode = PORT_VLAN_TAGGED_PVID;
+        } else if (!strcmp(cfg->vlan_mode, "untagged-pvid")) {
+            s.vlan_mode = PORT_VLAN_UNTAGGED_PVID;
+        } else {
+            VLOG_WARN("port %s: unknown VLAN mode %s.",
+                      port->name, cfg->vlan_mode);
+        }
+    }
+
     /* Get VLAN tag. */
     s.vlan = -1;
     if (cfg->tag) {
@@ -502,9 +519,11 @@ port_configure(struct port *port)
     s.trunks = NULL;
     if (s.vlan < 0 && cfg->n_trunks) {
         s.trunks = vlan_bitmap_from_array(cfg->trunks, cfg->n_trunks);
-    } else if (s.vlan >= 0 && cfg->n_trunks) {
-        VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
-                 port->name);
+    } else if (s.vlan >= 0 && cfg->n_trunks ) {
+        if (s.vlan_mode == PORT_VLAN_EMPTY) {
+            VLOG_ERR("port %s: ignoring trunks in favor of implicit vlan",
+                     port->name);
+        }
     }
 
     /* Get LACP settings. */
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index ca61a2c..1c5c530 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
- "version": "5.2.0",
- "cksum": "434778864 14545",
+ "version": "5.3.0",
+ "cksum": "146825217 14717",
  "tables": {
    "Open_vSwitch": {
      "columns": {
@@ -115,6 +115,10 @@
                           "minInteger": 0,
                           "maxInteger": 4095},
                   "min": 0, "max": 1}},
+       "vlan_mode": {
+         "type": {"key": {"type": "string",
+           "enum": ["set", ["trunk", "access", "pvid", "untagged-pvid"]]},
+         "min": 0, "max": 1}},
        "qos": {
          "type": {"key": {"type": "uuid",
                           "refTable": "QoS"},
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index b3029eb..895fc67 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -481,8 +481,8 @@
     </column>
 
     <group title="VLAN Configuration">
-      <p>A bridge port must be configured for VLANs in one of two
-        mutually exclusive ways:
+      <p>A bridge port must be configured for VLANs in one of these
+        ways:
         <ul>
           <li>A ``trunk port'' has an empty value for <ref
             column="tag"/>.  Its <ref column="trunks"/> value may be
@@ -490,11 +490,32 @@
           <li>An ``implicitly tagged VLAN port'' or ``access port''
             has an nonempty value for <ref column="tag"/>.  Its
             <ref column="trunks"/> value must be empty.</li>
+          <li>An trunk port for tagged packets mixed with implicitly 
+            tagged VLAN for untagged packets. The implicit tag is 
+            called Port VLAN identifier (PVID). The VLAN tag persistence
+            is configurable. When disabled (untagged PVID), the VLAN tag 
+            is removed from leaving packets whose VLAN tag matches the 
+            port PVID.</li>
         </ul>
-        If <ref column="trunks"/> and <ref column="tag"/> are both
-        nonempty, the configuration is ill-formed.
       </p>
 
+      <column name="vlan_mode">
+        <p>
+          This allows to select the working mode of the port. Allowed 
+          values are:
+          <ul>
+            <li>empty: the OpenVswitch standard behaviour is used.</li>
+            <li>access: the port is an access port (see above).</li>
+            <li>untagged-pvid: tagged packets are unchanged. Arriving
+              untagged packets are tagged with PVID. Leaving packets
+              tagged with PVID are untagged.</li>
+            <li>pvid: tagged packets are unchanged. Arriving
+              untagged packets are tagged with PVID. Leaving packets
+              tagged with PVID are unchanged.</li>
+          </ul>
+        </p>
+      </column>
+
       <column name="tag">
         <p>
           If this is an access port (see above), the port's implicitly
@@ -513,6 +534,27 @@
           When a frame with a 802.1Q header that indicates a nonzero
           VLAN is received on an access port, it is discarded.
         </p>
+        <p>
+          If this is a pvid or untagged-pvid port, this column contains
+          the PVID value. The <ref column="trunks"/> value must also be
+          defined.
+        </p>
+        <p>
+          Frames arriving on this port with an 802.1Q header indicating
+          a nonzero VLAN will be forwarded based on destination 
+          <ref column="trunks"/> value. Frames arriving on this port 
+          without an 802.1Q header or with an 802.1Q header indicating
+          VLAN 0 will first be tagged with <ref column="tag"/> value 
+          then will be forwarded based on destination
+          <ref column="trunks"/> value.
+       </p>
+       <p>
+          Frames leaving this port will keep their VLAN header expect 
+          if mode is untagged-pvid. In this case, all frames leaving 
+          this port will keep their VLAN header if it is different 
+          from <ref column="tag"/>. If it is equal to <ref column="tag"/>
+          the frame is untagged.
+        </p>
       </column>
 
       <column name="trunks">
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to