aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/openvswitch/actions.c16
-rw-r--r--net/openvswitch/flow.c65
-rw-r--r--net/openvswitch/flow.h8
-rw-r--r--net/openvswitch/flow_netlink.c310
-rw-r--r--net/openvswitch/vport.c7
5 files changed, 282 insertions, 124 deletions
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index ca91fc33f8a9..4fe9032b1160 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -246,20 +246,24 @@ static int pop_vlan(struct sk_buff *skb, struct sw_flow_key *key)
246 int err; 246 int err;
247 247
248 err = skb_vlan_pop(skb); 248 err = skb_vlan_pop(skb);
249 if (skb_vlan_tag_present(skb)) 249 if (skb_vlan_tag_present(skb)) {
250 invalidate_flow_key(key); 250 invalidate_flow_key(key);
251 else 251 } else {
252 key->eth.tci = 0; 252 key->eth.vlan.tci = 0;
253 key->eth.vlan.tpid = 0;
254 }
253 return err; 255 return err;
254} 256}
255 257
256static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key, 258static int push_vlan(struct sk_buff *skb, struct sw_flow_key *key,
257 const struct ovs_action_push_vlan *vlan) 259 const struct ovs_action_push_vlan *vlan)
258{ 260{
259 if (skb_vlan_tag_present(skb)) 261 if (skb_vlan_tag_present(skb)) {
260 invalidate_flow_key(key); 262 invalidate_flow_key(key);
261 else 263 } else {
262 key->eth.tci = vlan->vlan_tci; 264 key->eth.vlan.tci = vlan->vlan_tci;
265 key->eth.vlan.tpid = vlan->vlan_tpid;
266 }
263 return skb_vlan_push(skb, vlan->vlan_tpid, 267 return skb_vlan_push(skb, vlan->vlan_tpid,
264 ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT); 268 ntohs(vlan->vlan_tci) & ~VLAN_TAG_PRESENT);
265} 269}
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)))
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h
index 03378e75a67c..156a3029c17b 100644
--- a/net/openvswitch/flow.h
+++ b/net/openvswitch/flow.h
@@ -50,6 +50,11 @@ struct ovs_tunnel_info {
50 struct metadata_dst *tun_dst; 50 struct metadata_dst *tun_dst;
51}; 51};
52 52
53struct 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
53#define OVS_SW_FLOW_KEY_METADATA_SIZE \ 58#define OVS_SW_FLOW_KEY_METADATA_SIZE \
54 (offsetof(struct sw_flow_key, recirc_id) + \ 59 (offsetof(struct sw_flow_key, recirc_id) + \
55 FIELD_SIZEOF(struct sw_flow_key, recirc_id)) 60 FIELD_SIZEOF(struct sw_flow_key, recirc_id))
@@ -69,7 +74,8 @@ struct sw_flow_key {
69 struct { 74 struct {
70 u8 src[ETH_ALEN]; /* Ethernet source address. */ 75 u8 src[ETH_ALEN]; /* Ethernet source address. */
71 u8 dst[ETH_ALEN]; /* Ethernet destination address. */ 76 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;
73 __be16 type; /* Ethernet frame type. */ 79 __be16 type; /* Ethernet frame type. */
74 } eth; 80 } eth;
75 union { 81 union {
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index c78a6a1476fb..8efa718ddb5e 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -808,6 +808,167 @@ int ovs_nla_put_tunnel_info(struct sk_buff *skb,
808 ip_tunnel_info_af(tun_info)); 808 ip_tunnel_info_af(tun_info));
809} 809}
810 810
811static int encode_vlan_from_nlattrs(struct sw_flow_match *match,
812 const struct nlattr *a[],
813 bool is_mask, bool inner)
814{
815 __be16 tci = 0;
816 __be16 tpid = 0;
817
818 if (a[OVS_KEY_ATTR_VLAN])
819 tci = nla_get_be16(a[OVS_KEY_ATTR_VLAN]);
820
821 if (a[OVS_KEY_ATTR_ETHERTYPE])
822 tpid = nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE]);
823
824 if (likely(!inner)) {
825 SW_FLOW_KEY_PUT(match, eth.vlan.tpid, tpid, is_mask);
826 SW_FLOW_KEY_PUT(match, eth.vlan.tci, tci, is_mask);
827 } else {
828 SW_FLOW_KEY_PUT(match, eth.cvlan.tpid, tpid, is_mask);
829 SW_FLOW_KEY_PUT(match, eth.cvlan.tci, tci, is_mask);
830 }
831 return 0;
832}
833
834static int validate_vlan_from_nlattrs(const struct sw_flow_match *match,
835 u64 key_attrs, bool inner,
836 const struct nlattr **a, bool log)
837{
838 __be16 tci = 0;
839
840 if (!((key_attrs & (1 << OVS_KEY_ATTR_ETHERNET)) &&
841 (key_attrs & (1 << OVS_KEY_ATTR_ETHERTYPE)) &&
842 eth_type_vlan(nla_get_be16(a[OVS_KEY_ATTR_ETHERTYPE])))) {
843 /* Not a VLAN. */
844 return 0;
845 }
846
847 if (!((key_attrs & (1 << OVS_KEY_ATTR_VLAN)) &&
848 (key_attrs & (1 << OVS_KEY_ATTR_ENCAP)))) {
849 OVS_NLERR(log, "Invalid %s frame", (inner) ? "C-VLAN" : "VLAN");
850 return -EINVAL;
851 }
852
853 if (a[OVS_KEY_ATTR_VLAN])