Hi,
batman-adv still lacks the well-known gateway functionality the batman daemon offered since quite a while. Since batman-adv works sufficiently well without it and due to the ongoing debate whether a layer 2 mesh protocol should interfere with layer 3 this topic has been neglected for a while. In multi-gateway environments proper gateway support is a must have. Therefore I hereby propose a set of patches to add this functionality. Comments welcome!
What you get: * The first patch will add gateway announce / handling support to the protocol. You will have additional /proc files to switch gateway modes, get a list of gateways in the network and see the currently selected best gateway. * The second patch simply adds batctl support to conveniently configure the gateway setup. * The third patch checks whether locally received packets are DHCP queries and forwards them via uncicast to the best gateway instead of broadcasting them.
Note: * These patches change the routing protocol, therefore the compat version is increased. This (intentionally) breaks interoperability with older batman-adv versions! * Only DHCP traffic gets redirected to the best gateway - no other traffic is affected. This is part of the compromise we achieved during the last discussions. * IPv6 support is still missing but should be fairly easy to add. Any volunteers ?
Regards, Marek
Via the /proc filesystem you can change the gateway mode of a node to server or client (default is: off). Servers will announce there bandwidth, so that clients can choose their best gateway.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- batman-adv-kernelland/Makefile.kbuild | 2 +- batman-adv-kernelland/gateway_client.c | 335 ++++++++++++++++++++++++++++++++ batman-adv-kernelland/gateway_client.h | 29 +++ batman-adv-kernelland/gateway_common.c | 276 ++++++++++++++++++++++++++ batman-adv-kernelland/gateway_common.h | 34 ++++ batman-adv-kernelland/main.c | 6 + batman-adv-kernelland/originator.c | 6 +- batman-adv-kernelland/packet.h | 4 +- batman-adv-kernelland/proc.c | 144 ++++++++++++++ batman-adv-kernelland/proc.h | 2 + batman-adv-kernelland/routing.c | 13 ++- batman-adv-kernelland/send.c | 3 + batman-adv-kernelland/types.h | 14 +- 13 files changed, 860 insertions(+), 8 deletions(-) create mode 100644 batman-adv-kernelland/gateway_client.c create mode 100644 batman-adv-kernelland/gateway_client.h create mode 100644 batman-adv-kernelland/gateway_common.c create mode 100644 batman-adv-kernelland/gateway_common.h
diff --git a/batman-adv-kernelland/Makefile.kbuild b/batman-adv-kernelland/Makefile.kbuild index f75d4af..dc357e7 100644 --- a/batman-adv-kernelland/Makefile.kbuild +++ b/batman-adv-kernelland/Makefile.kbuild @@ -32,4 +32,4 @@ EXTRA_CFLAGS += -DREVISION_VERSION="r$(REVISION)" endif
obj-m += batman-adv.o -batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o $(shell [ "2" -eq "$(VERSION)" ] && [ "6" -eq "$(PATCHLEVEL)" ] && [ "$(SUBLEVEL)" -le "28" ] && echo bat_printk.o) +batman-adv-objs := main.o proc.o send.o routing.o soft-interface.o device.o translation-table.o bitarray.o hash.o ring_buffer.o vis.o hard-interface.o aggregation.o originator.o gateway_common.o gateway_client.o $(shell [ "2" -eq "$(VERSION)" ] && [ "6" -eq "$(PATCHLEVEL)" ] && [ "$(SUBLEVEL)" -le "28" ] && echo bat_printk.o) diff --git a/batman-adv-kernelland/gateway_client.c b/batman-adv-kernelland/gateway_client.c new file mode 100644 index 0000000..55789ad --- /dev/null +++ b/batman-adv-kernelland/gateway_client.c @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2009 B.A.T.M.A.N. contributors: + * Marek Lindner + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "gateway_client.h" +#include "gateway_common.h" + +LIST_HEAD(gw_list); +DEFINE_SPINLOCK(curr_gw_lock); +DEFINE_SPINLOCK(gw_list_lock); +atomic_t gw_clnt_class; +static struct gw_node *curr_gateway; + +void gw_deselect(void) +{ + spin_lock(&curr_gw_lock); + curr_gateway = NULL; + spin_unlock(&curr_gw_lock); +} + +void gw_election(void) +{ + struct gw_node *gw_node, *curr_gw_tmp = NULL; + uint8_t max_tq = 0; + uint32_t max_gw_factor = 0, tmp_gw_factor = 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(&gw_clnt_class) == 0) + return; + + if (curr_gateway) + return; + + rcu_read_lock(); + if (list_empty(&gw_list)) { + rcu_read_unlock(); + + if (curr_gateway) { + bat_dbg(DBG_BATMAN, + "Removing selected gateway - no gateway in range\n"); + gw_deselect(); + } + + return; + } + + list_for_each_entry_rcu(gw_node, &gw_list, list) { + if (!gw_node->orig_node->router) + continue; + + if (gw_node->deleted) + continue; + + switch (atomic_read(&gw_clnt_class)) { + case 1: /* fast connection */ + gw_srv_class_to_kbit(gw_node->orig_node->gw_flags, + &down, &up); + + tmp_gw_factor = (gw_node->orig_node->router->tq_avg * + gw_node->orig_node->router->tq_avg * + down * 100 * 100) / + (TQ_LOCAL_WINDOW_SIZE * + TQ_LOCAL_WINDOW_SIZE * 64); + + if ((tmp_gw_factor > max_gw_factor) || + ((tmp_gw_factor == max_gw_factor) && + (gw_node->orig_node->router->tq_avg > max_tq))) + curr_gw_tmp = gw_node; + break; + + default: /** + * 2: stable connection (use best statistic) + * 3: fast-switch (use best statistic but change as + * soon as a better gateway appears) + * XX: late-switch (use best statistic but change as + * soon as a better gateway appears which has + * $routing_class more tq points) + **/ + if (gw_node->orig_node->router->tq_avg > max_tq) + curr_gw_tmp = gw_node; + break; + } + + if (gw_node->orig_node->router->tq_avg > max_tq) + max_tq = gw_node->orig_node->router->tq_avg; + + if (tmp_gw_factor > max_gw_factor) + max_gw_factor = tmp_gw_factor; + } + rcu_read_unlock(); + + spin_lock(&curr_gw_lock); + if (curr_gateway != curr_gw_tmp) { + if ((curr_gateway) && (!curr_gw_tmp)) + bat_dbg(DBG_BATMAN, + "Removing selected gateway - no gateway in range\n"); + else if ((!curr_gateway) && (curr_gw_tmp)) + bat_dbg(DBG_BATMAN, + "Adding route to gateway %pM (gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + else + bat_dbg(DBG_BATMAN, + "Changing route to gateway %pM (gw_flags: %i, tq: %i)\n", + curr_gw_tmp->orig_node->orig, + curr_gw_tmp->orig_node->gw_flags, + curr_gw_tmp->orig_node->router->tq_avg); + + curr_gateway = curr_gw_tmp; + } + spin_unlock(&curr_gw_lock); +} + +void gw_check_election(struct orig_node *orig_node) +{ + struct gw_node *curr_gateway_tmp; + uint8_t gw_tq_avg, orig_tq_avg; + + spin_lock(&curr_gw_lock); + curr_gateway_tmp = curr_gateway; + spin_unlock(&curr_gw_lock); + + if (!curr_gateway_tmp) + return; + + /* this node already is the gateway */ + if (curr_gateway_tmp->orig_node == orig_node) + return; + + if (!orig_node->router) + return; + + gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; + orig_tq_avg = orig_node->router->tq_avg; + + /* the TQ value has to be better */ + if (orig_tq_avg < gw_tq_avg) + return; + + /** + * if the routing class is greater than 3 the value tells us how much + * greater the TQ value of the new gateway must be + **/ + if ((atomic_read(&gw_clnt_class) > 3) && + (orig_tq_avg - gw_tq_avg < atomic_read(&gw_clnt_class))) + return; + + bat_dbg(DBG_BATMAN, + "Restarting gateway selection: better gateway found (tq curr: %i, tq new: %i) \n", + gw_tq_avg, orig_tq_avg); + + gw_deselect(); +} + +static void gw_node_add(struct orig_node *orig_node, uint8_t new_gwflags) +{ + struct gw_node *gw_node; + int down, up; + + gw_node = kmalloc(sizeof(struct gw_node), GFP_ATOMIC); + if (!gw_node) + return; + + memset(gw_node, 0, sizeof(struct gw_node)); + INIT_LIST_HEAD(&gw_node->list); + gw_node->orig_node = orig_node; + + list_add_tail_rcu(&gw_node->list, &gw_list); + + gw_srv_class_to_kbit(new_gwflags, &down, &up); + bat_dbg(DBG_BATMAN, + "Found new gateway %pM -> gw_class: %i - %i%s/%i%s\n", + orig_node->orig, new_gwflags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); +} + +void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags) +{ + struct gw_node *gw_node; + + rcu_read_lock(); + list_for_each_entry_rcu(gw_node, &gw_list, list) { + if (gw_node->orig_node != orig_node) + continue; + + bat_dbg(DBG_BATMAN, + "Gateway class of originator %pM changed from %i to %i\n", + orig_node->orig, gw_node->orig_node->gw_flags, + new_gwflags); + + gw_node->deleted = 0; + + if (new_gwflags == 0) { + gw_node->deleted = jiffies; + bat_dbg(DBG_BATMAN, + "Gateway %pM removed from gateway list\n", + orig_node->orig); + + if (gw_node == curr_gateway) + gw_deselect(); + } + + return; + } + rcu_read_unlock(); + + if (new_gwflags == 0) + return; + + gw_node_add(orig_node, new_gwflags); +} + +void gw_node_delete(struct orig_node *orig_node) +{ + return gw_node_update(orig_node, 0); +} + +static void gw_node_free(struct rcu_head *rcu) +{ + struct gw_node *gw_node = container_of(rcu, struct gw_node, rcu); + kfree(gw_node); +} + +void gw_node_purge_deleted(void) +{ + struct gw_node *gw_node, *gw_node_tmp; + unsigned long timeout = (2 * PURGE_TIMEOUT * HZ) / 1000; + + spin_lock(&gw_list_lock); + + list_for_each_entry_safe(gw_node, gw_node_tmp, &gw_list, list) { + if ((gw_node->deleted) && + (time_after(jiffies, gw_node->deleted + timeout))) { + + list_del_rcu(&gw_node->list); + call_rcu(&gw_node->rcu, gw_node_free); + } + } + + spin_unlock(&gw_list_lock); +} + +void gw_node_list_free(void) +{ + struct gw_node *gw_node, *gw_node_tmp; + + spin_lock(&gw_list_lock); + + list_for_each_entry_safe(gw_node, gw_node_tmp, &gw_list, list) { + list_del_rcu(&gw_node->list); + call_rcu(&gw_node->rcu, gw_node_free); + } + + gw_deselect(); + spin_unlock(&gw_list_lock); +} + +static int _write_buffer_text(unsigned char *buff, int bytes_written, + struct gw_node *gw_node) +{ + int down, up; + char gw_str[ETH_STR_LEN], router_str[ETH_STR_LEN]; + + addr_to_string(gw_str, gw_node->orig_node->orig); + addr_to_string(router_str, gw_node->orig_node->router->addr); + gw_srv_class_to_kbit(gw_node->orig_node->gw_flags, &down, &up); + + return sprintf(buff + bytes_written, + "%s %-17s (%3i) %17s [%10s]: %3i - %i%s/%i%s\n", + (curr_gateway == gw_node ? "=>" : " "), + gw_str, + gw_node->orig_node->router->tq_avg, + router_str, + gw_node->orig_node->router->if_incoming->dev, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); +} + +int gw_client_fill_buffer_text(unsigned char *buff, int buff_len) +{ + struct gw_node *gw_node; + int bytes_written = 0, gw_count = 0; + + rcu_read_lock(); + list_for_each_entry_rcu(gw_node, &gw_list, list) { + if (gw_node->deleted) + continue; + + if (!gw_node->orig_node->router) + continue; + + if (buff_len < bytes_written + (2 * ETH_STR_LEN) + 30) + break; + + bytes_written += _write_buffer_text(buff, + bytes_written, + gw_node); + gw_count++; + } + rcu_read_unlock(); + + if (gw_count == 0) + sprintf(buff, "No gateways in range ... \n"); + + return bytes_written; +} diff --git a/batman-adv-kernelland/gateway_client.h b/batman-adv-kernelland/gateway_client.h new file mode 100644 index 0000000..5eb1e4c --- /dev/null +++ b/batman-adv-kernelland/gateway_client.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 B.A.T.M.A.N. contributors: + * Marek Lindner + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +extern atomic_t gw_clnt_class; + +void gw_deselect(void); +void gw_election(void); +void gw_check_election(struct orig_node *orig_node); +void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags); +void gw_node_delete(struct orig_node *orig_node); +void gw_node_purge_deleted(void); +void gw_node_list_free(void); +int gw_client_fill_buffer_text(unsigned char *buff, int buff_len); diff --git a/batman-adv-kernelland/gateway_common.c b/batman-adv-kernelland/gateway_common.c new file mode 100644 index 0000000..1d7fd2c --- /dev/null +++ b/batman-adv-kernelland/gateway_common.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2009 B.A.T.M.A.N. contributors: + * Marek Lindner + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +#include "main.h" +#include "gateway_common.h" +#include "gateway_client.h" + +atomic_t gw_mode; +atomic_t gw_srv_class; + +/* calculates the gateway class from kbit */ +void kbit_to_gw_srv_class(int down, int up, long *gw_srv_class) +{ + int mdown = 0, tdown, tup, difference; + uint8_t sbit, part; + + *gw_srv_class = 0; + difference = 0x0FFFFFFF; + + /* test all downspeeds */ + for (sbit = 0; sbit < 2; sbit++) { + for (part = 0; part < 16; part++) { + tdown = 32 * (sbit + 2) * (1 << part); + + if (abs(tdown - down) < difference) { + *gw_srv_class = (sbit << 7) + (part << 3); + difference = abs(tdown - down); + mdown = tdown; + } + } + } + + /* test all upspeeds */ + difference = 0x0FFFFFFF; + + for (part = 0; part < 8; part++) { + tup = ((part + 1) * (mdown)) / 8; + + if (abs(tup - up) < difference) { + *gw_srv_class = (*gw_srv_class & 0xF8) | part; + difference = abs(tup - up); + } + } +} + +/* returns the up and downspeeds in kbit, calculated from the class */ +void gw_srv_class_to_kbit(uint8_t gw_srv_class, int *down, int *up) +{ + char sbit = (gw_srv_class & 0x80) >> 7; + char dpart = (gw_srv_class & 0x7C) >> 3; + char upart = (gw_srv_class & 0x07); + + if (!gw_srv_class) { + *down = 0; + *up = 0; + return; + } + + *down = 32 * (sbit + 2) * (1 << dpart); + *up = ((upart + 1) * (*down)) / 8; +} + +static bool parse_gw_mode_tok(char *tokptr, long *gw_mode_tmp, + char **gw_mode_tmp_str, long *gw_clnt_class_tmp, + long *up, long *down) +{ + int ret; + char *slash_ptr, *tmp_ptr; + + switch (*gw_mode_tmp) { + case GW_MODE_CLIENT: + ret = strict_strtol(tokptr, 10, gw_clnt_class_tmp); + if (ret) { + printk(KERN_ERR "Client class of gateway mode invalid: %s\n", + tokptr); + return false; + } + + if (*gw_clnt_class_tmp > TQ_MAX_VALUE) { + printk(KERN_ERR "Client class of gateway mode greater than %i: %ld\n", + TQ_MAX_VALUE, *gw_clnt_class_tmp); + return false; + } + + break; + case GW_MODE_SERVER: + slash_ptr = strchr(tokptr, '/'); + if (slash_ptr) + *slash_ptr = 0; + + ret = strict_strtol(tokptr, 10, down); + if (ret) { + printk(KERN_ERR "Download speed of gateway mode invalid: %s\n", + tokptr); + return false; + } + + tmp_ptr = tokptr + strlen(tokptr) - 4; + + if ((strlen(tokptr) > 4) && + ((strncmp(tmp_ptr, "MBit", 4) == 0) || + (strncmp(tmp_ptr, "mbit", 4) == 0) || + (strncmp(tmp_ptr, "Mbit", 4) == 0))) + *down *= 1024; + + /* we also got some upload info */ + if (slash_ptr) { + ret = strict_strtol(slash_ptr + 1, 10, up); + if (ret) { + printk(KERN_ERR "Upload speed of gateway mode invalid: %s\n", + slash_ptr + 1); + return false; + } + + tmp_ptr = slash_ptr + 1 + strlen(slash_ptr + 1) - 4; + + if ((strlen(slash_ptr + 1) > 4) && + ((strncmp(tmp_ptr, "MBit", 4) == 0) || + (strncmp(tmp_ptr, "mbit", 4) == 0) || + (strncmp(tmp_ptr, "Mbit", 4) == 0))) + *up *= 1024; + + *slash_ptr = '/'; + } + + break; + default: + if (strcmp(tokptr, GW_MODE_OFF_NAME) == 0) { + *gw_mode_tmp = GW_MODE_OFF; + *gw_mode_tmp_str = GW_MODE_OFF_NAME; + } + + if (strcmp(tokptr, GW_MODE_CLIENT_NAME) == 0) { + *gw_mode_tmp = GW_MODE_CLIENT; + *gw_mode_tmp_str = GW_MODE_CLIENT_NAME; + } + + if (strcmp(tokptr, GW_MODE_SERVER_NAME) == 0) { + *gw_mode_tmp = GW_MODE_SERVER; + *gw_mode_tmp_str = GW_MODE_SERVER_NAME; + } + } + + return true; +} + +ssize_t gw_mode_set(const char __user *userbuffer, size_t count) +{ + char *gw_mode_string, *tokptr, *cp; + char *gw_mode_curr_str, *gw_mode_tmp_str = NULL; + int finished, not_copied = 0; + long gw_mode_curr, gw_mode_tmp = GW_MODE_OFF; + long gw_srv_class_tmp = 0, gw_clnt_class_tmp = 0, up = 0, down = 0; + bool ret; + + gw_mode_string = kmalloc(count, GFP_KERNEL); + + if (!gw_mode_string) + return -ENOMEM; + + not_copied = copy_from_user(gw_mode_string, userbuffer, count); + gw_mode_string[count - not_copied - 1] = 0; + + tokptr = gw_mode_string; + gw_mode_curr = atomic_read(&gw_mode); + + for (cp = gw_mode_string, finished = 0; !finished; cp++) { + switch (*cp) { + case 0: + finished = 1; + case ' ': + case '\n': + case '\t': + *cp = 0; + ret = parse_gw_mode_tok(tokptr, &gw_mode_tmp, + &gw_mode_tmp_str, + &gw_clnt_class_tmp, + &up, &down); + + if (!ret) + goto end; + + tokptr = cp + 1; + break; + default: + break; + } + } + + if (!gw_mode_tmp_str) { + printk(KERN_INFO "Gateway mode can only be set to: '%s', '%s' or '%s' - given value: %s\n", + GW_MODE_OFF_NAME, GW_MODE_CLIENT_NAME, + GW_MODE_SERVER_NAME, gw_mode_string); + goto end; + } + + switch (gw_mode_curr) { + case GW_MODE_CLIENT: + gw_mode_curr_str = GW_MODE_CLIENT_NAME; + break; + case GW_MODE_SERVER: + gw_mode_curr_str = GW_MODE_SERVER_NAME; + break; + default: + gw_mode_curr_str = GW_MODE_OFF_NAME; + break; + } + + switch (gw_mode_tmp) { + case GW_MODE_CLIENT: + if ((gw_mode_tmp == GW_MODE_CLIENT) && (!gw_clnt_class_tmp)) + gw_clnt_class_tmp = 20; + + printk(KERN_INFO "Changing gateway mode from: '%s' to: '%s' (gw_clnt_class: %ld)\n", + gw_mode_curr_str, gw_mode_tmp_str, + gw_clnt_class_tmp); + break; + case GW_MODE_SERVER: + if (!down) + down = 2000; + + if (!up) + up = down / 5; + + kbit_to_gw_srv_class(down, up, &gw_srv_class_tmp); + + /** + * the gw class we guessed above might not match the given + * speeds, hence we need to calculate it back to show the + * number that is going to be propagated + **/ + gw_srv_class_to_kbit((uint8_t)gw_srv_class_tmp, + (int *)&down, (int *)&up); + + printk(KERN_INFO + "Changing gateway mode from: '%s' to: '%s' (gw_srv_class: %ld -> propagating: %ld%s/%ld%s)\n", + gw_mode_curr_str, gw_mode_tmp_str, + gw_srv_class_tmp, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + break; + default: + printk(KERN_INFO "Changing gateway mode from: '%s' to: '%s'\n", + gw_mode_curr_str, gw_mode_tmp_str); + break; + } + + atomic_set(&gw_mode, gw_mode_tmp); + atomic_set(&gw_srv_class, gw_srv_class_tmp); + atomic_set(&gw_clnt_class, gw_clnt_class_tmp); + + if (gw_clnt_class_tmp == 0) + gw_deselect(); + +end: + kfree(gw_mode_string); + return count; +} diff --git a/batman-adv-kernelland/gateway_common.h b/batman-adv-kernelland/gateway_common.h new file mode 100644 index 0000000..365cd00 --- /dev/null +++ b/batman-adv-kernelland/gateway_common.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 B.A.T.M.A.N. contributors: + * Marek Lindner + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA + * + */ + +enum gw_modes { + GW_MODE_OFF, + GW_MODE_CLIENT, + GW_MODE_SERVER, +}; + +#define GW_MODE_OFF_NAME "off" +#define GW_MODE_CLIENT_NAME "client" +#define GW_MODE_SERVER_NAME "server" + +extern atomic_t gw_mode; +extern atomic_t gw_srv_class; + +void gw_srv_class_to_kbit(uint8_t gw_class, int *down, int *up); +ssize_t gw_mode_set(const char __user *userbuffer, size_t count); diff --git a/batman-adv-kernelland/main.c b/batman-adv-kernelland/main.c index 1d80ea3..a64f070 100644 --- a/batman-adv-kernelland/main.c +++ b/batman-adv-kernelland/main.c @@ -28,6 +28,8 @@ #include "device.h" #include "translation-table.h" #include "hard-interface.h" +#include "gateway_common.h" +#include "gateway_client.h" #include "types.h" #include "vis.h" #include "hash.h" @@ -85,6 +87,9 @@ int init_module(void) atomic_set(&vis_interval, 1000);/* TODO: raise this later, this is only * for debugging now. */ atomic_set(&aggregation_enabled, 1); + atomic_set(&gw_mode, GW_MODE_OFF); + atomic_set(&gw_srv_class, 0); + atomic_set(&gw_clnt_class, 0);
/* the name should not be longer than 10 chars - see * http://lwn.net/Articles/23634/ */ @@ -191,6 +196,7 @@ void shutdown_module(void)
/* TODO: unregister BATMAN pack */
+ gw_node_list_free(); originator_free();
hna_local_free(); diff --git a/batman-adv-kernelland/originator.c b/batman-adv-kernelland/originator.c index cff433e..a9ba24c 100644 --- a/batman-adv-kernelland/originator.c +++ b/batman-adv-kernelland/originator.c @@ -27,7 +27,7 @@ #include "translation-table.h" #include "routing.h" #include "compat.h" - +#include "gateway_client.h"
static DECLARE_DELAYED_WORK(purge_orig_wq, purge_orig);
@@ -241,6 +241,8 @@ void purge_orig(struct work_struct *work) while (hash_iterate(orig_hash, &hashit)) { orig_node = hashit.bucket->data; if (purge_orig_node(orig_node)) { + if (orig_node->gw_flags) + gw_node_delete(orig_node); hash_remove_bucket(orig_hash, &hashit); free_orig_node(orig_node); } @@ -248,5 +250,7 @@ void purge_orig(struct work_struct *work)
spin_unlock_irqrestore(&orig_hash_lock, flags);
+ gw_node_purge_deleted(); + gw_election(); start_purge_timer(); } diff --git a/batman-adv-kernelland/packet.h b/batman-adv-kernelland/packet.h index ad006ce..b543b03 100644 --- a/batman-adv-kernelland/packet.h +++ b/batman-adv-kernelland/packet.h @@ -28,7 +28,7 @@ #define BAT_VIS 0x05
/* this file is included by batctl which needs these defines */ -#define COMPAT_VERSION 8 +#define COMPAT_VERSION 9 #define DIRECTLINK 0x40 #define VIS_SERVER 0x20
@@ -53,6 +53,8 @@ struct batman_packet { uint8_t prev_sender[6]; uint8_t ttl; uint8_t num_hna; + uint8_t gw_flags; /* flags related to gateway class */ + uint8_t align; } __attribute__((packed));
#define BAT_PACKET_LEN sizeof(struct batman_packet) diff --git a/batman-adv-kernelland/proc.c b/batman-adv-kernelland/proc.c index 1bf493f..747ed5f 100644 --- a/batman-adv-kernelland/proc.c +++ b/batman-adv-kernelland/proc.c @@ -28,6 +28,8 @@ #include "hash.h" #include "vis.h" #include "compat.h" +#include "gateway_common.h" +#include "gateway_client.h"
static struct proc_dir_entry *proc_batman_dir, *proc_interface_file; static struct proc_dir_entry *proc_orig_interval_file, *proc_originators_file; @@ -35,6 +37,7 @@ static struct proc_dir_entry *proc_transt_local_file; static struct proc_dir_entry *proc_transt_global_file; static struct proc_dir_entry *proc_vis_srv_file, *proc_vis_data_file; static struct proc_dir_entry *proc_aggr_file; +static struct proc_dir_entry *proc_gw_mode_file, *proc_gw_srv_list_file;
static int proc_interfaces_read(struct seq_file *seq, void *offset) { @@ -462,6 +465,99 @@ static int proc_aggr_open(struct inode *inode, struct file *file) return single_open(file, proc_aggr_read, NULL); }
+static int proc_gw_mode_read(struct seq_file *seq, void *offset) +{ + int down, up; + long gw_mode_curr = atomic_read(&gw_mode); + uint8_t gw_srv_class_curr = (uint8_t)atomic_read(&gw_srv_class); + + gw_srv_class_to_kbit(gw_srv_class_curr, &down, &up); + + seq_printf(seq, "[%c] %s\n", + (gw_mode_curr == GW_MODE_OFF) ? 'x' : ' ', + GW_MODE_OFF_NAME); + + if (gw_mode_curr == GW_MODE_CLIENT) + seq_printf(seq, "[x] %s (gw_clnt_class: %i)\n", + GW_MODE_CLIENT_NAME, + atomic_read(&gw_clnt_class)); + else + seq_printf(seq, "[ ] %s\n", GW_MODE_CLIENT_NAME); + + if (gw_mode_curr == GW_MODE_SERVER) + seq_printf(seq, + "[x] %s (gw_srv_class: %i -> propagating: %i%s/%i%s)\n", + GW_MODE_SERVER_NAME, + gw_srv_class_curr, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + else + seq_printf(seq, "[ ] %s\n", GW_MODE_SERVER_NAME); + + return 0; +} + +static int proc_gw_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_gw_mode_read, NULL); +} + +static ssize_t proc_gw_mode_write(struct file *instance, + const char __user *userbuffer, + size_t count, loff_t *data) +{ + return gw_mode_set(userbuffer, count); +} + +static int proc_gw_srv_list_read(struct seq_file *seq, void *offset) +{ + char *buff; + int buffsize = 4096; + + buff = kmalloc(buffsize, GFP_KERNEL); + if (!buff) + return 0; + + rcu_read_lock(); + if (list_empty(&if_list)) { + rcu_read_unlock(); + seq_printf(seq, + "BATMAN disabled - please specify interfaces to enable it\n"); + goto end; + } + + if (((struct batman_if *)if_list.next)->if_active != IF_ACTIVE) { + rcu_read_unlock(); + seq_printf(seq, + "BATMAN disabled - primary interface not active\n"); + goto end; + } + + seq_printf(seq, + " %-12s (%s/%i) %17s [%10s]: gw_srv_class ... [B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%s] \n", + "Gateway", "#", TQ_MAX_VALUE, "Nexthop", + "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, + ((struct batman_if *)if_list.next)->dev, + ((struct batman_if *)if_list.next)->addr_str); + + rcu_read_unlock(); + + gw_client_fill_buffer_text(buff, buffsize); + seq_printf(seq, "%s", buff); + +end: + kfree(buff); + return 0; +} + +static int proc_gw_srv_list_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_gw_srv_list_read, NULL); +} + + /* satisfying different prototypes ... */ static ssize_t proc_dummy_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) @@ -469,6 +565,24 @@ static ssize_t proc_dummy_write(struct file *file, const char __user *buffer, return count; }
+static const struct file_operations proc_gw_srv_list_fops = { + .owner = THIS_MODULE, + .open = proc_gw_srv_list_open, + .read = seq_read, + .write = proc_dummy_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_gw_mode_fops = { + .owner = THIS_MODULE, + .open = proc_gw_mode_open, + .read = seq_read, + .write = proc_gw_mode_write, + .llseek = seq_lseek, + .release = single_release, +}; + static const struct file_operations proc_aggr_fops = { .owner = THIS_MODULE, .open = proc_aggr_open, @@ -567,6 +681,12 @@ void cleanup_procfs(void) if (proc_aggr_file) remove_proc_entry(PROC_FILE_AGGR, proc_batman_dir);
+ if (proc_gw_mode_file) + remove_proc_entry(PROC_FILE_GW_MODE, proc_batman_dir); + + if (proc_gw_srv_list_file) + remove_proc_entry(PROC_FILE_GW_SRV_LIST, proc_batman_dir); + if (proc_batman_dir) #ifdef __NET_NET_NAMESPACE_H remove_proc_entry(PROC_ROOT_DIR, init_net.proc_net); @@ -671,5 +791,29 @@ int setup_procfs(void) return -EFAULT; }
+ proc_gw_mode_file = create_proc_entry(PROC_FILE_GW_MODE, + S_IWUSR | S_IRUGO, + proc_batman_dir); + if (proc_gw_mode_file) { + proc_gw_mode_file->proc_fops = &proc_gw_mode_fops; + } else { + printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", + PROC_ROOT_DIR, PROC_FILE_GW_MODE); + cleanup_procfs(); + return -EFAULT; + } + + proc_gw_srv_list_file = create_proc_entry(PROC_FILE_GW_SRV_LIST, + S_IWUSR | S_IRUGO, + proc_batman_dir); + if (proc_gw_srv_list_file) { + proc_gw_srv_list_file->proc_fops = &proc_gw_srv_list_fops; + } else { + printk(KERN_ERR "batman-adv: Registering the '/proc/net/%s/%s' file failed\n", + PROC_ROOT_DIR, PROC_FILE_GW_SRV_LIST); + cleanup_procfs(); + return -EFAULT; + } + return 0; } diff --git a/batman-adv-kernelland/proc.h b/batman-adv-kernelland/proc.h index cd690e0..af38d40 100644 --- a/batman-adv-kernelland/proc.h +++ b/batman-adv-kernelland/proc.h @@ -34,6 +34,8 @@ #define PROC_FILE_VIS_SRV "vis_server" #define PROC_FILE_VIS_DATA "vis_data" #define PROC_FILE_AGGR "aggregate_ogm" +#define PROC_FILE_GW_MODE "gateway_mode" +#define PROC_FILE_GW_SRV_LIST "gateway_srv_list"
void cleanup_procfs(void); int setup_procfs(void); diff --git a/batman-adv-kernelland/routing.c b/batman-adv-kernelland/routing.c index 2eb932f..da6a779 100644 --- a/batman-adv-kernelland/routing.c +++ b/batman-adv-kernelland/routing.c @@ -33,6 +33,7 @@ #include "vis.h" #include "aggregation.h" #include "compat.h" +#include "gateway_client.h"
DECLARE_WAIT_QUEUE_HEAD(thread_wait);
@@ -306,10 +307,20 @@ static void update_orig(struct orig_node *orig_node, struct ethhdr *ethhdr, goto update_hna;
update_routes(orig_node, neigh_node, hna_buff, tmp_hna_buff_len); - return; + goto update_gw;
update_hna: update_routes(orig_node, orig_node->router, hna_buff, tmp_hna_buff_len); + +update_gw: + if (orig_node->gw_flags != batman_packet->gw_flags) + gw_node_update(orig_node, batman_packet->gw_flags); + + orig_node->gw_flags = batman_packet->gw_flags; + + /* restart gateway selection if fast or late switching was enabled */ + if ((orig_node->gw_flags) && (atomic_read(&gw_clnt_class) > 2)) + gw_check_election(orig_node); }
static char count_real_packets(struct ethhdr *ethhdr, diff --git a/batman-adv-kernelland/send.c b/batman-adv-kernelland/send.c index edfdd5d..a40e8b8 100644 --- a/batman-adv-kernelland/send.c +++ b/batman-adv-kernelland/send.c @@ -28,6 +28,7 @@ #include "types.h" #include "vis.h" #include "aggregation.h" +#include "gateway_common.h"
#include "compat.h"
@@ -279,6 +280,8 @@ void schedule_own_packet(struct batman_if *batman_if) else batman_packet->flags = 0;
+ batman_packet->gw_flags = (uint8_t)atomic_read(&gw_srv_class); + /* could be read by receive_bat_packet() */ atomic_inc(&batman_if->seqno);
diff --git a/batman-adv-kernelland/types.h b/batman-adv-kernelland/types.h index dec1b54..495d94a 100644 --- a/batman-adv-kernelland/types.h +++ b/batman-adv-kernelland/types.h @@ -43,7 +43,6 @@ struct batman_if { unsigned char *packet_buff; int packet_len; struct rcu_head rcu; - };
struct orig_node { /* structure for orig_list maintaining nodes of mesh */ @@ -55,10 +54,10 @@ struct orig_node { /* structure for orig_list maintaining nodes of uint8_t tq_own; int tq_asym_penalty; unsigned long last_valid; /* when last packet from this node was received */ -/* uint8_t gwflags; * flags related to gateway functions: gateway class */ - uint8_t flags; /* for now only VIS_SERVER flag. */ + uint8_t gw_flags; /* flags related to gateway class */ + uint8_t flags; /* for now only VIS_SERVER flag. */ unsigned char *hna_buff; - int16_t hna_buff_len; + int16_t hna_buff_len; uint16_t last_real_seqno; /* last and best known squence number */ uint8_t last_ttl; /* ttl of last received packet */ TYPE_OF_WORD bcast_bits[NUM_WORDS]; @@ -66,6 +65,13 @@ struct orig_node { /* structure for orig_list maintaining nodes of struct list_head neigh_list; };
+struct gw_node { + struct list_head list; + struct orig_node *orig_node; + unsigned long deleted; + struct rcu_head rcu; +}; + struct neigh_node { struct list_head list; uint8_t addr[ETH_ALEN];
--- batctl/main.c | 10 ++++++++++ batctl/man/batctl.8 | 6 ++++++ batctl/proc.c | 16 ++++++++++++++++ batctl/proc.h | 8 ++++---- 4 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/batctl/main.c b/batctl/main.c index 8be1d05..6e4493d 100644 --- a/batctl/main.c +++ b/batctl/main.c @@ -46,6 +46,8 @@ void print_usage(void) { printf(" \tinterval|it [orig_interval] \tdisplay or modify the originator interval in ms\n"); printf(" \tloglevel|ll [level] \tdisplay or modify the log level\n"); printf(" \tlog|l \tread the log produced by the kernel module\n"); + printf(" \tgw_mode|gw [mode] \tdisplay or modify the gateway mode\n"); + printf(" \tgw_srv_list|gwl \tdisplay the gateway server list\n"); printf(" \ttranslocal|tl \tdisplay the local translation table\n"); printf(" \ttransglobal|tg \tdisplay the global translation table\n"); printf(" \tvis_server|vs [enable|disable] \tdisplay or modify the status of the VIS server\n"); @@ -130,6 +132,14 @@ int main(int argc, char **argv)
ret = vis_data(argc - 1, argv + 1);
+ } else if ((strcmp(argv[1], "gw_mode") == 0) || (strcmp(argv[1], "gw") == 0)) { + + ret = handle_proc_setting(argc - 1, argv + 1, PROC_GW_MODE, gw_mode_usage); + + } else if ((strcmp(argv[1], "gw_srv_list") == 0) || (strcmp(argv[1], "gwl") == 0)) { + + ret = handle_table(argc - 1, argv + 1, PROC_GW_SRV_LIST, gw_srv_list_usage); + } else if ((strcmp(argv[1], "aggregation") == 0) || (strcmp(argv[1], "ag") == 0)) {
ret = handle_proc_setting(argc - 1, argv + 1, PROC_AGGR, aggregation_usage); diff --git a/batctl/man/batctl.8 b/batctl/man/batctl.8 index 304168c..61e7958 100644 --- a/batctl/man/batctl.8 +++ b/batctl/man/batctl.8 @@ -57,6 +57,12 @@ If no parameter is given the current log level settings are displayed otherwise .IP "\fBlog|l\fP " Once started batctl will continuously read the log produced by the kernel module (the amount of log message can be influenced by modifying the log level). Whenever there are new log messages sent by the kernel batctl will display it. Use the "-b" option to let batctl exit after the existing log buffer has been displayed. If "-n" was given batctl will not replace the mac addresses with bat-host names in the output. .br +.IP "\fBgw_mode|gw [off|client|server]\fP" +If no parameter is given the current gateway mode is displayed otherwise the parameter is used to set the gateway mode. +.br +.IP "\fBgw_srv_list|gwl\fP" +Once started batctl will refresh the displayed gateway server list every second. Use the "-b" option to let batctl display the list only once (useful for scripts). If "-n" was given batctl will not replace the mac addresses with bat-host names in the output. +.br .IP "\fBtranslocal|tl\fP" Once started batctl will refresh the displayed local translation table every second. Use the "-b" option to let batctl display the table only once (useful for scripts). If "-n" was given batctl will not replace the mac addresses with bat-host names in the output. .br diff --git a/batctl/proc.c b/batctl/proc.c index d73a9fa..7ae19b4 100644 --- a/batctl/proc.c +++ b/batctl/proc.c @@ -95,6 +95,15 @@ void trans_global_usage(void) printf(" \t -n don't replace mac addresses with bat-host names\n"); }
+void gw_srv_list_usage(void) +{ + printf("Usage: batctl [options] gw_srv_list \n"); + printf("options:\n"); + printf(" \t -b batch mode - read the gateway server list once and quit\n"); + printf(" \t -h print this help\n"); + printf(" \t -n don't replace mac addresses with bat-host names\n"); +} + void orig_interval_usage(void) { printf("Usage: batctl [options] interval \n"); @@ -116,6 +125,13 @@ void aggregation_usage(void) printf(" \t -h print this help\n"); }
+void gw_mode_usage(void) +{ + printf("Usage: batctl [options] gw_mode [mode]\n"); + printf("options:\n"); + printf(" \t -h print this help\n"); +} + int handle_table(int argc, char **argv, char *file_path, void table_usage(void)) { int optchar, read_opt = CLR_CONT_READ | USE_BAT_HOSTS; diff --git a/batctl/proc.h b/batctl/proc.h index ad00136..d867b78 100644 --- a/batctl/proc.h +++ b/batctl/proc.h @@ -19,19 +19,17 @@ * */
- - #define PROC_ROOT_PATH "/proc/net/batman-adv/" #define PROC_INTERFACES "interfaces" #define PROC_ORIGINATORS "originators" #define PROC_ORIG_INTERVAL "orig_interval" -#define PROC_GATEWAYS "gateways" #define PROC_TRANSTABLE_LOCAL "transtable_local" #define PROC_TRANSTABLE_GLOBAL "transtable_global" #define PROC_VIS_SERVER "vis_server" #define PROC_VIS_DATA "vis_data" #define PROC_AGGR "aggregate_ogm" - +#define PROC_GW_MODE "gateway_mode" +#define PROC_GW_SRV_LIST "gateway_srv_list"
int interface(int argc, char **argv);
@@ -41,5 +39,7 @@ void trans_global_usage(void); void orig_interval_usage(void); void vis_server_usage(void); void aggregation_usage(void); +void gw_mode_usage(void); +void gw_srv_list_usage(void); int handle_table(int argc, char **argv, char *file_path, void table_usage(void)); int handle_proc_setting(int argc, char **argv, char *file_path, void setting_usage(void));
If the gateway client mode is active batman-adv will send the broadcasted DHCP requests via unicast to the currently selected best gateway. Therefore attached clients can profit from batman's knowledge about the network topology.
Signed-off-by: Marek Lindner lindner_marek@yahoo.de --- batman-adv-kernelland/gateway_client.c | 45 ++++++++++++++++++++++++++++++++ batman-adv-kernelland/gateway_client.h | 2 + batman-adv-kernelland/soft-interface.c | 17 ++++++++++-- 3 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/batman-adv-kernelland/gateway_client.c b/batman-adv-kernelland/gateway_client.c index 55789ad..434af2b 100644 --- a/batman-adv-kernelland/gateway_client.c +++ b/batman-adv-kernelland/gateway_client.c @@ -20,6 +20,8 @@ #include "main.h" #include "gateway_client.h" #include "gateway_common.h" +#include <linux/ip.h> +#include <linux/udp.h>
LIST_HEAD(gw_list); DEFINE_SPINLOCK(curr_gw_lock); @@ -27,6 +29,20 @@ DEFINE_SPINLOCK(gw_list_lock); atomic_t gw_clnt_class; static struct gw_node *curr_gateway;
+void *gw_get_selected(void) +{ + struct gw_node *curr_gateway_tmp = NULL; + + spin_lock(&curr_gw_lock); + curr_gateway_tmp = curr_gateway; + spin_unlock(&curr_gw_lock); + + if (!curr_gateway_tmp) + return NULL; + + return curr_gateway_tmp->orig_node; +} + void gw_deselect(void) { spin_lock(&curr_gw_lock); @@ -333,3 +349,32 @@ int gw_client_fill_buffer_text(unsigned char *buff, int buff_len)
return bytes_written; } + +bool gw_is_target(struct sk_buff *skb) +{ + struct ethhdr *ethhdr; + struct iphdr *iphdr; + struct udphdr *udphdr; + + if (atomic_read(&gw_mode) != GW_MODE_CLIENT) + return false; + + if (!curr_gateway) + return false; + + ethhdr = (struct ethhdr *)skb->data; + if (ntohs(ethhdr->h_proto) != ETH_P_IP) + return false; + + iphdr = (struct iphdr *)(skb->data + ETH_HLEN); + + if (iphdr->protocol != IPPROTO_UDP) + return false; + + udphdr = (struct udphdr *)(skb->data + ETH_HLEN + (iphdr->ihl * 4)); + + if (ntohs(udphdr->dest) != 67) + return false; + + return true; +} diff --git a/batman-adv-kernelland/gateway_client.h b/batman-adv-kernelland/gateway_client.h index 5eb1e4c..fc7a0df 100644 --- a/batman-adv-kernelland/gateway_client.h +++ b/batman-adv-kernelland/gateway_client.h @@ -21,9 +21,11 @@ extern atomic_t gw_clnt_class;
void gw_deselect(void); void gw_election(void); +void *gw_get_selected(void); void gw_check_election(struct orig_node *orig_node); void gw_node_update(struct orig_node *orig_node, uint8_t new_gwflags); void gw_node_delete(struct orig_node *orig_node); void gw_node_purge_deleted(void); void gw_node_list_free(void); int gw_client_fill_buffer_text(unsigned char *buff, int buff_len); +bool gw_is_target(struct sk_buff *skb); diff --git a/batman-adv-kernelland/soft-interface.c b/batman-adv-kernelland/soft-interface.c index ee9aa39..80f7a23 100644 --- a/batman-adv-kernelland/soft-interface.c +++ b/batman-adv-kernelland/soft-interface.c @@ -26,6 +26,7 @@ #include "translation-table.h" #include "types.h" #include "hash.h" +#include "gateway_client.h" #include <linux/ethtool.h> #include <linux/etherdevice.h> #include "compat.h" @@ -181,6 +182,7 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) uint8_t dstaddr[6]; int data_len = skb->len; unsigned long flags; + bool bcast_dst = false, do_bcast = true;
if (atomic_read(&module_state) != MODULE_ACTIVE) goto dropped; @@ -189,9 +191,14 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) /* TODO: check this for locks */ hna_local_add(ethhdr->h_source);
- /* ethernet packet should be broadcasted */ - if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) { + if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) + bcast_dst = true; + + if ((bcast_dst) && gw_is_target(skb)) + do_bcast = false;
+ /* ethernet packet should be broadcasted */ + if (bcast_dst && do_bcast) { if (my_skb_push(skb, sizeof(struct bcast_packet)) < 0) goto dropped;
@@ -219,8 +226,12 @@ int interface_tx(struct sk_buff *skb, struct net_device *dev) /* unicast packet */ } else { spin_lock_irqsave(&orig_hash_lock, flags); + /* get routing information */ - orig_node = ((struct orig_node *)hash_find(orig_hash, + if (bcast_dst) + orig_node = (struct orig_node *)gw_get_selected(); + else + orig_node = ((struct orig_node *)hash_find(orig_hash, ethhdr->h_dest));
/* check for hna host */
+bool gw_is_target(struct sk_buff *skb) +{
- struct ethhdr *ethhdr;
- struct iphdr *iphdr;
- struct udphdr *udphdr;
- if (atomic_read(&gw_mode) != GW_MODE_CLIENT)
return false;
- if (!curr_gateway)
return false;
- ethhdr = (struct ethhdr *)skb->data;
- if (ntohs(ethhdr->h_proto) != ETH_P_IP)
return false;
- iphdr = (struct iphdr *)(skb->data + ETH_HLEN);
- if (iphdr->protocol != IPPROTO_UDP)
return false;
- udphdr = (struct udphdr *)(skb->data + ETH_HLEN + (iphdr->ihl * 4));
- if (ntohs(udphdr->dest) != 67)
return false;
- return true;
+}
- /* ethernet packet should be broadcasted */
- if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest)) {
- if (is_bcast(ethhdr->h_dest) || is_mcast(ethhdr->h_dest))
bcast_dst = true;
- if ((bcast_dst) && gw_is_target(skb))
do_bcast = false;
Say the DHCP server is running in client mode. It has also been requested to broadcast its replies, not unicast the replies.
http://blogs.technet.com/teamdhcp/archive/2009/02/12/dhcp-broadcast-flag-han...
If i'm reading this code correctly, it will end up sending the DHCP reply messages by unicast to the best gateway, not the DHCP client?
Andrew
On Tuesday 05 January 2010 14:43:49 you wrote:
Say the DHCP server is running in client mode. It has also been requested to broadcast its replies, not unicast the replies.
http://blogs.technet.com/teamdhcp/archive/2009/02/12/dhcp-broadcast-flag-ha ndling-in-windows-7.aspx
If i'm reading this code correctly, it will end up sending the DHCP reply messages by unicast to the best gateway, not the DHCP client?
I don't really get your question. The batman-adv gwclient will encapsulate the DHCP discover / request packets in ethernet unicast headers instead of broadcast headers to make sure only the best gateway receives these broadcasts. The server's replies won't be affected at all.
Regards, Marek
On Tuesday 05 January 2010 14:43:49 you wrote:
Say the DHCP server is running in client mode. It has also been requested to broadcast its replies, not unicast the replies.
http://blogs.technet.com/teamdhcp/archive/2009/02/12/dhcp-broadcast-flag-ha ndling-in-windows-7.aspx
If i'm reading this code correctly, it will end up sending the DHCP reply messages by unicast to the best gateway, not the DHCP client?
I don't really get your question. The batman-adv gwclient will encapsulate the DHCP discover / request packets in ethernet unicast headers instead of broadcast headers to make sure only the best gateway receives these broadcasts. The server's replies won't be affected at all.
Ah, just read the RFC. I though the client was free to choose its port, so it could choose port 67. If that was true, gw_is_target() would return true for the reply and the reply would then be sent to the gateway.
However, the RFC says the client must use port 68, so this can never happen. So there is no problem here...
Andrew
predrag balorda wrote:
predrag balorda predrag.balorda@gmail.com
You can. Just go to https://lists.open-mesh.net/mm/listinfo/b.a.t.m.a.n, enter your mail and click "Unsubscribe or edit options" -> "unsubscribe" and then reply to the mail you have received.
Best regards, Sven
Hi
On Tue, Jan 5, 2010 at 4:44 AM, Marek Lindner lindner_marek@yahoo.dewrote:
- The third patch checks whether locally received packets are DHCP queries
and forwards them via uncicast to the best gateway instead of broadcasting them.
Would it be possible to decide via a more general mechanism, maybe via a
BPF filter, which packets get sent to the gateway? For instance, it would be nice to be able to say that all ARP requests for *.*.*.1 also got sent to the gateway direct :-) This would also make adding IPv6 support trivial, it'd just be another (or a more complex) BPF filter.
donald
Would it be possible to decide via a more general mechanism, maybe via a BPF filter, which packets get sent to the gateway? For instance, it would be nice to be able to say that all ARP requests for *.*.*.1 also got sent to the gateway direct :-) This would also make adding IPv6 support trivial, it'd just be another (or a more complex) BPF filter.
BPF for outgoing packets? Different. I've only ever seen it used for filtering incoming packets. ARP requests for *.*.*.1? I don't get that. There should only be one host in the subnet which matches *.*.*.1/24, so its going to reply anyway. What are you trying to achieve here?
Also, how would you handle the gateway sending back an ICMP redirect because it is the wrong gateway for a given destination, or not a gateway at all? In the network i use most, *.*.*.5/24 happens to be the gateway, not *.*.*.1.
Andrew
On Tue, Jan 5, 2010 at 9:58 AM, Andrew Lunn andrew@lunn.ch wrote:
BPF for outgoing packets? Different. I've only ever seen it used for filtering incoming packets. ARP requests for *.*.*.1? I don't get that. There should only be one host in the subnet which matches *.*.*.1/24, so its going to reply anyway. What are you trying to achieve here?
BPF because it's already in the kernel and has a rule language. Rules to match "all DHCP packets, and IPv6 router solicitations" are easy to write, and people who want to do something different/wierd don't need to rebuild their kernels.
If it makes any more sense, substitute *.*.*.1 for "something matching the IPs I use for gateways". Aim: make it harder for people to configure their PCs to respond to those ARPs and break the network. Although for a mobile node whose DHCP lease hasn't yet expired I can see that causing problems. But if it's just a BPF filter then you can experiment with rules like these fairly easily.
donald
Hi,
despite the general, internal filtering rules it would be great to be able to fetch the best gateway (the gateway with the best BTM-TQ value) via /proc. So people would have the chance to use the basic gatewaying feature with just a switch in batman-adv, while people that want to do more complex filtering could fetch it from /proc and use ebtables on top for example. Maybe even a sorted list of all gateways in /proc would be nice to be able to set up some more advanced (fall-back) scenarios with other measuring methods/tools. And on the other hand we'd have the possibility of batman-adv not interfering too much with the other layers, instead tools explicitly designed for layer 2, 3, ... have an interface to fetch the gateway information then which only batman-adv knew before. I think I've been talking about this partly with Marek a couple of weeks ago before.
Cheers, Linus
On Tue, Jan 05, 2010 at 09:23:42AM +1300, Donald Gordon wrote:
Hi
On Tue, Jan 5, 2010 at 4:44 AM, Marek Lindner lindner_marek@yahoo.dewrote:
- The third patch checks whether locally received packets are DHCP queries
and forwards them via uncicast to the best gateway instead of broadcasting them.
Would it be possible to decide via a more general mechanism, maybe via a
BPF filter, which packets get sent to the gateway? For instance, it would be nice to be able to say that all ARP requests for *.*.*.1 also got sent to the gateway direct :-) This would also make adding IPv6 support trivial, it'd just be another (or a more complex) BPF filter.
donald
B.A.T.M.A.N mailing list B.A.T.M.A.N@lists.open-mesh.net https://lists.open-mesh.net/mm/listinfo/b.a.t.m.a.n
Hi
On Tue, Jan 5, 2010 at 10:45 AM, Linus Lüssing linus.luessing@web.dewrote:
Maybe even a sorted list of all gateways in /proc would be nice to be able to set up some more advanced (fall-back) scenarios with other measuring methods/tools. And on the other hand we'd have the possibility of batman-adv not interfering too much with the other layers, instead tools explicitly designed for layer 2, 3, ... have an interface to fetch the gateway information then which only batman-adv knew before.
That would be even better than what I was suggesting. It would, among other things, make it easy (with the addition of some sort of directory in userspace, or redefining the gateway flags) to find the closest node(s) with some particular service. I'm thinking of things like "all squids that are nearby".
donald
- The third patch checks whether locally received packets are DHCP
queries and forwards them via uncicast to the best gateway instead of broadcasting them.
Can this be made a bit more robust? An easy DoS would be to offer to be a gateway, but not run DHCP. All my near neighbours then fail to get an IP address and i have quiet network with more bandwidth for myself.
Could we inspect the DHCP packet a bit more deeply, look for DHCP discovery packets, unicast 3 in 4 to the best gateway, broadcast 1 in 4 as a fallback.
Andrew
On Tuesday 05 January 2010 14:31:46 Andrew Lunn wrote:
Can this be made a bit more robust? An easy DoS would be to offer to be a gateway, but not run DHCP. All my near neighbours then fail to get an IP address and i have quiet network with more bandwidth for myself.
Good point. Before I had another scheme in mind: DHCP requests are broadcasted but the batman-adv client would filter the responses preferring the selected gateway if its reply is available. Of course, that is more complex to implement.
Could we inspect the DHCP packet a bit more deeply, look for DHCP discovery packets, unicast 3 in 4 to the best gateway, broadcast 1 in 4 as a fallback.
I'm not sure this approach is feasible. As soon as we broadcast a single packet we might end up with a badly chosen gateway.
The batman daemon is able to blacklist broken gateways and switches to another one. We may want to do the same.
Regards, Marek
b.a.t.m.a.n@lists.open-mesh.org