batman-adv: Move bonding / iface alternating router search to own functions

This decreases the size of find_router() by outsourcing the router
search for the bonding and interface alternating modes to their own sub
functions. This shall make it easier to keep track of the correct
refcounting later.

Signed-off-by: Linus Lüssing <linus.luessing@web.de>
Signed-off-by: Marek Lindner <lindner_marek@yahoo.de>
Signed-off-by: Sven Eckelmann <sven@narfation.org>
This commit is contained in:
Linus Lüssing 2011-03-14 22:43:27 +00:00 committed by Sven Eckelmann
parent 0ce790e7d7
commit 551586292b
1 changed files with 105 additions and 75 deletions

View File

@ -1092,6 +1092,106 @@ out:
return ret;
}
/* In the bonding case, send the packets in a round
* robin fashion over the remaining interfaces.
*
* This method rotates the bonding list and increases the
* returned router's refcount. */
static struct neigh_node *find_bond_router(struct orig_node *primary_orig,
struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
rcu_read_lock();
list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming == recv_if)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
continue;
router = tmp_neigh_node;
break;
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
if (!router)
goto out;
/* selected should point to the next element
* after the current router */
spin_lock_bh(&primary_orig->neigh_list_lock);
/* this is a list_move(), which unfortunately
* does not exist as rcu version */
list_del_rcu(&primary_orig->bond_list);
list_add_rcu(&primary_orig->bond_list,
&router->bonding_list);
spin_unlock_bh(&primary_orig->neigh_list_lock);
out:
rcu_read_unlock();
return router;
}
/* Interface Alternating: Use the best of the
* remaining candidates which are not using
* this interface.
*
* Increases the returned router's refcount */
static struct neigh_node *find_ifalter_router(struct orig_node *primary_orig,
struct hard_iface *recv_if)
{
struct neigh_node *tmp_neigh_node;
struct neigh_node *router = NULL, *first_candidate = NULL;
rcu_read_lock();
list_for_each_entry_rcu(tmp_neigh_node, &primary_orig->bond_list,
bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming == recv_if)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
continue;
/* if we don't have a router yet
* or this one is better, choose it. */
if ((!router) ||
(tmp_neigh_node->tq_avg > router->tq_avg)) {
/* decrement refcount of
* previously selected router */
if (router)
neigh_node_free_ref(router);
router = tmp_neigh_node;
atomic_inc_not_zero(&router->refcount);
}
neigh_node_free_ref(tmp_neigh_node);
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
rcu_read_unlock();
return router;
}
/* find a suitable router for this originator, and use
* bonding if possible. increases the found neighbors
* refcount.*/
@ -1101,7 +1201,7 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
{
struct orig_node *primary_orig_node;
struct orig_node *router_orig;
struct neigh_node *router, *first_candidate, *tmp_neigh_node;
struct neigh_node *router;
static uint8_t zero_mac[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
int bonding_enabled;
@ -1157,82 +1257,12 @@ struct neigh_node *find_router(struct bat_priv *bat_priv,
* in. */
neigh_node_free_ref(router);
first_candidate = NULL;
router = NULL;
if (bonding_enabled) {
/* in the bonding case, send the packets in a round
* robin fashion over the remaining interfaces. */
if (bonding_enabled)
router = find_bond_router(primary_orig_node, recv_if);
else
router = find_ifalter_router(primary_orig_node, recv_if);
list_for_each_entry_rcu(tmp_neigh_node,
&primary_orig_node->bond_list, bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming != recv_if &&
atomic_inc_not_zero(&tmp_neigh_node->refcount)) {
router = tmp_neigh_node;
break;
}
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
if (!router) {
rcu_read_unlock();
return NULL;
}
/* selected should point to the next element
* after the current router */
spin_lock_bh(&primary_orig_node->neigh_list_lock);
/* this is a list_move(), which unfortunately
* does not exist as rcu version */
list_del_rcu(&primary_orig_node->bond_list);
list_add_rcu(&primary_orig_node->bond_list,
&router->bonding_list);
spin_unlock_bh(&primary_orig_node->neigh_list_lock);
} else {
/* if bonding is disabled, use the best of the
* remaining candidates which are not using
* this interface. */
list_for_each_entry_rcu(tmp_neigh_node,
&primary_orig_node->bond_list, bonding_list) {
if (!first_candidate)
first_candidate = tmp_neigh_node;
/* recv_if == NULL on the first node. */
if (tmp_neigh_node->if_incoming == recv_if)
continue;
if (!atomic_inc_not_zero(&tmp_neigh_node->refcount))
continue;
/* if we don't have a router yet
* or this one is better, choose it. */
if ((!router) ||
(tmp_neigh_node->tq_avg > router->tq_avg)) {
/* decrement refcount of
* previously selected router */
if (router)
neigh_node_free_ref(router);
router = tmp_neigh_node;
atomic_inc_not_zero(&router->refcount);
}
neigh_node_free_ref(tmp_neigh_node);
}
/* use the first candidate if nothing was found. */
if (!router && first_candidate &&
atomic_inc_not_zero(&first_candidate->refcount))
router = first_candidate;
}
return_router:
rcu_read_unlock();
return router;