From patchwork Wed Mar 1 22:48:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Garver X-Patchwork-Id: 734390 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3vYVyY1knNz9s7q for ; Thu, 2 Mar 2017 09:50:13 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id E0F13B5A; Wed, 1 Mar 2017 22:48:13 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 8B44B949 for ; Wed, 1 Mar 2017 22:48:11 +0000 (UTC) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id F38131E6 for ; Wed, 1 Mar 2017 22:48:07 +0000 (UTC) Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8C43E61D02 for ; Wed, 1 Mar 2017 22:48:08 +0000 (UTC) Received: from wsfd-netdev-buildsys.ntdv.lab.eng.bos.redhat.com (wsfd-netdev-buildsys.ntdv.lab.eng.bos.redhat.com [10.19.17.61]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id v21Mm6OK024652 for ; Wed, 1 Mar 2017 17:48:08 -0500 From: Eric Garver To: ovs dev Date: Wed, 1 Mar 2017 17:48:00 -0500 Message-Id: <20170301224805.619-3-e@erig.me> In-Reply-To: <20170301224805.619-1-e@erig.me> References: <20170301224805.619-1-e@erig.me> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Wed, 01 Mar 2017 22:48:08 +0000 (UTC) X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH 2/7] Add new port VLAN mode "dot1q-tunnel" X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org - Example: ovs-vsctl set Port p1 vlan_mode=dot1q-tunnel tag=100 Pushes another VLAN 100 header on packets (tagged and untagged) on ingress, and pops it on egress. - Customer VLAN check: ovs-vsctl set Port p1 vlan_mode=dot1q-tunnel tag=100 cvlans=10,20 Only customer VLAN of 10 and 20 are allowed. Co-authored-by: Xiao Liang Signed-off-by: Xiao Liang Signed-off-by: Eric Garver --- NEWS | 1 + ofproto/ofproto-dpif-xlate.c | 76 ++++++++++++++++++++++++++---- ofproto/ofproto-dpif-xlate.h | 4 +- ofproto/ofproto-dpif.c | 33 ++++++++++++- ofproto/ofproto.h | 8 +++- tests/ofproto-dpif.at | 110 +++++++++++++++++++++++++------------------ vswitchd/bridge.c | 27 ++++++++++- vswitchd/vswitch.ovsschema | 16 +++++-- vswitchd/vswitch.xml | 31 ++++++++++++ 9 files changed, 242 insertions(+), 64 deletions(-) diff --git a/NEWS b/NEWS index ca95bd313198..bbd6c92dacc1 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,7 @@ Post-v2.7.0 - Tunnels: * Added support to set packet mark for tunnel endpoint using `egress_pkt_mark` OVSDB option. + * New dot1q-tunnel (CVLAN) type via 802.1ad support. - EMC insertion probability is reduced to 1% and is configurable via the new 'other_config:emc-insert-inv-prob' option. - ovs-ofctl: diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 321b3ffc314a..53244f8f7685 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -127,9 +127,13 @@ struct xbundle { struct lacp *lacp; /* LACP handle or null. */ enum port_vlan_mode vlan_mode; /* VLAN mode. */ + uint16_t qinq_ethtype; /* Ethertype of dot1q-tunnel interface + * either 0x8100 or 0x88a8. */ 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. */ + unsigned long *cvlans; /* Bitmap of allowed customer vlans, + * NULL if all VLANs are allowed */ bool use_priority_tags; /* Use 802.1p tag for frames in VLAN 0? */ bool floodable; /* No port has OFPUTIL_PC_NO_FLOOD set? */ bool protected; /* Protected port mode */ @@ -499,6 +503,7 @@ static bool input_vid_is_valid(const struct xlate_ctx *, uint16_t vid, struct xbundle *); static void xvlan_copy(struct xvlan *dst, const struct xvlan *src); static void xvlan_pop(struct xvlan *src); +static void xvlan_push_uninit(struct xvlan *src); static void xvlan_extract(const struct flow *, struct xvlan *); static void xvlan_put(struct flow *, const struct xvlan *); static void xvlan_input_translate(const struct xbundle *, @@ -550,8 +555,8 @@ static void xlate_xbridge_set(struct xbridge *, struct dpif *, const struct dpif_backer_support *); static void xlate_xbundle_set(struct xbundle *xbundle, enum port_vlan_mode vlan_mode, - int vlan, - unsigned long *trunks, + uint16_t qinq_ethtype, int vlan, + unsigned long *trunks, unsigned long *cvlans, bool use_priority_tags, const struct bond *bond, const struct lacp *lacp, bool floodable, bool protected); @@ -857,8 +862,8 @@ xlate_xbridge_set(struct xbridge *xbridge, static void xlate_xbundle_set(struct xbundle *xbundle, - enum port_vlan_mode vlan_mode, - int vlan, unsigned long *trunks, + enum port_vlan_mode vlan_mode, uint16_t qinq_ethtype, + int vlan, unsigned long *trunks, unsigned long *cvlans, bool use_priority_tags, const struct bond *bond, const struct lacp *lacp, bool floodable, bool protected) @@ -866,8 +871,10 @@ xlate_xbundle_set(struct xbundle *xbundle, ovs_assert(xbundle->xbridge); xbundle->vlan_mode = vlan_mode; + xbundle->qinq_ethtype = qinq_ethtype; xbundle->vlan = vlan; xbundle->trunks = trunks; + xbundle->cvlans = cvlans; xbundle->use_priority_tags = use_priority_tags; xbundle->floodable = floodable; xbundle->protected = protected; @@ -962,8 +969,8 @@ xlate_xbundle_copy(struct xbridge *xbridge, struct xbundle *xbundle) new_xbundle->name = xstrdup(xbundle->name); xlate_xbundle_init(new_xcfg, new_xbundle); - xlate_xbundle_set(new_xbundle, xbundle->vlan_mode, - xbundle->vlan, xbundle->trunks, + xlate_xbundle_set(new_xbundle, xbundle->vlan_mode, xbundle->qinq_ethtype, + xbundle->vlan, xbundle->trunks, xbundle->cvlans, xbundle->use_priority_tags, xbundle->bond, xbundle->lacp, xbundle->floodable, xbundle->protected); LIST_FOR_EACH (xport, bundle_node, &xbundle->xports) { @@ -1157,8 +1164,8 @@ xlate_remove_ofproto(struct ofproto_dpif *ofproto) void xlate_bundle_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, const char *name, enum port_vlan_mode vlan_mode, - int vlan, - unsigned long *trunks, + uint16_t qinq_ethtype, int vlan, + unsigned long *trunks, unsigned long *cvlans, bool use_priority_tags, const struct bond *bond, const struct lacp *lacp, bool floodable, bool protected) @@ -1179,7 +1186,7 @@ xlate_bundle_set(struct ofproto_dpif *ofproto, struct ofbundle *ofbundle, free(xbundle->name); xbundle->name = xstrdup(name); - xlate_xbundle_set(xbundle, vlan_mode, vlan, trunks, + xlate_xbundle_set(xbundle, vlan_mode, qinq_ethtype, vlan, trunks, cvlans, use_priority_tags, bond, lacp, floodable, protected); } @@ -1701,6 +1708,12 @@ xbundle_trunks_vlan(const struct xbundle *bundle, uint16_t vlan) } static bool +xbundle_allows_cvlan(const struct xbundle *bundle, uint16_t vlan) +{ + return (!bundle->cvlans || bitmap_is_set(bundle->cvlans, vlan)); +} + +static bool xbundle_includes_vlan(const struct xbundle *xbundle, const struct xvlan *xvlan) { switch (xbundle->vlan_mode) { @@ -1712,6 +1725,10 @@ xbundle_includes_vlan(const struct xbundle *xbundle, const struct xvlan *xvlan) case PORT_VLAN_NATIVE_TAGGED: return xbundle_trunks_vlan(xbundle, xvlan->v[0].vid); + case PORT_VLAN_DOT1Q_TUNNEL: + return xvlan->v[0].vid == xbundle->vlan && + xbundle_allows_cvlan(xbundle, xvlan->v[1].vid); + default: OVS_NOT_REACHED(); } @@ -1948,6 +1965,15 @@ input_vid_is_valid(const struct xlate_ctx *ctx, } return true; + case PORT_VLAN_DOT1Q_TUNNEL: + if (!xbundle_allows_cvlan(in_xbundle, vid)) { + xlate_report_error(ctx, "dropping VLAN %"PRIu16" packet received " + "on port %s not configured for dot1q tunneling" + "VLAN %"PRIu16, vid, in_xbundle->name, vid); + return false; + } + return true; + default: OVS_NOT_REACHED(); } @@ -1968,6 +1994,13 @@ xvlan_pop(struct xvlan *src) sizeof(src->v[FLOW_MAX_VLAN_HEADERS - 1])); } +static void +xvlan_push_uninit(struct xvlan *src) +{ + memmove(&src->v[1], &src->v[0], sizeof(src->v) - sizeof(src->v[0])); + memset(&src->v[0], 0, sizeof(src->v[0])); +} + /* Extract VLAN information (headers) from flow */ static void xvlan_extract(const struct flow *flow, struct xvlan *xvlan) @@ -2035,6 +2068,14 @@ xvlan_input_translate(const struct xbundle *in_xbundle, } break; + case PORT_VLAN_DOT1Q_TUNNEL: + xvlan_copy(xvlan, in_xvlan); + xvlan_push_uninit(xvlan); + xvlan->v[0].tpid = in_xbundle->qinq_ethtype; + xvlan->v[0].vid = in_xbundle->vlan; + xvlan->v[0].pcp = 0; + break; + default: OVS_NOT_REACHED(); } @@ -2064,11 +2105,26 @@ xvlan_output_translate(const struct xbundle *out_xbundle, } break; + case PORT_VLAN_DOT1Q_TUNNEL: + xvlan_copy(out_xvlan, xvlan); + xvlan_pop(out_xvlan); + break; + default: OVS_NOT_REACHED(); } } +/* If output xbundle is dot1q-tunnel, set mask bits of cvlan */ +static void +check_and_set_cvlan_mask(struct flow_wildcards *wc, + const struct xbundle *xbundle) +{ + if (xbundle->vlan_mode == PORT_VLAN_DOT1Q_TUNNEL && xbundle->cvlans) { + wc->masks.vlans[1].tci = htons(0xffff); + } +} + static void output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, const struct xvlan *xvlan) @@ -2080,6 +2136,8 @@ output_normal(struct xlate_ctx *ctx, const struct xbundle *out_xbundle, bool use_recirc = false; struct xvlan out_xvlan; + check_and_set_cvlan_mask(ctx->wc, out_xbundle); + xvlan_output_translate(out_xbundle, xvlan, &out_xvlan); if (out_xbundle->use_priority_tags) { out_xvlan.v[0].pcp = ntohs(ctx->xin->flow.vlans[0].tci) & diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h index 708a19af0799..8a6bdf631600 100644 --- a/ofproto/ofproto-dpif-xlate.h +++ b/ofproto/ofproto-dpif-xlate.h @@ -150,8 +150,8 @@ void xlate_remove_ofproto(struct ofproto_dpif *); void xlate_bundle_set(struct ofproto_dpif *, struct ofbundle *, const char *name, enum port_vlan_mode, - int vlan, - unsigned long *trunks, + uint16_t qinq_ethtype, int vlan, + unsigned long *trunks, unsigned long *cvlans, bool use_priority_tags, const struct bond *, const struct lacp *, bool floodable, bool protected); diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 7f1d60493b99..aaea15386e79 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -94,9 +94,11 @@ struct ofbundle { /* Configuration. */ struct ovs_list ports; /* Contains "struct ofport"s. */ enum port_vlan_mode vlan_mode; /* VLAN mode */ + uint16_t qinq_ethtype; 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. */ + unsigned long *cvlans; 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? */ @@ -449,8 +451,8 @@ type_run(const char *type) HMAP_FOR_EACH (bundle, hmap_node, &ofproto->bundles) { xlate_bundle_set(ofproto, bundle, bundle->name, - bundle->vlan_mode, - bundle->vlan, bundle->trunks, + bundle->vlan_mode, bundle->qinq_ethtype, + bundle->vlan, bundle->trunks, bundle->cvlans, bundle->use_priority_tags, bundle->bond, bundle->lacp, bundle->floodable, bundle->protected); @@ -2796,6 +2798,7 @@ bundle_destroy(struct ofbundle *bundle) hmap_remove(&ofproto->bundles, &bundle->hmap_node); free(bundle->name); free(bundle->trunks); + free(bundle->cvlans); lacp_unref(bundle->lacp); bond_unref(bundle->bond); free(bundle); @@ -2810,6 +2813,7 @@ bundle_set(struct ofproto *ofproto_, void *aux, struct ofport_dpif *port; struct ofbundle *bundle; unsigned long *trunks = NULL; + unsigned long *cvlans = NULL; int vlan; size_t i; bool ok; @@ -2834,8 +2838,10 @@ bundle_set(struct ofproto *ofproto_, void *aux, ovs_list_init(&bundle->ports); bundle->vlan_mode = PORT_VLAN_TRUNK; + bundle->qinq_ethtype = ETH_TYPE_VLAN_8021AD; bundle->vlan = -1; bundle->trunks = NULL; + bundle->cvlans = NULL; bundle->use_priority_tags = s->use_priority_tags; bundle->lacp = NULL; bundle->bond = NULL; @@ -2900,6 +2906,11 @@ bundle_set(struct ofproto *ofproto_, void *aux, need_flush = true; } + if (s->qinq_ethtype != bundle->qinq_ethtype) { + bundle->qinq_ethtype= s->qinq_ethtype; + need_flush = true; + } + /* Set VLAN tag. */ vlan = (s->vlan_mode == PORT_VLAN_TRUNK ? -1 : s->vlan >= 0 && s->vlan <= 4095 ? s->vlan @@ -2937,6 +2948,10 @@ bundle_set(struct ofproto *ofproto_, void *aux, } break; + case PORT_VLAN_DOT1Q_TUNNEL: + cvlans = CONST_CAST(unsigned long *, s->cvlans); + break; + default: OVS_NOT_REACHED(); } @@ -2954,6 +2969,20 @@ bundle_set(struct ofproto *ofproto_, void *aux, free(trunks); } + if (!vlan_bitmap_equal(cvlans, bundle->cvlans)) { + free(bundle->cvlans); + if (cvlans== s->cvlans) { + bundle->cvlans = vlan_bitmap_clone(cvlans); + } else { + bundle->cvlans = cvlans; + cvlans = NULL; + } + need_flush = true; + } + if (cvlans != s->cvlans) { + free(cvlans); + } + /* Bonding. */ if (!ovs_list_is_short(&bundle->ports)) { bundle->ofproto->has_bonded_bundles = true; diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h index 2b36eaf410a5..d44845ce3cf6 100644 --- a/ofproto/ofproto.h +++ b/ofproto/ofproto.h @@ -388,7 +388,11 @@ enum port_vlan_mode { /* Untagged incoming packets are part of 'vlan', as are incoming packets * tagged with 'vlan'. Outgoing packets tagged with 'vlan' are untagged. * Other VLANs in 'trunks' are trunked. */ - PORT_VLAN_NATIVE_UNTAGGED + PORT_VLAN_NATIVE_UNTAGGED, + + /* 802.1q tunnel port. Incomming packets are added an outer vlan tag + * 'vlan'. If 'cvlans' is set, only allows VLANs in 'cvlans'. */ + PORT_VLAN_DOT1Q_TUNNEL }; /* Configuration of bundles. */ @@ -399,8 +403,10 @@ struct ofproto_bundle_settings { size_t n_slaves; enum port_vlan_mode vlan_mode; /* Selects mode for vlan and trunks */ + uint16_t qinq_ethtype; int vlan; /* VLAN VID, except for PORT_VLAN_TRUNK. */ unsigned long *trunks; /* vlan_bitmap, except for PORT_VLAN_ACCESS. */ + unsigned long *cvlans; bool use_priority_tags; /* Use 802.1p tag for frames in VLAN 0? */ struct bond_settings *bond; /* Must be nonnull iff if n_slaves > 1. */ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 56adf8c9e992..af90a7ce2056 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -3182,6 +3182,11 @@ OVS_VSWITCHD_START( add-port br0 p7 vlan_mode=native-untagged tag=12 -- \ add-port br0 p8 vlan_mode=native-untagged tag=12 trunks=10,12 \ other-config:priority-tags=true -- \ + add-port br0 p9 vlan_mode=dot1q-tunnel tag=10 qinq_ethtype=802.1q -- \ + add-port br0 p10 vlan_mode=dot1q-tunnel tag=10 cvlans=10,12 qinq_ethtype=802.1q -- \ + add-port br0 p11 vlan_mode=dot1q-tunnel tag=12 qinq_ethtype=802.1q -- \ + add-port br0 p12 vlan_mode=dot1q-tunnel tag=12 qinq_ethtype=802.1q \ + other-config:priority-tags=true -- \ set Interface p1 type=dummy -- \ set Interface p2 type=dummy -- \ set Interface p3 type=dummy -- \ @@ -3189,7 +3194,11 @@ OVS_VSWITCHD_START( set Interface p5 type=dummy -- \ set Interface p6 type=dummy -- \ set Interface p7 type=dummy -- \ - set Interface p8 type=dummy --]) + set Interface p8 type=dummy -- \ + set Interface p9 type=dummy -- \ + set Interface p10 type=dummy -- \ + set Interface p11 type=dummy -- \ + set Interface p12 type=dummy --]) dnl Each of these specifies an in_port by number, a VLAN VID (or "none"), dnl a VLAN PCP (used if the VID isn't "none") and the expected set of datapath @@ -3198,84 +3207,93 @@ for tuple in \ "100 none 0 drop" \ "100 0 0 drop" \ "100 0 1 drop" \ - "100 10 0 1,5,6,7,8,pop_vlan,2" \ - "100 10 1 1,5,6,7,8,pop_vlan,2" \ + "100 10 0 1,5,6,7,8,pop_vlan,2,9" \ + "100 10 1 1,5,6,7,8,pop_vlan,2,9" \ "100 11 0 5,7" \ "100 11 1 5,7" \ - "100 12 0 1,5,6,pop_vlan,3,4,7,8" \ - "100 12 1 1,5,6,pop_vlan,4,7,push_vlan(vid=0,pcp=1),3,8" \ + "100 12 0 1,5,6,pop_vlan,3,4,7,8,11,12" \ + "100 12 1 1,5,6,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \ "1 none 0 drop" \ "1 0 0 drop" \ "1 0 1 drop" \ - "1 10 0 5,6,7,8,100,pop_vlan,2" \ - "1 10 1 5,6,7,8,100,pop_vlan,2" \ + "1 10 0 5,6,7,8,100,pop_vlan,2,9" \ + "1 10 1 5,6,7,8,100,pop_vlan,2,9" \ "1 11 0 drop" \ "1 11 1 drop" \ - "1 12 0 5,6,100,pop_vlan,3,4,7,8" \ - "1 12 1 5,6,100,pop_vlan,4,7,push_vlan(vid=0,pcp=1),3,8" \ - "2 none 0 push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ - "2 0 0 pop_vlan,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ - "2 0 1 pop_vlan,push_vlan(vid=10,pcp=1),1,5,6,7,8,100" \ + "1 12 0 5,6,100,pop_vlan,3,4,7,8,11,12" \ + "1 12 1 5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \ + "2 none 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "2 0 0 pop_vlan,9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "2 0 1 pop_vlan,9,push_vlan(vid=10,pcp=1),1,5,6,7,8,100" \ "2 10 0 drop" \ "2 10 1 drop" \ "2 11 0 drop" \ "2 11 1 drop" \ "2 12 0 drop" \ "2 12 1 drop" \ - "3 none 0 4,7,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "3 0 0 pop_vlan,4,7,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "3 0 1 8,pop_vlan,4,7,push_vlan(vid=12,pcp=1),1,5,6,100" \ + "3 none 0 4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "3 0 0 pop_vlan,4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "3 0 1 8,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \ "3 10 0 drop" \ "3 10 1 drop" \ "3 11 0 drop" \ "3 11 1 drop" \ "3 12 0 drop" \ "3 12 1 drop" \ - "4 none 0 3,7,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "4 0 0 pop_vlan,3,7,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "4 0 1 3,8,pop_vlan,7,push_vlan(vid=12,pcp=1),1,5,6,100" \ + "4 none 0 3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "4 0 0 pop_vlan,3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "4 0 1 3,8,12,pop_vlan,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \ "4 10 0 drop" \ "4 10 1 drop" \ "4 11 0 drop" \ "4 11 1 drop" \ "4 12 0 drop" \ "4 12 1 drop" \ - "5 none 0 2,push_vlan(vid=10,pcp=0),1,6,7,8,100" \ - "5 0 0 pop_vlan,2,push_vlan(vid=10,pcp=0),1,6,7,8,100" \ - "5 0 1 pop_vlan,2,push_vlan(vid=10,pcp=1),1,6,7,8,100" \ - "5 10 0 1,6,7,8,100,pop_vlan,2" \ - "5 10 1 1,6,7,8,100,pop_vlan,2" \ + "5 none 0 2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \ + "5 0 0 pop_vlan,2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \ + "5 0 1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,6,7,8,100" \ + "5 10 0 1,6,7,8,100,pop_vlan,2,9" \ + "5 10 1 1,6,7,8,100,pop_vlan,2,9" \ "5 11 0 7,100" \ "5 11 1 7,100" \ - "5 12 0 1,6,100,pop_vlan,3,4,7,8" \ - "5 12 1 1,6,100,pop_vlan,4,7,push_vlan(vid=0,pcp=1),3,8" \ - "6 none 0 2,push_vlan(vid=10,pcp=0),1,5,7,8,100" \ - "6 0 0 pop_vlan,2,push_vlan(vid=10,pcp=0),1,5,7,8,100" \ - "6 0 1 pop_vlan,2,push_vlan(vid=10,pcp=1),1,5,7,8,100" \ - "6 10 0 1,5,7,8,100,pop_vlan,2" \ - "6 10 1 1,5,7,8,100,pop_vlan,2" \ + "5 12 0 1,6,100,pop_vlan,3,4,7,8,11,12" \ + "5 12 1 1,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \ + "6 none 0 2,9,push_vlan(vid=10,pcp=0),1,5,7,8,100" \ + "6 0 0 pop_vlan,2,9,push_vlan(vid=10,pcp=0),1,5,7,8,100" \ + "6 0 1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,5,7,8,100" \ + "6 10 0 1,5,7,8,100,pop_vlan,2,9" \ + "6 10 1 1,5,7,8,100,pop_vlan,2,9" \ "6 11 0 drop" \ "6 11 1 drop" \ - "6 12 0 1,5,100,pop_vlan,3,4,7,8" \ - "6 12 1 1,5,100,pop_vlan,4,7,push_vlan(vid=0,pcp=1),3,8" \ - "7 none 0 3,4,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "7 0 0 pop_vlan,3,4,8,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "7 0 1 3,8,pop_vlan,4,push_vlan(vid=12,pcp=1),1,5,6,100" \ - "7 10 0 1,5,6,8,100,pop_vlan,2" \ - "7 10 1 1,5,6,8,100,pop_vlan,2" \ + "6 12 0 1,5,100,pop_vlan,3,4,7,8,11,12" \ + "6 12 1 1,5,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \ + "7 none 0 3,4,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "7 0 0 pop_vlan,3,4,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "7 0 1 3,8,12,pop_vlan,4,11,push_vlan(vid=12,pcp=1),1,5,6,100" \ + "7 10 0 1,5,6,8,100,pop_vlan,2,9" \ + "7 10 1 1,5,6,8,100,pop_vlan,2,9" \ "7 11 0 5,100" \ "7 11 1 5,100" \ - "7 12 0 1,5,6,100,pop_vlan,3,4,8" \ - "7 12 1 1,5,6,100,pop_vlan,4,push_vlan(vid=0,pcp=1),3,8" \ - "8 none 0 3,4,7,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "8 0 0 pop_vlan,3,4,7,push_vlan(vid=12,pcp=0),1,5,6,100" \ - "8 0 1 3,pop_vlan,4,7,push_vlan(vid=12,pcp=1),1,5,6,100" \ - "8 10 0 1,5,6,7,100,pop_vlan,2" \ - "8 10 1 1,5,6,7,100,pop_vlan,2" \ + "7 12 0 1,5,6,100,pop_vlan,3,4,8,11,12" \ + "7 12 1 1,5,6,100,pop_vlan,4,11,push_vlan(vid=0,pcp=1),3,8,12" \ + "8 none 0 3,4,7,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "8 0 0 pop_vlan,3,4,7,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "8 0 1 3,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \ + "8 10 0 1,5,6,7,100,pop_vlan,2,9" \ + "8 10 1 1,5,6,7,100,pop_vlan,2,9" \ "8 11 0 drop" \ "8 11 1 drop" \ - "8 12 0 1,5,6,100,pop_vlan,3,4,7" \ - "8 12 1 1,5,6,100,pop_vlan,4,7,push_vlan(vid=0,pcp=1),3" + "8 12 0 1,5,6,100,pop_vlan,3,4,7,11,12" \ + "8 12 1 1,5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,12" \ + "9 none 0 2,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "9 10 0 10,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "9 11 0 push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "10 none 0 drop" \ + "10 0 0 drop" \ + "10 11 0 drop" \ + "10 12 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \ + "11 10 0 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100" \ + "11 10 1 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100" do set $tuple in_port=$1 diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index f1483112b46f..77fe686a51f2 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -978,6 +978,11 @@ port_configure(struct port *port) s.trunks = vlan_bitmap_from_array(cfg->trunks, cfg->n_trunks); } + s.cvlans = NULL; + if (cfg->n_cvlans) { + s.cvlans = vlan_bitmap_from_array(cfg->cvlans, cfg->n_cvlans); + } + /* Get VLAN mode. */ if (cfg->vlan_mode) { if (!strcmp(cfg->vlan_mode, "access")) { @@ -988,6 +993,8 @@ port_configure(struct port *port) s.vlan_mode = PORT_VLAN_NATIVE_TAGGED; } else if (!strcmp(cfg->vlan_mode, "native-untagged")) { s.vlan_mode = PORT_VLAN_NATIVE_UNTAGGED; + } else if (!strcmp(cfg->vlan_mode, "dot1q-tunnel")) { + s.vlan_mode = PORT_VLAN_DOT1Q_TUNNEL; } else { /* This "can't happen" because ovsdb-server should prevent it. */ VLOG_WARN("port %s: unknown VLAN mode %s, falling " @@ -997,7 +1004,7 @@ port_configure(struct port *port) } else { if (s.vlan >= 0) { s.vlan_mode = PORT_VLAN_ACCESS; - if (cfg->n_trunks) { + if (cfg->n_trunks || cfg->n_cvlans) { VLOG_WARN("port %s: ignoring trunks in favor of implicit vlan", port->name); } @@ -1005,6 +1012,24 @@ port_configure(struct port *port) s.vlan_mode = PORT_VLAN_TRUNK; } } + + if (cfg->qinq_ethtype) { + if (!strcmp(cfg->qinq_ethtype, "802.1q") || + !strcmp(cfg->qinq_ethtype, "0x8100")) { + s.qinq_ethtype = ETH_TYPE_VLAN_8021Q; + } else if (!strcmp(cfg->qinq_ethtype, "802.1ad") || + !strcmp(cfg->qinq_ethtype, "0x88a8")) { + s.qinq_ethtype = ETH_TYPE_VLAN_8021AD; + } else { + /* This "can't happen" because ovsdb-server should prevent it. */ + VLOG_WARN("port %s: invalid QinQ ethertype %s, falling " + "back to 802.1ad", port->name, cfg->qinq_ethtype); + s.qinq_ethtype = ETH_TYPE_VLAN_8021AD; + } + } else { + s.qinq_ethtype = ETH_TYPE_VLAN_8021AD; + } + s.use_priority_tags = smap_get_bool(&cfg->other_config, "priority-tags", false); diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema index de78dfd26d2c..c1804c847e1d 100644 --- a/vswitchd/vswitch.ovsschema +++ b/vswitchd/vswitch.ovsschema @@ -1,6 +1,6 @@ {"name": "Open_vSwitch", - "version": "7.15.0", - "cksum": "2264024465 22987", + "version": "7.16.0", + "cksum": "125603819 23400", "tables": { "Open_vSwitch": { "columns": { @@ -145,6 +145,11 @@ "minInteger": 0, "maxInteger": 4095}, "min": 0, "max": 4096}}, + "cvlans": { + "type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 4095}, + "min": 0, "max": 4096}}, "tag": { "type": {"key": {"type": "integer", "minInteger": 0, @@ -152,7 +157,12 @@ "min": 0, "max": 1}}, "vlan_mode": { "type": {"key": {"type": "string", - "enum": ["set", ["trunk", "access", "native-tagged", "native-untagged"]]}, + "enum": ["set", ["trunk", "access", "native-tagged", + "native-untagged", "dot1q-tunnel"]]}, + "min": 0, "max": 1}}, + "qinq_ethtype": { + "type": {"key": {"type": "string", + "enum": ["set", ["802.1q", "802.1ad", "0x88a8", "0x8100"]]}, "min": 0, "max": 1}}, "qos": { "type": {"key": {"type": "uuid", diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml index 14f5d14511fa..79b5462eb583 100644 --- a/vswitchd/vswitch.xml +++ b/vswitchd/vswitch.xml @@ -1326,6 +1326,22 @@ exception that a packet that egresses on a native-untagged port in the native VLAN will not have an 802.1Q header. + +
dot1q-tunnel
+
+

+ A dot1q-tunnel port tunnels packets with VLAN specified in + column. That is it adds 802.1Q header, with + ethertype and VLAN ID specified in + and , to both tagged and untagged packets on + ingress, and pops dot1q header of this VLAN on egress. +

+ +

+ If is set, only allows packets of these + VLANs. +

+

A packet will only egress through bridge ports that carry the VLAN of @@ -1349,6 +1365,13 @@ + +

+ Ethertype of dot1q-tunnel port, could be either "802.1q"(0x8100) or + "802.1ad"(0x88a8). Defaults to "802.1ad". +

+ +

For an access port, the port's implicitly tagged VLAN. For a @@ -1370,6 +1393,14 @@

+ +

+ For a trunk-qinq port if specific cvlans are specified only those + cvlans are 1ad tunneled, others are dropped. If no cvlans specified + explicitly then all cvlans are 1ad tunneled. +

+
+