[ovs-dev] [PATCH 1/1] vswitchd: PVID (Port VLAN ID) tagging feature

Philippe Jung phil.jung at free.fr
Fri Jul 29 23:41:04 UTC 2011


Hi,

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

Typical cookbook for using PVID:

One physical host (so one physical network)
Four virtual machines : VM1 and VM2 belongs to project 1, VM3 and VM4 
belongs
to project 2.
Two DHCP servers : VM1 and VM3 are DHCP/TFTP/BOOTP service providers
Two machines to install : VM2 has no OS installed. At boot time, VM2 
must get
IP address, TFTP server from VM1. VM4 depends on VM3 for an equivalent 
service

VM2 and VM4 send untagged packet at boot time. VM1 and VM3 receive it and
answer VM2 stars to install the application developped by project 2. 
Project 1
team is not happy

So:
VM1 and VM2 are configured with trunks="[1]", pvid=1, untag_pvid=true
VM3 is configured with trunks="[2]", pvid=2, untag_pvid=false
VM4 is configured with trunks="[2]", pvid=2, untag_pvid=true

At boot time, VM2 sends untagged DHCP request. It goes into the switch. 
As soon
as the packet is received it is tagged with VLAN ID 1. So now, only 
possible
destination is VM1. Packet is ready to go out of the switch. untag_pvid 
is true
so, as tag (1) is equal to PVID, the tag is removed.
VM1 receives the untagged DHCP request. DHCP OFFER goes the opposite way.

VM3 bond0 is used for administration so the DHCP service is exposed on 
bond0.2
VM4 sends the DHCP requests. It goes out of the switch still tagged
(untag_pvid=false). bond0.2 receives the packet. DHCP OFFER goes the 
opposite
way.

Typical use:
ovs-vsctl set port tap1 trunks="[10 20]"
ovs-vsctl set port tap1 pvid=10 (default for pvid is 0)
ovs-vsctl set port tap1 untag_pvid=true (default for untag_pvid is false)

To reset PVID to disable the feature:
ovs-vsctl set port tap1 pvid=0

---

Summary of changes:
===================
- updated schema: untag_pvid (boolean) and pvid (integer) added to table 
Port.
   Schema version changed to 3.2.0
- changed bridge.c in vswitchd

Tested with two VMs with & without trunks, with & without PVID, with & 
without
untag_pvid. Also tested with 20 VM hosted on 2 blades (2 vswitchd + 1 
physical
switch) with 10 VLANs. Seems to work :-)

Point of attention: based on what I have seen vswitchd seems to be used by
other components (openflow controller,...) I have the feeling that my patch
is inside the vswitchd perimeter and should not impact other components of
OpenVswitch. However, if someone with the full knownledge of OpenVswitch 
could
have a quick look and confirm my feeling...


Philippe

<--------- START OF PATCH ------------->

diff -up openvswitch-1.1.1/vswitchd/bridge.c 
openvswitch-1.1.1.modified/vswitchd/bridge.c
--- openvswitch-1.1.1/vswitchd/bridge.c    2011-05-30 07:57:20.000000000 
+0200
+++ openvswitch-1.1.1.modified/vswitchd/bridge.c    2011-07-29 
23:37:48.000000000 +0200
@@ -159,6 +159,8 @@ struct port {
      struct hmap_node hmap_node; /* Element in struct bridge's "ports" 
hmap. */
      char *name;

+    int pvid;                   /* port vlan id, -1=pvid disabled, else 
a 12-bit VLAN ID */
+    bool untag_pvid;            /* if true, outgoing trafic tagged with 
pvid is untagged */
      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. */
@@ -2502,10 +2504,19 @@ set_dst(struct dst *dst, const struct fl
          const struct port *in_port, const struct port *out_port,
          tag_type *tags)
  {
+    // If source vlan is not tagged and source port has pvid, uses
+    // this value
      dst->vlan = (out_port->vlan >= 0 ? OFP_VLAN_NONE
                : in_port->vlan >= 0 ? in_port->vlan
-              : flow->vlan_tci == 0 ? OFP_VLAN_NONE
+              : flow->vlan_tci == 0 ? (in_port->pvid > 0 ? 
in_port->pvid : OFP_VLAN_NONE)
                : vlan_tci_to_vid(flow->vlan_tci));
+
+    // If target vlan is out_port->pvid and the port is configured with 
untagged pvid
+    //  then the vlan tag should be removed
+    if (out_port->pvid > 0 && dst->vlan == out_port->pvid && 
out_port->untag_pvid) {
+        dst->vlan = OFP_VLAN_NONE;
+    }
+
      return choose_output_iface(out_port, flow, dst->vlan,
&dst->dp_ifidx, tags);
  }
@@ -2667,7 +2678,13 @@ compose_dsts(const struct bridge *br, co

      flow_vlan = vlan_tci_to_vid(flow->vlan_tci);
      if (flow_vlan == 0) {
-        flow_vlan = OFP_VLAN_NONE;
+        // Untagged packet on a port with pvid must be considered
+        // as packet tagged with pvid
+        if (in_port->pvid > 0) {
+            flow_vlan = in_port->pvid;
+        } else {
+            flow_vlan = OFP_VLAN_NONE;
+        }
      }

      if (out_port == FLOOD_PORT) {
@@ -2792,6 +2809,11 @@ static int flow_get_vlan(struct bridge *
                           struct port *in_port, bool have_packet)
  {
      int vlan = vlan_tci_to_vid(flow->vlan_tci);
+    // Untagged packet on a port with pvid must be considered
+    // as packet tagged with pvid
+    if (vlan == 0 && in_port->pvid > 0) {
+        vlan = in_port->pvid;
+    }
      if (in_port->vlan >= 0) {
          if (vlan) {
              /* XXX support double tagging? */
@@ -3973,6 +3995,8 @@ port_create(struct bridge *br, const cha

      port = xzalloc(sizeof *port);
      port->bridge = br;
+    port->pvid = -1;
+    port->untag_pvid = false;
      port->vlan = -1;
      port->trunks = NULL;
      port->name = xstrdup(name);
@@ -4058,6 +4082,8 @@ port_reconfigure(struct port *port, cons
      long long int next_rebalance, miimon_next_update, lacp_priority;
      bool need_flush = false;
      unsigned long *trunks;
+    int pvid;
+    bool untag_pvid = false;
      int vlan;
      size_t i;

@@ -4204,6 +4230,27 @@ port_reconfigure(struct port *port, cons
          port->lacp = NULL;
      }

+    /* Get PVID tag. */
+    pvid = cfg->pvid;
+    if (pvid > 0 && pvid <= 4095) {
+        VLOG_DBG("port %s: assigning PVID tag %d", port->name, pvid);
+    } else {
+        VLOG_DBG("port %s: no PVID tagging", port->name);
+        pvid = -1;
+    }
+    if (port->pvid != pvid) {
+        port->pvid = pvid;
+        need_flush = true;
+    }
+
+    /* Get UNTAG_PVID value. */
+    untag_pvid = cfg->untag_pvid;
+    VLOG_DBG("port %s: setting untag_pvid to %s", port->name, 
(untag_pvid?"Enabled":"Disabled") );
+    if (port->untag_pvid != untag_pvid) {
+        port->untag_pvid = untag_pvid;
+        need_flush = true;
+    }
+
      /* Get VLAN tag. */
      vlan = -1;
      if (cfg->tag) {
diff -up openvswitch-1.1.1/vswitchd/vswitch.ovsschema 
openvswitch-1.1.1.modified/vswitchd/vswitch.ovsschema
--- openvswitch-1.1.1/vswitchd/vswitch.ovsschema    2011-05-30 
07:57:20.000000000 +0200
+++ openvswitch-1.1.1.modified/vswitchd/vswitch.ovsschema    2011-07-29 
14:48:01.000000000 +0200
@@ -1,6 +1,6 @@
  {"name": "Open_vSwitch",
- "version": "3.1.0",
- "cksum": "2572059147 15155",
+ "version": "3.2.0",
+ "cksum": "3152676546 15253",
   "tables": {
     "Open_vSwitch": {
       "columns": {
@@ -102,6 +102,10 @@
           "type": {"key": {"type": "uuid",
                            "refTable": "Interface"},
                    "min": 1, "max": "unlimited"}},
+       "pvid": {
+         "type": "integer"},
+       "untag_pvid": {
+         "type": "boolean"},
         "trunks": {
           "type": {"key": {"type": "integer",
                            "minInteger": 0,



More information about the dev mailing list