]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv6/ip6_input.c
[IPV6]: Per-interface statistics support.
[net-next-2.6.git] / net / ipv6 / ip6_input.c
index ebf54ae90a0cecaa2ac6ec1acc8d3c5e5e5f754e..ad0b8abcdf4b65fbd9ebec449dcefd4acfb118e7 100644 (file)
@@ -60,14 +60,22 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 {
        struct ipv6hdr *hdr;
        u32             pkt_len;
+       struct inet6_dev *idev;
 
-       if (skb->pkt_type == PACKET_OTHERHOST)
-               goto drop;
+       if (skb->pkt_type == PACKET_OTHERHOST) {
+               kfree_skb(skb);
+               return 0;
+       }
+
+       rcu_read_lock();
 
-       IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
+       idev = __in6_dev_get(skb->dev);
+
+       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INRECEIVES);
 
        if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
-               IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+               IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
+               rcu_read_unlock();
                goto out;
        }
 
@@ -104,7 +112,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
                if (pkt_len + sizeof(struct ipv6hdr) > skb->len)
                        goto truncated;
                if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
-                       IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+                       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
                        goto drop;
                }
                hdr = skb->nh.ipv6h;
@@ -112,17 +120,21 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
 
        if (hdr->nexthdr == NEXTHDR_HOP) {
                if (ipv6_parse_hopopts(&skb) < 0) {
-                       IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+                       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
+                       rcu_read_unlock();
                        return 0;
                }
        }
 
+       rcu_read_unlock();
+
        return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
 truncated:
-       IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
+       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INTRUNCATEDPKTS);
 err:
-       IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INHDRERRORS);
 drop:
+       rcu_read_unlock();
        kfree_skb(skb);
 out:
        return 0;
@@ -140,6 +152,7 @@ static inline int ip6_input_finish(struct sk_buff *skb)
        unsigned int nhoff;
        int nexthdr;
        u8 hash;
+       struct inet6_dev *idev;
 
        /*
         *      Parse extension headers
@@ -147,6 +160,7 @@ static inline int ip6_input_finish(struct sk_buff *skb)
 
        rcu_read_lock();
 resubmit:
+       idev = ip6_dst_idev(skb->dst);
        if (!pskb_pull(skb, skb->h.raw - skb->data))
                goto discard;
        nhoff = IP6CB(skb)->nhoff;
@@ -185,24 +199,24 @@ resubmit:
                if (ret > 0)
                        goto resubmit;
                else if (ret == 0)
-                       IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
+                       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
        } else {
                if (!raw_sk) {
                        if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-                               IP6_INC_STATS_BH(IPSTATS_MIB_INUNKNOWNPROTOS);
+                               IP6_INC_STATS_BH(idev, IPSTATS_MIB_INUNKNOWNPROTOS);
                                icmpv6_send(skb, ICMPV6_PARAMPROB,
                                            ICMPV6_UNK_NEXTHDR, nhoff,
                                            skb->dev);
                        }
                } else
-                       IP6_INC_STATS_BH(IPSTATS_MIB_INDELIVERS);
+                       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDELIVERS);
                kfree_skb(skb);
        }
        rcu_read_unlock();
        return 0;
 
 discard:
-       IP6_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);
+       IP6_INC_STATS_BH(idev, IPSTATS_MIB_INDISCARDS);
        rcu_read_unlock();
        kfree_skb(skb);
        return 0;
@@ -219,7 +233,7 @@ int ip6_mc_input(struct sk_buff *skb)
        struct ipv6hdr *hdr;
        int deliver;
 
-       IP6_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS);
+       IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INMCASTPKTS);
 
        hdr = skb->nh.ipv6h;
        deliver = likely(!(skb->dev->flags & (IFF_PROMISC|IFF_ALLMULTI))) ||