aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch/flow.c
diff options
context:
space:
mode:
authorEric Garver <e@erig.me>2016-09-07 12:56:59 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-08 20:10:28 -0400
commit018c1dda5ff1e7bd1fe2d9fd1d0f5b82dc6fc0cd (patch)
treeccedb1acda9922d975903894776dcfb853fc3c2d /net/openvswitch/flow.c
parentfe19c4f971a55cea3be442d8032a5f6021702791 (diff)
openvswitch: 802.1AD Flow handling, actions, vlan parsing, netlink attributes
Add support for 802.1ad including the ability to push and pop double tagged vlans. Add support for 802.1ad to netlink parsing and flow conversion. Uses double nested encap attributes to represent double tagged vlan. Inner TPID encoded along with ctci in nested attributes. This is based on Thomas F Herbert's original v20 patch. I made some small clean ups and bug fixes. Signed-off-by: Thomas F Herbert <thomasfherbert@gmail.com> Signed-off-by: Eric Garver <e@erig.me> Acked-by: Pravin B Shelar <pshelar@ovn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/openvswitch/flow.c')
-rw-r--r--net/openvswitch/flow.c65
1 files changed, 47 insertions, 18 deletions
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c
index 0ea128eeeab2..1240ae3b88d2 100644
--- a/net/openvswitch/flow.c
+++ b/net/openvswitch/flow.c
@@ -302,24 +302,57 @@ static bool icmp6hdr_ok(struct sk_buff *skb)
302 sizeof(struct icmp6hdr)); 302 sizeof(struct icmp6hdr));
303} 303}
304 304
305static 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 */
311static int parse_vlan_tag(struct sk_buff *skb, struct vlan_head *key_vh)
306{ 312{
307 struct qtag_prefix { 313 struct vlan_head *vh = (struct vlan_head *)skb->data;
308 __be16 eth_type; /* ETH_P_8021Q */
309 __be16 tci;
310 };
311 struct qtag_prefix *qp;
312 314
313 if (unlikely(skb->len < sizeof(struct qtag_prefix) + sizeof(__be16))) 315 if (likely(!eth_type_vlan(vh->tpid)))
314 return 0; 316 return 0;
315 317
316 if (unlikely(!pskb_may_pull(skb, sizeof(struct qtag_prefix) + 318 if (unlikely(skb->len < sizeof(struct vlan_head) + sizeof(__be16)))
317 sizeof(__be16)))) 319 return 0;
320
321 if (unlikely(!pskb_may_pull(skb, sizeof(struct vlan_head) +
322 sizeof(__be16))))
318 return -ENOMEM; 323 return -ENOMEM;
319 324
320 qp = (struct qtag_prefix *) skb->data; 325 vh = (struct vlan_head *)skb->data;
321 key->eth.tci = qp->tci | htons(VLAN_TAG_PRESENT); 326 key_vh->tci = vh->tci | htons(VLAN_TAG_PRESENT);
322 __skb_pull(skb, sizeof(struct qtag_prefix)); 327 key_vh->tpid = vh->tpid;
328
329 __skb_pull(skb, sizeof(struct vlan_head));
330 return 1;
331}
332
333static 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;
323 356
324 return 0; 357 return 0;
325} 358}
@@ -480,12 +513,8 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key)
480 * update skb->csum here. 513 * update skb->csum here.
481 */ 514 */
482 515
483 key->eth.tci = 0; 516 if (unlikely(parse_vlan(skb, key)))
484 if (skb_vlan_tag_present(skb)) 517 return -ENOMEM;
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;
489 518
490 key->eth.type = parse_ethertype(skb); 519 key->eth.type = parse_ethertype(skb);
491 if (unlikely(key->eth.type == htons(0))) 520 if (unlikely(key->eth.type == htons(0)))