[PATCH/RFC] add ipv6 statistics per interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux