@@ -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:
@@ -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) &
@@ -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);
@@ -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;
@@ -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. */
@@ -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
@@ -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);
@@ -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",
@@ -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.
</dd>
+
+ <dt>dot1q-tunnel</dt>
+ <dd>
+ <p>
+ A dot1q-tunnel port tunnels packets with VLAN specified in
+ <ref column="tag"/> column. That is it adds 802.1Q header, with
+ ethertype and VLAN ID specified in <ref column="qinq-ethtype"/>
+ and <ref column="tag"/>, to both tagged and untagged packets on
+ ingress, and pops dot1q header of this VLAN on egress.
+ </p>
+
+ <p>
+ If <ref column="cvlans"/> is set, only allows packets of these
+ VLANs.
+ </p>
+ </dd>
</dl>
<p>
A packet will only egress through bridge ports that carry the VLAN of
@@ -1349,6 +1365,13 @@
</ul>
</column>
+ <column name="qinq_ethtype">
+ <p>
+ Ethertype of dot1q-tunnel port, could be either "802.1q"(0x8100) or
+ "802.1ad"(0x88a8). Defaults to "802.1ad".
+ </p>
+ </column>
+
<column name="tag">
<p>
For an access port, the port's implicitly tagged VLAN. For a
@@ -1370,6 +1393,14 @@
</p>
</column>
+ <column name="cvlans">
+ <p>
+ 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.
+ </p>
+ </column>
+
<column name="other_config" key="priority-tags"
type='{"type": "boolean"}'>
<p>