aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>2018-03-13 01:51:28 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-16 10:03:47 -0400
commitcbe7128c4b92e2004984f477fd38dfa81662f02e (patch)
tree7805f8eec1279109bf15a6177f286a0aacbf017c
parent4bbb3e0e8239f9079bf1fe20b3c0cb598714ae61 (diff)
vlan: Fix out of order vlan headers with reorder header off
With reorder header off, received packets are untagged in skb_vlan_untag() called from within __netif_receive_skb_core(), and later the tag will be inserted back in vlan_do_receive(). This caused out of order vlan headers when we create a vlan device on top of another vlan device, because vlan_do_receive() inserts a tag as the outermost vlan tag. E.g. the outer tag is first removed in skb_vlan_untag() and inserted back in vlan_do_receive(), then the inner tag is next removed and inserted back as the outermost tag. This patch fixes the behaviour by inserting the inner tag at the right position. Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/if_vlan.h66
-rw-r--r--net/8021q/vlan_core.c4
2 files changed, 57 insertions, 13 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 5e6a2d4dc366..c4a1cff9c768 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -300,30 +300,34 @@ static inline bool vlan_hw_offload_capable(netdev_features_t features,
300} 300}
301 301
302/** 302/**
303 * __vlan_insert_tag - regular VLAN tag inserting 303 * __vlan_insert_inner_tag - inner VLAN tag inserting
304 * @skb: skbuff to tag 304 * @skb: skbuff to tag
305 * @vlan_proto: VLAN encapsulation protocol 305 * @vlan_proto: VLAN encapsulation protocol
306 * @vlan_tci: VLAN TCI to insert 306 * @vlan_tci: VLAN TCI to insert
307 * @mac_len: MAC header length including outer vlan headers
307 * 308 *
308 * Inserts the VLAN tag into @skb as part of the payload 309 * Inserts the VLAN tag into @skb as part of the payload at offset mac_len
309 * Returns error if skb_cow_head failes. 310 * Returns error if skb_cow_head failes.
310 * 311 *
311 * Does not change skb->protocol so this function can be used during receive. 312 * Does not change skb->protocol so this function can be used during receive.
312 */ 313 */
313static inline int __vlan_insert_tag(struct sk_buff *skb, 314static inline int __vlan_insert_inner_tag(struct sk_buff *skb,
314 __be16 vlan_proto, u16 vlan_tci) 315 __be16 vlan_proto, u16 vlan_tci,
316 unsigned int mac_len)
315{ 317{
316 struct vlan_ethhdr *veth; 318 struct vlan_ethhdr *veth;
317 319
318 if (skb_cow_head(skb, VLAN_HLEN) < 0) 320 if (skb_cow_head(skb, VLAN_HLEN) < 0)
319 return -ENOMEM; 321 return -ENOMEM;
320 322
321 veth = skb_push(skb, VLAN_HLEN); 323 skb_push(skb, VLAN_HLEN);
322 324
323 /* Move the mac addresses to the beginning of the new header. */ 325 /* Move the mac header sans proto to the beginning of the new header. */
324 memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); 326 memmove(skb->data, skb->data + VLAN_HLEN, mac_len - ETH_TLEN);
325 skb->mac_header -= VLAN_HLEN; 327 skb->mac_header -= VLAN_HLEN;
326 328
329 veth = (struct vlan_ethhdr *)(skb->data + mac_len - ETH_HLEN);
330
327 /* first, the ethernet type */ 331 /* first, the ethernet type */
328 veth->h_vlan_proto = vlan_proto; 332 veth->h_vlan_proto = vlan_proto;
329 333
@@ -334,12 +338,30 @@ static inline int __vlan_insert_tag(struct sk_buff *skb,
334} 338}
335 339
336/** 340/**
337 * vlan_insert_tag - regular VLAN tag inserting 341 * __vlan_insert_tag - regular VLAN tag inserting
338 * @skb: skbuff to tag 342 * @skb: skbuff to tag
339 * @vlan_proto: VLAN encapsulation protocol 343 * @vlan_proto: VLAN encapsulation protocol
340 * @vlan_tci: VLAN TCI to insert 344 * @vlan_tci: VLAN TCI to insert
341 * 345 *
342 * Inserts the VLAN tag into @skb as part of the payload 346 * Inserts the VLAN tag into @skb as part of the payload
347 * Returns error if skb_cow_head failes.
348 *
349 * Does not change skb->protocol so this function can be used during receive.
350 */
351static inline int __vlan_insert_tag(struct sk_buff *skb,
352 __be16 vlan_proto, u16 vlan_tci)
353{
354 return __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN);
355}
356
357/**
358 * vlan_insert_inner_tag - inner VLAN tag inserting
359 * @skb: skbuff to tag
360 * @vlan_proto: VLAN encapsulation protocol
361 * @vlan_tci: VLAN TCI to insert
362 * @mac_len: MAC header length including outer vlan headers
363 *
364 * Inserts the VLAN tag into @skb as part of the payload at offset mac_len
343 * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. 365 * Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
344 * 366 *
345 * Following the skb_unshare() example, in case of error, the calling function 367 * Following the skb_unshare() example, in case of error, the calling function
@@ -347,12 +369,14 @@ static inline int __vlan_insert_tag(struct sk_buff *skb,
347 * 369 *
348 * Does not change skb->protocol so this function can be used during receive. 370 * Does not change skb->protocol so this function can be used during receive.
349 */ 371 */
350static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, 372static inline struct sk_buff *vlan_insert_inner_tag(struct sk_buff *skb,
351 __be16 vlan_proto, u16 vlan_tci) 373 __be16 vlan_proto,
374 u16 vlan_tci,
375 unsigned int mac_len)
352{ 376{
353 int err; 377 int err;
354 378
355 err = __vlan_insert_tag(skb, vlan_proto, vlan_tci); 379 err = __vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, mac_len);
356 if (err) { 380 if (err) {
357 dev_kfree_skb_any(skb); 381 dev_kfree_skb_any(skb);
358 return NULL; 382 return NULL;
@@ -361,6 +385,26 @@ static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
361} 385}
362 386
363/** 387/**
388 * vlan_insert_tag - regular VLAN tag inserting
389 * @skb: skbuff to tag
390 * @vlan_proto: VLAN encapsulation protocol
391 * @vlan_tci: VLAN TCI to insert
392 *
393 * Inserts the VLAN tag into @skb as part of the payload
394 * Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
395 *
396 * Following the skb_unshare() example, in case of error, the calling function
397 * doesn't have to worry about freeing the original skb.
398 *
399 * Does not change skb->protocol so this function can be used during receive.
400 */
401static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb,
402 __be16 vlan_proto, u16 vlan_tci)
403{
404 return vlan_insert_inner_tag(skb, vlan_proto, vlan_tci, ETH_HLEN);
405}
406
407/**
364 * vlan_insert_tag_set_proto - regular VLAN tag inserting 408 * vlan_insert_tag_set_proto - regular VLAN tag inserting
365 * @skb: skbuff to tag 409 * @skb: skbuff to tag
366 * @vlan_proto: VLAN encapsulation protocol 410 * @vlan_proto: VLAN encapsulation protocol
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 64aa9f755e1d..45c9bf5ff3a0 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -48,8 +48,8 @@ bool vlan_do_receive(struct sk_buff **skbp)
48 * original position later 48 * original position later
49 */ 49 */
50 skb_push(skb, offset); 50 skb_push(skb, offset);
51 skb = *skbp = vlan_insert_tag(skb, skb->vlan_proto, 51 skb = *skbp = vlan_insert_inner_tag(skb, skb->vlan_proto,
52 skb->vlan_tci); 52 skb->vlan_tci, skb->mac_len);
53 if (!skb) 53 if (!skb)
54 return false; 54 return false;
55 skb_pull(skb, offset + VLAN_HLEN); 55 skb_pull(skb, offset + VLAN_HLEN);