Commit a4c135c5 authored by Simon Wunderlich's avatar Simon Wunderlich Committed by Marek Lindner

batman-adv: protect bonding with rcu locks

bonding / alternating candidates need to be secured by rcu locks
as well. This patch therefore converts the bonding list
from a plain pointer list to a rcu securable lists and references
the bonding candidates.
Signed-off-by: default avatarSimon Wunderlich <siwu@hrz.tu-chemnitz.de>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
parent 2ae2daf6
......@@ -271,7 +271,7 @@ static void hardif_activate_interface(struct batman_if *batman_if)
static void hardif_deactivate_interface(struct batman_if *batman_if)
{
if ((batman_if->if_status != IF_ACTIVE) &&
(batman_if->if_status != IF_TO_BE_ACTIVATED))
(batman_if->if_status != IF_TO_BE_ACTIVATED))
return;
batman_if->if_status = IF_INACTIVE;
......
......@@ -75,6 +75,14 @@ static void neigh_node_free_rcu(struct rcu_head *rcu)
kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
void neigh_node_free_rcu_bond(struct rcu_head *rcu)
{
struct neigh_node *neigh_node;
neigh_node = container_of(rcu, struct neigh_node, rcu_bond);
kref_put(&neigh_node->refcount, neigh_node_free_ref);
}
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
uint8_t *neigh,
......@@ -91,6 +99,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
return NULL;
INIT_HLIST_NODE(&neigh_node->list);
INIT_LIST_HEAD(&neigh_node->bonding_list);
memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node;
......@@ -106,13 +115,20 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
void orig_node_free_ref(struct kref *refcount)
{
struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node;
struct neigh_node *neigh_node, *tmp_neigh_node;
struct orig_node *orig_node;
orig_node = container_of(refcount, struct orig_node, refcount);
spin_lock_bh(&orig_node->neigh_list_lock);
/* for all bonding members ... */
list_for_each_entry_safe(neigh_node, tmp_neigh_node,
&orig_node->bond_list, bonding_list) {
list_del_rcu(&neigh_node->bonding_list);
call_rcu(&neigh_node->rcu_bond, neigh_node_free_rcu_bond);
}
/* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) {
......@@ -207,6 +223,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list);
INIT_LIST_HEAD(&orig_node->bond_list);
spin_lock_init(&orig_node->ogm_cnt_lock);
spin_lock_init(&orig_node->neigh_list_lock);
kref_init(&orig_node->refcount);
......@@ -220,6 +237,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
orig_node->batman_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS);
atomic_set(&orig_node->bond_candidates, 0);
size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS;
orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
......@@ -295,6 +314,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_purged = true;
hlist_del_rcu(&neigh_node->list);
bonding_candidate_del(orig_node, neigh_node);
call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
} else {
if ((!*best_neigh_node) ||
......@@ -326,9 +346,6 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
best_neigh_node,
orig_node->hna_buff,
orig_node->hna_buff_len);
/* update bonding candidates, we could have lost
* some candidates. */
update_bonding_candidates(orig_node);
}
}
......
......@@ -26,6 +26,7 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct kref *refcount);
void neigh_node_free_rcu_bond(struct rcu_head *rcu);
struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node,
......
This diff is collapsed.
......@@ -39,7 +39,9 @@ int recv_bcast_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_bat_packet(struct sk_buff *skb, struct batman_if *recv_if);
struct neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node, struct batman_if *recv_if);
void update_bonding_candidates(struct orig_node *orig_node);
struct orig_node *orig_node,
struct batman_if *recv_if);
void bonding_candidate_del(struct orig_node *orig_node,
struct neigh_node *neigh_node);
#endif /* _NET_BATMAN_ADV_ROUTING_H_ */
......@@ -90,10 +90,8 @@ struct orig_node {
struct bat_priv *bat_priv;
unsigned long last_frag_packet;
spinlock_t ogm_cnt_lock; /* protects ogm counter */
struct {
uint8_t candidates;
struct neigh_node *selected;
} bond;
atomic_t bond_candidates;
struct list_head bond_list;
};
struct gw_node {
......@@ -116,11 +114,12 @@ struct neigh_node {
uint8_t tq_index;
uint8_t tq_avg;
uint8_t last_ttl;
struct neigh_node *next_bond_candidate;
struct list_head bonding_list;
unsigned long last_valid;
unsigned long real_bits[NUM_WORDS];
struct kref refcount;
struct rcu_head rcu;
struct rcu_head rcu_bond;
struct orig_node *orig_node;
struct batman_if *if_incoming;
};
......
......@@ -299,6 +299,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
if (!orig_node)
orig_node = transtable_search(bat_priv, ethhdr->h_dest);
/* find_router() increases neigh_nodes refcount if found. */
router = find_router(bat_priv, orig_node, NULL);
if (!router)
......@@ -306,7 +307,6 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
/* don't lock while sending the packets ... we therefore
* copy the required data before sending */
batman_if = router->if_incoming;
memcpy(dstaddr, router->addr, ETH_ALEN);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment