ipv6: Separate tcp offload functionality
authorVlad Yasevich <vyasevic@redhat.com>
Thu, 15 Nov 2012 08:49:17 +0000 (08:49 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Nov 2012 22:36:18 +0000 (17:36 -0500)
Pull TCPv6 offload functionality into its won file in preparation
for moving it out of the module.

Signed-off-by: Vlad Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/ip6_checksum.h
net/ipv6/Makefile
net/ipv6/ip6_offload.h
net/ipv6/tcp_ipv6.c
net/ipv6/tcpv6_offload.c [new file with mode: 0644]

index bc1b0fda2b0452d7cadd32a30f6df0e2a697d99e..652d3d309357c8d587c313817c61261479c78e0e 100644 (file)
@@ -31,6 +31,8 @@
 #include <net/ip.h>
 #include <asm/checksum.h>
 #include <linux/in6.h>
+#include <linux/tcp.h>
+#include <linux/ipv6.h>
 
 #ifndef _HAVE_ARCH_IPV6_CSUM
 
@@ -91,4 +93,37 @@ static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
 }
 
 #endif
+
+static __inline__ __sum16 tcp_v6_check(int len,
+                                  const struct in6_addr *saddr,
+                                  const struct in6_addr *daddr,
+                                  __wsum base)
+{
+       return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
+}
+
+static inline void __tcp_v6_send_check(struct sk_buff *skb,
+                                      const struct in6_addr *saddr,
+                                      const struct in6_addr *daddr)
+{
+       struct tcphdr *th = tcp_hdr(skb);
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
+               skb->csum_start = skb_transport_header(skb) - skb->head;
+               skb->csum_offset = offsetof(struct tcphdr, check);
+       } else {
+               th->check = tcp_v6_check(skb->len, saddr, daddr,
+                                        csum_partial(th, th->doff << 2,
+                                                     skb->csum));
+       }
+}
+
+static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+
+       __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
+}
+
 #endif
index 45bd9cdd9244f05392f94678209e606e9db4647d..f47ad9f6ea2c91531e4f5f09984e5010355752af 100644 (file)
@@ -10,7 +10,7 @@ ipv6-objs :=  af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
                raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
                exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o
 
-ipv6-offload :=        ip6_offload.o
+ipv6-offload :=        ip6_offload.o tcpv6_offload.o
 
 ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o
 ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o
index c09614eaa929f5d49a74191992fea44d1f0c16b8..1891946ceedb740fa081cba59a297aab50e01412 100644 (file)
@@ -11,6 +11,9 @@
 #ifndef __ip6_offload_h
 #define __ip6_offload_h
 
+int tcpv6_offload_init(void);
+void tcpv6_offload_cleanup(void);
+
 extern void ipv6_offload_init(void);
 extern void ipv6_offload_cleanup(void);
 
index 635206e8987e28364a66f39f905855ad84a7a79e..5bed594b429d06fe0f920187dc70911824551daa 100644 (file)
 
 #include <linux/crypto.h>
 #include <linux/scatterlist.h>
+#include "ip6_offload.h"
 
 static void    tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb);
 static void    tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req);
 
 static int     tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb);
-static void    __tcp_v6_send_check(struct sk_buff *skb,
-                                   const struct in6_addr *saddr,
-                                   const struct in6_addr *daddr);
 
 static const struct inet_connection_sock_af_ops ipv6_mapped;
 static const struct inet_connection_sock_af_ops ipv6_specific;
@@ -119,14 +117,6 @@ static void tcp_v6_hash(struct sock *sk)
        }
 }
 
-static __inline__ __sum16 tcp_v6_check(int len,
-                                  const struct in6_addr *saddr,
-                                  const struct in6_addr *daddr,
-                                  __wsum base)
-{
-       return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base);
-}
-
 static __u32 tcp_v6_init_sequence(const struct sk_buff *skb)
 {
        return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32,
@@ -722,94 +712,6 @@ static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
 };
 #endif
 
-static void __tcp_v6_send_check(struct sk_buff *skb,
-                               const struct in6_addr *saddr, const struct in6_addr *daddr)
-{
-       struct tcphdr *th = tcp_hdr(skb);
-
-       if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0);
-               skb->csum_start = skb_transport_header(skb) - skb->head;
-               skb->csum_offset = offsetof(struct tcphdr, check);
-       } else {
-               th->check = tcp_v6_check(skb->len, saddr, daddr,
-                                        csum_partial(th, th->doff << 2,
-                                                     skb->csum));
-       }
-}
-
-static void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb)
-{
-       struct ipv6_pinfo *np = inet6_sk(sk);
-
-       __tcp_v6_send_check(skb, &np->saddr, &np->daddr);
-}
-
-static int tcp_v6_gso_send_check(struct sk_buff *skb)
-{
-       const struct ipv6hdr *ipv6h;
-       struct tcphdr *th;
-
-       if (!pskb_may_pull(skb, sizeof(*th)))
-               return -EINVAL;
-
-       ipv6h = ipv6_hdr(skb);
-       th = tcp_hdr(skb);
-
-       th->check = 0;
-       skb->ip_summed = CHECKSUM_PARTIAL;
-       __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
-       return 0;
-}
-
-static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
-                                        struct sk_buff *skb)
-{
-       const struct ipv6hdr *iph = skb_gro_network_header(skb);
-       __wsum wsum;
-       __sum16 sum;
-
-       switch (skb->ip_summed) {
-       case CHECKSUM_COMPLETE:
-               if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
-                                 skb->csum)) {
-                       skb->ip_summed = CHECKSUM_UNNECESSARY;
-                       break;
-               }
-flush:
-               NAPI_GRO_CB(skb)->flush = 1;
-               return NULL;
-
-       case CHECKSUM_NONE:
-               wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
-                                                   skb_gro_len(skb),
-                                                   IPPROTO_TCP, 0));
-               sum = csum_fold(skb_checksum(skb,
-                                            skb_gro_offset(skb),
-                                            skb_gro_len(skb),
-                                            wsum));
-               if (sum)
-                       goto flush;
-
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-               break;
-       }
-
-       return tcp_gro_receive(head, skb);
-}
-
-static int tcp6_gro_complete(struct sk_buff *skb)
-{
-       const struct ipv6hdr *iph = ipv6_hdr(skb);
-       struct tcphdr *th = tcp_hdr(skb);
-
-       th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
-                                 &iph->saddr, &iph->daddr, 0);
-       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
-
-       return tcp_gro_complete(skb);
-}
-
 static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win,
                                 u32 ts, struct tcp_md5sig_key *key, int rst, u8 tclass)
 {
@@ -2069,13 +1971,6 @@ static const struct inet6_protocol tcpv6_protocol = {
        .flags          =       INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
 };
 
-static const struct net_offload tcpv6_offload = {
-       .gso_send_check =       tcp_v6_gso_send_check,
-       .gso_segment    =       tcp_tso_segment,
-       .gro_receive    =       tcp6_gro_receive,
-       .gro_complete   =       tcp6_gro_complete,
-};
-
 static struct inet_protosw tcpv6_protosw = {
        .type           =       SOCK_STREAM,
        .protocol       =       IPPROTO_TCP,
@@ -2112,7 +2007,7 @@ int __init tcpv6_init(void)
 {
        int ret;
 
-       ret = inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
+       ret = tcpv6_offload_init();
        if (ret)
                goto out;
 
@@ -2136,7 +2031,7 @@ out_tcpv6_protosw:
 out_tcpv6_protocol:
        inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
 out_offload:
-       inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+       tcpv6_offload_cleanup();
        goto out;
 }
 
@@ -2145,5 +2040,5 @@ void tcpv6_exit(void)
        unregister_pernet_subsys(&tcpv6_net_ops);
        inet6_unregister_protosw(&tcpv6_protosw);
        inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP);
-       inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+       tcpv6_offload_cleanup();
 }
diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c
new file mode 100644 (file)
index 0000000..edeafed
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *     IPV6 GSO/GRO offload support
+ *     Linux INET6 implementation
+ *
+ *     This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ *      TCPv6 GSO/GRO support
+ */
+#include <linux/skbuff.h>
+#include <net/protocol.h>
+#include <net/tcp.h>
+#include <net/ip6_checksum.h>
+#include "ip6_offload.h"
+
+static int tcp_v6_gso_send_check(struct sk_buff *skb)
+{
+       const struct ipv6hdr *ipv6h;
+       struct tcphdr *th;
+
+       if (!pskb_may_pull(skb, sizeof(*th)))
+               return -EINVAL;
+
+       ipv6h = ipv6_hdr(skb);
+       th = tcp_hdr(skb);
+
+       th->check = 0;
+       skb->ip_summed = CHECKSUM_PARTIAL;
+       __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr);
+       return 0;
+}
+
+static struct sk_buff **tcp6_gro_receive(struct sk_buff **head,
+                                        struct sk_buff *skb)
+{
+       const struct ipv6hdr *iph = skb_gro_network_header(skb);
+       __wsum wsum;
+       __sum16 sum;
+
+       switch (skb->ip_summed) {
+       case CHECKSUM_COMPLETE:
+               if (!tcp_v6_check(skb_gro_len(skb), &iph->saddr, &iph->daddr,
+                                 skb->csum)) {
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       break;
+               }
+flush:
+               NAPI_GRO_CB(skb)->flush = 1;
+               return NULL;
+
+       case CHECKSUM_NONE:
+               wsum = ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr,
+                                                   skb_gro_len(skb),
+                                                   IPPROTO_TCP, 0));
+               sum = csum_fold(skb_checksum(skb,
+                                            skb_gro_offset(skb),
+                                            skb_gro_len(skb),
+                                            wsum));
+               if (sum)
+                       goto flush;
+
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               break;
+       }
+
+       return tcp_gro_receive(head, skb);
+}
+
+static int tcp6_gro_complete(struct sk_buff *skb)
+{
+       const struct ipv6hdr *iph = ipv6_hdr(skb);
+       struct tcphdr *th = tcp_hdr(skb);
+
+       th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb),
+                                 &iph->saddr, &iph->daddr, 0);
+       skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
+
+       return tcp_gro_complete(skb);
+}
+
+static const struct net_offload tcpv6_offload = {
+       .gso_send_check =       tcp_v6_gso_send_check,
+       .gso_segment    =       tcp_tso_segment,
+       .gro_receive    =       tcp6_gro_receive,
+       .gro_complete   =       tcp6_gro_complete,
+};
+
+int __init tcpv6_offload_init(void)
+{
+       return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP);
+}
+
+void tcpv6_offload_cleanup(void)
+{
+       inet6_del_offload(&tcpv6_offload, IPPROTO_TCP);
+}