2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

Add new port VLAN mode "dot1q-tunnel"

- 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 <shaw.leon@gmail.com>
Signed-off-by: Xiao Liang <shaw.leon@gmail.com>
Signed-off-by: Eric Garver <e@erig.me>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Eric Garver 2017-03-01 17:48:00 -05:00 committed by Ben Pfaff
parent cc3ef00887
commit fed8962aff
9 changed files with 285 additions and 68 deletions

3
NEWS
View File

@ -11,7 +11,8 @@ Post-v2.7.0
'ovs-appctl vlog' commands for 'dpdk' module. Lower bound
still can be configured via extra arguments for DPDK EAL.
- The "learn" action now supports a "limit" option (see ovs-ofctl(8)).
- New support for multiple VLANs (802.1ad or "QinQ").
- New support for multiple VLANs (802.1ad or "QinQ"), including a new
"dot1q-tunnel" port VLAN mode.
v2.7.0 - 21 Feb 2017
---------------------

View File

@ -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);
}
@ -1700,6 +1707,12 @@ xbundle_trunks_vlan(const struct xbundle *bundle, uint16_t vlan)
&& (!bundle->trunks || bitmap_is_set(bundle->trunks, 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)
{
@ -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 dot1q-tunnel port %s that excludes this "
"VLAN", vid, in_xbundle->name);
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) &

View File

@ -168,8 +168,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);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -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);
@ -2857,6 +2859,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);
@ -2871,6 +2874,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;
@ -2895,8 +2899,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;
@ -2961,6 +2967,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
@ -2998,6 +3009,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();
}
@ -3015,6 +3030,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;

View File

@ -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. Incoming 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. */

View File

@ -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 other-config:qinq-ethtype=802.1q -- \
add-port br0 p10 vlan_mode=dot1q-tunnel tag=10 cvlans=10,12 other-config:qinq-ethtype=802.1q -- \
add-port br0 p11 vlan_mode=dot1q-tunnel tag=12 other-config:qinq-ethtype=802.1q -- \
add-port br0 p12 vlan_mode=dot1q-tunnel tag=12 other-config: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

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
/* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -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,12 @@ port_configure(struct port *port)
s.vlan_mode = PORT_VLAN_TRUNK;
}
}
const char *qe = smap_get_def(&cfg->other_config, "qinq-ethtype", "");
s.qinq_ethtype = (!strcmp(qe, "802.1q")
? ETH_TYPE_VLAN_8021Q
: ETH_TYPE_VLAN_8021AD);
s.use_priority_tags = smap_get_bool(&cfg->other_config, "priority-tags",
false);

View File

@ -1,6 +1,6 @@
{"name": "Open_vSwitch",
"version": "7.14.0",
"cksum": "3374030633 22987",
"version": "7.15.0",
"cksum": "544856471 23228",
"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,8 @@
"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}},
"qos": {
"type": {"key": {"type": "uuid",

View File

@ -1281,7 +1281,39 @@
</column>
<group title="VLAN Configuration">
<p>Bridge ports support the following types of VLAN configuration:</p>
<p>
In short, a VLAN (short for ``virtual LAN'') is a way to partition a
single switch into multiple switches. VLANs can be confusing, so for
an introduction, please refer to the question ``What's a VLAN?'' in the
Open vSwitch FAQ.
</p>
<p>
A VLAN is sometimes encoded into a packet using a 802.1Q or 802.1ad
VLAN header, but every packet is part of some VLAN whether or not it is
encoded in the packet. (A packet that appears to have no VLAN is part
of VLAN 0, by default.) As a result, it's useful to think of a VLAN as
a metadata property of a packet, separate from how the VLAN is encoded.
For a given port, this column determines how the encoding of a packet
that ingresses or egresses the port maps to the packet's VLAN. When a
packet enters the switch, its VLAN is determined based on its setting
in this column and its VLAN headers, if any, and then, conceptually,
the VLAN headers are then stripped off. Conversely, when a packet
exits the switch, its VLAN and the settings in this column determine
what VLAN headers, if any, are pushed onto the packet before it
egresses the port.
</p>
<p>
The VLAN configuration in this column affects Open vSwitch only when it
is doing ``normal switching.'' It does not affect flows set up by an
OpenFlow controller, outside of the OpenFlow ``normal action.''
</p>
<p>
Bridge ports support the following types of VLAN configuration:
</p>
<dl>
<dt>trunk</dt>
<dd>
@ -1329,6 +1361,29 @@
exception that a packet that egresses on a native-untagged port in
the native VLAN will not have an 802.1Q header.
</dd>
<dt>dot1q-tunnel</dt>
<dd>
<p>
A dot1q-tunnel port is somewhat like an access port. Like an
access port, it carries packets on the single VLAN specified in the
<ref column="tag"/> column and this VLAN, called the service VLAN,
does not appear in an 802.1Q header for packets that ingress or
egress on the port. The main difference lies in the behavior when
packets that include a 802.1Q header ingress on the port. Whereas
an access port drops such packets, a dot1q-tunnel port treats these
as double-tagged with the outer service VLAN <ref column="tag"/>
and the inner customer VLAN taken from the 802.1Q header.
Correspondingly, to egress on the port, a packet outer VLAN (or
only VLAN) must be <ref column="tag"/>, which is removed before
egress, which exposes the inner (customer) VLAN if one is present.
</p>
<p>
If <ref column="cvlans"/> is set, only allows packets in the
specified customer VLANs.
</p>
</dd>
</dl>
<p>
A packet will only egress through bridge ports that carry the VLAN of
@ -1373,6 +1428,37 @@
</p>
</column>
<column name="cvlans">
<p>
For a dot1q-tunnel port, the customer VLANs that this port includes.
If this is empty, the port includes all customer VLANs.
</p>
<p>
For other kinds of ports, this setting is ignored.
</p>
</column>
<column name="other_config" key="qinq-ethtype"
type='{"type": "string", "enum": ["set", ["802.1ad", "802.1q"]]}'>
<p>
For a dot1q-tunnel port, this is the TPID for the service tag, that
is, for the 802.1Q header that contains the service VLAN ID. Because
packets that actually ingress and egress a dot1q-tunnel port do not
include an 802.1Q header for the service VLAN, this does not affect
packets on the dot1q-tunnel port itself. Rather, it determines the
service VLAN for a packet that ingresses on a dot1q-tunnel port and
egresses on a trunk port.
</p>
<p>
The value <code>802.1ad</code> specifies TPID 0x88a8, which is also
the default if the setting is omitted. The value <code>802.1q</code>
specifies TPID 0x8100.
</p>
<p>
For other kinds of ports, this setting is ignored.
</p>
</column>
<column name="other_config" key="priority-tags"
type='{"type": "boolean"}'>
<p>