From b4e1705417c6cc7d46d9020259a2c8f457cf82bd Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Wed, 15 Jun 2011 09:41:37 +0200 Subject: batman-adv: Reduce usage of char char was used in different places to store information without really using the characteristics of that data type or by ignoring the fact that char has not a well defined signedness. Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/batman-adv/gateway_client.c') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 24aee561f3d..7248de2e66d 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -360,7 +360,7 @@ void gw_node_purge(struct bat_priv *bat_priv) struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; - char do_deselect = 0; + int do_deselect = 0; curr_gw = gw_get_selected_gw_node(bat_priv); -- cgit v1.2.3-18-g5258 From 2265c141086474bbae55a5bb3afa1ebb78ccaa7c Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Wed, 27 Apr 2011 00:22:00 +0200 Subject: 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: Antonio Quartulli Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 136 +++++++++++++++++++++++----------------- 1 file changed, 80 insertions(+), 56 deletions(-) (limited to 'net/batman-adv/gateway_client.c') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 7248de2e66d..0350c0cd690 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -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; +} - if ((curr_gw) && (!curr_gw_tmp)) - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - 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); +void gw_election(struct bat_priv *bat_priv) +{ + struct gw_node *curr_gw = NULL, *next_gw = NULL; + struct neigh_node *router = NULL; - 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: - rcu_read_unlock(); + if ((curr_gw) && (!next_gw)) { + 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: 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) -- cgit v1.2.3-18-g5258 From 19595e054d35820e026caac314414e435287e3ae Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Sun, 12 Jun 2011 11:58:58 +0200 Subject: batman-adv: throw uevent in userspace on gateway add/change/del event In case of new default gw, changing the default gw or deleting the default gw a uevent is triggered with type=gw, action=add/change/del and data={GW_ORIG_ADDRESS} (if any). Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/batman-adv/gateway_client.c') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 0350c0cd690..6381864c1ca 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -179,6 +179,7 @@ void gw_election(struct bat_priv *bat_priv) { struct gw_node *curr_gw = NULL, *next_gw = NULL; struct neigh_node *router = NULL; + char gw_addr[18] = { '\0' }; /** * The batman daemon checks here if we already passed a full originator @@ -200,6 +201,8 @@ void gw_election(struct bat_priv *bat_priv) goto out; if (next_gw) { + sprintf(gw_addr, "%pM", next_gw->orig_node->orig); + router = orig_node_get_router(next_gw->orig_node); if (!router) { gw_deselect(bat_priv); @@ -210,12 +213,14 @@ void gw_election(struct bat_priv *bat_priv) if ((curr_gw) && (!next_gw)) { bat_dbg(DBG_BATMAN, bat_priv, "Removing selected gateway - no gateway in range\n"); + throw_uevent(bat_priv, UEV_GW, UEV_DEL, NULL); } 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); + throw_uevent(bat_priv, UEV_GW, UEV_ADD, gw_addr); } else { bat_dbg(DBG_BATMAN, bat_priv, "Changing route to gateway %pM " @@ -223,6 +228,7 @@ void gw_election(struct bat_priv *bat_priv) next_gw->orig_node->orig, next_gw->orig_node->gw_flags, router->tq_avg); + throw_uevent(bat_priv, UEV_GW, UEV_CHANGE, gw_addr); } gw_select(bat_priv, next_gw); -- cgit v1.2.3-18-g5258 From 43676ab590c3f8686fd047d34c3e33803eef71f0 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 26 Apr 2011 21:31:45 +0200 Subject: batman-adv: improved gateway tq-based selection If a client issues a DHCPREQUEST for renewal, the packet is dropped if the old destination (the old gateway for the client) TQ is smaller than the current best gateway TQ less GW_THRESHOLD Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner Signed-off-by: Sven Eckelmann --- net/batman-adv/gateway_client.c | 94 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) (limited to 'net/batman-adv/gateway_client.c') diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 6381864c1ca..8b25b52a476 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -25,11 +25,17 @@ #include "gateway_common.h" #include "hard-interface.h" #include "originator.h" +#include "routing.h" #include #include #include #include +/* This is the offset of the options field in a dhcp packet starting at + * the beginning of the dhcp header */ +#define DHCP_OPTIONS_OFFSET 240 +#define DHCP_REQUEST 3 + static void gw_node_free_ref(struct gw_node *gw_node) { if (atomic_dec_and_test(&gw_node->refcount)) @@ -509,14 +515,75 @@ out: return ret; } -int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) +static bool is_type_dhcprequest(struct sk_buff *skb, int header_len) +{ + int ret = false; + unsigned char *p; + int pkt_len; + + if (skb_linearize(skb) < 0) + goto out; + + pkt_len = skb_headlen(skb); + + if (pkt_len < header_len + DHCP_OPTIONS_OFFSET + 1) + goto out; + + p = skb->data + header_len + DHCP_OPTIONS_OFFSET; + pkt_len -= header_len + DHCP_OPTIONS_OFFSET + 1; + + /* Access the dhcp option lists. Each entry is made up by: + * - octect 1: option type + * - octect 2: option data len (only if type != 255 and 0) + * - octect 3: option data */ + while (*p != 255 && !ret) { + /* p now points to the first octect: option type */ + if (*p == 53) { + /* type 53 is the message type option. + * Jump the len octect and go to the data octect */ + if (pkt_len < 2) + goto out; + p += 2; + + /* check if the message type is what we need */ + if (*p == DHCP_REQUEST) + ret = true; + break; + } else if (*p == 0) { + /* option type 0 (padding), just go forward */ + if (pkt_len < 1) + goto out; + pkt_len--; + p++; + } else { + /* This is any other option. So we get the length... */ + if (pkt_len < 1) + goto out; + pkt_len--; + p++; + + /* ...and then we jump over the data */ + if (pkt_len < *p) + goto out; + pkt_len -= *p; + p += (*p); + } + } +out: + return ret; +} + +int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb, + struct orig_node *old_gw) { struct ethhdr *ethhdr; struct iphdr *iphdr; struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; struct gw_node *curr_gw; + struct neigh_node *neigh_curr = NULL, *neigh_old = NULL; unsigned int header_len = 0; + int ret = 1; if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) return 0; @@ -584,7 +651,30 @@ int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) if (!curr_gw) return 0; + /* If old_gw != NULL then this packet is unicast. + * So, at this point we have to check the message type: if it is a + * DHCPREQUEST we have to decide whether to drop it or not */ + if (old_gw && curr_gw->orig_node != old_gw) { + if (is_type_dhcprequest(skb, header_len)) { + /* If the dhcp packet has been sent to a different gw, + * we have to evaluate whether the old gw is still + * reliable enough */ + neigh_curr = find_router(bat_priv, curr_gw->orig_node, + NULL); + neigh_old = find_router(bat_priv, old_gw, NULL); + if (!neigh_curr || !neigh_old) + goto free_neigh; + if (neigh_curr->tq_avg - neigh_old->tq_avg < + GW_THRESHOLD) + ret = -1; + } + } +free_neigh: + if (neigh_old) + neigh_node_free_ref(neigh_old); + if (neigh_curr) + neigh_node_free_ref(neigh_curr); if (curr_gw) gw_node_free_ref(curr_gw); - return 1; + return ret; } -- cgit v1.2.3-18-g5258