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