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) ...@@ -271,7 +271,7 @@ static void hardif_activate_interface(struct batman_if *batman_if)
static void hardif_deactivate_interface(struct batman_if *batman_if) static void hardif_deactivate_interface(struct batman_if *batman_if)
{ {
if ((batman_if->if_status != IF_ACTIVE) && if ((batman_if->if_status != IF_ACTIVE) &&
(batman_if->if_status != IF_TO_BE_ACTIVATED)) (batman_if->if_status != IF_TO_BE_ACTIVATED))
return; return;
batman_if->if_status = IF_INACTIVE; batman_if->if_status = IF_INACTIVE;
......
...@@ -75,6 +75,14 @@ static void neigh_node_free_rcu(struct rcu_head *rcu) ...@@ -75,6 +75,14 @@ static void neigh_node_free_rcu(struct rcu_head *rcu)
kref_put(&neigh_node->refcount, neigh_node_free_ref); 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 neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_node, struct orig_node *orig_neigh_node,
uint8_t *neigh, uint8_t *neigh,
...@@ -91,6 +99,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, ...@@ -91,6 +99,7 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
return NULL; return NULL;
INIT_HLIST_NODE(&neigh_node->list); INIT_HLIST_NODE(&neigh_node->list);
INIT_LIST_HEAD(&neigh_node->bonding_list);
memcpy(neigh_node->addr, neigh, ETH_ALEN); memcpy(neigh_node->addr, neigh, ETH_ALEN);
neigh_node->orig_node = orig_neigh_node; neigh_node->orig_node = orig_neigh_node;
...@@ -106,13 +115,20 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node, ...@@ -106,13 +115,20 @@ struct neigh_node *create_neighbor(struct orig_node *orig_node,
void orig_node_free_ref(struct kref *refcount) void orig_node_free_ref(struct kref *refcount)
{ {
struct hlist_node *node, *node_tmp; struct hlist_node *node, *node_tmp;
struct neigh_node *neigh_node; struct neigh_node *neigh_node, *tmp_neigh_node;
struct orig_node *orig_node; struct orig_node *orig_node;
orig_node = container_of(refcount, struct orig_node, refcount); orig_node = container_of(refcount, struct orig_node, refcount);
spin_lock_bh(&orig_node->neigh_list_lock); 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 ... */ /* for all neighbors towards this originator ... */
hlist_for_each_entry_safe(neigh_node, node, node_tmp, hlist_for_each_entry_safe(neigh_node, node, node_tmp,
&orig_node->neigh_list, list) { &orig_node->neigh_list, list) {
...@@ -207,6 +223,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) ...@@ -207,6 +223,7 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr)
return NULL; return NULL;
INIT_HLIST_HEAD(&orig_node->neigh_list); 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->ogm_cnt_lock);
spin_lock_init(&orig_node->neigh_list_lock); spin_lock_init(&orig_node->neigh_list_lock);
kref_init(&orig_node->refcount); kref_init(&orig_node->refcount);
...@@ -220,6 +237,8 @@ struct orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr) ...@@ -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 orig_node->batman_seqno_reset = jiffies - 1
- msecs_to_jiffies(RESET_PROTECTION_MS); - msecs_to_jiffies(RESET_PROTECTION_MS);
atomic_set(&orig_node->bond_candidates, 0);
size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS; size = bat_priv->num_ifaces * sizeof(unsigned long) * NUM_WORDS;
orig_node->bcast_own = kzalloc(size, GFP_ATOMIC); orig_node->bcast_own = kzalloc(size, GFP_ATOMIC);
...@@ -295,6 +314,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv, ...@@ -295,6 +314,7 @@ static bool purge_orig_neighbors(struct bat_priv *bat_priv,
neigh_purged = true; neigh_purged = true;
hlist_del_rcu(&neigh_node->list); hlist_del_rcu(&neigh_node->list);
bonding_candidate_del(orig_node, neigh_node);
call_rcu(&neigh_node->rcu, neigh_node_free_rcu); call_rcu(&neigh_node->rcu, neigh_node_free_rcu);
} else { } else {
if ((!*best_neigh_node) || if ((!*best_neigh_node) ||
...@@ -326,9 +346,6 @@ static bool purge_orig_node(struct bat_priv *bat_priv, ...@@ -326,9 +346,6 @@ static bool purge_orig_node(struct bat_priv *bat_priv,
best_neigh_node, best_neigh_node,
orig_node->hna_buff, orig_node->hna_buff,
orig_node->hna_buff_len); 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); ...@@ -26,6 +26,7 @@ int originator_init(struct bat_priv *bat_priv);
void originator_free(struct bat_priv *bat_priv); void originator_free(struct bat_priv *bat_priv);
void purge_orig_ref(struct bat_priv *bat_priv); void purge_orig_ref(struct bat_priv *bat_priv);
void orig_node_free_ref(struct kref *refcount); 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 orig_node *get_orig_node(struct bat_priv *bat_priv, uint8_t *addr);
struct neigh_node *create_neighbor(struct orig_node *orig_node, struct neigh_node *create_neighbor(struct orig_node *orig_node,
struct orig_node *orig_neigh_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); ...@@ -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_vis_packet(struct sk_buff *skb, struct batman_if *recv_if);
int recv_bat_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 neigh_node *find_router(struct bat_priv *bat_priv,
struct orig_node *orig_node, struct batman_if *recv_if); struct orig_node *orig_node,
void update_bonding_candidates(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_ */ #endif /* _NET_BATMAN_ADV_ROUTING_H_ */
...@@ -90,10 +90,8 @@ struct orig_node { ...@@ -90,10 +90,8 @@ struct orig_node {
struct bat_priv *bat_priv; struct bat_priv *bat_priv;
unsigned long last_frag_packet; unsigned long last_frag_packet;
spinlock_t ogm_cnt_lock; /* protects ogm counter */ spinlock_t ogm_cnt_lock; /* protects ogm counter */
struct { atomic_t bond_candidates;
uint8_t candidates; struct list_head bond_list;
struct neigh_node *selected;
} bond;
}; };
struct gw_node { struct gw_node {
...@@ -116,11 +114,12 @@ struct neigh_node { ...@@ -116,11 +114,12 @@ struct neigh_node {
uint8_t tq_index; uint8_t tq_index;
uint8_t tq_avg; uint8_t tq_avg;
uint8_t last_ttl; uint8_t last_ttl;
struct neigh_node *next_bond_candidate; struct list_head bonding_list;
unsigned long last_valid; unsigned long last_valid;
unsigned long real_bits[NUM_WORDS]; unsigned long real_bits[NUM_WORDS];
struct kref refcount; struct kref refcount;
struct rcu_head rcu; struct rcu_head rcu;
struct rcu_head rcu_bond;
struct orig_node *orig_node; struct orig_node *orig_node;
struct batman_if *if_incoming; struct batman_if *if_incoming;
}; };
......
...@@ -299,6 +299,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) ...@@ -299,6 +299,7 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv)
if (!orig_node) if (!orig_node)
orig_node = transtable_search(bat_priv, ethhdr->h_dest); 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); router = find_router(bat_priv, orig_node, NULL);
if (!router) if (!router)
...@@ -306,7 +307,6 @@ int unicast_send_skb(struct sk_buff *skb, struct bat_priv *bat_priv) ...@@ -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 /* don't lock while sending the packets ... we therefore
* copy the required data before sending */ * copy the required data before sending */
batman_if = router->if_incoming; batman_if = router->if_incoming;
memcpy(dstaddr, router->addr, ETH_ALEN); 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