aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2006-11-04 06:11:37 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-03 00:22:08 -0500
commita11d206d0f88e092419877c7f706cafb5e1c2e57 (patch)
treeed96428bb52765198d5c5b7ccbc1f1b6516ffb3f /net/ipv6/ip6_output.c
parent7a3025b1b3a0173be5de6ced18754b909da27b38 (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.c71
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
487error: 491error:
488 IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS); 492 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
489drop: 493drop:
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
793fail: 802fail:
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;
1266error: 1276error:
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