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

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
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
*/ */
#include "main.h" #include "main.h"
#include "bat_sysfs.h"
#include "gateway_client.h" #include "gateway_client.h"
#include "gateway_common.h" #include "gateway_common.h"
#include "hard-interface.h" #include "hard-interface.h"
...@@ -97,40 +98,19 @@ static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) ...@@ -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) 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; 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; uint32_t max_gw_factor = 0, tmp_gw_factor = 0;
uint8_t max_tq = 0;
int down, up; 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(); 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) { hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) {
if (gw_node->deleted) if (gw_node->deleted)
continue; continue;
...@@ -139,6 +119,9 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -139,6 +119,9 @@ void gw_election(struct bat_priv *bat_priv)
if (!router) if (!router)
continue; continue;
if (!atomic_inc_not_zero(&gw_node->refcount))
goto next;
switch (atomic_read(&bat_priv->gw_sel_class)) { switch (atomic_read(&bat_priv->gw_sel_class)) {
case 1: /* fast connection */ case 1: /* fast connection */
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags,
...@@ -151,8 +134,12 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -151,8 +134,12 @@ void gw_election(struct bat_priv *bat_priv)
if ((tmp_gw_factor > max_gw_factor) || if ((tmp_gw_factor > max_gw_factor) ||
((tmp_gw_factor == max_gw_factor) && ((tmp_gw_factor == max_gw_factor) &&
(router->tq_avg > max_tq))) (router->tq_avg > max_tq))) {
curr_gw_tmp = gw_node; if (curr_gw)
gw_node_free_ref(curr_gw);
curr_gw = gw_node;
atomic_inc(&curr_gw->refcount);
}
break; break;
default: /** default: /**
...@@ -163,8 +150,12 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -163,8 +150,12 @@ void gw_election(struct bat_priv *bat_priv)
* soon as a better gateway appears which has * soon as a better gateway appears which has
* $routing_class more tq points) * $routing_class more tq points)
**/ **/
if (router->tq_avg > max_tq) if (router->tq_avg > max_tq) {
curr_gw_tmp = gw_node; if (curr_gw)
gw_node_free_ref(curr_gw);
curr_gw = gw_node;
atomic_inc(&curr_gw->refcount);
}
break; break;
} }
...@@ -174,42 +165,75 @@ void gw_election(struct bat_priv *bat_priv) ...@@ -174,42 +165,75 @@ void gw_election(struct bat_priv *bat_priv)
if (tmp_gw_factor > max_gw_factor) if (tmp_gw_factor > max_gw_factor)
max_gw_factor = tmp_gw_factor; max_gw_factor = tmp_gw_factor;
gw_node_free_ref(gw_node);
next:
neigh_node_free_ref(router); neigh_node_free_ref(router);
} }
rcu_read_unlock();
if (curr_gw != curr_gw_tmp) { return curr_gw;
router = orig_node_get_router(curr_gw_tmp->orig_node); }
if (!router)
goto unlock;
if ((curr_gw) && (!curr_gw_tmp)) void gw_election(struct bat_priv *bat_priv)
bat_dbg(DBG_BATMAN, bat_priv, {
"Removing selected gateway - " struct gw_node *curr_gw = NULL, *next_gw = NULL;
"no gateway in range\n"); struct neigh_node *router = NULL;
else if ((!curr_gw) && (curr_gw_tmp))
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,
router->tq_avg);
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,
router->tq_avg);
neigh_node_free_ref(router); /**
gw_select(bat_priv, curr_gw_tmp); * 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;
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;
}
} }
unlock: if ((curr_gw) && (!next_gw)) {
rcu_read_unlock(); bat_dbg(DBG_BATMAN, bat_priv,
"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",
next_gw->orig_node->orig,
next_gw->orig_node->gw_flags,
router->tq_avg);
} else {
bat_dbg(DBG_BATMAN, bat_priv,
"Changing route to gateway %pM "
"(gw_flags: %i, tq: %i)\n",
next_gw->orig_node->orig,
next_gw->orig_node->gw_flags,
router->tq_avg);
}
gw_select(bat_priv, next_gw);
out: out:
if (curr_gw) if (curr_gw)
gw_node_free_ref(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) void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node)
......
...@@ -113,6 +113,7 @@ int mesh_init(struct net_device *soft_iface) ...@@ -113,6 +113,7 @@ int mesh_init(struct net_device *soft_iface)
if (vis_init(bat_priv) < 1) if (vis_init(bat_priv) < 1)
goto err; goto err;
atomic_set(&bat_priv->gw_reselect, 0);
atomic_set(&bat_priv->mesh_state, MESH_ACTIVE); atomic_set(&bat_priv->mesh_state, MESH_ACTIVE);
goto end; goto end;
......
...@@ -201,6 +201,7 @@ struct bat_priv { ...@@ -201,6 +201,7 @@ struct bat_priv {
struct delayed_work orig_work; struct delayed_work orig_work;
struct delayed_work vis_work; struct delayed_work vis_work;
struct gw_node __rcu *curr_gw; /* rcu protected pointer */ struct gw_node __rcu *curr_gw; /* rcu protected pointer */
atomic_t gw_reselect;
struct hard_iface __rcu *primary_if; /* rcu protected pointer */ struct hard_iface __rcu *primary_if; /* rcu protected pointer */
struct vis_info *my_vis_info; struct vis_info *my_vis_info;
}; };
......
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