diff options
-rw-r--r-- | net/8021q/vlan.c | 96 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 99 |
2 files changed, 99 insertions, 96 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 1b7a375c6616..aef1a977279c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c | |||
@@ -648,93 +648,6 @@ out: | |||
648 | return err; | 648 | return err; |
649 | } | 649 | } |
650 | 650 | ||
651 | static struct sk_buff *vlan_gro_receive(struct list_head *head, | ||
652 | struct sk_buff *skb) | ||
653 | { | ||
654 | const struct packet_offload *ptype; | ||
655 | unsigned int hlen, off_vlan; | ||
656 | struct sk_buff *pp = NULL; | ||
657 | struct vlan_hdr *vhdr; | ||
658 | struct sk_buff *p; | ||
659 | __be16 type; | ||
660 | int flush = 1; | ||
661 | |||
662 | off_vlan = skb_gro_offset(skb); | ||
663 | hlen = off_vlan + sizeof(*vhdr); | ||
664 | vhdr = skb_gro_header_fast(skb, off_vlan); | ||
665 | if (skb_gro_header_hard(skb, hlen)) { | ||
666 | vhdr = skb_gro_header_slow(skb, hlen, off_vlan); | ||
667 | if (unlikely(!vhdr)) | ||
668 | goto out; | ||
669 | } | ||
670 | |||
671 | type = vhdr->h_vlan_encapsulated_proto; | ||
672 | |||
673 | rcu_read_lock(); | ||
674 | ptype = gro_find_receive_by_type(type); | ||
675 | if (!ptype) | ||
676 | goto out_unlock; | ||
677 | |||
678 | flush = 0; | ||
679 | |||
680 | list_for_each_entry(p, head, list) { | ||
681 | struct vlan_hdr *vhdr2; | ||
682 | |||
683 | if (!NAPI_GRO_CB(p)->same_flow) | ||
684 | continue; | ||
685 | |||
686 | vhdr2 = (struct vlan_hdr *)(p->data + off_vlan); | ||
687 | if (compare_vlan_header(vhdr, vhdr2)) | ||
688 | NAPI_GRO_CB(p)->same_flow = 0; | ||
689 | } | ||
690 | |||
691 | skb_gro_pull(skb, sizeof(*vhdr)); | ||
692 | skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); | ||
693 | pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); | ||
694 | |||
695 | out_unlock: | ||
696 | rcu_read_unlock(); | ||
697 | out: | ||
698 | skb_gro_flush_final(skb, pp, flush); | ||
699 | |||
700 | return pp; | ||
701 | } | ||
702 | |||
703 | static int vlan_gro_complete(struct sk_buff *skb, int nhoff) | ||
704 | { | ||
705 | struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff); | ||
706 | __be16 type = vhdr->h_vlan_encapsulated_proto; | ||
707 | struct packet_offload *ptype; | ||
708 | int err = -ENOENT; | ||
709 | |||
710 | rcu_read_lock(); | ||
711 | ptype = gro_find_complete_by_type(type); | ||
712 | if (ptype) | ||
713 | err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr)); | ||
714 | |||
715 | rcu_read_unlock(); | ||
716 | return err; | ||
717 | } | ||
718 | |||
719 | static struct packet_offload vlan_packet_offloads[] __read_mostly = { | ||
720 | { | ||
721 | .type = cpu_to_be16(ETH_P_8021Q), | ||
722 | .priority = 10, | ||
723 | .callbacks = { | ||
724 | .gro_receive = vlan_gro_receive, | ||
725 | .gro_complete = vlan_gro_complete, | ||
726 | }, | ||
727 | }, | ||
728 | { | ||
729 | .type = cpu_to_be16(ETH_P_8021AD), | ||
730 | .priority = 10, | ||
731 | .callbacks = { | ||
732 | .gro_receive = vlan_gro_receive, | ||
733 | .gro_complete = vlan_gro_complete, | ||
734 | }, | ||
735 | }, | ||
736 | }; | ||
737 | |||
738 | static int __net_init vlan_init_net(struct net *net) | 651 | static int __net_init vlan_init_net(struct net *net) |
739 | { | 652 | { |
740 | struct vlan_net *vn = net_generic(net, vlan_net_id); | 653 | struct vlan_net *vn = net_generic(net, vlan_net_id); |
@@ -762,7 +675,6 @@ static struct pernet_operations vlan_net_ops = { | |||
762 | static int __init vlan_proto_init(void) | 675 | static int __init vlan_proto_init(void) |
763 | { | 676 | { |
764 | int err; | 677 | int err; |
765 | unsigned int i; | ||
766 | 678 | ||
767 | pr_info("%s v%s\n", vlan_fullname, vlan_version); | 679 | pr_info("%s v%s\n", vlan_fullname, vlan_version); |
768 | 680 | ||
@@ -786,9 +698,6 @@ static int __init vlan_proto_init(void) | |||
786 | if (err < 0) | 698 | if (err < 0) |
787 | goto err5; | 699 | goto err5; |
788 | 700 | ||
789 | for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) | ||
790 | dev_add_offload(&vlan_packet_offloads[i]); | ||
791 | |||
792 | vlan_ioctl_set(vlan_ioctl_handler); | 701 | vlan_ioctl_set(vlan_ioctl_handler); |
793 | return 0; | 702 | return 0; |
794 | 703 | ||
@@ -806,13 +715,8 @@ err0: | |||
806 | 715 | ||
807 | static void __exit vlan_cleanup_module(void) | 716 | static void __exit vlan_cleanup_module(void) |
808 | { | 717 | { |
809 | unsigned int i; | ||
810 | |||
811 | vlan_ioctl_set(NULL); | 718 | vlan_ioctl_set(NULL); |
812 | 719 | ||
813 | for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) | ||
814 | dev_remove_offload(&vlan_packet_offloads[i]); | ||
815 | |||
816 | vlan_netlink_fini(); | 720 | vlan_netlink_fini(); |
817 | 721 | ||
818 | unregister_netdevice_notifier(&vlan_notifier_block); | 722 | unregister_netdevice_notifier(&vlan_notifier_block); |
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 57425049faf2..a313165e7a67 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c | |||
@@ -453,3 +453,102 @@ bool vlan_uses_dev(const struct net_device *dev) | |||
453 | return vlan_info->grp.nr_vlan_devs ? true : false; | 453 | return vlan_info->grp.nr_vlan_devs ? true : false; |
454 | } | 454 | } |
455 | EXPORT_SYMBOL(vlan_uses_dev); | 455 | EXPORT_SYMBOL(vlan_uses_dev); |
456 | |||
457 | static struct sk_buff *vlan_gro_receive(struct list_head *head, | ||
458 | struct sk_buff *skb) | ||
459 | { | ||
460 | const struct packet_offload *ptype; | ||
461 | unsigned int hlen, off_vlan; | ||
462 | struct sk_buff *pp = NULL; | ||
463 | struct vlan_hdr *vhdr; | ||
464 | struct sk_buff *p; | ||
465 | __be16 type; | ||
466 | int flush = 1; | ||
467 | |||
468 | off_vlan = skb_gro_offset(skb); | ||
469 | hlen = off_vlan + sizeof(*vhdr); | ||
470 | vhdr = skb_gro_header_fast(skb, off_vlan); | ||
471 | if (skb_gro_header_hard(skb, hlen)) { | ||
472 | vhdr = skb_gro_header_slow(skb, hlen, off_vlan); | ||
473 | if (unlikely(!vhdr)) | ||
474 | goto out; | ||
475 | } | ||
476 | |||
477 | type = vhdr->h_vlan_encapsulated_proto; | ||
478 | |||
479 | rcu_read_lock(); | ||
480 | ptype = gro_find_receive_by_type(type); | ||
481 | if (!ptype) | ||
482 | goto out_unlock; | ||
483 | |||
484 | flush = 0; | ||
485 | |||
486 | list_for_each_entry(p, head, list) { | ||
487 | struct vlan_hdr *vhdr2; | ||
488 | |||
489 | if (!NAPI_GRO_CB(p)->same_flow) | ||
490 | continue; | ||
491 | |||
492 | vhdr2 = (struct vlan_hdr *)(p->data + off_vlan); | ||
493 | if (compare_vlan_header(vhdr, vhdr2)) | ||
494 | NAPI_GRO_CB(p)->same_flow = 0; | ||
495 | } | ||
496 | |||
497 | skb_gro_pull(skb, sizeof(*vhdr)); | ||
498 | skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr)); | ||
499 | pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); | ||
500 | |||
501 | out_unlock: | ||
502 | rcu_read_unlock(); | ||
503 | out: | ||
504 | skb_gro_flush_final(skb, pp, flush); | ||
505 | |||
506 | return pp; | ||
507 | } | ||
508 | |||
509 | static int vlan_gro_complete(struct sk_buff *skb, int nhoff) | ||
510 | { | ||
511 | struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff); | ||
512 | __be16 type = vhdr->h_vlan_encapsulated_proto; | ||
513 | struct packet_offload *ptype; | ||
514 | int err = -ENOENT; | ||
515 | |||
516 | rcu_read_lock(); | ||
517 | ptype = gro_find_complete_by_type(type); | ||
518 | if (ptype) | ||
519 | err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr)); | ||
520 | |||
521 | rcu_read_unlock(); | ||
522 | return err; | ||
523 | } | ||
524 | |||
525 | static struct packet_offload vlan_packet_offloads[] __read_mostly = { | ||
526 | { | ||
527 | .type = cpu_to_be16(ETH_P_8021Q), | ||
528 | .priority = 10, | ||
529 | .callbacks = { | ||
530 | .gro_receive = vlan_gro_receive, | ||
531 | .gro_complete = vlan_gro_complete, | ||
532 | }, | ||
533 | }, | ||
534 | { | ||
535 | .type = cpu_to_be16(ETH_P_8021AD), | ||
536 | .priority = 10, | ||
537 | .callbacks = { | ||
538 | .gro_receive = vlan_gro_receive, | ||
539 | .gro_complete = vlan_gro_complete, | ||
540 | }, | ||
541 | }, | ||
542 | }; | ||
543 | |||
544 | static int __init vlan_offload_init(void) | ||
545 | { | ||
546 | unsigned int i; | ||
547 | |||
548 | for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++) | ||
549 | dev_add_offload(&vlan_packet_offloads[i]); | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | fs_initcall(vlan_offload_init); | ||