aboutsummaryrefslogtreecommitdiff
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
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)
} else if (dst->neighbour)
return dst->neighbour->output(skb);
- IP6_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
kfree_skb(skb);
return -EINVAL;
@@ -118,6 +118,7 @@ static int ip6_output2(struct sk_buff *skb)
if (ipv6_addr_is_multicast(&skb->nh.ipv6h->daddr)) {
struct ipv6_pinfo* np = skb->sk ? inet6_sk(skb->sk) : NULL;
+ struct inet6_dev *idev = ip6_dst_idev(skb->dst);
if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) &&
ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr,
@@ -133,13 +134,13 @@ static int ip6_output2(struct sk_buff *skb)
ip6_dev_loopback_xmit);
if (skb->nh.ipv6h->hop_limit == 0) {
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
return 0;
}
}
- IP6_INC_STATS(IPSTATS_MIB_OUTMCASTPKTS);
+ IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);
}
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,
if (skb_headroom(skb) < head_room) {
struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room);
- kfree_skb(skb);
- skb = skb2;
- if (skb == NULL) {
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+ if (skb2 == NULL) {
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_OUTDISCARDS);
+ kfree_skb(skb);
return -ENOBUFS;
}
+ kfree_skb(skb);
+ skb = skb2;
if (sk)
skb_set_owner_w(skb, sk);
}
@@ -230,7 +233,8 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
mtu = dst_mtu(dst);
if ((skb->len <= mtu) || ipfragok || skb_is_gso(skb)) {
- IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_OUTREQUESTS);
return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev,
dst_output);
}
@@ -239,7 +243,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
kfree_skb(skb);
return -EMSGSIZE;
}
@@ -373,7 +377,7 @@ int ip6_forward(struct sk_buff *skb)
goto error;
if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
goto drop;
}
@@ -406,7 +410,7 @@ int ip6_forward(struct sk_buff *skb)
skb->dev = dst->dev;
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT,
0, skb->dev);
- IP6_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS);
kfree_skb(skb);
return -ETIMEDOUT;
@@ -419,13 +423,13 @@ int ip6_forward(struct sk_buff *skb)
if (proxied > 0)
return ip6_input(skb);
else if (proxied < 0) {
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
goto drop;
}
}
if (!xfrm6_route_forward(skb)) {
- IP6_INC_STATS(IPSTATS_MIB_INDISCARDS);
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_INDISCARDS);
goto drop;
}
dst = skb->dst;
@@ -464,14 +468,14 @@ 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_mtu(dst), skb->dev);
- IP6_INC_STATS_BH(IPSTATS_MIB_INTOOBIGERRORS);
- IP6_INC_STATS_BH(IPSTATS_MIB_FRAGFAILS);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INTOOBIGERRORS);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_FRAGFAILS);
kfree_skb(skb);
return -EMSGSIZE;
}
if (skb_cow(skb, dst->dev->hard_header_len)) {
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+ IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTDISCARDS);
goto drop;
}
@@ -481,11 +485,11 @@ int ip6_forward(struct sk_buff *skb)
hdr->hop_limit--;
- IP6_INC_STATS_BH(IPSTATS_MIB_OUTFORWDATAGRAMS);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS);
return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
error:
- IP6_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
+ IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS);
drop:
kfree_skb(skb);
return -EINVAL;
@@ -622,7 +626,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
tmp_hdr = kmalloc(hlen, GFP_ATOMIC);
if (!tmp_hdr) {
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS);
return -ENOMEM;
}
@@ -643,7 +647,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
skb->data_len = first_len - skb_headlen(skb);
skb->len = first_len;
skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
-
+
+ dst_hold(&rt->u.dst);
for (;;) {
/* Prepare header of the next frame,
@@ -667,7 +672,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
err = output(skb);
if(!err)
- IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGCREATES);
if (err || !frag)
break;
@@ -680,7 +685,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
kfree(tmp_hdr);
if (err == 0) {
- IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGOKS);
+ dst_release(&rt->u.dst);
return 0;
}
@@ -690,7 +696,8 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *))
frag = skb;
}
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+ IP6_INC_STATS(ip6_dst_idev(&rt->u.dst), IPSTATS_MIB_FRAGFAILS);
+ dst_release(&rt->u.dst);
return err;
}
@@ -723,7 +730,8 @@ slow_path:
if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
NETDEBUG(KERN_INFO "IPv6: frag: no memory for new fragment!\n");
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_FRAGFAILS);
err = -ENOMEM;
goto fail;
}
@@ -784,15 +792,17 @@ slow_path:
if (err)
goto fail;
- IP6_INC_STATS(IPSTATS_MIB_FRAGCREATES);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGCREATES);
}
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_FRAGOKS);
kfree_skb(skb);
- IP6_INC_STATS(IPSTATS_MIB_FRAGOKS);
return err;
fail:
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_FRAGFAILS);
kfree_skb(skb);
- IP6_INC_STATS(IPSTATS_MIB_FRAGFAILS);
return err;
}
@@ -1265,7 +1275,7 @@ alloc_new_skb:
return 0;
error:
inet->cork.length -= length;
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+ IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS);
return err;
}
@@ -1326,7 +1336,7 @@ int ip6_push_pending_frames(struct sock *sk)
skb->priority = sk->sk_priority;
skb->dst = dst_clone(&rt->u.dst);
- IP6_INC_STATS(IPSTATS_MIB_OUTREQUESTS);
+ IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS);
err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
if (err) {
if (err > 0)
@@ -1357,7 +1367,8 @@ void ip6_flush_pending_frames(struct sock *sk)
struct sk_buff *skb;
while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) {
- IP6_INC_STATS(IPSTATS_MIB_OUTDISCARDS);
+ IP6_INC_STATS(ip6_dst_idev(skb->dst),
+ IPSTATS_MIB_OUTDISCARDS);
kfree_skb(skb);
}