diff options
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/esp6_offload.c | 8 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 4 | ||||
-rw-r--r-- | net/ipv6/ip6_flowlabel.c | 22 | ||||
-rw-r--r-- | net/ipv6/route.c | 70 | ||||
-rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 6 |
5 files changed, 62 insertions, 48 deletions
diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c index bff83279d76f..d453cf417b03 100644 --- a/net/ipv6/esp6_offload.c +++ b/net/ipv6/esp6_offload.c | |||
@@ -74,13 +74,13 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head, | |||
74 | goto out; | 74 | goto out; |
75 | 75 | ||
76 | if (sp->len == XFRM_MAX_DEPTH) | 76 | if (sp->len == XFRM_MAX_DEPTH) |
77 | goto out; | 77 | goto out_reset; |
78 | 78 | ||
79 | x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, | 79 | x = xfrm_state_lookup(dev_net(skb->dev), skb->mark, |
80 | (xfrm_address_t *)&ipv6_hdr(skb)->daddr, | 80 | (xfrm_address_t *)&ipv6_hdr(skb)->daddr, |
81 | spi, IPPROTO_ESP, AF_INET6); | 81 | spi, IPPROTO_ESP, AF_INET6); |
82 | if (!x) | 82 | if (!x) |
83 | goto out; | 83 | goto out_reset; |
84 | 84 | ||
85 | sp->xvec[sp->len++] = x; | 85 | sp->xvec[sp->len++] = x; |
86 | sp->olen++; | 86 | sp->olen++; |
@@ -88,7 +88,7 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head, | |||
88 | xo = xfrm_offload(skb); | 88 | xo = xfrm_offload(skb); |
89 | if (!xo) { | 89 | if (!xo) { |
90 | xfrm_state_put(x); | 90 | xfrm_state_put(x); |
91 | goto out; | 91 | goto out_reset; |
92 | } | 92 | } |
93 | } | 93 | } |
94 | 94 | ||
@@ -109,6 +109,8 @@ static struct sk_buff *esp6_gro_receive(struct list_head *head, | |||
109 | xfrm_input(skb, IPPROTO_ESP, spi, -2); | 109 | xfrm_input(skb, IPPROTO_ESP, spi, -2); |
110 | 110 | ||
111 | return ERR_PTR(-EINPROGRESS); | 111 | return ERR_PTR(-EINPROGRESS); |
112 | out_reset: | ||
113 | secpath_reset(skb); | ||
112 | out: | 114 | out: |
113 | skb_push(skb, offset); | 115 | skb_push(skb, offset); |
114 | NAPI_GRO_CB(skb)->same_flow = 0; | 116 | NAPI_GRO_CB(skb)->same_flow = 0; |
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index a8919c217cc2..08e0390e001c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c | |||
@@ -916,9 +916,7 @@ static void fib6_drop_pcpu_from(struct fib6_info *f6i, | |||
916 | if (pcpu_rt) { | 916 | if (pcpu_rt) { |
917 | struct fib6_info *from; | 917 | struct fib6_info *from; |
918 | 918 | ||
919 | from = rcu_dereference_protected(pcpu_rt->from, | 919 | from = xchg((__force struct fib6_info **)&pcpu_rt->from, NULL); |
920 | lockdep_is_held(&table->tb6_lock)); | ||
921 | rcu_assign_pointer(pcpu_rt->from, NULL); | ||
922 | fib6_info_release(from); | 920 | fib6_info_release(from); |
923 | } | 921 | } |
924 | } | 922 | } |
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index cb54a8a3c273..be5f3d7ceb96 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c | |||
@@ -94,15 +94,21 @@ static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) | |||
94 | return fl; | 94 | return fl; |
95 | } | 95 | } |
96 | 96 | ||
97 | static void fl_free_rcu(struct rcu_head *head) | ||
98 | { | ||
99 | struct ip6_flowlabel *fl = container_of(head, struct ip6_flowlabel, rcu); | ||
100 | |||
101 | if (fl->share == IPV6_FL_S_PROCESS) | ||
102 | put_pid(fl->owner.pid); | ||
103 | kfree(fl->opt); | ||
104 | kfree(fl); | ||
105 | } | ||
106 | |||
97 | 107 | ||
98 | static void fl_free(struct ip6_flowlabel *fl) | 108 | static void fl_free(struct ip6_flowlabel *fl) |
99 | { | 109 | { |
100 | if (fl) { | 110 | if (fl) |
101 | if (fl->share == IPV6_FL_S_PROCESS) | 111 | call_rcu(&fl->rcu, fl_free_rcu); |
102 | put_pid(fl->owner.pid); | ||
103 | kfree(fl->opt); | ||
104 | kfree_rcu(fl, rcu); | ||
105 | } | ||
106 | } | 112 | } |
107 | 113 | ||
108 | static void fl_release(struct ip6_flowlabel *fl) | 114 | static void fl_release(struct ip6_flowlabel *fl) |
@@ -633,9 +639,9 @@ recheck: | |||
633 | if (fl1->share == IPV6_FL_S_EXCL || | 639 | if (fl1->share == IPV6_FL_S_EXCL || |
634 | fl1->share != fl->share || | 640 | fl1->share != fl->share || |
635 | ((fl1->share == IPV6_FL_S_PROCESS) && | 641 | ((fl1->share == IPV6_FL_S_PROCESS) && |
636 | (fl1->owner.pid == fl->owner.pid)) || | 642 | (fl1->owner.pid != fl->owner.pid)) || |
637 | ((fl1->share == IPV6_FL_S_USER) && | 643 | ((fl1->share == IPV6_FL_S_USER) && |
638 | uid_eq(fl1->owner.uid, fl->owner.uid))) | 644 | !uid_eq(fl1->owner.uid, fl->owner.uid))) |
639 | goto release; | 645 | goto release; |
640 | 646 | ||
641 | err = -ENOMEM; | 647 | err = -ENOMEM; |
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 | ||
390 | static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, | 387 | static 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 | ||
3532 | out: | 3521 | out: |
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 | ||
3773 | static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) | 3762 | static 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) { |
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index bc65db782bfb..d9e5f6808811 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -345,7 +345,7 @@ static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | |||
345 | unsigned int i; | 345 | unsigned int i; |
346 | 346 | ||
347 | xfrm_flush_gc(); | 347 | xfrm_flush_gc(); |
348 | xfrm_state_flush(net, IPSEC_PROTO_ANY, false, true); | 348 | xfrm_state_flush(net, 0, false, true); |
349 | 349 | ||
350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | 350 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) |
351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); | 351 | WARN_ON_ONCE(!hlist_empty(&xfrm6_tn->spi_byaddr[i])); |
@@ -402,6 +402,10 @@ static void __exit xfrm6_tunnel_fini(void) | |||
402 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 402 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
403 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 403 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
404 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); | 404 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
405 | /* Someone maybe has gotten the xfrm6_tunnel_spi. | ||
406 | * So need to wait it. | ||
407 | */ | ||
408 | rcu_barrier(); | ||
405 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | 409 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); |
406 | } | 410 | } |
407 | 411 | ||