aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/af_inet6.c5
-rw-r--r--net/ipv6/anycast.c80
-rw-r--r--net/ipv6/ip6_fib.c4
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c13
4 files changed, 92 insertions, 10 deletions
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 3f4d61017a69..f0cd291034f0 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -1001,6 +1001,9 @@ static int __init inet6_init(void)
1001 err = ip6_flowlabel_init(); 1001 err = ip6_flowlabel_init();
1002 if (err) 1002 if (err)
1003 goto ip6_flowlabel_fail; 1003 goto ip6_flowlabel_fail;
1004 err = ipv6_anycast_init();
1005 if (err)
1006 goto ipv6_anycast_fail;
1004 err = addrconf_init(); 1007 err = addrconf_init();
1005 if (err) 1008 if (err)
1006 goto addrconf_fail; 1009 goto addrconf_fail;
@@ -1091,6 +1094,8 @@ ipv6_frag_fail:
1091ipv6_exthdrs_fail: 1094ipv6_exthdrs_fail:
1092 addrconf_cleanup(); 1095 addrconf_cleanup();
1093addrconf_fail: 1096addrconf_fail:
1097 ipv6_anycast_cleanup();
1098ipv6_anycast_fail:
1094 ip6_flowlabel_cleanup(); 1099 ip6_flowlabel_cleanup();
1095ip6_flowlabel_fail: 1100ip6_flowlabel_fail:
1096 ndisc_late_cleanup(); 1101 ndisc_late_cleanup();
diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c
index 4e0ff7031edd..94999058e110 100644
--- a/net/ipv6/anycast.c
+++ b/net/ipv6/anycast.c
@@ -44,8 +44,22 @@
44 44
45#include <net/checksum.h> 45#include <net/checksum.h>
46 46
47#define IN6_ADDR_HSIZE_SHIFT 8
48#define IN6_ADDR_HSIZE BIT(IN6_ADDR_HSIZE_SHIFT)
49/* anycast address hash table
50 */
51static struct hlist_head inet6_acaddr_lst[IN6_ADDR_HSIZE];
52static DEFINE_SPINLOCK(acaddr_hash_lock);
53
47static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); 54static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr);
48 55
56static u32 inet6_acaddr_hash(struct net *net, const struct in6_addr *addr)
57{
58 u32 val = ipv6_addr_hash(addr) ^ net_hash_mix(net);
59
60 return hash_32(val, IN6_ADDR_HSIZE_SHIFT);
61}
62
49/* 63/*
50 * socket join an anycast group 64 * socket join an anycast group
51 */ 65 */
@@ -204,16 +218,39 @@ void ipv6_sock_ac_close(struct sock *sk)
204 rtnl_unlock(); 218 rtnl_unlock();
205} 219}
206 220
221static void ipv6_add_acaddr_hash(struct net *net, struct ifacaddr6 *aca)
222{
223 unsigned int hash = inet6_acaddr_hash(net, &aca->aca_addr);
224
225 spin_lock(&acaddr_hash_lock);
226 hlist_add_head_rcu(&aca->aca_addr_lst, &inet6_acaddr_lst[hash]);
227 spin_unlock(&acaddr_hash_lock);
228}
229
230static void ipv6_del_acaddr_hash(struct ifacaddr6 *aca)
231{
232 spin_lock(&acaddr_hash_lock);
233 hlist_del_init_rcu(&aca->aca_addr_lst);
234 spin_unlock(&acaddr_hash_lock);
235}
236
207static void aca_get(struct ifacaddr6 *aca) 237static void aca_get(struct ifacaddr6 *aca)
208{ 238{
209 refcount_inc(&aca->aca_refcnt); 239 refcount_inc(&aca->aca_refcnt);
210} 240}
211 241
242static void aca_free_rcu(struct rcu_head *h)
243{
244 struct ifacaddr6 *aca = container_of(h, struct ifacaddr6, rcu);
245
246 fib6_info_release(aca->aca_rt);
247 kfree(aca);
248}
249
212static void aca_put(struct ifacaddr6 *ac) 250static void aca_put(struct ifacaddr6 *ac)
213{ 251{
214 if (refcount_dec_and_test(&ac->aca_refcnt)) { 252 if (refcount_dec_and_test(&ac->aca_refcnt)) {
215 fib6_info_release(ac->aca_rt); 253 call_rcu(&ac->rcu, aca_free_rcu);
216 kfree(ac);
217 } 254 }
218} 255}
219 256
@@ -229,6 +266,7 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *f6i,
229 aca->aca_addr = *addr; 266 aca->aca_addr = *addr;
230 fib6_info_hold(f6i); 267 fib6_info_hold(f6i);
231 aca->aca_rt = f6i; 268 aca->aca_rt = f6i;
269 INIT_HLIST_NODE(&aca->aca_addr_lst);
232 aca->aca_users = 1; 270 aca->aca_users = 1;
233 /* aca_tstamp should be updated upon changes */ 271 /* aca_tstamp should be updated upon changes */
234 aca->aca_cstamp = aca->aca_tstamp = jiffies; 272 aca->aca_cstamp = aca->aca_tstamp = jiffies;
@@ -285,6 +323,8 @@ int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr)
285 aca_get(aca); 323 aca_get(aca);
286 write_unlock_bh(&idev->lock); 324 write_unlock_bh(&idev->lock);
287 325
326 ipv6_add_acaddr_hash(net, aca);
327
288 ip6_ins_rt(net, f6i); 328 ip6_ins_rt(net, f6i);
289 329
290 addrconf_join_solict(idev->dev, &aca->aca_addr); 330 addrconf_join_solict(idev->dev, &aca->aca_addr);
@@ -325,6 +365,7 @@ int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr)
325 else 365 else
326 idev->ac_list = aca->aca_next; 366 idev->ac_list = aca->aca_next;
327 write_unlock_bh(&idev->lock); 367 write_unlock_bh(&idev->lock);
368 ipv6_del_acaddr_hash(aca);
328 addrconf_leave_solict(idev, &aca->aca_addr); 369 addrconf_leave_solict(idev, &aca->aca_addr);
329 370
330 ip6_del_rt(dev_net(idev->dev), aca->aca_rt); 371 ip6_del_rt(dev_net(idev->dev), aca->aca_rt);
@@ -352,6 +393,8 @@ void ipv6_ac_destroy_dev(struct inet6_dev *idev)
352 idev->ac_list = aca->aca_next; 393 idev->ac_list = aca->aca_next;
353 write_unlock_bh(&idev->lock); 394 write_unlock_bh(&idev->lock);
354 395
396 ipv6_del_acaddr_hash(aca);
397
355 addrconf_leave_solict(idev, &aca->aca_addr); 398 addrconf_leave_solict(idev, &aca->aca_addr);
356 399
357 ip6_del_rt(dev_net(idev->dev), aca->aca_rt); 400 ip6_del_rt(dev_net(idev->dev), aca->aca_rt);
@@ -390,17 +433,25 @@ static bool ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *ad
390bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, 433bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev,
391 const struct in6_addr *addr) 434 const struct in6_addr *addr)
392{ 435{
436 unsigned int hash = inet6_acaddr_hash(net, addr);
437 struct net_device *nh_dev;
438 struct ifacaddr6 *aca;
393 bool found = false; 439 bool found = false;
394 440
395 rcu_read_lock(); 441 rcu_read_lock();
396 if (dev) 442 if (dev)
397 found = ipv6_chk_acast_dev(dev, addr); 443 found = ipv6_chk_acast_dev(dev, addr);
398 else 444 else
399 for_each_netdev_rcu(net, dev) 445 hlist_for_each_entry_rcu(aca, &inet6_acaddr_lst[hash],
400 if (ipv6_chk_acast_dev(dev, addr)) { 446 aca_addr_lst) {
447 nh_dev = fib6_info_nh_dev(aca->aca_rt);
448 if (!nh_dev || !net_eq(dev_net(nh_dev), net))
449 continue;
450 if (ipv6_addr_equal(&aca->aca_addr, addr)) {
401 found = true; 451 found = true;
402 break; 452 break;
403 } 453 }
454 }
404 rcu_read_unlock(); 455 rcu_read_unlock();
405 return found; 456 return found;
406} 457}
@@ -540,3 +591,24 @@ void ac6_proc_exit(struct net *net)
540 remove_proc_entry("anycast6", net->proc_net); 591 remove_proc_entry("anycast6", net->proc_net);
541} 592}
542#endif 593#endif
594
595/* Init / cleanup code
596 */
597int __init ipv6_anycast_init(void)
598{
599 int i;
600
601 for (i = 0; i < IN6_ADDR_HSIZE; i++)
602 INIT_HLIST_HEAD(&inet6_acaddr_lst[i]);
603 return 0;
604}
605
606void ipv6_anycast_cleanup(void)
607{
608 int i;
609
610 spin_lock(&acaddr_hash_lock);
611 for (i = 0; i < IN6_ADDR_HSIZE; i++)
612 WARN_ON(!hlist_empty(&inet6_acaddr_lst[i]));
613 spin_unlock(&acaddr_hash_lock);
614}
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 1b8bc008b53b..ae3786132c23 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -591,7 +591,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
591 591
592 /* fib entries are never clones */ 592 /* fib entries are never clones */
593 if (arg.filter.flags & RTM_F_CLONED) 593 if (arg.filter.flags & RTM_F_CLONED)
594 return skb->len; 594 goto out;
595 595
596 w = (void *)cb->args[2]; 596 w = (void *)cb->args[2];
597 if (!w) { 597 if (!w) {
@@ -621,7 +621,7 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb)
621 tb = fib6_get_table(net, arg.filter.table_id); 621 tb = fib6_get_table(net, arg.filter.table_id);
622 if (!tb) { 622 if (!tb) {
623 if (arg.filter.dump_all_families) 623 if (arg.filter.dump_all_families)
624 return skb->len; 624 goto out;
625 625
626 NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist"); 626 NL_SET_ERR_MSG_MOD(cb->extack, "FIB table does not exist");
627 return -ENOENT; 627 return -ENOENT;
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index b8ac369f98ad..d219979c3e52 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -587,11 +587,16 @@ int nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 user)
587 */ 587 */
588 ret = -EINPROGRESS; 588 ret = -EINPROGRESS;
589 if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && 589 if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
590 fq->q.meat == fq->q.len && 590 fq->q.meat == fq->q.len) {
591 nf_ct_frag6_reasm(fq, skb, dev)) 591 unsigned long orefdst = skb->_skb_refdst;
592 ret = 0; 592
593 else 593 skb->_skb_refdst = 0UL;
594 if (nf_ct_frag6_reasm(fq, skb, dev))
595 ret = 0;
596 skb->_skb_refdst = orefdst;
597 } else {
594 skb_dst_drop(skb); 598 skb_dst_drop(skb);
599 }
595 600
596out_unlock: 601out_unlock:
597 spin_unlock_bh(&fq->q.lock); 602 spin_unlock_bh(&fq->q.lock);