Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55158629 authored by Linus Lüssing's avatar Linus Lüssing Committed by Sven Eckelmann
Browse files

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: default avatarLinus Lüssing <linus.luessing@web.de>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
parent 0ce790e7
Loading
Loading
Loading
Loading
+105 −75
Original line number Diff line number Diff line
@@ -1092,6 +1092,106 @@ int recv_icmp_packet(struct sk_buff *skb, struct hard_iface *recv_if)
	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. */

		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);
		}
	if (bonding_enabled)
		router = find_bond_router(primary_orig_node, recv_if);
	else
		router = find_ifalter_router(primary_orig_node, recv_if);

		/* 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;