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
[email protected]
http://openvswitch.org/mailman/listinfo/dev