]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv4/af_inet.c
[NET]: Add software TSOv4
[net-next-2.6.git] / net / ipv4 / af_inet.c
index dc206f1f914f51af724d2a8e6f21240f9956cd9b..461216b47948681791162829e8c4ca2b78e54d87 100644 (file)
@@ -68,6 +68,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/socket.h>
@@ -1096,6 +1097,54 @@ int inet_sk_rebuild_header(struct sock *sk)
 
 EXPORT_SYMBOL(inet_sk_rebuild_header);
 
+static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int sg)
+{
+       struct sk_buff *segs = ERR_PTR(-EINVAL);
+       struct iphdr *iph;
+       struct net_protocol *ops;
+       int proto;
+       int ihl;
+       int id;
+
+       if (!pskb_may_pull(skb, sizeof(*iph)))
+               goto out;
+
+       iph = skb->nh.iph;
+       ihl = iph->ihl * 4;
+       if (ihl < sizeof(*iph))
+               goto out;
+
+       if (!pskb_may_pull(skb, ihl))
+               goto out;
+
+       skb->h.raw = __skb_pull(skb, ihl);
+       iph = skb->nh.iph;
+       id = ntohs(iph->id);
+       proto = iph->protocol & (MAX_INET_PROTOS - 1);
+       segs = ERR_PTR(-EPROTONOSUPPORT);
+
+       rcu_read_lock();
+       ops = rcu_dereference(inet_protos[proto]);
+       if (ops && ops->gso_segment)
+               segs = ops->gso_segment(skb, sg);
+       rcu_read_unlock();
+
+       if (IS_ERR(segs))
+               goto out;
+
+       skb = segs;
+       do {
+               iph = skb->nh.iph;
+               iph->id = htons(id++);
+               iph->tot_len = htons(skb->len - skb->mac_len);
+               iph->check = 0;
+               iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+       } while ((skb = skb->next));
+
+out:
+       return segs;
+}
+
 #ifdef CONFIG_IP_MULTICAST
 static struct net_protocol igmp_protocol = {
        .handler =      igmp_rcv,
@@ -1105,6 +1154,7 @@ static struct net_protocol igmp_protocol = {
 static struct net_protocol tcp_protocol = {
        .handler =      tcp_v4_rcv,
        .err_handler =  tcp_v4_err,
+       .gso_segment =  tcp_tso_segment,
        .no_policy =    1,
 };
 
@@ -1150,6 +1200,7 @@ static int ipv4_proc_init(void);
 static struct packet_type ip_packet_type = {
        .type = __constant_htons(ETH_P_IP),
        .func = ip_rcv,
+       .gso_segment = inet_gso_segment,
 };
 
 static int __init inet_init(void)
@@ -1257,7 +1308,7 @@ out_unregister_udp_proto:
        goto out;
 }
 
-module_init(inet_init);
+fs_initcall(inet_init);
 
 /* ------------------------------------------------------------------------ */