Skip to content

Commit cef6341

Browse files
Marek Lindnerordex
authored andcommitted
batman-adv: add list of unique single hop neighbors per hard-interface
Signed-off-by: Marek Lindner <mareklindner@neomailbox.ch> Signed-off-by: Antonio Quartulli <antonio@meshcoding.com>
1 parent 030ee5f commit cef6341

File tree

4 files changed

+188
-0
lines changed

4 files changed

+188
-0
lines changed

net/batman-adv/hard-interface.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <linux/rculist.h>
3333
#include <linux/rtnetlink.h>
3434
#include <linux/slab.h>
35+
#include <linux/spinlock.h>
3536
#include <linux/workqueue.h>
3637
#include <net/net_namespace.h>
3738

@@ -639,9 +640,12 @@ batadv_hardif_add_interface(struct net_device *net_dev)
639640
goto free_sysfs;
640641

641642
INIT_LIST_HEAD(&hard_iface->list);
643+
INIT_HLIST_HEAD(&hard_iface->neigh_list);
642644
INIT_WORK(&hard_iface->cleanup_work,
643645
batadv_hardif_remove_interface_finish);
644646

647+
spin_lock_init(&hard_iface->neigh_list_lock);
648+
645649
hard_iface->num_bcasts = BATADV_NUM_BCASTS_DEFAULT;
646650
if (batadv_is_wifi_netdev(net_dev))
647651
hard_iface->num_bcasts = BATADV_NUM_BCASTS_WIRELESS;

net/batman-adv/originator.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,47 @@ void batadv_neigh_ifinfo_free_ref(struct batadv_neigh_ifinfo *neigh_ifinfo)
201201
call_rcu(&neigh_ifinfo->rcu, batadv_neigh_ifinfo_free_rcu);
202202
}
203203

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+
204245
/**
205246
* batadv_neigh_node_free_rcu - free the neigh_node
206247
* @rcu: rcu pointer of the neigh_node
@@ -209,6 +250,7 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
209250
{
210251
struct hlist_node *node_tmp;
211252
struct batadv_neigh_node *neigh_node;
253+
struct batadv_hardif_neigh_node *hardif_neigh;
212254
struct batadv_neigh_ifinfo *neigh_ifinfo;
213255
struct batadv_algo_ops *bao;
214256

@@ -220,6 +262,14 @@ static void batadv_neigh_node_free_rcu(struct rcu_head *rcu)
220262
batadv_neigh_ifinfo_free_ref_now(neigh_ifinfo);
221263
}
222264

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+
223273
if (bao->bat_neigh_free)
224274
bao->bat_neigh_free(neigh_node);
225275

@@ -478,6 +528,102 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node,
478528
return res;
479529
}
480530

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+
481627
/**
482628
* batadv_neigh_node_new - create and init a new neigh_node object
483629
* @orig_node: originator object representing the neighbour
@@ -493,11 +639,17 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
493639
const u8 *neigh_addr)
494640
{
495641
struct batadv_neigh_node *neigh_node;
642+
struct batadv_hardif_neigh_node *hardif_neigh = NULL;
496643

497644
neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr);
498645
if (neigh_node)
499646
goto out;
500647

648+
hardif_neigh = batadv_hardif_neigh_get_or_create(hard_iface,
649+
neigh_addr);
650+
if (!hardif_neigh)
651+
goto out;
652+
501653
neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC);
502654
if (!neigh_node)
503655
goto out;
@@ -523,11 +675,16 @@ batadv_neigh_node_new(struct batadv_orig_node *orig_node,
523675
hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list);
524676
spin_unlock_bh(&orig_node->neigh_list_lock);
525677

678+
/* increment unique neighbor refcount */
679+
atomic_inc(&hardif_neigh->refcount);
680+
526681
batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv,
527682
"Creating new neighbor %pM for orig_node %pM on interface %s\n",
528683
neigh_addr, orig_node->orig, hard_iface->net_dev->name);
529684

530685
out:
686+
if (hardif_neigh)
687+
batadv_hardif_neigh_free_ref(hardif_neigh);
531688
return neigh_node;
532689
}
533690

net/batman-adv/originator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node);
4141
void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node);
4242
struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv,
4343
const u8 *addr);
44+
struct batadv_hardif_neigh_node *
45+
batadv_hardif_neigh_get(const struct batadv_hard_iface *hard_iface,
46+
const u8 *neigh_addr);
47+
void
48+
batadv_hardif_neigh_free_ref(struct batadv_hardif_neigh_node *hardif_neigh);
4449
struct batadv_neigh_node *
4550
batadv_neigh_node_new(struct batadv_orig_node *orig_node,
4651
struct batadv_hard_iface *hard_iface,

net/batman-adv/types.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ struct batadv_hard_iface_bat_iv {
100100
* @bat_iv: BATMAN IV specific per hard interface data
101101
* @cleanup_work: work queue callback item for hard interface deinit
102102
* @debug_dir: dentry for nc subdir in batman-adv directory in debugfs
103+
* @neigh_list: list of unique single hop neighbors via this interface
104+
* @neigh_list_lock: lock protecting neigh_list
103105
*/
104106
struct batadv_hard_iface {
105107
struct list_head list;
@@ -115,6 +117,9 @@ struct batadv_hard_iface {
115117
struct batadv_hard_iface_bat_iv bat_iv;
116118
struct work_struct cleanup_work;
117119
struct dentry *debug_dir;
120+
struct hlist_head neigh_list;
121+
/* neigh_list_lock protects: neigh_list */
122+
spinlock_t neigh_list_lock;
118123
};
119124

120125
/**
@@ -340,6 +345,23 @@ struct batadv_gw_node {
340345
struct rcu_head rcu;
341346
};
342347

348+
/**
349+
* batadv_hardif_neigh_node - unique neighbor per hard interface
350+
* @list: list node for batadv_hard_iface::neigh_list
351+
* @addr: the MAC address of the neighboring interface
352+
* @if_incoming: pointer to incoming hard interface
353+
* @refcount: number of contexts the object is used
354+
* @rcu: struct used for freeing in a RCU-safe manner
355+
*/
356+
struct batadv_hardif_neigh_node {
357+
struct hlist_node list;
358+
u8 addr[ETH_ALEN];
359+
struct batadv_hard_iface *if_incoming;
360+
unsigned long last_seen;
361+
atomic_t refcount;
362+
struct rcu_head rcu;
363+
};
364+
343365
/**
344366
* struct batadv_neigh_node - structure for single hops neighbors
345367
* @list: list node for batadv_orig_node::neigh_list

0 commit comments

Comments
 (0)