Skip to content

Commit 3b61075

Browse files
committed
Merge branch 'ovs-802.1ad'
Eric Garver says: ==================== openvswitch: add 802.1ad support This series adds 802.1ad support to openvswitch. It is a continuation of the work originally started by Thomas F Herbert - hence the large rev number. The extra VLAN is implemented by using an additional level of the OVS_KEY_ATTR_ENCAP netlink attribute. In OVS flow speak, this looks like eth_type(0x88a8),vlan(vid=100),encap(eth_type(0x8100), vlan(vid=200), encap(eth_type(0x0800), ...)) The userspace counterpart has also seen recent activity on the ovs-dev mailing lists. There are some new 802.1ad OVS tests being added - also on the ovs-dev list. This patch series has been tested using the most recent version of userspace (v3) and tests (v2). v22 changes: - merge patch 4 into patch 3 - fix checkpatch.pl errors - Still some 80 char warnings for long string literals - refresh pointer after pskb_may_pull() - refactor vlan nlattr parsing to remove some double checks - introduce ovs_nla_put_vlan() - move triple VLAN check to after ethertype serialization - WARN_ON_ONCE() on triple VLAN and unexpected encap values v21 changes: - Fix (and simplify) netlink attribute parsing - re-add handling of truncated VLAN tags - fix if/else dangling assignment in {push,pop}_vlan() - simplify parse_vlan() ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents d545cac + 018c1dd commit 3b61075

File tree

7 files changed

+314
-142
lines changed

7 files changed

+314
-142
lines changed

include/linux/if_vlan.h

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,23 @@ static inline int vlan_get_encap_level(struct net_device *dev)
272272
}
273273
#endif
274274

275+
/**
276+
* eth_type_vlan - check for valid vlan ether type.
277+
* @ethertype: ether type to check
278+
*
279+
* Returns true if the ether type is a vlan ether type.
280+
*/
281+
static inline bool eth_type_vlan(__be16 ethertype)
282+
{
283+
switch (ethertype) {
284+
case htons(ETH_P_8021Q):
285+
case htons(ETH_P_8021AD):
286+
return true;
287+
default:
288+
return false;
289+
}
290+
}
291+
275292
static inline bool vlan_hw_offload_capable(netdev_features_t features,
276293
__be16 proto)
277294
{
@@ -425,8 +442,7 @@ static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
425442
{
426443
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
427444

428-
if (veth->h_vlan_proto != htons(ETH_P_8021Q) &&
429-
veth->h_vlan_proto != htons(ETH_P_8021AD))
445+
if (!eth_type_vlan(veth->h_vlan_proto))
430446
return -EINVAL;
431447

432448
*vlan_tci = ntohs(veth->h_vlan_TCI);
@@ -488,7 +504,7 @@ static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
488504
* present at mac_len - VLAN_HLEN (if mac_len > 0), or at
489505
* ETH_HLEN otherwise
490506
*/
491-
if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
507+
if (eth_type_vlan(type)) {
492508
if (vlan_depth) {
493509
if (WARN_ON(vlan_depth < VLAN_HLEN))
494510
return 0;
@@ -506,8 +522,7 @@ static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
506522
vh = (struct vlan_hdr *)(skb->data + vlan_depth);
507523
type = vh->h_vlan_encapsulated_proto;
508524
vlan_depth += VLAN_HLEN;
509-
} while (type == htons(ETH_P_8021Q) ||
510-
type == htons(ETH_P_8021AD));
525+
} while (eth_type_vlan(type));
511526
}
512527

513528
if (depth)
@@ -572,8 +587,7 @@ static inline void vlan_set_encap_proto(struct sk_buff *skb,
572587
static inline bool skb_vlan_tagged(const struct sk_buff *skb)
573588
{
574589
if (!skb_vlan_tag_present(skb) &&
575-
likely(skb->protocol != htons(ETH_P_8021Q) &&
576-
skb->protocol != htons(ETH_P_8021AD)))
590+
likely(!eth_type_vlan(skb->protocol)))
577591
return false;
578592

579593
return true;
@@ -593,15 +607,14 @@ static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb)
593607
if (!skb_vlan_tag_present(skb)) {
594608
struct vlan_ethhdr *veh;
595609

596-
if (likely(protocol != htons(ETH_P_8021Q) &&
597-
protocol != htons(ETH_P_8021AD)))
610+
if (likely(!eth_type_vlan(protocol)))
598611
return false;
599612

600613
veh = (struct vlan_ethhdr *)skb->data;
601614
protocol = veh->h_vlan_encapsulated_proto;
602615
}
603616

604-
if (protocol != htons(ETH_P_8021Q) && protocol != htons(ETH_P_8021AD))
617+
if (!eth_type_vlan(protocol))
605618
return false;
606619

607620
return true;

include/uapi/linux/openvswitch.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -605,13 +605,13 @@ struct ovs_action_push_mpls {
605605
* @vlan_tci: Tag control identifier (TCI) to push. The CFI bit must be set
606606
* (but it will not be set in the 802.1Q header that is pushed).
607607
*
608-
* The @vlan_tpid value is typically %ETH_P_8021Q. The only acceptable TPID
609-
* values are those that the kernel module also parses as 802.1Q headers, to
610-
* prevent %OVS_ACTION_ATTR_PUSH_VLAN followed by %OVS_ACTION_ATTR_POP_VLAN
611-
* from having surprising results.
608+
* The @vlan_tpid value is typically %ETH_P_8021Q or %ETH_P_8021AD.
609+
* The only acceptable TPID values are those that the kernel module also parses
610+
* as 802.1Q or 802.1AD headers, to prevent %OVS_ACTION_ATTR_PUSH_VLAN followed
611+
* by %OVS_ACTION_ATTR_POP_VLAN from having surprising results.
612612
*/
613613
struct ovs_action_push_vlan {
614-
__be16 vlan_tpid; /* 802.1Q TPID. */
614+
__be16 vlan_tpid; /* 802.1Q or 802.1ad TPID. */
615615
__be16 vlan_tci; /* 802.1Q TCI (VLAN ID and priority). */
616616
};
617617

@@ -721,9 +721,10 @@ enum ovs_nat_attr {
721721
* is copied from the value to the packet header field, rest of the bits are
722722
* left unchanged. The non-masked value bits must be passed in as zeroes.
723723
* Masking is not supported for the %OVS_KEY_ATTR_TUNNEL attribute.
724-
* @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q header onto the
725-
* packet.
726-
* @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q header off the packet.
724+
* @OVS_ACTION_ATTR_PUSH_VLAN: Push a new outermost 802.1Q or 802.1ad header
725+
* onto the packet.
726+
* @OVS_ACTION_ATTR_POP_VLAN: Pop the outermost 802.1Q or 802.1ad header
727+
* from the packet.
727728
* @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
728729
* the nested %OVS_SAMPLE_ATTR_* attributes.
729730
* @OVS_ACTION_ATTR_PUSH_MPLS: Push a new MPLS label stack entry onto the

net/openvswitch/actions.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,20 +246,24 @@ static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
246246
int err;
247247

248248
err = skb_vlan_pop(skb);
249-
if (skb_vlan_tag_present(skb))
249+
if (skb_vlan_tag_present(skb)) {
250250
invalidate_flow_key(key);
251-
else
252-
key->eth.tci = 0;
251+
} else {
252+
key->eth.vlan.tci = 0;
253+
key->eth.vlan.tpid = 0;
254+
}
253255
return err;
254256
}
255257

256258
static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
257259
const struct ovs_action_push_vlan *vlan)
258260
{
259-
if (skb_vlan_tag_present(skb))
261+
if (skb_vlan_tag_present(skb)) {
260262
invalidate_flow_key(key);
261-
else
262-
key->eth.tci = vlan->vlan_tci;
263+
} else {
264+
key->eth.vlan.tci = vlan->vlan_tci;
265+
key->eth.vlan.tpid = vlan->vlan_tpid;
266+
}
263267
return skb_vlan_push(skb, vlan->vlan_tpid,
264268
ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
265269
}

net/openvswitch/flow.c

Lines changed: 47 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -302,24 +302,57 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
302302
sizeof(struct icmp6hdr));
303303
}
304304

305-
static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
305+
/**
306+
* Parse vlan tag from vlan header.
307+
* Returns ERROR on memory error.
308+
* Returns 0 if it encounters a non-vlan or incomplete packet.
309+
* Returns 1 after successfully parsing vlan tag.
310+
*/
311+
static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh)
306312
{
307-
struct qtag_prefix {
308-
__be16 eth_type; /* ETH_P_8021Q */
309-
__be16 tci;
310-
};
311-
struct qtag_prefix *qp;
313+
struct vlan_head *vh = (struct vlan_head *)skb->data;
312314

313-
if (unlikely(skb->len < sizeof(struct qtag_prefix) + sizeof(__be16)))
315+
if (likely(!eth_type_vlan(vh->tpid)))
314316
return 0;
315317

316-
if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) +
317-
sizeof(__be16))))
318+
if (unlikely(skb->len < sizeof(struct vlan_head) + sizeof(__be16)))
319+
return 0;
320+
321+
if (unlikely(!pskb_may_pull(skb, sizeof(struct vlan_head) +
322+
sizeof(__be16))))
318323
return -ENOMEM;
319324

320-
qp = (struct qtag_prefix *) skb->data;
321-
key->eth.tci = qp->tci | htons(VLAN_TAG_PRESENT);
322-
__skb_pull(skb, sizeof(struct qtag_prefix));
325+
vh = (struct vlan_head *)skb->data;
326+
key_vh->tci = vh->tci | htons(VLAN_TAG_PRESENT);
327+
key_vh->tpid = vh->tpid;
328+
329+
__skb_pull(skb, sizeof(struct vlan_head));
330+
return 1;
331+
}
332+
333+
static int parse_vlan(struct sk_buff *skb, struct sw_flow_key *key)
334+
{
335+
int res;
336+
337+
key->eth.vlan.tci = 0;
338+
key->eth.vlan.tpid = 0;
339+
key->eth.cvlan.tci = 0;
340+
key->eth.cvlan.tpid = 0;
341+
342+
if (likely(skb_vlan_tag_present(skb))) {
343+
key->eth.vlan.tci = htons(skb->vlan_tci);
344+
key->eth.vlan.tpid = skb->vlan_proto;
345+
} else {
346+
/* Parse outer vlan tag in the non-accelerated case. */
347+
res = parse_vlan_tag(skb, &key->eth.vlan);
348+
if (res <= 0)
349+
return res;
350+
}
351+
352+
/* Parse inner vlan tag. */
353+
res = parse_vlan_tag(skb, &key->eth.cvlan);
354+
if (res <= 0)
355+
return res;
323356

324357
return 0;
325358
}
@@ -480,12 +513,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
480513
* update skb->csum here.
481514
*/
482515

483-
key->eth.tci = 0;
484-
if (skb_vlan_tag_present(skb))
485-
key->eth.tci = htons(skb->vlan_tci);
486-
else if (eth->h_proto == htons(ETH_P_8021Q))
487-
if (unlikely(parse_vlan(skb, key)))
488-
return -ENOMEM;
516+
if (unlikely(parse_vlan(skb, key)))
517+
return -ENOMEM;
489518

490519
key->eth.type = parse_ethertype(skb);
491520
if (unlikely(key->eth.type == htons(0)))

net/openvswitch/flow.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ struct ovs_tunnel_info {
5050
struct metadata_dst *tun_dst;
5151
};
5252

53+
struct vlan_head {
54+
__be16 tpid; /* Vlan type. Generally 802.1q or 802.1ad.*/
55+
__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
56+
};
57+
5358
#define OVS_SW_FLOW_KEY_METADATA_SIZE \
5459
(offsetof(struct sw_flow_key, recirc_id) + \
5560
FIELD_SIZEOF(struct sw_flow_key, recirc_id))
@@ -69,7 +74,8 @@ struct sw_flow_key {
6974
struct {
7075
u8 src[ETH_ALEN]; /* Ethernet source address. */
7176
u8 dst[ETH_ALEN]; /* Ethernet destination address. */
72-
__be16 tci; /* 0 if no VLAN, VLAN_TAG_PRESENT set otherwise. */
77+
struct vlan_head vlan;
78+
struct vlan_head cvlan;
7379
__be16 type; /* Ethernet frame type. */
7480
} eth;
7581
union {

0 commit comments

Comments
 (0)