Skip to content

Commit

Permalink
ipv6: some RCU conversions
Browse files Browse the repository at this point in the history
ICMP and ND are not fast path, but still we can avoid changing idev
refcount, using RCU.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Aug 1, 2011
1 parent ab1594e commit cfdf764
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 35 deletions.
25 changes: 10 additions & 15 deletions net/ipv6/icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,8 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
goto out_dst_release;
}

idev = in6_dev_get(skb->dev);
rcu_read_lock();
idev = __in6_dev_get(skb->dev);

err = ip6_append_data(sk, icmpv6_getfrag, &msg,
len + sizeof(struct icmp6hdr),
Expand All @@ -500,19 +501,16 @@ void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info)
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
goto out_put;
} else {
err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
len + sizeof(struct icmp6hdr));
}
err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, len + sizeof(struct icmp6hdr));

out_put:
if (likely(idev != NULL))
in6_dev_put(idev);
rcu_read_unlock();
out_dst_release:
dst_release(dst);
out:
icmpv6_xmit_unlock(sk);
}

EXPORT_SYMBOL(icmpv6_send);

static void icmpv6_echo_reply(struct sk_buff *skb)
Expand Down Expand Up @@ -569,7 +567,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (hlimit < 0)
hlimit = ip6_dst_hoplimit(dst);

idev = in6_dev_get(skb->dev);
idev = __in6_dev_get(skb->dev);

msg.skb = skb;
msg.offset = 0;
Expand All @@ -583,13 +581,10 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
if (err) {
ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_OUTERRORS);
ip6_flush_pending_frames(sk);
goto out_put;
} else {
err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr,
skb->len + sizeof(struct icmp6hdr));
}
err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, skb->len + sizeof(struct icmp6hdr));

out_put:
if (likely(idev != NULL))
in6_dev_put(idev);
dst_release(dst);
out:
icmpv6_xmit_unlock(sk);
Expand Down
31 changes: 11 additions & 20 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,8 @@ void ndisc_send_skb(struct sk_buff *skb,

skb_dst_set(skb, dst);

idev = in6_dev_get(dst->dev);
rcu_read_lock();
idev = __in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);

err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, skb, NULL, dst->dev,
Expand All @@ -543,8 +544,7 @@ void ndisc_send_skb(struct sk_buff *skb,
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
}

if (likely(idev != NULL))
in6_dev_put(idev);
rcu_read_unlock();
}

EXPORT_SYMBOL(ndisc_send_skb);
Expand Down Expand Up @@ -1039,7 +1039,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
if (skb->len < sizeof(*rs_msg))
return;

idev = in6_dev_get(skb->dev);
idev = __in6_dev_get(skb->dev);
if (!idev) {
if (net_ratelimit())
ND_PRINTK1("ICMP6 RS: can't find in6 device\n");
Expand Down Expand Up @@ -1080,7 +1080,7 @@ static void ndisc_recv_rs(struct sk_buff *skb)
neigh_release(neigh);
}
out:
in6_dev_put(idev);
return;
}

static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
Expand Down Expand Up @@ -1179,7 +1179,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
* set the RA_RECV flag in the interface
*/

in6_dev = in6_dev_get(skb->dev);
in6_dev = __in6_dev_get(skb->dev);
if (in6_dev == NULL) {
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: can't find inet6 device for %s.\n",
Expand All @@ -1188,7 +1188,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
}

if (!ndisc_parse_options(opt, optlen, &ndopts)) {
in6_dev_put(in6_dev);
ND_PRINTK2(KERN_WARNING
"ICMP6 RA: invalid ND options\n");
return;
Expand Down Expand Up @@ -1255,7 +1254,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
ND_PRINTK0(KERN_ERR
"ICMPv6 RA: %s() failed to add default route.\n",
__func__);
in6_dev_put(in6_dev);
return;
}

Expand All @@ -1265,7 +1263,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
"ICMPv6 RA: %s() got default router without neighbour.\n",
__func__);
dst_release(&rt->dst);
in6_dev_put(in6_dev);
return;
}
neigh->flags |= NTF_ROUTER;
Expand Down Expand Up @@ -1422,7 +1419,6 @@ static void ndisc_router_discovery(struct sk_buff *skb)
dst_release(&rt->dst);
else if (neigh)
neigh_release(neigh);
in6_dev_put(in6_dev);
}

static void ndisc_redirect_rcv(struct sk_buff *skb)
Expand Down Expand Up @@ -1481,13 +1477,11 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
return;
}

in6_dev = in6_dev_get(skb->dev);
in6_dev = __in6_dev_get(skb->dev);
if (!in6_dev)
return;
if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {
in6_dev_put(in6_dev);
if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects)
return;
}

/* RFC2461 8.1:
* The IP source address of the Redirect MUST be the same as the current
Expand All @@ -1497,7 +1491,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
if (!ndisc_parse_options((u8*)(dest + 1), optlen, &ndopts)) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: invalid ND options\n");
in6_dev_put(in6_dev);
return;
}
if (ndopts.nd_opts_tgt_lladdr) {
Expand All @@ -1506,7 +1499,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
if (!lladdr) {
ND_PRINTK2(KERN_WARNING
"ICMPv6 Redirect: invalid link-layer address length\n");
in6_dev_put(in6_dev);
return;
}
}
Expand All @@ -1518,7 +1510,6 @@ static void ndisc_redirect_rcv(struct sk_buff *skb)
on_link);
neigh_release(neigh);
}
in6_dev_put(in6_dev);
}

void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
Expand Down Expand Up @@ -1651,7 +1642,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
csum_partial(icmph, len, 0));

skb_dst_set(buff, dst);
idev = in6_dev_get(dst->dev);
rcu_read_lock();
idev = __in6_dev_get(dst->dev);
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, buff, NULL, dst->dev,
dst_output);
Expand All @@ -1660,8 +1652,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
}

if (likely(idev != NULL))
in6_dev_put(idev);
rcu_read_unlock();
return;

release:
Expand Down

0 comments on commit cfdf764

Please sign in to comment.