Hi, This patch builds upon the per-interface statistics patch that Yoshfuji-san and I did a few weeks ago (for icmpv6). This one adds ipv6 statistics per network interface. It retains the current /proc/net/snmp6 counters and adds counters in /proc/net/dev_snmp6/<ifname>. Patch is to 2.5.70-bk-current of 2003-06-05. Builds and boots, counters are working. Tested by using ncp between 2 machines running IPv6. Comments? idev locking? Dave, do you want these counters exposed via netlink instead of via /proc? Thanks, -- ~Randy diffstat: include/net/if_inet6.h | 1 include/net/ipv6.h | 23 ++++++++- net/ipv6/exthdrs.c | 46 +++++++++++++------ net/ipv6/icmp.c | 2 net/ipv6/ip6_input.c | 36 ++++++++++----- net/ipv6/ip6_output.c | 116 ++++++++++++++++++++++++++++++++----------------- net/ipv6/proc.c | 6 ++ net/ipv6/raw.c | 2 net/ipv6/reassembly.c | 26 ++++++---- net/ipv6/route.c | 2 10 files changed, 180 insertions(+), 80 deletions(-) diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/include/net/if_inet6.h linux-2570-605/include/net/if_inet6.h --- linux-2570-605-pv/include/net/if_inet6.h 2003-06-05 13:40:03.000000000 -0700 +++ linux-2570-605/include/net/if_inet6.h 2003-06-05 11:41:05.000000000 -0700 @@ -156,6 +156,7 @@ struct ipv6_devconf struct ipv6_devstat { struct proc_dir_entry *proc_dir_entry; + DEFINE_SNMP_STAT(struct ipv6_mib, ipv6); DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6); }; diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/include/net/ipv6.h linux-2570-605/include/net/ipv6.h --- linux-2570-605-pv/include/net/ipv6.h 2003-06-05 13:39:48.000000000 -0700 +++ linux-2570-605/include/net/ipv6.h 2003-06-05 11:42:30.000000000 -0700 @@ -108,9 +108,25 @@ extern int sysctl_ipv6_bindv6only; /* MIBs */ DECLARE_SNMP_STAT(struct ipv6_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); \ @@ -137,6 +153,7 @@ DECLARE_SNMP_STAT(struct icmpv6_mib, icm SNMP_INC_STATS_OFFSET_BH(_idev->stats.icmpv6, field, _offset); \ SNMP_INC_STATS_OFFSET_BH(icmpv6_statistics, field, _offset); \ }) + DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6); #define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) #define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/exthdrs.c linux-2570-605/net/ipv6/exthdrs.c --- linux-2570-605-pv/net/ipv6/exthdrs.c 2003-06-05 13:39:12.000000000 -0700 +++ linux-2570-605/net/ipv6/exthdrs.c 2003-06-05 11:42:30.000000000 -0700 @@ -215,6 +215,7 @@ void __init ipv6_nodata_init(void) static int ipv6_rthdr_rcv(struct sk_buff **skbp, unsigned int *nhoffp) { struct sk_buff *skb = *skbp; + struct inet6_dev *idev = NULL; struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; struct in6_addr *addr; struct in6_addr daddr; @@ -224,11 +225,13 @@ static int ipv6_rthdr_rcv(struct sk_buff struct ipv6_rt_hdr *hdr; struct rt0_hdr *rthdr; + idev = in6_dev_get(skb->dev); + 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(Ip6InHdrErrors); + IP6_INC_STATS_BH(idev, Ip6InHdrErrors); kfree_skb(skb); - return -1; + goto errout; } hdr = (struct ipv6_rt_hdr *) skb->h.raw; @@ -236,7 +239,7 @@ static int ipv6_rthdr_rcv(struct sk_buff if ((ipv6_addr_type(&skb->nh.ipv6h->daddr)&IPV6_ADDR_MULTICAST) || skb->pkt_type != PACKET_HOST) { kfree_skb(skb); - return -1; + goto errout; } looped_back: @@ -246,17 +249,17 @@ looped_back: opt->dst0 = opt->dst1; opt->dst1 = 0; *nhoffp = (&hdr->nexthdr) - skb->nh.raw; - return 1; + goto ok; } if (hdr->type != IPV6_SRCRT_TYPE_0) { icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw); - return -1; + goto errout; } if (hdr->hdrlen & 0x01) { icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw); - return -1; + goto errout; } /* @@ -268,7 +271,7 @@ looped_back: if (hdr->segments_left > n) { icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->segments_left) - skb->nh.raw); - return -1; + goto errout; } /* We are about to mangle packet header. Be careful! @@ -278,7 +281,7 @@ looped_back: struct sk_buff *skb2 = skb_copy(skb, GFP_ATOMIC); kfree_skb(skb); if (skb2 == NULL) - return -1; + goto errout; *skbp = skb = skb2; opt = (struct inet6_skb_parm *)skb2->cb; hdr = (struct ipv6_rt_hdr *) skb2->h.raw; @@ -297,7 +300,7 @@ looped_back: if (addr_type&IPV6_ADDR_MULTICAST) { kfree_skb(skb); - return -1; + goto errout; } ipv6_addr_copy(&daddr, addr); @@ -308,21 +311,29 @@ looped_back: ip6_route_input(skb); if (skb->dst->error) { dst_input(skb); - return -1; + goto errout; } if (skb->dst->dev->flags&IFF_LOOPBACK) { if (skb->nh.ipv6h->hop_limit <= 1) { icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0, skb->dev); kfree_skb(skb); - return -1; + goto errout; } skb->nh.ipv6h->hop_limit--; goto looped_back; } dst_input(skb); + errout: + if (likely(idev != NULL)) + in6_dev_put(idev); return -1; + + ok: + if (likely(idev != NULL)) + in6_dev_put(idev); + return 1; } static struct inet6_protocol rthdr_protocol = { @@ -424,6 +435,7 @@ static int ipv6_hop_ra(struct sk_buff *s static int ipv6_hop_jumbo(struct sk_buff *skb, int optoff) { u32 pkt_len; + struct inet6_dev *idev = in6_dev_get(skb->dev); if (skb->nh.raw[optoff+1] != 4 || (optoff&3) != 2) { if (net_ratelimit()) @@ -434,15 +446,15 @@ static int ipv6_hop_jumbo(struct sk_buff pkt_len = ntohl(*(u32*)(skb->nh.raw+optoff+2)); if (pkt_len < 0x10000) { icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); - return 0; + goto out; } if (skb->nh.ipv6h->payload_len) { icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); - return 0; + goto out; } if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { - IP6_INC_STATS_BH(Ip6InTruncatedPkts); + IP6_INC_STATS_BH(idev, Ip6InTruncatedPkts); goto drop; } if (pkt_len + sizeof(struct ipv6hdr) < skb->len) { @@ -450,10 +462,16 @@ static int ipv6_hop_jumbo(struct sk_buff if (skb->ip_summed == CHECKSUM_HW) skb->ip_summed = CHECKSUM_NONE; } + + if (likely(idev != NULL)) + in6_dev_put(idev); return 1; drop: kfree_skb(skb); +out: + if (likely(idev != NULL)) + in6_dev_put(idev); return 0; } diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/icmp.c linux-2570-605/net/ipv6/icmp.c --- linux-2570-605-pv/net/ipv6/icmp.c 2003-06-05 13:39:21.000000000 -0700 +++ linux-2570-605/net/ipv6/icmp.c 2003-06-05 11:42:30.000000000 -0700 @@ -173,7 +173,7 @@ static inline int icmpv6_xrlim_allow(str */ dst = ip6_route_output(sk, fl); if (dst->error) { - IP6_INC_STATS(Ip6OutNoRoutes); + IP6_INC_STATS(NULL, Ip6OutNoRoutes); } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { res = 1; } else { diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/ip6_input.c linux-2570-605/net/ipv6/ip6_input.c --- linux-2570-605-pv/net/ipv6/ip6_input.c 2003-06-05 13:39:46.000000000 -0700 +++ linux-2570-605/net/ipv6/ip6_input.c 2003-06-05 11:42:30.000000000 -0700 @@ -60,14 +60,16 @@ int ipv6_rcv(struct sk_buff *skb, struct { struct ipv6hdr *hdr; u32 pkt_len; + struct inet6_dev *idev = NULL; if (skb->pkt_type == PACKET_OTHERHOST) goto drop; - IP6_INC_STATS_BH(Ip6InReceives); + idev = in6_dev_get(dev); + IP6_INC_STATS_BH(idev, Ip6InReceives); if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - IP6_INC_STATS_BH(Ip6InDiscards); + IP6_INC_STATS_BH(idev, Ip6InDiscards); goto out; } @@ -105,20 +107,22 @@ int ipv6_rcv(struct sk_buff *skb, struct if (hdr->nexthdr == NEXTHDR_HOP) { skb->h.raw = (u8*)(hdr+1); if (ipv6_parse_hopopts(skb, offsetof(struct ipv6hdr, nexthdr)) < 0) { - IP6_INC_STATS_BH(Ip6InHdrErrors); - return 0; + IP6_INC_STATS_BH(idev, Ip6InHdrErrors); + goto out; } hdr = skb->nh.ipv6h; } return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish); truncated: - IP6_INC_STATS_BH(Ip6InTruncatedPkts); + IP6_INC_STATS_BH(idev, Ip6InTruncatedPkts); err: - IP6_INC_STATS_BH(Ip6InHdrErrors); + IP6_INC_STATS_BH(idev, Ip6InHdrErrors); drop: kfree_skb(skb); out: + if (likely(idev != NULL)) + in6_dev_put(idev); return 0; } @@ -131,6 +135,7 @@ static inline int ip6_input_finish(struc { struct inet6_protocol *ipprot; struct sock *raw_sk; + struct inet6_dev *idev = NULL; unsigned int nhoff; int nexthdr; u8 hash; @@ -145,13 +150,14 @@ static inline int ip6_input_finish(struc nexthdr = skb->nh.ipv6h->nexthdr; nhoff = offsetof(struct ipv6hdr, nexthdr); - /* Skip hop-by-hop options, they are already parsed. */ + /* Skip hop-by-hop options, they are already parsed. */ if (nexthdr == NEXTHDR_HOP) { nhoff = sizeof(struct ipv6hdr); nexthdr = skb->h.raw[0]; skb->h.raw += (skb->h.raw[1]+1)<<3; } + idev = in6_dev_get(skb->dev); rcu_read_lock(); resubmit: if (!pskb_pull(skb, skb->h.raw - skb->data)) @@ -182,23 +188,27 @@ resubmit: if (ret > 0) goto resubmit; else if (ret == 0) - IP6_INC_STATS_BH(Ip6InDelivers); + IP6_INC_STATS_BH(idev, Ip6InDelivers); } else { if (!raw_sk) { if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - IP6_INC_STATS_BH(Ip6InUnknownProtos); + IP6_INC_STATS_BH(idev, Ip6InUnknownProtos); icmpv6_param_prob(skb, ICMPV6_UNK_NEXTHDR, nhoff); } } else { - IP6_INC_STATS_BH(Ip6InDelivers); + IP6_INC_STATS_BH(idev, Ip6InDelivers); kfree_skb(skb); } } rcu_read_unlock(); + if (likely(idev != NULL)) + in6_dev_put(idev); return 0; discard: rcu_read_unlock(); + if (likely(idev != NULL)) + in6_dev_put(idev); kfree_skb(skb); return 0; } @@ -214,8 +224,9 @@ int ip6_mc_input(struct sk_buff *skb) struct ipv6hdr *hdr; int deliver = 0; int discard = 1; + struct inet6_dev *idev = in6_dev_get(skb->dev); - IP6_INC_STATS_BH(Ip6InMcastPkts); + IP6_INC_STATS_BH(idev, Ip6InMcastPkts); hdr = skb->nh.ipv6h; if (ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, &hdr->saddr)) @@ -256,5 +267,8 @@ int ip6_mc_input(struct sk_buff *skb) if (discard) kfree_skb(skb); + if (likely(idev != NULL)) + in6_dev_put(idev); + return 0; } diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/ip6_output.c linux-2570-605/net/ipv6/ip6_output.c --- linux-2570-605-pv/net/ipv6/ip6_output.c 2003-06-05 13:39:13.000000000 -0700 +++ linux-2570-605/net/ipv6/ip6_output.c 2003-06-05 12:59:58.000000000 -0700 @@ -133,7 +133,7 @@ int ip6_output2(struct sk_buff *skb) } } - IP6_INC_STATS(Ip6OutMcastPkts); + IP6_INC_STATS(__in6_dev_get(dev), Ip6OutMcastPkts); } return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); @@ -202,6 +202,7 @@ int ip6_xmit(struct sock *sk, struct sk_ struct in6_addr *first_hop = &fl->fl6_dst; struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr; + struct inet6_dev *idev = NULL; u8 proto = fl->proto; int seg_len = skb->len; int hlimit; @@ -259,8 +260,12 @@ int ip6_xmit(struct sock *sk, struct sk_ mtu = dst_pmtu(dst); if (skb->len <= mtu) { - IP6_INC_STATS(Ip6OutRequests); - return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); + idev = in6_dev_get(dst->dev); + IP6_INC_STATS(idev, Ip6OutRequests); + err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); + if (likely(idev != NULL)) + in6_dev_put(idev); + return err; } if (net_ratelimit()) @@ -348,6 +353,7 @@ static int ip6_frag_xmit(struct sock *sk { struct ipv6hdr *hdr; struct sk_buff *last_skb; + struct inet6_dev *idev = NULL; u8 *prev_hdr; int unfrag_len; int frag_len; @@ -381,7 +387,7 @@ static int ip6_frag_xmit(struct sock *sk /* * Length of fragmented part on every packet but * the last must be an: - * "integer multiple of 8 octects". + * "integer multiple of 8 octets". */ frag_len = (mtu - unfrag_len) & ~0x7; @@ -449,6 +455,8 @@ static int ip6_frag_xmit(struct sock *sk prev_hdr = ipv6_build_fraghdr(last_skb, prev_hdr, frag_off); fhdr_dist = prev_hdr - last_skb->data; + idev = in6_dev_get(dst->dev); + err = getfrag(data, &hdr->saddr, last_skb->tail, data_off, last_len); if (!err) { @@ -460,9 +468,10 @@ static int ip6_frag_xmit(struct sock *sk skb = skb_copy(last_skb, sk->allocation); if (skb == NULL) { - IP6_INC_STATS(Ip6FragFails); + IP6_INC_STATS(idev, Ip6FragFails); kfree_skb(last_skb); - return -ENOMEM; + err = -ENOMEM; + goto outerr; } frag_off -= frag_len; @@ -488,20 +497,21 @@ static int ip6_frag_xmit(struct sock *sk break; } - IP6_INC_STATS(Ip6FragCreates); - IP6_INC_STATS(Ip6OutRequests); + IP6_INC_STATS(idev, Ip6FragCreates); + IP6_INC_STATS(idev, Ip6OutRequests); err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); if (err) { kfree_skb(last_skb); - return err; + goto outerr; } } } if (err) { - IP6_INC_STATS(Ip6FragFails); + IP6_INC_STATS(idev, Ip6FragFails); kfree_skb(last_skb); - return -EFAULT; + err = -EFAULT; + goto outerr; } hdr->payload_len = htons(unfrag_len + last_len - sizeof(struct ipv6hdr)); @@ -513,10 +523,15 @@ static int ip6_frag_xmit(struct sock *sk skb_put(last_skb, last_len); - IP6_INC_STATS(Ip6FragCreates); - IP6_INC_STATS(Ip6FragOKs); - IP6_INC_STATS(Ip6OutRequests); - return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute); + IP6_INC_STATS(idev, Ip6FragCreates); + IP6_INC_STATS(idev, Ip6FragOKs); + IP6_INC_STATS(idev, Ip6OutRequests); + err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL, dst->dev, ip6_maybe_reroute); + +outerr: + if (likely(idev != NULL)) + in6_dev_put(idev); + return err; } int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, @@ -576,7 +591,7 @@ int ip6_build_xmit(struct sock *sk, inet dst = ip6_route_output(sk, fl); if (dst->error) { - IP6_INC_STATS(Ip6OutNoRoutes); + IP6_INC_STATS(NULL, Ip6OutNoRoutes); dst_release(dst); return -ENETUNREACH; } @@ -587,7 +602,7 @@ int ip6_build_xmit(struct sock *sk, inet if (err) { #if IP6_DEBUG >= 2 printk(KERN_DEBUG "ip6_build_xmit: " - "no availiable source address\n"); + "no available source address\n"); #endif goto out; } @@ -660,7 +675,7 @@ int ip6_build_xmit(struct sock *sk, inet flags & MSG_DONTWAIT, &err); if (skb == NULL) { - IP6_INC_STATS(Ip6OutDiscards); + IP6_INC_STATS(__in6_dev_get(dev), Ip6OutDiscards); goto out; } @@ -691,7 +706,7 @@ int ip6_build_xmit(struct sock *sk, inet skb->h.raw = ((char *) hdr) + (pktlength - length); if (!err) { - IP6_INC_STATS(Ip6OutRequests); + IP6_INC_STATS(__in6_dev_get(dev), Ip6OutRequests); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); } else { err = -EFAULT; @@ -758,7 +773,9 @@ int ip6_forward(struct sk_buff *skb) struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = skb->nh.ipv6h; struct inet6_skb_parm *opt =(struct inet6_skb_parm*)skb->cb; - + struct inet6_dev *idev = in6_dev_get(skb->dev); + int err = 0; + if (ipv6_devconf.forwarding == 0) goto error; @@ -783,7 +800,7 @@ int ip6_forward(struct sk_buff *skb) if (opt->ra) { u8 *ptr = skb->nh.raw + opt->ra; if (ip6_call_ra_chain(skb, (ptr[2]<<8) + ptr[3])) - return 0; + goto fini; } /* @@ -796,7 +813,8 @@ int ip6_forward(struct sk_buff *skb) 0, skb->dev); kfree_skb(skb); - return -ETIMEDOUT; + err = -ETIMEDOUT; + goto fini; } if (!xfrm6_route_forward(skb)) @@ -836,9 +854,10 @@ int ip6_forward(struct sk_buff *skb) /* Again, force OUTPUT device used as source address */ skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_pmtu(dst), skb->dev); - IP6_INC_STATS_BH(Ip6InTooBigErrors); + IP6_INC_STATS_BH(idev, Ip6InTooBigErrors); kfree_skb(skb); - return -EMSGSIZE; + err = -EMSGSIZE; + goto fini; } if (skb_cow(skb, dst->dev->hard_header_len)) @@ -850,14 +869,21 @@ int ip6_forward(struct sk_buff *skb) hdr->hop_limit--; - IP6_INC_STATS_BH(Ip6OutForwDatagrams); - return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); + IP6_INC_STATS_BH(idev, Ip6OutForwDatagrams); + err = NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); + goto fini; error: - IP6_INC_STATS_BH(Ip6InAddrErrors); + IP6_INC_STATS_BH(idev, Ip6InAddrErrors); drop: kfree_skb(skb); + if (likely(idev != NULL)) + in6_dev_put(idev); return -EINVAL; +fini: + if (likely(idev != NULL)) + in6_dev_put(idev); + return err; } static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) @@ -923,12 +949,14 @@ static int ip6_fragment(struct sk_buff * struct sk_buff *frag; struct ipv6hdr *tmp_hdr; struct frag_hdr *fh; + struct inet6_dev *idev; unsigned int mtu, hlen, left, len; u32 frag_id = 0; int ptr, offset = 0, err=0; u8 *prevhdr, nexthdr = 0; dev = rt->u.dst.dev; + idev = in6_dev_get(dev); hlen = ip6_found_nexthdr(skb, &prevhdr); nexthdr = *prevhdr; @@ -966,8 +994,9 @@ static int ip6_fragment(struct sk_buff * tmp_hdr = kmalloc(hlen, GFP_ATOMIC); if (!tmp_hdr) { - IP6_INC_STATS(Ip6FragFails); - return -ENOMEM; + IP6_INC_STATS(idev, Ip6FragFails); + err = -ENOMEM; + goto outerr; } *prevhdr = NEXTHDR_FRAGMENT; @@ -1021,8 +1050,8 @@ static int ip6_fragment(struct sk_buff * kfree(tmp_hdr); if (err == 0) { - IP6_INC_STATS(Ip6FragOKs); - return 0; + IP6_INC_STATS(idev, Ip6FragOKs); + goto outerr; } while (frag) { @@ -1031,8 +1060,8 @@ static int ip6_fragment(struct sk_buff * frag = skb; } - IP6_INC_STATS(Ip6FragFails); - return err; + IP6_INC_STATS(idev, Ip6FragFails); + goto outerr; } slow_path: @@ -1119,19 +1148,24 @@ slow_path: * Put this fragment into the sending queue. */ - IP6_INC_STATS(Ip6FragCreates); + IP6_INC_STATS(idev, Ip6FragCreates); err = output(frag); if (err) goto fail; } kfree_skb(skb); - IP6_INC_STATS(Ip6FragOKs); + IP6_INC_STATS(idev, Ip6FragOKs); + if (likely(idev != NULL)) + in6_dev_put(idev); return err; fail: kfree_skb(skb); - IP6_INC_STATS(Ip6FragFails); + IP6_INC_STATS(idev, Ip6FragFails); +outerr: + if (likely(idev != NULL)) + in6_dev_put(idev); return err; } @@ -1176,7 +1210,7 @@ int ip6_dst_lookup(struct sock *sk, stru *dst = ip6_route_output(sk, fl); if ((*dst)->error) { - IP6_INC_STATS(Ip6OutNoRoutes); + IP6_INC_STATS(NULL, Ip6OutNoRoutes); dst_release(*dst); return -ENETUNREACH; } @@ -1187,7 +1221,7 @@ int ip6_dst_lookup(struct sock *sk, stru if (err) { #if IP6_DEBUG >= 2 printk(KERN_DEBUG "ip6_build_xmit: " - "no availiable source address\n"); + "no available source address\n"); #endif return err; } @@ -1211,6 +1245,7 @@ int ip6_append_data(struct sock *sk, int struct inet_opt *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct sk_buff *skb; + struct inet6_dev *idev = NULL; unsigned int maxfraglen, fragheaderlen; int exthdrlen; int hh_len; @@ -1404,8 +1439,11 @@ alloc_new_skb: } return 0; error: + idev = in6_dev_get(rt->u.dst.dev); inet->cork.length -= length; - IP6_INC_STATS(Ip6OutDiscards); + IP6_INC_STATS(idev, Ip6OutDiscards); + if (likely(idev != NULL)) + in6_dev_put(idev); return err; } diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/proc.c linux-2570-605/net/ipv6/proc.c --- linux-2570-605-pv/net/ipv6/proc.c 2003-06-05 13:39:24.000000000 -0700 +++ linux-2570-605/net/ipv6/proc.c 2003-06-05 14:04:06.000000000 -0700 @@ -183,6 +183,7 @@ static int snmp6_seq_show(struct seq_fil if (idev) { seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); + snmp6_seq_show_item(seq, (void **)idev->stats.ipv6, snmp6_ipv6_list); snmp6_seq_show_item(seq, (void **)idev->stats.icmpv6, snmp6_icmp6_list); } else { snmp6_seq_show_item(seq, (void **)ipv6_statistics, snmp6_ipv6_list); @@ -228,6 +229,8 @@ int snmp6_register_dev(struct inet6_dev if (!idev || !idev->dev) return -EINVAL; + if (snmp6_mib_init((void **)idev->stats.ipv6, sizeof(struct ipv6_mib)) < 0) + goto err_ip; if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib)) < 0) goto err_icmp; @@ -251,6 +254,8 @@ err_proc: snmp6_mib_free((void **)idev->stats.icmpv6); #endif err_icmp: + snmp6_mib_free((void **)idev->stats.ipv6); +err_ip: return err; } @@ -265,6 +270,7 @@ int snmp6_unregister_dev(struct inet6_de proc_net_devsnmp6); #endif snmp6_mib_free((void **)idev->stats.icmpv6); + snmp6_mib_free((void **)idev->stats.ipv6); return 0; } diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/raw.c linux-2570-605/net/ipv6/raw.c --- linux-2570-605-pv/net/ipv6/raw.c 2003-06-05 13:39:23.000000000 -0700 +++ linux-2570-605/net/ipv6/raw.c 2003-06-05 11:42:30.000000000 -0700 @@ -533,7 +533,7 @@ error_fault: err = -EFAULT; kfree_skb(skb); error: - IP6_INC_STATS(Ip6OutDiscards); + IP6_INC_STATS(!skb ? NULL : __in6_dev_get(skb->dev), Ip6OutDiscards); return err; } static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len) diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/reassembly.c linux-2570-605/net/ipv6/reassembly.c --- linux-2570-605-pv/net/ipv6/reassembly.c 2003-06-05 13:39:21.000000000 -0700 +++ linux-2570-605/net/ipv6/reassembly.c 2003-06-05 11:42:30.000000000 -0700 @@ -264,6 +264,7 @@ static void ip6_evictor(void) { struct frag_queue *fq; struct list_head *tmp; + struct net_device *dev; for(;;) { if (atomic_read(&ip6_frag_mem) <= sysctl_ip6frag_low_thresh) @@ -283,14 +284,18 @@ static void ip6_evictor(void) fq_kill(fq); spin_unlock(&fq->lock); + dev = dev_get_by_index(fq->iif); fq_put(fq); - IP6_INC_STATS_BH(Ip6ReasmFails); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmFails); + dev_put(dev); } } static void ip6_frag_expire(unsigned long data) { struct frag_queue *fq = (struct frag_queue *) data; + struct net_device *dev = dev_get_by_index(fq->iif); + struct inet6_dev *idev = in6_dev_get(dev); spin_lock(&fq->lock); @@ -299,12 +304,11 @@ static void ip6_frag_expire(unsigned lon fq_kill(fq); - IP6_INC_STATS_BH(Ip6ReasmTimeout); - IP6_INC_STATS_BH(Ip6ReasmFails); + IP6_INC_STATS_BH(idev, Ip6ReasmTimeout); + IP6_INC_STATS_BH(idev, Ip6ReasmFails); /* Send error only if the first segment arrived. */ if (fq->last_in&FIRST_IN && fq->fragments) { - struct net_device *dev = dev_get_by_index(fq->iif); /* But use as source device on which LAST ARRIVED @@ -320,6 +324,8 @@ static void ip6_frag_expire(unsigned lon } out: spin_unlock(&fq->lock); + if (likely(idev != NULL)) + in6_dev_put(idev); fq_put(fq); } @@ -386,7 +392,7 @@ ip6_frag_create(unsigned int hash, u32 i return ip6_frag_intern(hash, fq); oom: - IP6_INC_STATS_BH(Ip6ReasmFails); + IP6_INC_STATS_BH(NULL, Ip6ReasmFails); return NULL; } @@ -664,7 +670,7 @@ static int ip6_frag_reasm(struct frag_qu if (head->ip_summed == CHECKSUM_HW) head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum); - IP6_INC_STATS_BH(Ip6ReasmOKs); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmOKs); fq->fragments = NULL; *nhoffp = nhoff; return 1; @@ -677,7 +683,7 @@ out_oom: if (net_ratelimit()) printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n"); out_fail: - IP6_INC_STATS_BH(Ip6ReasmFails); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmFails); return -1; } @@ -691,7 +697,7 @@ static int ipv6_frag_rcv(struct sk_buff hdr = skb->nh.ipv6h; - IP6_INC_STATS_BH(Ip6ReasmReqds); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmReqds); /* Jumbo payload inhibits frag. header */ if (hdr->payload_len==0) { @@ -709,7 +715,7 @@ static int ipv6_frag_rcv(struct sk_buff if (!(fhdr->frag_off & htons(0xFFF9))) { /* It is not a fragmented frame */ skb->h.raw += sizeof(struct frag_hdr); - IP6_INC_STATS_BH(Ip6ReasmOKs); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmOKs); *nhoffp = (u8*)fhdr - skb->nh.raw; return 1; @@ -734,7 +740,7 @@ static int ipv6_frag_rcv(struct sk_buff return ret; } - IP6_INC_STATS_BH(Ip6ReasmFails); + IP6_INC_STATS_BH(__in6_dev_get(dev), Ip6ReasmFails); kfree_skb(skb); return -1; } diff -Naurp -X /home/rddunlap/doc/dontdiff-osdl linux-2570-605-pv/net/ipv6/route.c linux-2570-605/net/ipv6/route.c --- linux-2570-605-pv/net/ipv6/route.c 2003-06-05 13:39:47.000000000 -0700 +++ linux-2570-605/net/ipv6/route.c 2003-06-05 11:42:30.000000000 -0700 @@ -1203,7 +1203,7 @@ int ipv6_route_ioctl(unsigned int cmd, v int ip6_pkt_discard(struct sk_buff *skb) { - IP6_INC_STATS(Ip6OutNoRoutes); + IP6_INC_STATS(__in6_dev_get(skb->dev), Ip6OutNoRoutes); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); kfree_skb(skb); return 0; - : send the line "unsubscribe linux-net" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html