44
44
45
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
+ */
51
+ static struct hlist_head inet6_acaddr_lst [IN6_ADDR_HSIZE ];
52
+ static DEFINE_SPINLOCK (acaddr_hash_lock );
53
+
47
54
static int ipv6_dev_ac_dec (struct net_device * dev , const struct in6_addr * addr );
48
55
56
+ static 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
64
* socket join an anycast group
51
65
*/
@@ -204,16 +218,39 @@ void ipv6_sock_ac_close(struct sock *sk)
204
218
rtnl_unlock ();
205
219
}
206
220
221
+ static 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
+
230
+ static 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
+
207
237
static void aca_get (struct ifacaddr6 * aca )
208
238
{
209
239
refcount_inc (& aca -> aca_refcnt );
210
240
}
211
241
242
+ static 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
+
212
250
static void aca_put (struct ifacaddr6 * ac )
213
251
{
214
252
if (refcount_dec_and_test (& ac -> aca_refcnt )) {
215
- fib6_info_release (ac -> aca_rt );
216
- kfree (ac );
253
+ call_rcu (& ac -> rcu , aca_free_rcu );
217
254
}
218
255
}
219
256
@@ -229,6 +266,7 @@ static struct ifacaddr6 *aca_alloc(struct fib6_info *f6i,
229
266
aca -> aca_addr = * addr ;
230
267
fib6_info_hold (f6i );
231
268
aca -> aca_rt = f6i ;
269
+ INIT_HLIST_NODE (& aca -> aca_addr_lst );
232
270
aca -> aca_users = 1 ;
233
271
/* aca_tstamp should be updated upon changes */
234
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
323
aca_get (aca );
286
324
write_unlock_bh (& idev -> lock );
287
325
326
+ ipv6_add_acaddr_hash (net , aca );
327
+
288
328
ip6_ins_rt (net , f6i );
289
329
290
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
365
else
326
366
idev -> ac_list = aca -> aca_next ;
327
367
write_unlock_bh (& idev -> lock );
368
+ ipv6_del_acaddr_hash (aca );
328
369
addrconf_leave_solict (idev , & aca -> aca_addr );
329
370
330
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
393
idev -> ac_list = aca -> aca_next ;
353
394
write_unlock_bh (& idev -> lock );
354
395
396
+ ipv6_del_acaddr_hash (aca );
397
+
355
398
addrconf_leave_solict (idev , & aca -> aca_addr );
356
399
357
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
390
433
bool ipv6_chk_acast_addr (struct net * net , struct net_device * dev ,
391
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
439
bool found = false;
394
440
395
441
rcu_read_lock ();
396
442
if (dev )
397
443
found = ipv6_chk_acast_dev (dev , addr );
398
444
else
399
- for_each_netdev_rcu (net , dev )
400
- if (ipv6_chk_acast_dev (dev , addr )) {
445
+ hlist_for_each_entry_rcu (aca , & inet6_acaddr_lst [hash ],
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
451
found = true;
402
452
break ;
403
453
}
454
+ }
404
455
rcu_read_unlock ();
405
456
return found ;
406
457
}
@@ -539,4 +590,25 @@ void ac6_proc_exit(struct net *net)
539
590
{
540
591
remove_proc_entry ("anycast6" , net -> proc_net );
541
592
}
593
+
594
+ /* Init / cleanup code
595
+ */
596
+ int __init ipv6_anycast_init (void )
597
+ {
598
+ int i ;
599
+
600
+ for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ )
601
+ INIT_HLIST_HEAD (& inet6_acaddr_lst [i ]);
602
+ return 0 ;
603
+ }
604
+
605
+ void ipv6_anycast_cleanup (void )
606
+ {
607
+ int i ;
608
+
609
+ spin_lock (& acaddr_hash_lock );
610
+ for (i = 0 ; i < IN6_ADDR_HSIZE ; i ++ )
611
+ WARN_ON (!hlist_empty (& inet6_acaddr_lst [i ]));
612
+ spin_unlock (& acaddr_hash_lock );
613
+ }
542
614
#endif
0 commit comments