aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorToshiaki Makita <makita.toshiaki@lab.ntt.co.jp>2015-06-01 08:55:06 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-01 19:50:52 -0400
commit66e5133f19e901a044fa5eaeeb6ecff4545839e5 (patch)
tree02419230bb0e8cf4545acdd7fbee4369d1b76095
parent661b689bbd2e9392c3d9935e791af75ddbc455dc (diff)
vlan: Add GRO support for non hardware accelerated vlan
Currently packets with non-hardware-accelerated vlan cannot be handled by GRO. This causes low performance for 802.1ad and stacked vlan, as their vlan tags are currently not stripped by hardware. This patch adds GRO support for non-hardware-accelerated vlan and improves receive performance of them. Test Environment: vlan device (.1Q) on vlan device (.1ad) on ixgbe (82599) Result: - Before $ netperf -t TCP_STREAM -H 192.168.20.2 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.00 5233.17 Rx side CPU usage: %usr %sys %irq %soft %idle 0.27 58.03 0.00 41.70 0.00 - After $ netperf -t TCP_STREAM -H 192.168.20.2 -l 60 Recv Send Send Socket Socket Message Elapsed Size Size Size Time Throughput bytes bytes bytes secs. 10^6bits/sec 87380 16384 16384 60.00 7586.85 Rx side CPU usage: %usr %sys %irq %soft %idle 0.50 25.83 0.00 59.53 14.14 [ Register VLAN offloads with priority 10 -DaveM ] 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.h20
-rw-r--r--net/8021q/vlan.c96
2 files changed, 116 insertions, 0 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index a40d29846ac2..67ce5bd3b56a 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -628,4 +628,24 @@ static inline netdev_features_t vlan_features_check(const struct sk_buff *skb,
628 return features; 628 return features;
629} 629}
630 630
631/**
632 * compare_vlan_header - Compare two vlan headers
633 * @h1: Pointer to vlan header
634 * @h2: Pointer to vlan header
635 *
636 * Compare two vlan headers, returns 0 if equal.
637 *
638 * Please note that alignment of h1 & h2 are only guaranteed to be 16 bits.
639 */
640static inline unsigned long compare_vlan_header(const struct vlan_hdr *h1,
641 const struct vlan_hdr *h2)
642{
643#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
644 return *(u32 *)h1 ^ *(u32 *)h2;
645#else
646 return ((__force u32)h1->h_vlan_TCI ^ (__force u32)h2->h_vlan_TCI) |
647 ((__force u32)h1->h_vlan_encapsulated_proto ^
648 (__force u32)h2->h_vlan_encapsulated_proto);
649#endif
650}
631#endif /* !(_LINUX_IF_VLAN_H_) */ 651#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 59555f0f8fc8..d2cd9de4b724 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -618,6 +618,92 @@ out:
618 return err; 618 return err;
619} 619}
620 620
621static struct sk_buff **vlan_gro_receive(struct sk_buff **head,
622 struct sk_buff *skb)
623{
624 struct sk_buff *p, **pp = NULL;
625 struct vlan_hdr *vhdr;
626 unsigned int hlen, off_vlan;
627 const struct packet_offload *ptype;
628 __be16 type;
629 int flush = 1;
630
631 off_vlan = skb_gro_offset(skb);
632 hlen = off_vlan + sizeof(*vhdr);
633 vhdr = skb_gro_header_fast(skb, off_vlan);
634 if (skb_gro_header_hard(skb, hlen)) {
635 vhdr = skb_gro_header_slow(skb, hlen, off_vlan);
636 if (unlikely(!vhdr))
637 goto out;
638 }
639
640 type = vhdr->h_vlan_encapsulated_proto;
641
642 rcu_read_lock();
643 ptype = gro_find_receive_by_type(type);
644 if (!ptype)
645 goto out_unlock;
646
647 flush = 0;
648
649 for (p = *head; p; p = p->next) {
650 struct vlan_hdr *vhdr2;
651
652 if (!NAPI_GRO_CB(p)->same_flow)
653 continue;
654
655 vhdr2 = (struct vlan_hdr *)(p->data + off_vlan);
656 if (compare_vlan_header(vhdr, vhdr2))
657 NAPI_GRO_CB(p)->same_flow = 0;
658 }
659
660 skb_gro_pull(skb, sizeof(*vhdr));
661 skb_gro_postpull_rcsum(skb, vhdr, sizeof(*vhdr));
662 pp = ptype->callbacks.gro_receive(head, skb);
663
664out_unlock:
665 rcu_read_unlock();
666out:
667 NAPI_GRO_CB(skb)->flush |= flush;
668
669 return pp;
670}
671
672static int vlan_gro_complete(struct sk_buff *skb, int nhoff)
673{
674 struct vlan_hdr *vhdr = (struct vlan_hdr *)(skb->data + nhoff);
675 __be16 type = vhdr->h_vlan_encapsulated_proto;
676 struct packet_offload *ptype;
677 int err = -ENOENT;
678
679 rcu_read_lock();
680 ptype = gro_find_complete_by_type(type);
681 if (ptype)
682 err = ptype->callbacks.gro_complete(skb, nhoff + sizeof(*vhdr));
683
684 rcu_read_unlock();
685 return err;
686}
687
688static struct packet_offload vlan_packet_offloads[] __read_mostly = {
689 {
690 .type = cpu_to_be16(ETH_P_8021Q),
691 .priority = 10,
692 .callbacks = {
693 .gro_receive = vlan_gro_receive,
694 .gro_complete = vlan_gro_complete,
695 },
696 },
697 {
698 .type = cpu_to_be16(ETH_P_8021AD),
699 .priority = 10,
700 .callbacks = {
701 .gro_receive = vlan_gro_receive,
702 .gro_complete = vlan_gro_complete,
703 },
704 },
705};
706
621static int __net_init vlan_init_net(struct net *net) 707static int __net_init vlan_init_net(struct net *net)
622{ 708{
623 struct vlan_net *vn = net_generic(net, vlan_net_id); 709 struct vlan_net *vn = net_generic(net, vlan_net_id);
@@ -645,6 +731,7 @@ static struct pernet_operations vlan_net_ops = {
645static int __init vlan_proto_init(void) 731static int __init vlan_proto_init(void)
646{ 732{
647 int err; 733 int err;
734 unsigned int i;
648 735
649 pr_info("%s v%s\n", vlan_fullname, vlan_version); 736 pr_info("%s v%s\n", vlan_fullname, vlan_version);
650 737
@@ -668,6 +755,9 @@ static int __init vlan_proto_init(void)
668 if (err < 0) 755 if (err < 0)
669 goto err5; 756 goto err5;
670 757
758 for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++)
759 dev_add_offload(&vlan_packet_offloads[i]);
760
671 vlan_ioctl_set(vlan_ioctl_handler); 761 vlan_ioctl_set(vlan_ioctl_handler);
672 return 0; 762 return 0;
673 763
@@ -685,7 +775,13 @@ err0:
685 775
686static void __exit vlan_cleanup_module(void) 776static void __exit vlan_cleanup_module(void)
687{ 777{
778 unsigned int i;
779
688 vlan_ioctl_set(NULL); 780 vlan_ioctl_set(NULL);
781
782 for (i = 0; i < ARRAY_SIZE(vlan_packet_offloads); i++)
783 dev_remove_offload(&vlan_packet_offloads[i]);
784
689 vlan_netlink_fini(); 785 vlan_netlink_fini();
690 786
691 unregister_netdevice_notifier(&vlan_notifier_block); 787 unregister_netdevice_notifier(&vlan_notifier_block);