aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/protocol.h8
-rw-r--r--net/ipv6/af_inet6.c22
-rw-r--r--net/ipv6/exthdrs.c38
-rw-r--r--net/ipv6/tcp_ipv6.c17
-rw-r--r--net/ipv6/udp.c11
5 files changed, 64 insertions, 32 deletions
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 3bb70510b686..7019c1637848 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -54,14 +54,6 @@ struct inet6_protocol {
54 struct inet6_skb_parm *opt, 54 struct inet6_skb_parm *opt,
55 u8 type, u8 code, int offset, 55 u8 type, u8 code, int offset,
56 __be32 info); 56 __be32 info);
57
58 int (*gso_send_check)(struct sk_buff *skb);
59 struct sk_buff *(*gso_segment)(struct sk_buff *skb,
60 netdev_features_t features);
61 struct sk_buff **(*gro_receive)(struct sk_buff **head,
62 struct sk_buff *skb);
63 int (*gro_complete)(struct sk_buff *skb);
64
65 unsigned int flags; /* INET6_PROTO_xxx */ 57 unsigned int flags; /* INET6_PROTO_xxx */
66}; 58};
67 59
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 6e245177608c..eb63dac68728 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -701,14 +701,14 @@ EXPORT_SYMBOL_GPL(ipv6_opt_accepted);
701 701
702static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) 702static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
703{ 703{
704 const struct inet6_protocol *ops = NULL; 704 const struct net_offload *ops = NULL;
705 705
706 for (;;) { 706 for (;;) {
707 struct ipv6_opt_hdr *opth; 707 struct ipv6_opt_hdr *opth;
708 int len; 708 int len;
709 709
710 if (proto != NEXTHDR_HOP) { 710 if (proto != NEXTHDR_HOP) {
711 ops = rcu_dereference(inet6_protos[proto]); 711 ops = rcu_dereference(inet6_offloads[proto]);
712 712
713 if (unlikely(!ops)) 713 if (unlikely(!ops))
714 break; 714 break;
@@ -736,7 +736,7 @@ static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto)
736static int ipv6_gso_send_check(struct sk_buff *skb) 736static int ipv6_gso_send_check(struct sk_buff *skb)
737{ 737{
738 const struct ipv6hdr *ipv6h; 738 const struct ipv6hdr *ipv6h;
739 const struct inet6_protocol *ops; 739 const struct net_offload *ops;
740 int err = -EINVAL; 740 int err = -EINVAL;
741 741
742 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) 742 if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h))))
@@ -747,7 +747,7 @@ static int ipv6_gso_send_check(struct sk_buff *skb)
747 err = -EPROTONOSUPPORT; 747 err = -EPROTONOSUPPORT;
748 748
749 rcu_read_lock(); 749 rcu_read_lock();
750 ops = rcu_dereference(inet6_protos[ 750 ops = rcu_dereference(inet6_offloads[
751 ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]); 751 ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr)]);
752 752
753 if (likely(ops && ops->gso_send_check)) { 753 if (likely(ops && ops->gso_send_check)) {
@@ -765,7 +765,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
765{ 765{
766 struct sk_buff *segs = ERR_PTR(-EINVAL); 766 struct sk_buff *segs = ERR_PTR(-EINVAL);
767 struct ipv6hdr *ipv6h; 767 struct ipv6hdr *ipv6h;
768 const struct inet6_protocol *ops; 768 const struct net_offload *ops;
769 int proto; 769 int proto;
770 struct frag_hdr *fptr; 770 struct frag_hdr *fptr;
771 unsigned int unfrag_ip6hlen; 771 unsigned int unfrag_ip6hlen;
@@ -792,7 +792,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
792 792
793 proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); 793 proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr);
794 rcu_read_lock(); 794 rcu_read_lock();
795 ops = rcu_dereference(inet6_protos[proto]); 795 ops = rcu_dereference(inet6_offloads[proto]);
796 if (likely(ops && ops->gso_segment)) { 796 if (likely(ops && ops->gso_segment)) {
797 skb_reset_transport_header(skb); 797 skb_reset_transport_header(skb);
798 segs = ops->gso_segment(skb, features); 798 segs = ops->gso_segment(skb, features);
@@ -825,7 +825,7 @@ out:
825static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, 825static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
826 struct sk_buff *skb) 826 struct sk_buff *skb)
827{ 827{
828 const struct inet6_protocol *ops; 828 const struct net_offload *ops;
829 struct sk_buff **pp = NULL; 829 struct sk_buff **pp = NULL;
830 struct sk_buff *p; 830 struct sk_buff *p;
831 struct ipv6hdr *iph; 831 struct ipv6hdr *iph;
@@ -852,7 +852,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
852 852
853 rcu_read_lock(); 853 rcu_read_lock();
854 proto = iph->nexthdr; 854 proto = iph->nexthdr;
855 ops = rcu_dereference(inet6_protos[proto]); 855 ops = rcu_dereference(inet6_offloads[proto]);
856 if (!ops || !ops->gro_receive) { 856 if (!ops || !ops->gro_receive) {
857 __pskb_pull(skb, skb_gro_offset(skb)); 857 __pskb_pull(skb, skb_gro_offset(skb));
858 proto = ipv6_gso_pull_exthdrs(skb, proto); 858 proto = ipv6_gso_pull_exthdrs(skb, proto);
@@ -860,7 +860,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
860 skb_reset_transport_header(skb); 860 skb_reset_transport_header(skb);
861 __skb_push(skb, skb_gro_offset(skb)); 861 __skb_push(skb, skb_gro_offset(skb));
862 862
863 ops = rcu_dereference(inet6_protos[proto]); 863 ops = rcu_dereference(inet6_offloads[proto]);
864 if (!ops || !ops->gro_receive) 864 if (!ops || !ops->gro_receive)
865 goto out_unlock; 865 goto out_unlock;
866 866
@@ -915,7 +915,7 @@ out:
915 915
916static int ipv6_gro_complete(struct sk_buff *skb) 916static int ipv6_gro_complete(struct sk_buff *skb)
917{ 917{
918 const struct inet6_protocol *ops; 918 const struct net_offload *ops;
919 struct ipv6hdr *iph = ipv6_hdr(skb); 919 struct ipv6hdr *iph = ipv6_hdr(skb);
920 int err = -ENOSYS; 920 int err = -ENOSYS;
921 921
@@ -923,7 +923,7 @@ static int ipv6_gro_complete(struct sk_buff *skb)
923 sizeof(*iph)); 923 sizeof(*iph));
924 924
925 rcu_read_lock(); 925 rcu_read_lock();
926 ops = rcu_dereference(inet6_protos[NAPI_GRO_CB(skb)->proto]); 926 ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]);
927 if (WARN_ON(!ops || !ops->gro_complete)) 927 if (WARN_ON(!ops || !ops->gro_complete))
928 goto out_unlock; 928 goto out_unlock;
929 929
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index cb6f0828ca44..de6559e3aa0a 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -549,14 +549,44 @@ static const struct inet6_protocol nodata_protocol = {
549 .flags = INET6_PROTO_NOPOLICY, 549 .flags = INET6_PROTO_NOPOLICY,
550}; 550};
551 551
552static int ipv6_exthdrs_offload_init(void)
553{
554 int ret;
555
556 ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING);
557 if (!ret)
558 goto out;
559
560 ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS);
561 if (!ret)
562 goto out_rt;
563
564out:
565 return ret;
566
567out_rt:
568 inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
569 goto out;
570}
571
572static void ipv6_exthdrs_offload_exit(void)
573{
574 inet_del_offload(&rthdr_offload, IPPROTO_ROUTING);
575 inet_del_offload(&rthdr_offload, IPPROTO_DSTOPTS);
576}
577
552int __init ipv6_exthdrs_init(void) 578int __init ipv6_exthdrs_init(void)
553{ 579{
554 int ret; 580 int ret;
555 581
556 ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING); 582 ret = ipv6_exthdrs_offload_init();
557 if (ret) 583 if (ret)
558 goto out; 584 goto out;
559 585
586 ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING);
587 if (ret)
588 goto out_offload;
589
560 ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS); 590 ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
561 if (ret) 591 if (ret)
562 goto out_rthdr; 592 goto out_rthdr;
@@ -567,10 +597,12 @@ int __init ipv6_exthdrs_init(void)
567 597
568out: 598out:
569 return ret; 599 return ret;
570out_rthdr:
571 inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
572out_destopt: 600out_destopt:
573 inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); 601 inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS);
602out_rthdr:
603 inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING);
604out_offload:
605 ipv6_exthdrs_offload_exit();
574 goto out; 606 goto out;
575}; 607};
576 608
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 6884a95be433..635206e8987e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2066,10 +2066,6 @@ static const struct inet6_protocol tcpv6_protocol = {
2066 .early_demux = tcp_v6_early_demux, 2066 .early_demux = tcp_v6_early_demux,
2067 .handler = tcp_v6_rcv, 2067 .handler = tcp_v6_rcv,
2068 .err_handler = tcp_v6_err, 2068 .err_handler = tcp_v6_err,
2069 .gso_send_check = tcp_v6_gso_send_check,
2070 .gso_segment = tcp_tso_segment,
2071 .gro_receive = tcp6_gro_receive,
2072 .gro_complete = tcp6_gro_complete,
2073 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 2069 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
2074}; 2070};
2075 2071
@@ -2116,10 +2112,14 @@ int __init tcpv6_init(void)
2116{ 2112{
2117 int ret; 2113 int ret;
2118 2114
2119 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP); 2115 ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
2120 if (ret) 2116 if (ret)
2121 goto out; 2117 goto out;
2122 2118
2119 ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP);
2120 if (ret)
2121 goto out_offload;
2122
2123 /* register inet6 protocol */ 2123 /* register inet6 protocol */
2124 ret = inet6_register_protosw(&tcpv6_protosw); 2124 ret = inet6_register_protosw(&tcpv6_protosw);
2125 if (ret) 2125 if (ret)
@@ -2131,10 +2131,12 @@ int __init tcpv6_init(void)
2131out: 2131out:
2132 return ret; 2132 return ret;
2133 2133
2134out_tcpv6_protocol:
2135 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2136out_tcpv6_protosw: 2134out_tcpv6_protosw:
2137 inet6_unregister_protosw(&tcpv6_protosw); 2135 inet6_unregister_protosw(&tcpv6_protosw);
2136out_tcpv6_protocol:
2137 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2138out_offload:
2139 inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
2138 goto out; 2140 goto out;
2139} 2141}
2140 2142
@@ -2143,4 +2145,5 @@ void tcpv6_exit(void)
2143 unregister_pernet_subsys(&tcpv6_net_ops); 2145 unregister_pernet_subsys(&tcpv6_net_ops);
2144 inet6_unregister_protosw(&tcpv6_protosw); 2146 inet6_unregister_protosw(&tcpv6_protosw);
2145 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); 2147 inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
2148 inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
2146} 2149}
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3ad44e176503..e4cc1f41012d 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1438,8 +1438,6 @@ out:
1438static const struct inet6_protocol udpv6_protocol = { 1438static const struct inet6_protocol udpv6_protocol = {
1439 .handler = udpv6_rcv, 1439 .handler = udpv6_rcv,
1440 .err_handler = udpv6_err, 1440 .err_handler = udpv6_err,
1441 .gso_send_check = udp6_ufo_send_check,
1442 .gso_segment = udp6_ufo_fragment,
1443 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, 1441 .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
1444}; 1442};
1445 1443
@@ -1570,10 +1568,14 @@ int __init udpv6_init(void)
1570{ 1568{
1571 int ret; 1569 int ret;
1572 1570
1573 ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); 1571 ret = inet6_add_offload(&udpv6_offload, IPPROTO_UDP);
1574 if (ret) 1572 if (ret)
1575 goto out; 1573 goto out;
1576 1574
1575 ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP);
1576 if (ret)
1577 goto out_offload;
1578
1577 ret = inet6_register_protosw(&udpv6_protosw); 1579 ret = inet6_register_protosw(&udpv6_protosw);
1578 if (ret) 1580 if (ret)
1579 goto out_udpv6_protocol; 1581 goto out_udpv6_protocol;
@@ -1582,6 +1584,8 @@ out:
1582 1584
1583out_udpv6_protocol: 1585out_udpv6_protocol:
1584 inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); 1586 inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
1587out_offload:
1588 inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
1585 goto out; 1589 goto out;
1586} 1590}
1587 1591
@@ -1589,4 +1593,5 @@ void udpv6_exit(void)
1589{ 1593{
1590 inet6_unregister_protosw(&udpv6_protosw); 1594 inet6_unregister_protosw(&udpv6_protosw);
1591 inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); 1595 inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP);
1596 inet6_del_offload(&udpv6_offload, IPPROTO_UDP);
1592} 1597}