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

Commit 2265c141 authored by Antonio Quartulli's avatar Antonio Quartulli Committed by Sven Eckelmann
Browse files

batman-adv: gateway election code refactoring



The gateway election mechanism has been a little revised. Now the
gw_election is trigered by an atomic_t flag (gw_reselect) which is set
to 1 in case of election needed, avoding to set curr_gw to NULL.

Signed-off-by: default avatarAntonio Quartulli <ordex@autistici.org>
Signed-off-by: default avatarMarek Lindner <lindner_marek@yahoo.de>
Signed-off-by: default avatarSven Eckelmann <sven@narfation.org>
parent c6bda689
Loading
Loading
Loading
Loading
+80 −56
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
 */

#include "main.h"
#include "bat_sysfs.h"
#include "gateway_client.h"
#include "gateway_common.h"
#include "hard-interface.h"
@@ -97,40 +98,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node)

void gw_deselect(struct bat_priv *bat_priv)
{
	gw_select(bat_priv, NULL);
	atomic_set(&bat_priv->gw_reselect, 1);
}

void gw_election(struct bat_priv *bat_priv)
static struct gw_node *gw_get_best_gw_node(struct bat_priv *bat_priv)
{
	struct hlist_node *node;
	struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL;
	struct neigh_node *router;
	uint8_t max_tq = 0;
	struct hlist_node *node;
	struct gw_node *gw_node, *curr_gw = NULL;
	uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
	uint8_t max_tq = 0;
	int down, up;

	/**
	 * The batman daemon checks here if we already passed a full originator
	 * cycle in order to make sure we don't choose the first gateway we
	 * hear about. This check is based on the daemon's uptime which we
	 * don't have.
	 **/
	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
		return;

	curr_gw = gw_get_selected_gw_node(bat_priv);
	if (curr_gw)
		goto out;

	rcu_read_lock();
	if (hlist_empty(&bat_priv->gw_list)) {
		bat_dbg(DBG_BATMAN, bat_priv,
			"Removing selected gateway - "
			"no gateway in range\n");
		gw_deselect(bat_priv);
		goto unlock;
	}

	hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
		if (gw_node->deleted)
			continue;
@@ -139,6 +119,9 @@ void gw_election(struct bat_priv *bat_priv)
		if (!router)
			continue;

		if (!atomic_inc_not_zero(&gw_node->refcount))
			goto next;

		switch (atomic_read(&bat_priv->gw_sel_class)) {
		case 1: /* fast connection */
			gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
@@ -151,8 +134,12 @@ void gw_election(struct bat_priv *bat_priv)

			if ((tmp_gw_factor > max_gw_factor) ||
			    ((tmp_gw_factor == max_gw_factor) &&
			     (router->tq_avg > max_tq)))
				curr_gw_tmp = gw_node;
			     (router->tq_avg > max_tq))) {
				if (curr_gw)
					gw_node_free_ref(curr_gw);
				curr_gw = gw_node;
				atomic_inc(&curr_gw->refcount);
			}
			break;

		default: /**
@@ -163,8 +150,12 @@ void gw_election(struct bat_priv *bat_priv)
			  *     soon as a better gateway appears which has
			  *     $routing_class more tq points)
			  **/
			if (router->tq_avg > max_tq)
				curr_gw_tmp = gw_node;
			if (router->tq_avg > max_tq) {
				if (curr_gw)
					gw_node_free_ref(curr_gw);
				curr_gw = gw_node;
				atomic_inc(&curr_gw->refcount);
			}
			break;
		}

@@ -174,42 +165,75 @@ void gw_election(struct bat_priv *bat_priv)
		if (tmp_gw_factor > max_gw_factor)
			max_gw_factor = tmp_gw_factor;

		gw_node_free_ref(gw_node);

next:
		neigh_node_free_ref(router);
	}
	rcu_read_unlock();

	if (curr_gw != curr_gw_tmp) {
		router = orig_node_get_router(curr_gw_tmp->orig_node);
		if (!router)
			goto unlock;
	return curr_gw;
}

void gw_election(struct bat_priv *bat_priv)
{
	struct gw_node *curr_gw = NULL, *next_gw = NULL;
	struct neigh_node *router = NULL;

	/**
	 * The batman daemon checks here if we already passed a full originator
	 * cycle in order to make sure we don't choose the first gateway we
	 * hear about. This check is based on the daemon's uptime which we
	 * don't have.
	 **/
	if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT)
		goto out;

	if (!atomic_dec_not_zero(&bat_priv->gw_reselect))
		goto out;

		if ((curr_gw) && (!curr_gw_tmp))
	curr_gw = gw_get_selected_gw_node(bat_priv);

	next_gw = gw_get_best_gw_node(bat_priv);

	if (curr_gw == next_gw)
		goto out;

	if (next_gw) {
		router = orig_node_get_router(next_gw->orig_node);
		if (!router) {
			gw_deselect(bat_priv);
			goto out;
		}
	}

	if ((curr_gw) && (!next_gw)) {
		bat_dbg(DBG_BATMAN, bat_priv,
				"Removing selected gateway - "
				"no gateway in range\n");
		else if ((!curr_gw) && (curr_gw_tmp))
			"Removing selected gateway - no gateway in range\n");
	} else if ((!curr_gw) && (next_gw)) {
		bat_dbg(DBG_BATMAN, bat_priv,
				"Adding route to gateway %pM "
				"(gw_flags: %i, tq: %i)\n",
				curr_gw_tmp->orig_node->orig,
				curr_gw_tmp->orig_node->gw_flags,
			"Adding route to gateway %pM (gw_flags: %i, tq: %i)\n",
			next_gw->orig_node->orig,
			next_gw->orig_node->gw_flags,
			router->tq_avg);
		else
	} else {
		bat_dbg(DBG_BATMAN, bat_priv,
			"Changing route to gateway %pM "
			"(gw_flags: %i, tq: %i)\n",
				curr_gw_tmp->orig_node->orig,
				curr_gw_tmp->orig_node->gw_flags,
			next_gw->orig_node->orig,
			next_gw->orig_node->gw_flags,
			router->tq_avg);

		neigh_node_free_ref(router);
		gw_select(bat_priv, curr_gw_tmp);
	}

unlock:
	rcu_read_unlock();
	gw_select(bat_priv, next_gw);

out:
	if (curr_gw)
		gw_node_free_ref(curr_gw);
	if (next_gw)
		gw_node_free_ref(next_gw);
	if (router)
		neigh_node_free_ref(router);
}

void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
+1 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ int mesh_init(struct net_device *soft_iface)
	if (vis_init(bat_priv) < 1)
		goto err;

	atomic_set(&bat_priv->gw_reselect, 0);
	atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
	goto end;

+1 −0
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ struct bat_priv {
	struct delayed_work orig_work;
	struct delayed_work vis_work;
	struct gw_node __rcu *curr_gw;  /* rcu protected pointer */
	atomic_t gw_reselect;
	struct hard_iface __rcu *primary_if;  /* rcu protected pointer */
	struct vis_info *my_vis_info;
};