]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv6/af_inet6.c
net: convert usage of packet_type to read_mostly
[net-next-2.6.git] / net / ipv6 / af_inet6.c
index c802bc1658a854bc2599c6821fe6bfb4b5998870..3e2ddfaee81a5b1cd2b5f133db31bce0d43528c2 100644 (file)
@@ -72,6 +72,10 @@ MODULE_LICENSE("GPL");
 static struct list_head inetsw6[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw6_lock);
 
+static int disable_ipv6 = 0;
+module_param_named(disable, disable_ipv6, int, 0);
+MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional");
+
 static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 {
        const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo);
@@ -799,24 +803,34 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head,
        int proto;
        __wsum csum;
 
-       if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
+       iph = skb_gro_header(skb, sizeof(*iph));
+       if (unlikely(!iph))
                goto out;
 
-       iph = ipv6_hdr(skb);
-       __skb_pull(skb, sizeof(*iph));
+       skb_gro_pull(skb, sizeof(*iph));
+       skb_set_transport_header(skb, skb_gro_offset(skb));
 
-       flush += ntohs(iph->payload_len) != skb->len;
+       flush += ntohs(iph->payload_len) != skb_gro_len(skb);
 
        rcu_read_lock();
-       proto = ipv6_gso_pull_exthdrs(skb, iph->nexthdr);
-       iph = ipv6_hdr(skb);
-       IPV6_GRO_CB(skb)->proto = proto;
+       proto = iph->nexthdr;
        ops = rcu_dereference(inet6_protos[proto]);
-       if (!ops || !ops->gro_receive)
-               goto out_unlock;
+       if (!ops || !ops->gro_receive) {
+               __pskb_pull(skb, skb_gro_offset(skb));
+               proto = ipv6_gso_pull_exthdrs(skb, proto);
+               skb_gro_pull(skb, -skb_transport_offset(skb));
+               skb_reset_transport_header(skb);
+               __skb_push(skb, skb_gro_offset(skb));
+
+               if (!ops || !ops->gro_receive)
+                       goto out_unlock;
+
+               iph = ipv6_hdr(skb);
+       }
+
+       IPV6_GRO_CB(skb)->proto = proto;
 
        flush--;
-       skb_reset_transport_header(skb);
        nlen = skb_network_header_len(skb);
 
        for (p = *head; p; p = p->next) {
@@ -879,8 +893,8 @@ out_unlock:
        return err;
 }
 
-static struct packet_type ipv6_packet_type = {
-       .type = __constant_htons(ETH_P_IPV6),
+static struct packet_type ipv6_packet_type __read_mostly = {
+       .type = cpu_to_be16(ETH_P_IPV6),
        .func = ipv6_rcv,
        .gso_send_check = ipv6_gso_send_check,
        .gso_segment = ipv6_gso_segment,
@@ -991,10 +1005,21 @@ static int __init inet6_init(void)
 {
        struct sk_buff *dummy_skb;
        struct list_head *r;
-       int err;
+       int err = 0;
 
        BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb));
 
+       /* Register the socket-side information for inet6_create.  */
+       for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
+               INIT_LIST_HEAD(r);
+
+       if (disable_ipv6) {
+               printk(KERN_INFO
+                      "IPv6: Loaded, but administratively disabled, "
+                      "reboot required to enable\n");
+               goto out;
+       }
+
        err = proto_register(&tcpv6_prot, 1);
        if (err)
                goto out;
@@ -1012,10 +1037,6 @@ static int __init inet6_init(void)
                goto out_unregister_udplite_proto;
 
 
-       /* Register the socket-side information for inet6_create.  */
-       for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
-               INIT_LIST_HEAD(r);
-
        /* We MUST register RAW sockets before we create the ICMP6,
         * IGMP6, or NDISC control sockets.
         */