aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c70
1 files changed, 37 insertions, 33 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index b18e85cd7587..23a20d62daac 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -380,11 +380,8 @@ static void ip6_dst_destroy(struct dst_entry *dst)
380 in6_dev_put(idev); 380 in6_dev_put(idev);
381 } 381 }
382 382
383 rcu_read_lock(); 383 from = xchg((__force struct fib6_info **)&rt->from, NULL);
384 from = rcu_dereference(rt->from);
385 rcu_assign_pointer(rt->from, NULL);
386 fib6_info_release(from); 384 fib6_info_release(from);
387 rcu_read_unlock();
388} 385}
389 386
390static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 387static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
@@ -1323,9 +1320,7 @@ static void rt6_remove_exception(struct rt6_exception_bucket *bucket,
1323 /* purge completely the exception to allow releasing the held resources: 1320 /* purge completely the exception to allow releasing the held resources:
1324 * some [sk] cache may keep the dst around for unlimited time 1321 * some [sk] cache may keep the dst around for unlimited time
1325 */ 1322 */
1326 from = rcu_dereference_protected(rt6_ex->rt6i->from, 1323 from = xchg((__force struct fib6_info **)&rt6_ex->rt6i->from, NULL);
1327 lockdep_is_held(&rt6_exception_lock));
1328 rcu_assign_pointer(rt6_ex->rt6i->from, NULL);
1329 fib6_info_release(from); 1324 fib6_info_release(from);
1330 dst_dev_put(&rt6_ex->rt6i->dst); 1325 dst_dev_put(&rt6_ex->rt6i->dst);
1331 1326
@@ -3495,11 +3490,8 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3495 3490
3496 rcu_read_lock(); 3491 rcu_read_lock();
3497 res.f6i = rcu_dereference(rt->from); 3492 res.f6i = rcu_dereference(rt->from);
3498 /* This fib6_info_hold() is safe here because we hold reference to rt 3493 if (!res.f6i)
3499 * and rt already holds reference to fib6_info. 3494 goto out;
3500 */
3501 fib6_info_hold(res.f6i);
3502 rcu_read_unlock();
3503 3495
3504 res.nh = &res.f6i->fib6_nh; 3496 res.nh = &res.f6i->fib6_nh;
3505 res.fib6_flags = res.f6i->fib6_flags; 3497 res.fib6_flags = res.f6i->fib6_flags;
@@ -3514,10 +3506,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3514 3506
3515 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; 3507 nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key;
3516 3508
3517 /* No need to remove rt from the exception table if rt is 3509 /* rt6_insert_exception() will take care of duplicated exceptions */
3518 * a cached route because rt6_insert_exception() will
3519 * takes care of it
3520 */
3521 if (rt6_insert_exception(nrt, &res)) { 3510 if (rt6_insert_exception(nrt, &res)) {
3522 dst_release_immediate(&nrt->dst); 3511 dst_release_immediate(&nrt->dst);
3523 goto out; 3512 goto out;
@@ -3530,7 +3519,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
3530 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); 3519 call_netevent_notifiers(NETEVENT_REDIRECT, &netevent);
3531 3520
3532out: 3521out:
3533 fib6_info_release(res.f6i); 3522 rcu_read_unlock();
3534 neigh_release(neigh); 3523 neigh_release(neigh);
3535} 3524}
3536 3525
@@ -3772,23 +3761,34 @@ int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg)
3772 3761
3773static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) 3762static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
3774{ 3763{
3775 int type;
3776 struct dst_entry *dst = skb_dst(skb); 3764 struct dst_entry *dst = skb_dst(skb);
3765 struct net *net = dev_net(dst->dev);
3766 struct inet6_dev *idev;
3767 int type;
3768
3769 if (netif_is_l3_master(skb->dev) &&
3770 dst->dev == net->loopback_dev)
3771 idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
3772 else
3773 idev = ip6_dst_idev(dst);
3774
3777 switch (ipstats_mib_noroutes) { 3775 switch (ipstats_mib_noroutes) {
3778 case IPSTATS_MIB_INNOROUTES: 3776 case IPSTATS_MIB_INNOROUTES:
3779 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); 3777 type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
3780 if (type == IPV6_ADDR_ANY) { 3778 if (type == IPV6_ADDR_ANY) {
3781 IP6_INC_STATS(dev_net(dst->dev), 3779 IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
3782 __in6_dev_get_safely(skb->dev),
3783 IPSTATS_MIB_INADDRERRORS);
3784 break; 3780 break;
3785 } 3781 }
3786 /* FALLTHROUGH */ 3782 /* FALLTHROUGH */
3787 case IPSTATS_MIB_OUTNOROUTES: 3783 case IPSTATS_MIB_OUTNOROUTES:
3788 IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), 3784 IP6_INC_STATS(net, idev, ipstats_mib_noroutes);
3789 ipstats_mib_noroutes);
3790 break; 3785 break;
3791 } 3786 }
3787
3788 /* Start over by dropping the dst for l3mdev case */
3789 if (netif_is_l3_master(skb->dev))
3790 skb_dst_drop(skb);
3791
3792 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); 3792 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
3793 kfree_skb(skb); 3793 kfree_skb(skb);
3794 return 0; 3794 return 0;
@@ -5056,16 +5056,20 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
5056 5056
5057 rcu_read_lock(); 5057 rcu_read_lock();
5058 from = rcu_dereference(rt->from); 5058 from = rcu_dereference(rt->from);
5059 5059 if (from) {
5060 if (fibmatch) 5060 if (fibmatch)
5061 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL, iif, 5061 err = rt6_fill_node(net, skb, from, NULL, NULL, NULL,
5062 RTM_NEWROUTE, NETLINK_CB(in_skb).portid, 5062 iif, RTM_NEWROUTE,
5063 nlh->nlmsg_seq, 0); 5063 NETLINK_CB(in_skb).portid,
5064 else 5064 nlh->nlmsg_seq, 0);
5065 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr, 5065 else
5066 &fl6.saddr, iif, RTM_NEWROUTE, 5066 err = rt6_fill_node(net, skb, from, dst, &fl6.daddr,
5067 NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, 5067 &fl6.saddr, iif, RTM_NEWROUTE,
5068 0); 5068 NETLINK_CB(in_skb).portid,
5069 nlh->nlmsg_seq, 0);
5070 } else {
5071 err = -ENETUNREACH;
5072 }
5069 rcu_read_unlock(); 5073 rcu_read_unlock();
5070 5074
5071 if (err < 0) { 5075 if (err < 0) {