[ovs-dev] [PATCH 2/4] lib: Userspace library changes to support provider VLANs
Avinash
avinashandrew at gmail.com
Tue Jun 10 13:33:44 UTC 2014
This commit contains the following changes:
1. New vlan variables (tpid and count) are added to flow structure to support
provider VLANs.
2. miniflow_extract() initialises these new variables based on received
packet.
3. Altered flow sequence is modified in all the required places.
4. commit_vlan_action() is modified to support stacked VLANs
Signed-off-by: Avinash <avinashandrew at gmail.com>
---
lib/flow.c | 53 +++++++++++++++++++++++++++++++++++++++++++----------
lib/flow.h | 8 +++++---
lib/match.c | 2 +-
lib/nx-match.c | 2 +-
lib/odp-util.c | 39 ++++++++++++++++++++++++++++++---------
lib/ofp-util.c | 2 +-
lib/packets.c | 2 +-
lib/packets.h | 16 ++++++++++++++++
8 files changed, 98 insertions(+), 26 deletions(-)
diff --git a/lib/flow.c b/lib/flow.c
index 1f7f310..06e45ac 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -57,6 +57,11 @@ BUILD_ASSERT_DECL(offsetof(struct flow, dl_type) + 2
offsetof(struct flow, dl_type) / 4
== offsetof(struct flow, vlan_tci) / 4 );
+BUILD_ASSERT_DECL(offsetof(struct flow, vlan_tpid) + 2
+ == offsetof(struct flow, vlan_count) &&
+ offsetof(struct flow, vlan_tpid) / 4
+ == offsetof(struct flow, vlan_count) / 4 );
+
BUILD_ASSERT_DECL(offsetof(struct flow, nw_frag) + 3
== offsetof(struct flow, nw_proto) &&
offsetof(struct flow, nw_tos) + 2
@@ -121,7 +126,7 @@ struct mf_ctx {
* away. Some GCC versions gave warnigns on ALWAYS_INLINE, so these are
* defined as macros. */
-#if (FLOW_WC_SEQ != 26)
+#if (FLOW_WC_SEQ != 27)
#define MINIFLOW_ASSERT(X) ovs_assert(X)
#else
#define MINIFLOW_ASSERT(X)
@@ -214,21 +219,24 @@ parse_mpls(void **datap, size_t *sizep)
}
static inline ovs_be16
-parse_vlan(void **datap, size_t *sizep)
+parse_vlan(void **datap, size_t *sizep, ovs_be16 *tpid, uint8_t *vlan_count)
{
const struct eth_header *eth = *datap;
struct qtag_prefix {
- ovs_be16 eth_type; /* ETH_TYPE_VLAN */
+ ovs_be16 eth_type; /* ETH_TYPE_VLAN or ETH_TYPE_VLAN_8021AD */
ovs_be16 tci;
};
data_pull(datap, sizep, ETH_ADDR_LEN * 2);
-
- if (eth->eth_type == htons(ETH_TYPE_VLAN)) {
+ *tpid = htons(0);
+ *vlan_count = 0;
+ 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);
+ *tpid = qp->eth_type;
+ *vlan_count = 1;
return qp->tci | htons(VLAN_CFI);
}
}
@@ -268,6 +276,27 @@ parse_ethertype(void **datap, size_t *sizep)
return htons(FLOW_DL_TYPE_NONE);
}
+static inline ovs_be16
+parse_remaining_vlans(void **datap, size_t *sizep, uint8_t *vlan_count)
+{
+ ovs_be16 dl_type;
+ struct qtag_prefix {
+ ovs_be16 eth_type; /* ETH_TYPE_VLAN or ETH_TYPE_VLAN_8021AD */
+ ovs_be16 tci;
+ };
+
+ dl_type = parse_ethertype(datap, sizep);
+ while (eth_type_vlan(dl_type)
+ && (OVS_LIKELY(*sizep
+ >= sizeof(struct qtag_prefix) + sizeof(ovs_be16)))) {
+ const struct qtag_prefix *qp = data_pull(datap, sizep, sizeof *qp);
+ /* 'tci' field contains the actual ether type */
+ dl_type = qp->tci;
+ (*vlan_count)++;
+ }
+ return dl_type;
+}
+
static inline bool
parse_icmpv6(void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
const struct in6_addr **nd_target,
@@ -391,16 +420,20 @@ miniflow_extract(struct ofpbuf *packet, const
struct pkt_metadata *md,
goto out;
} else {
ovs_be16 vlan_tci;
+ ovs_be16 vlan_tpid;
+ uint8_t vlan_count;
/* Link layer. */
BUILD_ASSERT(offsetof(struct flow, dl_dst) + 6
== offsetof(struct flow, dl_src));
miniflow_push_words(mf, dl_dst, data, ETH_ADDR_LEN * 2 / 4);
/* dl_type, vlan_tci. */
- vlan_tci = parse_vlan(&data, &size);
- dl_type = parse_ethertype(&data, &size);
+ vlan_tci = parse_vlan(&data, &size, &vlan_tpid, &vlan_count);
+ dl_type = parse_remaining_vlans(&data, &size, &vlan_count);
miniflow_push_be16(mf, dl_type, dl_type);
miniflow_push_be16(mf, vlan_tci, vlan_tci);
+ miniflow_push_be16(mf, vlan_tpid, vlan_tpid);
+ miniflow_push_be16(mf, vlan_count, vlan_count);
}
/* Parse mpls. */
@@ -656,7 +689,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 == 26);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
fmd->dp_hash = flow->dp_hash;
fmd->recirc_id = flow->recirc_id;
@@ -1316,7 +1349,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 == 26);
+ BUILD_ASSERT(FLOW_WC_SEQ == 27);
memset((char *) flow + FLOW_SEGMENT_2_ENDS_AT, 0,
sizeof(struct flow) - FLOW_SEGMENT_2_ENDS_AT);
}
@@ -1487,7 +1520,7 @@ flow_compose(struct ofpbuf *b, const struct flow *flow)
}
if (flow->vlan_tci & htons(VLAN_CFI)) {
- eth_push_vlan(b, htons(ETH_TYPE_VLAN), flow->vlan_tci);
+ eth_push_vlan(b, get_vlan_tpid(flow->vlan_count), flow->vlan_tci);
}
if (flow->dl_type == htons(ETH_TYPE_IP)) {
diff --git a/lib/flow.h b/lib/flow.h
index 139e7f6..07314dc 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 26
+#define FLOW_WC_SEQ 27
#define FLOW_N_REGS 8
BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -98,6 +98,8 @@ struct flow {
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_tpid; /* VLAN identifier; Either 802.1Q or 802.1AD */
+ uint8_t vlan_count; /* Number of stacked VLANs */
ovs_be32 mpls_lse[FLOW_MAX_MPLS_LABELS]; /* MPLS label stack entry. */
/* L3 */
@@ -129,8 +131,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) + 172
- && FLOW_WC_SEQ == 26);
+ == sizeof(struct flow_tnl) + 176
+ && FLOW_WC_SEQ == 27);
/* Incremental points at which flow classification may be performed in
* segments.
diff --git a/lib/match.c b/lib/match.c
index 93b725a..ff84d61 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -944,7 +944,7 @@ match_format(const struct match *match, struct ds
*s, unsigned int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 26);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
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 295eec0..678e6f3 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -616,7 +616,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 == 26);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
/* Metadata. */
if (match->wc.masks.dp_hash) {
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 3c69ada..e9f4dd8 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -3252,10 +3252,13 @@ parse_8021q_onward(const struct nlattr
*attrs[OVS_KEY_ATTR_MAX + 1],
/* Set vlan_tci.
* Remove the TPID from dl_type since it's not the real Ethertype. */
+ flow->vlan_tpid = flow->dl_type;
flow->dl_type = htons(0);
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_count = (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN)
+ ? 1: 0);
if (!is_mask) {
if (!(present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_VLAN))) {
return ODP_FIT_TOO_LITTLE;
@@ -3378,7 +3381,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);
}
@@ -3568,24 +3571,42 @@ pop_vlan(struct flow *base,
}
}
+/* This function determines and commits the VLAN action.
+ *
+ * POP VLAN:
+ * - Number of stacked VLANs is more in base flow than current flow.
+ * - Same number of stacked VLANs but difference in VLAN tci.
+ *
+ * PUSH VLAN: Number of stacked VLANs in current flow greater than
+ * or equal to base flow.
+ *
+ * Neither PUSH nor POP: Base and current flow has same vlan tci and count
+ */
static void
-commit_vlan_action(ovs_be16 vlan_tci, struct flow *base,
+commit_vlan_action(const struct flow *flow, struct flow *base,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
- if (base->vlan_tci == vlan_tci) {
+ if ((base->vlan_tci == flow->vlan_tci) &&
+ (base->vlan_count == flow->vlan_count)) {
return;
}
- pop_vlan(base, odp_actions, wc);
- if (vlan_tci & htons(VLAN_CFI)) {
+ if (base->vlan_count > flow->vlan_count ||
+ (base->vlan_tci != flow->vlan_tci && base->vlan_count ==
flow->vlan_count))
+ pop_vlan(base, odp_actions, wc);
+
+ if (flow->vlan_count >= base->vlan_count &&
+ flow->vlan_tci & htons(VLAN_CFI)) {
struct ovs_action_push_vlan vlan;
- vlan.vlan_tpid = htons(ETH_TYPE_VLAN);
- vlan.vlan_tci = vlan_tci;
+ vlan.vlan_tpid = get_vlan_tpid(flow->vlan_count);
+ vlan.vlan_tci = flow->vlan_tci;
nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_PUSH_VLAN,
&vlan, sizeof vlan);
}
- base->vlan_tci = vlan_tci;
+ base->vlan_tci = flow->vlan_tci;
+ base->vlan_tpid = flow->vlan_tpid;
+ base->vlan_count = flow->vlan_count;
}
static void
@@ -3885,7 +3906,7 @@ commit_odp_actions(const struct flow *flow,
struct flow *base,
slow = commit_set_nw_action(flow, base, odp_actions, wc);
commit_set_port_action(flow, base, odp_actions, wc);
commit_mpls_action(flow, base, odp_actions, wc);
- 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);
commit_set_pkt_mark_action(flow, base, odp_actions, wc);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 09e4438..9037fd4 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -132,7 +132,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 == 26);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 27);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
diff --git a/lib/packets.c b/lib/packets.c
index 6244c3f..ef1aebe 100644
--- a/lib/packets.c
+++ b/lib/packets.c
@@ -199,7 +199,7 @@ eth_pop_vlan(struct ofpbuf *packet)
struct vlan_eth_header *veh = ofpbuf_l2(packet);
if (veh && ofpbuf_size(packet) >= sizeof *veh
- && veh->veth_type == htons(ETH_TYPE_VLAN)) {
+ && (eth_type_vlan(veh->veth_type))) {
memmove((char *)veh + VLAN_HEADER_LEN, veh, 2 * ETH_ADDR_LEN);
ofpbuf_resize_l2(packet, -VLAN_HEADER_LEN);
diff --git a/lib/packets.h b/lib/packets.h
index 4575dd0..0d175f4 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -249,6 +249,22 @@ 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) ||
+ eth_type == htons(ETH_TYPE_VLAN_8021AD);
+}
+
+/*
+ * Returns vlan tpid in network byte order considering vlan count
+ */
+static inline ovs_be16 get_vlan_tpid(uint8_t vlan_count)
+{
+ return (vlan_count >= 2)
+ ? htons(ETH_TYPE_VLAN_8021AD)
+ : htons(ETH_TYPE_VLAN);
+}
+
/* Minimum value for an Ethernet type. Values below this are IEEE 802.2 frame
* lengths. */
#define ETH_TYPE_MIN 0x600
--
1.9.0
More information about the dev
mailing list