[IPV6]: Per-interface statistics support.
For IP MIB (RFC4293).
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index ebf54ae..ad0b8ab 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -60,14 +60,22 @@
{
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;
+ }
- IP6_INC_STATS_BH(IPSTATS_MIB_INRECEIVES);
+ rcu_read_lock();
+
+ 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 @@
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 @@
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 @@
unsigned int nhoff;
int nexthdr;
u8 hash;
+ struct inet6_dev *idev;
/*
* Parse extension headers
@@ -147,6 +160,7 @@
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 @@
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 @@
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))) ||