This is the userspace portion of the patch.
Signed-off-by: Thomas F Herbert <[email protected]>
---
lib/flow.c | 31 +++++++++--
lib/flow.h | 12 ++--
lib/match.c | 2 +-
lib/nx-match.c | 2 +-
lib/odp-execute.c | 3 +-
lib/odp-util.c | 130 +++++++++++++++++++++++++++++++++++--------
lib/odp-util.h | 2 +-
lib/ofp-actions.c | 32 ++++++-----
lib/ofp-actions.h | 13 ++++-
lib/ofp-util.c | 2 +-
lib/packets.c | 2 +-
lib/packets.h | 7 +++
ofproto/ofproto-dpif-xlate.c | 13 ++++-
utilities/ovs-ofctl.8.in | 3 +-
14 files changed, 196 insertions(+), 58 deletions(-)
diff --git a/lib/flow.c b/lib/flow.c
index 7fb53de..d7a24c6 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -121,7 +121,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnings on ALWAYS_INLINE, so these are
* defined as macros. */
-#if (FLOW_WC_SEQ != 27)
+#if (FLOW_WC_SEQ != 28)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime "
"assertions enabled. Consider updating FLOW_WC_SEQ after "
@@ -228,7 +228,7 @@ parse_vlan(void **datap, size_t *sizep)
data_pull(datap, sizep, ETH_ADDR_LEN * 2);
- if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
+ if (eth_type_vlan(eth->eth_type)) {
if (OVS_LIKELY(*sizep
>= sizeof(struct qtag_prefix) + sizeof(ovs_be16))) {
const struct qtag_prefix *qp = data_pull(datap, sizep, sizeof *qp);
@@ -668,7 +668,7 @@ flow_unwildcard_tp_ports(const struct flow *flow, struct
flow_wildcards *wc)
void
flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
fmd->dp_hash = flow->dp_hash;
fmd->recirc_id = flow->recirc_id;
@@ -1323,6 +1323,21 @@ flow_set_vlan_pcp(struct flow *flow, uint8_t pcp)
flow->vlan_tci &= ~htons(VLAN_PCP_MASK);
flow->vlan_tci |= htons((pcp << VLAN_PCP_SHIFT) | VLAN_CFI);
}
+/*
+ * Pushes a VLAN tag for either 802.1q or 802.1ad. The combination of tci,
+ * ctci and tpid determine whether to push a 802.1q tpid or whether to
+ * push a 802.1ad service tag or whether the flow is already double tagged.
+ */
+void
+flow_push_vlan(struct flow *flow, ovs_be16 vlan_eth_type,
+ struct flow_wildcards *wc)
+{
+ if (wc) {
+ wc->masks.vlan_tpid = OVS_BE16_MAX;
+ }
+ ovs_assert(eth_type_vlan(vlan_eth_type));
+ flow->vlan_tpid = vlan_eth_type;
+}
/* Returns the number of MPLS LSEs present in 'flow'
*
@@ -1458,7 +1473,7 @@ flow_push_mpls(struct flow *flow, int n, ovs_be16
mpls_eth_type,
flow->mpls_lse[0] = set_mpls_lse_values(ttl, tc, 1, htonl(label));
/* Clear all L3 and L4 fields. */
- BUILD_ASSERT(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT(FLOW_WC_SEQ == 28);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
}
@@ -1644,8 +1659,12 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
return;
}
- if (flow->vlan_tci & htons(VLAN_CFI)) {
- eth_push_vlan(b, htons(ETH_TYPE_VLAN), flow->vlan_tci);
+ if (flow->vlan_tci & htons(VLAN_CFI) &&
+ (flow->vlan_ctci & htons(VLAN_CFI))) {
+ eth_push_vlan(b, htons(ETH_TYPE_VLAN_8021Q), flow->vlan_ctci);
+ eth_push_vlan(b, htons(ETH_TYPE_VLAN_8021AD), flow->vlan_tci);
+ } else if (flow->vlan_tci & htons(VLAN_CFI)) {
+ eth_push_vlan(b, htons(ETH_TYPE_VLAN_8021Q), flow->vlan_tci);
}
if (flow->dl_type == htons(ETH_TYPE_IP)) {
diff --git a/lib/flow.h b/lib/flow.h
index 2b053da..3e3e335 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -38,7 +38,7 @@ struct pkt_metadata;
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 27
+#define FLOW_WC_SEQ 28
/* Number of Open vSwitch extension 32-bit registers. */
#define FLOW_N_REGS 8
@@ -107,7 +107,9 @@ struct flow {
uint8_t dl_dst[6]; /* Ethernet destination address. */
uint8_t dl_src[6]; /* Ethernet source address. */
ovs_be16 dl_type; /* Ethernet frame type. */
- ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
+ ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; If 802.1ad,
outer tag */
+ ovs_be16 vlan_ctci; /* If 802.1ad, Customer TCI | VLAN_CFI, inner
tag */
+ ovs_be16 vlan_tpid; /* Vlan protocol type, either 802.1ad or
802.1q. */
ovs_be32 mpls_lse[FLOW_MAX_MPLS_LABELS]; /* MPLS label stack entry. */
/* L3 */
@@ -153,8 +155,8 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
BUILD_ASSERT_DECL(offsetof(struct flow, dp_hash) + sizeof(uint32_t)
- == sizeof(struct flow_tnl) + 176
- && FLOW_WC_SEQ == 27);
+ == sizeof(struct flow_tnl) + 180
+ && FLOW_WC_SEQ == 28);
/* Incremental points at which flow classification may be performed in
* segments.
@@ -213,6 +215,8 @@ static inline size_t flow_hash(const struct flow *,
uint32_t basis);
void flow_set_dl_vlan(struct flow *, ovs_be16 vid);
void flow_set_vlan_vid(struct flow *, ovs_be16 vid);
void flow_set_vlan_pcp(struct flow *, uint8_t pcp);
+void flow_push_vlan(struct flow *flow, ovs_be16 vlan_eth_type,
+ struct flow_wildcards *wc);
int flow_count_mpls_labels(const struct flow *, struct flow_wildcards *);
int flow_count_common_mpls_labels(const struct flow *a, int an,
diff --git a/lib/match.c b/lib/match.c
index 0eb11f0..5d4d58f 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -862,7 +862,7 @@ match_format(const struct match *match, struct ds *s,
unsigned int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "priority=%u,", priority);
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 82b472c..f36fccf 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -842,7 +842,7 @@ nx_put_raw(struct ofpbuf *b, enum ofp_version oxm, const
struct match *match,
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
/* Metadata. */
if (match->wc.masks.dp_hash) {
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 230e6e1..38fd721 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -456,11 +456,10 @@ odp_execute_actions(void *dp, struct dpif_packet
**packets, int cnt, bool steal,
case OVS_ACTION_ATTR_PUSH_VLAN: {
const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
-
for (i = 0; i < cnt; i++) {
struct ofpbuf *buf = &packets[i]->ofpbuf;
- eth_push_vlan(buf, htons(ETH_TYPE_VLAN), vlan->vlan_tci);
+ eth_push_vlan(buf, vlan->vlan_tpid, vlan->vlan_tci);
}
break;
}
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 8f5ed08..489a161 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -109,6 +109,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr, char
*namebuf, size_t bufsize)
case OVS_KEY_ATTR_IN_PORT: return "in_port";
case OVS_KEY_ATTR_ETHERNET: return "eth";
case OVS_KEY_ATTR_VLAN: return "vlan";
+ case OVS_KEY_ATTR_CVLAN: return "cvlan";
case OVS_KEY_ATTR_ETHERTYPE: return "eth_type";
case OVS_KEY_ATTR_IPV4: return "ipv4";
case OVS_KEY_ATTR_IPV6: return "ipv6";
@@ -945,6 +946,7 @@ odp_flow_key_attr_len(uint16_t type)
case OVS_KEY_ATTR_IN_PORT: return 4;
case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
case OVS_KEY_ATTR_VLAN: return sizeof(ovs_be16);
+ case OVS_KEY_ATTR_CVLAN: return sizeof(ovs_be16);
case OVS_KEY_ATTR_ETHERTYPE: return 2;
case OVS_KEY_ATTR_MPLS: return -2;
case OVS_KEY_ATTR_IPV4: return sizeof(struct ovs_key_ipv4);
@@ -1585,6 +1587,11 @@ format_odp_key_attr(const struct nlattr *a, const struct
nlattr *ma,
ma ? nl_attr_get_be16(ma) : OVS_BE16_MAX, verbose);
break;
+ case OVS_KEY_ATTR_CVLAN:
+ format_vlan_tci(ds, nl_attr_get_be16(a),
+ ma ? nl_attr_get_be16(ma) : OVS_BE16_MAX, verbose);
+ break;
+
case OVS_KEY_ATTR_MPLS: {
const struct ovs_key_mpls *mpls_key = nl_attr_get(a);
const struct ovs_key_mpls *mpls_mask = NULL;
@@ -2600,11 +2607,20 @@ odp_flow_key_from_flow__(struct ofpbuf *buf, const
struct flow *flow,
sizeof *eth_key);
get_ethernet_key(data, eth_key);
- if (flow->vlan_tci != htons(0) || flow->dl_type == htons(ETH_TYPE_VLAN)) {
- if (export_mask) {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ if (flow->vlan_tci != htons(0) || eth_type_vlan(flow->dl_type)) {
+ if (flow->vlan_ctci != htons(0)) {
+ if (export_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ } else {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE,
htons(ETH_TYPE_VLAN_8021AD));
+ }
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_CVLAN, data->vlan_ctci);
} else {
- nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, htons(ETH_TYPE_VLAN));
+ if (export_mask) {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE, OVS_BE16_MAX);
+ } else {
+ nl_msg_put_be16(buf, OVS_KEY_ATTR_ETHERTYPE,
htons(ETH_TYPE_VLAN_8021Q));
+ }
}
nl_msg_put_be16(buf, OVS_KEY_ATTR_VLAN, data->vlan_tci);
encap = nl_msg_start_nested(buf, OVS_KEY_ATTR_ENCAP);
@@ -3304,6 +3320,9 @@ parse_8021q_onward(const struct nlattr
*attrs[OVS_KEY_ATTR_MAX + 1],
flow->vlan_tci = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN)
? nl_attr_get_be16(attrs[OVS_KEY_ATTR_VLAN])
: htons(0));
+ flow->vlan_ctci = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_CVLAN)
+ ? nl_attr_get_be16(attrs[OVS_KEY_ATTR_CVLAN])
+ : htons(0));
if (!is_mask) {
if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN))) {
return ODP_FIT_TOO_LITTLE;
@@ -3425,7 +3444,7 @@ odp_flow_key_to_flow__(const struct nlattr *key, size_t
key_len,
if (is_mask
? (src_flow->vlan_tci & htons(VLAN_CFI)) != 0
- : src_flow->dl_type == htons(ETH_TYPE_VLAN)) {
+ : eth_type_vlan(src_flow->dl_type)) {
return parse_8021q_onward(attrs, present_attrs, out_of_range_attr,
expected_attrs, flow, key, key_len,
src_flow);
}
@@ -3654,37 +3673,104 @@ commit_set_ether_addr_action(const struct flow *flow,
struct flow *base_flow,
put_ethernet_key(&mask, &wc->masks);
}
}
-
+static int
+flow_get_vlan_depth(const struct flow *flow)
+{
+ int n = 0;
+ if (flow->vlan_tci & htons(VLAN_CFI))
+ n++;
+ if (flow->vlan_ctci & htons(VLAN_CFI))
+ n++;
+ return n;
+}
static void
-pop_vlan(struct flow *base,
- struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+pop_vlan(struct flow *base, struct ofpbuf *odp_actions, struct flow_wildcards
*wc)
{
+ int base_n = flow_get_vlan_depth(base);
+
+ if (base_n == 0)
+ return;
+
memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
- if (base->vlan_tci & htons(VLAN_CFI)) {
- nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN);
+ if (base_n == 1) {
+
base->vlan_tci = 0;
+ base->vlan_tpid = 0;
+ base->vlan_ctci = 0;
+
+ } else if (base_n ==2) {
+
+ base->vlan_tci = base->vlan_ctci;
+ base->vlan_ctci = 0;
+ base->vlan_tpid = htons(ETH_TYPE_VLAN_8021Q);
}
+ nl_msg_put_flag(odp_actions, OVS_ACTION_ATTR_POP_VLAN);
}
static void
-commit_vlan_action(ovs_be16 vlan_tci, struct flow *base,
- struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+push_vlan(struct flow *base, ovs_be16 vlan_tci,
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
- if (base->vlan_tci == vlan_tci) {
+ struct ovs_action_push_vlan vlan;
+ int base_n;
+ ovs_be16 tpid = htons(ETH_TYPE_VLAN_8021Q);
+
+ if (!(vlan_tci & htons(VLAN_CFI)))
return;
- }
- pop_vlan(base, odp_actions, wc);
- if (vlan_tci & htons(VLAN_CFI)) {
- struct ovs_action_push_vlan vlan;
+ memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
+
- vlan.vlan_tpid = htons(ETH_TYPE_VLAN);
- vlan.vlan_tci = vlan_tci;
- nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN,
- &vlan, sizeof vlan);
+ base_n = flow_get_vlan_depth(base);
+
+ if (base_n == 2) {
+ return;
+ } else if (base_n == 1) {
+ tpid = htons(ETH_TYPE_VLAN_8021AD);
+ base->vlan_ctci = base->vlan_tci;
+ } else if (base_n == 0) {
+ tpid = htons(ETH_TYPE_VLAN_8021Q);
+ base->vlan_ctci = 0;
}
base->vlan_tci = vlan_tci;
+ base->vlan_tpid = tpid;
+
+ vlan.vlan_tpid = tpid;
+ vlan.vlan_tci = vlan_tci;
+ nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN,
+ &vlan, sizeof vlan);
+}
+static void
+commit_vlan_action(const struct flow *flow, struct flow *base,
+ struct ofpbuf *odp_actions, struct flow_wildcards *wc)
+{
+ ovs_be16 vlan_tci = flow->vlan_tci;
+ int base_n;
+ int flow_n;
+
+
+ if ((base->vlan_tci == vlan_tci) && (base->vlan_ctci == vlan_tci))
+ return;
+
+ base_n = flow_get_vlan_depth(base);
+ flow_n = flow_get_vlan_depth(flow);
+
+
+ if (flow_n == base_n) {
+ if (vlan_tci == base->vlan_tci) {
+ return;
+ } else {
+ pop_vlan(base, odp_actions, wc);
+ push_vlan(base, vlan_tci, odp_actions, wc);
+ }
+ }
+ else if (flow_n > base_n) {
+ push_vlan(base, vlan_tci, odp_actions, wc);
+ }
+ else if (flow_n < base_n) {
+ pop_vlan(base, odp_actions, wc);
+ }
}
/* Wildcarding already done at action translation time. */
@@ -4034,7 +4120,7 @@ commit_odp_actions(const struct flow *flow, struct flow
*base,
slow = commit_set_nw_action(flow, base, odp_actions, wc, use_masked);
commit_set_port_action(flow, base, odp_actions, wc, use_masked);
commit_mpls_action(flow, base, odp_actions);
- commit_vlan_action(flow->vlan_tci, base, odp_actions, wc);
+ commit_vlan_action(flow, base, odp_actions, wc);
commit_set_priority_action(flow, base, odp_actions, wc, use_masked);
commit_set_pkt_mark_action(flow, base, odp_actions, wc, use_masked);
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 11b54dd..ef4e82c 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -133,7 +133,7 @@ void odp_portno_names_destroy(struct hmap *portno_names);
* add another field and forget to adjust this value.
*/
#define ODPUTIL_FLOW_KEY_BYTES 512
-BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
/* A buffer with sufficient size and alignment to hold an nlattr-formatted flow
* key. An array of "struct nlattr" might not, in theory, be sufficiently
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 7d9ee58..8c50411 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -1264,16 +1264,20 @@ format_STRIP_VLAN(const struct ofpact_null *a, struct
ds *s)
static enum ofperr
decode_OFPAT_RAW11_PUSH_VLAN(ovs_be16 eth_type, struct ofpbuf *out)
{
- if (eth_type != htons(ETH_TYPE_VLAN_8021Q)) {
- /* XXX 802.1AD(QinQ) isn't supported at the moment */
+ struct ofpact_push_vlan *oam;
+
+ if (!eth_type_vlan(eth_type)) {
+ /* XXX Only 802.1q and 802.1AD(QinQ) is supported. */
return OFPERR_OFPBAC_BAD_ARGUMENT;
}
- ofpact_put_PUSH_VLAN(out);
+ oam = ofpact_put_PUSH_VLAN(out);
+ oam->ethertype = eth_type;
+
return 0;
}
static void
-encode_PUSH_VLAN(const struct ofpact_null *null OVS_UNUSED,
+encode_PUSH_VLAN(const struct ofpact_push_vlan *push_vlan,
enum ofp_version ofp_version, struct ofpbuf *out)
{
if (ofp_version == OFP10_VERSION) {
@@ -1281,7 +1285,7 @@ encode_PUSH_VLAN(const struct ofpact_null *null
OVS_UNUSED,
* follow this action. */
} else {
/* XXX ETH_TYPE_VLAN_8021AD case */
- put_OFPAT11_PUSH_VLAN(out, htons(ETH_TYPE_VLAN_8021Q));
+ put_OFPAT11_PUSH_VLAN(out, push_vlan->ethertype);
}
}
@@ -1293,25 +1297,25 @@ parse_PUSH_VLAN(char *arg, struct ofpbuf *ofpacts,
char *error;
*usable_protocols &= OFPUTIL_P_OF11_UP;
- error = str_to_u16(arg, "ethertype", ðertype);
+ error = str_to_u16(arg, "push_vlan", ðertype);
if (error) {
return error;
}
- if (ethertype != ETH_TYPE_VLAN_8021Q) {
- /* XXX ETH_TYPE_VLAN_8021AD case isn't supported */
+ if (!eth_type_vlan(htons(ethertype))) {
+ /* Check for valid VLAN ethertypes */
return xasprintf("%s: not a valid VLAN ethertype", arg);
}
- ofpact_put_PUSH_VLAN(ofpacts);
+ ofpact_put_PUSH_VLAN(ofpacts)->ethertype = htons(ethertype);
return NULL;
}
static void
-format_PUSH_VLAN(const struct ofpact_null *a OVS_UNUSED, struct ds *s)
+format_PUSH_VLAN(const struct ofpact_push_vlan *a OVS_UNUSED, struct ds *s)
{
/* XXX 802.1AD case*/
- ds_put_format(s, "push_vlan:%#"PRIx16, ETH_TYPE_VLAN_8021Q);
+ ds_put_format(s, "push_vlan:%#"PRIx16, ntohs(a->ethertype));
}
/* Action structure for OFPAT10_SET_DL_SRC/DST and OFPAT11_SET_DL_SRC/DST. */
@@ -5304,8 +5308,9 @@ ofpact_check__(enum ofputil_protocol *usable_protocols,
struct ofpact *a,
return 0;
case OFPACT_PUSH_VLAN:
- if (flow->vlan_tci & htons(VLAN_CFI)) {
- /* Multiple VLAN headers not supported. */
+ if (flow->vlan_tci & htons(VLAN_CFI) &&
+ flow->vlan_ctci & htons(VLAN_CFI)) {
+ /* More then 2 levels of VLAN headers not supported. */
return OFPERR_OFPBAC_BAD_TAG;
}
/* Temporary mark that we have a vlan tag. */
@@ -5925,6 +5930,7 @@ ofpacts_get_meter(const struct ofpact ofpacts[], size_t
ofpacts_len)
/* Formatting ofpacts. */
+
static void
ofpact_format(const struct ofpact *a, struct ds *s)
{
diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index e863cdc..3c69a9a 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -66,7 +66,7 @@
OFPACT(SET_VLAN_VID, ofpact_vlan_vid, ofpact, "set_vlan_vid") \
OFPACT(SET_VLAN_PCP, ofpact_vlan_pcp, ofpact, "set_vlan_pcp") \
OFPACT(STRIP_VLAN, ofpact_null, ofpact, "strip_vlan") \
- OFPACT(PUSH_VLAN, ofpact_null, ofpact, "push_vlan") \
+ OFPACT(PUSH_VLAN, ofpact_push_vlan, ofpact, "push_vlan") \
OFPACT(SET_ETH_SRC, ofpact_mac, ofpact, "mod_dl_src") \
OFPACT(SET_ETH_DST, ofpact_mac, ofpact, "mod_dl_dst") \
OFPACT(SET_IPV4_SRC, ofpact_ipv4, ofpact, "mod_nw_src") \
@@ -393,7 +393,7 @@ struct ofpact_set_field {
union mf_value mask;
};
-/* OFPACT_PUSH_VLAN/MPLS/PBB
+/* OFPACT_PUSH_MPLS
*
* Used for NXAST_PUSH_MPLS, OFPAT11_PUSH_MPLS. */
struct ofpact_push_mpls {
@@ -401,9 +401,16 @@ struct ofpact_push_mpls {
ovs_be16 ethertype;
};
+/* OFPACT_PUSH_VLAN
+ *
+ * Used for OFPAT11_PUSH_VLAN. */
+struct ofpact_push_vlan {
+ struct ofpact ofpact;
+ ovs_be16 ethertype;
+};
/* OFPACT_POP_MPLS
*
- * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS.. */
+ * Used for NXAST_POP_MPLS, OFPAT11_POP_MPLS. */
struct ofpact_pop_mpls {
struct ofpact ofpact;
ovs_be16 ethertype;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index d765d03..8366cfe 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -185,7 +185,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
diff --git a/lib/packets.c b/lib/packets.c
index 65d8109..e7ad086 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -217,7 +217,7 @@ set_ethertype(struct ofpbuf *packet, ovs_be16 eth_type)
return;
}
- if (eh->eth_type == htons(ETH_TYPE_VLAN)) {
+ if (eth_type_vlan(eh->eth_type)) {
ovs_be16 *p;
char *l2_5 = ofpbuf_l2_5(packet);
diff --git a/lib/packets.h b/lib/packets.h
index 26c6ff1..0c2e2b7 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -251,6 +251,13 @@ static inline bool eth_type_mpls(ovs_be16 eth_type)
eth_type == htons(ETH_TYPE_MPLS_MCAST);
}
+static inline bool eth_type_vlan(ovs_be16 eth_type)
+{
+ return eth_type == htons(ETH_TYPE_VLAN_8021Q) ||
+ eth_type == htons(ETH_TYPE_VLAN_8021AD);
+}
+
+
/* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame
* lengths. */
#define ETH_TYPE_MIN 0x600
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 07a1f29..53b403b 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -2477,6 +2477,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t
ofp_port,
struct flow_wildcards *wc = &ctx->xout->wc;
struct flow *flow = &ctx->xin->flow;
ovs_be16 flow_vlan_tci;
+ ovs_be16 flow_vlan_ctci;
uint32_t flow_pkt_mark;
uint8_t flow_nw_tos;
odp_port_t out_port, odp_port;
@@ -2484,7 +2485,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t
ofp_port,
/* If 'struct flow' gets additional metadata, we'll need to zero it out
* before traversing a patch port. */
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 28);
if (!xport) {
xlate_report(ctx, "Nonexistent output port");
@@ -2576,6 +2577,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t
ofp_port,
}
flow_vlan_tci = flow->vlan_tci;
+ flow_vlan_ctci = flow->vlan_ctci;
flow_pkt_mark = flow->pkt_mark;
flow_nw_tos = flow->nw_tos;
@@ -2666,6 +2668,7 @@ compose_output_action__(struct xlate_ctx *ctx, ofp_port_t
ofp_port,
out:
/* Restore flow */
flow->vlan_tci = flow_vlan_tci;
+ flow->vlan_ctci = flow_vlan_ctci;
flow->pkt_mark = flow_pkt_mark;
flow->nw_tos = flow_nw_tos;
}
@@ -3704,6 +3707,14 @@ do_xlate_actions(const struct ofpact *ofpacts, size_t
ofpacts_len,
/* XXX 802.1AD(QinQ) */
memset(&wc->masks.vlan_tci, 0xff, sizeof wc->masks.vlan_tci);
flow->vlan_tci = htons(VLAN_CFI);
+ if (ofpact_get_PUSH_VLAN(a)->ethertype ==
htons(ETH_TYPE_VLAN_8021AD)) {
+ memset(&wc->masks.vlan_ctci, 0xff, sizeof wc->masks.vlan_ctci);
+ flow->vlan_ctci |= htons(VLAN_CFI);
+ memset(&wc->masks.vlan_tpid, 0xff, sizeof wc->masks.vlan_tpid);
+ flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021AD);
+ } else if (ofpact_get_PUSH_VLAN(a)->ethertype ==
htons(ETH_TYPE_VLAN_8021Q)) {
+ flow->vlan_tpid = htons(ETH_TYPE_VLAN_8021Q);
+ }
break;
case OFPACT_SET_ETH_SRC:
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index bcc3f33..334ec23 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -1254,8 +1254,7 @@ Strips the VLAN tag from a packet if it is present.
.
.IP \fBpush_vlan\fR:\fIethertype\fR
Push a new VLAN tag onto the packet. Ethertype is used as the the Ethertype
-for the tag. Only ethertype 0x8100 should be used. (0x88a8 which the spec
-allows isn't supported at the moment.)
+for the tag. Ethertypes 0x8100, 0x88a8, or 0x9100 may be used.
A priority of zero and the tag of zero are used for the new tag.
.
.IP \fBpush_mpls\fR:\fIethertype\fR
--
1.8.3.2
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev