@@ -201,6 +201,47 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
201
201
call_rcu (& neigh_ifinfo -> rcu , batadv_neigh_ifinfo_free_rcu );
202
202
}
203
203
204
+ /**
205
+ * batadv_hardif_neigh_free_rcu - free the hardif neigh_node
206
+ * @rcu: rcu pointer of the neigh_node
207
+ */
208
+ static void batadv_hardif_neigh_free_rcu (struct rcu_head * rcu )
209
+ {
210
+ struct batadv_hardif_neigh_node * hardif_neigh ;
211
+
212
+ hardif_neigh = container_of (rcu , struct batadv_hardif_neigh_node , rcu );
213
+
214
+ spin_lock_bh (& hardif_neigh -> if_incoming -> neigh_list_lock );
215
+ hlist_del_init_rcu (& hardif_neigh -> list );
216
+ spin_unlock_bh (& hardif_neigh -> if_incoming -> neigh_list_lock );
217
+
218
+ batadv_hardif_free_ref_now (hardif_neigh -> if_incoming );
219
+ kfree (hardif_neigh );
220
+ }
221
+
222
+ /**
223
+ * batadv_hardif_neigh_free_now - decrement the hardif neighbors refcounter
224
+ * and possibly free it (without rcu callback)
225
+ * @hardif_neigh: hardif neigh neighbor to free
226
+ */
227
+ static void
228
+ batadv_hardif_neigh_free_now (struct batadv_hardif_neigh_node * hardif_neigh )
229
+ {
230
+ if (atomic_dec_and_test (& hardif_neigh -> refcount ))
231
+ batadv_hardif_neigh_free_rcu (& hardif_neigh -> rcu );
232
+ }
233
+
234
+ /**
235
+ * batadv_hardif_neigh_free_ref - decrement the hardif neighbors refcounter
236
+ * and possibly free it
237
+ * @hardif_neigh: hardif neigh neighbor to free
238
+ */
239
+ void batadv_hardif_neigh_free_ref (struct batadv_hardif_neigh_node * hardif_neigh )
240
+ {
241
+ if (atomic_dec_and_test (& hardif_neigh -> refcount ))
242
+ call_rcu (& hardif_neigh -> rcu , batadv_hardif_neigh_free_rcu );
243
+ }
244
+
204
245
/**
205
246
* batadv_neigh_node_free_rcu - free the neigh_node
206
247
* @rcu: rcu pointer of the neigh_node
@@ -209,6 +250,7 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
209
250
{
210
251
struct hlist_node * node_tmp ;
211
252
struct batadv_neigh_node * neigh_node ;
253
+ struct batadv_hardif_neigh_node * hardif_neigh ;
212
254
struct batadv_neigh_ifinfo * neigh_ifinfo ;
213
255
struct batadv_algo_ops * bao ;
214
256
@@ -220,6 +262,14 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
220
262
batadv_neigh_ifinfo_free_ref_now (neigh_ifinfo );
221
263
}
222
264
265
+ hardif_neigh = batadv_hardif_neigh_get (neigh_node -> if_incoming ,
266
+ neigh_node -> addr );
267
+ if (hardif_neigh ) {
268
+ /* batadv_hardif_neigh_get() increases refcount too */
269
+ batadv_hardif_neigh_free_now (hardif_neigh );
270
+ batadv_hardif_neigh_free_now (hardif_neigh );
271
+ }
272
+
223
273
if (bao -> bat_neigh_free )
224
274
bao -> bat_neigh_free (neigh_node );
225
275
@@ -478,6 +528,102 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
478
528
return res ;
479
529
}
480
530
531
+ /**
532
+ * batadv_hardif_neigh_create - create a hardif neighbour node
533
+ * @hard_iface: the interface this neighbour is connected to
534
+ * @neigh_addr: the interface address of the neighbour to retrieve
535
+ *
536
+ * Returns the hardif neighbour node if found or created or NULL otherwise.
537
+ */
538
+ static struct batadv_hardif_neigh_node *
539
+ batadv_hardif_neigh_create (struct batadv_hard_iface * hard_iface ,
540
+ const u8 * neigh_addr )
541
+ {
542
+ struct batadv_hardif_neigh_node * hardif_neigh = NULL ;
543
+
544
+ spin_lock_bh (& hard_iface -> neigh_list_lock );
545
+
546
+ /* check if neighbor hasn't been added in the meantime */
547
+ hardif_neigh = batadv_hardif_neigh_get (hard_iface , neigh_addr );
548
+ if (hardif_neigh )
549
+ goto out ;
550
+
551
+ if (!atomic_inc_not_zero (& hard_iface -> refcount ))
552
+ goto out ;
553
+
554
+ hardif_neigh = kzalloc (sizeof (* hardif_neigh ), GFP_ATOMIC );
555
+ if (!hardif_neigh ) {
556
+ batadv_hardif_free_ref (hard_iface );
557
+ goto out ;
558
+ }
559
+
560
+ INIT_HLIST_NODE (& hardif_neigh -> list );
561
+ ether_addr_copy (hardif_neigh -> addr , neigh_addr );
562
+ hardif_neigh -> if_incoming = hard_iface ;
563
+ hardif_neigh -> last_seen = jiffies ;
564
+
565
+ atomic_set (& hardif_neigh -> refcount , 1 );
566
+
567
+ hlist_add_head (& hardif_neigh -> list , & hard_iface -> neigh_list );
568
+
569
+ out :
570
+ spin_unlock_bh (& hard_iface -> neigh_list_lock );
571
+ return hardif_neigh ;
572
+ }
573
+
574
+ /**
575
+ * batadv_hardif_neigh_get_or_create - retrieve or create a hardif neighbour
576
+ * node
577
+ * @hard_iface: the interface this neighbour is connected to
578
+ * @neigh_addr: the interface address of the neighbour to retrieve
579
+ *
580
+ * Returns the hardif neighbour node if found or created or NULL otherwise.
581
+ */
582
+ static struct batadv_hardif_neigh_node *
583
+ batadv_hardif_neigh_get_or_create (struct batadv_hard_iface * hard_iface ,
584
+ const u8 * neigh_addr )
585
+ {
586
+ struct batadv_hardif_neigh_node * hardif_neigh = NULL ;
587
+
588
+ /* first check without locking to avoid the overhead */
589
+ hardif_neigh = batadv_hardif_neigh_get (hard_iface , neigh_addr );
590
+ if (hardif_neigh )
591
+ return hardif_neigh ;
592
+
593
+ return batadv_hardif_neigh_create (hard_iface , neigh_addr );
594
+ }
595
+
596
+ /**
597
+ * batadv_hardif_neigh_get - retrieve a hardif neighbour from the list
598
+ * @hard_iface: the interface where this neighbour is connected to
599
+ * @neigh_addr: the address of the neighbour
600
+ *
601
+ * Looks for and possibly returns a neighbour belonging to this hard interface.
602
+ * Returns NULL if the neighbour is not found.
603
+ */
604
+ struct batadv_hardif_neigh_node *
605
+ batadv_hardif_neigh_get (const struct batadv_hard_iface * hard_iface ,
606
+ const u8 * neigh_addr )
607
+ {
608
+ struct batadv_hardif_neigh_node * tmp_hardif_neigh , * hardif_neigh = NULL ;
609
+
610
+ rcu_read_lock ();
611
+ hlist_for_each_entry_rcu (tmp_hardif_neigh ,
612
+ & hard_iface -> neigh_list , list ) {
613
+ if (!batadv_compare_eth (tmp_hardif_neigh -> addr , neigh_addr ))
614
+ continue ;
615
+
616
+ if (!atomic_inc_not_zero (& tmp_hardif_neigh -> refcount ))
617
+ continue ;
618
+
619
+ hardif_neigh = tmp_hardif_neigh ;
620
+ break ;
621
+ }
622
+ rcu_read_unlock ();
623
+
624
+ return hardif_neigh ;
625
+ }
626
+
481
627
/**
482
628
* batadv_neigh_node_new - create and init a new neigh_node object
483
629
* @orig_node: originator object representing the neighbour
@@ -493,11 +639,17 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
493
639
const u8 * neigh_addr )
494
640
{
495
641
struct batadv_neigh_node * neigh_node ;
642
+ struct batadv_hardif_neigh_node * hardif_neigh = NULL ;
496
643
497
644
neigh_node = batadv_neigh_node_get (orig_node , hard_iface , neigh_addr );
498
645
if (neigh_node )
499
646
goto out ;
500
647
648
+ hardif_neigh = batadv_hardif_neigh_get_or_create (hard_iface ,
649
+ neigh_addr );
650
+ if (!hardif_neigh )
651
+ goto out ;
652
+
501
653
neigh_node = kzalloc (sizeof (* neigh_node ), GFP_ATOMIC );
502
654
if (!neigh_node )
503
655
goto out ;
@@ -523,11 +675,16 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
523
675
hlist_add_head_rcu (& neigh_node -> list , & orig_node -> neigh_list );
524
676
spin_unlock_bh (& orig_node -> neigh_list_lock );
525
677
678
+ /* increment unique neighbor refcount */
679
+ atomic_inc (& hardif_neigh -> refcount );
680
+
526
681
batadv_dbg (BATADV_DBG_BATMAN , orig_node -> bat_priv ,
527
682
"Creating new neighbor %pM for orig_node %pM on interface %s\n" ,
528
683
neigh_addr , orig_node -> orig , hard_iface -> net_dev -> name );
529
684
530
685
out :
686
+ if (hardif_neigh )
687
+ batadv_hardif_neigh_free_ref (hardif_neigh );
531
688
return neigh_node ;
532
689
}
533
690
0 commit comments