diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-11-04 06:11:37 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-03 00:22:08 -0500 |
commit | a11d206d0f88e092419877c7f706cafb5e1c2e57 (patch) | |
tree | ed96428bb52765198d5c5b7ccbc1f1b6516ffb3f /net/ipv6/ip6_output.c | |
parent | 7a3025b1b3a0173be5de6ced18754b909da27b38 (diff) |
[IPV6]: Per-interface statistics support.
For IP MIB (RFC4293).
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 71 |
1 files changed, 41 insertions, 30 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 1bde3aca3466..85f889270492 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
@@ -88,7 +88,7 @@ static inline int ip6_output_finish(struct sk_buff *skb) | |||
88 | } else if (dst->neighbour) | 88 | } else if (dst->neighbour) |
89 | return dst->neighbour->output(skb); | 89 | return dst->neighbour->output(skb); |
90 | 90 | ||
91 | IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); | 91 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); |
92 | kfree_skb(skb); | 92 | kfree_skb(skb); |
93 | return -EINVAL; | 93 | return -EINVAL; |
94 | 94 | ||
@@ -118,6 +118,7 @@ static int ip6_output2(struct sk_buff *skb) | |||
118 | 118 | ||
119 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) { | 119 | if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) { |
120 | struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; | 120 | struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL; |
121 | struct inet6_dev *idev = ip6_dst_idev(skb->dst); | ||
121 | 122 | ||
122 | if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && | 123 | if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && |
123 | ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, | 124 | ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr, |
@@ -133,13 +134,13 @@ static int ip6_output2(struct sk_buff *skb) | |||
133 | ip6_dev_loopback_xmit); | 134 | ip6_dev_loopback_xmit); |
134 | 135 | ||
135 | if (skb->nh.ipv6h->hop_limit == 0) { | 136 | if (skb->nh.ipv6h->hop_limit == 0) { |
136 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 137 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS); |
137 | kfree_skb(skb); | 138 | kfree_skb(skb); |
138 | return 0; | 139 | return 0; |
139 | } | 140 | } |
140 | } | 141 | } |
141 | 142 | ||
142 | IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS); | 143 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS); |
143 | } | 144 | } |
144 | 145 | ||
145 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); | 146 | return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish); |
@@ -182,12 +183,14 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
182 | 183 | ||
183 | if (skb_headroom(skb) < head_room) { | 184 | if (skb_headroom(skb) < head_room) { |
184 | struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); | 185 | struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); |
185 | kfree_skb(skb); | 186 | if (skb2 == NULL) { |
186 | skb = skb2; | 187 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
187 | if (skb == NULL) { | 188 | IPSTATS_MIB_OUTDISCARDS); |
188 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 189 | kfree_skb(skb); |
189 | return -ENOBUFS; | 190 | return -ENOBUFS; |
190 | } | 191 | } |
192 | kfree_skb(skb); | ||
193 | skb = skb2; | ||
191 | if (sk) | 194 | if (sk) |
192 | skb_set_owner_w(skb, sk); | 195 | skb_set_owner_w(skb, sk); |
193 | } | 196 | } |
@@ -230,7 +233,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
230 | 233 | ||
231 | mtu = dst_mtu(dst); | 234 | mtu = dst_mtu(dst); |
232 | if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { | 235 | if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) { |
233 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 236 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
237 | IPSTATS_MIB_OUTREQUESTS); | ||
234 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, | 238 | return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, |
235 | dst_output); | 239 | dst_output); |
236 | } | 240 | } |
@@ -239,7 +243,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, | |||
239 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); | 243 | printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); |
240 | skb->dev = dst->dev; | 244 | skb->dev = dst->dev; |
241 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); | 245 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); |
242 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 246 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); |
243 | kfree_skb(skb); | 247 | kfree_skb(skb); |
244 | return -EMSGSIZE; | 248 | return -EMSGSIZE; |
245 | } | 249 | } |
@@ -373,7 +377,7 @@ int ip6_forward(struct sk_buff *skb) | |||
373 | goto error; | 377 | goto error; |
374 | 378 | ||
375 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { | 379 | if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { |
376 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 380 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
377 | goto drop; | 381 | goto drop; |
378 | } | 382 | } |
379 | 383 | ||
@@ -406,7 +410,7 @@ int ip6_forward(struct sk_buff *skb) | |||
406 | skb->dev = dst->dev; | 410 | skb->dev = dst->dev; |
407 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, | 411 | icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, |
408 | 0, skb->dev); | 412 | 0, skb->dev); |
409 | IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); | 413 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); |
410 | 414 | ||
411 | kfree_skb(skb); | 415 | kfree_skb(skb); |
412 | return -ETIMEDOUT; | 416 | return -ETIMEDOUT; |
@@ -419,13 +423,13 @@ int ip6_forward(struct sk_buff *skb) | |||
419 | if (proxied > 0) | 423 | if (proxied > 0) |
420 | return ip6_input(skb); | 424 | return ip6_input(skb); |
421 | else if (proxied < 0) { | 425 | else if (proxied < 0) { |
422 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 426 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
423 | goto drop; | 427 | goto drop; |
424 | } | 428 | } |
425 | } | 429 | } |
426 | 430 | ||
427 | if (!xfrm6_route_forward(skb)) { | 431 | if (!xfrm6_route_forward(skb)) { |
428 | IP6_INC_STATS(IPSTATS_MIB_INDISCARDS); | 432 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS); |
429 | goto drop; | 433 | goto drop; |
430 | } | 434 | } |
431 | dst = skb->dst; | 435 | dst = skb->dst; |
@@ -464,14 +468,14 @@ int ip6_forward(struct sk_buff *skb) | |||
464 | /* Again, force OUTPUT device used as source address */ | 468 | /* Again, force OUTPUT device used as source address */ |
465 | skb->dev = dst->dev; | 469 | skb->dev = dst->dev; |
466 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); | 470 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, dst_mtu(dst), skb->dev); |
467 | IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS); | 471 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS); |
468 | IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS); | 472 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS); |
469 | kfree_skb(skb); | 473 | kfree_skb(skb); |
470 | return -EMSGSIZE; | 474 | return -EMSGSIZE; |
471 | } | 475 | } |
472 | 476 | ||
473 | if (skb_cow(skb, dst->dev->hard_header_len)) { | 477 | if (skb_cow(skb, dst->dev->hard_header_len)) { |
474 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 478 | IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS); |
475 | goto drop; | 479 | goto drop; |
476 | } | 480 | } |
477 | 481 | ||
@@ -481,11 +485,11 @@ int ip6_forward(struct sk_buff *skb) | |||
481 | 485 | ||
482 | hdr->hop_limit--; | 486 | hdr->hop_limit--; |
483 | 487 | ||
484 | IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS); | 488 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); |
485 | return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); | 489 | return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish); |
486 | 490 | ||
487 | error: | 491 | error: |
488 | IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); | 492 | IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS); |
489 | drop: | 493 | drop: |
490 | kfree_skb(skb); | 494 | kfree_skb(skb); |
491 | return -EINVAL; | 495 | return -EINVAL; |
@@ -622,7 +626,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
622 | 626 | ||
623 | tmp_hdr = kmalloc(hlen, GFP_ATOMIC); | 627 | tmp_hdr = kmalloc(hlen, GFP_ATOMIC); |
624 | if (!tmp_hdr) { | 628 | if (!tmp_hdr) { |
625 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 629 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); |
626 | return -ENOMEM; | 630 | return -ENOMEM; |
627 | } | 631 | } |
628 | 632 | ||
@@ -643,7 +647,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
643 | skb->data_len = first_len - skb_headlen(skb); | 647 | skb->data_len = first_len - skb_headlen(skb); |
644 | skb->len = first_len; | 648 | skb->len = first_len; |
645 | skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); | 649 | skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr)); |
646 | 650 | ||
651 | dst_hold(&rt->u.dst); | ||
647 | 652 | ||
648 | for (;;) { | 653 | for (;;) { |
649 | /* Prepare header of the next frame, | 654 | /* Prepare header of the next frame, |
@@ -667,7 +672,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
667 | 672 | ||
668 | err = output(skb); | 673 | err = output(skb); |
669 | if(!err) | 674 | if(!err) |
670 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | 675 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES); |
671 | 676 | ||
672 | if (err || !frag) | 677 | if (err || !frag) |
673 | break; | 678 | break; |
@@ -680,7 +685,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
680 | kfree(tmp_hdr); | 685 | kfree(tmp_hdr); |
681 | 686 | ||
682 | if (err == 0) { | 687 | if (err == 0) { |
683 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | 688 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS); |
689 | dst_release(&rt->u.dst); | ||
684 | return 0; | 690 | return 0; |
685 | } | 691 | } |
686 | 692 | ||
@@ -690,7 +696,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | |||
690 | frag = skb; | 696 | frag = skb; |
691 | } | 697 | } |
692 | 698 | ||
693 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 699 | IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS); |
700 | dst_release(&rt->u.dst); | ||
694 | return err; | 701 | return err; |
695 | } | 702 | } |
696 | 703 | ||
@@ -723,7 +730,8 @@ slow_path: | |||
723 | 730 | ||
724 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { | 731 | if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) { |
725 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); | 732 | NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n"); |
726 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | 733 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
734 | IPSTATS_MIB_FRAGFAILS); | ||
727 | err = -ENOMEM; | 735 | err = -ENOMEM; |
728 | goto fail; | 736 | goto fail; |
729 | } | 737 | } |
@@ -784,15 +792,17 @@ slow_path: | |||
784 | if (err) | 792 | if (err) |
785 | goto fail; | 793 | goto fail; |
786 | 794 | ||
787 | IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES); | 795 | IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES); |
788 | } | 796 | } |
797 | IP6_INC_STATS(ip6_dst_idev(skb->dst), | ||
798 | IPSTATS_MIB_FRAGOKS); | ||
789 | kfree_skb(skb); | 799 | kfree_skb(skb); |
790 | IP6_INC_STATS(IPSTATS_MIB_FRAGOKS); | ||
791 | return err; | 800 | return err; |
792 | 801 | ||
793 | fail: | 802 | fail: |
803 | IP6_INC_STATS(ip6_dst_idev(skb->dst), | ||
804 | IPSTATS_MIB_FRAGFAILS); | ||
794 | kfree_skb(skb); | 805 | kfree_skb(skb); |
795 | IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS); | ||
796 | return err; | 806 | return err; |
797 | } | 807 | } |
798 | 808 | ||
@@ -1265,7 +1275,7 @@ alloc_new_skb: | |||
1265 | return 0; | 1275 | return 0; |
1266 | error: | 1276 | error: |
1267 | inet->cork.length -= length; | 1277 | inet->cork.length -= length; |
1268 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1278 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); |
1269 | return err; | 1279 | return err; |
1270 | } | 1280 | } |
1271 | 1281 | ||
@@ -1326,7 +1336,7 @@ int ip6_push_pending_frames(struct sock *sk) | |||
1326 | skb->priority = sk->sk_priority; | 1336 | skb->priority = sk->sk_priority; |
1327 | 1337 | ||
1328 | skb->dst = dst_clone(&rt->u.dst); | 1338 | skb->dst = dst_clone(&rt->u.dst); |
1329 | IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 1339 | IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); |
1330 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); | 1340 | err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output); |
1331 | if (err) { | 1341 | if (err) { |
1332 | if (err > 0) | 1342 | if (err > 0) |
@@ -1357,7 +1367,8 @@ void ip6_flush_pending_frames(struct sock *sk) | |||
1357 | struct sk_buff *skb; | 1367 | struct sk_buff *skb; |
1358 | 1368 | ||
1359 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { | 1369 | while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) { |
1360 | IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS); | 1370 | IP6_INC_STATS(ip6_dst_idev(skb->dst), |
1371 | IPSTATS_MIB_OUTDISCARDS); | ||
1361 | kfree_skb(skb); | 1372 | kfree_skb(skb); |
1362 | } | 1373 | } |
1363 | 1374 | ||