Skip to content

Commit

Permalink
[IPV6]: Per-interface statistics support.
Browse files Browse the repository at this point in the history
For IP MIB (RFC4293).

Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  • Loading branch information
YOSHIFUJI Hideaki authored and David S. Miller committed Dec 3, 2006
1 parent 7a3025b commit a11d206
Show file tree
Hide file tree
Showing 13 changed files with 195 additions and 108 deletions.
1 change: 1 addition & 0 deletions include/net/if_inet6.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ struct ifacaddr6

struct ipv6_devstat {
struct proc_dir_entry *proc_dir_entry;
DEFINE_SNMP_STAT(struct ipstats_mib, ipv6);
DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6);
};

Expand Down
21 changes: 18 additions & 3 deletions include/net/ipv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,24 @@ extern int sysctl_mld_max_msf;

/* MIBs */
DECLARE_SNMP_STAT(struct ipstats_mib, ipv6_statistics);
#define IP6_INC_STATS(field) SNMP_INC_STATS(ipv6_statistics, field)
#define IP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(ipv6_statistics, field)
#define IP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(ipv6_statistics, field)
#define IP6_INC_STATS(idev,field) ({ \
struct inet6_dev *_idev = (idev); \
if (likely(_idev != NULL)) \
SNMP_INC_STATS(_idev->stats.ipv6, field); \
SNMP_INC_STATS(ipv6_statistics, field); \
})
#define IP6_INC_STATS_BH(idev,field) ({ \
struct inet6_dev *_idev = (idev); \
if (likely(_idev != NULL)) \
SNMP_INC_STATS_BH(_idev->stats.ipv6, field); \
SNMP_INC_STATS_BH(ipv6_statistics, field); \
})
#define IP6_INC_STATS_USER(idev,field) ({ \
struct inet6_dev *_idev = (idev); \
if (likely(_idev != NULL)) \
SNMP_INC_STATS_USER(_idev->stats.ipv6, field); \
SNMP_INC_STATS_USER(ipv6_statistics, field); \
})
DECLARE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
#define ICMP6_INC_STATS(idev, field) ({ \
struct inet6_dev *_idev = (idev); \
Expand Down
57 changes: 38 additions & 19 deletions net/ipv6/exthdrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,12 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
#ifdef CONFIG_IPV6_MIP6
__u16 dstbuf;
#endif
struct dst_entry *dst;

if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -298,7 +300,9 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
dstbuf = opt->dst1;
#endif

dst = dst_clone(skb->dst);
if (ip6_parse_tlv(tlvprocdestopt_lst, skbp)) {
dst_release(dst);
skb = *skbp;
skb->h.raw += ((skb->h.raw[1]+1)<<3);
opt = IP6CB(skb);
Expand All @@ -310,7 +314,8 @@ static int ipv6_destopt_rcv(struct sk_buff **skbp)
return 1;
}

IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
dst_release(dst);
return -1;
}

Expand Down Expand Up @@ -365,7 +370,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)

if (!pskb_may_pull(skb, (skb->h.raw-skb->data)+8) ||
!pskb_may_pull(skb, (skb->h.raw-skb->data)+((skb->h.raw[1]+1)<<3))) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -374,7 +380,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)

if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr) ||
skb->pkt_type != PACKET_HOST) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -388,7 +395,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
* processed by own
*/
if (!addr) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -410,7 +418,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
switch (hdr->type) {
case IPV6_SRCRT_TYPE_0:
if (hdr->hdrlen & 0x01) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
return -1;
}
Expand All @@ -419,14 +428,16 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
case IPV6_SRCRT_TYPE_2:
/* Silently discard invalid RTH type 2 */
if (hdr->hdrlen != 2 || hdr->segments_left != 1) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -1;
}
break;
#endif
default:
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
return -1;
}
Expand All @@ -439,7 +450,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
n = hdr->hdrlen >> 1;

if (hdr->segments_left > n) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw);
return -1;
}
Expand All @@ -449,12 +461,14 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
*/
if (skb_cloned(skb)) {
struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC);
kfree_skb(skb);
/* the copy is a forwarded packet */
if (skb2 == NULL) {
IP6_INC_STATS_BH(IPSTATS_MIB_OUTDISCARDS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return -1;
}
kfree_skb(skb);
*skbp = skb = skb2;
opt = IP6CB(skb2);
hdr = (struct ipv6_rt_hdr *) skb2->h.raw;
Expand All @@ -475,12 +489,14 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
if (xfrm6_input_addr(skb, (xfrm_address_t *)addr,
(xfrm_address_t *)&skb->nh.ipv6h->saddr,
IPPROTO_ROUTING) < 0) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
if (!ipv6_chk_home_addr(addr)) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -491,7 +507,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)
}

if (ipv6_addr_is_multicast(addr)) {
IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INADDRERRORS);
kfree_skb(skb);
return -1;
}
Expand All @@ -510,7 +527,8 @@ static int ipv6_rthdr_rcv(struct sk_buff **skbp)

if (skb->dst->dev->flags&IFF_LOOPBACK) {
if (skb->nh.ipv6h->hop_limit <= 1) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev);
kfree_skb(skb);
Expand Down Expand Up @@ -632,24 +650,25 @@ static int ipv6_hop_jumbo(struct sk_buff **skbp, int optoff)
if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) {
LIMIT_NETDEBUG(KERN_DEBUG "ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
skb->nh.raw[optoff+1]);
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst),
IPSTATS_MIB_INHDRERRORS);
goto drop;
}

pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2));
if (pkt_len <= IPV6_MAXPLEN) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
return 0;
}
if (skb->nh.ipv6h->payload_len) {
IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INHDRERRORS);
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
return 0;
}

if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
IP6_INC_STATS_BH(IPSTATS_MIB_INTRUNCATEDPKTS);
IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop;
}

Expand Down
3 changes: 2 additions & 1 deletion net/ipv6/icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
*/
dst = ip6_route_output(sk, fl);
if (dst->error) {
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
IP6_INC_STATS(ip6_dst_idev(dst),
IPSTATS_MIB_OUTNOROUTES);
} else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) {
res = 1;
} else {
Expand Down
40 changes: 27 additions & 13 deletions net/ipv6/ip6_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -104,25 +112,29 @@ 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;
}

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;
Expand All @@ -140,13 +152,15 @@ static inline int ip6_input_finish(struct sk_buff *skb)
unsigned int nhoff;
int nexthdr;
u8 hash;
struct inet6_dev *idev;

/*
* Parse extension headers
*/

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;
Expand Down Expand Up @@ -185,24 +199,24 @@ static inline int ip6_input_finish(struct sk_buff *skb)
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;
Expand All @@ -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))) ||
Expand Down
Loading

0 comments on commit a11d206

Please sign in to comment.