From 5734509c0545ebd95a5b8e3f22a911c1a39ffa1b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 25 Dec 2011 17:52:09 +0100 Subject: babeld: Initial import, for Babel routing protocol. * Initial import of the Babel routing protocol, ported to Quagga. * LICENCE: Update the original LICENCE file to include all known potentially applicable copyright claims. Ask that any future contributors to babeld/ grant MIT/X11 licence to their work. * *.{c,h}: Add GPL headers, in according with the SFLC guidance on dealing with potentially mixed GPL/other licensed work, at: https://www.softwarefreedom.org/resources/2007/gpl-non-gpl-collaboration.html --- babeld/.gitignore | 7 + babeld/LICENCE | 36 ++ babeld/Makefile.am | 29 + babeld/babel_filter.c | 188 ++++++ babeld/babel_filter.h | 54 ++ babeld/babel_interface.c | 778 ++++++++++++++++++++++++ babeld/babel_interface.h | 141 +++++ babeld/babel_main.c | 522 ++++++++++++++++ babeld/babel_main.h | 54 ++ babeld/babel_zebra.c | 299 ++++++++++ babeld/babel_zebra.h | 43 ++ babeld/babeld.c | 766 ++++++++++++++++++++++++ babeld/babeld.conf.sample | 31 + babeld/babeld.h | 136 +++++ babeld/kernel.c | 113 ++++ babeld/kernel.h | 82 +++ babeld/kernel_zebra.c | 461 ++++++++++++++ babeld/message.c | 1456 +++++++++++++++++++++++++++++++++++++++++++++ babeld/message.h | 112 ++++ babeld/neighbour.c | 342 +++++++++++ babeld/neighbour.h | 66 ++ babeld/net.c | 229 +++++++ babeld/net.h | 44 ++ babeld/resend.c | 330 ++++++++++ babeld/resend.h | 77 +++ babeld/route.c | 756 +++++++++++++++++++++++ babeld/route.h | 104 ++++ babeld/source.c | 159 +++++ babeld/source.h | 66 ++ babeld/util.c | 509 ++++++++++++++++ babeld/util.h | 168 ++++++ babeld/xroute.c | 226 +++++++ babeld/xroute.h | 63 ++ 33 files changed, 8447 insertions(+) create mode 100644 babeld/.gitignore create mode 100644 babeld/LICENCE create mode 100644 babeld/Makefile.am create mode 100644 babeld/babel_filter.c create mode 100644 babeld/babel_filter.h create mode 100644 babeld/babel_interface.c create mode 100644 babeld/babel_interface.h create mode 100644 babeld/babel_main.c create mode 100644 babeld/babel_main.h create mode 100644 babeld/babel_zebra.c create mode 100644 babeld/babel_zebra.h create mode 100644 babeld/babeld.c create mode 100644 babeld/babeld.conf.sample create mode 100644 babeld/babeld.h create mode 100644 babeld/kernel.c create mode 100644 babeld/kernel.h create mode 100644 babeld/kernel_zebra.c create mode 100644 babeld/message.c create mode 100644 babeld/message.h create mode 100644 babeld/neighbour.c create mode 100644 babeld/neighbour.h create mode 100644 babeld/net.c create mode 100644 babeld/net.h create mode 100644 babeld/resend.c create mode 100644 babeld/resend.h create mode 100644 babeld/route.c create mode 100644 babeld/route.h create mode 100644 babeld/source.c create mode 100644 babeld/source.h create mode 100644 babeld/util.c create mode 100644 babeld/util.h create mode 100644 babeld/xroute.c create mode 100644 babeld/xroute.h (limited to 'babeld') diff --git a/babeld/.gitignore b/babeld/.gitignore new file mode 100644 index 00000000..8384763a --- /dev/null +++ b/babeld/.gitignore @@ -0,0 +1,7 @@ +* +!*.c +!*.h +!LICENCE +!Makefile.am +!babeld.conf.sample +!.gitignore \ No newline at end of file diff --git a/babeld/LICENCE b/babeld/LICENCE new file mode 100644 index 00000000..9da569dc --- /dev/null +++ b/babeld/LICENCE @@ -0,0 +1,36 @@ +Code in this directory is made available under the following licence: + + --------------------------------------------------------------------------- + Copyright (c) 2007, 2008 by Juliusz Chroboczek + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + --------------------------------------------------------------------------- + +The code also makes calls to and links with the "libzebra" code of Quagga, +in the lib/ directory of this project, which is subject to the GPL licence +as given in the top-level COPYING file included with Quagga. + +Contributors to the code in babeld/ are asked to make their work available +under the same MIT/X11 licence as given immediately above. Please indicate +your assent to this by updating this file and appending the appropriate + + Copyright , + +line to the existing copyright assertion lines in the MIT/X11 licence text +above in this file. diff --git a/babeld/Makefile.am b/babeld/Makefile.am new file mode 100644 index 00000000..468b5a5f --- /dev/null +++ b/babeld/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to produce Makefile.in. + +INCLUDES = @INCLUDES@ -I.. -I$(top_srcdir) -I$(top_srcdir)/lib @SNMP_INCLUDES@ +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +INSTALL_SDATA=@INSTALL@ -m 600 + +AM_CFLAGS = $(PICFLAGS) +AM_LDFLAGS = $(PILDFLAGS) + +noinst_LIBRARIES = libbabel.a +sbin_PROGRAMS = babeld + +libbabel_a_SOURCES = \ + babel_zebra.c net.c kernel.c util.c source.c neighbour.c \ + route.c xroute.c message.c resend.c babel_interface.c babeld.c \ + babel_filter.c + +noinst_HEADERS = \ + babel_zebra.h net.h kernel.h util.h source.h neighbour.h \ + route.h xroute.h message.h resend.h babel_interface.h babeld.h \ + babel_filter.h + +babeld_SOURCES = \ + babel_main.c $(libbabel_a_SOURCES) + +babeld_LDADD = ../lib/libzebra.la @LIBCAP@ + +examplesdir = $(exampledir) +dist_examples_DATA = babeld.conf.sample diff --git a/babeld/babel_filter.c b/babeld/babel_filter.c new file mode 100644 index 00000000..5c93d13a --- /dev/null +++ b/babeld/babel_filter.c @@ -0,0 +1,188 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "babel_filter.h" +#include "vty.h" +#include "filter.h" +#include "log.h" +#include "plist.h" +#include "distribute.h" +#include "util.h" + + +int +babel_filter_in (struct prefix *p, babel_interface_nfo *babel_ifp) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + /* Input distribute-list filtering. */ + if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_IN]) { + if (access_list_apply (babel_ifp->list[BABEL_FILTER_IN], p) + == FILTER_DENY) { + debugf(BABEL_DEBUG_FILTER, + "%s/%d filtered by distribute in", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_IN]) { + if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_IN], p) + == PREFIX_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) { + if (dist->list[DISTRIBUTE_IN]) { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); + + if (alist) { + if (access_list_apply (alist, p) == FILTER_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_IN]) { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); + if (plist) { + if (prefix_list_apply (plist, p) == PREFIX_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +int +babel_filter_out (struct prefix *p, babel_interface_nfo *babel_ifp) +{ + struct distribute *dist; + struct access_list *alist; + struct prefix_list *plist; + + if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_OUT]) { + if (access_list_apply (babel_ifp->list[BABEL_FILTER_OUT], p) + == FILTER_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_OUT]) { + if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_OUT], p) + == PREFIX_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + + /* All interface filter check. */ + dist = distribute_lookup (NULL); + if (dist) { + if (dist->list[DISTRIBUTE_OUT]) { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); + if (alist) { + if (access_list_apply (alist, p) == FILTER_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + } + if (dist->prefix[DISTRIBUTE_OUT]) { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); + if (plist) { + if (prefix_list_apply (plist, p) == PREFIX_DENY) { + debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return -1; + } + } + } + } + return 0; +} + +int +babel_filter_redistribute (struct prefix *p, + babel_interface_nfo *babel_ifp) +{ + debugf(BABEL_DEBUG_FILTER, "%s/%d WARNING: no redistribute filter implemented !!!!", + p->family == AF_INET ? + inet_ntoa(p->u.prefix4) : + inet6_ntoa (p->u.prefix6), + p->prefixlen); + return 0; /* TODO: it redistributes always */ +} diff --git a/babeld/babel_filter.h b/babeld/babel_filter.h new file mode 100644 index 00000000..52b72f60 --- /dev/null +++ b/babeld/babel_filter.h @@ -0,0 +1,54 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BABELD_BABEL_FILTER_H +#define BABELD_BABEL_FILTER_H + +#include +#include "prefix.h" +#include "babel_interface.h" + +/* filter route coming from other worlds */ +int babel_filter_in (struct prefix *, babel_interface_nfo *); +/* filter route sending to other worlds */ +int babel_filter_out (struct prefix *, babel_interface_nfo *); +/* filter route coming from our friend zebra */ +int babel_filter_redistribute + (struct prefix *, babel_interface_nfo *); + +#endif /* BABELD_BABEL_FILTER_H */ diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c new file mode 100644 index 00000000..0130f26b --- /dev/null +++ b/babeld/babel_interface.c @@ -0,0 +1,778 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "memory.h" +#include "log.h" +#include "command.h" +#include "prefix.h" +#include "vector.h" + +#include "babel_main.h" +#include "util.h" +#include "kernel.h" +#include "babel_interface.h" +#include "message.h" +#include "route.h" +#include "babel_zebra.h" + + +static int babel_enable_if_lookup (const char *ifname); +static int babel_enable_if_add (const char *ifname); +static int babel_enable_if_delete (const char *ifname); +static int interface_recalculate(struct interface *ifp); +static int interface_reset(struct interface *ifp); +static int babel_if_new_hook (struct interface *ifp); +static int babel_if_delete_hook (struct interface *ifp); +static int interface_config_write (struct vty *vty); +static babel_interface_nfo * babel_interface_allocate (); +static void babel_interface_free (babel_interface_nfo *bi); + + +static vector babel_enable_if; /* enable interfaces (by cmd). */ +static struct cmd_node babel_interface_node = /* babeld's interface node. */ +{ + INTERFACE_NODE, + "%s(config-if)# ", + 1 /* VTYSH */ +}; + + +int +babel_interface_up (int cmd, struct zclient *client, zebra_size_t length) +{ + struct stream *s = NULL; + struct interface *ifp = NULL; + + debugf(BABEL_DEBUG_IF, "receive a 'interface up'"); + + s = zclient->ibuf; + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) { + return 0; + } + + interface_recalculate(ifp); + return 0; +} + +int +babel_interface_down (int cmd, struct zclient *client, zebra_size_t length) +{ + struct stream *s = NULL; + struct interface *ifp = NULL; + + debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); + + s = zclient->ibuf; + ifp = zebra_interface_state_read(s); + + if (ifp == NULL) { + return 0; + } + + interface_reset(ifp); + return 0; +} + +int +babel_interface_add (int cmd, struct zclient *client, zebra_size_t length) +{ + struct interface *ifp = NULL; + + debugf(BABEL_DEBUG_IF, "receive a 'interface add'"); + + /* read and add the interface in the iflist. */ + ifp = zebra_interface_add_read (zclient->ibuf); + + if (ifp == NULL) { + return 0; + } + + interface_recalculate(ifp); + + return 0; +} + +int +babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length) +{ + debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); + return 0; +} + +int +babel_interface_address_add (int cmd, struct zclient *client, + zebra_size_t length) +{ + babel_interface_nfo *babel_ifp; + struct connected *ifc; + struct prefix *prefix; + + debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); + + ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, + zclient->ibuf); + + if (ifc == NULL) + return 0; + + prefix = ifc->address; + + if (prefix->family == AF_INET) { + flush_interface_routes(ifc->ifp, 0); + babel_ifp = babel_get_if_nfo(ifc->ifp); + if (babel_ifp->ipv4 == NULL) { + babel_ifp->ipv4 = malloc(4); + if (babel_ifp->ipv4 == NULL) { + zlog_err("not einough memory"); + } else { + memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4); + } + } + } + + send_request(ifc->ifp, NULL, 0); + send_update(ifc->ifp, 0, NULL, 0); + + return 0; +} + +int +babel_interface_address_delete (int cmd, struct zclient *client, + zebra_size_t length) +{ + babel_interface_nfo *babel_ifp; + struct connected *ifc; + struct prefix *prefix; + + debugf(BABEL_DEBUG_IF, "receive a 'interface address add'"); + + ifc = zebra_interface_address_read (ZEBRA_INTERFACE_ADDRESS_ADD, + zclient->ibuf); + + if (ifc == NULL) + return 0; + + prefix = ifc->address; + + if (prefix->family == AF_INET) { + flush_interface_routes(ifc->ifp, 0); + babel_ifp = babel_get_if_nfo(ifc->ifp); + if (babel_ifp->ipv4 != NULL + && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, 4) == 0) { + free(babel_ifp->ipv4); + babel_ifp->ipv4 = NULL; + } + } + + send_request(ifc->ifp, NULL, 0); + send_update(ifc->ifp, 0, NULL, 0); + + return 0; +} + +/* Lookup function. */ +static int +babel_enable_if_lookup (const char *ifname) +{ + unsigned int i; + char *str; + + for (i = 0; i < vector_active (babel_enable_if); i++) + if ((str = vector_slot (babel_enable_if, i)) != NULL) + if (strcmp (str, ifname) == 0) + return i; + return -1; +} + +/* Add interface to babel_enable_if. */ +static int +babel_enable_if_add (const char *ifname) +{ + int ret; + struct interface *ifp = NULL; + + ret = babel_enable_if_lookup (ifname); + if (ret >= 0) + return -1; + + vector_set (babel_enable_if, strdup (ifname)); + + ifp = if_lookup_by_name(ifname); + if (ifp != NULL) + babel_get_if_nfo(ifp)->flags |= BABEL_IF_IS_ENABLE; + + return 1; +} + +/* Delete interface from babel_enable_if. */ +static int +babel_enable_if_delete (const char *ifname) +{ + int babel_enable_if_index; + char *str; + struct interface *ifp = NULL; + + babel_enable_if_index = babel_enable_if_lookup (ifname); + if (babel_enable_if_index < 0) + return -1; + + str = vector_slot (babel_enable_if, babel_enable_if_index); + free (str); + vector_unset (babel_enable_if, babel_enable_if_index); + + ifp = if_lookup_by_name(ifname); + if (ifp != NULL) + babel_get_if_nfo(ifp)->flags &= ~BABEL_IF_IS_ENABLE; + + return 1; +} + + +/* [Babel Command] Babel enable on specified interface or matched network. */ +DEFUN (babel_network, + babel_network_cmd, + "network IF_OR_ADDR", + "Babel enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is: */ + if (ret) /* an IPv4 or v6 network */ + return CMD_ERR_NO_MATCH; /* not implemented yet */ + else /* an interface name */ + ret = babel_enable_if_add (argv[0]); + + if (ret < 0) { + vty_out (vty, "There is same network configuration %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* [Babel Command] Babel enable on specified interface or matched network. */ +DEFUN (no_babel_network, + no_babel_network_cmd, + "no network IF_OR_ADDR", + NO_STR + "Babel enable on specified interface or network.\n" + "Interface or address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is: */ + if (ret) /* an IPv4 or v6 network */ + return CMD_ERR_NO_MATCH; /* not implemented yet */ + else /* an interface name */ + ret = babel_enable_if_delete (argv[0]); + + if (ret < 0) { + vty_out (vty, "can't find network %s%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* [Interface Command] Tell the interface is wire. */ +DEFUN (babel_set_wired, + babel_set_wired_cmd, + "wired", + "Set this interface as wired (default: wireless).\n" + "No attributes") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + + assert (babel_ifp != NULL); + babel_ifp->flags |= BABEL_IF_WIRED; + return CMD_SUCCESS; +} + +/* [Interface Command] Tell the interface is wireless (default). */ +DEFUN (babel_set_wireless, + babel_set_wireless_cmd, + "wireless", + NO_STR + "Set this interface as wireless (is default).\n" + "No attributes") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + + assert (babel_ifp != NULL); + babel_ifp->flags &= ~BABEL_IF_WIRED; + return CMD_SUCCESS; +} + +/* [Interface Command] Enable split horizon. */ +DEFUN (babel_split_horizon, + babel_split_horizon_cmd, + "babel split-horizon", + IPV6_STR + "Routing Information Protocol\n" + "Perform split horizon\n") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + + assert (babel_ifp != NULL); + babel_ifp->flags |= BABEL_IF_SPLIT_HORIZON; + return CMD_SUCCESS; +} + +/* [Interface Command] Disable split horizon (default). */ +DEFUN (no_babel_split_horizon, + no_babel_split_horizon_cmd, + "no babel split-horizon", + NO_STR + IPV6_STR + "Routing Information Protocol\n" + "Perform split horizon\n") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + + assert (babel_ifp != NULL); + babel_ifp->flags &= ~BABEL_IF_SPLIT_HORIZON; + return CMD_SUCCESS; +} + +/* [Interface Command]. */ +DEFUN (babel_set_hello_interval, + babel_set_hello_interval_cmd, + "hello interval <5-1000000>", + "Set interface's hello interval (default: 4000).\n" + "Value in miliseconds\n") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + + int interval = atoi(argv[1]); + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + + assert (babel_ifp != NULL); + babel_ifp->hello_interval = interval; + return CMD_SUCCESS; +} + +/* [Interface Command]. */ +DEFUN (babel_passive_interface, + babel_passive_interface_cmd, + "passive-interface", + "The daemon will only announce redistributed routes\n" + "Interface name\n") +{ + if (allow_duplicates) { + return CMD_WARNING; + } + parasitic = -1; + return CMD_SUCCESS; +} + +/* [Interface Command]. */ +DEFUN (no_babel_passive_interface, + no_babel_passive_interface_cmd, + "no passive-interface", + NO_STR + "The daemon will announce all (filtred) routes\n" + "Interface name\n") +{ + parasitic = 0; + return CMD_SUCCESS; +} + + +int +interface_idle(babel_interface_nfo *babel_ifp) +{ + return (idle_hello_interval > 0 && + babel_ifp->activity_time < babel_now.tv_sec - idle_time); +} + +/* This should be no more than half the hello interval, so that hellos + aren't sent late. The result is in milliseconds. */ +unsigned +jitter(babel_interface_nfo *babel_ifp, int urgent) +{ + unsigned interval = babel_ifp->hello_interval; + if(urgent) + interval = MIN(interval, 100); + else + interval = MIN(interval, 4000); + return roughly(interval) / 4; +} + +unsigned +update_jitter(babel_interface_nfo *babel_ifp, int urgent) +{ + unsigned interval = babel_ifp->hello_interval; + if(urgent) + interval = MIN(interval, 100); + else + interval = MIN(interval, 4000); + return roughly(interval); +} + +/* calculate babeld's specific datas of an interface (change when the interface + change) */ +static int +interface_recalculate(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + unsigned char *tmp = NULL; + int mtu, rc; + struct ipv6_mreq mreq; + + mtu = MIN(ifp->mtu, ifp->mtu6); + + /* We need to be able to fit at least two messages into a packet, + so MTUs below 116 require lower layer fragmentation. */ + /* In IPv6, the minimum MTU is 1280, and every host must be able + to reassemble up to 1500 bytes, but I'd rather not rely on this. */ + if(mtu < 128) { + debugf(BABEL_DEBUG_IF, "Suspiciously low MTU %d on interface %s (%d).", + mtu, ifp->name, ifp->ifindex); + mtu = 128; + } + + /* 40 for IPv6 header, 8 for UDP header, 12 for good luck. */ + babel_ifp->bufsize = mtu - sizeof(packet_header) - 60; + tmp = babel_ifp->sendbuf; + babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize); + if(babel_ifp->sendbuf == NULL) { + fprintf(stderr, "Couldn't reallocate sendbuf.\n"); + free(tmp); + babel_ifp->bufsize = 0; + return -1; + } + tmp = NULL; + + resize_receive_buffer(mtu); + + if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */ + babel_ifp->cost = 96; + babel_ifp->flags &= ~BABEL_IF_LQ; + } else { + babel_ifp->cost = 256; + babel_ifp->flags |= BABEL_IF_LQ; + } + + babel_ifp->activity_time = babel_now.tv_sec; + /* Since the interface was marked as active above, the + idle_hello_interval cannot be the one being used here. */ + babel_ifp->update_interval = babel_ifp->hello_interval * 4; + + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); + mreq.ipv6mr_interface = ifp->ifindex; + + rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char*)&mreq, sizeof(mreq)); + if(rc < 0) { + zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s", + ifp->name, safe_strerror(errno)); + /* This is probably due to a missing link-local address, + so down this interface, and wait until the main loop + tries to up it again. */ + interface_reset(ifp); + return -1; + } + + set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); + set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); + send_hello(ifp); + send_request(ifp, NULL, 0); + + update_interface_metric(ifp); + + debugf(BABEL_DEBUG_COMMON, + "Upped network %s (%s, cost=%d%s).", + ifp->name, + (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", + babel_ifp->cost, + babel_ifp->ipv4 ? ", IPv4" : ""); + + if(rc > 0) + send_update(ifp, 0, NULL, 0); + + /* Check and set if interface is enable. */ + if (babel_enable_if_lookup(ifp->name) >= 0) { + babel_ifp->flags |= BABEL_IF_IS_ENABLE; + } else { + babel_ifp->flags &= ~BABEL_IF_IS_ENABLE; + } + + return 1; +} + +/* Reset the interface as it was new: it's not removed from the interface list, + and may be considered as a upped interface. */ +static int +interface_reset(struct interface *ifp) +{ + int rc; + struct ipv6_mreq mreq; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + + flush_interface_routes(ifp, 0); + babel_ifp->buffered = 0; + babel_ifp->bufsize = 0; + free(babel_ifp->sendbuf); + babel_ifp->num_buffered_updates = 0; + babel_ifp->update_bufsize = 0; + if(babel_ifp->buffered_updates) + free(babel_ifp->buffered_updates); + babel_ifp->buffered_updates = NULL; + babel_ifp->sendbuf = NULL; + + if(ifp->ifindex > 0) { + memset(&mreq, 0, sizeof(mreq)); + memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); + mreq.ipv6mr_interface = ifp->ifindex; + rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + (char*)&mreq, sizeof(mreq)); + if(rc < 0) + zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s", + ifp->name, safe_strerror(errno)); + } + + update_interface_metric(ifp); + + debugf(BABEL_DEBUG_COMMON,"Upped network %s (%s, cost=%d%s).", + ifp->name, + (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", + babel_ifp->cost, + babel_ifp->ipv4 ? ", IPv4" : ""); + + return 1; +} + +/* Send retraction to all, and reset all interfaces statistics. */ +void +babel_interface_close_all(void) +{ + struct interface *ifp = NULL; + struct listnode *linklist_node = NULL; + + FOR_ALL_INTERFACES(ifp, linklist_node) { + if(!if_up(ifp)) + continue; + send_wildcard_retraction(ifp); + /* Make sure that we expire quickly from our neighbours' + association caches. */ + send_hello_noupdate(ifp, 10); + flushbuf(ifp); + usleep(roughly(1000)); + gettime(&babel_now); + } + FOR_ALL_INTERFACES(ifp, linklist_node) { + if(!if_up(ifp)) + continue; + /* Make sure they got it. */ + send_wildcard_retraction(ifp); + send_hello_noupdate(ifp, 1); + flushbuf(ifp); + usleep(roughly(10000)); + gettime(&babel_now); + interface_reset(ifp); + } +} + +/* return "true" if address is one of our ipv6 addresses */ +int +is_interface_ll_address(struct interface *ifp, const unsigned char *address) +{ + struct connected *connected; + struct listnode *node; + + if(!if_up(ifp)) + return 0; + + FOR_ALL_INTERFACES_ADDRESSES(ifp, connected, node) { + if(connected->address->family == AF_INET6 && + memcmp(&connected->address->u.prefix6, address, 16) == 0) + return 1; + } + + return 0; +} + + +void +babel_if_init () +{ + /* initialize interface list */ + if_init(); + if_add_hook (IF_NEW_HOOK, babel_if_new_hook); + if_add_hook (IF_DELETE_HOOK, babel_if_delete_hook); + + babel_enable_if = vector_init (1); + + /* install interface node and commands */ + install_element (CONFIG_NODE, &interface_cmd); + install_element (CONFIG_NODE, &no_interface_cmd); + install_node (&babel_interface_node, interface_config_write); + install_default(INTERFACE_NODE); + install_element(INTERFACE_NODE, &interface_cmd); + install_element(INTERFACE_NODE, &no_interface_cmd); + + install_element(BABEL_NODE, &babel_network_cmd); + install_element(BABEL_NODE, &no_babel_network_cmd); + install_element(INTERFACE_NODE, &babel_split_horizon_cmd); + install_element(INTERFACE_NODE, &no_babel_split_horizon_cmd); + install_element(INTERFACE_NODE, &babel_set_wired_cmd); + install_element(INTERFACE_NODE, &babel_set_wireless_cmd); + install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); + install_element(INTERFACE_NODE, &babel_passive_interface_cmd); + install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); +} + +/* hooks: functions called respectively when struct interface is + created or deleted. */ +static int +babel_if_new_hook (struct interface *ifp) +{ + ifp->info = babel_interface_allocate(); + return 0; +} + +static int +babel_if_delete_hook (struct interface *ifp) +{ + babel_interface_free(ifp->info); + ifp->info = NULL; + return 0; +} + +/* Configuration write function for babeld. */ +static int +interface_config_write (struct vty *vty) +{ + struct listnode *node; + struct interface *ifp; + babel_interface_nfo *babel_ifp; + int write = 0; + + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { + babel_ifp = babel_get_if_nfo(ifp); + + /* Do not display the interface if there is no configuration about it */ + if (ifp->desc == NULL) + continue; + + vty_out (vty, "interface %s%s", ifp->name, + VTY_NEWLINE); + if (ifp->desc) + vty_out (vty, " description %s%s", ifp->desc, + VTY_NEWLINE); + + /* TODO: to be completed... */ + + vty_out (vty, "!%s", VTY_NEWLINE); + + write++; + } + return write; +} + +/* functions to allocate or free memory for a babel_interface_nfo, filling + needed fields */ +static babel_interface_nfo * +babel_interface_allocate () +{ + babel_interface_nfo *babel_ifp; + babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); + if(babel_ifp == NULL) + return NULL; + + /* Here are set the default values for an interface. */ + memset(babel_ifp, 0, sizeof(babel_interface_nfo)); + /* All flags are unset */ + babel_ifp->activity_time = babel_now.tv_sec; + babel_ifp->bucket_time = babel_now.tv_sec; + babel_ifp->bucket = BUCKET_TOKENS_MAX; + babel_ifp->hello_seqno = (random() & 0xFFFF); + babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL; + + return babel_ifp; +} + +static void +babel_interface_free (babel_interface_nfo *babel_ifp) +{ + XFREE(MTYPE_BABEL_IF, babel_ifp); +} diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h new file mode 100644 index 00000000..7a6efb93 --- /dev/null +++ b/babeld/babel_interface.h @@ -0,0 +1,141 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BABEL_INTERFACE_H +#define BABEL_INTERFACE_H + +#include +#include "zclient.h" + +/* babeld interface informations */ +struct babel_interface { + unsigned short flags; /* see below */ + unsigned short cost; + struct timeval hello_timeout; + struct timeval update_timeout; + struct timeval flush_timeout; + struct timeval update_flush_timeout; + unsigned char *ipv4; + int buffered; + int bufsize; + char have_buffered_hello; + char have_buffered_id; + char have_buffered_nh; + char have_buffered_prefix; + unsigned char buffered_id[16]; + unsigned char buffered_nh[4]; + unsigned char buffered_prefix[16]; + unsigned char *sendbuf; + struct buffered_update *buffered_updates; + int num_buffered_updates; + int update_bufsize; + time_t bucket_time; + unsigned int bucket; + time_t activity_time; + unsigned short hello_seqno; + unsigned hello_interval; + unsigned update_interval; + + /* For filter type slot. */ +#define BABEL_FILTER_IN 0 +#define BABEL_FILTER_OUT 1 +#define BABEL_FILTER_MAX 2 + struct access_list *list[BABEL_FILTER_MAX]; /* Access-list. */ + struct prefix_list *prefix[BABEL_FILTER_MAX]; /* Prefix-list. */ +}; + +typedef struct babel_interface babel_interface_nfo; +static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) +{ + return ((babel_interface_nfo*) ifp->info); +} + +/* babel_interface_nfo flags */ +#define BABEL_IF_WIRED (1 << 1) +#define BABEL_IF_SPLIT_HORIZON (1 << 2) +#define BABEL_IF_LQ (1 << 3) +#define BABEL_IF_IS_ENABLE (1 << 4) + +static inline int +if_up(struct interface *ifp) +{ + return (if_is_up(ifp) && + ifp->connected != NULL && + (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_ENABLE)); +} + +/* types: + struct interface _ifp, struct listnode node */ +#define FOR_ALL_INTERFACES(_ifp, _node) \ + for(ALL_LIST_ELEMENTS_RO(iflist, _node, _ifp)) + +/* types: + struct interface *ifp, struct connected *_connected, struct listnode *node */ +#define FOR_ALL_INTERFACES_ADDRESSES(ifp, _connected, _node) \ + for(ALL_LIST_ELEMENTS_RO(ifp->connected, _node, _connected)) + +struct buffered_update { + unsigned char id[8]; + unsigned char prefix[16]; + unsigned char plen; + unsigned char pad[3]; +}; + + +/* init function */ +void babel_if_init(void); + +/* Callback functions for zebra client */ +int babel_interface_up (int, struct zclient *, zebra_size_t); +int babel_interface_down (int, struct zclient *, zebra_size_t); +int babel_interface_add (int, struct zclient *, zebra_size_t); +int babel_interface_delete (int, struct zclient *, zebra_size_t); +int babel_interface_address_add (int, struct zclient *, zebra_size_t); +int babel_interface_address_delete (int, struct zclient *, zebra_size_t); + +/* others functions */ +int interface_idle(babel_interface_nfo *); +unsigned jitter(babel_interface_nfo *, int); +unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); +/* return "true" if "address" is one of our ipv6 addresses */ +int is_interface_ll_address(struct interface *ifp, const unsigned char *address); +/* Send retraction to all, and reset all interfaces statistics. */ +void babel_interface_close_all(void); + + +#endif diff --git a/babeld/babel_main.c b/babeld/babel_main.c new file mode 100644 index 00000000..6065b7bc --- /dev/null +++ b/babeld/babel_main.c @@ -0,0 +1,522 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* include zebra library */ +#include +#include "getopt.h" +#include "if.h" +#include "log.h" +#include "thread.h" +#include "privs.h" +#include "sigevent.h" +#include "version.h" +#include "command.h" +#include "vty.h" +#include "memory.h" + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" +#include "kernel.h" +#include "babel_interface.h" +#include "neighbour.h" +#include "route.h" +#include "xroute.h" +#include "message.h" +#include "resend.h" +#include "babel_zebra.h" + + +static void babel_init (int argc, char **argv); +static void babel_usage (char *progname); +static char *babel_get_progname(char *argv_0); +static void babel_fail(void); +static void babel_init_random(void); +static void babel_replace_by_null(int fd); +static void babel_load_state_file(void); +static void babel_init_signals(void); +static void babel_exit_properly(void); +static void babel_save_state_file(void); + + +struct thread_master *master; /* quagga's threads handler */ +struct timeval babel_now; /* current time */ + +unsigned char myid[8]; /* unique id (mac address of an interface) */ +int debug = BABEL_DEBUG_COMMON; + +time_t reboot_time; +int idle_time = 320; +int link_detect = 0; +int wireless_hello_interval = -1; +int wired_hello_interval = -1; +int idle_hello_interval = -1; +char *pidfile = "/var/run/babeld.pid"; + +const unsigned char zeroes[16] = {0}; +const unsigned char ones[16] = + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static char *state_file = "/var/lib/babeld/babel-state"; + +unsigned char protocol_group[16]; /* babel's link-local multicast address */ +int protocol_port; /* babel's port */ +int protocol_socket = -1; /* socket: communicate with others babeld */ + +static char babel_config_default[] = SYSCONFDIR BABEL_DEFAULT_CONFIG; +static char *babel_config_file = NULL; +static char *babel_vty_addr = NULL; +static int babel_vty_port = BABEL_VTY_PORT; + +/* Babeld options. */ +struct option longopts[] = +{ + { "daemon", no_argument, NULL, 'd'}, + { "config_file", required_argument, NULL, 'f'}, + { "pid_file", required_argument, NULL, 'i'}, + { "help", no_argument, NULL, 'h'}, + { "vty_addr", required_argument, NULL, 'A'}, + { "vty_port", required_argument, NULL, 'P'}, + { "user", required_argument, NULL, 'u'}, + { "group", required_argument, NULL, 'g'}, + { "version", no_argument, NULL, 'v'}, + { 0 } +}; + +/* babeld privileges */ +static zebra_capabilities_t _caps_p [] = +{ + ZCAP_NET_RAW, + ZCAP_BIND +}; +static struct zebra_privs_t babeld_privs = +{ +#if defined(QUAGGA_USER) + .user = QUAGGA_USER, +#endif +#if defined QUAGGA_GROUP + .group = QUAGGA_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = 2, + .cap_num_i = 0 +}; + + +int +main(int argc, char **argv) +{ + struct thread thread; + /* and print banner too */ + babel_init(argc, argv); + while (thread_fetch (master, &thread)) { + thread_call (&thread); + } + return 0; +} + +/* make initialisations witch don't need infos about kernel(interfaces, etc.) */ +static void +babel_init(int argc, char **argv) +{ + int rc, opt; + int do_daemonise = 0; + char *progname = NULL; + char *pidfile = PATH_BABELD_PID; + + /* Set umask before anything for security */ + umask (0027); + progname = babel_get_progname(argv[0]); + + /* set default log (lib/log.h) */ + zlog_default = openzlog(progname, ZLOG_BABEL, + LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); + /* set log destination as stdout until the config file is read */ + zlog_set_level(NULL, ZLOG_DEST_STDOUT, LOG_WARNING); + + babel_init_random(); + + /* set the Babel's default link-local multicast address and Babel's port */ + parse_address("ff02:0:0:0:0:0:1:6", protocol_group, NULL); + protocol_port = 6696; + + /* get options */ + while(1) { + opt = getopt_long(argc, argv, "df:i:hA:P:u:g:v", longopts, 0); + if(opt < 0) + break; + + switch(opt) { + case 0: + break; + case 'd': + do_daemonise = -1; + break; + case 'f': + babel_config_file = optarg; + break; + case 'i': + pidfile = optarg; + break; + case 'A': + babel_vty_addr = optarg; + break; + case 'P': + babel_vty_port = atoi (optarg); + if (babel_vty_port < 0 || babel_vty_port > 0xffff + || (babel_vty_port == 0 && optarg[0] != '0'/*atoi error*/)) + babel_vty_port = BABEL_VTY_PORT; + break; + case 'u': + babeld_privs.user = optarg; + break; + case 'g': + babeld_privs.group = optarg; + break; + case 'v': + print_version (progname); + exit (0); + break; + case 'h': + babel_usage (progname); + break; + default: + babel_usage(progname); + break; + } + } + + /* create the threads handler */ + master = thread_master_create (); + + /* Library inits. */ + zprivs_init (&babeld_privs); + babel_init_signals(); + cmd_init (1); + vty_init (master); + memory_init (); + + /* babeld inits (default options) */ + /* set default interval's values */ + if(wireless_hello_interval <= 0) + wireless_hello_interval = 4000; + wireless_hello_interval = MAX(wireless_hello_interval, 5); + + if(wired_hello_interval <= 0) + wired_hello_interval = 4000; + wired_hello_interval = MAX(wired_hello_interval, 5); + + /* an assertion */ + if(parasitic && allow_duplicates >= 0) { + /* Too difficult to get right. */ + zlog_err("Sorry, -P and -A are incompatible."); + exit(1); + } + + babel_replace_by_null(STDIN_FILENO); + + if (do_daemonise && daemonise() < 0) { + zlog_err("daemonise: %s", safe_strerror(errno)); + exit (1); + } + + /* write pid file */ + if (pid_output(pidfile) < 0) { + zlog_err("error while writing pidfile"); + exit (1); + }; + + /* init some quagga's dependencies, and babeld's commands */ + babeld_quagga_init(); + /* init zebra client's structure and it's commands */ + /* this replace kernel_setup && kernel_setup_socket */ + babelz_zebra_init (); + + /* Sort all installed commands. */ + sort_node (); + + /* Get zebra configuration file. */ + zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); + vty_read_config (babel_config_file, babel_config_default); + + myseqno = (random() & 0xFFFF); + babel_load_state_file(); + + /* Create VTY socket */ + vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); + + /* init buffer */ + rc = resize_receive_buffer(1500); + if(rc < 0) + babel_fail(); + + schedule_neighbours_check(5000, 1); + + zlog_notice ("BABELd %s starting: vty@%d", BABEL_VERSION, babel_vty_port); +} + +/* return the progname (without path, example: "./x/progname" --> "progname") */ +static char * +babel_get_progname(char *argv_0) { + char *p = strrchr (argv_0, '/'); + return (p ? ++p : argv_0); +} + +static void +babel_usage(char *progname) +{ + fprintf(stderr, + "Syntax: %s " + "[-m multicast_address] [-p port] [-S state-file]\n" + " " + "[-h hello] [-H wired_hello] [-i idle_hello]\n" + " " + "[-k metric] [-A metric] [-s] [-P] [-l] [-w] [-d level] [-g port]\n" + " " + "[-t table] [-T table] [-c file] [-C statement]\n" + " " + "[-D] [-L logfile] [-I pidfile]\n" + " " + "[id] interface...\n", + progname); + exit(1); +} + +static void +babel_fail(void) +{ + exit(1); +} + +/* initialize random value, and set 'babel_now' by the way. */ +static void +babel_init_random(void) +{ + gettime(&babel_now); + int rc; + unsigned int seed; + + rc = read_random_bytes(&seed, sizeof(seed)); + if(rc < 0) { + zlog_err("read(random): %s", safe_strerror(errno)); + seed = 42; + } + + seed ^= (babel_now.tv_sec ^ babel_now.tv_usec); + srandom(seed); +} + +/* + close fd, and replace it by "/dev/null" + exit if error + */ +static void +babel_replace_by_null(int fd) +{ + int fd_null; + int rc; + + fd_null = open("/dev/null", O_RDONLY); + if(fd_null < 0) { + zlog_err("open(null): %s", safe_strerror(errno)); + exit(1); + } + + rc = dup2(fd_null, fd); + if(rc < 0) { + zlog_err("dup2(null, 0): %s", safe_strerror(errno)); + exit(1); + } + + close(fd_null); +} + +/* + Load the state file: check last babeld's running state, usefull in case of + "/etc/init.d/babeld restart" + */ +static void +babel_load_state_file(void) +{ + reboot_time = babel_now.tv_sec; + int fd; + int rc; + + fd = open(state_file, O_RDONLY); + if(fd < 0 && errno != ENOENT) + zlog_err("open(babel-state: %s)", safe_strerror(errno)); + rc = unlink(state_file); + if(fd >= 0 && rc < 0) { + zlog_err("unlink(babel-state): %s", safe_strerror(errno)); + /* If we couldn't unlink it, it's probably stale. */ + close(fd); + fd = -1; + } + if(fd >= 0) { + char buf[100]; + char buf2[100]; + int s; + long t; + rc = read(fd, buf, 99); + if(rc < 0) { + zlog_err("read(babel-state): %s", safe_strerror(errno)); + } else { + buf[rc] = '\0'; + rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t); + if(rc == 3 && s >= 0 && s <= 0xFFFF) { + unsigned char sid[8]; + rc = parse_eui64(buf2, sid); + if(rc < 0) { + zlog_err("Couldn't parse babel-state."); + } else { + struct timeval realnow; + debugf(BABEL_DEBUG_COMMON, + "Got %s %d %ld from babel-state.", + format_eui64(sid), s, t); + gettimeofday(&realnow, NULL); + if(memcmp(sid, myid, 8) == 0) + myseqno = seqno_plus(s, 1); + else + zlog_err("ID mismatch in babel-state."); + /* Convert realtime into monotonic time. */ + if(t >= 1176800000L && t <= realnow.tv_sec) + reboot_time = babel_now.tv_sec - (realnow.tv_sec - t); + } + } else { + zlog_err("Couldn't parse babel-state."); + } + } + close(fd); + fd = -1; + } +} + +static void +babel_sigexit(void) +{ + zlog_notice("Terminating on signal"); + + babel_exit_properly(); +} + +static void +babel_sigusr1 (void) +{ + zlog_rotate (NULL); +} + +static void +babel_init_signals(void) +{ + static struct quagga_signal_t babel_signals[] = + { + { + .signal = SIGUSR1, + .handler = &babel_sigusr1, + }, + { + .signal = SIGINT, + .handler = &babel_sigexit, + }, + { + .signal = SIGTERM, + .handler = &babel_sigexit, + }, + }; + + signal_init (master, Q_SIGC(babel_signals), babel_signals); +} + +static void +babel_exit_properly(void) +{ + debugf(BABEL_DEBUG_COMMON, "Exiting..."); + usleep(roughly(10000)); + gettime(&babel_now); + + /* Uninstall and flush all routes. */ + debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); + babel_uninstall_all_routes(); + babel_interface_close_all(); + babel_zebra_close_connexion(); + babel_save_state_file(); + debugf(BABEL_DEBUG_COMMON, "Remove pid file."); + if(pidfile) + unlink(pidfile); + debugf(BABEL_DEBUG_COMMON, "Done."); + + exit(0); +} + +static void +babel_save_state_file(void) +{ + int fd; + int rc; + + debugf(BABEL_DEBUG_COMMON, "Save state file."); + fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644); + if(fd < 0) { + zlog_err("creat(babel-state): %s", safe_strerror(errno)); + unlink(state_file); + } else { + struct timeval realnow; + char buf[100]; + gettimeofday(&realnow, NULL); + rc = snprintf(buf, 100, "%s %d %ld\n", + format_eui64(myid), (int)myseqno, + (long)realnow.tv_sec); + if(rc < 0 || rc >= 100) { + zlog_err("write(babel-state): overflow."); + unlink(state_file); + } else { + rc = write(fd, buf, rc); + if(rc < 0) { + zlog_err("write(babel-state): %s", safe_strerror(errno)); + unlink(state_file); + } + fsync(fd); + } + close(fd); + } +} diff --git a/babeld/babel_main.h b/babeld/babel_main.h new file mode 100644 index 00000000..2bacfabf --- /dev/null +++ b/babeld/babel_main.h @@ -0,0 +1,54 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +extern struct timeval babel_now; /* current time */ +extern struct thread_master *master; /* quagga's threads handler */ +extern int debug; +extern int wireless_hello_interval, wired_hello_interval, idle_hello_interval; +extern int idle_time; +extern int link_detect; + +extern unsigned char myid[8]; + +extern const unsigned char zeroes[16], ones[16]; + +extern int protocol_port; +extern unsigned char protocol_group[16]; +extern int protocol_socket; +extern int kernel_socket; +extern int max_request_hopcount; diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c new file mode 100644 index 00000000..6d78ecc6 --- /dev/null +++ b/babeld/babel_zebra.c @@ -0,0 +1,299 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +/* quagga's includes */ +#include +#include "command.h" +#include "zclient.h" +#include "stream.h" + +/* babel's includes*/ +#include "babel_zebra.h" +#include "babel_interface.h" +#include "xroute.h" + +void babelz_zebra_init(void); + + +/* we must use a pointer because of zclient.c's functions (new, free). */ +struct zclient *zclient; +static int zebra_config_write (struct vty *vty); +/* Redistribution types */ +static struct { + int type; + int str_min_len; + const char *str; +} redist_type[] = { + {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, + {ZEBRA_ROUTE_CONNECT, 1, "connected"}, + {ZEBRA_ROUTE_STATIC, 1, "static"}, + {ZEBRA_ROUTE_OSPF6, 1, "ospf6"}, + {ZEBRA_ROUTE_BGP, 1, "bgp"}, + {0, 0, NULL} +}; + +/* Zebra node structure. */ +struct cmd_node zebra_node = +{ + ZEBRA_NODE, + "%s(config-router)# ", + 1 /* vtysh? yes */ +}; + + +/* Zebra route add and delete treatment (ipv6). */ +static int +babel_zebra_read_ipv6 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv6 api; + unsigned long ifindex = -1; + struct in6_addr nexthop; + struct prefix_ipv6 prefix; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in6_addr)); + memset (&api, 0, sizeof(struct zapi_ipv6)); + memset (&prefix, 0, sizeof (struct prefix_ipv6)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + prefix.family = AF_INET6; + prefix.prefixlen = stream_getc (s); + stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, sizeof(nexthop)); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) + babel_ipv6_route_add(&api, &prefix, ifindex, &nexthop); + else + babel_ipv6_route_delete(&api, &prefix, ifindex); + + return 0; +} + +static int +babel_zebra_read_ipv4 (int command, struct zclient *zclient, + zebra_size_t length) +{ + struct stream *s; + struct zapi_ipv4 api; + unsigned long ifindex = -1; + struct in_addr nexthop; + struct prefix_ipv4 prefix; + + s = zclient->ibuf; + ifindex = 0; + memset (&nexthop, 0, sizeof (struct in_addr)); + memset (&api, 0, sizeof(struct zapi_ipv4)); + memset (&prefix, 0, sizeof (struct prefix_ipv4)); + + /* Type, flags, message. */ + api.type = stream_getc (s); + api.flags = stream_getc (s); + api.message = stream_getc (s); + + /* IPv6 prefix. */ + prefix.family = AF_INET; + prefix.prefixlen = stream_getc (s); + stream_get (&prefix.prefix, s, PSIZE (prefix.prefixlen)); + + /* Nexthop, ifindex, distance, metric. */ + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_NEXTHOP)) { + api.nexthop_num = stream_getc (s); + stream_get (&nexthop, s, sizeof(nexthop)); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_IFINDEX)) { + api.ifindex_num = stream_getc (s); + ifindex = stream_getl (s); + } + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_DISTANCE)) + api.distance = stream_getc (s); + else + api.distance = 0; + if (CHECK_FLAG (api.message, ZAPI_MESSAGE_METRIC)) + api.metric = stream_getl (s); + else + api.metric = 0; + + if (command == ZEBRA_IPV6_ROUTE_ADD) { + babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop); + } else { + babel_ipv4_route_delete(&api, &prefix, ifindex); + } + + return 0; +} + +static int +babel_redistribute_unset (int type) +{ + if (! zclient->redist[type]) + return CMD_SUCCESS; + + zclient->redist[type] = 0; + + if (zclient->sock > 0) + zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + + /* perhaps should we remove xroutes having the same type... */ + + return CMD_SUCCESS; +} + + +/* [Babel Command] */ +DEFUN (babel_redistribute_type, + babel_redistribute_type_cmd, + "redistribute (kernel|connected|static|ospf6|bgp)", + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPFv3)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for(i = 0; redist_type[i].str != NULL; i++) { + if (strncmp (redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) { + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, + redist_type[i].type); + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + + return CMD_WARNING; +} + +/* [Babel Command] */ +DEFUN (no_babel_redistribute_type, + no_babel_redistribute_type_cmd, + "no redistribute (kernel|connected|static|ospf6|bgp)", + NO_STR + "Redistribute information from another routing protocol\n" + "Kernel routes\n" + "Connected\n" + "Static routes\n" + "Open Shortest Path First (OSPFv3)\n" + "Border Gateway Protocol (BGP)\n") +{ + int i; + + for (i = 0; redist_type[i].str; i++) { + if (strncmp(redist_type[i].str, argv[0], + redist_type[i].str_min_len) == 0) { + return babel_redistribute_unset (redist_type[i].type); + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + + return CMD_WARNING; +} + + +void babelz_zebra_init(void) +{ + zclient = zclient_new(); + zclient_init(zclient, ZEBRA_ROUTE_BABEL); + + zclient->interface_add = babel_interface_add; + zclient->interface_delete = babel_interface_delete; + zclient->interface_up = babel_interface_up; + zclient->interface_down = babel_interface_down; + zclient->interface_address_add = babel_interface_address_add; + zclient->interface_address_delete = babel_interface_address_delete; + zclient->ipv4_route_add = babel_zebra_read_ipv4; + zclient->ipv4_route_delete = babel_zebra_read_ipv4; + zclient->ipv6_route_add = babel_zebra_read_ipv6; + zclient->ipv6_route_delete = babel_zebra_read_ipv6; + + install_node (&zebra_node, zebra_config_write); + install_element(BABEL_NODE, &babel_redistribute_type_cmd); + install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); +} + +static int +zebra_config_write (struct vty *vty) +{ + fprintf(stderr, "\tzebra_config_write\n"); + if (! zclient->enable) + { + vty_out (vty, "no router zebra%s", VTY_NEWLINE); + return 1; + } + else if (! zclient->redist[ZEBRA_ROUTE_BABEL]) + { + vty_out (vty, "router zebra%s", VTY_NEWLINE); + vty_out (vty, " no redistribute babel%s", VTY_NEWLINE); + return 1; + } + return 0; +} + +void +babel_zebra_close_connexion(void) +{ + zclient_stop(zclient); +} diff --git a/babeld/babel_zebra.h b/babeld/babel_zebra.h new file mode 100644 index 00000000..1b623f01 --- /dev/null +++ b/babeld/babel_zebra.h @@ -0,0 +1,43 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + + +extern struct zclient *zclient; + +void babelz_zebra_init(void); +void babel_zebra_close_connexion(void); diff --git a/babeld/babeld.c b/babeld/babeld.c new file mode 100644 index 00000000..18b4e34f --- /dev/null +++ b/babeld/babeld.c @@ -0,0 +1,766 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "command.h" +#include "prefix.h" +#include "memory.h" +#include "memtypes.h" +#include "table.h" +#include "distribute.h" +#include "prefix.h" +#include "filter.h" +#include "plist.h" + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" +#include "net.h" +#include "kernel.h" +#include "babel_interface.h" +#include "neighbour.h" +#include "route.h" +#include "message.h" +#include "resend.h" +#include "babel_filter.h" + + +static int babel_init_routing_process(struct thread *thread); +static void babel_get_myid(void); +static void babel_initial_noise(void); +static int babel_read_protocol (struct thread *thread); +static int babel_main_loop(struct thread *thread); +static void babel_set_timer(struct timeval *timeout); +static void babel_fill_with_next_timeout(struct timeval *tv); + + +/* Informations relative to the babel running daemon. */ +static struct babel *babel_routing_process = NULL; +static unsigned char *receive_buffer = NULL; +static int receive_buffer_size = 0; + +/* timeouts */ +struct timeval check_neighbours_timeout; +static time_t expiry_time; +static time_t source_expiry_time; + +/* Babel node structure. */ +static struct cmd_node cmd_babel_node = +{ + .node = BABEL_NODE, + .prompt = "%s(config-router)# ", + .vtysh = 1, +}; + +/* print current babel configuration on vty */ +static int +babel_config_write (struct vty *vty) +{ + return 0; +} + + +static int +babel_create_routing_process (void) +{ + assert (babel_routing_process == NULL); + + /* Allocaste Babel instance. */ + babel_routing_process = XCALLOC (MTYPE_BABEL, sizeof (struct babel)); + + /* Initialize timeouts */ + gettime(&babel_now); + expiry_time = babel_now.tv_sec + roughly(30); + source_expiry_time = babel_now.tv_sec + roughly(300); + + /* Make socket for Babel protocol. */ + protocol_socket = babel_socket(protocol_port); + if (protocol_socket < 0) { + zlog_err("Couldn't create link local socket: %s", safe_strerror(errno)); + goto fail; + } + + /* Threads. */ + babel_routing_process->t_read = + thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); + /* wait a little: zebra will announce interfaces, addresses, routes... */ + babel_routing_process->t_update = + thread_add_timer_msec(master, &babel_init_routing_process, NULL, 200L); + return 0; + +fail: + XFREE(MTYPE_BABEL, babel_routing_process); + babel_routing_process = NULL; + return -1; +} + +/* thread reading entries form others babel daemons */ +static int +babel_read_protocol (struct thread *thread) +{ + int rc; + struct interface *ifp = NULL; + struct sockaddr_in6 sin6; + struct listnode *linklist_node = NULL; + + assert(babel_routing_process != NULL); + assert(protocol_socket >= 0); + + rc = babel_recv(protocol_socket, + receive_buffer, receive_buffer_size, + (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) { + if(errno != EAGAIN && errno != EINTR) { + zlog_err("recv: %s", safe_strerror(errno)); + } + } else { + FOR_ALL_INTERFACES(ifp, linklist_node) { + if(!if_up(ifp)) + continue; + if(ifp->ifindex == sin6.sin6_scope_id) { + parse_packet((unsigned char*)&sin6.sin6_addr, ifp, + receive_buffer, rc); + break; + } + } + } + + /* re-add thread */ + babel_routing_process->t_read = + thread_add_read(master, &babel_read_protocol, NULL, protocol_socket); + return 0; +} + +/* Zebra will give some information, especially about interfaces. This function + must be call with a litte timeout wich may give zebra the time to do his job, + making these inits have sense. */ +static int +babel_init_routing_process(struct thread *thread) +{ + babel_get_myid(); + debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); + babel_initial_noise(); + babel_main_loop(thread);/* this function self-add to the t_update thread */ + return 0; +} + +/* fill "myid" with an unique id (only if myid != {0}). */ +static void +babel_get_myid(void) +{ + struct interface *ifp = NULL; + struct listnode *linklist_node = NULL; + int rc; + int i; + + /* if we already have an id (from state file), we return. */ + if (memcmp(myid, zeroes, 8) != 0) { + return; + } + + FOR_ALL_INTERFACES(ifp, linklist_node) { + /* ifp->ifindex is not necessarily valid at this point */ + int ifindex = if_nametoindex(ifp->name); + if(ifindex > 0) { + unsigned char eui[8]; + rc = if_eui64(ifp->name, ifindex, eui); + if(rc < 0) + continue; + memcpy(myid, eui, 8); + return; + } + } + + /* We failed to get a global EUI64 from the interfaces we were given. + Let's try to find an interface with a MAC address. */ + for(i = 1; i < 256; i++) { + char buf[IF_NAMESIZE], *ifname; + unsigned char eui[8]; + ifname = if_indextoname(i, buf); + if(ifname == NULL) + continue; + rc = if_eui64(ifname, i, eui); + if(rc < 0) + continue; + memcpy(myid, eui, 8); + return; + } + + zlog_err("Warning: couldn't find router id -- using random value."); + + rc = read_random_bytes(myid, 8); + if(rc < 0) { + zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno)); + exit(1); + } + /* Clear group and global bits */ + myid[0] &= ~3; +} + +/* Make some noise so that others notice us, and send retractions in + case we were restarted recently */ +static void +babel_initial_noise(void) +{ + struct interface *ifp = NULL; + struct listnode *linklist_node = NULL; + + FOR_ALL_INTERFACES(ifp, linklist_node) { + if(!if_up(ifp)) + continue; + /* Apply jitter before we send the first message. */ + usleep(roughly(10000)); + gettime(&babel_now); + send_hello(ifp); + send_wildcard_retraction(ifp); + } + + FOR_ALL_INTERFACES(ifp, linklist_node) { + if(!if_up(ifp)) + continue; + usleep(roughly(10000)); + gettime(&babel_now); + send_hello(ifp); + send_wildcard_retraction(ifp); + send_self_update(ifp); + send_request(ifp, NULL, 0); + flushupdates(ifp); + flushbuf(ifp); + } +} + +/* Delete all the added babel routes, make babeld only speak to zebra. */ +static void +babel_clean_routing_process() +{ + babel_uninstall_all_routes(); + babel_interface_close_all(); + + /* cancel threads */ + if (babel_routing_process->t_read != NULL) { + thread_cancel(babel_routing_process->t_read); + } + if (babel_routing_process->t_update != NULL) { + thread_cancel(babel_routing_process->t_update); + } + + XFREE(MTYPE_BABEL, babel_routing_process); + babel_routing_process = NULL; +} + +/* Function used with timeout. */ +static int +babel_main_loop(struct thread *thread) +{ + struct timeval tv; + struct interface *ifp = NULL; + struct listnode *linklist_node = NULL; + + while(1) { + gettime(&babel_now); + + /* timeouts --------------------------------------------------------- */ + /* get the next timeout */ + babel_fill_with_next_timeout(&tv); + /* if there is no timeout, we must wait. */ + if(timeval_compare(&tv, &babel_now) > 0) { + timeval_minus(&tv, &tv, &babel_now); + debugf(BABEL_DEBUG_TIMEOUT, "babel main loop : timeout: %ld msecs", + tv.tv_sec * 1000 + tv.tv_usec / 1000); + /* it happens often to have less than 1 ms, it's bad. */ + timeval_add_msec(&tv, &tv, 300); + babel_set_timer(&tv); + return 0; + } + + gettime(&babel_now); + + /* update database -------------------------------------------------- */ + if(timeval_compare(&check_neighbours_timeout, &babel_now) < 0) { + int msecs; + msecs = check_neighbours(); + msecs = MAX(msecs, 10); + schedule_neighbours_check(msecs, 1); + } + + if(babel_now.tv_sec >= expiry_time) { + expire_routes(); + expire_resend(); + expiry_time = babel_now.tv_sec + roughly(30); + } + + if(babel_now.tv_sec >= source_expiry_time) { + expire_sources(); + source_expiry_time = babel_now.tv_sec + roughly(300); + } + + FOR_ALL_INTERFACES(ifp, linklist_node) { + babel_interface_nfo *babel_ifp = NULL; + if(!if_up(ifp)) + continue; + babel_ifp = babel_get_if_nfo(ifp); + if(timeval_compare(&babel_now, &babel_ifp->hello_timeout) >= 0) + send_hello(ifp); + if(timeval_compare(&babel_now, &babel_ifp->update_timeout) >= 0) + send_update(ifp, 0, NULL, 0); + if(timeval_compare(&babel_now, + &babel_ifp->update_flush_timeout) >= 0) + flushupdates(ifp); + } + + if(resend_time.tv_sec != 0) { + if(timeval_compare(&babel_now, &resend_time) >= 0) + do_resend(); + } + + if(unicast_flush_timeout.tv_sec != 0) { + if(timeval_compare(&babel_now, &unicast_flush_timeout) >= 0) + flush_unicast(1); + } + + FOR_ALL_INTERFACES(ifp, linklist_node) { + babel_interface_nfo *babel_ifp = NULL; + if(!if_up(ifp)) + continue; + babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->flush_timeout.tv_sec != 0) { + if(timeval_compare(&babel_now, &babel_ifp->flush_timeout) >= 0) + flushbuf(ifp); + } + } + } + + assert(0); /* this line should never be reach */ +} + +static void +printIfMin(struct timeval *tv, int cmd, const char *tag, const char *ifname) +{ + static struct timeval curr_tv; + static char buffer[200]; + static const char *curr_tag = NULL; + + switch (cmd) { + case 0: /* reset timeval */ + curr_tv = *tv; + if(ifname != NULL) { + snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); + curr_tag = buffer; + } else { + curr_tag = tag; + } + break; + case 1: /* take the min */ + if (tv->tv_sec == 0 && tv->tv_usec == 0) { /* if (tv == ∞) */ + break; + } + if (tv->tv_sec < curr_tv.tv_sec ||(tv->tv_sec == curr_tv.tv_sec && + tv->tv_usec < curr_tv.tv_usec)) { + curr_tv = *tv; + if(ifname != NULL) { + snprintf(buffer, 200L, "interface: %s; %s", ifname, tag); + curr_tag = buffer; + } else { + curr_tag = tag; + } + } + break; + case 2: /* print message */ + debugf(BABEL_DEBUG_TIMEOUT, "next timeout due to: %s", curr_tag); + break; + default: + break; + } +} + +static void +babel_fill_with_next_timeout(struct timeval *tv) +{ +#if (defined NO_DEBUG) +#define printIfMin(a,b,c,d) +#else +#define printIfMin(a,b,c,d) \ + if (UNLIKELY(debug & BABEL_DEBUG_TIMEOUT)) {printIfMin(a,b,c,d);} + + struct interface *ifp = NULL; + struct listnode *linklist_node = NULL; + + *tv = check_neighbours_timeout; + printIfMin(tv, 0, "check_neighbours_timeout", NULL); + timeval_min_sec(tv, expiry_time); + printIfMin(tv, 1, "expiry_time", NULL); + timeval_min_sec(tv, source_expiry_time); + printIfMin(tv, 1, "source_expiry_time", NULL); + timeval_min(tv, &resend_time); + printIfMin(tv, 1, "resend_time", NULL); + FOR_ALL_INTERFACES(ifp, linklist_node) { + babel_interface_nfo *babel_ifp = NULL; + if(!if_up(ifp)) + continue; + babel_ifp = babel_get_if_nfo(ifp); + timeval_min(tv, &babel_ifp->flush_timeout); + printIfMin(tv, 1, "flush_timeout", ifp->name); + timeval_min(tv, &babel_ifp->hello_timeout); + printIfMin(tv, 1, "hello_timeout", ifp->name); + timeval_min(tv, &babel_ifp->update_timeout); + printIfMin(tv, 1, "update_timeout", ifp->name); + timeval_min(tv, &babel_ifp->update_flush_timeout); + printIfMin(tv, 1, "update_flush_timeout",ifp->name); + } + timeval_min(tv, &unicast_flush_timeout); + printIfMin(tv, 1, "unicast_flush_timeout", NULL); + printIfMin(tv, 2, NULL, NULL); +#undef printIfMin +#endif +} + +/* set the t_update thread of the babel routing process to be launch in + 'timeout' (approximate at the milisecond) */ +static void +babel_set_timer(struct timeval *timeout) +{ + long msecs = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; + if (babel_routing_process->t_update != NULL) { + thread_cancel(babel_routing_process->t_update); + } + babel_routing_process->t_update = + thread_add_timer_msec(master, &babel_main_loop, NULL, msecs); +} + +/* Schedule a neighbours check after roughly 3/2 times msecs have elapsed. */ +void +schedule_neighbours_check(int msecs, int override) +{ + struct timeval timeout; + + timeval_add_msec(&timeout, &babel_now, roughly(msecs * 3 / 2)); + if(override) + check_neighbours_timeout = timeout; + else + timeval_min(&check_neighbours_timeout, &timeout); +} + +int +resize_receive_buffer(int size) +{ + if(size <= receive_buffer_size) + return 0; + + if(receive_buffer == NULL) { + receive_buffer = malloc(size); + if(receive_buffer == NULL) { + zlog_err("malloc(receive_buffer): %s", safe_strerror(errno)); + return -1; + } + receive_buffer_size = size; + } else { + unsigned char *new; + new = realloc(receive_buffer, size); + if(new == NULL) { + zlog_err("realloc(receive_buffer): %s", safe_strerror(errno)); + return -1; + } + receive_buffer = new; + receive_buffer_size = size; + } + return 1; +} + +static void +babel_distribute_update (struct distribute *dist) +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + struct access_list *alist; + struct prefix_list *plist; + + if (! dist->ifname) + return; + + ifp = if_lookup_by_name (dist->ifname); + if (ifp == NULL) + return; + + babel_ifp = babel_get_if_nfo(ifp); + + if (dist->list[DISTRIBUTE_IN]) { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); + if (alist) + babel_ifp->list[BABEL_FILTER_IN] = alist; + else + babel_ifp->list[BABEL_FILTER_IN] = NULL; + } else { + babel_ifp->list[BABEL_FILTER_IN] = NULL; + } + + if (dist->list[DISTRIBUTE_OUT]) { + alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); + if (alist) + babel_ifp->list[BABEL_FILTER_OUT] = alist; + else + babel_ifp->list[BABEL_FILTER_OUT] = NULL; + } else { + babel_ifp->list[BABEL_FILTER_OUT] = NULL; + } + + if (dist->prefix[DISTRIBUTE_IN]) { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); + if (plist) + babel_ifp->prefix[BABEL_FILTER_IN] = plist; + else + babel_ifp->prefix[BABEL_FILTER_IN] = NULL; + } else { + babel_ifp->prefix[BABEL_FILTER_IN] = NULL; + } + + if (dist->prefix[DISTRIBUTE_OUT]) { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); + if (plist) + babel_ifp->prefix[BABEL_FILTER_OUT] = plist; + else + babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; + } else { + babel_ifp->prefix[BABEL_FILTER_OUT] = NULL; + } +} + +void +babel_distribute_update_interface (struct interface *ifp) +{ + struct distribute *dist; + + dist = distribute_lookup (ifp->name); + if (dist) + babel_distribute_update (dist); +} + +/* Update all interface's distribute list. */ +static void +babel_distribute_update_all (struct prefix_list *notused) +{ + struct interface *ifp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + babel_distribute_update_interface (ifp); +} + +static void +babel_distribute_update_all_wrapper (struct access_list *notused) +{ + babel_distribute_update_all(NULL); +} + + +/* [Command] */ +DEFUN (router_babel, + router_babel_cmd, + "router babel", + "Enable a routing process\n" + "Make Babel instance command\n") +{ + int ret; + + vty->node = BABEL_NODE; + + if (!babel_routing_process) { + ret = babel_create_routing_process (); + + /* Notice to user we couldn't create Babel. */ + if (ret < 0) { + zlog_warn ("can't create Babel"); + } + } + + return CMD_SUCCESS; +} + +/* [Command] */ +DEFUN (no_router_babel, + no_router_babel_cmd, + "no router babel", + NO_STR + "Disable a routing process\n" + "Remove Babel instance command\n") +{ + if(babel_routing_process) + babel_clean_routing_process(); + return CMD_SUCCESS; +} + +/* [Babel Command] */ +DEFUN (babel_set_protocol_group, + babel_set_protocol_group_cmd, + "protocol group ADDR", + "Set the protocol group, default is ff02::1:6.\n" + "IPv6 address") +{ + int ret; + struct prefix p; + + ret = str2prefix (argv[0], &p); + + /* Given string is: */ + if (ret) { /* an IPv4 or v6 network */ + if (p.family != AF_INET6) { + return CMD_WARNING; + } + in6addr_to_uchar(protocol_group, &p.u.prefix6); + } else { /* an interface name */ + return CMD_WARNING; + } + + if (ret < 0) { + vty_out (vty, "%s must be an ipv6 address%s", argv[0], + VTY_NEWLINE); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +/* [Babel Command] */ +DEFUN (babel_set_protocol_port, + babel_set_protocol_port_cmd, + "protocol port <1-65535>", + "Set the protocol port (default is defined in RFC).\n" + "IPv6 address") +{ + int port = atoi(argv[0]); + protocol_port = port; + + return CMD_SUCCESS; +} + + +void +babeld_quagga_init(void) +{ + + install_node(&cmd_babel_node, &babel_config_write); + + install_element(CONFIG_NODE, &router_babel_cmd); + install_element(CONFIG_NODE, &no_router_babel_cmd); + + install_default(BABEL_NODE); + + babel_if_init(); + + /* Access list install. */ + access_list_init (); + access_list_add_hook (babel_distribute_update_all_wrapper); + access_list_delete_hook (babel_distribute_update_all_wrapper); + + /* Prefix list initialize.*/ + prefix_list_init (); + prefix_list_add_hook (babel_distribute_update_all); + prefix_list_delete_hook (babel_distribute_update_all); + + /* Distribute list install. */ + distribute_list_init (BABEL_NODE); + distribute_list_add_hook (babel_distribute_update); + distribute_list_delete_hook (babel_distribute_update); +} + +int /* DEPRECATED: for compatibility with old babeld (configuration.{c,h})*/ +input_filter(const unsigned char *id, + const unsigned char *prefix, unsigned short plen, + const unsigned char *neigh, unsigned int ifindex) +{ + struct interface *ifp = NULL; + struct prefix p; + p.family = v4mapped(prefix) ? AF_INET : AF_INET6; + p.prefixlen = plen; + if (p.family == AF_INET) { + uchar_to_inaddr(&p.u.prefix4, prefix); + } else { + uchar_to_in6addr(&p.u.prefix6, prefix); + } + + ifp = if_lookup_by_index(ifindex); + if (ifp != NULL) { + return babel_filter_in(&p, babel_get_if_nfo(ifp)); + } + + return babel_filter_in(&p, NULL); +} + +int /* DEPRECATED: for compatibility with old babeld */ +output_filter(const unsigned char *id, const unsigned char *prefix, + unsigned short plen, unsigned int ifindex) +{ + struct interface *ifp = NULL; + struct prefix p; + p.family = v4mapped(prefix) ? AF_INET : AF_INET6; + p.prefixlen = plen; + if (p.family == AF_INET) { + uchar_to_inaddr(&p.u.prefix4, prefix); + } else { + uchar_to_in6addr(&p.u.prefix6, prefix); + } + + ifp = if_lookup_by_index(ifindex); + if (ifp != NULL) { + return babel_filter_out(&p, babel_get_if_nfo(ifp)); + } + + return babel_filter_out(&p, NULL); +} + +int /* DEPRECATED: for compatibility with old babeld */ +redistribute_filter(const unsigned char *prefix, unsigned short plen, + unsigned int ifindex, int proto) +{ + struct interface *ifp = NULL; + struct prefix p; + p.family = v4mapped(prefix) ? AF_INET : AF_INET6; + p.prefixlen = plen; + if (p.family == AF_INET) { + uchar_to_inaddr(&p.u.prefix4, prefix); + } else { + uchar_to_in6addr(&p.u.prefix6, prefix); + } + + ifp = if_lookup_by_index(ifindex); + if (ifp != NULL) { + return babel_filter_redistribute(&p,babel_get_if_nfo(ifp)); + } + + return babel_filter_redistribute(&p, NULL); +} diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample new file mode 100644 index 00000000..bb2c1dbb --- /dev/null +++ b/babeld/babeld.conf.sample @@ -0,0 +1,31 @@ +# placeholder +# This is an example. See documentation for more results. +# +# let 'eth0' be an interface. +# +# Remark: '#' and '!' are comments. +# NB, just for this example: +# each line at the same indentation is only dependant of the less level +# line. BUT the quagga parser is insensitive. + + +# setup the routing for Babel. +router babel #activate the Babel routing babeld.c + network eth0 #eth0 is match interface.c + redistribute kernel #(kernel|connected|static|ospf6|bgp) babel_zebra.c + no redistribute static #... + + +# setup each interface, one by one... +Interface eth0 #Set eth0 options interface.c +! wired #with wire interface.c + wireless #without wire (défaut) interface.c +! babel split-horizon #with Split-horizon interface.c + no babel split-horizon #without (defaut) interface.c + hello interval 4096 #default = 4096 (in miliseconds) interface.c + + +# setup the log destination. +# log stdout +# log stdout debugging +log file /var/log/quagga/babeld.log \ No newline at end of file diff --git a/babeld/babeld.h b/babeld/babeld.h new file mode 100644 index 00000000..87b4de7b --- /dev/null +++ b/babeld/babeld.h @@ -0,0 +1,136 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BABEL_BABELD_H +#define BABEL_BABELD_H + +#include + +#define INFINITY ((unsigned short)(~0)) + +#ifndef RTPROT_BABEL +#define RTPROT_BABEL 42 +#endif + +#define RTPROT_BABEL_LOCAL -2 + +#undef MAX +#undef MIN + +#define MAX(x,y) ((x)<=(y)?(y):(x)) +#define MIN(x,y) ((x)<=(y)?(x):(y)) + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L +/* nothing */ +#elif defined(__GNUC__) +#define inline __inline +#if (__GNUC__ >= 3) +#define restrict __restrict +#else +#define restrict /**/ +#endif +#else +#define inline /**/ +#define restrict /**/ +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 3) +#define ATTRIBUTE(x) __attribute__ (x) +#define LIKELY(_x) __builtin_expect(!!(_x), 1) +#define UNLIKELY(_x) __builtin_expect(!!(_x), 0) +#else +#define ATTRIBUTE(x) /**/ +#define LIKELY(_x) !!(_x) +#define UNLIKELY(_x) !!(_x) +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 3) +#define COLD __attribute__ ((cold)) +#else +#define COLD /**/ +#endif + +#ifndef IF_NAMESIZE +#include +#include +#endif + +#ifdef HAVE_VALGRIND +#include +#else +#ifndef VALGRIND_MAKE_MEM_UNDEFINED +#define VALGRIND_MAKE_MEM_UNDEFINED(a, b) do {} while(0) +#endif +#ifndef VALGRIND_CHECK_MEM_IS_DEFINED +#define VALGRIND_CHECK_MEM_IS_DEFINED(a, b) do {} while(0) +#endif +#endif + + +#define BABEL_VTY_PORT 2609 +#define BABEL_DEFAULT_CONFIG "babeld.conf" +#define BABEL_VERSION "0.1 for quagga" +#define BABELD_DEFAULT_HELLO_INTERVAL 4000 /* miliseconds */ + + +/* Babel socket. */ +extern int protocol_socket; + +/* Babel structure. */ +struct babel +{ + /* Babel threads. */ + struct thread *t_read; /* on Babel protocol's socket */ + struct thread *t_update; /* timers */ +}; + + +extern void babeld_quagga_init(void); +extern int input_filter(const unsigned char *id, + const unsigned char *prefix, unsigned short plen, + const unsigned char *neigh, unsigned int ifindex); +extern int output_filter(const unsigned char *id, const unsigned char *prefix, + unsigned short plen, unsigned int ifindex); +extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, + unsigned int ifindex, int proto); +extern int resize_receive_buffer(int size); +extern void schedule_neighbours_check(int msecs, int override); + + +#endif /* BABEL_BABELD_H */ diff --git a/babeld/kernel.c b/babeld/kernel.c new file mode 100644 index 00000000..4b5bd7b2 --- /dev/null +++ b/babeld/kernel.c @@ -0,0 +1,113 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include + +#include "babeld.h" + +#include "kernel_zebra.c" + +/* Like gettimeofday, but returns monotonic time. If POSIX clocks are not + available, falls back to gettimeofday but enforces monotonicity. */ +int +gettime(struct timeval *tv) +{ + int rc; + static time_t offset = 0, previous = 0; + +#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC) + static int have_posix_clocks = -1; + + if(UNLIKELY(have_posix_clocks < 0)) { + struct timespec ts; + rc = clock_gettime(CLOCK_MONOTONIC, &ts); + if(rc < 0) { + have_posix_clocks = 0; + } else { + have_posix_clocks = 1; + } + } + + if(have_posix_clocks) { + struct timespec ts; + int rc; + rc = clock_gettime(CLOCK_MONOTONIC, &ts); + if(rc < 0) + return rc; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + return rc; + } +#endif + + rc = gettimeofday(tv, NULL); + if(rc < 0) + return rc; + tv->tv_sec += offset; + if(UNLIKELY(previous > tv->tv_sec)) { + offset += previous - tv->tv_sec; + tv->tv_sec = previous; + } + previous = tv->tv_sec; + return rc; +} + +/* If /dev/urandom doesn't exist, this will fail with ENOENT, which the + caller will deal with gracefully. */ + +int +read_random_bytes(void *buf, size_t len) +{ + int fd; + int rc; + + fd = open("/dev/urandom", O_RDONLY); + if(fd < 0) { + rc = -1; + } else { + rc = read(fd, buf, len); + if(rc < 0 || (unsigned) rc < len) + rc = -1; + close(fd); + } + return rc; +} + diff --git a/babeld/kernel.h b/babeld/kernel.h new file mode 100644 index 00000000..d9d650dc --- /dev/null +++ b/babeld/kernel.h @@ -0,0 +1,82 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include "babel_main.h" +#include "if.h" + +#define KERNEL_INFINITY 0xFFFF + +struct kernel_route { + unsigned char prefix[16]; + int plen; + int metric; + unsigned int ifindex; + int proto; + unsigned char gw[16]; +}; + +#define ROUTE_FLUSH 0 +#define ROUTE_ADD 1 +#define ROUTE_MODIFY 2 + +#define CHANGE_LINK (1 << 0) +#define CHANGE_ROUTE (1 << 1) +#define CHANGE_ADDR (1 << 2) + +extern int export_table, import_table; + +int kernel_setup(int setup); +int kernel_setup_socket(int setup); +int kernel_setup_interface(int setup, struct interface *interface); +int kernel_interface_operational(struct interface *interface); +int kernel_interface_ipv4(struct interface *interface, + unsigned char *addr_r); +int kernel_interface_mtu(struct interface *interface); +int kernel_interface_wireless(struct interface *interface); +int kernel_route(int operation, const unsigned char *dest, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric); +int kernel_routes(struct kernel_route *routes, int maxroutes); +int kernel_callback(int (*fn)(int, void*), void *closure); +int kernel_addresses(struct interface *interface, int ll, + struct kernel_route *routes, int maxroutes); +int if_eui64(char *ifname, int ifindex, unsigned char *eui); +int gettime(struct timeval *tv); +int read_random_bytes(void *buf, size_t len); diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c new file mode 100644 index 00000000..0fecb527 --- /dev/null +++ b/babeld/kernel_zebra.c @@ -0,0 +1,461 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include +#include "prefix.h" +#include "zclient.h" +#include "kernel.h" +#include "privs.h" +#include "command.h" +#include "vty.h" +#include "memory.h" +#include "thread.h" + +#include "util.h" +#include "babel_interface.h" +#include "babel_zebra.h" + + +static int +kernel_route_add_v4(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric); +static int +kernel_route_add_v6(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric); +static int +kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric); +static int +kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric); + + +int export_table = -1, import_table = -1; /* just for compatibility */ + +int +kernel_setup(int setup) +{ + return 0; +} + +/* get a connection with zebra client, at all costs */ +int +kernel_setup_socket(int setup) +{ + return -1; +} + +int +kernel_setup_interface(int setup, struct interface *interface) +{ + return 1; +} + +int +kernel_interface_operational(struct interface *interface) +{ + return if_is_operative(interface); +} + +int +kernel_interface_ipv4(struct interface *interface, unsigned char *addr_r) +{ + assert(0); /* function not used */ + return -1; +} + +int +kernel_interface_mtu(struct interface *interface) +{ + return MIN(interface->mtu, interface->mtu6); +} + +int +kernel_interface_wireless(struct interface *interface) +{ + return 0; +} + +extern int +zapi_ipv6_route (u_char cmd, struct zclient *zclient, + struct prefix_ipv6 *p, struct zapi_ipv6 *api); + +int +kernel_route(int operation, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + int rc; + int added; + int ipv4; + + /* Check that the protocol family is consistent. */ + if(plen >= 96 && v4mapped(pref)) { + if(!v4mapped(gate)) { + errno = EINVAL; + return -1; + } + ipv4 = 1; + } else { + if(v4mapped(gate)) { + errno = EINVAL; + return -1; + } + ipv4 = 0; + } + + switch (operation) { + case ROUTE_ADD: + return ipv4 ? + kernel_route_add_v4(pref, plen, gate, ifindex, metric, + newgate, newifindex, newmetric): + kernel_route_add_v6(pref, plen, gate, ifindex, metric, + newgate, newifindex, newmetric); + break; + case ROUTE_FLUSH: + return ipv4 ? + kernel_route_delete_v4(pref, plen, gate, ifindex, metric, + newgate, newifindex, newmetric): + kernel_route_delete_v6(pref, plen, gate, ifindex, metric, + newgate, newifindex, newmetric); + break; + case ROUTE_MODIFY: + if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && + newifindex == ifindex) + return 0; + /* It is better to add the new route before removing the old + one, to avoid losing packets. However, if the old and new + priorities are equal, this only works if the kernel supports + ECMP. So we first try the "right" order, and fall back on + the "wrong" order if it fails with EEXIST. */ + rc = ipv4 ? + kernel_route_add_v4(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0): + kernel_route_add_v6(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0); + if(rc < 0) { + if(errno != EEXIST) + return rc; + added = 0; + } else { + added = 1; + } + + if (ipv4) { + kernel_route_delete_v4(pref, plen, + gate, ifindex, metric, + NULL, 0, 0); + } else { + kernel_route_delete_v6(pref, plen, + gate, ifindex, metric, + NULL, 0, 0); + } + + if(!added) { + rc = ipv4 ? + kernel_route_add_v4(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0): + kernel_route_add_v6(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0); + if(rc < 0) { + if(errno == EEXIST) + rc = 1; + /* In principle, we should try to re-install the flushed + route on failure to preserve. However, this should + hopefully not matter much in practice. */ + } + } + + return rc; + break; + default: + zlog_err("this should never appens (false value - kernel_route)"); + assert(0); + exit(1); + break; + } +} + +static int +kernel_route_add_v4(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + unsigned int tmp_ifindex = ifindex; /* (for typing) */ + struct zapi_ipv4 api; /* quagga's communication system */ + struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ + struct in_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in_addr nexthop; /* next router to go */ + struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ + + /* convert to be comprehensive by quagga */ + /* convert given addresses */ + uchar_to_inaddr(&babel_prefix_addr, pref); + uchar_to_inaddr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET; + IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen - 96; /* our plen is for v4mapped's addr */ + apply_mask_ipv4(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + debugf(BABEL_DEBUG_ROUTE, "adding route (ipv4) to zebra"); + return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, + &quagga_prefix, &api); +} + +static int +kernel_route_add_v6(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + unsigned int tmp_ifindex = ifindex; /* (for typing) */ + struct zapi_ipv6 api; /* quagga's communication system */ + struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ + struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in6_addr nexthop; /* next router to go */ + struct in6_addr *nexthop_pointer = &nexthop; + + /* convert to be comprehensive by quagga */ + /* convert given addresses */ + uchar_to_in6addr(&babel_prefix_addr, pref); + uchar_to_in6addr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET6; + IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen; + apply_mask_ipv6(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + debugf(BABEL_DEBUG_ROUTE, "adding route (ipv6) to zebra"); + return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, + &quagga_prefix, &api); +} + +static int +kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + unsigned int tmp_ifindex = ifindex; /* (for typing) */ + struct zapi_ipv4 api; /* quagga's communication system */ + struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ + struct in_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in_addr nexthop; /* next router to go */ + struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ + + /* convert to be comprehensive by quagga */ + /* convert given addresses */ + uchar_to_inaddr(&babel_prefix_addr, pref); + uchar_to_inaddr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET; + IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen - 96; + apply_mask_ipv4(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + + debugf(BABEL_DEBUG_ROUTE, "removing route (ipv4) to zebra"); + return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, + &quagga_prefix, &api); +} + +static int +kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric, + const unsigned char *newgate, int newifindex, + unsigned int newmetric) +{ + unsigned int tmp_ifindex = ifindex; /* (for typing) */ + struct zapi_ipv6 api; /* quagga's communication system */ + struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ + struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ + struct in6_addr nexthop; /* next router to go */ + struct in6_addr *nexthop_pointer = &nexthop; + + /* convert to be comprehensive by quagga */ + /* convert given addresses */ + uchar_to_in6addr(&babel_prefix_addr, pref); + uchar_to_in6addr(&nexthop, gate); + + /* make prefix structure */ + memset (&quagga_prefix, 0, sizeof(quagga_prefix)); + quagga_prefix.family = AF_INET6; + IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); + quagga_prefix.prefixlen = plen; + apply_mask_ipv6(&quagga_prefix); + + api.type = ZEBRA_ROUTE_BABEL; + api.flags = 0; + api.message = 0; + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + + debugf(BABEL_DEBUG_ROUTE, "removing route (ipv6) to zebra"); + return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, + &quagga_prefix, &api); +} + +int +kernel_routes(struct kernel_route *routes, int maxroutes) +{ + fprintf(stderr, "\tkernel_routes --- not implemented\n"); + return 0; +} + +int +kernel_callback(int (*fn)(int, void*), void *closure) +{ + struct thread thread; + fprintf(stderr, "\tkernel_callback\n"); + /* do a little work on threads */ + if (thread_fetch(master, &thread) != NULL) { + thread_call (&thread); + } + return 0; +} + +int +kernel_addresses(struct interface *interface, int ll, + struct kernel_route *routes, int maxroutes) +{ + fprintf(stderr, "\tkernel_addresses --- not implemented\n"); + return 0; +} + +int +if_eui64(char *ifname, int ifindex, unsigned char *eui) +{ + struct interface *ifp = if_lookup_by_index(ifindex); + if (ifp == NULL) { + return -1; + } +#ifdef HAVE_STRUCT_SOCKADDR_DL + u_char len = ifp->sdl.sdl_alen; + char *tmp = ifp->sdl.sdl_data + ifp->sdl.sdl_nlen; +#else + u_char len = (u_char) ifp->hw_addr_len; + char *tmp = (void*) ifp->hw_addr; +#endif + if (len == 8) { + memcpy(eui, tmp, 8); + eui[0] ^= 2; + } else if (len == 6) { + memcpy(eui, tmp, 3); + eui[3] = 0xFF; + eui[4] = 0xFE; + memcpy(eui+5, tmp+3, 3); + } else if (len > 8) { + memcpy(eui, tmp, 8); + } else if (len > 0){ + memset(eui, 0, 8 - len); + memcpy(eui + 8 - len, tmp, len); + } else { + return -1; + } + return 0; +} diff --git a/babeld/message.c b/babeld/message.c new file mode 100644 index 00000000..bfb17625 --- /dev/null +++ b/babeld/message.c @@ -0,0 +1,1456 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "if.h" + +#include "babeld.h" +#include "util.h" +#include "net.h" +#include "babel_interface.h" +#include "source.h" +#include "neighbour.h" +#include "route.h" +#include "xroute.h" +#include "resend.h" +#include "message.h" +#include "kernel.h" + +unsigned char packet_header[4] = {42, 2}; + +int parasitic = 0; +int split_horizon = 1; + +unsigned short myseqno = 0; +struct timeval seqno_time = {0, 0}; + +#define UNICAST_BUFSIZE 1024 +int unicast_buffered = 0; +unsigned char *unicast_buffer = NULL; +struct neighbour *unicast_neighbour = NULL; +struct timeval unicast_flush_timeout = {0, 0}; + +static const unsigned char v4prefix[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; + +static int +network_prefix(int ae, int plen, unsigned int omitted, + const unsigned char *p, const unsigned char *dp, + unsigned int len, unsigned char *p_r) +{ + unsigned pb; + unsigned char prefix[16]; + + if(plen >= 0) + pb = (plen + 7) / 8; + else if(ae == 1) + pb = 4; + else + pb = 16; + + if(pb > 16) + return -1; + + memset(prefix, 0, 16); + + switch(ae) { + case 0: break; + case 1: + if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) + return -1; + memcpy(prefix, v4prefix, 12); + if(omitted) { + if (dp == NULL || !v4mapped(dp)) return -1; + memcpy(prefix, dp, 12 + omitted); + } + if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + break; + case 2: + if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; + if(omitted) { + if (dp == NULL || v4mapped(dp)) return -1; + memcpy(prefix, dp, omitted); + } + if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + break; + case 3: + if(pb > 8 && len < pb - 8) return -1; + prefix[0] = 0xfe; + prefix[1] = 0x80; + if(pb > 8) memcpy(prefix + 8, p, pb - 8); + break; + default: + return -1; + } + + mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); + return 1; +} + +static int +network_address(int ae, const unsigned char *a, unsigned int len, + unsigned char *a_r) +{ + return network_prefix(ae, -1, 0, a, NULL, len, a_r); +} + +void +parse_packet(const unsigned char *from, struct interface *ifp, + const unsigned char *packet, int packetlen) +{ + int i; + const unsigned char *message; + unsigned char type, len; + int bodylen; + struct neighbour *neigh; + int have_router_id = 0, have_v4_prefix = 0, have_v6_prefix = 0, + have_v4_nh = 0, have_v6_nh = 0; + unsigned char router_id[8], v4_prefix[16], v6_prefix[16], + v4_nh[16], v6_nh[16]; + + if(!linklocal(from)) { + fprintf(stderr, "Received packet from non-local address %s.\n", + format_address(from)); + return; + } + + if(packet[0] != 42) { + fprintf(stderr, "Received malformed packet on %s from %s.\n", + ifp->name, format_address(from)); + return; + } + + if(packet[1] != 2) { + fprintf(stderr, + "Received packet with unknown version %d on %s from %s.\n", + packet[1], ifp->name, format_address(from)); + return; + } + + neigh = find_neighbour(from, ifp); + if(neigh == NULL) { + fprintf(stderr, "Couldn't allocate neighbour.\n"); + return; + } + + DO_NTOHS(bodylen, packet + 2); + + if(bodylen + 4 > packetlen) { + fprintf(stderr, "Received truncated packet (%d + 4 > %d).\n", + bodylen, packetlen); + bodylen = packetlen - 4; + } + + i = 0; + while(i < bodylen) { + message = packet + 4 + i; + type = message[0]; + if(type == MESSAGE_PAD1) { + debugf(BABEL_DEBUG_COMMON,"Received pad1 from %s on %s.", + format_address(from), ifp->name); + i++; + continue; + } + if(i + 1 > bodylen) { + fprintf(stderr, "Received truncated message.\n"); + break; + } + len = message[1]; + if(i + len > bodylen) { + fprintf(stderr, "Received truncated message.\n"); + break; + } + + if(type == MESSAGE_PADN) { + debugf(BABEL_DEBUG_COMMON,"Received pad%d from %s on %s.", + len, format_address(from), ifp->name); + } else if(type == MESSAGE_ACK_REQ) { + unsigned short nonce, interval; + if(len < 6) goto fail; + DO_NTOHS(nonce, message + 4); + DO_NTOHS(interval, message + 6); + debugf(BABEL_DEBUG_COMMON,"Received ack-req (%04X %d) from %s on %s.", + nonce, interval, format_address(from), ifp->name); + send_ack(neigh, nonce, interval); + } else if(type == MESSAGE_ACK) { + debugf(BABEL_DEBUG_COMMON,"Received ack from %s on %s.", + format_address(from), ifp->name); + /* Nothing right now */ + } else if(type == MESSAGE_HELLO) { + unsigned short seqno, interval; + int changed; + if(len < 6) goto fail; + DO_NTOHS(seqno, message + 4); + DO_NTOHS(interval, message + 6); + debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", + seqno, interval, + format_address(from), ifp->name); + babel_get_if_nfo(ifp)->activity_time = babel_now.tv_sec; + changed = update_neighbour(neigh, seqno, interval); + update_neighbour_metric(neigh, changed); + if(interval > 0) + schedule_neighbours_check(interval * 10, 0); + } else if(type == MESSAGE_IHU) { + unsigned short txcost, interval; + unsigned char address[16]; + int rc; + if(len < 6) goto fail; + DO_NTOHS(txcost, message + 4); + DO_NTOHS(interval, message + 6); + rc = network_address(message[2], message + 8, len - 6, address); + if(rc < 0) goto fail; + debugf(BABEL_DEBUG_COMMON,"Received ihu %d (%d) from %s on %s for %s.", + txcost, interval, + format_address(from), ifp->name, + format_address(address)); + if(message[2] == 0 || is_interface_ll_address(ifp, address)) { + int changed = txcost != neigh->txcost; + neigh->txcost = txcost; + neigh->ihu_time = babel_now; + neigh->ihu_interval = interval; + update_neighbour_metric(neigh, changed); + if(interval > 0) + schedule_neighbours_check(interval * 10 * 3, 0); + } + } else if(type == MESSAGE_ROUTER_ID) { + if(len < 10) { + have_router_id = 0; + goto fail; + } + memcpy(router_id, message + 4, 8); + have_router_id = 1; + debugf(BABEL_DEBUG_COMMON,"Received router-id %s from %s on %s.", + format_eui64(router_id), format_address(from), ifp->name); + } else if(type == MESSAGE_NH) { + unsigned char nh[16]; + int rc; + if(len < 2) { + have_v4_nh = 0; + have_v6_nh = 0; + goto fail; + } + rc = network_address(message[2], message + 4, len - 2, + nh); + if(rc < 0) { + have_v4_nh = 0; + have_v6_nh = 0; + goto fail; + } + debugf(BABEL_DEBUG_COMMON,"Received nh %s (%d) from %s on %s.", + format_address(nh), message[2], + format_address(from), ifp->name); + if(message[2] == 1) { + memcpy(v4_nh, nh, 16); + have_v4_nh = 1; + } else { + memcpy(v6_nh, nh, 16); + have_v6_nh = 1; + } + } else if(type == MESSAGE_UPDATE) { + unsigned char prefix[16], *nh; + unsigned char plen; + unsigned short interval, seqno, metric; + int rc; + if(len < 10) { + if(len < 2 || message[3] & 0x80) + have_v4_prefix = have_v6_prefix = 0; + goto fail; + } + DO_NTOHS(interval, message + 6); + DO_NTOHS(seqno, message + 8); + DO_NTOHS(metric, message + 10); + if(message[5] == 0 || + (message[3] == 1 ? have_v4_prefix : have_v6_prefix)) + rc = network_prefix(message[2], message[4], message[5], + message + 12, + message[2] == 1 ? v4_prefix : v6_prefix, + len - 10, prefix); + else + rc = -1; + if(rc < 0) { + if(message[3] & 0x80) + have_v4_prefix = have_v6_prefix = 0; + goto fail; + } + + plen = message[4] + (message[2] == 1 ? 96 : 0); + + if(message[3] & 0x80) { + if(message[2] == 1) { + memcpy(v4_prefix, prefix, 16); + have_v4_prefix = 1; + } else { + memcpy(v6_prefix, prefix, 16); + have_v6_prefix = 1; + } + } + if(message[3] & 0x40) { + if(message[2] == 1) { + memset(router_id, 0, 4); + memcpy(router_id + 4, prefix + 12, 4); + } else { + memcpy(router_id, prefix + 8, 8); + } + have_router_id = 1; + } + if(!have_router_id && message[2] != 0) { + fprintf(stderr, "Received prefix with no router id.\n"); + goto fail; + } + debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", + (message[3] & 0x80) ? "/prefix" : "", + (message[3] & 0x40) ? "/id" : "", + format_prefix(prefix, plen), + format_address(from), ifp->name); + + if(message[2] == 0) { + if(metric < 0xFFFF) { + fprintf(stderr, + "Received wildcard update with finite metric.\n"); + goto done; + } + retract_neighbour_routes(neigh); + goto done; + } else if(message[2] == 1) { + if(!have_v4_nh) + goto fail; + nh = v4_nh; + } else if(have_v6_nh) { + nh = v6_nh; + } else { + nh = neigh->address; + } + + if(message[2] == 1) { + if(!babel_get_if_nfo(ifp)->ipv4) + goto done; + } + + update_route(router_id, prefix, plen, seqno, metric, interval, + neigh, nh); + } else if(type == MESSAGE_REQUEST) { + unsigned char prefix[16], plen; + int rc; + if(len < 2) goto fail; + rc = network_prefix(message[2], message[3], 0, + message + 4, NULL, len - 2, prefix); + if(rc < 0) goto fail; + plen = message[3] + (message[2] == 1 ? 96 : 0); + debugf(BABEL_DEBUG_COMMON,"Received request for %s from %s on %s.", + message[2] == 0 ? "any" : format_prefix(prefix, plen), + format_address(from), ifp->name); + if(message[2] == 0) { + /* If a neighbour is requesting a full route dump from us, + we might as well send it an IHU. */ + send_ihu(neigh, NULL); + send_update(neigh->ifp, 0, NULL, 0); + } else { + send_update(neigh->ifp, 0, prefix, plen); + } + } else if(type == MESSAGE_MH_REQUEST) { + unsigned char prefix[16], plen; + unsigned short seqno; + int rc; + if(len < 14) goto fail; + DO_NTOHS(seqno, message + 4); + rc = network_prefix(message[2], message[3], 0, + message + 16, NULL, len - 14, prefix); + if(rc < 0) goto fail; + plen = message[3] + (message[2] == 1 ? 96 : 0); + debugf(BABEL_DEBUG_COMMON,"Received request (%d) for %s from %s on %s (%s, %d).", + message[6], + format_prefix(prefix, plen), + format_address(from), ifp->name, + format_eui64(message + 8), seqno); + handle_request(neigh, prefix, plen, message[6], + seqno, message + 8); + } else { + debugf(BABEL_DEBUG_COMMON,"Received unknown packet type %d from %s on %s.", + type, format_address(from), ifp->name); + } + done: + i += len + 2; + continue; + + fail: + fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n", + message[0], message[1], format_address(from), ifp->name); + goto done; + } + return; +} + +/* Under normal circumstances, there are enough moderation mechanisms + elsewhere in the protocol to make sure that this last-ditch check + should never trigger. But I'm superstitious. */ + +static int +check_bucket(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bucket <= 0) { + int seconds = babel_now.tv_sec - babel_ifp->bucket_time; + if(seconds > 0) { + babel_ifp->bucket = MIN(BUCKET_TOKENS_MAX, + seconds * BUCKET_TOKENS_PER_SEC); + } + /* Reset bucket time unconditionally, in case clock is stepped. */ + babel_ifp->bucket_time = babel_now.tv_sec; + } + + if(babel_ifp->bucket > 0) { + babel_ifp->bucket--; + return 1; + } else { + return 0; + } +} + +void +flushbuf(struct interface *ifp) +{ + int rc; + struct sockaddr_in6 sin6; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + + assert(babel_ifp->buffered <= babel_ifp->bufsize); + + flushupdates(ifp); + + if(babel_ifp->buffered > 0) { + debugf(BABEL_DEBUG_COMMON," (flushing %d buffered bytes on %s)", + babel_ifp->buffered, ifp->name); + if(check_bucket(ifp)) { + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, protocol_group, 16); + sin6.sin6_port = htons(protocol_port); + sin6.sin6_scope_id = ifp->ifindex; + DO_HTONS(packet_header + 2, babel_ifp->buffered); + rc = babel_send(protocol_socket, + packet_header, sizeof(packet_header), + babel_ifp->sendbuf, babel_ifp->buffered, + (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + zlog_err("send: %s", safe_strerror(errno)); + } else { + fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n", + ifp->name); + } + } + VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); + babel_ifp->buffered = 0; + babel_ifp->have_buffered_hello = 0; + babel_ifp->have_buffered_id = 0; + babel_ifp->have_buffered_nh = 0; + babel_ifp->have_buffered_prefix = 0; + babel_ifp->flush_timeout.tv_sec = 0; + babel_ifp->flush_timeout.tv_usec = 0; +} + +static void +schedule_flush(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + unsigned msecs = jitter(babel_ifp, 0); + if(babel_ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->flush_timeout, msecs); +} + +static void +schedule_flush_now(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + /* Almost now */ + unsigned msecs = roughly(10); + if(babel_ifp->flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->flush_timeout, msecs); +} + +static void +schedule_unicast_flush(unsigned msecs) +{ + if(!unicast_neighbour) + return; + if(unicast_flush_timeout.tv_sec != 0 && + timeval_minus_msec(&unicast_flush_timeout, &babel_now) < msecs) + return; + unicast_flush_timeout.tv_usec = (babel_now.tv_usec + msecs * 1000) %1000000; + unicast_flush_timeout.tv_sec = + babel_now.tv_sec + (babel_now.tv_usec / 1000 + msecs) / 1000; +} + +static void +ensure_space(struct interface *ifp, int space) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bufsize - babel_ifp->buffered < space) + flushbuf(ifp); +} + +static void +start_message(struct interface *ifp, int type, int len) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->bufsize - babel_ifp->buffered < len + 2) + flushbuf(ifp); + babel_ifp->sendbuf[babel_ifp->buffered++] = type; + babel_ifp->sendbuf[babel_ifp->buffered++] = len; +} + +static void +end_message(struct interface *ifp, int type, int bytes) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert(babel_ifp->buffered >= bytes + 2 && + babel_ifp->sendbuf[babel_ifp->buffered - bytes - 2] == type && + babel_ifp->sendbuf[babel_ifp->buffered - bytes - 1] == bytes); + schedule_flush(ifp); +} + +static void +accumulate_byte(struct interface *ifp, unsigned char value) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + babel_ifp->sendbuf[babel_ifp->buffered++] = value; +} + +static void +accumulate_short(struct interface *ifp, unsigned short value) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + DO_HTONS(babel_ifp->sendbuf + babel_ifp->buffered, value); + babel_ifp->buffered += 2; +} + +static void +accumulate_bytes(struct interface *ifp, + const unsigned char *value, unsigned len) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + memcpy(babel_ifp->sendbuf + babel_ifp->buffered, value, len); + babel_ifp->buffered += len; +} + +static int +start_unicast_message(struct neighbour *neigh, int type, int len) +{ + if(unicast_neighbour) { + if(neigh != unicast_neighbour || + unicast_buffered + len + 2 >= + MIN(UNICAST_BUFSIZE, babel_get_if_nfo(neigh->ifp)->bufsize)) + flush_unicast(0); + } + if(!unicast_buffer) + unicast_buffer = malloc(UNICAST_BUFSIZE); + if(!unicast_buffer) { + zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno)); + return -1; + } + + unicast_neighbour = neigh; + + unicast_buffer[unicast_buffered++] = type; + unicast_buffer[unicast_buffered++] = len; + return 1; +} + +static void +end_unicast_message(struct neighbour *neigh, int type, int bytes) +{ + assert(unicast_neighbour == neigh && unicast_buffered >= bytes + 2 && + unicast_buffer[unicast_buffered - bytes - 2] == type && + unicast_buffer[unicast_buffered - bytes - 1] == bytes); + schedule_unicast_flush(jitter(babel_get_if_nfo(neigh->ifp), 0)); +} + +static void +accumulate_unicast_byte(struct neighbour *neigh, unsigned char value) +{ + unicast_buffer[unicast_buffered++] = value; +} + +static void +accumulate_unicast_short(struct neighbour *neigh, unsigned short value) +{ + DO_HTONS(unicast_buffer + unicast_buffered, value); + unicast_buffered += 2; +} + +static void +accumulate_unicast_bytes(struct neighbour *neigh, + const unsigned char *value, unsigned len) +{ + memcpy(unicast_buffer + unicast_buffered, value, len); + unicast_buffered += len; +} + +void +send_ack(struct neighbour *neigh, unsigned short nonce, unsigned short interval) +{ + int rc; + debugf(BABEL_DEBUG_COMMON,"Sending ack (%04x) to %s on %s.", + nonce, format_address(neigh->address), neigh->ifp->name); + rc = start_unicast_message(neigh, MESSAGE_ACK, 2); if(rc < 0) return; + accumulate_unicast_short(neigh, nonce); + end_unicast_message(neigh, MESSAGE_ACK, 2); + /* Roughly yields a value no larger than 3/2, so this meets the deadline */ + schedule_unicast_flush(roughly(interval * 6)); +} + +void +send_hello_noupdate(struct interface *ifp, unsigned interval) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + /* This avoids sending multiple hellos in a single packet, which breaks + link quality estimation. */ + if(babel_ifp->have_buffered_hello) + flushbuf(ifp); + + babel_ifp->hello_seqno = seqno_plus(babel_ifp->hello_seqno, 1); + set_timeout(&babel_ifp->hello_timeout, babel_ifp->hello_interval); + + if(!if_up(ifp)) + return; + + debugf(BABEL_DEBUG_COMMON,"Sending hello %d (%d) to %s.", + babel_ifp->hello_seqno, interval, ifp->name); + + start_message(ifp, MESSAGE_HELLO, 6); + accumulate_short(ifp, 0); + accumulate_short(ifp, babel_ifp->hello_seqno); + accumulate_short(ifp, interval > 0xFFFF ? 0xFFFF : interval); + end_message(ifp, MESSAGE_HELLO, 6); + babel_ifp->have_buffered_hello = 1; +} + +void +send_hello(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); + /* Send full IHU every 3 hellos, and marginal IHU each time */ + if(babel_ifp->hello_seqno % 3 == 0) + send_ihu(NULL, ifp); + else + send_marginal_ihu(ifp); +} + +void +flush_unicast(int dofree) +{ + struct sockaddr_in6 sin6; + int rc; + + if(unicast_buffered == 0) + goto done; + + if(!if_up(unicast_neighbour->ifp)) + goto done; + + /* Preserve ordering of messages */ + flushbuf(unicast_neighbour->ifp); + + if(check_bucket(unicast_neighbour->ifp)) { + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, unicast_neighbour->address, 16); + sin6.sin6_port = htons(protocol_port); + sin6.sin6_scope_id = unicast_neighbour->ifp->ifindex; + DO_HTONS(packet_header + 2, unicast_buffered); + rc = babel_send(protocol_socket, + packet_header, sizeof(packet_header), + unicast_buffer, unicast_buffered, + (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + zlog_err("send(unicast): %s", safe_strerror(errno)); + } else { + fprintf(stderr, + "Warning: bucket full, dropping unicast packet" + "to %s if %s.\n", + format_address(unicast_neighbour->address), + unicast_neighbour->ifp->name); + } + + done: + VALGRIND_MAKE_MEM_UNDEFINED(unicast_buffer, UNICAST_BUFSIZE); + unicast_buffered = 0; + if(dofree && unicast_buffer) { + free(unicast_buffer); + unicast_buffer = NULL; + } + unicast_neighbour = NULL; + unicast_flush_timeout.tv_sec = 0; + unicast_flush_timeout.tv_usec = 0; +} + +static void +really_send_update(struct interface *ifp, + const unsigned char *id, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, unsigned short metric) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + int add_metric, v4, real_plen, omit = 0; + const unsigned char *real_prefix; + unsigned short flags = 0; + + if(!if_up(ifp)) + return; + + add_metric = output_filter(id, prefix, plen, ifp->ifindex); + if(add_metric >= INFINITY) + return; + + metric = MIN(metric + add_metric, INFINITY); + /* Worst case */ + ensure_space(ifp, 20 + 12 + 28); + + v4 = plen >= 96 && v4mapped(prefix); + + if(v4) { + if(!babel_ifp->ipv4) + return; + if(!babel_ifp->have_buffered_nh || + memcmp(babel_ifp->buffered_nh, babel_ifp->ipv4, 4) != 0) { + start_message(ifp, MESSAGE_NH, 6); + accumulate_byte(ifp, 1); + accumulate_byte(ifp, 0); + accumulate_bytes(ifp, babel_ifp->ipv4, 4); + end_message(ifp, MESSAGE_NH, 6); + memcpy(babel_ifp->buffered_nh, babel_ifp->ipv4, 4); + babel_ifp->have_buffered_nh = 1; + } + + real_prefix = prefix + 12; + real_plen = plen - 96; + } else { + if(babel_ifp->have_buffered_prefix) { + while(omit < plen / 8 && + babel_ifp->buffered_prefix[omit] == prefix[omit]) + omit++; + } + if(!babel_ifp->have_buffered_prefix || plen >= 48) + flags |= 0x80; + real_prefix = prefix; + real_plen = plen; + } + + if(!babel_ifp->have_buffered_id + || memcmp(id, babel_ifp->buffered_id, 8) != 0) { + if(real_plen == 128 && memcmp(real_prefix + 8, id, 8) == 0) { + flags |= 0x40; + } else { + start_message(ifp, MESSAGE_ROUTER_ID, 10); + accumulate_short(ifp, 0); + accumulate_bytes(ifp, id, 8); + end_message(ifp, MESSAGE_ROUTER_ID, 10); + } + memcpy(babel_ifp->buffered_id, id, 16); + babel_ifp->have_buffered_id = 1; + } + + start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + accumulate_byte(ifp, v4 ? 1 : 2); + accumulate_byte(ifp, flags); + accumulate_byte(ifp, real_plen); + accumulate_byte(ifp, omit); + accumulate_short(ifp, (babel_ifp->update_interval + 5) / 10); + accumulate_short(ifp, seqno); + accumulate_short(ifp, metric); + accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); + end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + + if(flags & 0x80) { + memcpy(babel_ifp->buffered_prefix, prefix, 16); + babel_ifp->have_buffered_prefix = 1; + } +} + +static int +compare_buffered_updates(const void *av, const void *bv) +{ + const struct buffered_update *a = av, *b = bv; + int rc, v4a, v4b, ma, mb; + + rc = memcmp(a->id, b->id, 8); + if(rc != 0) + return rc; + + v4a = (a->plen >= 96 && v4mapped(a->prefix)); + v4b = (b->plen >= 96 && v4mapped(b->prefix)); + + if(v4a > v4b) + return 1; + else if(v4a < v4b) + return -1; + + ma = (!v4a && a->plen == 128 && memcmp(a->prefix + 8, a->id, 8) == 0); + mb = (!v4b && b->plen == 128 && memcmp(b->prefix + 8, b->id, 8) == 0); + + if(ma > mb) + return -1; + else if(mb > ma) + return 1; + + if(a->plen < b->plen) + return 1; + else if(a->plen > b->plen) + return -1; + + return memcmp(a->prefix, b->prefix, 16); +} + +void +flushupdates(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + struct xroute *xroute; + struct route *route; + const unsigned char *last_prefix = NULL; + unsigned char last_plen = 0xFF; + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + flushupdates(ifp_aux); + return; + } + + babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->num_buffered_updates > 0) { + struct buffered_update *b = babel_ifp->buffered_updates; + int n = babel_ifp->num_buffered_updates; + + babel_ifp->buffered_updates = NULL; + babel_ifp->update_bufsize = 0; + babel_ifp->num_buffered_updates = 0; + + if(!if_up(ifp)) + goto done; + + debugf(BABEL_DEBUG_COMMON," (flushing %d buffered updates on %s (%d))", + n, ifp->name, ifp->ifindex); + + /* In order to send fewer update messages, we want to send updates + with the same router-id together, with IPv6 going out before IPv4. */ + + for(i = 0; i < n; i++) { + route = find_installed_route(b[i].prefix, b[i].plen); + if(route) + memcpy(b[i].id, route->src->id, 8); + else + memcpy(b[i].id, myid, 8); + } + + qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); + + for(i = 0; i < n; i++) { + unsigned short seqno; + unsigned short metric; + + /* The same update may be scheduled multiple times before it is + sent out. Since our buffer is now sorted, it is enough to + compare with the previous update. */ + + if(last_prefix) { + if(b[i].plen == last_plen && + memcmp(b[i].prefix, last_prefix, 16) == 0) + continue; + } + + xroute = find_xroute(b[i].prefix, b[i].plen); + route = find_installed_route(b[i].prefix, b[i].plen); + + if(xroute && (!route || xroute->metric <= kernel_metric)) { + really_send_update(ifp, myid, + xroute->prefix, xroute->plen, + myseqno, xroute->metric); + last_prefix = xroute->prefix; + last_plen = xroute->plen; + } else if(route) { + seqno = route->seqno; + metric = route_metric(route); + if(metric < INFINITY) + satisfy_request(route->src->prefix, route->src->plen, + seqno, route->src->id, ifp); + if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && + route->neigh->ifp == ifp) + continue; + really_send_update(ifp, route->src->id, + route->src->prefix, + route->src->plen, + seqno, metric); + update_source(route->src, seqno, metric); + last_prefix = route->src->prefix; + last_plen = route->src->plen; + } else { + /* There's no route for this prefix. This can happen shortly + after an xroute has been retracted, so send a retraction. */ + really_send_update(ifp, myid, b[i].prefix, b[i].plen, + myseqno, INFINITY); + } + } + schedule_flush_now(ifp); + done: + free(b); + } + babel_ifp->update_flush_timeout.tv_sec = 0; + babel_ifp->update_flush_timeout.tv_usec = 0; +} + +static void +schedule_update_flush(struct interface *ifp, int urgent) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + unsigned msecs; + msecs = update_jitter(babel_ifp, urgent); + if(babel_ifp->update_flush_timeout.tv_sec != 0 && + timeval_minus_msec(&babel_ifp->update_flush_timeout, &babel_now) < msecs) + return; + set_timeout(&babel_ifp->update_flush_timeout, msecs); +} + +static void +buffer_update(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if(babel_ifp->num_buffered_updates > 0 && + babel_ifp->num_buffered_updates >= babel_ifp->update_bufsize) + flushupdates(ifp); + + if(babel_ifp->update_bufsize == 0) { + int n; + assert(babel_ifp->buffered_updates == NULL); + n = MAX(babel_ifp->bufsize / 16, 4); + again: + babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); + if(babel_ifp->buffered_updates == NULL) { + zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); + if(n > 4) { + n = 4; + goto again; + } + return; + } + babel_ifp->update_bufsize = n; + babel_ifp->num_buffered_updates = 0; + } + + memcpy(babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].prefix, + prefix, 16); + babel_ifp->buffered_updates[babel_ifp->num_buffered_updates].plen = plen; + babel_ifp->num_buffered_updates++; +} + +void +send_update(struct interface *ifp, int urgent, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = NULL; + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + struct route *route; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + send_update(ifp_aux, urgent, prefix, plen); + if(prefix) { + /* Since flushupdates only deals with non-wildcard interfaces, we + need to do this now. */ + route = find_installed_route(prefix, plen); + if(route && route_metric(route) < INFINITY) + satisfy_request(prefix, plen, route->src->seqno, route->src->id, + NULL); + } + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + if(prefix) { + if(!parasitic || find_xroute(prefix, plen)) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", + ifp->name, format_prefix(prefix, plen)); + buffer_update(ifp, prefix, plen); + } + } else { + if(!interface_idle(babel_ifp)) { + send_self_update(ifp); + if(!parasitic) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); + for(i = 0; i < numroutes; i++) + if(routes[i].installed) + buffer_update(ifp, + routes[i].src->prefix, + routes[i].src->plen); + } + } + set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); + } + schedule_update_flush(ifp, urgent); +} + +void +send_update_resend(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + int delay; + + assert(prefix != NULL); + + send_update(ifp, 1, prefix, plen); + + delay = 2000; + delay = MIN(delay, wireless_hello_interval / 2); + delay = MIN(delay, wired_hello_interval / 2); + delay = MAX(delay, 10); + record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, delay); +} + +void +send_wildcard_retraction(struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) + send_wildcard_retraction(ifp_aux); + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + start_message(ifp, MESSAGE_UPDATE, 10); + accumulate_byte(ifp, 0); + accumulate_byte(ifp, 0x40); + accumulate_byte(ifp, 0); + accumulate_byte(ifp, 0); + accumulate_short(ifp, 0xFFFF); + accumulate_short(ifp, myseqno); + accumulate_short(ifp, 0xFFFF); + end_message(ifp, MESSAGE_UPDATE, 10); + + babel_ifp->have_buffered_id = 0; +} + +void +update_myseqno() +{ + myseqno = seqno_plus(myseqno, 1); + seqno_time = babel_now; +} + +void +send_self_update(struct interface *ifp) +{ + int i; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(!if_up(ifp_aux)) + continue; + send_self_update(ifp_aux); + } + return; + } + + if(!interface_idle(babel_get_if_nfo(ifp))) { + debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); + for(i = 0; i < numxroutes; i++) + send_update(ifp, 0, xroutes[i].prefix, xroutes[i].plen); + } +} + +void +send_ihu(struct neighbour *neigh, struct interface *ifp) +{ + babel_interface_nfo *babel_ifp = NULL; + int rxcost, interval; + int ll; + + if(neigh == NULL && ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(if_up(ifp_aux)) + continue; + send_ihu(NULL, ifp_aux); + } + return; + } + + if(neigh == NULL) { + struct neighbour *ngh; + FOR_ALL_NEIGHBOURS(ngh) { + if(ngh->ifp == ifp) + send_ihu(ngh, ifp); + } + return; + } + + + if(ifp && neigh->ifp != ifp) + return; + + ifp = neigh->ifp; + babel_ifp = babel_get_if_nfo(ifp); + if(!if_up(ifp)) + return; + + rxcost = neighbour_rxcost(neigh); + interval = (babel_ifp->hello_interval * 3 + 9) / 10; + + /* Conceptually, an IHU is a unicast message. We usually send them as + multicast, since this allows aggregation into a single packet and + avoids an ARP exchange. If we already have a unicast message queued + for this neighbour, however, we might as well piggyback the IHU. */ + debugf(BABEL_DEBUG_COMMON,"Sending %sihu %d on %s to %s.", + unicast_neighbour == neigh ? "unicast " : "", + rxcost, + neigh->ifp->name, + format_address(neigh->address)); + + ll = linklocal(neigh->address); + + if(unicast_neighbour != neigh) { + start_message(ifp, MESSAGE_IHU, ll ? 14 : 22); + accumulate_byte(ifp, ll ? 3 : 2); + accumulate_byte(ifp, 0); + accumulate_short(ifp, rxcost); + accumulate_short(ifp, interval); + if(ll) + accumulate_bytes(ifp, neigh->address + 8, 8); + else + accumulate_bytes(ifp, neigh->address, 16); + end_message(ifp, MESSAGE_IHU, ll ? 14 : 22); + } else { + int rc; + rc = start_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); + if(rc < 0) return; + accumulate_unicast_byte(neigh, ll ? 3 : 2); + accumulate_unicast_byte(neigh, 0); + accumulate_unicast_short(neigh, rxcost); + accumulate_unicast_short(neigh, interval); + if(ll) + accumulate_unicast_bytes(neigh, neigh->address + 8, 8); + else + accumulate_unicast_bytes(neigh, neigh->address, 16); + end_unicast_message(neigh, MESSAGE_IHU, ll ? 14 : 22); + } +} + +/* Send IHUs to all marginal neighbours */ +void +send_marginal_ihu(struct interface *ifp) +{ + struct neighbour *neigh; + FOR_ALL_NEIGHBOURS(neigh) { + if(ifp && neigh->ifp != ifp) + continue; + if(neigh->txcost >= 384 || (neigh->reach & 0xF000) != 0xF000) + send_ihu(neigh, ifp); + } +} + +void +send_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen) +{ + babel_interface_nfo *babel_ifp = NULL; + int v4, len; + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(if_up(ifp_aux)) + continue; + send_request(ifp_aux, prefix, plen); + } + return; + } + + /* make sure any buffered updates go out before this request. */ + flushupdates(ifp); + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", + ifp->name, prefix ? format_prefix(prefix, plen) : "any"); + v4 = plen >= 96 && v4mapped(prefix); + len = !prefix ? 2 : v4 ? 6 : 18; + + start_message(ifp, MESSAGE_REQUEST, len); + accumulate_byte(ifp, !prefix ? 0 : v4 ? 1 : 2); + accumulate_byte(ifp, !prefix ? 0 : v4 ? plen - 96 : plen); + if(prefix) { + if(v4) + accumulate_bytes(ifp, prefix + 12, 4); + else + accumulate_bytes(ifp, prefix, 16); + } + end_message(ifp, MESSAGE_REQUEST, len); +} + +void +send_unicast_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen) +{ + int rc, v4, len; + + /* make sure any buffered updates go out before this request. */ + flushupdates(neigh->ifp); + + debugf(BABEL_DEBUG_COMMON,"sending unicast request to %s for %s.", + format_address(neigh->address), + prefix ? format_prefix(prefix, plen) : "any"); + v4 = plen >= 96 && v4mapped(prefix); + len = !prefix ? 2 : v4 ? 6 : 18; + + rc = start_unicast_message(neigh, MESSAGE_REQUEST, len); + if(rc < 0) return; + accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? 1 : 2); + accumulate_unicast_byte(neigh, !prefix ? 0 : v4 ? plen - 96 : plen); + if(prefix) { + if(v4) + accumulate_unicast_bytes(neigh, prefix + 12, 4); + else + accumulate_unicast_bytes(neigh, prefix, 16); + } + end_unicast_message(neigh, MESSAGE_REQUEST, len); +} + +void +send_multihop_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count) +{ + babel_interface_nfo *babel_ifp = NULL; + int v4, pb, len; + + /* Make sure any buffered updates go out before this request. */ + flushupdates(ifp); + + if(ifp == NULL) { + struct interface *ifp_aux; + struct listnode *linklist_node = NULL; + FOR_ALL_INTERFACES(ifp_aux, linklist_node) { + if(!if_up(ifp_aux)) + continue; + send_multihop_request(ifp_aux, prefix, plen, seqno, id, hop_count); + } + return; + } + + if(!if_up(ifp)) + return; + + babel_ifp = babel_get_if_nfo(ifp); + debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", + hop_count, ifp->name, format_prefix(prefix, plen)); + v4 = plen >= 96 && v4mapped(prefix); + pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; + len = 6 + 8 + pb; + + start_message(ifp, MESSAGE_MH_REQUEST, len); + accumulate_byte(ifp, v4 ? 1 : 2); + accumulate_byte(ifp, v4 ? plen - 96 : plen); + accumulate_short(ifp, seqno); + accumulate_byte(ifp, hop_count); + accumulate_byte(ifp, 0); + accumulate_bytes(ifp, id, 8); + if(prefix) { + if(v4) + accumulate_bytes(ifp, prefix + 12, pb); + else + accumulate_bytes(ifp, prefix, pb); + } + end_message(ifp, MESSAGE_MH_REQUEST, len); +} + +void +send_unicast_multihop_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count) +{ + int rc, v4, pb, len; + + /* Make sure any buffered updates go out before this request. */ + flushupdates(neigh->ifp); + + debugf(BABEL_DEBUG_COMMON,"Sending multi-hop request to %s for %s (%d hops).", + format_address(neigh->address), + format_prefix(prefix, plen), hop_count); + v4 = plen >= 96 && v4mapped(prefix); + pb = v4 ? ((plen - 96) + 7) / 8 : (plen + 7) / 8; + len = 6 + 8 + pb; + + rc = start_unicast_message(neigh, MESSAGE_MH_REQUEST, len); + if(rc < 0) return; + accumulate_unicast_byte(neigh, v4 ? 1 : 2); + accumulate_unicast_byte(neigh, v4 ? plen - 96 : plen); + accumulate_unicast_short(neigh, seqno); + accumulate_unicast_byte(neigh, hop_count); + accumulate_unicast_byte(neigh, 0); + accumulate_unicast_bytes(neigh, id, 8); + if(prefix) { + if(v4) + accumulate_unicast_bytes(neigh, prefix + 12, pb); + else + accumulate_unicast_bytes(neigh, prefix, pb); + } + end_unicast_message(neigh, MESSAGE_MH_REQUEST, len); +} + +void +send_request_resend(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, unsigned char *id) +{ + int delay; + + if(neigh) + send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); + else + send_multihop_request(NULL, prefix, plen, seqno, id, 127); + + delay = 2000; + delay = MIN(delay, wireless_hello_interval / 2); + delay = MIN(delay, wired_hello_interval / 2); + delay = MAX(delay, 10); + record_resend(RESEND_REQUEST, prefix, plen, seqno, id, + neigh ? neigh->ifp : NULL, delay); +} + +void +handle_request(struct neighbour *neigh, const unsigned char *prefix, + unsigned char plen, unsigned char hop_count, + unsigned short seqno, const unsigned char *id) +{ + struct xroute *xroute; + struct route *route; + struct neighbour *successor = NULL; + + xroute = find_xroute(prefix, plen); + route = find_installed_route(prefix, plen); + + if(xroute && (!route || xroute->metric <= kernel_metric)) { + if(hop_count > 0 && memcmp(id, myid, 8) == 0) { + if(seqno_compare(seqno, myseqno) > 0) { + if(seqno_minus(seqno, myseqno) > 100) { + /* Hopelessly out-of-date request */ + return; + } + update_myseqno(); + } + } + send_update(neigh->ifp, 1, prefix, plen); + return; + } + + if(route && + (memcmp(id, route->src->id, 8) != 0 || + seqno_compare(seqno, route->seqno) <= 0)) { + send_update(neigh->ifp, 1, prefix, plen); + return; + } + + if(hop_count <= 1) + return; + + if(route && memcmp(id, route->src->id, 8) == 0 && + seqno_minus(seqno, route->seqno) > 100) { + /* Hopelessly out-of-date */ + return; + } + + if(request_redundant(neigh->ifp, prefix, plen, seqno, id)) + return; + + /* Let's try to forward this request. */ + if(route && route_metric(route) < INFINITY) + successor = route->neigh; + + if(!successor || successor == neigh) { + /* We were about to forward a request to its requestor. Try to + find a different neighbour to forward the request to. */ + struct route *other_route; + + other_route = find_best_route(prefix, plen, 0, neigh); + if(other_route && route_metric(other_route) < INFINITY) + successor = other_route->neigh; + } + + if(!successor || successor == neigh) + /* Give up */ + return; + + send_unicast_multihop_request(successor, prefix, plen, seqno, id, + hop_count - 1); + record_resend(RESEND_REQUEST, prefix, plen, seqno, id, + neigh->ifp, 0); +} diff --git a/babeld/message.h b/babeld/message.h new file mode 100644 index 00000000..1626a887 --- /dev/null +++ b/babeld/message.h @@ -0,0 +1,112 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BABEL_MESSAGE_H +#define BABEL_MESSAGE_H + +#include "babel_interface.h" + +#define MAX_BUFFERED_UPDATES 200 + +#define BUCKET_TOKENS_MAX 200 +#define BUCKET_TOKENS_PER_SEC 40 + +#define MESSAGE_PAD1 0 +#define MESSAGE_PADN 1 +#define MESSAGE_ACK_REQ 2 +#define MESSAGE_ACK 3 +#define MESSAGE_HELLO 4 +#define MESSAGE_IHU 5 +#define MESSAGE_ROUTER_ID 6 +#define MESSAGE_NH 7 +#define MESSAGE_UPDATE 8 +#define MESSAGE_REQUEST 9 +#define MESSAGE_MH_REQUEST 10 + + +extern unsigned short myseqno; +extern struct timeval seqno_time; + +extern int parasitic; +extern int broadcast_ihu; +extern int split_horizon; + +extern unsigned char packet_header[4]; + +extern struct neighbour *unicast_neighbour; +extern struct timeval unicast_flush_timeout; + +void parse_packet(const unsigned char *from, struct interface *ifp, + const unsigned char *packet, int packetlen); +void flushbuf(struct interface *ifp); +void flushupdates(struct interface *ifp); +void send_ack(struct neighbour *neigh, unsigned short nonce, + unsigned short interval); +void send_hello_noupdate(struct interface *ifp, unsigned interval); +void send_hello(struct interface *ifp); +void flush_unicast(int dofree); +void send_update(struct interface *ifp, int urgent, + const unsigned char *prefix, unsigned char plen); +void send_update_resend(struct interface *ifp, + const unsigned char *prefix, unsigned char plen); +void send_wildcard_retraction(struct interface *ifp); +void update_myseqno(void); +void send_self_update(struct interface *ifp); +void send_ihu(struct neighbour *neigh, struct interface *ifp); +void send_marginal_ihu(struct interface *ifp); +void send_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen); +void send_unicast_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen); +void send_multihop_request(struct interface *ifp, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count); +void +send_unicast_multihop_request(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + unsigned short hop_count); +void send_request_resend(struct neighbour *neigh, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, unsigned char *id); +void handle_request(struct neighbour *neigh, const unsigned char *prefix, + unsigned char plen, unsigned char hop_count, + unsigned short seqno, const unsigned char *id); + +#endif diff --git a/babeld/neighbour.c b/babeld/neighbour.c new file mode 100644 index 00000000..43da8e09 --- /dev/null +++ b/babeld/neighbour.c @@ -0,0 +1,342 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include + +#include +#include "if.h" + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" +#include "babel_interface.h" +#include "neighbour.h" +#include "source.h" +#include "route.h" +#include "message.h" +#include "resend.h" + +struct neighbour *neighs = NULL; + +static struct neighbour * +find_neighbour_nocreate(const unsigned char *address, struct interface *ifp) +{ + struct neighbour *neigh; + FOR_ALL_NEIGHBOURS(neigh) { + if(memcmp(address, neigh->address, 16) == 0 && + neigh->ifp == ifp) + return neigh; + } + return NULL; +} + +void +flush_neighbour(struct neighbour *neigh) +{ + flush_neighbour_routes(neigh); + if(unicast_neighbour == neigh) + flush_unicast(1); + flush_resends(neigh); + + if(neighs == neigh) { + neighs = neigh->next; + } else { + struct neighbour *previous = neighs; + while(previous->next != neigh) + previous = previous->next; + previous->next = neigh->next; + } + free(neigh); +} + +struct neighbour * +find_neighbour(const unsigned char *address, struct interface *ifp) +{ + struct neighbour *neigh; + const struct timeval zero = {0, 0}; + + neigh = find_neighbour_nocreate(address, ifp); + if(neigh) + return neigh; + + debugf(BABEL_DEBUG_COMMON,"Creating neighbour %s on %s.", + format_address(address), ifp->name); + + neigh = malloc(sizeof(struct neighbour)); + if(neigh == NULL) { + zlog_err("malloc(neighbour): %s", safe_strerror(errno)); + return NULL; + } + + neigh->hello_seqno = -1; + memcpy(neigh->address, address, 16); + neigh->reach = 0; + neigh->txcost = INFINITY; + neigh->ihu_time = babel_now; + neigh->hello_time = zero; + neigh->hello_interval = 0; + neigh->ihu_interval = 0; + neigh->ifp = ifp; + neigh->next = neighs; + neighs = neigh; + send_hello(ifp); + return neigh; +} + +/* Recompute a neighbour's rxcost. Return true if anything changed. */ +int +update_neighbour(struct neighbour *neigh, int hello, int hello_interval) +{ + int missed_hellos; + int rc = 0; + + if(hello < 0) { + if(neigh->hello_interval <= 0) + return rc; + missed_hellos = + ((int)timeval_minus_msec(&babel_now, &neigh->hello_time) - + neigh->hello_interval * 7) / + (neigh->hello_interval * 10); + if(missed_hellos <= 0) + return rc; + timeval_add_msec(&neigh->hello_time, &neigh->hello_time, + missed_hellos * neigh->hello_interval * 10); + } else { + if(neigh->hello_seqno >= 0 && neigh->reach > 0) { + missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1; + if(missed_hellos < -8) { + /* Probably a neighbour that rebooted and lost its seqno. + Reboot the universe. */ + neigh->reach = 0; + missed_hellos = 0; + rc = 1; + } else if(missed_hellos < 0) { + if(hello_interval > neigh->hello_interval) { + /* This neighbour has increased its hello interval, + and we didn't notice. */ + neigh->reach <<= -missed_hellos; + missed_hellos = 0; + } else { + /* Late hello. Probably due to the link layer buffering + packets during a link outage. Ignore it, but reset + the expected seqno. */ + neigh->hello_seqno = hello; + hello = -1; + missed_hellos = 0; + } + rc = 1; + } + } else { + missed_hellos = 0; + } + neigh->hello_time = babel_now; + neigh->hello_interval = hello_interval; + } + + if(missed_hellos > 0) { + neigh->reach >>= missed_hellos; + neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos); + missed_hellos = 0; + rc = 1; + } + + if(hello >= 0) { + neigh->hello_seqno = hello; + neigh->reach >>= 1; + neigh->reach |= 0x8000; + if((neigh->reach & 0xFC00) != 0xFC00) + rc = 1; + } + + /* Make sure to give neighbours some feedback early after association */ + if((neigh->reach & 0xBF00) == 0x8000) { + /* A new neighbour */ + send_hello(neigh->ifp); + } else { + /* Don't send hellos, in order to avoid a positive feedback loop. */ + int a = (neigh->reach & 0xC000); + int b = (neigh->reach & 0x3000); + if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) { + /* Reachability is either 1100 or 0011 */ + send_self_update(neigh->ifp); + } + } + + if((neigh->reach & 0xFC00) == 0xC000) { + /* This is a newish neighbour, let's request a full route dump. + We ought to avoid this when the network is dense */ + send_unicast_request(neigh, NULL, 0); + send_ihu(neigh, NULL); + } + return rc; +} + +static int +reset_txcost(struct neighbour *neigh) +{ + unsigned delay; + + delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); + + if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10 * 3) + return 0; + + /* If we're losing a lot of packets, we probably lost an IHU too */ + if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || + (neigh->ihu_interval > 0 && + delay >= neigh->ihu_interval * 10 * 10)) { + neigh->txcost = INFINITY; + neigh->ihu_time = babel_now; + return 1; + } + + return 0; +} + +unsigned +neighbour_txcost(struct neighbour *neigh) +{ + return neigh->txcost; +} + +unsigned +check_neighbours() +{ + struct neighbour *neigh; + int changed, rc; + unsigned msecs = 50000; + + debugf(BABEL_DEBUG_COMMON,"Checking neighbours."); + + neigh = neighs; + while(neigh) { + changed = update_neighbour(neigh, -1, 0); + + if(neigh->reach == 0 || + neigh->hello_time.tv_sec > babel_now.tv_sec || /* clock stepped */ + timeval_minus_msec(&babel_now, &neigh->hello_time) > 300000) { + struct neighbour *old = neigh; + neigh = neigh->next; + flush_neighbour(old); + continue; + } + + rc = reset_txcost(neigh); + changed = changed || rc; + + update_neighbour_metric(neigh, changed); + + if(neigh->hello_interval > 0) + msecs = MIN(msecs, neigh->hello_interval * 10); + if(neigh->ihu_interval > 0) + msecs = MIN(msecs, neigh->ihu_interval * 10); + neigh = neigh->next; + } + + return msecs; +} + +unsigned +neighbour_rxcost(struct neighbour *neigh) +{ + unsigned delay; + unsigned short reach = neigh->reach; + + delay = timeval_minus_msec(&babel_now, &neigh->hello_time); + + if((reach & 0xFFF0) == 0 || delay >= 180000) { + return INFINITY; + } else if(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) { + int sreach = + ((reach & 0x8000) >> 2) + + ((reach & 0x4000) >> 1) + + (reach & 0x3FFF); + /* 0 <= sreach <= 0x7FFF */ + int cost = (0x8000 * babel_get_if_nfo(neigh->ifp)->cost) / (sreach + 1); + /* cost >= interface->cost */ + if(delay >= 40000) + cost = (cost * (delay - 20000) + 10000) / 20000; + return MIN(cost, INFINITY); + } else { + /* To lose one hello is a misfortune, to lose two is carelessness. */ + if((reach & 0xC000) == 0xC000) + return babel_get_if_nfo(neigh->ifp)->cost; + else if((reach & 0xC000) == 0) + return INFINITY; + else if((reach & 0x2000)) + return babel_get_if_nfo(neigh->ifp)->cost; + else + return INFINITY; + } +} + +unsigned +neighbour_cost(struct neighbour *neigh) +{ + unsigned a, b; + + if(!if_up(neigh->ifp)) + return INFINITY; + + a = neighbour_txcost(neigh); + + if(a >= INFINITY) + return INFINITY; + + b = neighbour_rxcost(neigh); + if(b >= INFINITY) + return INFINITY; + + if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) + || (a <= 256 && b <= 256)) { + return a; + } else { + /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected + probabilities of a packet getting through in the direct and reverse + directions. */ + a = MAX(a, 256); + b = MAX(b, 256); + /* 1/(alpha * beta), which is just plain ETX. */ + /* Since a and b are capped to 16 bits, overflow is impossible. */ + return (a * b + 128) >> 8; + } +} diff --git a/babeld/neighbour.h b/babeld/neighbour.h new file mode 100644 index 00000000..cf8c0f0b --- /dev/null +++ b/babeld/neighbour.h @@ -0,0 +1,66 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +struct neighbour { + struct neighbour *next; + /* This is -1 when unknown, so don't make it unsigned */ + int hello_seqno; + unsigned char address[16]; + unsigned short reach; + unsigned short txcost; + struct timeval hello_time; + struct timeval ihu_time; + unsigned short hello_interval; /* in centiseconds */ + unsigned short ihu_interval; /* in centiseconds */ + struct interface *ifp; +}; + +extern struct neighbour *neighs; + +#define FOR_ALL_NEIGHBOURS(_neigh) \ + for(_neigh = neighs; _neigh; _neigh = _neigh->next) + +int neighbour_valid(struct neighbour *neigh); +void flush_neighbour(struct neighbour *neigh); +struct neighbour *find_neighbour(const unsigned char *address, + struct interface *ifp); +int update_neighbour(struct neighbour *neigh, int hello, int hello_interval); +unsigned check_neighbours(void); +unsigned neighbour_txcost(struct neighbour *neigh); +unsigned neighbour_rxcost(struct neighbour *neigh); +unsigned neighbour_cost(struct neighbour *neigh); diff --git a/babeld/net.c b/babeld/net.c new file mode 100644 index 00000000..5cb1236e --- /dev/null +++ b/babeld/net.c @@ -0,0 +1,229 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "babeld.h" +#include "util.h" +#include "net.h" + +int +babel_socket(int port) +{ + struct sockaddr_in6 sin6; + int s, rc; + int saved_errno; + int one = 1, zero = 0; + + s = socket(PF_INET6, SOCK_DGRAM, 0); + if(s < 0) + return -1; + + rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + if(rc < 0) + goto fail; + + rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if(rc < 0) + goto fail; + + rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &zero, sizeof(zero)); + if(rc < 0) + goto fail; + + rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, + &one, sizeof(one)); + if(rc < 0) + goto fail; + + rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &one, sizeof(one)); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_GETFL, 0); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_GETFD, 0); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); + if(rc < 0) + goto fail; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); + rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + goto fail; + + return s; + + fail: + saved_errno = errno; + close(s); + errno = saved_errno; + return -1; +} + +int +babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) +{ + struct iovec iovec; + struct msghdr msg; + int rc; + + memset(&msg, 0, sizeof(msg)); + iovec.iov_base = buf; + iovec.iov_len = buflen; + msg.msg_name = sin; + msg.msg_namelen = slen; + msg.msg_iov = &iovec; + msg.msg_iovlen = 1; + + rc = recvmsg(s, &msg, 0); + return rc; +} + +int +babel_send(int s, + const void *buf1, int buflen1, const void *buf2, int buflen2, + const struct sockaddr *sin, int slen) +{ + struct iovec iovec[2]; + struct msghdr msg; + int rc; + + iovec[0].iov_base = (void*)buf1; + iovec[0].iov_len = buflen1; + iovec[1].iov_base = (void*)buf2; + iovec[1].iov_len = buflen2; + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (struct sockaddr*)sin; + msg.msg_namelen = slen; + msg.msg_iov = iovec; + msg.msg_iovlen = 2; + + again: + rc = sendmsg(s, &msg, 0); + if(rc < 0) { + if(errno == EINTR) + goto again; + else if(errno == EAGAIN) { + int rc2; + rc2 = wait_for_fd(1, s, 5); + if(rc2 > 0) + goto again; + errno = EAGAIN; + } + } + return rc; +} + +int +tcp_server_socket(int port, int local) +{ + struct sockaddr_in6 sin6; + int s, rc, saved_errno; + int one = 1; + + s = socket(PF_INET6, SOCK_STREAM, 0); + if(s < 0) + return -1; + + rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_GETFL, 0); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK)); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_GETFD, 0); + if(rc < 0) + goto fail; + + rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC); + if(rc < 0) + goto fail; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = htons(port); + if(local) { + rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr); + if(rc < 0) + goto fail; + } + rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6)); + if(rc < 0) + goto fail; + + rc = listen(s, 2); + if(rc < 0) + goto fail; + + return s; + + fail: + saved_errno = errno; + close(s); + errno = saved_errno; + return -1; +} diff --git a/babeld/net.h b/babeld/net.h new file mode 100644 index 00000000..e6729001 --- /dev/null +++ b/babeld/net.h @@ -0,0 +1,44 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +int babel_socket(int port); +int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen); +int babel_send(int s, + const void *buf1, int buflen1, const void *buf2, int buflen2, + const struct sockaddr *sin, int slen); +int tcp_server_socket(int port, int local); diff --git a/babeld/resend.c b/babeld/resend.c new file mode 100644 index 00000000..5a786fcd --- /dev/null +++ b/babeld/resend.c @@ -0,0 +1,330 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include +#include "if.h" + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" +#include "neighbour.h" +#include "resend.h" +#include "message.h" +#include "babel_interface.h" + +struct timeval resend_time = {0, 0}; +struct resend *to_resend = NULL; + +static int +resend_match(struct resend *resend, + int kind, const unsigned char *prefix, unsigned char plen) +{ + return (resend->kind == kind && + resend->plen == plen && memcmp(resend->prefix, prefix, 16) == 0); +} + +/* This is called by neigh.c when a neighbour is flushed */ + +void +flush_resends(struct neighbour *neigh) +{ + /* Nothing for now */ +} + +static struct resend * +find_resend(int kind, const unsigned char *prefix, unsigned char plen, + struct resend **previous_return) +{ + struct resend *current, *previous; + + previous = NULL; + current = to_resend; + while(current) { + if(resend_match(current, kind, prefix, plen)) { + if(previous_return) + *previous_return = previous; + return current; + } + previous = current; + current = current->next; + } + + return NULL; +} + +struct resend * +find_request(const unsigned char *prefix, unsigned char plen, + struct resend **previous_return) +{ + return find_resend(RESEND_REQUEST, prefix, plen, previous_return); +} + +int +record_resend(int kind, const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + struct interface *ifp, int delay) +{ + struct resend *resend; + unsigned int ifindex = ifp ? ifp->ifindex : 0; + + if((kind == RESEND_REQUEST && + input_filter(NULL, prefix, plen, NULL, ifindex) >= INFINITY) || + (kind == RESEND_UPDATE && + output_filter(NULL, prefix, plen, ifindex) >= INFINITY)) + return 0; + + if(delay >= 0xFFFF) + delay = 0xFFFF; + + resend = find_resend(kind, prefix, plen, NULL); + if(resend) { + if(resend->delay && delay) + resend->delay = MIN(resend->delay, delay); + else if(delay) + resend->delay = delay; + resend->time = babel_now; + resend->max = kind == RESEND_REQUEST ? 128 : UPDATE_MAX; + if(id && memcmp(resend->id, id, 8) == 0 && + seqno_compare(resend->seqno, seqno) > 0) { + return 0; + } + if(id) + memcpy(resend->id, id, 8); + else + memset(resend->id, 0, 8); + resend->seqno = seqno; + if(resend->ifp != ifp) + resend->ifp = NULL; + } else { + resend = malloc(sizeof(struct resend)); + if(resend == NULL) + return -1; + resend->kind = kind; + resend->max = kind == RESEND_REQUEST ? 128 : UPDATE_MAX; + resend->delay = delay; + memcpy(resend->prefix, prefix, 16); + resend->plen = plen; + resend->seqno = seqno; + if(id) + memcpy(resend->id, id, 8); + else + memset(resend->id, 0, 8); + resend->ifp = ifp; + resend->time = babel_now; + resend->next = to_resend; + to_resend = resend; + } + + if(resend->delay) { + struct timeval timeout; + timeval_add_msec(&timeout, &resend->time, resend->delay); + timeval_min(&resend_time, &timeout); + } + return 1; +} + +static int +resend_expired(struct resend *resend) +{ + switch(resend->kind) { + case RESEND_REQUEST: + return timeval_minus_msec(&babel_now, &resend->time) >= REQUEST_TIMEOUT; + default: + return resend->max <= 0; + } +} + +int +unsatisfied_request(const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id) +{ + struct resend *request; + + request = find_request(prefix, plen, NULL); + if(request == NULL || resend_expired(request)) + return 0; + + if(memcmp(request->id, id, 8) != 0 || + seqno_compare(request->seqno, seqno) <= 0) + return 1; + + return 0; +} + +/* Determine whether a given request should be forwarded. */ +int +request_redundant(struct interface *ifp, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id) +{ + struct resend *request; + + request = find_request(prefix, plen, NULL); + if(request == NULL || resend_expired(request)) + return 0; + + if(memcmp(request->id, id, 8) == 0 && + seqno_compare(request->seqno, seqno) > 0) + return 0; + + if(request->ifp != NULL && request->ifp != ifp) + return 0; + + if(request->max > 0) + /* Will be resent. */ + return 1; + + if(timeval_minus_msec(&babel_now, &request->time) < + (ifp ? MIN(babel_get_if_nfo(ifp)->hello_interval, 1000) : 1000)) + /* Fairly recent. */ + return 1; + + return 0; +} + +int +satisfy_request(const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + struct interface *ifp) +{ + struct resend *request, *previous; + + request = find_request(prefix, plen, &previous); + if(request == NULL) + return 0; + + if(ifp != NULL && request->ifp != ifp) + return 0; + + if(memcmp(request->id, id, 8) != 0 || + seqno_compare(request->seqno, seqno) <= 0) { + /* We cannot remove the request, as we may be walking the list right + now. Mark it as expired, so that expire_resend will remove it. */ + request->max = 0; + request->time.tv_sec = 0; + recompute_resend_time(); + return 1; + } + + return 0; +} + +void +expire_resend() +{ + struct resend *current, *previous; + int recompute = 0; + + previous = NULL; + current = to_resend; + while(current) { + if(resend_expired(current)) { + if(previous == NULL) { + to_resend = current->next; + free(current); + current = to_resend; + } else { + previous->next = current->next; + free(current); + current = previous->next; + } + recompute = 1; + } else { + previous = current; + current = current->next; + } + } + if(recompute) + recompute_resend_time(); +} + +void +recompute_resend_time() +{ + struct resend *request; + struct timeval resend = {0, 0}; + + request = to_resend; + while(request) { + if(!resend_expired(request) && request->delay > 0 && request->max > 0) { + struct timeval timeout; + timeval_add_msec(&timeout, &request->time, request->delay); + timeval_min(&resend, &timeout); + } + request = request->next; + } + + resend_time = resend; +} + +void +do_resend() +{ + struct resend *resend; + + resend = to_resend; + while(resend) { + if(!resend_expired(resend) && resend->delay > 0 && resend->max > 0) { + struct timeval timeout; + timeval_add_msec(&timeout, &resend->time, resend->delay); + if(timeval_compare(&babel_now, &timeout) >= 0) { + switch(resend->kind) { + case RESEND_REQUEST: + send_multihop_request(resend->ifp, + resend->prefix, resend->plen, + resend->seqno, resend->id, 127); + break; + case RESEND_UPDATE: + send_update(resend->ifp, 1, + resend->prefix, resend->plen); + break; + default: abort(); + } + resend->delay = MIN(0xFFFF, resend->delay * 2); + resend->max--; + } + } + resend = resend->next; + } + recompute_resend_time(); +} diff --git a/babeld/resend.h b/babeld/resend.h new file mode 100644 index 00000000..fdb57300 --- /dev/null +++ b/babeld/resend.h @@ -0,0 +1,77 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#define REQUEST_TIMEOUT 65000 +#define UPDATE_MAX 4 + +#define RESEND_REQUEST 1 +#define RESEND_UPDATE 2 + +struct resend { + unsigned char kind; + unsigned char max; + unsigned short delay; + struct timeval time; + unsigned char prefix[16]; + unsigned char plen; + unsigned short seqno; + unsigned char id[8]; + struct interface *ifp; + struct resend *next; +}; + +extern struct timeval resend_time; + +struct resend *find_request(const unsigned char *prefix, unsigned char plen, + struct resend **previous_return); +void flush_resends(struct neighbour *neigh); +int record_resend(int kind, const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + struct interface *ifp, int delay); +int unsatisfied_request(const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id); +int request_redundant(struct interface *ifp, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id); +int satisfy_request(const unsigned char *prefix, unsigned char plen, + unsigned short seqno, const unsigned char *id, + struct interface *ifp); + +void expire_resend(void); +void recompute_resend_time(void); +void do_resend(void); diff --git a/babeld/route.c b/babeld/route.c new file mode 100644 index 00000000..e0c9d047 --- /dev/null +++ b/babeld/route.c @@ -0,0 +1,756 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include "if.h" + +#include "babeld.h" +#include "util.h" +#include "kernel.h" +#include "babel_interface.h" +#include "source.h" +#include "neighbour.h" +#include "route.h" +#include "xroute.h" +#include "message.h" +#include "resend.h" + +static void consider_route(struct route *route); + +struct route *routes = NULL; +int numroutes = 0, maxroutes = 0; +int kernel_metric = 0; +int allow_duplicates = -1; + +struct route * +find_route(const unsigned char *prefix, unsigned char plen, + struct neighbour *neigh, const unsigned char *nexthop) +{ + int i; + for(i = 0; i < numroutes; i++) { + if(routes[i].neigh == neigh && + memcmp(routes[i].nexthop, nexthop, 16) == 0 && + source_match(routes[i].src, prefix, plen)) + return &routes[i]; + } + return NULL; +} + +struct route * +find_installed_route(const unsigned char *prefix, unsigned char plen) +{ + int i; + for(i = 0; i < numroutes; i++) { + if(routes[i].installed && source_match(routes[i].src, prefix, plen)) + return &routes[i]; + } + return NULL; +} + +void +flush_route(struct route *route) +{ + int i; + struct source *src; + unsigned oldmetric; + int lost = 0; + + i = route - routes; + assert(i >= 0 && i < numroutes); + + oldmetric = route_metric(route); + + if(route->installed) { + uninstall_route(route); + lost = 1; + } + + src = route->src; + + if(i != numroutes - 1) + memcpy(routes + i, routes + numroutes - 1, sizeof(struct route)); + numroutes--; + VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route)); + + if(numroutes == 0) { + free(routes); + routes = NULL; + maxroutes = 0; + } else if(maxroutes > 8 && numroutes < maxroutes / 4) { + struct route *new_routes; + int n = maxroutes / 2; + new_routes = realloc(routes, n * sizeof(struct route)); + if(new_routes != NULL) { + routes = new_routes; + maxroutes = n; + } + } + + if(lost) + route_lost(src, oldmetric); +} + +void +flush_neighbour_routes(struct neighbour *neigh) +{ + int i; + + i = 0; + while(i < numroutes) { + if(routes[i].neigh == neigh) { + flush_route(&routes[i]); + continue; + } + i++; + } +} + +void +flush_interface_routes(struct interface *ifp, int v4only) +{ + int i; + + i = 0; + while(i < numroutes) { + if(routes[i].neigh->ifp == ifp && + (!v4only || v4mapped(routes[i].nexthop))) { + flush_route(&routes[i]); + continue; + } + i++; + } +} + +static int +metric_to_kernel(int metric) +{ + return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; +} + +void +install_route(struct route *route) +{ + int rc; + + if(route->installed) + return; + + if(!route_feasible(route)) + fprintf(stderr, "WARNING: installing unfeasible route " + "(this shouldn't happen)."); + + rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, + route->nexthop, + route->neigh->ifp->ifindex, + metric_to_kernel(route_metric(route)), NULL, 0, 0); + if(rc < 0) { + int save = errno; + zlog_err("kernel_route(ADD): %s", safe_strerror(errno)); + if(save != EEXIST) + return; + } + route->installed = 1; +} + +void +uninstall_route(struct route *route) +{ + int rc; + + if(!route->installed) + return; + + rc = kernel_route(ROUTE_FLUSH, route->src->prefix, route->src->plen, + route->nexthop, + route->neigh->ifp->ifindex, + metric_to_kernel(route_metric(route)), NULL, 0, 0); + if(rc < 0) + zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno)); + + route->installed = 0; +} + +/* This is equivalent to uninstall_route followed with install_route, + but without the race condition. The destination of both routes + must be the same. */ + +static void +switch_routes(struct route *old, struct route *new) +{ + int rc; + + if(!old) { + install_route(new); + return; + } + + if(!old->installed) + return; + + if(!route_feasible(new)) + fprintf(stderr, "WARNING: switching to unfeasible route " + "(this shouldn't happen)."); + + rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, + old->nexthop, old->neigh->ifp->ifindex, + metric_to_kernel(route_metric(old)), + new->nexthop, new->neigh->ifp->ifindex, + metric_to_kernel(route_metric(new))); + if(rc < 0) { + zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno)); + return; + } + + old->installed = 0; + new->installed = 1; +} + +static void +change_route_metric(struct route *route, unsigned newmetric) +{ + int old, new; + + if(route_metric(route) == newmetric) + return; + + old = metric_to_kernel(route_metric(route)); + new = metric_to_kernel(newmetric); + + if(route->installed && old != new) { + int rc; + rc = kernel_route(ROUTE_MODIFY, route->src->prefix, route->src->plen, + route->nexthop, route->neigh->ifp->ifindex, + old, + route->nexthop, route->neigh->ifp->ifindex, + new); + if(rc < 0) { + zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno)); + return; + } + } + + route->metric = newmetric; +} + +static void +retract_route(struct route *route) +{ + route->refmetric = INFINITY; + change_route_metric(route, INFINITY); +} + +int +route_feasible(struct route *route) +{ + return update_feasible(route->src, route->seqno, route->refmetric); +} + +int +route_old(struct route *route) +{ + return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; +} + +int +route_expired(struct route *route) +{ + return route->time < babel_now.tv_sec - route->hold_time; +} + +int +update_feasible(struct source *src, + unsigned short seqno, unsigned short refmetric) +{ + if(src == NULL) + return 1; + + if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) + /* Never mind what is probably stale data */ + return 1; + + if(refmetric >= INFINITY) + /* Retractions are always feasible */ + return 1; + + return (seqno_compare(seqno, src->seqno) > 0 || + (src->seqno == seqno && refmetric < src->metric)); +} + +/* This returns the feasible route with the smallest metric. */ +struct route * +find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, + struct neighbour *exclude) +{ + struct route *route = NULL; + int i; + + for(i = 0; i < numroutes; i++) { + if(!source_match(routes[i].src, prefix, plen)) + continue; + if(route_expired(&routes[i])) + continue; + if(feasible && !route_feasible(&routes[i])) + continue; + if(exclude && routes[i].neigh == exclude) + continue; + if(route && route_metric(route) <= route_metric(&routes[i])) + continue; + route = &routes[i]; + } + return route; +} + +void +update_route_metric(struct route *route) +{ + int oldmetric = route_metric(route); + + if(route_expired(route)) { + if(route->refmetric < INFINITY) { + route->seqno = seqno_plus(route->src->seqno, 1); + retract_route(route); + if(oldmetric < INFINITY) + route_changed(route, route->src, oldmetric); + } + } else { + struct neighbour *neigh = route->neigh; + int add_metric = input_filter(route->src->id, + route->src->prefix, route->src->plen, + neigh->address, + neigh->ifp->ifindex); + int newmetric = MIN(route->refmetric + + add_metric + + neighbour_cost(route->neigh), + INFINITY); + + if(newmetric != oldmetric) { + change_route_metric(route, newmetric); + route_changed(route, route->src, oldmetric); + } + } +} + +/* Called whenever a neighbour's cost changes, to update the metric of + all routes through that neighbour. */ +void +update_neighbour_metric(struct neighbour *neigh, int changed) +{ + if(changed) { + int i; + + i = 0; + while(i < numroutes) { + if(routes[i].neigh == neigh) + update_route_metric(&routes[i]); + i++; + } + } +} + +void +update_interface_metric(struct interface *ifp) +{ + int i; + + i = 0; + while(i < numroutes) { + if(routes[i].neigh->ifp == ifp) + update_route_metric(&routes[i]); + i++; + } +} + +/* This is called whenever we receive an update. */ +struct route * +update_route(const unsigned char *router_id, + const unsigned char *prefix, unsigned char plen, + unsigned short seqno, unsigned short refmetric, + unsigned short interval, + struct neighbour *neigh, const unsigned char *nexthop) +{ + struct route *route; + struct source *src; + int metric, feasible; + int add_metric; + int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); + + if(memcmp(router_id, myid, 8) == 0) + return NULL; /* I have announced the route */ + + if(martian_prefix(prefix, plen)) { + fprintf(stderr, "Rejecting martian route to %s through %s.\n", + format_prefix(prefix, plen), format_address(router_id)); + return NULL; + } + + add_metric = input_filter(router_id, prefix, plen, + neigh->address, neigh->ifp->ifindex); + if(add_metric >= INFINITY) + return NULL; + + src = find_source(router_id, prefix, plen, 1, seqno); + if(src == NULL) + return NULL; + + feasible = update_feasible(src, seqno, refmetric); + route = find_route(prefix, plen, neigh, nexthop); + metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); + + if(route) { + struct source *oldsrc; + unsigned short oldmetric; + int lost = 0; + + oldsrc = route->src; + oldmetric = route_metric(route); + + /* If a successor switches sources, we must accept his update even + if it makes a route unfeasible in order to break any routing loops + in a timely manner. If the source remains the same, we ignore + the update. */ + if(!feasible && route->installed) { + debugf(BABEL_DEBUG_COMMON,"Unfeasible update for installed route to %s " + "(%s %d %d -> %s %d %d).", + format_prefix(src->prefix, src->plen), + format_address(route->src->id), + route->seqno, route->refmetric, + format_address(src->id), seqno, refmetric); + if(src != route->src) { + uninstall_route(route); + lost = 1; + } + } + + route->src = src; + if(feasible && refmetric < INFINITY) + route->time = babel_now.tv_sec; + route->seqno = seqno; + route->refmetric = refmetric; + change_route_metric(route, metric); + route->hold_time = hold_time; + + route_changed(route, oldsrc, oldmetric); + if(lost) + route_lost(oldsrc, oldmetric); + + if(!feasible) + send_unfeasible_request(neigh, route->installed && route_old(route), + seqno, metric, src); + } else { + if(refmetric >= INFINITY) + /* Somebody's retracting a route we never saw. */ + return NULL; + if(!feasible) { + send_unfeasible_request(neigh, 0, seqno, metric, src); + return NULL; + } + if(numroutes >= maxroutes) { + struct route *new_routes; + int n = maxroutes < 1 ? 8 : 2 * maxroutes; + new_routes = routes == NULL ? + malloc(n * sizeof(struct route)) : + realloc(routes, n * sizeof(struct route)); + if(new_routes == NULL) + return NULL; + maxroutes = n; + routes = new_routes; + } + route = &routes[numroutes]; + route->src = src; + route->refmetric = refmetric; + route->seqno = seqno; + route->metric = metric; + route->neigh = neigh; + memcpy(route->nexthop, nexthop, 16); + route->time = babel_now.tv_sec; + route->hold_time = hold_time; + route->installed = 0; + numroutes++; + consider_route(route); + } + return route; +} + +/* We just received an unfeasible update. If it's any good, send + a request for a new seqno. */ +void +send_unfeasible_request(struct neighbour *neigh, int force, + unsigned short seqno, unsigned short metric, + struct source *src) +{ + struct route *route = find_installed_route(src->prefix, src->plen); + + if(seqno_minus(src->seqno, seqno) > 100) { + /* Probably a source that lost its seqno. Let it time-out. */ + return; + } + + if(force || !route || route_metric(route) >= metric + 512) { + send_unicast_multihop_request(neigh, src->prefix, src->plen, + src->metric >= INFINITY ? + src->seqno : + seqno_plus(src->seqno, 1), + src->id, 127); + } +} + +/* This takes a feasible route and decides whether to install it. */ +static void +consider_route(struct route *route) +{ + struct route *installed; + struct xroute *xroute; + + if(route->installed) + return; + + if(!route_feasible(route)) + return; + + xroute = find_xroute(route->src->prefix, route->src->plen); + if(xroute && (allow_duplicates < 0 || xroute->metric >= allow_duplicates)) + return; + + installed = find_installed_route(route->src->prefix, route->src->plen); + + if(installed == NULL) + goto install; + + if(route_metric(route) >= INFINITY) + return; + + if(route_metric(installed) >= INFINITY) + goto install; + + if(route_metric(installed) >= route_metric(route) + 192) + goto install; + + /* Avoid switching sources */ + if(installed->src != route->src) + return; + + if(route_metric(installed) >= route_metric(route) + 64) + goto install; + + return; + + install: + switch_routes(installed, route); + if(installed && route->installed) + send_triggered_update(route, installed->src, route_metric(installed)); + else + send_update(NULL, 1, route->src->prefix, route->src->plen); + return; +} + +void +retract_neighbour_routes(struct neighbour *neigh) +{ + int i; + + i = 0; + while(i < numroutes) { + if(routes[i].neigh == neigh) { + if(routes[i].refmetric != INFINITY) { + unsigned short oldmetric = route_metric(&routes[i]); + retract_route(&routes[i]); + if(oldmetric != INFINITY) + route_changed(&routes[i], routes[i].src, oldmetric); + } + } + i++; + } +} + +void +send_triggered_update(struct route *route, struct source *oldsrc, + unsigned oldmetric) +{ + unsigned newmetric, diff; + /* 1 means send speedily, 2 means resend */ + int urgent; + + if(!route->installed) + return; + + newmetric = route_metric(route); + diff = + newmetric >= oldmetric ? newmetric - oldmetric : oldmetric - newmetric; + + if(route->src != oldsrc || (oldmetric < INFINITY && newmetric >= INFINITY)) + /* Switching sources can cause transient routing loops. + Retractions can cause blackholes. */ + urgent = 2; + else if(newmetric > oldmetric && oldmetric < 6 * 256 && diff >= 512) + /* Route getting significantly worse */ + urgent = 1; + else if(unsatisfied_request(route->src->prefix, route->src->plen, + route->seqno, route->src->id)) + /* Make sure that requests are satisfied speedily */ + urgent = 1; + else if(oldmetric >= INFINITY && newmetric < INFINITY) + /* New route */ + urgent = 0; + else if(newmetric < oldmetric && diff < 1024) + /* Route getting better. This may be a transient fluctuation, so + don't advertise it to avoid making routes unfeasible later on. */ + return; + else if(diff < 384) + /* Don't fret about trivialities */ + return; + else + urgent = 0; + + if(urgent >= 2) + send_update_resend(NULL, route->src->prefix, route->src->plen); + else + send_update(NULL, urgent, route->src->prefix, route->src->plen); + + if(oldmetric < INFINITY) { + if(newmetric >= oldmetric + 512) { + send_request_resend(NULL, route->src->prefix, route->src->plen, + route->src->metric >= INFINITY ? + route->src->seqno : + seqno_plus(route->src->seqno, 1), + route->src->id); + } else if(newmetric >= oldmetric + 288) { + send_request(NULL, route->src->prefix, route->src->plen); + } + } +} + +/* A route has just changed. Decide whether to switch to a different route or + send an update. */ +void +route_changed(struct route *route, + struct source *oldsrc, unsigned short oldmetric) +{ + if(route->installed) { + if(route_metric(route) > oldmetric) { + struct route *better_route; + better_route = + find_best_route(route->src->prefix, route->src->plen, 1, NULL); + if(better_route && + route_metric(better_route) <= route_metric(route) - 96) + consider_route(better_route); + } + + if(route->installed) + /* We didn't change routes after all. */ + send_triggered_update(route, oldsrc, oldmetric); + } else { + /* Reconsider routes even when their metric didn't decrease, + they may not have been feasible before. */ + consider_route(route); + } +} + +/* We just lost the installed route to a given destination. */ +void +route_lost(struct source *src, unsigned oldmetric) +{ + struct route *new_route; + new_route = find_best_route(src->prefix, src->plen, 1, NULL); + if(new_route) { + consider_route(new_route); + } else if(oldmetric < INFINITY) { + /* Complain loudly. */ + send_update_resend(NULL, src->prefix, src->plen); + send_request_resend(NULL, src->prefix, src->plen, + src->metric >= INFINITY ? + src->seqno : seqno_plus(src->seqno, 1), + src->id); + } +} + +void +expire_routes(void) +{ + int i; + + debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); + + i = 0; + while(i < numroutes) { + struct route *route = &routes[i]; + + if(route->time > babel_now.tv_sec || /* clock stepped */ + route_old(route)) { + flush_route(route); + continue; + } + + update_route_metric(route); + + if(route->installed && route->refmetric < INFINITY) { + if(route_old(route)) + send_unicast_request(route->neigh, + route->src->prefix, route->src->plen); + } + i++; + } +} + +void +babel_uninstall_all_routes(void) +{ + while(numroutes > 0) { + uninstall_route(&routes[0]); + /* We need to flush the route so network_up won't reinstall it */ + flush_route(&routes[0]); + } +} + +struct route * +babel_route_get_by_source(struct source *src) +{ + int i; + for(i = 0; i < numroutes; i++) { + if(routes[i].src == src) + return &routes[i]; + } + return NULL; +} diff --git a/babeld/route.h b/babeld/route.h new file mode 100644 index 00000000..e36f6c34 --- /dev/null +++ b/babeld/route.h @@ -0,0 +1,104 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "babel_interface.h" +#include "source.h" + +struct route { + struct source *src; + unsigned short metric; + unsigned short refmetric; + unsigned short seqno; + struct neighbour *neigh; + unsigned char nexthop[16]; + time_t time; + unsigned short hold_time; /* in seconds */ + short installed; +}; + +static inline int +route_metric(const struct route *route) +{ + return route->metric; +} + +extern struct route *routes; +extern int numroutes, maxroutes; +extern int kernel_metric, allow_duplicates; + +struct route *find_route(const unsigned char *prefix, unsigned char plen, + struct neighbour *neigh, const unsigned char *nexthop); +struct route *find_installed_route(const unsigned char *prefix, + unsigned char plen); +void flush_route(struct route *route); +void flush_neighbour_routes(struct neighbour *neigh); +void flush_interface_routes(struct interface *ifp, int v4only); +void install_route(struct route *route); +void uninstall_route(struct route *route); +void switch_route(struct route *old, struct route *new); +int route_feasible(struct route *route); +int route_old(struct route *route); +int route_expired(struct route *route); +int update_feasible(struct source *src, + unsigned short seqno, unsigned short refmetric); +struct route *find_best_route(const unsigned char *prefix, unsigned char plen, + int feasible, struct neighbour *exclude); +struct route *install_best_route(const unsigned char prefix[16], + unsigned char plen); +void update_neighbour_metric(struct neighbour *neigh, int change); +void update_interface_metric(struct interface *ifp); +void update_route_metric(struct route *route); +struct route *update_route(const unsigned char *a, + const unsigned char *p, unsigned char plen, + unsigned short seqno, unsigned short refmetric, + unsigned short interval, struct neighbour *neigh, + const unsigned char *nexthop); +void retract_neighbour_routes(struct neighbour *neigh); +void send_unfeasible_request(struct neighbour *neigh, int force, + unsigned short seqno, unsigned short metric, + struct source *src); +void send_triggered_update(struct route *route, + struct source *oldsrc, unsigned oldmetric); +void route_changed(struct route *route, + struct source *oldsrc, unsigned short oldmetric); +void route_lost(struct source *src, unsigned oldmetric); +void expire_routes(void); + +void babel_uninstall_all_routes(void); +struct route *babel_route_get_by_source(struct source *src); diff --git a/babeld/source.c b/babeld/source.c new file mode 100644 index 00000000..cc4ed445 --- /dev/null +++ b/babeld/source.c @@ -0,0 +1,159 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" +#include "source.h" +#include "babel_interface.h" +#include "route.h" + +struct source *srcs = NULL; + +struct source* +find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, + int create, unsigned short seqno) +{ + struct source *src; + + for(src = srcs; src; src = src->next) { + /* This should really be a hash table. For now, check the + last byte first. */ + if(src->id[7] != id[7]) + continue; + if(memcmp(src->id, id, 8) != 0) + continue; + if(source_match(src, p, plen)) + return src; + } + + if(!create) + return NULL; + + src = malloc(sizeof(struct source)); + if(src == NULL) { + zlog_err("malloc(source): %s", safe_strerror(errno)); + return NULL; + } + + memcpy(src->id, id, 8); + memcpy(src->prefix, p, 16); + src->plen = plen; + src->seqno = seqno; + src->metric = INFINITY; + src->time = babel_now.tv_sec; + src->next = srcs; + srcs = src; + return src; +} + +int +flush_source(struct source *src) +{ + /* This is absolutely horrible -- it makes expire_sources quadratic. + But it's not called very often. */ + + if (babel_route_get_by_source(src) != NULL) + return 0; + + if(srcs == src) { + srcs = src->next; + } else { + struct source *previous = srcs; + while(previous->next != src) + previous = previous->next; + previous->next = src->next; + } + + free(src); + return 1; +} + +int +source_match(struct source *src, + const unsigned char *p, unsigned char plen) +{ + if(src->plen != plen) + return 0; + if(src->prefix[15] != p[15]) + return 0; + if(memcmp(src->prefix, p, 16) != 0) + return 0; + return 1; +} + +void +update_source(struct source *src, + unsigned short seqno, unsigned short metric) +{ + if(metric >= INFINITY) + return; + + if(src->time < babel_now.tv_sec - SOURCE_GC_TIME || + seqno_compare(src->seqno, seqno) < 0 || + (src->seqno == seqno && src->metric > metric)) { + src->seqno = seqno; + src->metric = metric; + } + src->time = babel_now.tv_sec; +} + +void +expire_sources() +{ + struct source *src; + + src = srcs; + while(src) { + if(src->time > babel_now.tv_sec) + /* clock stepped */ + src->time = babel_now.tv_sec; + if(src->time < babel_now.tv_sec - SOURCE_GC_TIME) { + struct source *old = src; + src = src->next; + flush_source(old); + continue; + } + src = src->next; + } +} diff --git a/babeld/source.h b/babeld/source.h new file mode 100644 index 00000000..38d3c004 --- /dev/null +++ b/babeld/source.h @@ -0,0 +1,66 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef BABEL_SOURCE_H +#define BABEL_SOURCE_H + +#define SOURCE_GC_TIME 200 + +struct source { + struct source *next; + unsigned char id[8]; + unsigned char prefix[16]; + unsigned char plen; + unsigned short seqno; + unsigned short metric; + time_t time; +}; + +int source_match(struct source *src, + const unsigned char *p, unsigned char plen); +struct source *find_source(const unsigned char *id, + const unsigned char *p, + unsigned char plen, + int create, unsigned short seqno); +int flush_source(struct source *src); +void update_source(struct source *src, + unsigned short seqno, unsigned short metric); +void expire_sources(void); + + +#endif diff --git a/babeld/util.c b/babeld/util.c new file mode 100644 index 00000000..f1ac0f15 --- /dev/null +++ b/babeld/util.c @@ -0,0 +1,509 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "babel_main.h" +#include "babeld.h" +#include "util.h" + +unsigned +roughly(unsigned value) +{ + return value * 3 / 4 + random() % (value / 2); +} + +/* d = s1 - s2 */ +void +timeval_minus(struct timeval *d, + const struct timeval *s1, const struct timeval *s2) +{ + if(s1->tv_usec >= s2->tv_usec) { + d->tv_usec = s1->tv_usec - s2->tv_usec; + d->tv_sec = s1->tv_sec - s2->tv_sec; + } else { + d->tv_usec = s1->tv_usec + 1000000 - s2->tv_usec; + d->tv_sec = s1->tv_sec - s2->tv_sec - 1; + } +} + +unsigned +timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) +{ + if(s1->tv_sec < s2->tv_sec) + return 0; + + /* Avoid overflow. */ + if(s1->tv_sec - s2->tv_sec > 2000000) + return 2000000000; + + if(s1->tv_sec > s2->tv_sec) + return + (unsigned)((unsigned)(s1->tv_sec - s2->tv_sec) * 1000 + + ((int)s1->tv_usec - s2->tv_usec) / 1000); + + if(s1->tv_usec <= s2->tv_usec) + return 0; + + return (unsigned)(s1->tv_usec - s2->tv_usec) / 1000u; +} + +/* d = s + msecs */ +void +timeval_add_msec(struct timeval *d, const struct timeval *s, const int msecs) +{ + int usecs; + d->tv_sec = s->tv_sec + msecs / 1000; + usecs = s->tv_usec + (msecs % 1000) * 1000; + if(usecs < 1000000) { + d->tv_usec = usecs; + } else { + d->tv_usec = usecs - 1000000; + d->tv_sec++; + } +} + +void +set_timeout(struct timeval *timeout, int msecs) +{ + timeval_add_msec(timeout, &babel_now, roughly(msecs)); +} + +/* returns <0 if "s1" < "s2", etc. */ +int +timeval_compare(const struct timeval *s1, const struct timeval *s2) +{ + if(s1->tv_sec < s2->tv_sec) + return -1; + else if(s1->tv_sec > s2->tv_sec) + return 1; + else if(s1->tv_usec < s2->tv_usec) + return -1; + else if(s1->tv_usec > s2->tv_usec) + return 1; + else + return 0; +} + +/* set d at min(d, s) */ +/* {0, 0} represents infinity */ +void +timeval_min(struct timeval *d, const struct timeval *s) +{ + if(s->tv_sec == 0) + return; + + if(d->tv_sec == 0 || timeval_compare(d, s) > 0) { + *d = *s; + } +} + +/* set d to min(d, x) with x in [secs, secs+1] */ +void +timeval_min_sec(struct timeval *d, time_t secs) +{ + if(d->tv_sec == 0 || d->tv_sec > secs) { + d->tv_sec = secs; + d->tv_usec = random() % 1000000; + } +} + +/* parse a float value in second and return the corresponding mili-seconds. + For example: + parse_msec("12.342345") returns 12342 */ +int +parse_msec(const char *string) +{ + unsigned int in, fl; + int i, j; + + in = fl = 0; + i = 0; + while(string[i] == ' ' || string[i] == '\t') + i++; + while(string[i] >= '0' && string[i] <= '9') { + in = in * 10 + string[i] - '0'; + i++; + } + if(string[i] == '.') { + i++; + j = 0; + while(string[i] >= '0' && string[i] <= '9') { + fl = fl * 10 + string[i] - '0'; + i++; + j++; + } + + while(j > 3) { + fl /= 10; + j--; + } + while(j < 3) { + fl *= 10; + j++; + } + } + + while(string[i] == ' ' || string[i] == '\t') + i++; + + if(string[i] == '\0') + return in * 1000 + fl; + + return -1; +} + +void +do_debugf(const char *format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + fflush(stderr); + va_end(args); +} + +int +in_prefix(const unsigned char *restrict address, + const unsigned char *restrict prefix, unsigned char plen) +{ + unsigned char m; + + if(plen > 128) + plen = 128; + + if(memcmp(address, prefix, plen / 8) != 0) + return 0; + + if(plen % 8 == 0) + return 1; + + m = 0xFF << (8 - (plen % 8)); + + return ((address[plen / 8] & m) == (prefix[plen / 8] & m)); +} + +unsigned char * +mask_prefix(unsigned char *restrict ret, + const unsigned char *restrict prefix, unsigned char plen) +{ + if(plen >= 128) { + memcpy(ret, prefix, 16); + return ret; + } + + memset(ret, 0, 16); + memcpy(ret, prefix, plen / 8); + if(plen % 8 != 0) + ret[plen / 8] = + (prefix[plen / 8] & ((0xFF << (8 - (plen % 8))) & 0xFF)); + return ret; +} + +static const unsigned char v4prefix[16] = + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; + +static const unsigned char llprefix[16] = + {0xFE, 0x80}; + +const char * +format_address(const unsigned char *address) +{ + static char buf[4][INET6_ADDRSTRLEN]; + static int i = 0; + i = (i + 1) % 4; + if(v4mapped(address)) + inet_ntop(AF_INET, address + 12, buf[i], INET6_ADDRSTRLEN); + else + inet_ntop(AF_INET6, address, buf[i], INET6_ADDRSTRLEN); + return buf[i]; +} + +const char * +format_prefix(const unsigned char *prefix, unsigned char plen) +{ + static char buf[4][INET6_ADDRSTRLEN + 4]; + static int i = 0; + int n; + i = (i + 1) % 4; + if(plen >= 96 && v4mapped(prefix)) { + inet_ntop(AF_INET, prefix + 12, buf[i], INET6_ADDRSTRLEN); + n = strlen(buf[i]); + snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen - 96); + } else { + inet_ntop(AF_INET6, prefix, buf[i], INET6_ADDRSTRLEN); + n = strlen(buf[i]); + snprintf(buf[i] + n, INET6_ADDRSTRLEN + 4 - n, "/%d", plen); + } + return buf[i]; +} + +const char * +format_eui64(const unsigned char *eui) +{ + static char buf[4][28]; + static int i = 0; + i = (i + 1) % 4; + snprintf(buf[i], 28, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", + eui[0], eui[1], eui[2], eui[3], + eui[4], eui[5], eui[6], eui[7]); + return buf[i]; +} + +int +parse_address(const char *address, unsigned char *addr_r, int *af_r) +{ + struct in_addr ina; + struct in6_addr ina6; + int rc; + + rc = inet_pton(AF_INET, address, &ina); + if(rc > 0) { + memcpy(addr_r, v4prefix, 12); + memcpy(addr_r + 12, &ina, 4); + if(af_r) *af_r = AF_INET; + return 0; + } + + rc = inet_pton(AF_INET6, address, &ina6); + if(rc > 0) { + memcpy(addr_r, &ina6, 16); + if(af_r) *af_r = AF_INET6; + return 0; + } + + return -1; +} + +int +parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r, + int *af_r) +{ + char buf[INET6_ADDRSTRLEN]; + char *slash, *end; + unsigned char prefix[16]; + long plen; + int af; + struct in_addr ina; + struct in6_addr ina6; + int rc; + + if(strcmp(net, "default") == 0) { + memset(prefix, 0, 16); + plen = 0; + } else { + slash = strchr(net, '/'); + if(slash == NULL) { + rc = parse_address(net, prefix, &af); + if(rc < 0) + return rc; + plen = 128; + } else { + if(slash - net >= INET6_ADDRSTRLEN) + return -1; + memcpy(buf, net, slash - net); + buf[slash - net] = '\0'; + rc = inet_pton(AF_INET, buf, &ina); + if(rc > 0) { + memcpy(prefix, v4prefix, 12); + memcpy(prefix + 12, &ina, 4); + plen = strtol(slash + 1, &end, 0); + if(*end != '\0' || plen < 0 || plen > 32) + return -1; + plen += 96; + af = AF_INET; + } else { + rc = inet_pton(AF_INET6, buf, &ina6); + if(rc > 0) { + memcpy(prefix, &ina6, 16); + plen = strtol(slash + 1, &end, 0); + if(*end != '\0' || plen < 0 || plen > 128) + return -1; + af = AF_INET6; + } else { + return -1; + } + } + } + } + mask_prefix(prefix_r, prefix, plen); + *plen_r = plen; + if(af_r) *af_r = af; + return 0; +} + +int +parse_eui64(const char *eui, unsigned char *eui_r) +{ + int n; + n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], + &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); + if(n == 8) + return 0; + + n = sscanf(eui, "%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx-%02hhx", + &eui_r[0], &eui_r[1], &eui_r[2], &eui_r[3], + &eui_r[4], &eui_r[5], &eui_r[6], &eui_r[7]); + if(n == 8) + return 0; + + n = sscanf(eui, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &eui_r[0], &eui_r[1], &eui_r[2], + &eui_r[5], &eui_r[6], &eui_r[7]); + if(n == 6) { + eui_r[3] = 0xFF; + eui_r[4] = 0xFE; + return 0; + } + return -1; +} + +int +wait_for_fd(int direction, int fd, int msecs) +{ + fd_set fds; + int rc; + struct timeval tv; + + tv.tv_sec = msecs / 1000; + tv.tv_usec = (msecs % 1000) * 1000; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + if(direction) + rc = select(fd + 1, NULL, &fds, NULL, &tv); + else + rc = select(fd + 1, &fds, NULL, NULL, &tv); + + return rc; +} + +int +martian_prefix(const unsigned char *prefix, int plen) +{ + return + (plen >= 8 && prefix[0] == 0xFF) || + (plen >= 10 && prefix[0] == 0xFE && (prefix[1] & 0xC0) == 0x80) || + (plen >= 128 && memcmp(prefix, zeroes, 15) == 0 && + (prefix[15] == 0 || prefix[15] == 1)) || + (plen >= 96 && v4mapped(prefix) && + ((plen >= 104 && (prefix[12] == 127 || prefix[12] == 0)) || + (plen >= 100 && (prefix[12] & 0xE0) == 0xE0))); +} + +int +linklocal(const unsigned char *address) +{ + return memcmp(address, llprefix, 8) == 0; +} + +int +v4mapped(const unsigned char *address) +{ + return memcmp(address, v4prefix, 12) == 0; +} + +void +v4tov6(unsigned char *dst, const unsigned char *src) +{ + memcpy(dst, v4prefix, 12); + memcpy(dst + 12, src, 4); +} + +void +inaddr_to_uchar(unsigned char *dest, const struct in_addr *src) +{ + memcpy(dest, v4prefix, 12); + memcpy(dest + 12, src, 4); + assert(v4mapped(dest)); +} + +void +uchar_to_inaddr(struct in_addr *dest, const unsigned char *src) +{ + assert(v4mapped(src)); + memcpy(dest, src + 12, 4); +} + +void +in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src) +{ + memcpy(dest, src, 16); +} + +void +uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src) +{ + memcpy(dest, src, 16); +} + +int +daemonise() +{ + int rc; + + fflush(stdout); + fflush(stderr); + + rc = fork(); + if(rc < 0) + return -1; + + if(rc > 0) + exit(0); + + rc = setsid(); + if(rc < 0) + return -1; + + return 1; +} diff --git a/babeld/util.h b/babeld/util.h new file mode 100644 index 00000000..d653b613 --- /dev/null +++ b/babeld/util.h @@ -0,0 +1,168 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "babeld.h" +#include "babel_main.h" +#include "log.h" + +#if defined(i386) || defined(__mc68020__) || defined(__x86_64__) +#define DO_NTOHS(_d, _s) do { _d = ntohs(*(unsigned short*)(_s)); } while(0) +#define DO_NTOHL(_d, _s) do { _d = ntohl(*(unsigned*)(_s)); } while(0) +#define DO_HTONS(_d, _s) do { *(unsigned short*)(_d) = htons(_s); } while(0) +#define DO_HTONL(_d, _s) do { *(unsigned*)(_d) = htonl(_s); } while(0) +/* Some versions of gcc seem to be buggy, and ignore the packed attribute. + Disable this code until the issue is clarified. */ +/* #elif defined __GNUC__*/ +#elif 0 +struct __us { unsigned short x __attribute__((packed)); }; +#define DO_NTOHS(_d, _s) \ + do { _d = ntohs(((const struct __us*)(_s))->x); } while(0) +#define DO_HTONS(_d, _s) \ + do { ((struct __us*)(_d))->x = htons(_s); } while(0) +#else +#define DO_NTOHS(_d, _s) \ + do { short _dd; \ + memcpy(&(_dd), (_s), 2); \ + _d = ntohs(_dd); } while(0) +#define DO_HTONS(_d, _s) \ + do { unsigned short _dd; \ + _dd = htons(_s); \ + memcpy((_d), &(_dd), 2); } while(0) +#endif + +static inline int +seqno_compare(unsigned short s1, unsigned short s2) +{ + if(s1 == s2) + return 0; + else + return ((s2 - s1) & 0x8000) ? 1 : -1; +} + +static inline short +seqno_minus(unsigned short s1, unsigned short s2) +{ + return (short)((s1 - s2) & 0xFFFF); +} + +static inline unsigned short +seqno_plus(unsigned short s, int plus) +{ + return ((s + plus) & 0xFFFF); +} + +unsigned roughly(unsigned value); +void timeval_minus(struct timeval *d, + const struct timeval *s1, const struct timeval *s2); +unsigned timeval_minus_msec(const struct timeval *s1, const struct timeval *s2) + ATTRIBUTE ((pure)); +void timeval_add_msec(struct timeval *d, + const struct timeval *s, const int msecs); +void set_timeout (struct timeval *timeout, int msecs); +int timeval_compare(const struct timeval *s1, const struct timeval *s2) + ATTRIBUTE ((pure)); +void timeval_min(struct timeval *d, const struct timeval *s); +void timeval_min_sec(struct timeval *d, time_t secs); +int parse_msec(const char *string) ATTRIBUTE ((pure)); +void do_debugf(const char *format, ...) + ATTRIBUTE ((format (printf, 1, 2))) COLD; +int in_prefix(const unsigned char *restrict address, + const unsigned char *restrict prefix, unsigned char plen) + ATTRIBUTE ((pure)); +unsigned char *mask_prefix(unsigned char *restrict ret, + const unsigned char *restrict prefix, + unsigned char plen); +const char *format_address(const unsigned char *address); +const char *format_prefix(const unsigned char *address, unsigned char prefix); +const char *format_eui64(const unsigned char *eui); +int parse_address(const char *address, unsigned char *addr_r, int *af_r); +int parse_net(const char *ifp, unsigned char *prefix_r, unsigned char *plen_r, + int *af_r); +int parse_eui64(const char *eui, unsigned char *eui_r); +int wait_for_fd(int direction, int fd, int msecs); +int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure)); +int linklocal(const unsigned char *address) ATTRIBUTE ((pure)); +int v4mapped(const unsigned char *address) ATTRIBUTE ((pure)); +void v4tov6(unsigned char *dst, const unsigned char *src); +void inaddr_to_uchar(unsigned char *dest, const struct in_addr *src); +void uchar_to_inaddr(struct in_addr *dest, const unsigned char *src); +void in6addr_to_uchar(unsigned char *dest, const struct in6_addr *src); +void uchar_to_in6addr(struct in6_addr *dest, const unsigned char *src); +int daemonise(void); + +/* If debugging is disabled, we want to avoid calling format_address + for every omitted debugging message. So debug is a macro. But + vararg macros are not portable. */ +#if defined NO_DEBUG + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#define debugf(...) do {} while(0) +#elif defined __GNUC__ +#define debugf(_args...) do {} while(0) +#else +static inline void debugf(int level, const char *format, ...) { return; } +#endif + +#else /* NO_DEBUG */ + +/* some levels */ +#define BABEL_DEBUG_COMMON (1 << 0) +#define BABEL_DEBUG_KERNEL (1 << 1) +#define BABEL_DEBUG_FILTER (1 << 2) +#define BABEL_DEBUG_TIMEOUT (1 << 3) +#define BABEL_DEBUG_IF (1 << 4) +#define BABEL_DEBUG_ROUTE (1 << 5) +#define BABEL_DEBUG_ALL (0xFFFF) + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#define debugf(level, ...) \ +do { \ +if(UNLIKELY(debug & level)) do_debugf(__VA_ARGS__); \ +} while(0) +#elif defined __GNUC__ +#define debugf(level, _args...) \ +do { \ +if(UNLIKELY(debug & level)) do_debugf(_args); \ +} while(0) +#else +static inline void debugf(int level, const char *format, ...) { return; } +#endif + +#endif /* NO_DEBUG */ + diff --git a/babeld/xroute.c b/babeld/xroute.c new file mode 100644 index 00000000..42f83d07 --- /dev/null +++ b/babeld/xroute.c @@ -0,0 +1,226 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "if.h" +#include "log.h" + +#include "babeld.h" +#include "kernel.h" +#include "neighbour.h" +#include "message.h" +#include "route.h" +#include "xroute.h" +#include "util.h" +#include "babel_interface.h" + +struct xroute *xroutes; +int numxroutes = 0; +int maxxroutes = 0; + +/* Add redistributed route to Babel table. */ +int +babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, + unsigned int ifindex, struct in_addr *nexthop) +{ + unsigned char uchar_prefix[16]; + + inaddr_to_uchar(uchar_prefix, &prefix->prefix); + debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra."); + xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, + 0, 1); + return 0; +} + +/* Remove redistributed route from Babel table. */ +int +babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, + unsigned int ifindex) +{ + unsigned char uchar_prefix[16]; + struct xroute *xroute = NULL; + + inaddr_to_uchar(uchar_prefix, &prefix->prefix); + xroute = find_xroute(uchar_prefix, prefix->prefixlen); + if (xroute != NULL) { + debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); + flush_xroute(xroute); + } + return 0; +} + +/* Add redistributed route to Babel table. */ +int +babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, + unsigned int ifindex, struct in6_addr *nexthop) +{ + unsigned char uchar_prefix[16]; + + in6addr_to_uchar(uchar_prefix, &prefix->prefix); + debugf(BABEL_DEBUG_ROUTE, "Adding new route comming from Zebra."); + xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, + 0, 1); + return 0; +} + +/* Remove redistributed route from Babel table. */ +int +babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, + unsigned int ifindex) +{ + unsigned char uchar_prefix[16]; + struct xroute *xroute = NULL; + + in6addr_to_uchar(uchar_prefix, &prefix->prefix); + xroute = find_xroute(uchar_prefix, prefix->prefixlen); + if (xroute != NULL) { + debugf(BABEL_DEBUG_ROUTE, "Removing route (from zebra)."); + flush_xroute(xroute); + } + return 0; +} + +struct xroute * +find_xroute(const unsigned char *prefix, unsigned char plen) +{ + int i; + for(i = 0; i < numxroutes; i++) { + if(xroutes[i].plen == plen && + memcmp(xroutes[i].prefix, prefix, 16) == 0) + return &xroutes[i]; + } + return NULL; +} + +void +flush_xroute(struct xroute *xroute) +{ + int i; + + i = xroute - xroutes; + assert(i >= 0 && i < numxroutes); + + if(i != numxroutes - 1) + memcpy(xroutes + i, xroutes + numxroutes - 1, sizeof(struct xroute)); + numxroutes--; + VALGRIND_MAKE_MEM_UNDEFINED(xroutes + numxroutes, sizeof(struct xroute)); + + if(numxroutes == 0) { + free(xroutes); + xroutes = NULL; + maxxroutes = 0; + } else if(maxxroutes > 8 && numxroutes < maxxroutes / 4) { + struct xroute *new_xroutes; + int n = maxxroutes / 2; + new_xroutes = realloc(xroutes, n * sizeof(struct xroute)); + if(new_xroutes == NULL) + return; + xroutes = new_xroutes; + maxxroutes = n; + } +} + +static int +add_xroute(unsigned char prefix[16], unsigned char plen, + unsigned short metric, unsigned int ifindex, int proto) +{ + struct xroute *xroute = find_xroute(prefix, plen); + if(xroute) { + if(xroute->metric <= metric) + return 0; + xroute->metric = metric; + return 1; + } + + if(numxroutes >= maxxroutes) { + struct xroute *new_xroutes; + int n = maxxroutes < 1 ? 8 : 2 * maxxroutes; + new_xroutes = xroutes == NULL ? + malloc(n * sizeof(struct xroute)) : + realloc(xroutes, n * sizeof(struct xroute)); + if(new_xroutes == NULL) + return -1; + maxxroutes = n; + xroutes = new_xroutes; + } + + memcpy(xroutes[numxroutes].prefix, prefix, 16); + xroutes[numxroutes].plen = plen; + xroutes[numxroutes].metric = metric; + xroutes[numxroutes].ifindex = ifindex; + xroutes[numxroutes].proto = proto; + numxroutes++; + return 1; +} + +/* add an xroute, verifying some conditions; return 0 if there is no changes */ +int +xroute_add_new_route(unsigned char prefix[16], unsigned char plen, + unsigned short metric, unsigned int ifindex, + int proto, int send_updates) +{ + int rc; + if(martian_prefix(prefix, plen)) + return 0; + metric = redistribute_filter(prefix, plen, ifindex, proto); + if(metric < INFINITY) { + rc = add_xroute(prefix, plen, metric, ifindex, proto); + if(rc > 0) { + struct route *route; + route = find_installed_route(prefix, plen); + if(route) { + if(allow_duplicates < 0 || + metric < allow_duplicates) + uninstall_route(route); + } + if(send_updates) + send_update(NULL, 0, prefix, plen); + return 1; + } + } + return 0; +} diff --git a/babeld/xroute.h b/babeld/xroute.h new file mode 100644 index 00000000..c9a4f85f --- /dev/null +++ b/babeld/xroute.h @@ -0,0 +1,63 @@ +/* + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file 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, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * +Copyright (c) 2007, 2008 by Juliusz Chroboczek +Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +struct xroute { + unsigned char prefix[16]; + unsigned char plen; + unsigned short metric; + unsigned int ifindex; + int proto; +}; + +extern struct xroute *xroutes; +extern int numxroutes; + +struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); +void flush_xroute(struct xroute *xroute); +int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, + unsigned short metric, unsigned int ifindex, + int proto, int send_updates); +int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, + unsigned int ifindex, struct in_addr *nexthop); +int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, + unsigned int ifindex); +int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, + unsigned int ifindex, struct in6_addr *nexthop); +int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, + unsigned int ifindex); -- cgit v1.2.1 From 089082b5d51c41a4498edb6a3f495ade0d517e73 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Fri, 6 Jan 2012 23:09:23 +0100 Subject: babeld: clean kernel_zebra (old functions, fields...). --- babeld/kernel.h | 13 ----------- babeld/kernel_zebra.c | 60 --------------------------------------------------- 2 files changed, 73 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel.h b/babeld/kernel.h index d9d650dc..e8c8f9b7 100644 --- a/babeld/kernel.h +++ b/babeld/kernel.h @@ -55,28 +55,15 @@ struct kernel_route { #define ROUTE_ADD 1 #define ROUTE_MODIFY 2 -#define CHANGE_LINK (1 << 0) -#define CHANGE_ROUTE (1 << 1) -#define CHANGE_ADDR (1 << 2) - extern int export_table, import_table; -int kernel_setup(int setup); -int kernel_setup_socket(int setup); -int kernel_setup_interface(int setup, struct interface *interface); int kernel_interface_operational(struct interface *interface); -int kernel_interface_ipv4(struct interface *interface, - unsigned char *addr_r); int kernel_interface_mtu(struct interface *interface); int kernel_interface_wireless(struct interface *interface); int kernel_route(int operation, const unsigned char *dest, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, const unsigned char *newgate, int newifindex, unsigned int newmetric); -int kernel_routes(struct kernel_route *routes, int maxroutes); -int kernel_callback(int (*fn)(int, void*), void *closure); -int kernel_addresses(struct interface *interface, int ll, - struct kernel_route *routes, int maxroutes); int if_eui64(char *ifname, int ifindex, unsigned char *eui); int gettime(struct timeval *tv); int read_random_bytes(void *buf, size_t len); diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 0fecb527..82f03e43 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -80,41 +80,12 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, const unsigned char *newgate, int newifindex, unsigned int newmetric); - -int export_table = -1, import_table = -1; /* just for compatibility */ - -int -kernel_setup(int setup) -{ - return 0; -} - -/* get a connection with zebra client, at all costs */ -int -kernel_setup_socket(int setup) -{ - return -1; -} - -int -kernel_setup_interface(int setup, struct interface *interface) -{ - return 1; -} - int kernel_interface_operational(struct interface *interface) { return if_is_operative(interface); } -int -kernel_interface_ipv4(struct interface *interface, unsigned char *addr_r) -{ - assert(0); /* function not used */ - return -1; -} - int kernel_interface_mtu(struct interface *interface) { @@ -127,10 +98,6 @@ kernel_interface_wireless(struct interface *interface) return 0; } -extern int -zapi_ipv6_route (u_char cmd, struct zclient *zclient, - struct prefix_ipv6 *p, struct zapi_ipv6 *api); - int kernel_route(int operation, const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric, @@ -400,33 +367,6 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, &quagga_prefix, &api); } -int -kernel_routes(struct kernel_route *routes, int maxroutes) -{ - fprintf(stderr, "\tkernel_routes --- not implemented\n"); - return 0; -} - -int -kernel_callback(int (*fn)(int, void*), void *closure) -{ - struct thread thread; - fprintf(stderr, "\tkernel_callback\n"); - /* do a little work on threads */ - if (thread_fetch(master, &thread) != NULL) { - thread_call (&thread); - } - return 0; -} - -int -kernel_addresses(struct interface *interface, int ll, - struct kernel_route *routes, int maxroutes) -{ - fprintf(stderr, "\tkernel_addresses --- not implemented\n"); - return 0; -} - int if_eui64(char *ifname, int ifindex, unsigned char *eui) { -- cgit v1.2.1 From ef4de4d36c2dc10a68d41e518057d04b262ec867 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 8 Jan 2012 15:29:19 +0400 Subject: babeld: address FreeBSD "struct route" issue FreeBSD system headers have their own "struct route", which made it impossible to compile babeld. Switching babeld to "struct babel_route". --- babeld/message.c | 8 +++---- babeld/route.c | 68 ++++++++++++++++++++++++++++---------------------------- babeld/route.h | 38 +++++++++++++++---------------- babeld/xroute.c | 2 +- 4 files changed, 58 insertions(+), 58 deletions(-) (limited to 'babeld') diff --git a/babeld/message.c b/babeld/message.c index bfb17625..57d875fb 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -854,7 +854,7 @@ flushupdates(struct interface *ifp) { babel_interface_nfo *babel_ifp = NULL; struct xroute *xroute; - struct route *route; + struct babel_route *route; const unsigned char *last_prefix = NULL; unsigned char last_plen = 0xFF; int i; @@ -1004,7 +1004,7 @@ send_update(struct interface *ifp, int urgent, if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; - struct route *route; + struct babel_route *route; FOR_ALL_INTERFACES(ifp_aux, linklist_node) send_update(ifp_aux, urgent, prefix, plen); if(prefix) { @@ -1392,7 +1392,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix, unsigned short seqno, const unsigned char *id) { struct xroute *xroute; - struct route *route; + struct babel_route *route; struct neighbour *successor = NULL; xroute = find_xroute(prefix, plen); @@ -1438,7 +1438,7 @@ handle_request(struct neighbour *neigh, const unsigned char *prefix, if(!successor || successor == neigh) { /* We were about to forward a request to its requestor. Try to find a different neighbour to forward the request to. */ - struct route *other_route; + struct babel_route *other_route; other_route = find_best_route(prefix, plen, 0, neigh); if(other_route && route_metric(other_route) < INFINITY) diff --git a/babeld/route.c b/babeld/route.c index e0c9d047..a92018fd 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -58,14 +58,14 @@ THE SOFTWARE. #include "message.h" #include "resend.h" -static void consider_route(struct route *route); +static void consider_route(struct babel_route *route); -struct route *routes = NULL; +struct babel_route *routes = NULL; int numroutes = 0, maxroutes = 0; int kernel_metric = 0; int allow_duplicates = -1; -struct route * +struct babel_route * find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop) { @@ -79,7 +79,7 @@ find_route(const unsigned char *prefix, unsigned char plen, return NULL; } -struct route * +struct babel_route * find_installed_route(const unsigned char *prefix, unsigned char plen) { int i; @@ -91,7 +91,7 @@ find_installed_route(const unsigned char *prefix, unsigned char plen) } void -flush_route(struct route *route) +flush_route(struct babel_route *route) { int i; struct source *src; @@ -111,18 +111,18 @@ flush_route(struct route *route) src = route->src; if(i != numroutes - 1) - memcpy(routes + i, routes + numroutes - 1, sizeof(struct route)); + memcpy(routes + i, routes + numroutes - 1, sizeof(struct babel_route)); numroutes--; - VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct route)); + VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct babel_route)); if(numroutes == 0) { free(routes); routes = NULL; maxroutes = 0; } else if(maxroutes > 8 && numroutes < maxroutes / 4) { - struct route *new_routes; + struct babel_route *new_routes; int n = maxroutes / 2; - new_routes = realloc(routes, n * sizeof(struct route)); + new_routes = realloc(routes, n * sizeof(struct babel_route)); if(new_routes != NULL) { routes = new_routes; maxroutes = n; @@ -171,7 +171,7 @@ metric_to_kernel(int metric) } void -install_route(struct route *route) +install_route(struct babel_route *route) { int rc; @@ -196,7 +196,7 @@ install_route(struct route *route) } void -uninstall_route(struct route *route) +uninstall_route(struct babel_route *route) { int rc; @@ -218,7 +218,7 @@ uninstall_route(struct route *route) must be the same. */ static void -switch_routes(struct route *old, struct route *new) +switch_routes(struct babel_route *old, struct babel_route *new) { int rc; @@ -249,7 +249,7 @@ switch_routes(struct route *old, struct route *new) } static void -change_route_metric(struct route *route, unsigned newmetric) +change_route_metric(struct babel_route *route, unsigned newmetric) { int old, new; @@ -276,26 +276,26 @@ change_route_metric(struct route *route, unsigned newmetric) } static void -retract_route(struct route *route) +retract_route(struct babel_route *route) { route->refmetric = INFINITY; change_route_metric(route, INFINITY); } int -route_feasible(struct route *route) +route_feasible(struct babel_route *route) { return update_feasible(route->src, route->seqno, route->refmetric); } int -route_old(struct route *route) +route_old(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time * 7 / 8; } int -route_expired(struct route *route) +route_expired(struct babel_route *route) { return route->time < babel_now.tv_sec - route->hold_time; } @@ -320,11 +320,11 @@ update_feasible(struct source *src, } /* This returns the feasible route with the smallest metric. */ -struct route * +struct babel_route * find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude) { - struct route *route = NULL; + struct babel_route *route = NULL; int i; for(i = 0; i < numroutes; i++) { @@ -344,7 +344,7 @@ find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, } void -update_route_metric(struct route *route) +update_route_metric(struct babel_route *route) { int oldmetric = route_metric(route); @@ -404,14 +404,14 @@ update_interface_metric(struct interface *ifp) } /* This is called whenever we receive an update. */ -struct route * +struct babel_route * update_route(const unsigned char *router_id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, const unsigned char *nexthop) { - struct route *route; + struct babel_route *route; struct source *src; int metric, feasible; int add_metric; @@ -488,11 +488,11 @@ update_route(const unsigned char *router_id, return NULL; } if(numroutes >= maxroutes) { - struct route *new_routes; + struct babel_route *new_routes; int n = maxroutes < 1 ? 8 : 2 * maxroutes; new_routes = routes == NULL ? - malloc(n * sizeof(struct route)) : - realloc(routes, n * sizeof(struct route)); + malloc(n * sizeof(struct babel_route)) : + realloc(routes, n * sizeof(struct babel_route)); if(new_routes == NULL) return NULL; maxroutes = n; @@ -521,7 +521,7 @@ send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src) { - struct route *route = find_installed_route(src->prefix, src->plen); + struct babel_route *route = find_installed_route(src->prefix, src->plen); if(seqno_minus(src->seqno, seqno) > 100) { /* Probably a source that lost its seqno. Let it time-out. */ @@ -539,9 +539,9 @@ send_unfeasible_request(struct neighbour *neigh, int force, /* This takes a feasible route and decides whether to install it. */ static void -consider_route(struct route *route) +consider_route(struct babel_route *route) { - struct route *installed; + struct babel_route *installed; struct xroute *xroute; if(route->installed) @@ -606,7 +606,7 @@ retract_neighbour_routes(struct neighbour *neigh) } void -send_triggered_update(struct route *route, struct source *oldsrc, +send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric) { unsigned newmetric, diff; @@ -665,12 +665,12 @@ send_triggered_update(struct route *route, struct source *oldsrc, /* A route has just changed. Decide whether to switch to a different route or send an update. */ void -route_changed(struct route *route, +route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric) { if(route->installed) { if(route_metric(route) > oldmetric) { - struct route *better_route; + struct babel_route *better_route; better_route = find_best_route(route->src->prefix, route->src->plen, 1, NULL); if(better_route && @@ -692,7 +692,7 @@ route_changed(struct route *route, void route_lost(struct source *src, unsigned oldmetric) { - struct route *new_route; + struct babel_route *new_route; new_route = find_best_route(src->prefix, src->plen, 1, NULL); if(new_route) { consider_route(new_route); @@ -715,7 +715,7 @@ expire_routes(void) i = 0; while(i < numroutes) { - struct route *route = &routes[i]; + struct babel_route *route = &routes[i]; if(route->time > babel_now.tv_sec || /* clock stepped */ route_old(route)) { @@ -744,7 +744,7 @@ babel_uninstall_all_routes(void) } } -struct route * +struct babel_route * babel_route_get_by_source(struct source *src) { int i; diff --git a/babeld/route.h b/babeld/route.h index e36f6c34..dbb205d1 100644 --- a/babeld/route.h +++ b/babeld/route.h @@ -40,7 +40,7 @@ THE SOFTWARE. #include "babel_interface.h" #include "source.h" -struct route { +struct babel_route { struct source *src; unsigned short metric; unsigned short refmetric; @@ -53,38 +53,38 @@ struct route { }; static inline int -route_metric(const struct route *route) +route_metric(const struct babel_route *route) { return route->metric; } -extern struct route *routes; +extern struct babel_route *routes; extern int numroutes, maxroutes; extern int kernel_metric, allow_duplicates; -struct route *find_route(const unsigned char *prefix, unsigned char plen, +struct babel_route *find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop); -struct route *find_installed_route(const unsigned char *prefix, +struct babel_route *find_installed_route(const unsigned char *prefix, unsigned char plen); -void flush_route(struct route *route); +void flush_route(struct babel_route *route); void flush_neighbour_routes(struct neighbour *neigh); void flush_interface_routes(struct interface *ifp, int v4only); -void install_route(struct route *route); -void uninstall_route(struct route *route); -void switch_route(struct route *old, struct route *new); -int route_feasible(struct route *route); -int route_old(struct route *route); -int route_expired(struct route *route); +void install_route(struct babel_route *route); +void uninstall_route(struct babel_route *route); +void switch_route(struct babel_route *old, struct babel_route *new); +int route_feasible(struct babel_route *route); +int route_old(struct babel_route *route); +int route_expired(struct babel_route *route); int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric); -struct route *find_best_route(const unsigned char *prefix, unsigned char plen, +struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude); -struct route *install_best_route(const unsigned char prefix[16], +struct babel_route *install_best_route(const unsigned char prefix[16], unsigned char plen); void update_neighbour_metric(struct neighbour *neigh, int change); void update_interface_metric(struct interface *ifp); -void update_route_metric(struct route *route); -struct route *update_route(const unsigned char *a, +void update_route_metric(struct babel_route *route); +struct babel_route *update_route(const unsigned char *a, const unsigned char *p, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, @@ -93,12 +93,12 @@ void retract_neighbour_routes(struct neighbour *neigh); void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, struct source *src); -void send_triggered_update(struct route *route, +void send_triggered_update(struct babel_route *route, struct source *oldsrc, unsigned oldmetric); -void route_changed(struct route *route, +void route_changed(struct babel_route *route, struct source *oldsrc, unsigned short oldmetric); void route_lost(struct source *src, unsigned oldmetric); void expire_routes(void); void babel_uninstall_all_routes(void); -struct route *babel_route_get_by_source(struct source *src); +struct babel_route *babel_route_get_by_source(struct source *src); diff --git a/babeld/xroute.c b/babeld/xroute.c index 42f83d07..7b09cb87 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -210,7 +210,7 @@ xroute_add_new_route(unsigned char prefix[16], unsigned char plen, if(metric < INFINITY) { rc = add_xroute(prefix, plen, metric, ifindex, proto); if(rc > 0) { - struct route *route; + struct babel_route *route; route = find_installed_route(prefix, plen); if(route) { if(allow_duplicates < 0 || -- cgit v1.2.1 From 3dbda0ceebe369a1071600fe7d8d8ecf45f1027c Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sun, 8 Jan 2012 16:52:36 +0400 Subject: babeld: address some compilation warnings Including system headers is not necessary with zebra.h included and sometimes results in "__ASSERT_FUNCTION redefined" compilation warning. * babeld.c * babel_distribute_update_interface(): make static * babel_interface.c * interface_config_write(): unused 'babel_ifp' * don't include system headers * message.c * send_request(): unused 'babel_ifp' * send_multihop_request(): idem * don't include system headers * route.c: don't include system headers * xroute.c: idem * source.h: newline at EOF * message.h: idem --- babeld/babel_interface.c | 14 -------------- babeld/babeld.c | 2 +- babeld/message.c | 12 ------------ babeld/route.c | 7 ------- babeld/xroute.c | 8 -------- 5 files changed, 1 insertion(+), 42 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 0130f26b..ff9c5eb4 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -37,17 +37,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include #include "memory.h" #include "log.h" @@ -724,12 +713,9 @@ interface_config_write (struct vty *vty) { struct listnode *node; struct interface *ifp; - babel_interface_nfo *babel_ifp; int write = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { - babel_ifp = babel_get_if_nfo(ifp); - /* Do not display the interface if there is no configuration about it */ if (ifp->desc == NULL) continue; diff --git a/babeld/babeld.c b/babeld/babeld.c index 18b4e34f..3dc35b5d 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -560,7 +560,7 @@ babel_distribute_update (struct distribute *dist) } } -void +static void babel_distribute_update_interface (struct interface *ifp) { struct distribute *dist; diff --git a/babeld/message.c b/babeld/message.c index 57d875fb..7930a1b1 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -37,14 +37,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include - #include #include "if.h" @@ -1216,7 +1208,6 @@ void send_request(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { - babel_interface_nfo *babel_ifp = NULL; int v4, len; if(ifp == NULL) { @@ -1236,7 +1227,6 @@ send_request(struct interface *ifp, if(!if_up(ifp)) return; - babel_ifp = babel_get_if_nfo(ifp); debugf(BABEL_DEBUG_COMMON,"sending request to %s for %s.", ifp->name, prefix ? format_prefix(prefix, plen) : "any"); v4 = plen >= 96 && v4mapped(prefix); @@ -1288,7 +1278,6 @@ send_multihop_request(struct interface *ifp, unsigned short seqno, const unsigned char *id, unsigned short hop_count) { - babel_interface_nfo *babel_ifp = NULL; int v4, pb, len; /* Make sure any buffered updates go out before this request. */ @@ -1308,7 +1297,6 @@ send_multihop_request(struct interface *ifp, if(!if_up(ifp)) return; - babel_ifp = babel_get_if_nfo(ifp); debugf(BABEL_DEBUG_COMMON,"Sending request (%d) on %s for %s.", hop_count, ifp->name, format_prefix(prefix, plen)); v4 = plen >= 96 && v4mapped(prefix); diff --git a/babeld/route.c b/babeld/route.c index a92018fd..aa181be7 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -37,13 +37,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include - #include #include "if.h" diff --git a/babeld/xroute.c b/babeld/xroute.c index 7b09cb87..eb4aaeb5 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -37,14 +37,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include -#include - #include #include "if.h" #include "log.h" -- cgit v1.2.1 From c7c53fa88ccdbc2d48cf7327c9e4f33cdc517a8a Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Sun, 8 Jan 2012 16:43:08 +0100 Subject: babeld: address some other compilation warnings. --- babeld/babel_interface.c | 4 ++-- babeld/neighbour.c | 8 ++++---- babeld/route.h | 2 +- babeld/util.h | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index ff9c5eb4..4bd4499a 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -61,7 +61,7 @@ static int interface_reset(struct interface *ifp); static int babel_if_new_hook (struct interface *ifp); static int babel_if_delete_hook (struct interface *ifp); static int interface_config_write (struct vty *vty); -static babel_interface_nfo * babel_interface_allocate (); +static babel_interface_nfo * babel_interface_allocate (void); static void babel_interface_free (babel_interface_nfo *bi); @@ -738,7 +738,7 @@ interface_config_write (struct vty *vty) /* functions to allocate or free memory for a babel_interface_nfo, filling needed fields */ static babel_interface_nfo * -babel_interface_allocate () +babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XMALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); diff --git a/babeld/neighbour.c b/babeld/neighbour.c index 43da8e09..f360b891 100644 --- a/babeld/neighbour.c +++ b/babeld/neighbour.c @@ -217,13 +217,13 @@ reset_txcost(struct neighbour *neigh) delay = timeval_minus_msec(&babel_now, &neigh->ihu_time); - if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10 * 3) + if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 10U * 3U) return 0; /* If we're losing a lot of packets, we probably lost an IHU too */ if(delay >= 180000 || (neigh->reach & 0xFFF0) == 0 || (neigh->ihu_interval > 0 && - delay >= neigh->ihu_interval * 10 * 10)) { + delay >= neigh->ihu_interval * 10U * 10U)) { neigh->txcost = INFINITY; neigh->ihu_time = babel_now; return 1; @@ -266,9 +266,9 @@ check_neighbours() update_neighbour_metric(neigh, changed); if(neigh->hello_interval > 0) - msecs = MIN(msecs, neigh->hello_interval * 10); + msecs = MIN(msecs, neigh->hello_interval * 10U); if(neigh->ihu_interval > 0) - msecs = MIN(msecs, neigh->ihu_interval * 10); + msecs = MIN(msecs, neigh->ihu_interval * 10U); neigh = neigh->next; } diff --git a/babeld/route.h b/babeld/route.h index dbb205d1..e38f1577 100644 --- a/babeld/route.h +++ b/babeld/route.h @@ -52,7 +52,7 @@ struct babel_route { short installed; }; -static inline int +static inline unsigned short route_metric(const struct babel_route *route) { return route->metric; diff --git a/babeld/util.h b/babeld/util.h index d653b613..4e7635f6 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -42,10 +42,10 @@ THE SOFTWARE. #include "log.h" #if defined(i386) || defined(__mc68020__) || defined(__x86_64__) -#define DO_NTOHS(_d, _s) do { _d = ntohs(*(unsigned short*)(_s)); } while(0) -#define DO_NTOHL(_d, _s) do { _d = ntohl(*(unsigned*)(_s)); } while(0) -#define DO_HTONS(_d, _s) do { *(unsigned short*)(_d) = htons(_s); } while(0) -#define DO_HTONL(_d, _s) do { *(unsigned*)(_d) = htonl(_s); } while(0) +#define DO_NTOHS(_d, _s) do{ _d = ntohs(*(const unsigned short*)(_s)); }while(0) +#define DO_NTOHL(_d, _s) do{ _d = ntohl(*(const unsigned*)(_s)); } while(0) +#define DO_HTONS(_d, _s) do{ *(unsigned short*)(_d) = htons(_s); } while(0) +#define DO_HTONL(_d, _s) do{ *(unsigned*)(_d) = htonl(_s); } while(0) /* Some versions of gcc seem to be buggy, and ignore the packed attribute. Disable this code until the issue is clarified. */ /* #elif defined __GNUC__*/ -- cgit v1.2.1 From 528eab1fd04434e0befe9a98191b11602e3cb2ff Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Sun, 8 Jan 2012 17:07:10 +0100 Subject: babeld: fix bug concerning pidfile. --- babeld/babel_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 6065b7bc..b4d60886 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -87,7 +87,7 @@ int link_detect = 0; int wireless_hello_interval = -1; int wired_hello_interval = -1; int idle_hello_interval = -1; -char *pidfile = "/var/run/babeld.pid"; +static char *pidfile = PATH_BABELD_PID; const unsigned char zeroes[16] = {0}; const unsigned char ones[16] = @@ -162,7 +162,6 @@ babel_init(int argc, char **argv) int rc, opt; int do_daemonise = 0; char *progname = NULL; - char *pidfile = PATH_BABELD_PID; /* Set umask before anything for security */ umask (0027); -- cgit v1.2.1 From 87c271c69330cfcea7955503eba3ed15a15cb634 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 10 Jan 2012 15:58:04 +0400 Subject: babeld: address remaining -Wcast-qual warnings * net.c * babel_send(): arguments are not treated as "const", justify declaration * babel_main.c: declare constant pointers as such --- babeld/babel_main.c | 4 ++-- babeld/net.c | 8 ++++---- babeld/net.h | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index b4d60886..1c1d0eeb 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -87,14 +87,14 @@ int link_detect = 0; int wireless_hello_interval = -1; int wired_hello_interval = -1; int idle_hello_interval = -1; -static char *pidfile = PATH_BABELD_PID; +static const char *pidfile = PATH_BABELD_PID; const unsigned char zeroes[16] = {0}; const unsigned char ones[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -static char *state_file = "/var/lib/babeld/babel-state"; +static const char *state_file = "/var/lib/babeld/babel-state"; unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ diff --git a/babeld/net.c b/babeld/net.c index 5cb1236e..eaed51d2 100644 --- a/babeld/net.c +++ b/babeld/net.c @@ -139,16 +139,16 @@ babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen) int babel_send(int s, - const void *buf1, int buflen1, const void *buf2, int buflen2, - const struct sockaddr *sin, int slen) + void *buf1, int buflen1, void *buf2, int buflen2, + struct sockaddr *sin, int slen) { struct iovec iovec[2]; struct msghdr msg; int rc; - iovec[0].iov_base = (void*)buf1; + iovec[0].iov_base = buf1; iovec[0].iov_len = buflen1; - iovec[1].iov_base = (void*)buf2; + iovec[1].iov_base = buf2; iovec[1].iov_len = buflen2; memset(&msg, 0, sizeof(msg)); msg.msg_name = (struct sockaddr*)sin; diff --git a/babeld/net.h b/babeld/net.h index e6729001..4bd0f04f 100644 --- a/babeld/net.h +++ b/babeld/net.h @@ -39,6 +39,6 @@ THE SOFTWARE. int babel_socket(int port); int babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen); int babel_send(int s, - const void *buf1, int buflen1, const void *buf2, int buflen2, - const struct sockaddr *sin, int slen); + void *buf1, int buflen1, void *buf2, int buflen2, + struct sockaddr *sin, int slen); int tcp_server_socket(int port, int local); -- cgit v1.2.1 From 446d73b7ae544df3af68b4e85ddcd06c2d3589bf Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 17 Jan 2012 17:00:20 +0400 Subject: babeld: bring babel_usage() into focus --- babeld/babel_main.c | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 1c1d0eeb..fd1d94f4 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -64,7 +64,6 @@ THE SOFTWARE. static void babel_init (int argc, char **argv); -static void babel_usage (char *progname); static char *babel_get_progname(char *argv_0); static void babel_fail(void); static void babel_init_random(void); @@ -155,6 +154,30 @@ main(int argc, char **argv) return 0; } +static void +babel_usage (char *progname, int status) +{ + if (status != 0) + fprintf (stderr, "Try `%s --help' for more information.\n", progname); + else + { + printf ("Usage : %s [OPTION...]\n\ +Daemon which manages Babel routing protocol.\n\n\ +-d, --daemon Runs in daemon mode\n\ +-f, --config_file Set configuration file name\n\ +-i, --pid_file Set process identifier file name\n\ +-A, --vty_addr Set vty's bind address\n\ +-P, --vty_port Set vty's port number\n\ +-u, --user User to run as\n\ +-g, --group Group to run as\n\ +-v, --version Print program version\n\ +-h, --help Display this help and exit\n\ +\n\ +Report bugs to %s\n", progname, ZEBRA_BUG_ADDRESS); + } + exit (status); +} + /* make initialisations witch don't need infos about kernel(interfaces, etc.) */ static void babel_init(int argc, char **argv) @@ -217,10 +240,10 @@ babel_init(int argc, char **argv) exit (0); break; case 'h': - babel_usage (progname); + babel_usage (progname, 0); break; default: - babel_usage(progname); + babel_usage (progname, 1); break; } } @@ -301,26 +324,6 @@ babel_get_progname(char *argv_0) { return (p ? ++p : argv_0); } -static void -babel_usage(char *progname) -{ - fprintf(stderr, - "Syntax: %s " - "[-m multicast_address] [-p port] [-S state-file]\n" - " " - "[-h hello] [-H wired_hello] [-i idle_hello]\n" - " " - "[-k metric] [-A metric] [-s] [-P] [-l] [-w] [-d level] [-g port]\n" - " " - "[-t table] [-T table] [-c file] [-C statement]\n" - " " - "[-D] [-L logfile] [-I pidfile]\n" - " " - "[id] interface...\n", - progname); - exit(1); -} - static void babel_fail(void) { -- cgit v1.2.1 From 8f3607f84eb5d21d4732a51b39775b7edf8796c2 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 17 Jan 2012 17:04:00 +0400 Subject: babeld: add handling of "-z" cmdline arg --- babeld/babel_main.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index fd1d94f4..2ae8b917 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -110,6 +110,7 @@ struct option longopts[] = { "daemon", no_argument, NULL, 'd'}, { "config_file", required_argument, NULL, 'f'}, { "pid_file", required_argument, NULL, 'i'}, + { "socket", required_argument, NULL, 'z'}, { "help", no_argument, NULL, 'h'}, { "vty_addr", required_argument, NULL, 'A'}, { "vty_port", required_argument, NULL, 'P'}, @@ -166,6 +167,7 @@ Daemon which manages Babel routing protocol.\n\n\ -d, --daemon Runs in daemon mode\n\ -f, --config_file Set configuration file name\n\ -i, --pid_file Set process identifier file name\n\ +-z, --socket Set path of zebra socket\n\ -A, --vty_addr Set vty's bind address\n\ -P, --vty_port Set vty's port number\n\ -u, --user User to run as\n\ @@ -204,7 +206,7 @@ babel_init(int argc, char **argv) /* get options */ while(1) { - opt = getopt_long(argc, argv, "df:i:hA:P:u:g:v", longopts, 0); + opt = getopt_long(argc, argv, "df:i:z:hA:P:u:g:v", longopts, 0); if(opt < 0) break; @@ -220,6 +222,9 @@ babel_init(int argc, char **argv) case 'i': pidfile = optarg; break; + case 'z': + zclient_serv_path_set (optarg); + break; case 'A': babel_vty_addr = optarg; break; -- cgit v1.2.1 From d4e46e681434e768b870679b998eb1ac7635fdfc Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 17 Jan 2012 19:25:03 +0400 Subject: babeld: implement "show babel interface" command * babel_interface.c * show_babel_interface_sub(): new function to process one ifp * show_babel_interface(): new function, VTY wrapper * babel_if_init(): update respectively --- babeld/babel_interface.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 4bd4499a..df68afba 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -660,6 +660,62 @@ is_interface_ll_address(struct interface *ifp, const unsigned char *address) return 0; } +static void +show_babel_interface_sub (struct vty *vty, struct interface *ifp) +{ + int is_up; + babel_interface_nfo *babel_ifp; + + vty_out (vty, "%s is %s%s", ifp->name, + ((is_up = if_is_operative(ifp)) ? "up" : "down"), VTY_NEWLINE); + vty_out (vty, " ifindex %u, MTU %u bytes %s%s", + ifp->ifindex, ifp->mtu, if_flag_dump(ifp->flags), VTY_NEWLINE); + + if (babel_enable_if_lookup (ifp->name) < 0) + { + vty_out (vty, " Babel protocol is not enabled on this interface%s", VTY_NEWLINE); + return; + } + if (!is_up) + { + vty_out (vty, " Babel protocol is enabled, but not running on this interface%s", VTY_NEWLINE); + return; + } + babel_ifp = babel_get_if_nfo (ifp); + vty_out (vty, " Babel protocol is running on this interface%s", VTY_NEWLINE); + vty_out (vty, " Operating mode is \"%s\"%s", + CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless", VTY_NEWLINE); + vty_out (vty, " Split horizon mode is %s%s", + CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); + vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); +} + +DEFUN (show_babel_interface, + show_babel_interface_cmd, + "show babel interface [INTERFACE]", + SHOW_STR + IP_STR + "Babel information\n" + "Interface information\n" + "Interface name\n") +{ + struct interface *ifp; + struct listnode *node; + + if (argc == 0) + { + for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) + show_babel_interface_sub (vty, ifp); + return CMD_SUCCESS; + } + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + { + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + return CMD_WARNING; + } + show_babel_interface_sub (vty, ifp); + return CMD_SUCCESS; +} void babel_if_init () @@ -688,6 +744,10 @@ babel_if_init () install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); install_element(INTERFACE_NODE, &babel_passive_interface_cmd); install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); + + /* "show babel ..." commands */ + install_element (VIEW_NODE, &show_babel_interface_cmd); + install_element (ENABLE_NODE, &show_babel_interface_cmd); } /* hooks: functions called respectively when struct interface is -- cgit v1.2.1 From 4eedea551290906fc76f3a0c908ae759e78bb68a Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Tue, 17 Jan 2012 22:46:21 +0100 Subject: babeld: change fprintf(stderr) in term of zlog_err. --- babeld/babel_interface.c | 2 +- babeld/babel_zebra.c | 1 - babeld/message.c | 44 ++++++++++++++++++++------------------------ babeld/route.c | 12 ++++++------ 4 files changed, 27 insertions(+), 32 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index df68afba..b80bf94e 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -503,7 +503,7 @@ interface_recalculate(struct interface *ifp) tmp = babel_ifp->sendbuf; babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize); if(babel_ifp->sendbuf == NULL) { - fprintf(stderr, "Couldn't reallocate sendbuf.\n"); + zlog_err("Couldn't reallocate sendbuf."); free(tmp); babel_ifp->bufsize = 0; return -1; diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 6d78ecc6..7ba1adfe 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -277,7 +277,6 @@ void babelz_zebra_init(void) static int zebra_config_write (struct vty *vty) { - fprintf(stderr, "\tzebra_config_write\n"); if (! zclient->enable) { vty_out (vty, "no router zebra%s", VTY_NEWLINE); diff --git a/babeld/message.c b/babeld/message.c index 7930a1b1..92c416b9 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -145,35 +145,34 @@ parse_packet(const unsigned char *from, struct interface *ifp, v4_nh[16], v6_nh[16]; if(!linklocal(from)) { - fprintf(stderr, "Received packet from non-local address %s.\n", - format_address(from)); + zlog_err("Received packet from non-local address %s.", + format_address(from)); return; } if(packet[0] != 42) { - fprintf(stderr, "Received malformed packet on %s from %s.\n", - ifp->name, format_address(from)); + zlog_err("Received malformed packet on %s from %s.", + ifp->name, format_address(from)); return; } if(packet[1] != 2) { - fprintf(stderr, - "Received packet with unknown version %d on %s from %s.\n", - packet[1], ifp->name, format_address(from)); + zlog_err("Received packet with unknown version %d on %s from %s.", + packet[1], ifp->name, format_address(from)); return; } neigh = find_neighbour(from, ifp); if(neigh == NULL) { - fprintf(stderr, "Couldn't allocate neighbour.\n"); + zlog_err("Couldn't allocate neighbour."); return; } DO_NTOHS(bodylen, packet + 2); if(bodylen + 4 > packetlen) { - fprintf(stderr, "Received truncated packet (%d + 4 > %d).\n", - bodylen, packetlen); + zlog_err("Received truncated packet (%d + 4 > %d).", + bodylen, packetlen); bodylen = packetlen - 4; } @@ -188,12 +187,12 @@ parse_packet(const unsigned char *from, struct interface *ifp, continue; } if(i + 1 > bodylen) { - fprintf(stderr, "Received truncated message.\n"); + zlog_err("Received truncated message."); break; } len = message[1]; if(i + len > bodylen) { - fprintf(stderr, "Received truncated message.\n"); + zlog_err("Received truncated message."); break; } @@ -330,7 +329,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, have_router_id = 1; } if(!have_router_id && message[2] != 0) { - fprintf(stderr, "Received prefix with no router id.\n"); + zlog_err("Received prefix with no router id."); goto fail; } debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.", @@ -341,8 +340,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, if(message[2] == 0) { if(metric < 0xFFFF) { - fprintf(stderr, - "Received wildcard update with finite metric.\n"); + zlog_err("Received wildcard update with finite metric."); goto done; } retract_neighbour_routes(neigh); @@ -409,8 +407,8 @@ parse_packet(const unsigned char *from, struct interface *ifp, continue; fail: - fprintf(stderr, "Couldn't parse packet (%d, %d) from %s on %s.\n", - message[0], message[1], format_address(from), ifp->name); + zlog_err("Couldn't parse packet (%d, %d) from %s on %s.", + message[0], message[1], format_address(from), ifp->name); goto done; } return; @@ -470,8 +468,8 @@ flushbuf(struct interface *ifp) if(rc < 0) zlog_err("send: %s", safe_strerror(errno)); } else { - fprintf(stderr, "Warning: bucket full, dropping packet to %s.\n", - ifp->name); + zlog_err("Warning: bucket full, dropping packet to %s.", + ifp->name); } } VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize); @@ -705,11 +703,9 @@ flush_unicast(int dofree) if(rc < 0) zlog_err("send(unicast): %s", safe_strerror(errno)); } else { - fprintf(stderr, - "Warning: bucket full, dropping unicast packet" - "to %s if %s.\n", - format_address(unicast_neighbour->address), - unicast_neighbour->ifp->name); + zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.", + format_address(unicast_neighbour->address), + unicast_neighbour->ifp->name); } done: diff --git a/babeld/route.c b/babeld/route.c index aa181be7..aadf80f2 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -172,8 +172,8 @@ install_route(struct babel_route *route) return; if(!route_feasible(route)) - fprintf(stderr, "WARNING: installing unfeasible route " - "(this shouldn't happen)."); + zlog_err("WARNING: installing unfeasible route " + "(this shouldn't happen)."); rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, route->nexthop, @@ -224,8 +224,8 @@ switch_routes(struct babel_route *old, struct babel_route *new) return; if(!route_feasible(new)) - fprintf(stderr, "WARNING: switching to unfeasible route " - "(this shouldn't happen)."); + zlog_err("WARNING: switching to unfeasible route " + "(this shouldn't happen)."); rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen, old->nexthop, old->neigh->ifp->ifindex, @@ -414,8 +414,8 @@ update_route(const unsigned char *router_id, return NULL; /* I have announced the route */ if(martian_prefix(prefix, plen)) { - fprintf(stderr, "Rejecting martian route to %s through %s.\n", - format_prefix(prefix, plen), format_address(router_id)); + zlog_err("Rejecting martian route to %s through %s.", + format_prefix(prefix, plen), format_address(router_id)); return NULL; } -- cgit v1.2.1 From 0ee8a1f1d61ce55642d9164625ab36700fe2c3a9 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 00:52:06 +0100 Subject: babeld: avoid segfault (bug 706). --- babeld/babel_interface.c | 10 ++++++++++ babeld/babel_interface.h | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index b80bf94e..edfa2b40 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -486,6 +486,13 @@ interface_recalculate(struct interface *ifp) int mtu, rc; struct ipv6_mreq mreq; + if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) { + interface_reset(ifp); + return -1; + } + + babel_ifp->flags |= BABEL_IF_IS_UP; + mtu = MIN(ifp->mtu, ifp->mtu6); /* We need to be able to fit at least two messages into a packet, @@ -577,6 +584,9 @@ interface_reset(struct interface *ifp) struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name); + babel_ifp->flags &= ~BABEL_IF_IS_UP; + flush_interface_routes(ifp, 0); babel_ifp->buffered = 0; babel_ifp->bufsize = 0; diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index 7a6efb93..d9fb9a4a 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -90,12 +90,15 @@ static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) #define BABEL_IF_SPLIT_HORIZON (1 << 2) #define BABEL_IF_LQ (1 << 3) #define BABEL_IF_IS_ENABLE (1 << 4) +#define BABEL_IF_IS_UP (1 << 5) static inline int if_up(struct interface *ifp) { - return (if_is_up(ifp) && + return (if_is_operative(ifp) && ifp->connected != NULL && + babel_get_if_nfo(ifp) != NULL && + (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP) && (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_ENABLE)); } -- cgit v1.2.1 From 297a55ba1ce58b281b825400abeca6c32b99db52 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 16:39:29 +0100 Subject: babeld: add command: "show_babel_neighbour". --- babeld/babel_interface.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index edfa2b40..bd32d263 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -51,6 +51,7 @@ THE SOFTWARE. #include "message.h" #include "route.h" #include "babel_zebra.h" +#include "neighbour.h" static int babel_enable_if_lookup (const char *ifname); @@ -727,6 +728,51 @@ DEFUN (show_babel_interface, return CMD_SUCCESS; } +static void +show_babel_neighbour_sub (struct vty *vty, struct neighbour *neigh) +{ + vty_out (vty, + "Neighbour %s dev %s reach %04x rxcost %d txcost %d %s.%s", + format_address(neigh->address), + neigh->ifp->name, + neigh->reach, + neighbour_rxcost(neigh), + neigh->txcost, + if_up(neigh->ifp) ? "" : " (down)", + VTY_NEWLINE); +} + +DEFUN (show_babel_neighbour, + show_babel_neighbour_cmd, + "show babel neighbour [INTERFACE]", + SHOW_STR + IP_STR + "Babel information\n" + "Print neighbours\n" + "Interface name\n") +{ + struct neighbour *neigh; + struct interface *ifp; + + if (argc == 0) { + FOR_ALL_NEIGHBOURS(neigh) { + show_babel_neighbour_sub(vty, neigh); + } + return CMD_SUCCESS; + } + if ((ifp = if_lookup_by_name (argv[0])) == NULL) + { + vty_out (vty, "No such interface name%s", VTY_NEWLINE); + return CMD_WARNING; + } + FOR_ALL_NEIGHBOURS(neigh) { + if(ifp->ifindex == neigh->ifp->ifindex) { + show_babel_neighbour_sub(vty, neigh); + } + } + return CMD_SUCCESS; +} + void babel_if_init () { @@ -758,6 +804,8 @@ babel_if_init () /* "show babel ..." commands */ install_element (VIEW_NODE, &show_babel_interface_cmd); install_element (ENABLE_NODE, &show_babel_interface_cmd); + install_element(VIEW_NODE, &show_babel_neighbour_cmd); + install_element(ENABLE_NODE, &show_babel_neighbour_cmd); } /* hooks: functions called respectively when struct interface is -- cgit v1.2.1 From 1f39f466e439f217dcbae741ddc23a5340a05ec9 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 20:01:31 +0100 Subject: babeld: add command: "show_babel_database". --- babeld/babel_interface.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ babeld/route.h | 5 +++++ 2 files changed, 63 insertions(+) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index bd32d263..d4c84b35 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -52,6 +52,8 @@ THE SOFTWARE. #include "route.h" #include "babel_zebra.h" #include "neighbour.h" +#include "route.h" +#include "xroute.h" static int babel_enable_if_lookup (const char *ifname); @@ -773,6 +775,60 @@ DEFUN (show_babel_neighbour, return CMD_SUCCESS; } +static void +show_babel_routes_sub (struct vty *vty, struct babel_route *route) +{ + const unsigned char *nexthop = + memcmp(route->nexthop, route->neigh->address, 16) == 0 ? + NULL : route->nexthop; + + vty_out(vty, + "%s metric %d refmetric %d id %s seqno %d age %d " + "via %s neigh %s%s%s%s%s", + format_prefix(route->src->prefix, route->src->plen), + route_metric(route), route->refmetric, + format_eui64(route->src->id), + (int)route->seqno, + (int)(babel_now.tv_sec - route->time), + route->neigh->ifp->name, + format_address(route->neigh->address), + nexthop ? " nexthop " : "", + nexthop ? format_address(nexthop) : "", + route->installed ? " (installed)" : + route_feasible(route) ? " (feasible)" : "", + VTY_NEWLINE); +} + +static void +show_babel_xroutes_sub (struct vty *vty, struct xroute *xroute) +{ + vty_out(vty, "%s metric %d (exported)%s", + format_prefix(xroutes->prefix, xroute->plen), + xroutes->metric, + VTY_NEWLINE); +} + +DEFUN (show_babel_database, + show_babel_database_cmd, + "show babel database", + SHOW_STR + IP_STR + "Babel information\n" + "Database information\n" + "No attributes\n") +{ + int i; + + for(i = 0; i < numroutes; i++) { + show_babel_routes_sub(vty, &routes[i]); + } + for(i = 0; i < numxroutes; i++) { + show_babel_xroutes_sub(vty, &xroutes[i]); + } + + return CMD_SUCCESS; +} + void babel_if_init () { @@ -806,6 +862,8 @@ babel_if_init () install_element (ENABLE_NODE, &show_babel_interface_cmd); install_element(VIEW_NODE, &show_babel_neighbour_cmd); install_element(ENABLE_NODE, &show_babel_neighbour_cmd); + install_element(VIEW_NODE, &show_babel_database_cmd); + install_element(ENABLE_NODE, &show_babel_database_cmd); } /* hooks: functions called respectively when struct interface is diff --git a/babeld/route.h b/babeld/route.h index e38f1577..c08332a6 100644 --- a/babeld/route.h +++ b/babeld/route.h @@ -37,6 +37,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef BABEL_ROUTE_H +#define BABEL_ROUTE_H + #include "babel_interface.h" #include "source.h" @@ -102,3 +105,5 @@ void expire_routes(void); void babel_uninstall_all_routes(void); struct babel_route *babel_route_get_by_source(struct source *src); + +#endif -- cgit v1.2.1 From d3351d1ebf99591cf436035bb148e4ae0b351ffc Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Thu, 19 Jan 2012 22:36:56 +0100 Subject: babeld: add command: "show_babel_running_config". --- babeld/babel_interface.c | 21 +++++++++++++++ babeld/babel_main.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ babeld/babel_main.h | 4 +++ babeld/babeld.c | 7 +++++ babeld/babeld.h | 2 ++ babeld/util.c | 4 +++ babeld/util.h | 1 + 7 files changed, 105 insertions(+) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index d4c84b35..3f580046 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -43,6 +43,7 @@ THE SOFTWARE. #include "command.h" #include "prefix.h" #include "vector.h" +#include "distribute.h" #include "babel_main.h" #include "util.h" @@ -829,6 +830,24 @@ DEFUN (show_babel_database, return CMD_SUCCESS; } +DEFUN (show_babel_running_config, + show_babel_running_config_cmd, + "show babel running-config", + SHOW_STR + IP_STR + "Babel information\n" + "Configuration information\n" + "No attributes\n") +{ + vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); + show_babel_main_configuration(vty); + show_babeld_configuration(vty); + vty_out(vty, " -- ditribution lists --%s", VTY_NEWLINE); + config_show_distribute(vty); + + return CMD_SUCCESS; +} + void babel_if_init () { @@ -864,6 +883,8 @@ babel_if_init () install_element(ENABLE_NODE, &show_babel_neighbour_cmd); install_element(VIEW_NODE, &show_babel_database_cmd); install_element(ENABLE_NODE, &show_babel_database_cmd); + install_element(VIEW_NODE, &show_babel_running_config_cmd); + install_element(ENABLE_NODE, &show_babel_running_config_cmd); } /* hooks: functions called respectively when struct interface is diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 2ae8b917..0a958e60 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -527,3 +527,69 @@ babel_save_state_file(void) close(fd); } } + +void +show_babel_main_configuration (struct vty *vty) +{ +#ifdef NO_DEBUG + vty_out(vty, "No debug.%s", VTY_NEWLINE); +#else + vty_out(vty, "Activated debug options:"); + if (debug == BABEL_DEBUG_ALL) { + vty_out(vty, " all%s", VTY_NEWLINE); + } else { + vty_out(vty, "%s%s%s%s%s%s%s%s%s%s%s%s%s", + debug & BABEL_DEBUG_COMMON ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_COMMON ? " common" : "", + debug & BABEL_DEBUG_KERNEL ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_KERNEL ? " kernel" : "", + debug & BABEL_DEBUG_FILTER ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_FILTER ? " filter" : "", + debug & BABEL_DEBUG_TIMEOUT ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_TIMEOUT ? " timeout" : "", + debug & BABEL_DEBUG_IF ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_IF ? " interface": "", + debug & BABEL_DEBUG_ROUTE ? VTY_NEWLINE : "", + debug & BABEL_DEBUG_ROUTE ? " route" : "", + VTY_NEWLINE); + } +#endif + + vty_out(vty, + "pid file = %s%s" + "state file = %s%s" + "configuration file = %s%s" + "protocol informations:%s" + " multicast address = %s%s" + " port = %d%s" + "vty address = %s%s" + "vty port = %d%s" + "id = %s%s" + "idle time = %d%s" + "wireless hello interval = %d%s" + "wired hello interval = %d%s" + "idle hello interval = %d%s" + "parasitic = %s%s" + "split-horizon = %s%s" + "allow_duplicates = %s%s" + "kernel_metric = %d%s", + pidfile, VTY_NEWLINE, + state_file, VTY_NEWLINE, + babel_config_file ? babel_config_file : babel_config_default, + VTY_NEWLINE, + VTY_NEWLINE, + format_address(protocol_group), VTY_NEWLINE, + protocol_port, VTY_NEWLINE, + babel_vty_addr ? babel_vty_addr : "None", + VTY_NEWLINE, + babel_vty_port, VTY_NEWLINE, + format_eui64(myid), VTY_NEWLINE, + idle_time, VTY_NEWLINE, + wireless_hello_interval, VTY_NEWLINE, + wired_hello_interval, VTY_NEWLINE, + idle_hello_interval, VTY_NEWLINE, + format_bool(parasitic), VTY_NEWLINE, + format_bool(split_horizon), VTY_NEWLINE, + format_bool(allow_duplicates), VTY_NEWLINE, + kernel_metric, VTY_NEWLINE); +} diff --git a/babeld/babel_main.h b/babeld/babel_main.h index 2bacfabf..a21a5274 100644 --- a/babeld/babel_main.h +++ b/babeld/babel_main.h @@ -36,6 +36,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "vty.h" + extern struct timeval babel_now; /* current time */ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; @@ -52,3 +54,5 @@ extern unsigned char protocol_group[16]; extern int protocol_socket; extern int kernel_socket; extern int max_request_hopcount; + +void show_babel_main_configuration (struct vty *vty); diff --git a/babeld/babeld.c b/babeld/babeld.c index 3dc35b5d..9f2ab5d9 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -764,3 +764,10 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen, return babel_filter_redistribute(&p, NULL); } + +void +show_babeld_configuration (struct vty *vty) +{ + vty_out(vty, "babeld running process %s.%s", + babel_routing_process ? "enable" : "disable", VTY_NEWLINE); +} diff --git a/babeld/babeld.h b/babeld/babeld.h index 87b4de7b..29bc5e8f 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -41,6 +41,7 @@ THE SOFTWARE. #define BABEL_BABELD_H #include +#include "vty.h" #define INFINITY ((unsigned short)(~0)) @@ -131,6 +132,7 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto); extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); +extern void show_babeld_configuration (struct vty *vty); #endif /* BABEL_BABELD_H */ diff --git a/babeld/util.c b/babeld/util.c index f1ac0f15..514e0ff3 100644 --- a/babeld/util.c +++ b/babeld/util.c @@ -298,6 +298,10 @@ format_eui64(const unsigned char *eui) return buf[i]; } +const char *format_bool(const int b) { + return b ? "true" : "false"; +} + int parse_address(const char *address, unsigned char *addr_r, int *af_r) { diff --git a/babeld/util.h b/babeld/util.h index 4e7635f6..d64169b0 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -111,6 +111,7 @@ unsigned char *mask_prefix(unsigned char *restrict ret, const char *format_address(const unsigned char *address); const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_eui64(const unsigned char *eui); +const char *format_bool(const int b); int parse_address(const char *address, unsigned char *addr_r, int *af_r); int parse_net(const char *ifp, unsigned char *prefix_r, unsigned char *plen_r, int *af_r); -- cgit v1.2.1 From 3cb4134bcfb2b9f7aa885a39cc0efc3b18125490 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 20:20:59 +0100 Subject: babeld: use zlog_debug instead of do_debugf, for debugf. --- babeld/util.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/util.h b/babeld/util.h index d64169b0..376b967f 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -154,12 +154,12 @@ static inline void debugf(int level, const char *format, ...) { return; } #if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L #define debugf(level, ...) \ do { \ -if(UNLIKELY(debug & level)) do_debugf(__VA_ARGS__); \ +if(UNLIKELY(debug & level)) zlog_debug(__VA_ARGS__); \ } while(0) #elif defined __GNUC__ #define debugf(level, _args...) \ do { \ -if(UNLIKELY(debug & level)) do_debugf(_args); \ +if(UNLIKELY(debug & level)) zlog_debug(_args); \ } while(0) #else static inline void debugf(int level, const char *format, ...) { return; } -- cgit v1.2.1 From 72db20bf8f6af1fd70ae42f287360cad835f042b Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 22:06:10 +0100 Subject: babeld: place the babel-state file in the quagga vars directory. --- babeld/babel_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 0a958e60..b7fffc1f 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -93,7 +93,7 @@ const unsigned char ones[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; -static const char *state_file = "/var/lib/babeld/babel-state"; +static const char *state_file = DAEMON_VTY_DIR "/babel-state"; unsigned char protocol_group[16]; /* babel's link-local multicast address */ int protocol_port; /* babel's port */ -- cgit v1.2.1 From 3f031ed536cf96d44015cf49d1f734d15d194f0a Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 18 Jan 2012 23:03:00 +0100 Subject: babeld: fix commands informations messages. --- babeld/babel_interface.c | 12 ++++++------ babeld/babeld.c | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 3f580046..e403cce0 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -368,8 +368,8 @@ DEFUN (babel_split_horizon, babel_split_horizon_cmd, "babel split-horizon", IPV6_STR - "Routing Information Protocol\n" - "Perform split horizon\n") + "Perform split horizon\n" + "No attributes\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -388,8 +388,8 @@ DEFUN (no_babel_split_horizon, "no babel split-horizon", NO_STR IPV6_STR - "Routing Information Protocol\n" - "Perform split horizon\n") + "Disable split horizon\n" + "No attributes\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -427,7 +427,7 @@ DEFUN (babel_passive_interface, babel_passive_interface_cmd, "passive-interface", "The daemon will only announce redistributed routes\n" - "Interface name\n") + "No attributes\n") { if (allow_duplicates) { return CMD_WARNING; @@ -442,7 +442,7 @@ DEFUN (no_babel_passive_interface, "no passive-interface", NO_STR "The daemon will announce all (filtred) routes\n" - "Interface name\n") + "No attributes\n") { parasitic = 0; return CMD_SUCCESS; diff --git a/babeld/babeld.c b/babeld/babeld.c index 9f2ab5d9..6487bbe1 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -593,7 +593,8 @@ DEFUN (router_babel, router_babel_cmd, "router babel", "Enable a routing process\n" - "Make Babel instance command\n") + "Make Babel instance command\n" + "No attributes\n") { int ret; @@ -617,7 +618,8 @@ DEFUN (no_router_babel, "no router babel", NO_STR "Disable a routing process\n" - "Remove Babel instance command\n") + "Remove Babel instance command\n" + "No attributes\n") { if(babel_routing_process) babel_clean_routing_process(); -- cgit v1.2.1 From b5d43c939476b49106b1ab80b61609aba43c915d Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Thu, 19 Jan 2012 22:38:56 +0100 Subject: babeld: remove useless variable, make local another. --- babeld/babel_main.c | 3 +-- babeld/babel_main.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index b7fffc1f..159ba656 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -80,9 +80,7 @@ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ int debug = BABEL_DEBUG_COMMON; -time_t reboot_time; int idle_time = 320; -int link_detect = 0; int wireless_hello_interval = -1; int wired_hello_interval = -1; int idle_hello_interval = -1; @@ -385,6 +383,7 @@ babel_replace_by_null(int fd) static void babel_load_state_file(void) { + time_t reboot_time; reboot_time = babel_now.tv_sec; int fd; int rc; diff --git a/babeld/babel_main.h b/babeld/babel_main.h index a21a5274..fb22c58e 100644 --- a/babeld/babel_main.h +++ b/babeld/babel_main.h @@ -43,7 +43,6 @@ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; extern int wireless_hello_interval, wired_hello_interval, idle_hello_interval; extern int idle_time; -extern int link_detect; extern unsigned char myid[8]; -- cgit v1.2.1 From f1305cbfbed050ed4f389fa282bef49917ffd638 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Fri, 20 Jan 2012 00:19:35 +0100 Subject: babeld: add command (config) to set debug flags. --- babeld/babel_zebra.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'babeld') diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 7ba1adfe..e68c2b70 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -46,6 +46,7 @@ THE SOFTWARE. #include "babel_zebra.h" #include "babel_interface.h" #include "xroute.h" +#include "util.h" void babelz_zebra_init(void); @@ -67,6 +68,22 @@ static struct { {0, 0, NULL} }; +/* Debug types */ +static struct { + int type; + int str_min_len; + const char *str; +} debug_type[] = { + {BABEL_DEBUG_COMMON, 1, "common"}, + {BABEL_DEBUG_KERNEL, 1, "kernel"}, + {BABEL_DEBUG_FILTER, 1, "filter"}, + {BABEL_DEBUG_TIMEOUT, 1, "timeout"}, + {BABEL_DEBUG_IF, 1, "interface"}, + {BABEL_DEBUG_ROUTE, 1, "route"}, + {BABEL_DEBUG_ALL, 1, "all"}, + {0, 0, NULL} +}; + /* Zebra node structure. */ struct cmd_node zebra_node = { @@ -252,6 +269,64 @@ DEFUN (no_babel_redistribute_type, return CMD_WARNING; } +#ifndef NO_DEBUG +/* [Babel Command] */ +DEFUN (babel_debug, + babel_debug_cmd, + "debug (common|kernel|filter|timeout|interface|route|all)", + "Enable debug messages for specific or all part.\n" + "Common messages (default)\n" + "Kernel messages\n" + "Filter messages\n" + "Timeout messages\n" + "Interface messages\n" + "Route messages\n" + "All messages\n") +{ + int i; + + for(i = 0; debug_type[i].str != NULL; i++) { + if (strncmp (debug_type[i].str, argv[0], + debug_type[i].str_min_len) == 0) { + debug |= debug_type[i].type; + return CMD_SUCCESS; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + + return CMD_WARNING; +} + +/* [Babel Command] */ +DEFUN (no_babel_debug, + no_babel_debug_cmd, + "no debug (common|kernel|filter|timeout|interface|route|all)", + NO_STR + "Disable debug messages for specific or all part.\n" + "Common messages (default)\n" + "Kernel messages\n" + "Filter messages\n" + "Timeout messages\n" + "Interface messages\n" + "Route messages\n" + "All messages\n") +{ + int i; + + for (i = 0; debug_type[i].str; i++) { + if (strncmp(debug_type[i].str, argv[0], + debug_type[i].str_min_len) == 0) { + debug &= ~debug_type[i].type; + } + } + + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + + return CMD_WARNING; +} +#endif /* NO_DEBUG */ + void babelz_zebra_init(void) { @@ -272,6 +347,8 @@ void babelz_zebra_init(void) install_node (&zebra_node, zebra_config_write); install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); + install_element(BABEL_NODE, &babel_debug_cmd); + install_element(BABEL_NODE, &no_babel_debug_cmd); } static int -- cgit v1.2.1 From 6dfeb3f6cfaf89ce0e11421b48feb2965a43ffd6 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Fri, 20 Jan 2012 17:53:57 +0100 Subject: babeld: fix bug due to v4mapped addresses. --- babeld/babeld.c | 6 +++--- babeld/xroute.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'babeld') diff --git a/babeld/babeld.c b/babeld/babeld.c index 6487bbe1..0cf8c8a1 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -708,7 +708,7 @@ input_filter(const unsigned char *id, struct interface *ifp = NULL; struct prefix p; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = plen; + p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) { uchar_to_inaddr(&p.u.prefix4, prefix); } else { @@ -730,7 +730,7 @@ output_filter(const unsigned char *id, const unsigned char *prefix, struct interface *ifp = NULL; struct prefix p; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = plen; + p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) { uchar_to_inaddr(&p.u.prefix4, prefix); } else { @@ -752,7 +752,7 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen, struct interface *ifp = NULL; struct prefix p; p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = plen; + p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; if (p.family == AF_INET) { uchar_to_inaddr(&p.u.prefix4, prefix); } else { diff --git a/babeld/xroute.c b/babeld/xroute.c index eb4aaeb5..8330b492 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -63,8 +63,8 @@ babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, inaddr_to_uchar(uchar_prefix, &prefix->prefix); debugf(BABEL_DEBUG_ROUTE, "Adding new ipv4 route comming from Zebra."); - xroute_add_new_route(uchar_prefix, prefix->prefixlen, api->metric, ifindex, - 0, 1); + xroute_add_new_route(uchar_prefix, prefix->prefixlen + 96, + api->metric, ifindex, 0, 1); return 0; } @@ -77,7 +77,7 @@ babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, struct xroute *xroute = NULL; inaddr_to_uchar(uchar_prefix, &prefix->prefix); - xroute = find_xroute(uchar_prefix, prefix->prefixlen); + xroute = find_xroute(uchar_prefix, prefix->prefixlen + 96); if (xroute != NULL) { debugf(BABEL_DEBUG_ROUTE, "Removing ipv4 route (from zebra)."); flush_xroute(xroute); -- cgit v1.2.1 From ec8d8d5ba648302cf9405f1346e3760d9b9d061c Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Fri, 20 Jan 2012 15:32:16 +0100 Subject: babeld: change the modify route system. Zebra doesn't set errno to EEXIST if we add a route who was already in the kernel, so we always returned after just doing "add; delete". This patch fix the problem by doing "delete; add" always. --- babeld/kernel_zebra.c | 49 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 35 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 82f03e43..7ddc797d 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -142,26 +142,7 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; - /* It is better to add the new route before removing the old - one, to avoid losing packets. However, if the old and new - priorities are equal, this only works if the kernel supports - ECMP. So we first try the "right" order, and fall back on - the "wrong" order if it fails with EEXIST. */ - rc = ipv4 ? - kernel_route_add_v4(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0): - kernel_route_add_v6(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0); - if(rc < 0) { - if(errno != EEXIST) - return rc; - added = 0; - } else { - added = 1; - } - + debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); if (ipv4) { kernel_route_delete_v4(pref, plen, gate, ifindex, metric, @@ -172,21 +153,19 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, NULL, 0, 0); } - if(!added) { - rc = ipv4 ? - kernel_route_add_v4(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0): - kernel_route_add_v6(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0); - if(rc < 0) { - if(errno == EEXIST) - rc = 1; - /* In principle, we should try to re-install the flushed - route on failure to preserve. However, this should - hopefully not matter much in practice. */ - } + rc = ipv4 ? + kernel_route_add_v4(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0): + kernel_route_add_v6(pref, plen, + newgate, newifindex, newmetric, + NULL, 0, 0); + if(rc < 0) { + if(errno == EEXIST) + rc = 1; + /* In principle, we should try to re-install the flushed + route on failure to preserve. However, this should + hopefully not matter much in practice. */ } return rc; -- cgit v1.2.1 From a19a3bf94740aebff6fdfc76f3d4b17c0013fae4 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 21 Jan 2012 23:16:00 +0400 Subject: babeld: add MP-specific zclient API fix Add proper initialization of SAFI field, which is present in the revisions of zapi_ipv4 and zapi_ipv6 structures specific to MP-BGP patchset. Without this change no Babel routes could make into zebra RIB. --- babeld/kernel_zebra.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 7ddc797d..53da5f40 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -206,6 +206,7 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; @@ -248,6 +249,7 @@ kernel_route_add_v6(const unsigned char *pref, unsigned short plen, api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; @@ -291,6 +293,7 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; @@ -334,6 +337,7 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, api.type = ZEBRA_ROUTE_BABEL; api.flags = 0; api.message = 0; + api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; -- cgit v1.2.1 From 16e51b246be6b18641327685f44bd4f5f6649367 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Mon, 23 Jan 2012 00:22:14 +0100 Subject: babeld: remove unused variable. --- babeld/kernel_zebra.c | 1 - 1 file changed, 1 deletion(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 53da5f40..d556a605 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -105,7 +105,6 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, unsigned int newmetric) { int rc; - int added; int ipv4; /* Check that the protocol family is consistent. */ -- cgit v1.2.1 From c35fafdf887aa32c5be6ad738d3a3b0140cea6e8 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Mon, 23 Jan 2012 23:46:32 +0100 Subject: babeld: babelz merge. Babelz is the last version of the stand-alone babel daemon. In particular, it use multiple channels to diminuate interferences. Please refer to this one for more details. --- babeld/babel_interface.c | 72 ++++-- babeld/babel_interface.h | 19 +- babeld/babel_main.c | 2 +- babeld/babeld.c | 2 +- babeld/message.c | 202 ++++++++++++++--- babeld/neighbour.c | 5 +- babeld/net.c | 10 + babeld/route.c | 574 ++++++++++++++++++++++++++++++++++------------- babeld/route.h | 50 ++++- babeld/source.c | 59 +++-- babeld/source.h | 7 +- babeld/util.c | 68 ------ babeld/util.h | 4 - babeld/xroute.c | 27 ++- babeld/xroute.h | 8 +- 15 files changed, 792 insertions(+), 317 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index e403cce0..1c8c8868 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -456,6 +456,30 @@ interface_idle(babel_interface_nfo *babel_ifp) babel_ifp->activity_time < babel_now.tv_sec - idle_time); } +int +update_hello_interval(struct interface *ifp) +{ + int rc = 0; + unsigned short interval; + struct babel_interface *babel_ifp = babel_get_if_nfo(ifp); + + if(interface_idle(babel_ifp)) + interval = idle_hello_interval; + else if(IF_CONF(ifp, hello_interval) > 0) + interval = IF_CONF(ifp, hello_interval); + else if((ifp->flags & BABEL_IF_WIRED)) + interval = wired_hello_interval; + else + interval = wireless_hello_interval; + + if(babel_ifp->hello_interval != interval) { + babel_ifp->hello_interval = interval; + rc = 1; + } + + return rc; +} + /* This should be no more than half the hello interval, so that hellos aren't sent late. The result is in milliseconds. */ unsigned @@ -560,10 +584,11 @@ interface_recalculate(struct interface *ifp) update_interface_metric(ifp); debugf(BABEL_DEBUG_COMMON, - "Upped network %s (%s, cost=%d%s).", + "Upped interface %s (%s, cost=%d, channel=%d%s).", ifp->name, (babel_ifp->flags & BABEL_IF_WIRED) ? "wired" : "wireless", babel_ifp->cost, + babel_ifp->channel, babel_ifp->ipv4 ? ", IPv4" : ""); if(rc > 0) @@ -777,19 +802,41 @@ DEFUN (show_babel_neighbour, } static void -show_babel_routes_sub (struct vty *vty, struct babel_route *route) +show_babel_routes_sub (struct babel_route *route, void *closure) { + struct vty *vty = (struct vty*) closure; const unsigned char *nexthop = memcmp(route->nexthop, route->neigh->address, 16) == 0 ? NULL : route->nexthop; + char channels[100]; + + if(route->channels[0] == 0) + channels[0] = '\0'; + else { + int k, j = 0; + snprintf(channels, 100, " chan ("); + j = strlen(channels); + for(k = 0; k < DIVERSITY_HOPS; k++) { + if(route->channels[k] == 0) + break; + if(k > 0) + channels[j++] = ','; + snprintf(channels + j, 100 - j, "%d", route->channels[k]); + j = strlen(channels); + } + snprintf(channels + j, 100 - j, ")"); + if(k == 0) + channels[0] = '\0'; + } vty_out(vty, - "%s metric %d refmetric %d id %s seqno %d age %d " + "%s metric %d refmetric %d id %s seqno %d%s age %d " "via %s neigh %s%s%s%s%s", format_prefix(route->src->prefix, route->src->plen), route_metric(route), route->refmetric, format_eui64(route->src->id), (int)route->seqno, + channels, (int)(babel_now.tv_sec - route->time), route->neigh->ifp->name, format_address(route->neigh->address), @@ -801,11 +848,12 @@ show_babel_routes_sub (struct vty *vty, struct babel_route *route) } static void -show_babel_xroutes_sub (struct vty *vty, struct xroute *xroute) +show_babel_xroutes_sub (struct xroute *xroute, void *closure) { + struct vty *vty = (struct vty *) closure; vty_out(vty, "%s metric %d (exported)%s", - format_prefix(xroutes->prefix, xroute->plen), - xroutes->metric, + format_prefix(xroute->prefix, xroute->plen), + xroute->metric, VTY_NEWLINE); } @@ -818,15 +866,8 @@ DEFUN (show_babel_database, "Database information\n" "No attributes\n") { - int i; - - for(i = 0; i < numroutes; i++) { - show_babel_routes_sub(vty, &routes[i]); - } - for(i = 0; i < numxroutes; i++) { - show_babel_xroutes_sub(vty, &xroutes[i]); - } - + for_all_routes(show_babel_routes_sub, vty); + for_all_xroutes(show_babel_xroutes_sub, vty); return CMD_SUCCESS; } @@ -950,6 +991,7 @@ babel_interface_allocate (void) babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (random() & 0xFFFF); babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL; + babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; return babel_ifp; } diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index d9fb9a4a..5b551fbe 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -42,10 +42,15 @@ THE SOFTWARE. #include #include "zclient.h" +#define CONFIG_DEFAULT 0 +#define CONFIG_NO 1 +#define CONFIG_YES 2 + /* babeld interface informations */ struct babel_interface { unsigned short flags; /* see below */ unsigned short cost; + int channel; struct timeval hello_timeout; struct timeval update_timeout; struct timeval flush_timeout; @@ -67,6 +72,7 @@ struct babel_interface { time_t bucket_time; unsigned int bucket; time_t activity_time; + time_t last_update_time; unsigned short hello_seqno; unsigned hello_interval; unsigned update_interval; @@ -85,12 +91,20 @@ static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) return ((babel_interface_nfo*) ifp->info); } +#define IF_CONF(_ifp, _field) babel_get_if_nfo(_ifp)->_field + /* babel_interface_nfo flags */ +#define BABEL_IF_IS_UP (1 << 0) #define BABEL_IF_WIRED (1 << 1) #define BABEL_IF_SPLIT_HORIZON (1 << 2) #define BABEL_IF_LQ (1 << 3) -#define BABEL_IF_IS_ENABLE (1 << 4) -#define BABEL_IF_IS_UP (1 << 5) +#define BABEL_IF_FARAWAY (1 << 4) +#define BABEL_IF_IS_ENABLE (1 << 7) + +/* Only INTERFERING can appear on the wire. */ +#define BABEL_IF_CHANNEL_UNKNOWN 0 +#define BABEL_IF_CHANNEL_INTERFERING 255 +#define BABEL_IF_CHANNEL_NONINTERFERING -2 static inline int if_up(struct interface *ifp) @@ -133,6 +147,7 @@ int babel_interface_address_delete (int, struct zclient *, zebra_size_t); /* others functions */ int interface_idle(babel_interface_nfo *); +int update_hello_interval(struct interface *ifp); unsigned jitter(babel_interface_nfo *, int); unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); /* return "true" if "address" is one of our ipv6 addresses */ diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 159ba656..4d6f60eb 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -482,7 +482,7 @@ babel_exit_properly(void) /* Uninstall and flush all routes. */ debugf(BABEL_DEBUG_COMMON, "Uninstall routes."); - babel_uninstall_all_routes(); + flush_all_routes(); babel_interface_close_all(); babel_zebra_close_connexion(); babel_save_state_file(); diff --git a/babeld/babeld.c b/babeld/babeld.c index 0cf8c8a1..d69662c0 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -269,7 +269,7 @@ babel_initial_noise(void) static void babel_clean_routing_process() { - babel_uninstall_all_routes(); + flush_all_routes(); babel_interface_close_all(); /* cancel threads */ diff --git a/babeld/message.c b/babeld/message.c index 92c416b9..8cd1db63 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -69,6 +69,8 @@ struct timeval unicast_flush_timeout = {0, 0}; static const unsigned char v4prefix[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }; +/* Parse a network prefix, encoded in the somewhat baroque compressed + representation used by Babel. Return the number of bytes parsed. */ static int network_prefix(int ae, int plen, unsigned int omitted, const unsigned char *p, const unsigned char *dp, @@ -76,6 +78,7 @@ network_prefix(int ae, int plen, unsigned int omitted, { unsigned pb; unsigned char prefix[16]; + int ret = -1; if(plen >= 0) pb = (plen + 7) / 8; @@ -90,7 +93,9 @@ network_prefix(int ae, int plen, unsigned int omitted, memset(prefix, 0, 16); switch(ae) { - case 0: break; + case 0: + ret = 0; + break; case 1: if(omitted > 4 || pb > 4 || (pb > omitted && len < pb - omitted)) return -1; @@ -100,6 +105,7 @@ network_prefix(int ae, int plen, unsigned int omitted, memcpy(prefix, dp, 12 + omitted); } if(pb > omitted) memcpy(prefix + 12 + omitted, p, pb - omitted); + ret = pb - omitted; break; case 2: if(omitted > 16 || (pb > omitted && len < pb - omitted)) return -1; @@ -108,19 +114,68 @@ network_prefix(int ae, int plen, unsigned int omitted, memcpy(prefix, dp, omitted); } if(pb > omitted) memcpy(prefix + omitted, p, pb - omitted); + ret = pb - omitted; break; case 3: if(pb > 8 && len < pb - 8) return -1; prefix[0] = 0xfe; prefix[1] = 0x80; if(pb > 8) memcpy(prefix + 8, p, pb - 8); + ret = pb - 8; break; default: return -1; } mask_prefix(p_r, prefix, plen < 0 ? 128 : ae == 1 ? plen + 96 : plen); - return 1; + return ret; +} + +static void +parse_route_attributes(const unsigned char *a, int alen, + unsigned char *channels) +{ + int type, len, i = 0; + + while(i < alen) { + type = a[i]; + if(type == 0) { + i++; + continue; + } + + if(i + 1 > alen) { + fprintf(stderr, "Received truncated attributes.\n"); + return; + } + len = a[i + 1]; + if(i + len > alen) { + fprintf(stderr, "Received truncated attributes.\n"); + return; + } + + if(type == 1) { + /* Nothing. */ + } else if(type == 2) { + if(len > DIVERSITY_HOPS) { + fprintf(stderr, + "Received overlong channel information (%d > %d).\n", + len, DIVERSITY_HOPS); + len = DIVERSITY_HOPS; + } + if(memchr(a + i + 2, 0, len) != NULL) { + /* 0 is reserved. */ + fprintf(stderr, "Channel information contains 0!"); + return; + } + memset(channels, 0, DIVERSITY_HOPS); + memcpy(channels, a + i + 2, len); + } else { + fprintf(stderr, "Received unknown route attribute %d.\n", type); + } + + i += len + 2; + } } static int @@ -130,6 +185,13 @@ network_address(int ae, const unsigned char *a, unsigned int len, return network_prefix(ae, -1, 0, a, NULL, len, a_r); } +static int +channels_len(unsigned char *channels) +{ + unsigned char *p = memchr(channels, 0, DIVERSITY_HOPS); + return p ? (p - channels) : DIVERSITY_HOPS; +} + void parse_packet(const unsigned char *from, struct interface *ifp, const unsigned char *packet, int packetlen) @@ -284,8 +346,9 @@ parse_packet(const unsigned char *from, struct interface *ifp, } else if(type == MESSAGE_UPDATE) { unsigned char prefix[16], *nh; unsigned char plen; + unsigned char channels[DIVERSITY_HOPS]; unsigned short interval, seqno, metric; - int rc; + int rc, parsed_len; if(len < 10) { if(len < 2 || message[3] & 0x80) have_v4_prefix = have_v6_prefix = 0; @@ -307,6 +370,7 @@ parse_packet(const unsigned char *from, struct interface *ifp, have_v4_prefix = have_v6_prefix = 0; goto fail; } + parsed_len = 10 + rc; plen = message[4] + (message[2] == 1 ? 96 : 0); @@ -360,8 +424,27 @@ parse_packet(const unsigned char *from, struct interface *ifp, goto done; } + if((ifp->flags & BABEL_IF_FARAWAY)) { + channels[0] = 0; + } else { + /* This will be overwritten by parse_route_attributes below. */ + if(metric < 256) { + /* Assume non-interfering (wired) link. */ + channels[0] = 0; + } else { + /* Assume interfering. */ + channels[0] = BABEL_IF_CHANNEL_INTERFERING; + channels[1] = 0; + } + + if(parsed_len < len) + parse_route_attributes(message + 2 + parsed_len, + len - parsed_len, channels); + } + update_route(router_id, prefix, plen, seqno, metric, interval, - neigh, nh); + neigh, nh, + channels, channels_len(channels)); } else if(type == MESSAGE_REQUEST) { unsigned char prefix[16], plen; int rc; @@ -374,10 +457,17 @@ parse_packet(const unsigned char *from, struct interface *ifp, message[2] == 0 ? "any" : format_prefix(prefix, plen), format_address(from), ifp->name); if(message[2] == 0) { + struct babel_interface *babel_ifp =babel_get_if_nfo(neigh->ifp); /* If a neighbour is requesting a full route dump from us, we might as well send it an IHU. */ send_ihu(neigh, NULL); - send_update(neigh->ifp, 0, NULL, 0); + /* Since nodes send wildcard requests on boot, booting + a large number of nodes at the same time may cause an + update storm. Ignore a wildcard request that happens + shortly after we sent a full update. */ + if(babel_ifp->last_update_time < + babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1)) + send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); } @@ -665,10 +755,12 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) void send_hello(struct interface *ifp) { + int changed; + changed = update_hello_interval(ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(babel_ifp->hello_seqno % 3 == 0) + if(changed || babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); @@ -724,12 +816,19 @@ static void really_send_update(struct interface *ifp, const unsigned char *id, const unsigned char *prefix, unsigned char plen, - unsigned short seqno, unsigned short metric) + unsigned short seqno, unsigned short metric, + unsigned char *channels, int channels_len) { babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); int add_metric, v4, real_plen, omit = 0; const unsigned char *real_prefix; unsigned short flags = 0; + int channels_size; + + if(diversity_kind != DIVERSITY_CHANNEL) + channels_len = -1; + + channels_size = channels_len >= 0 ? channels_len + 2 : 0; if(!if_up(ifp)) return; @@ -786,7 +885,8 @@ really_send_update(struct interface *ifp, babel_ifp->have_buffered_id = 1; } - start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + start_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + channels_size); accumulate_byte(ifp, v4 ? 1 : 2); accumulate_byte(ifp, flags); accumulate_byte(ifp, real_plen); @@ -795,7 +895,14 @@ really_send_update(struct interface *ifp, accumulate_short(ifp, seqno); accumulate_short(ifp, metric); accumulate_bytes(ifp, real_prefix + omit, (real_plen + 7) / 8 - omit); - end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit); + /* Note that an empty channels TLV is different from no such TLV. */ + if(channels_len >= 0) { + accumulate_byte(ifp, 2); + accumulate_byte(ifp, channels_len); + accumulate_bytes(ifp, channels, channels_len); + } + end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit + + channels_size); if(flags & 0x80) { memcpy(babel_ifp->buffered_prefix, prefix, 16); @@ -884,9 +991,6 @@ flushupdates(struct interface *ifp) qsort(b, n, sizeof(struct buffered_update), compare_buffered_updates); for(i = 0; i < n; i++) { - unsigned short seqno; - unsigned short metric; - /* The same update may be scheduled multiple times before it is sent out. Since our buffer is now sorted, it is enough to compare with the previous update. */ @@ -903,22 +1007,51 @@ flushupdates(struct interface *ifp) if(xroute && (!route || xroute->metric <= kernel_metric)) { really_send_update(ifp, myid, xroute->prefix, xroute->plen, - myseqno, xroute->metric); + myseqno, xroute->metric, + NULL, 0); last_prefix = xroute->prefix; last_plen = xroute->plen; } else if(route) { + unsigned char channels[DIVERSITY_HOPS]; + int chlen; + struct interface *route_ifp = route->neigh->ifp; + struct babel_interface *babel_route_ifp = NULL; + unsigned short metric; + unsigned short seqno; + seqno = route->seqno; - metric = route_metric(route); + metric = + route_interferes(route, ifp) ? + route_metric(route) : + route_metric_noninterfering(route); + if(metric < INFINITY) satisfy_request(route->src->prefix, route->src->plen, seqno, route->src->id, ifp); if((babel_ifp->flags & BABEL_IF_SPLIT_HORIZON) && route->neigh->ifp == ifp) continue; + + babel_route_ifp = babel_get_if_nfo(route_ifp); + if(babel_route_ifp->channel ==BABEL_IF_CHANNEL_NONINTERFERING) { + memcpy(channels, route->channels, DIVERSITY_HOPS); + } else { + if(babel_route_ifp->channel == BABEL_IF_CHANNEL_UNKNOWN) + channels[0] = BABEL_IF_CHANNEL_INTERFERING; + else { + assert(babel_route_ifp->channel > 0 && + babel_route_ifp->channel <= 255); + channels[0] = babel_route_ifp->channel; + } + memcpy(channels + 1, route->channels, DIVERSITY_HOPS - 1); + } + + chlen = channels_len(channels); really_send_update(ifp, route->src->id, route->src->prefix, route->src->plen, - seqno, metric); + seqno, metric, + channels, chlen); update_source(route->src, seqno, metric); last_prefix = route->src->prefix; last_plen = route->src->plen; @@ -926,7 +1059,7 @@ flushupdates(struct interface *ifp) /* There's no route for this prefix. This can happen shortly after an xroute has been retracted, so send a retraction. */ really_send_update(ifp, myid, b[i].prefix, b[i].plen, - myseqno, INFINITY); + myseqno, INFINITY, NULL, -1); } } schedule_flush_now(ifp); @@ -961,12 +1094,17 @@ buffer_update(struct interface *ifp, if(babel_ifp->update_bufsize == 0) { int n; assert(babel_ifp->buffered_updates == NULL); - n = MAX(babel_ifp->bufsize / 16, 4); + /* Allocate enough space to hold a full update. Since the + number of installed routes will grow over time, make sure we + have enough space to send a full-ish frame. */ + n = installed_routes_estimate() + xroutes_estimate() + 4; + n = MAX(n, babel_ifp->bufsize / 16); again: babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update)); if(babel_ifp->buffered_updates == NULL) { zlog_err("malloc(buffered_updates): %s", safe_strerror(errno)); if(n > 4) { + /* Try again with a tiny buffer. */ n = 4; goto again; } @@ -982,12 +1120,18 @@ buffer_update(struct interface *ifp, babel_ifp->num_buffered_updates++; } +static void +buffer_update_callback(struct babel_route *route, void *closure) +{ + buffer_update((struct interface*)closure, + route->src->prefix, route->src->plen); +} + void send_update(struct interface *ifp, int urgent, const unsigned char *prefix, unsigned char plen) { babel_interface_nfo *babel_ifp = NULL; - int i; if(ifp == NULL) { struct interface *ifp_aux; @@ -1020,15 +1164,13 @@ send_update(struct interface *ifp, int urgent, if(!interface_idle(babel_ifp)) { send_self_update(ifp); if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); - for(i = 0; i < numroutes; i++) - if(routes[i].installed) - buffer_update(ifp, - routes[i].src->prefix, - routes[i].src->plen); + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", + ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); } } set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); + babel_ifp->last_update_time = babel_now.tv_sec; } schedule_update_flush(ifp, urgent); } @@ -1086,11 +1228,16 @@ update_myseqno() seqno_time = babel_now; } +static void +send_xroute_update_callback(struct xroute *xroute, void *closure) +{ + struct interface *ifp = (struct interface*)closure; + send_update(ifp, 0, xroute->prefix, xroute->plen); +} + void send_self_update(struct interface *ifp) { - int i; - if(ifp == NULL) { struct interface *ifp_aux; struct listnode *linklist_node = NULL; @@ -1104,8 +1251,7 @@ send_self_update(struct interface *ifp) if(!interface_idle(babel_get_if_nfo(ifp))) { debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); - for(i = 0; i < numxroutes; i++) - send_update(ifp, 0, xroutes[i].prefix, xroutes[i].plen); + for_all_xroutes(send_xroute_update_callback, ifp); } } diff --git a/babeld/neighbour.c b/babeld/neighbour.c index f360b891..5a327dfe 100644 --- a/babeld/neighbour.c +++ b/babeld/neighbour.c @@ -122,7 +122,8 @@ find_neighbour(const unsigned char *address, struct interface *ifp) return neigh; } -/* Recompute a neighbour's rxcost. Return true if anything changed. */ +/* Recompute a neighbour's rxcost. Return true if anything changed. + This does not call local_notify_neighbour, see update_neighbour_metric. */ int update_neighbour(struct neighbour *neigh, int hello, int hello_interval) { @@ -327,7 +328,7 @@ neighbour_cost(struct neighbour *neigh) return INFINITY; if(!(babel_get_if_nfo(neigh->ifp)->flags & BABEL_IF_LQ) - || (a <= 256 && b <= 256)) { + || (a < 256 && b < 256)) { return a; } else { /* a = 256/alpha, b = 256/beta, where alpha and beta are the expected diff --git a/babeld/net.c b/babeld/net.c index eaed51d2..5e0200b0 100644 --- a/babeld/net.c +++ b/babeld/net.c @@ -58,6 +58,7 @@ babel_socket(int port) int s, rc; int saved_errno; int one = 1, zero = 0; + const int ds = 0xc0; /* CS6 - Network Control */ s = socket(PF_INET6, SOCK_DGRAM, 0); if(s < 0) @@ -86,6 +87,15 @@ babel_socket(int port) if(rc < 0) goto fail; +#ifdef IPV6_TCLASS + rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds)); +#else + rc = -1; + errno = ENOSYS; +#endif + if(rc < 0) + perror("Couldn't set traffic class"); + rc = fcntl(s, F_GETFL, 0); if(rc < 0) goto fail; diff --git a/babeld/route.c b/babeld/route.c index aadf80f2..a9ffc5d9 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -53,36 +53,161 @@ THE SOFTWARE. static void consider_route(struct babel_route *route); -struct babel_route *routes = NULL; -int numroutes = 0, maxroutes = 0; +struct babel_route **routes = NULL; +static int route_slots = 0, max_route_slots = 0; int kernel_metric = 0; int allow_duplicates = -1; +int diversity_kind = DIVERSITY_NONE; +int diversity_factor = 256; /* in units of 1/256 */ +int keep_unfeasible = 0; + +/* We maintain a list of "slots", ordered by prefix. Every slot + contains a linked list of the routes to this prefix, with the + installed route, if any, at the head of the list. */ + +static int +route_compare(const unsigned char *prefix, unsigned char plen, + struct babel_route *route) +{ + int i = memcmp(prefix, route->src->prefix, 16); + if(i != 0) + return i; + + if(plen < route->src->plen) + return -1; + else if(plen > route->src->plen) + return 1; + else + return 0; +} + +/* Performs binary search, returns -1 in case of failure. In the latter + case, new_return is the place where to insert the new element. */ + +static int +find_route_slot(const unsigned char *prefix, unsigned char plen, + int *new_return) +{ + int p, m, g, c; + + if(route_slots < 1) { + if(new_return) + *new_return = 0; + return -1; + } + + p = 0; g = route_slots - 1; + + do { + m = (p + g) / 2; + c = route_compare(prefix, plen, routes[m]); + if(c == 0) + return m; + else if(c < 0) + g = m - 1; + else + p = m + 1; + } while(p <= g); + + if(new_return) + *new_return = p; + + return -1; +} struct babel_route * find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop) { - int i; - for(i = 0; i < numroutes; i++) { - if(routes[i].neigh == neigh && - memcmp(routes[i].nexthop, nexthop, 16) == 0 && - source_match(routes[i].src, prefix, plen)) - return &routes[i]; + struct babel_route *route; + int i = find_route_slot(prefix, plen, NULL); + + if(i < 0) + return NULL; + + route = routes[i]; + + while(route) { + if(route->neigh == neigh && memcmp(route->nexthop, nexthop, 16) == 0) + return route; + route = route->next; } + return NULL; } struct babel_route * find_installed_route(const unsigned char *prefix, unsigned char plen) { - int i; - for(i = 0; i < numroutes; i++) { - if(routes[i].installed && source_match(routes[i].src, prefix, plen)) - return &routes[i]; - } + int i = find_route_slot(prefix, plen, NULL); + + if(i >= 0 && routes[i]->installed) + return routes[i]; + return NULL; } +/* Returns an overestimate of the number of installed routes. */ +int +installed_routes_estimate(void) +{ + return route_slots; +} + +static int +resize_route_table(int new_slots) +{ + struct babel_route **new_routes; + assert(new_slots >= route_slots); + + if(new_slots == 0) { + new_routes = NULL; + free(routes); + } else { + new_routes = realloc(routes, new_slots * sizeof(struct babel_route*)); + if(new_routes == NULL) + return -1; + } + + max_route_slots = new_slots; + routes = new_routes; + return 1; +} + +/* Insert a route into the table. If successful, retains the route. + On failure, caller must free the route. */ +static struct babel_route * +insert_route(struct babel_route *route) +{ + int i, n; + + assert(!route->installed); + + i = find_route_slot(route->src->prefix, route->src->plen, &n); + + if(i < 0) { + if(route_slots >= max_route_slots) + resize_route_table(max_route_slots < 1 ? 8 : 2 * max_route_slots); + if(route_slots >= max_route_slots) + return NULL; + route->next = NULL; + if(n < route_slots) + memmove(routes + n + 1, routes + n, + (route_slots - n) * sizeof(struct babel_route*)); + route_slots++; + routes[n] = route; + } else { + struct babel_route *r; + r = routes[i]; + while(r->next) + r = r->next; + r->next = route; + route->next = NULL; + } + + return route; +} + void flush_route(struct babel_route *route) { @@ -91,39 +216,67 @@ flush_route(struct babel_route *route) unsigned oldmetric; int lost = 0; - i = route - routes; - assert(i >= 0 && i < numroutes); - oldmetric = route_metric(route); + src = route->src; if(route->installed) { uninstall_route(route); lost = 1; } - src = route->src; + i = find_route_slot(route->src->prefix, route->src->plen, NULL); + assert(i >= 0 && i < route_slots); - if(i != numroutes - 1) - memcpy(routes + i, routes + numroutes - 1, sizeof(struct babel_route)); - numroutes--; - VALGRIND_MAKE_MEM_UNDEFINED(routes + numroutes, sizeof(struct babel_route)); + if(route == routes[i]) { + routes[i] = route->next; + route->next = NULL; + free(route); - if(numroutes == 0) { - free(routes); - routes = NULL; - maxroutes = 0; - } else if(maxroutes > 8 && numroutes < maxroutes / 4) { - struct babel_route *new_routes; - int n = maxroutes / 2; - new_routes = realloc(routes, n * sizeof(struct babel_route)); - if(new_routes != NULL) { - routes = new_routes; - maxroutes = n; + if(routes[i] == NULL) { + if(i < route_slots - 1) + memmove(routes + i, routes + i + 1, + (route_slots - i - 1) * sizeof(struct babel_route*)); + routes[route_slots - 1] = NULL; + route_slots--; } + + if(route_slots == 0) + resize_route_table(0); + else if(max_route_slots > 8 && route_slots < max_route_slots / 4) + resize_route_table(max_route_slots / 2); + } else { + struct babel_route *r = routes[i]; + while(r->next != route) + r = r->next; + r->next = route->next; + route->next = NULL; + free(route); } if(lost) route_lost(src, oldmetric); + + release_source(src); +} + +void +flush_all_routes() +{ + int i; + + /* Start from the end, to avoid shifting the table. */ + i = route_slots - 1; + while(i >= 0) { + while(i < route_slots) { + /* Uninstall first, to avoid calling route_lost. */ + if(routes[i]->installed) + uninstall_route(routes[0]); + flush_route(routes[i]); + } + i--; + } + + check_sources_released(); } void @@ -132,12 +285,19 @@ flush_neighbour_routes(struct neighbour *neigh) int i; i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) { - flush_route(&routes[i]); - continue; + while(i < route_slots) { + struct babel_route *r; + r = routes[i]; + while(r) { + if(r->neigh == neigh) { + flush_route(r); + goto again; + } + r = r->next; } i++; + again: + ; } } @@ -147,13 +307,46 @@ flush_interface_routes(struct interface *ifp, int v4only) int i; i = 0; - while(i < numroutes) { - if(routes[i].neigh->ifp == ifp && - (!v4only || v4mapped(routes[i].nexthop))) { - flush_route(&routes[i]); - continue; + while(i < route_slots) { + struct babel_route *r; + r = routes[i]; + while(r) { + if(r->neigh->ifp == ifp && + (!v4only || v4mapped(r->nexthop))) { + flush_route(r); + goto again; + } + r = r->next; } i++; + again: + ; + } +} + +/* Iterate a function over all routes. */ +void +for_all_routes(void (*f)(struct babel_route*, void*), void *closure) +{ + int i; + + for(i = 0; i < route_slots; i++) { + struct babel_route *r = routes[i]; + while(r) { + (*f)(r, closure); + r = r->next; + } + } +} + +void +for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure) +{ + int i; + + for(i = 0; i < route_slots; i++) { + if(routes[i]->installed) + (*f)(routes[i], closure); } } @@ -163,10 +356,28 @@ metric_to_kernel(int metric) return metric < INFINITY ? kernel_metric : KERNEL_INFINITY; } +/* This is used to maintain the invariant that the installed route is at + the head of the list. */ +static void +move_installed_route(struct babel_route *route, int i) +{ + assert(i >= 0 && i < route_slots); + assert(route->installed); + + if(route != routes[i]) { + struct babel_route *r = routes[i]; + while(r->next != route) + r = r->next; + r->next = route->next; + route->next = routes[i]; + routes[i] = route; + } +} + void install_route(struct babel_route *route) { - int rc; + int i, rc; if(route->installed) return; @@ -175,6 +386,15 @@ install_route(struct babel_route *route) zlog_err("WARNING: installing unfeasible route " "(this shouldn't happen)."); + i = find_route_slot(route->src->prefix, route->src->plen, NULL); + assert(i >= 0 && i < route_slots); + + if(routes[i] != route && routes[i]->installed) { + fprintf(stderr, "WARNING: attempting to install duplicate route " + "(this shouldn't happen)."); + return; + } + rc = kernel_route(ROUTE_ADD, route->src->prefix, route->src->plen, route->nexthop, route->neigh->ifp->ifindex, @@ -186,6 +406,8 @@ install_route(struct babel_route *route) return; } route->installed = 1; + move_installed_route(route, i); + } void @@ -239,15 +461,16 @@ switch_routes(struct babel_route *old, struct babel_route *new) old->installed = 0; new->installed = 1; + move_installed_route(new, find_route_slot(new->src->prefix, new->src->plen, + NULL)); } static void -change_route_metric(struct babel_route *route, unsigned newmetric) +change_route_metric(struct babel_route *route, + unsigned refmetric, unsigned cost, unsigned add) { int old, new; - - if(route_metric(route) == newmetric) - return; + int newmetric = MIN(refmetric + cost + add, INFINITY); old = metric_to_kernel(route_metric(route)); new = metric_to_kernel(newmetric); @@ -265,14 +488,15 @@ change_route_metric(struct babel_route *route, unsigned newmetric) } } - route->metric = newmetric; + route->refmetric = refmetric; + route->cost = cost; + route->add_metric = add; } static void retract_route(struct babel_route *route) { - route->refmetric = INFINITY; - change_route_metric(route, INFINITY); + change_route_metric(route, INFINITY, INFINITY, 0); } int @@ -293,6 +517,51 @@ route_expired(struct babel_route *route) return route->time < babel_now.tv_sec - route->hold_time; } +static int +channels_interfere(int ch1, int ch2) +{ + if(ch1 == BABEL_IF_CHANNEL_NONINTERFERING + || ch2 == BABEL_IF_CHANNEL_NONINTERFERING) + return 0; + if(ch1 == BABEL_IF_CHANNEL_INTERFERING + || ch2 == BABEL_IF_CHANNEL_INTERFERING) + return 1; + return ch1 == ch2; +} + +int +route_interferes(struct babel_route *route, struct interface *ifp) +{ + struct babel_interface *babel_ifp = NULL; + switch(diversity_kind) { + case DIVERSITY_NONE: + return 1; + case DIVERSITY_INTERFACE_1: + return route->neigh->ifp == ifp; + case DIVERSITY_CHANNEL_1: + case DIVERSITY_CHANNEL: + if(route->neigh->ifp == ifp) + return 1; + babel_ifp = babel_get_if_nfo(ifp); + if(channels_interfere(babel_ifp->channel, + babel_get_if_nfo(route->neigh->ifp)->channel)) + return 1; + if(diversity_kind == DIVERSITY_CHANNEL) { + int i; + for(i = 0; i < DIVERSITY_HOPS; i++) { + if(route->channels[i] == 0) + break; + if(channels_interfere(babel_ifp->channel, route->channels[i])) + return 1; + } + } + return 0; + default: + fprintf(stderr, "Unknown kind of diversity.\n"); + return 1; + } +} + int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric) @@ -317,21 +586,22 @@ struct babel_route * find_best_route(const unsigned char *prefix, unsigned char plen, int feasible, struct neighbour *exclude) { - struct babel_route *route = NULL; - int i; + struct babel_route *route = NULL, *r = NULL; + int i = find_route_slot(prefix, plen, NULL); + + if(i < 0) + return NULL; + + route = routes[i]; - for(i = 0; i < numroutes; i++) { - if(!source_match(routes[i].src, prefix, plen)) - continue; - if(route_expired(&routes[i])) - continue; - if(feasible && !route_feasible(&routes[i])) - continue; - if(exclude && routes[i].neigh == exclude) - continue; - if(route && route_metric(route) <= route_metric(&routes[i])) - continue; - route = &routes[i]; + r = route->next; + while(r) { + if(!route_expired(r) && + (!feasible || route_feasible(r)) && + (!exclude || r->neigh != exclude) && + (route_metric(r) < route_metric(route))) + route = r; + r = r->next; } return route; } @@ -354,31 +624,29 @@ update_route_metric(struct babel_route *route) route->src->prefix, route->src->plen, neigh->address, neigh->ifp->ifindex); - int newmetric = MIN(route->refmetric + - add_metric + - neighbour_cost(route->neigh), - INFINITY); - - if(newmetric != oldmetric) { - change_route_metric(route, newmetric); + change_route_metric(route, route->refmetric, + neighbour_cost(route->neigh), add_metric); + if(route_metric(route) != oldmetric) route_changed(route, route->src, oldmetric); - } } } /* Called whenever a neighbour's cost changes, to update the metric of - all routes through that neighbour. */ + all routes through that neighbour. Calls local_notify_neighbour. */ void update_neighbour_metric(struct neighbour *neigh, int changed) { + if(changed) { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) - update_route_metric(&routes[i]); - i++; + for(i = 0; i < route_slots; i++) { + struct babel_route *r = routes[i]; + while(r) { + if(r->neigh == neigh) + update_route_metric(r); + r = r->next; + } } } } @@ -388,11 +656,13 @@ update_interface_metric(struct interface *ifp) { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh->ifp == ifp) - update_route_metric(&routes[i]); - i++; + for(i = 0; i < route_slots; i++) { + struct babel_route *r = routes[i]; + while(r) { + if(r->neigh->ifp == ifp) + update_route_metric(r); + r = r->next; + } } } @@ -402,7 +672,8 @@ update_route(const unsigned char *router_id, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, - struct neighbour *neigh, const unsigned char *nexthop) + struct neighbour *neigh, const unsigned char *nexthop, + const unsigned char *channels, int channels_len) { struct babel_route *route; struct source *src; @@ -424,12 +695,18 @@ update_route(const unsigned char *router_id, if(add_metric >= INFINITY) return NULL; - src = find_source(router_id, prefix, plen, 1, seqno); + route = find_route(prefix, plen, neigh, nexthop); + + if(route && memcmp(route->src->id, router_id, 8) == 0) + /* Avoid scanning the source table. */ + src = route->src; + else + src = find_source(router_id, prefix, plen, 1, seqno); + if(src == NULL) return NULL; feasible = update_feasible(src, seqno, refmetric); - route = find_route(prefix, plen, neigh, nexthop); metric = MIN((int)refmetric + neighbour_cost(neigh) + add_metric, INFINITY); if(route) { @@ -457,12 +734,12 @@ update_route(const unsigned char *router_id, } } - route->src = src; - if(feasible && refmetric < INFINITY) + route->src = retain_source(src); + if((feasible || keep_unfeasible) && refmetric < INFINITY) route->time = babel_now.tv_sec; route->seqno = seqno; - route->refmetric = refmetric; - change_route_metric(route, metric); + change_route_metric(route, + refmetric, neighbour_cost(neigh), add_metric); route->hold_time = hold_time; route_changed(route, oldsrc, oldmetric); @@ -472,36 +749,46 @@ update_route(const unsigned char *router_id, if(!feasible) send_unfeasible_request(neigh, route->installed && route_old(route), seqno, metric, src); + release_source(oldsrc); } else { + struct babel_route *new_route; + if(refmetric >= INFINITY) /* Somebody's retracting a route we never saw. */ return NULL; if(!feasible) { send_unfeasible_request(neigh, 0, seqno, metric, src); - return NULL; - } - if(numroutes >= maxroutes) { - struct babel_route *new_routes; - int n = maxroutes < 1 ? 8 : 2 * maxroutes; - new_routes = routes == NULL ? - malloc(n * sizeof(struct babel_route)) : - realloc(routes, n * sizeof(struct babel_route)); - if(new_routes == NULL) + if(!keep_unfeasible) return NULL; - maxroutes = n; - routes = new_routes; } - route = &routes[numroutes]; - route->src = src; + + route = malloc(sizeof(struct babel_route)); + if(route == NULL) { + perror("malloc(route)"); + return NULL; + } + + route->src = retain_source(src); route->refmetric = refmetric; + route->cost = neighbour_cost(neigh); + route->add_metric = add_metric; route->seqno = seqno; - route->metric = metric; route->neigh = neigh; memcpy(route->nexthop, nexthop, 16); route->time = babel_now.tv_sec; route->hold_time = hold_time; route->installed = 0; - numroutes++; + memset(&route->channels, 0, sizeof(route->channels)); + if(channels_len > 0) + memcpy(&route->channels, channels, + MIN(channels_len, DIVERSITY_HOPS)); + route->next = NULL; + new_route = insert_route(route); + if(new_route == NULL) { + fprintf(stderr, "Couldn't insert route.\n"); + free(route); + return NULL; + } consider_route(route); } return route; @@ -558,13 +845,6 @@ consider_route(struct babel_route *route) if(route_metric(installed) >= INFINITY) goto install; - if(route_metric(installed) >= route_metric(route) + 192) - goto install; - - /* Avoid switching sources */ - if(installed->src != route->src) - return; - if(route_metric(installed) >= route_metric(route) + 64) goto install; @@ -584,15 +864,18 @@ retract_neighbour_routes(struct neighbour *neigh) { int i; - i = 0; - while(i < numroutes) { - if(routes[i].neigh == neigh) { - if(routes[i].refmetric != INFINITY) { - unsigned short oldmetric = route_metric(&routes[i]); - retract_route(&routes[i]); + for(i = 0; i < route_slots; i++) { + struct babel_route *r = routes[i]; + while(r) { + if(r->neigh == neigh) { + if(r->refmetric != INFINITY) { + unsigned short oldmetric = route_metric(r); + retract_route(r); if(oldmetric != INFINITY) - route_changed(&routes[i], routes[i].src, oldmetric); + route_changed(r, r->src, oldmetric); + } } + r = r->next; } i++; } @@ -699,51 +982,38 @@ route_lost(struct source *src, unsigned oldmetric) } } +/* This is called periodically to flush old routes. It will also send + requests for routes that are about to expire. */ void expire_routes(void) { + struct babel_route *r; int i; debugf(BABEL_DEBUG_COMMON,"Expiring old routes."); i = 0; - while(i < numroutes) { - struct babel_route *route = &routes[i]; - - if(route->time > babel_now.tv_sec || /* clock stepped */ - route_old(route)) { - flush_route(route); - continue; - } + while(i < route_slots) { + r = routes[i]; + while(r) { + /* Protect against clock being stepped. */ + if(r->time > babel_now.tv_sec || route_old(r)) { + flush_route(r); + goto again; + } - update_route_metric(route); + update_route_metric(r); - if(route->installed && route->refmetric < INFINITY) { - if(route_old(route)) - send_unicast_request(route->neigh, - route->src->prefix, route->src->plen); + if(r->installed && r->refmetric < INFINITY) { + if(route_old(r)) + /* Route about to expire, send a request. */ + send_unicast_request(r->neigh, + r->src->prefix, r->src->plen); + } + r = r->next; } i++; + again: + ; } } - -void -babel_uninstall_all_routes(void) -{ - while(numroutes > 0) { - uninstall_route(&routes[0]); - /* We need to flush the route so network_up won't reinstall it */ - flush_route(&routes[0]); - } -} - -struct babel_route * -babel_route_get_by_source(struct source *src) -{ - int i; - for(i = 0; i < numroutes; i++) { - if(routes[i].src == src) - return &routes[i]; - } - return NULL; -} diff --git a/babeld/route.h b/babeld/route.h index c08332a6..b6d2d294 100644 --- a/babeld/route.h +++ b/babeld/route.h @@ -43,41 +43,69 @@ THE SOFTWARE. #include "babel_interface.h" #include "source.h" +#define DIVERSITY_NONE 0 +#define DIVERSITY_INTERFACE_1 1 +#define DIVERSITY_CHANNEL_1 2 +#define DIVERSITY_CHANNEL 3 + +#define DIVERSITY_HOPS 8 + struct babel_route { struct source *src; - unsigned short metric; unsigned short refmetric; + unsigned short cost; + unsigned short add_metric; unsigned short seqno; struct neighbour *neigh; unsigned char nexthop[16]; time_t time; unsigned short hold_time; /* in seconds */ short installed; + unsigned char channels[DIVERSITY_HOPS]; + struct babel_route *next; }; -static inline unsigned short +extern struct babel_route **routes; +extern int kernel_metric, allow_duplicates; +extern int diversity_kind, diversity_factor; +extern int keep_unfeasible; + +static inline int route_metric(const struct babel_route *route) { - return route->metric; + int m = (int)route->refmetric + route->cost + route->add_metric; + return MIN(m, INFINITY); } -extern struct babel_route *routes; -extern int numroutes, maxroutes; -extern int kernel_metric, allow_duplicates; +static inline int +route_metric_noninterfering(const struct babel_route *route) +{ + int m = + (int)route->refmetric + + (diversity_factor * route->cost + 128) / 256 + + route->add_metric; + m = MAX(m, route->refmetric + 1); + return MIN(m, INFINITY); +} struct babel_route *find_route(const unsigned char *prefix, unsigned char plen, struct neighbour *neigh, const unsigned char *nexthop); struct babel_route *find_installed_route(const unsigned char *prefix, unsigned char plen); +int installed_routes_estimate(void); void flush_route(struct babel_route *route); +void flush_all_routes(void); void flush_neighbour_routes(struct neighbour *neigh); void flush_interface_routes(struct interface *ifp, int v4only); +void for_all_routes(void (*f)(struct babel_route*, void*), void *closure); +void for_all_installed_routes(void (*f)(struct babel_route*, void*), void *closure); void install_route(struct babel_route *route); void uninstall_route(struct babel_route *route); void switch_route(struct babel_route *old, struct babel_route *new); int route_feasible(struct babel_route *route); int route_old(struct babel_route *route); int route_expired(struct babel_route *route); +int route_interferes(struct babel_route *route, struct interface *ifp); int update_feasible(struct source *src, unsigned short seqno, unsigned short refmetric); struct babel_route *find_best_route(const unsigned char *prefix, unsigned char plen, @@ -87,11 +115,12 @@ struct babel_route *install_best_route(const unsigned char prefix[16], void update_neighbour_metric(struct neighbour *neigh, int change); void update_interface_metric(struct interface *ifp); void update_route_metric(struct babel_route *route); -struct babel_route *update_route(const unsigned char *a, - const unsigned char *p, unsigned char plen, +struct babel_route *update_route(const unsigned char *id, + const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned short refmetric, unsigned short interval, struct neighbour *neigh, - const unsigned char *nexthop); + const unsigned char *nexthop, + const unsigned char *channels, int channels_len); void retract_neighbour_routes(struct neighbour *neigh); void send_unfeasible_request(struct neighbour *neigh, int force, unsigned short seqno, unsigned short metric, @@ -103,7 +132,4 @@ void route_changed(struct babel_route *route, void route_lost(struct source *src, unsigned oldmetric); void expire_routes(void); -void babel_uninstall_all_routes(void); -struct babel_route *babel_route_get_by_source(struct source *src); - #endif diff --git a/babeld/source.c b/babeld/source.c index cc4ed445..772112d4 100644 --- a/babeld/source.c +++ b/babeld/source.c @@ -63,8 +63,10 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, continue; if(memcmp(src->id, id, 8) != 0) continue; - if(source_match(src, p, plen)) - return src; + if(src->plen != plen) + continue; + if(memcmp(src->prefix, p, 16) == 0) + return src; } if(!create) @@ -82,18 +84,32 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, src->seqno = seqno; src->metric = INFINITY; src->time = babel_now.tv_sec; + src->route_count = 0; src->next = srcs; srcs = src; return src; } +struct source * +retain_source(struct source *src) +{ + assert(src->route_count < 0xffff); + src->route_count++; + return src; +} + +void +release_source(struct source *src) +{ + assert(src->route_count > 0); + src->route_count--; +} + int flush_source(struct source *src) { - /* This is absolutely horrible -- it makes expire_sources quadratic. - But it's not called very often. */ - - if (babel_route_get_by_source(src) != NULL) + if(src->route_count > 0) + /* The source is in use by a route. */ return 0; if(srcs == src) { @@ -109,19 +125,6 @@ flush_source(struct source *src) return 1; } -int -source_match(struct source *src, - const unsigned char *p, unsigned char plen) -{ - if(src->plen != plen) - return 0; - if(src->prefix[15] != p[15]) - return 0; - if(memcmp(src->prefix, p, 16) != 0) - return 0; - return 1; -} - void update_source(struct source *src, unsigned short seqno, unsigned short metric) @@ -129,6 +132,10 @@ update_source(struct source *src, if(metric >= INFINITY) return; + /* If a source is expired, pretend that it doesn't exist and update + it unconditionally. This makes ensures that old data will + eventually be overridden, and prevents us from getting stuck if + a router loses its sequence number. */ if(src->time < babel_now.tv_sec - SOURCE_GC_TIME || seqno_compare(src->seqno, seqno) < 0 || (src->seqno == seqno && src->metric > metric)) { @@ -157,3 +164,17 @@ expire_sources() src = src->next; } } + +void +check_sources_released(void) +{ + struct source *src; + + for(src = srcs; src; src = src->next) { + if(src->route_count != 0) + fprintf(stderr, "Warning: source %s %s has refcount %d.\n", + format_eui64(src->id), + format_prefix(src->prefix, src->plen), + (int)src->route_count); + } +} diff --git a/babeld/source.h b/babeld/source.h index 38d3c004..62a7e1ee 100644 --- a/babeld/source.h +++ b/babeld/source.h @@ -48,19 +48,20 @@ struct source { unsigned char plen; unsigned short seqno; unsigned short metric; + unsigned short route_count; time_t time; }; -int source_match(struct source *src, - const unsigned char *p, unsigned char plen); struct source *find_source(const unsigned char *id, const unsigned char *p, unsigned char plen, int create, unsigned short seqno); +struct source *retain_source(struct source *src); +void release_source(struct source *src); int flush_source(struct source *src); void update_source(struct source *src, unsigned short seqno, unsigned short metric); void expire_sources(void); - +void check_sources_released(void); #endif diff --git a/babeld/util.c b/babeld/util.c index 514e0ff3..011f3824 100644 --- a/babeld/util.c +++ b/babeld/util.c @@ -200,17 +200,6 @@ parse_msec(const char *string) return -1; } -void -do_debugf(const char *format, ...) -{ - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - fprintf(stderr, "\n"); - fflush(stderr); - va_end(args); -} - int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) @@ -327,63 +316,6 @@ parse_address(const char *address, unsigned char *addr_r, int *af_r) return -1; } -int -parse_net(const char *net, unsigned char *prefix_r, unsigned char *plen_r, - int *af_r) -{ - char buf[INET6_ADDRSTRLEN]; - char *slash, *end; - unsigned char prefix[16]; - long plen; - int af; - struct in_addr ina; - struct in6_addr ina6; - int rc; - - if(strcmp(net, "default") == 0) { - memset(prefix, 0, 16); - plen = 0; - } else { - slash = strchr(net, '/'); - if(slash == NULL) { - rc = parse_address(net, prefix, &af); - if(rc < 0) - return rc; - plen = 128; - } else { - if(slash - net >= INET6_ADDRSTRLEN) - return -1; - memcpy(buf, net, slash - net); - buf[slash - net] = '\0'; - rc = inet_pton(AF_INET, buf, &ina); - if(rc > 0) { - memcpy(prefix, v4prefix, 12); - memcpy(prefix + 12, &ina, 4); - plen = strtol(slash + 1, &end, 0); - if(*end != '\0' || plen < 0 || plen > 32) - return -1; - plen += 96; - af = AF_INET; - } else { - rc = inet_pton(AF_INET6, buf, &ina6); - if(rc > 0) { - memcpy(prefix, &ina6, 16); - plen = strtol(slash + 1, &end, 0); - if(*end != '\0' || plen < 0 || plen > 128) - return -1; - af = AF_INET6; - } else { - return -1; - } - } - } - } - mask_prefix(prefix_r, prefix, plen); - *plen_r = plen; - if(af_r) *af_r = af; - return 0; -} - int parse_eui64(const char *eui, unsigned char *eui_r) { diff --git a/babeld/util.h b/babeld/util.h index 376b967f..5d9d2f5d 100644 --- a/babeld/util.h +++ b/babeld/util.h @@ -100,8 +100,6 @@ int timeval_compare(const struct timeval *s1, const struct timeval *s2) void timeval_min(struct timeval *d, const struct timeval *s); void timeval_min_sec(struct timeval *d, time_t secs); int parse_msec(const char *string) ATTRIBUTE ((pure)); -void do_debugf(const char *format, ...) - ATTRIBUTE ((format (printf, 1, 2))) COLD; int in_prefix(const unsigned char *restrict address, const unsigned char *restrict prefix, unsigned char plen) ATTRIBUTE ((pure)); @@ -113,8 +111,6 @@ const char *format_prefix(const unsigned char *address, unsigned char prefix); const char *format_eui64(const unsigned char *eui); const char *format_bool(const int b); int parse_address(const char *address, unsigned char *addr_r, int *af_r); -int parse_net(const char *ifp, unsigned char *prefix_r, unsigned char *plen_r, - int *af_r); int parse_eui64(const char *eui, unsigned char *eui_r); int wait_for_fd(int direction, int fd, int msecs); int martian_prefix(const unsigned char *prefix, int plen) ATTRIBUTE ((pure)); diff --git a/babeld/xroute.c b/babeld/xroute.c index 8330b492..80651671 100644 --- a/babeld/xroute.c +++ b/babeld/xroute.c @@ -50,9 +50,12 @@ THE SOFTWARE. #include "util.h" #include "babel_interface.h" -struct xroute *xroutes; -int numxroutes = 0; -int maxxroutes = 0; +static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, + unsigned short metric, unsigned int ifindex, + int proto, int send_updates); + +static struct xroute *xroutes; +static int numxroutes = 0, maxxroutes = 0; /* Add redistributed route to Babel table. */ int @@ -189,8 +192,24 @@ add_xroute(unsigned char prefix[16], unsigned char plen, return 1; } -/* add an xroute, verifying some conditions; return 0 if there is no changes */ +/* Returns an overestimate of the number of xroutes. */ int +xroutes_estimate() +{ + return numxroutes; +} + +void +for_all_xroutes(void (*f)(struct xroute*, void*), void *closure) +{ + int i; + + for(i = 0; i < numxroutes; i++) + (*f)(&xroutes[i], closure); +} + +/* add an xroute, verifying some conditions; return 0 if there is no changes */ +static int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, unsigned short metric, unsigned int ifindex, int proto, int send_updates) diff --git a/babeld/xroute.h b/babeld/xroute.h index c9a4f85f..4d4ab99d 100644 --- a/babeld/xroute.h +++ b/babeld/xroute.h @@ -45,14 +45,8 @@ struct xroute { int proto; }; -extern struct xroute *xroutes; -extern int numxroutes; - struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen); void flush_xroute(struct xroute *xroute); -int xroute_add_new_route(unsigned char prefix[16], unsigned char plen, - unsigned short metric, unsigned int ifindex, - int proto, int send_updates); int babel_ipv4_route_add (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, unsigned int ifindex, struct in_addr *nexthop); int babel_ipv4_route_delete (struct zapi_ipv4 *api, struct prefix_ipv4 *prefix, @@ -61,3 +55,5 @@ int babel_ipv6_route_add (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex, struct in6_addr *nexthop); int babel_ipv6_route_delete (struct zapi_ipv6 *api, struct prefix_ipv6 *prefix, unsigned int ifindex); +int xroutes_estimate(void); +void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure); -- cgit v1.2.1 From 05c943ac43087750ebc81b916b7dccfe4ae074ff Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Thu, 26 Jan 2012 22:15:34 +0100 Subject: babeld: Replace redistribution strings with route_types.h defines. --- babeld/babel_zebra.c | 74 +++++++++++++++++++--------------------------------- 1 file changed, 27 insertions(+), 47 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index e68c2b70..1890291d 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -54,19 +54,6 @@ void babelz_zebra_init(void); /* we must use a pointer because of zclient.c's functions (new, free). */ struct zclient *zclient; static int zebra_config_write (struct vty *vty); -/* Redistribution types */ -static struct { - int type; - int str_min_len; - const char *str; -} redist_type[] = { - {ZEBRA_ROUTE_KERNEL, 1, "kernel"}, - {ZEBRA_ROUTE_CONNECT, 1, "connected"}, - {ZEBRA_ROUTE_STATIC, 1, "static"}, - {ZEBRA_ROUTE_OSPF6, 1, "ospf6"}, - {ZEBRA_ROUTE_BGP, 1, "bgp"}, - {0, 0, NULL} -}; /* Debug types */ static struct { @@ -219,54 +206,47 @@ babel_redistribute_unset (int type) /* [Babel Command] */ DEFUN (babel_redistribute_type, babel_redistribute_type_cmd, - "redistribute (kernel|connected|static|ospf6|bgp)", - "Redistribute information from another routing protocol\n" - "Kernel routes\n" - "Connected\n" - "Static routes\n" - "Open Shortest Path First (OSPFv3)\n" - "Border Gateway Protocol (BGP)\n") + "redistribute " QUAGGA_REDIST_STR_BABELD, + "Redistribute\n" + QUAGGA_REDIST_HELP_STR_BABELD) { - int i; + int type; - for(i = 0; redist_type[i].str != NULL; i++) { - if (strncmp (redist_type[i].str, argv[0], - redist_type[i].str_min_len) == 0) { - zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, - redist_type[i].type); - return CMD_SUCCESS; - } - } + type = proto_redistnum(AFI_IP6, argv[0]); - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + if (type < 0) + type = proto_redistnum(AFI_IP, argv[0]); - return CMD_WARNING; + if (type < 0) { + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type); + return CMD_SUCCESS; } /* [Babel Command] */ DEFUN (no_babel_redistribute_type, no_babel_redistribute_type_cmd, - "no redistribute (kernel|connected|static|ospf6|bgp)", + "no redistribute " QUAGGA_REDIST_STR_BABELD, NO_STR - "Redistribute information from another routing protocol\n" - "Kernel routes\n" - "Connected\n" - "Static routes\n" - "Open Shortest Path First (OSPFv3)\n" - "Border Gateway Protocol (BGP)\n") + "Redistribute\n" + QUAGGA_REDIST_HELP_STR_BABELD) { - int i; + int type; - for (i = 0; redist_type[i].str; i++) { - if (strncmp(redist_type[i].str, argv[0], - redist_type[i].str_min_len) == 0) { - return babel_redistribute_unset (redist_type[i].type); - } - } + type = proto_redistnum(AFI_IP6, argv[0]); - vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + if (type < 0) + type = proto_redistnum(AFI_IP, argv[0]); - return CMD_WARNING; + if (type < 0) { + vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + + return babel_redistribute_unset (type); } #ifndef NO_DEBUG -- cgit v1.2.1 From a0edef1b74bc9785b2aa1ed292a2777b6a75d40e Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Fri, 27 Jan 2012 22:54:11 +0100 Subject: babeld: "return CMD_SUCCESS" was missing for command 'no debug'. --- babeld/babel_zebra.c | 1 + 1 file changed, 1 insertion(+) (limited to 'babeld') diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index 1890291d..eced995e 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -298,6 +298,7 @@ DEFUN (no_babel_debug, if (strncmp(debug_type[i].str, argv[0], debug_type[i].str_min_len) == 0) { debug &= ~debug_type[i].type; + return CMD_SUCCESS; } } -- cgit v1.2.1 From 210f6f66287c40f247c1a4ff983aae85b9e42e2c Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Sat, 28 Jan 2012 00:07:14 +0100 Subject: babeld: fix eui64 features. We are interested by eui64 with at least 6 octets. --- babeld/babel_main.c | 4 +++- babeld/kernel_zebra.c | 5 ----- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 4d6f60eb..c039c880 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -423,7 +423,9 @@ babel_load_state_file(void) if(memcmp(sid, myid, 8) == 0) myseqno = seqno_plus(s, 1); else - zlog_err("ID mismatch in babel-state."); + zlog_err("ID mismatch in babel-state. id=%s; old=%s", + format_eui64(myid), + format_eui64(sid)); /* Convert realtime into monotonic time. */ if(t >= 1176800000L && t <= realnow.tv_sec) reboot_time = babel_now.tv_sec - (realnow.tv_sec - t); diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index d556a605..97b7c584 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -371,11 +371,6 @@ if_eui64(char *ifname, int ifindex, unsigned char *eui) eui[3] = 0xFF; eui[4] = 0xFE; memcpy(eui+5, tmp+3, 3); - } else if (len > 8) { - memcpy(eui, tmp, 8); - } else if (len > 0){ - memset(eui, 0, 8 - len); - memcpy(eui + 8 - len, tmp, len); } else { return -1; } -- cgit v1.2.1 From 69394543597a0fd8c161c5c8a0d25c8b1cfa8a93 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Sat, 28 Jan 2012 10:35:12 +0100 Subject: babeld: state-file was loaded too early. Initial seqno too. --- babeld/babel_main.c | 6 +----- babeld/babel_main.h | 1 + babeld/babeld.c | 2 ++ 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index c039c880..951da7d1 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -68,7 +68,6 @@ static char *babel_get_progname(char *argv_0); static void babel_fail(void); static void babel_init_random(void); static void babel_replace_by_null(int fd); -static void babel_load_state_file(void); static void babel_init_signals(void); static void babel_exit_properly(void); static void babel_save_state_file(void); @@ -304,9 +303,6 @@ babel_init(int argc, char **argv) zlog_set_level (NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED); vty_read_config (babel_config_file, babel_config_default); - myseqno = (random() & 0xFFFF); - babel_load_state_file(); - /* Create VTY socket */ vty_serv_sock (babel_vty_addr, babel_vty_port, BABEL_VTYSH_PATH); @@ -380,7 +376,7 @@ babel_replace_by_null(int fd) Load the state file: check last babeld's running state, usefull in case of "/etc/init.d/babeld restart" */ -static void +void babel_load_state_file(void) { time_t reboot_time; diff --git a/babeld/babel_main.h b/babeld/babel_main.h index fb22c58e..2afebc9e 100644 --- a/babeld/babel_main.h +++ b/babeld/babel_main.h @@ -54,4 +54,5 @@ extern int protocol_socket; extern int kernel_socket; extern int max_request_hopcount; +void babel_load_state_file(void); void show_babel_main_configuration (struct vty *vty); diff --git a/babeld/babeld.c b/babeld/babeld.c index d69662c0..33b5d9e1 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -173,7 +173,9 @@ babel_read_protocol (struct thread *thread) static int babel_init_routing_process(struct thread *thread) { + myseqno = (random() & 0xFFFF); babel_get_myid(); + babel_load_state_file(); debugf(BABEL_DEBUG_COMMON, "My ID is : %s.", format_eui64(myid)); babel_initial_noise(); babel_main_loop(thread);/* this function self-add to the t_update thread */ -- cgit v1.2.1 From 8c4e57a57562c9329b1de4c29ee921ab98182c6b Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Sat, 28 Jan 2012 00:29:51 +0100 Subject: babeld: fix interface bug, simplify code. Perhaps could it be able to free already free memory (so free(NULL)), in function interface_reset(). On other hand, it initiated untracked interfaces, raising (at least) inappropriate messages. Finally, I remove the BABEL_IF_IS_ENABLE flag, witch was not really usefull. Note the test if_up isn't weaker, because (...IS_UP => ...IS_ENABLE). --- babeld/babel_interface.c | 41 +++++++++++++++++++++++++++++------------ babeld/babel_interface.h | 5 +---- 2 files changed, 30 insertions(+), 16 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 1c8c8868..fafe009f 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -57,6 +57,8 @@ THE SOFTWARE. #include "xroute.h" +#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0) + static int babel_enable_if_lookup (const char *ifname); static int babel_enable_if_add (const char *ifname); static int babel_enable_if_delete (const char *ifname); @@ -87,7 +89,7 @@ babel_interface_up (int cmd, struct zclient *client, zebra_size_t length) debugf(BABEL_DEBUG_IF, "receive a 'interface up'"); s = zclient->ibuf; - ifp = zebra_interface_state_read(s); + ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; @@ -106,7 +108,7 @@ babel_interface_down (int cmd, struct zclient *client, zebra_size_t length) debugf(BABEL_DEBUG_IF, "receive a 'interface down'"); s = zclient->ibuf; - ifp = zebra_interface_state_read(s); + ifp = zebra_interface_state_read(s); /* it updates iflist */ if (ifp == NULL) { return 0; @@ -131,14 +133,30 @@ babel_interface_add (int cmd, struct zclient *client, zebra_size_t length) } interface_recalculate(ifp); - return 0; } int babel_interface_delete (int cmd, struct zclient *client, zebra_size_t length) { + struct interface *ifp; + struct stream *s; + debugf(BABEL_DEBUG_IF, "receive a 'interface delete'"); + + s = zclient->ibuf; + ifp = zebra_interface_state_read(s); /* it updates iflist */ + + if (ifp == NULL) + return 0; + + if (IS_ENABLE(ifp)) + interface_reset(ifp); + + /* To support pseudo interface do not free interface structure. */ + /* if_delete(ifp); */ + ifp->ifindex = IFINDEX_INTERNAL; + return 0; } @@ -242,7 +260,7 @@ babel_enable_if_add (const char *ifname) ifp = if_lookup_by_name(ifname); if (ifp != NULL) - babel_get_if_nfo(ifp)->flags |= BABEL_IF_IS_ENABLE; + interface_recalculate(ifp); return 1; } @@ -265,7 +283,7 @@ babel_enable_if_delete (const char *ifname) ifp = if_lookup_by_name(ifname); if (ifp != NULL) - babel_get_if_nfo(ifp)->flags &= ~BABEL_IF_IS_ENABLE; + interface_reset(ifp); return 1; } @@ -514,6 +532,9 @@ interface_recalculate(struct interface *ifp) int mtu, rc; struct ipv6_mreq mreq; + if (!IS_ENABLE(ifp)) + return -1; + if (!if_is_operative(ifp) || !CHECK_FLAG(ifp->flags, IFF_RUNNING)) { interface_reset(ifp); return -1; @@ -594,13 +615,6 @@ interface_recalculate(struct interface *ifp) if(rc > 0) send_update(ifp, 0, NULL, 0); - /* Check and set if interface is enable. */ - if (babel_enable_if_lookup(ifp->name) >= 0) { - babel_ifp->flags |= BABEL_IF_IS_ENABLE; - } else { - babel_ifp->flags &= ~BABEL_IF_IS_ENABLE; - } - return 1; } @@ -613,6 +627,9 @@ interface_reset(struct interface *ifp) struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + if (!(babel_ifp->flags & BABEL_IF_IS_UP)) + return 0; + debugf(BABEL_DEBUG_IF, "interface reset: %s", ifp->name); babel_ifp->flags &= ~BABEL_IF_IS_UP; diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index 5b551fbe..ec69bff4 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -99,7 +99,6 @@ static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) #define BABEL_IF_SPLIT_HORIZON (1 << 2) #define BABEL_IF_LQ (1 << 3) #define BABEL_IF_FARAWAY (1 << 4) -#define BABEL_IF_IS_ENABLE (1 << 7) /* Only INTERFERING can appear on the wire. */ #define BABEL_IF_CHANNEL_UNKNOWN 0 @@ -111,9 +110,7 @@ if_up(struct interface *ifp) { return (if_is_operative(ifp) && ifp->connected != NULL && - babel_get_if_nfo(ifp) != NULL && - (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP) && - (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_ENABLE)); + (babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP)); } /* types: -- cgit v1.2.1 From 831aeb9a87d9071829758caf11130aee5578f9c2 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 7 Feb 2012 04:56:47 +0100 Subject: babeld: Replace the babeld.conf.sample file by one that actually works. --- babeld/babeld.conf.sample | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) (limited to 'babeld') diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample index bb2c1dbb..e1585c1d 100644 --- a/babeld/babeld.conf.sample +++ b/babeld/babeld.conf.sample @@ -1,31 +1,13 @@ -# placeholder -# This is an example. See documentation for more results. -# -# let 'eth0' be an interface. -# -# Remark: '#' and '!' are comments. -# NB, just for this example: -# each line at the same indentation is only dependant of the less level -# line. BUT the quagga parser is insensitive. - - -# setup the routing for Babel. -router babel #activate the Babel routing babeld.c - network eth0 #eth0 is match interface.c - redistribute kernel #(kernel|connected|static|ospf6|bgp) babel_zebra.c - no redistribute static #... - - -# setup each interface, one by one... -Interface eth0 #Set eth0 options interface.c -! wired #with wire interface.c - wireless #without wire (défaut) interface.c -! babel split-horizon #with Split-horizon interface.c - no babel split-horizon #without (defaut) interface.c - hello interval 4096 #default = 4096 (in miliseconds) interface.c - - -# setup the log destination. -# log stdout -# log stdout debugging -log file /var/log/quagga/babeld.log \ No newline at end of file +router babel +! network eth0 +! redistribute kernel +! no redistribute static + +!interface eth0 +! wired +! wireless +! babel split-horizon +! no babel split-horizon + +! log file /var/log/quagga/babeld.log +log stdout \ No newline at end of file -- cgit v1.2.1 From e19ed8c4516621be74b9a28c887185fc66b67430 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 7 Feb 2012 05:36:06 +0100 Subject: babeld: Fix typo in hello interval command. --- babeld/babel_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index fafe009f..a874289c 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -430,7 +430,7 @@ DEFUN (babel_set_hello_interval, struct interface *ifp; babel_interface_nfo *babel_ifp; - int interval = atoi(argv[1]); + int interval = atoi(argv[0]); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); -- cgit v1.2.1 From 38846de1fd7fa9005933564de28360fb9bdf02bb Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 7 Feb 2012 05:43:36 +0100 Subject: babeld: Error handling and tweaks for babeld commands. --- babeld/babel_interface.c | 9 +++++---- babeld/babel_main.c | 3 +-- babeld/babeld.c | 7 +++++-- 3 files changed, 11 insertions(+), 8 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index a874289c..906f349e 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -429,13 +429,14 @@ DEFUN (babel_set_hello_interval, { struct interface *ifp; babel_interface_nfo *babel_ifp; + int interval; - int interval = atoi(argv[0]); + VTY_GET_INTEGER_RANGE("hello interval", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); - assert (babel_ifp != NULL); + babel_ifp->hello_interval = interval; return CMD_SUCCESS; } @@ -450,7 +451,7 @@ DEFUN (babel_passive_interface, if (allow_duplicates) { return CMD_WARNING; } - parasitic = -1; + parasitic = 1; return CMD_SUCCESS; } @@ -900,7 +901,7 @@ DEFUN (show_babel_running_config, vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); show_babel_main_configuration(vty); show_babeld_configuration(vty); - vty_out(vty, " -- ditribution lists --%s", VTY_NEWLINE); + vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE); config_show_distribute(vty); return CMD_SUCCESS; diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 951da7d1..a75171e0 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -227,8 +227,7 @@ babel_init(int argc, char **argv) break; case 'P': babel_vty_port = atoi (optarg); - if (babel_vty_port < 0 || babel_vty_port > 0xffff - || (babel_vty_port == 0 && optarg[0] != '0'/*atoi error*/)) + if (babel_vty_port <= 0 || babel_vty_port > 0xffff) babel_vty_port = BABEL_VTY_PORT; break; case 'u': diff --git a/babeld/babeld.c b/babeld/babeld.c index 33b5d9e1..da074349 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -608,6 +608,7 @@ DEFUN (router_babel, /* Notice to user we couldn't create Babel. */ if (ret < 0) { zlog_warn ("can't create Babel"); + return CMD_WARNING; } } @@ -666,9 +667,11 @@ DEFUN (babel_set_protocol_port, "Set the protocol port (default is defined in RFC).\n" "IPv6 address") { - int port = atoi(argv[0]); - protocol_port = port; + int port; + VTY_GET_INTEGER_RANGE("port", port, argv[0], 1, 0xFFFF); + + protocol_port = port; return CMD_SUCCESS; } -- cgit v1.2.1 From ec0c848047954158b4316d45586079cbb774a7fe Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 7 Feb 2012 05:44:41 +0100 Subject: babeld: Indentation fix. --- babeld/babel_interface.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 906f349e..047a6ebf 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -935,9 +935,9 @@ babel_if_init () install_element(INTERFACE_NODE, &babel_passive_interface_cmd); install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); - /* "show babel ..." commands */ - install_element (VIEW_NODE, &show_babel_interface_cmd); - install_element (ENABLE_NODE, &show_babel_interface_cmd); + /* "show babel ..." commands */ + install_element(VIEW_NODE, &show_babel_interface_cmd); + install_element(ENABLE_NODE, &show_babel_interface_cmd); install_element(VIEW_NODE, &show_babel_neighbour_cmd); install_element(ENABLE_NODE, &show_babel_neighbour_cmd); install_element(VIEW_NODE, &show_babel_database_cmd); -- cgit v1.2.1 From 53b21956f650df86a76b7a7047cfa85114c99dcc Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Tue, 31 Jan 2012 17:09:55 +0100 Subject: babeld: remove some unused functions' arguments. --- babeld/kernel_zebra.c | 84 ++++++++++++++++----------------------------------- 1 file changed, 26 insertions(+), 58 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 97b7c584..f23403ec 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -59,26 +59,20 @@ THE SOFTWARE. static int kernel_route_add_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric); + const unsigned char *gate, int ifindex, + unsigned int metric); static int kernel_route_add_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric); + const unsigned char *gate, int ifindex, + unsigned int metric); static int kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, - unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric); + unsigned int metric); static int kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, - unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric); + unsigned int metric); int kernel_interface_operational(struct interface *interface) @@ -125,47 +119,29 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, switch (operation) { case ROUTE_ADD: return ipv4 ? - kernel_route_add_v4(pref, plen, gate, ifindex, metric, - newgate, newifindex, newmetric): - kernel_route_add_v6(pref, plen, gate, ifindex, metric, - newgate, newifindex, newmetric); + kernel_route_add_v4(pref, plen, gate, ifindex, metric): + kernel_route_add_v6(pref, plen, gate, ifindex, metric); break; case ROUTE_FLUSH: return ipv4 ? - kernel_route_delete_v4(pref, plen, gate, ifindex, metric, - newgate, newifindex, newmetric): - kernel_route_delete_v6(pref, plen, gate, ifindex, metric, - newgate, newifindex, newmetric); + kernel_route_delete_v4(pref, plen, gate, ifindex, metric): + kernel_route_delete_v6(pref, plen, gate, ifindex, metric); break; case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && newifindex == ifindex) return 0; debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); - if (ipv4) { - kernel_route_delete_v4(pref, plen, - gate, ifindex, metric, - NULL, 0, 0); - } else { - kernel_route_delete_v6(pref, plen, - gate, ifindex, metric, - NULL, 0, 0); - } + rc = ipv4 ? + kernel_route_delete_v4(pref, plen, gate, ifindex, metric): + kernel_route_delete_v6(pref, plen, gate, ifindex, metric); + + if (rc < 0) + return -1; rc = ipv4 ? - kernel_route_add_v4(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0): - kernel_route_add_v6(pref, plen, - newgate, newifindex, newmetric, - NULL, 0, 0); - if(rc < 0) { - if(errno == EEXIST) - rc = 1; - /* In principle, we should try to re-install the flushed - route on failure to preserve. However, this should - hopefully not matter much in practice. */ - } + kernel_route_add_v4(pref, plen, newgate, newifindex, newmetric): + kernel_route_add_v6(pref, plen, newgate, newifindex, newmetric); return rc; break; @@ -179,9 +155,7 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, static int kernel_route_add_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) + const unsigned char *gate, int ifindex, unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv4 api; /* quagga's communication system */ @@ -190,7 +164,7 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, struct in_addr nexthop; /* next router to go */ struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ - /* convert to be comprehensive by quagga */ + /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_inaddr(&babel_prefix_addr, pref); uchar_to_inaddr(&nexthop, gate); @@ -222,9 +196,7 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, static int kernel_route_add_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) + const unsigned char *gate, int ifindex, unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv6 api; /* quagga's communication system */ @@ -233,7 +205,7 @@ kernel_route_add_v6(const unsigned char *pref, unsigned short plen, struct in6_addr nexthop; /* next router to go */ struct in6_addr *nexthop_pointer = &nexthop; - /* convert to be comprehensive by quagga */ + /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_in6addr(&babel_prefix_addr, pref); uchar_to_in6addr(&nexthop, gate); @@ -266,9 +238,7 @@ kernel_route_add_v6(const unsigned char *pref, unsigned short plen, static int kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, - unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) + unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv4 api; /* quagga's communication system */ @@ -277,7 +247,7 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, struct in_addr nexthop; /* next router to go */ struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ - /* convert to be comprehensive by quagga */ + /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_inaddr(&babel_prefix_addr, pref); uchar_to_inaddr(&nexthop, gate); @@ -310,9 +280,7 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, static int kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, - unsigned int metric, - const unsigned char *newgate, int newifindex, - unsigned int newmetric) + unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv6 api; /* quagga's communication system */ @@ -321,7 +289,7 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, struct in6_addr nexthop; /* next router to go */ struct in6_addr *nexthop_pointer = &nexthop; - /* convert to be comprehensive by quagga */ + /* convert to be understandable by quagga */ /* convert given addresses */ uchar_to_in6addr(&babel_prefix_addr, pref); uchar_to_in6addr(&nexthop, gate); -- cgit v1.2.1 From b6475ecb14abab936919894050f9ca47415d0f48 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Thu, 9 Feb 2012 12:29:10 +0100 Subject: babeld: Don't use an ifindex when installing IPv4 routes. Stand-alone babeld installs routes using both a next-hop gateway and an interface index. Unfortunately, this doesn't work for IPv4 under Quagga. We now ignore the ifindex when installing IPv4 routes, which makes Babel work for IPv4 in prefix-based networks. Of course this breaks IPv4 mesh networks, unless you play some tricks with your interfaces' netmasks. --- babeld/kernel_zebra.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index f23403ec..1df4217f 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -157,7 +157,6 @@ static int kernel_route_add_v4(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { - unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv4 api; /* quagga's communication system */ struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ struct in_addr babel_prefix_addr; /* babeld's prefix addr */ @@ -180,12 +179,17 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, api.flags = 0; api.message = 0; api.safi = SAFI_UNICAST; + + /* Unlike the native Linux and BSD interfaces, Quagga doesn't like + there to be both and IPv4 nexthop and an ifindex. Omit the + ifindex, and assume that the connected prefixes be set up + correctly. */ + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; + api.ifindex_num = 0; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; @@ -240,7 +244,6 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, const unsigned char *gate, int ifindex, unsigned int metric) { - unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv4 api; /* quagga's communication system */ struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ struct in_addr babel_prefix_addr; /* babeld's prefix addr */ @@ -266,9 +269,7 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); api.nexthop_num = 1; api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; + api.ifindex_num = 0; SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); api.metric = metric; -- cgit v1.2.1 From 82509bfde09b15ac8856a374aac6d5d62b91f54a Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Thu, 9 Feb 2012 13:35:27 +0100 Subject: babeld: Use quagga_gettime. --- babeld/kernel.c | 39 +-------------------------------------- 1 file changed, 1 insertion(+), 38 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel.c b/babeld/kernel.c index 4b5bd7b2..c31f617b 100644 --- a/babeld/kernel.c +++ b/babeld/kernel.c @@ -50,44 +50,7 @@ THE SOFTWARE. int gettime(struct timeval *tv) { - int rc; - static time_t offset = 0, previous = 0; - -#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 && defined(CLOCK_MONOTONIC) - static int have_posix_clocks = -1; - - if(UNLIKELY(have_posix_clocks < 0)) { - struct timespec ts; - rc = clock_gettime(CLOCK_MONOTONIC, &ts); - if(rc < 0) { - have_posix_clocks = 0; - } else { - have_posix_clocks = 1; - } - } - - if(have_posix_clocks) { - struct timespec ts; - int rc; - rc = clock_gettime(CLOCK_MONOTONIC, &ts); - if(rc < 0) - return rc; - tv->tv_sec = ts.tv_sec; - tv->tv_usec = ts.tv_nsec / 1000; - return rc; - } -#endif - - rc = gettimeofday(tv, NULL); - if(rc < 0) - return rc; - tv->tv_sec += offset; - if(UNLIKELY(previous > tv->tv_sec)) { - offset += previous - tv->tv_sec; - tv->tv_sec = previous; - } - previous = tv->tv_sec; - return rc; + return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv); } /* If /dev/urandom doesn't exist, this will fail with ENOENT, which the -- cgit v1.2.1 From 31e2a19fd2b4aca34b1d2f5e2eb8c9a44b9ea6c9 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Thu, 9 Feb 2012 14:06:11 +0100 Subject: babeld: refactor filtering stubs. Factorise the common parts of the in/out filtering functions. This also fixes a bug with filtered out routes, which in babeld are signalled by a filter returing INFINITY, not -1. --- babeld/babel_filter.c | 152 +++++++++++++++----------------------------------- babeld/babel_filter.h | 9 +-- babeld/babeld.c | 61 ++++---------------- 3 files changed, 56 insertions(+), 166 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_filter.c b/babeld/babel_filter.c index 5c93d13a..191a9f77 100644 --- a/babeld/babel_filter.c +++ b/babeld/babel_filter.c @@ -45,144 +45,80 @@ THE SOFTWARE. #include "distribute.h" #include "util.h" - int -babel_filter_in (struct prefix *p, babel_interface_nfo *babel_ifp) +babel_filter(int output, const unsigned char *prefix, unsigned short plen, + unsigned int ifindex) { + struct interface *ifp = if_lookup_by_index(ifindex); + babel_interface_nfo *babel_ifp = ifp ? babel_get_if_nfo(ifp) : NULL; + struct prefix p; struct distribute *dist; struct access_list *alist; struct prefix_list *plist; + int filter = output ? BABEL_FILTER_OUT : BABEL_FILTER_IN; + int distribute = output ? DISTRIBUTE_OUT : DISTRIBUTE_IN; + + p.family = v4mapped(prefix) ? AF_INET : AF_INET6; + p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; + if (p.family == AF_INET) + uchar_to_inaddr(&p.u.prefix4, prefix); + else + uchar_to_in6addr(&p.u.prefix6, prefix); - /* Input distribute-list filtering. */ - if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_IN]) { - if (access_list_apply (babel_ifp->list[BABEL_FILTER_IN], p) + if (babel_ifp != NULL && babel_ifp->list[filter]) { + if (access_list_apply (babel_ifp->list[filter], &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; + p.family == AF_INET ? + inet_ntoa(p.u.prefix4) : + inet6_ntoa (p.u.prefix6), + p.prefixlen); + return INFINITY; } } - if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_IN]) { - if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_IN], p) + if (babel_ifp != NULL && babel_ifp->prefix[filter]) { + if (prefix_list_apply (babel_ifp->prefix[filter], &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; + p.family == AF_INET ? + inet_ntoa(p.u.prefix4) : + inet6_ntoa (p.u.prefix6), + p.prefixlen); + return INFINITY; } } /* All interface filter check. */ dist = distribute_lookup (NULL); if (dist) { - if (dist->list[DISTRIBUTE_IN]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_IN]); + if (dist->list[distribute]) { + alist = access_list_lookup (AFI_IP6, dist->list[distribute]); if (alist) { - if (access_list_apply (alist, p) == FILTER_DENY) { + if (access_list_apply (alist, &p) == FILTER_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; + p.family == AF_INET ? + inet_ntoa(p.u.prefix4) : + inet6_ntoa (p.u.prefix6), + p.prefixlen); + return INFINITY; } } } - if (dist->prefix[DISTRIBUTE_IN]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_IN]); + if (dist->prefix[distribute]) { + plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]); if (plist) { - if (prefix_list_apply (plist, p) == PREFIX_DENY) { + if (prefix_list_apply (plist, &p) == PREFIX_DENY) { debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute in", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; - } - } - } - } - return 0; -} - -int -babel_filter_out (struct prefix *p, babel_interface_nfo *babel_ifp) -{ - struct distribute *dist; - struct access_list *alist; - struct prefix_list *plist; - - if (babel_ifp != NULL && babel_ifp->list[BABEL_FILTER_OUT]) { - if (access_list_apply (babel_ifp->list[BABEL_FILTER_OUT], p) - == FILTER_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; - } - } - if (babel_ifp != NULL && babel_ifp->prefix[BABEL_FILTER_OUT]) { - if (prefix_list_apply (babel_ifp->prefix[BABEL_FILTER_OUT], p) - == PREFIX_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; - } - } - - /* All interface filter check. */ - dist = distribute_lookup (NULL); - if (dist) { - if (dist->list[DISTRIBUTE_OUT]) { - alist = access_list_lookup (AFI_IP6, dist->list[DISTRIBUTE_OUT]); - if (alist) { - if (access_list_apply (alist, p) == FILTER_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; - } - } - } - if (dist->prefix[DISTRIBUTE_OUT]) { - plist = prefix_list_lookup (AFI_IP6, dist->prefix[DISTRIBUTE_OUT]); - if (plist) { - if (prefix_list_apply (plist, p) == PREFIX_DENY) { - debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute out", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return -1; + p.family == AF_INET ? + inet_ntoa(p.u.prefix4) : + inet6_ntoa (p.u.prefix6), + p.prefixlen); + return INFINITY; } } } } return 0; } - -int -babel_filter_redistribute (struct prefix *p, - babel_interface_nfo *babel_ifp) -{ - debugf(BABEL_DEBUG_FILTER, "%s/%d WARNING: no redistribute filter implemented !!!!", - p->family == AF_INET ? - inet_ntoa(p->u.prefix4) : - inet6_ntoa (p->u.prefix6), - p->prefixlen); - return 0; /* TODO: it redistributes always */ -} diff --git a/babeld/babel_filter.h b/babeld/babel_filter.h index 52b72f60..73722e0a 100644 --- a/babeld/babel_filter.h +++ b/babeld/babel_filter.h @@ -43,12 +43,7 @@ THE SOFTWARE. #include "prefix.h" #include "babel_interface.h" -/* filter route coming from other worlds */ -int babel_filter_in (struct prefix *, babel_interface_nfo *); -/* filter route sending to other worlds */ -int babel_filter_out (struct prefix *, babel_interface_nfo *); -/* filter route coming from our friend zebra */ -int babel_filter_redistribute - (struct prefix *, babel_interface_nfo *); +int babel_filter(int output, const unsigned char *prefix, unsigned short plen, + unsigned int index); #endif /* BABELD_BABEL_FILTER_H */ diff --git a/babeld/babeld.c b/babeld/babeld.c index da074349..14990a68 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -705,71 +705,30 @@ babeld_quagga_init(void) distribute_list_delete_hook (babel_distribute_update); } -int /* DEPRECATED: for compatibility with old babeld (configuration.{c,h})*/ +/* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ + +int input_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, const unsigned char *neigh, unsigned int ifindex) { - struct interface *ifp = NULL; - struct prefix p; - p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; - if (p.family == AF_INET) { - uchar_to_inaddr(&p.u.prefix4, prefix); - } else { - uchar_to_in6addr(&p.u.prefix6, prefix); - } - - ifp = if_lookup_by_index(ifindex); - if (ifp != NULL) { - return babel_filter_in(&p, babel_get_if_nfo(ifp)); - } - - return babel_filter_in(&p, NULL); + return babel_filter(0, prefix, plen, ifindex); } -int /* DEPRECATED: for compatibility with old babeld */ +int output_filter(const unsigned char *id, const unsigned char *prefix, unsigned short plen, unsigned int ifindex) { - struct interface *ifp = NULL; - struct prefix p; - p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; - if (p.family == AF_INET) { - uchar_to_inaddr(&p.u.prefix4, prefix); - } else { - uchar_to_in6addr(&p.u.prefix6, prefix); - } - - ifp = if_lookup_by_index(ifindex); - if (ifp != NULL) { - return babel_filter_out(&p, babel_get_if_nfo(ifp)); - } - - return babel_filter_out(&p, NULL); + return babel_filter(1, prefix, plen, ifindex); } -int /* DEPRECATED: for compatibility with old babeld */ +/* There's no redistribute filter in Quagga -- the zebra daemon does its + own filtering. */ +int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto) { - struct interface *ifp = NULL; - struct prefix p; - p.family = v4mapped(prefix) ? AF_INET : AF_INET6; - p.prefixlen = v4mapped(prefix) ? plen - 96 : plen; - if (p.family == AF_INET) { - uchar_to_inaddr(&p.u.prefix4, prefix); - } else { - uchar_to_in6addr(&p.u.prefix6, prefix); - } - - ifp = if_lookup_by_index(ifindex); - if (ifp != NULL) { - return babel_filter_redistribute(&p,babel_get_if_nfo(ifp)); - } - - return babel_filter_redistribute(&p, NULL); + return 0; } void -- cgit v1.2.1 From d70ab9dcd8f054ebd5f60a29dbbd9b39f9fe7566 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Thu, 9 Feb 2012 17:23:09 +0100 Subject: babeld: Add support for blackhole routes. Babel makes use of blackhole routes to prevent routing loops between overlapping prefixes shortly after a route is retracted (see RFC 6126 sections 2.8 and 3.5.5). This patch adds support for installing such blackhole routes. --- babeld/kernel_zebra.c | 64 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 21 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 1df4217f..d262a86b 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -186,12 +186,16 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, correctly. */ SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; api.ifindex_num = 0; - - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; + if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.nexthop_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } debugf(BABEL_DEBUG_ROUTE, "adding route (ipv4) to zebra"); return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, @@ -226,13 +230,18 @@ kernel_route_add_v6(const unsigned char *pref, unsigned short plen, api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; + if(metric >= KERNEL_INFINITY) { + api.nexthop_num = 0; + api.ifindex_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } debugf(BABEL_DEBUG_ROUTE, "adding route (ipv6) to zebra"); return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, @@ -267,11 +276,16 @@ kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; api.ifindex_num = 0; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; + if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.nexthop_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } debugf(BABEL_DEBUG_ROUTE, "removing route (ipv4) to zebra"); return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, @@ -307,11 +321,19 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, api.message = 0; api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; + if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; + api.nexthop_num = 0; + api.ifindex_num = 0; + } else { + api.nexthop_num = 1; + api.nexthop = &nexthop_pointer; + SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); + api.ifindex_num = 1; + api.ifindex = &tmp_ifindex; + SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); + api.metric = metric; + } debugf(BABEL_DEBUG_ROUTE, "removing route (ipv6) to zebra"); return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, -- cgit v1.2.1 From 3c442e8802c260a0ce9787b5f432a7a2a093be25 Mon Sep 17 00:00:00 2001 From: Matthieu Boutier Date: Wed, 8 Feb 2012 23:30:46 +0100 Subject: babeld: fix wire{d,less} commands name. --- babeld/babel_interface.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 047a6ebf..42a9e0ea 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -347,7 +347,7 @@ DEFUN (no_babel_network, /* [Interface Command] Tell the interface is wire. */ DEFUN (babel_set_wired, babel_set_wired_cmd, - "wired", + "babel wired", "Set this interface as wired (default: wireless).\n" "No attributes") { @@ -365,7 +365,7 @@ DEFUN (babel_set_wired, /* [Interface Command] Tell the interface is wireless (default). */ DEFUN (babel_set_wireless, babel_set_wireless_cmd, - "wireless", + "babel wireless", NO_STR "Set this interface as wireless (is default).\n" "No attributes") -- cgit v1.2.1 From 359be3d0e4db5c931b1ad0dabbac2dea77394de1 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 11 Feb 2012 15:25:01 +0400 Subject: babeld: dismiss babel_redistribute_unset() The function was effectively duplicating existing zclient_redistribute(). This makes no_babel_redistribute_type() consistent with babel_redistribute_type() --- babeld/babel_zebra.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index eced995e..ed6566f7 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -186,23 +186,6 @@ babel_zebra_read_ipv4 (int command, struct zclient *zclient, return 0; } -static int -babel_redistribute_unset (int type) -{ - if (! zclient->redist[type]) - return CMD_SUCCESS; - - zclient->redist[type] = 0; - - if (zclient->sock > 0) - zebra_redistribute_send (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); - - /* perhaps should we remove xroutes having the same type... */ - - return CMD_SUCCESS; -} - - /* [Babel Command] */ DEFUN (babel_redistribute_type, babel_redistribute_type_cmd, @@ -246,7 +229,9 @@ DEFUN (no_babel_redistribute_type, return CMD_WARNING; } - return babel_redistribute_unset (type); + zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type); + /* perhaps should we remove xroutes having the same type... */ + return CMD_SUCCESS; } #ifndef NO_DEBUG -- cgit v1.2.1 From 52d54422bdc0b70356d84a38a0ce15ba5dea03e0 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 13:08:00 +0100 Subject: Resynchronise with babeld-1.3.1. --- babeld/babel_interface.c | 34 ---------------------------------- babeld/babel_interface.h | 4 ---- babeld/babel_main.c | 35 ++++++++++++++--------------------- babeld/babel_main.h | 4 ++-- babeld/message.c | 43 ++++++++++++------------------------------- babeld/resend.c | 4 ++-- babeld/resend.h | 2 +- babeld/route.c | 2 +- 8 files changed, 32 insertions(+), 96 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 42a9e0ea..0f254ecc 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -467,38 +467,6 @@ DEFUN (no_babel_passive_interface, return CMD_SUCCESS; } - -int -interface_idle(babel_interface_nfo *babel_ifp) -{ - return (idle_hello_interval > 0 && - babel_ifp->activity_time < babel_now.tv_sec - idle_time); -} - -int -update_hello_interval(struct interface *ifp) -{ - int rc = 0; - unsigned short interval; - struct babel_interface *babel_ifp = babel_get_if_nfo(ifp); - - if(interface_idle(babel_ifp)) - interval = idle_hello_interval; - else if(IF_CONF(ifp, hello_interval) > 0) - interval = IF_CONF(ifp, hello_interval); - else if((ifp->flags & BABEL_IF_WIRED)) - interval = wired_hello_interval; - else - interval = wireless_hello_interval; - - if(babel_ifp->hello_interval != interval) { - babel_ifp->hello_interval = interval; - rc = 1; - } - - return rc; -} - /* This should be no more than half the hello interval, so that hellos aren't sent late. The result is in milliseconds. */ unsigned @@ -577,7 +545,6 @@ interface_recalculate(struct interface *ifp) babel_ifp->flags |= BABEL_IF_LQ; } - babel_ifp->activity_time = babel_now.tv_sec; /* Since the interface was marked as active above, the idle_hello_interval cannot be the one being used here. */ babel_ifp->update_interval = babel_ifp->hello_interval * 4; @@ -1004,7 +971,6 @@ babel_interface_allocate (void) /* Here are set the default values for an interface. */ memset(babel_ifp, 0, sizeof(babel_interface_nfo)); /* All flags are unset */ - babel_ifp->activity_time = babel_now.tv_sec; babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (random() & 0xFFFF); diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index ec69bff4..579dc043 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -71,7 +71,6 @@ struct babel_interface { int update_bufsize; time_t bucket_time; unsigned int bucket; - time_t activity_time; time_t last_update_time; unsigned short hello_seqno; unsigned hello_interval; @@ -142,9 +141,6 @@ int babel_interface_delete (int, struct zclient *, zebra_size_t); int babel_interface_address_add (int, struct zclient *, zebra_size_t); int babel_interface_address_delete (int, struct zclient *, zebra_size_t); -/* others functions */ -int interface_idle(babel_interface_nfo *); -int update_hello_interval(struct interface *ifp); unsigned jitter(babel_interface_nfo *, int); unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); /* return "true" if "address" is one of our ipv6 addresses */ diff --git a/babeld/babel_main.c b/babeld/babel_main.c index a75171e0..f2db0b37 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -79,10 +79,9 @@ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ int debug = BABEL_DEBUG_COMMON; -int idle_time = 320; -int wireless_hello_interval = -1; -int wired_hello_interval = -1; -int idle_hello_interval = -1; +int default_wireless_hello_interval = -1; +int default_wired_hello_interval = -1; +int resend_delay = -1; static const char *pidfile = PATH_BABELD_PID; const unsigned char zeroes[16] = {0}; @@ -259,17 +258,19 @@ babel_init(int argc, char **argv) vty_init (master); memory_init (); - /* babeld inits (default options) */ - /* set default interval's values */ - if(wireless_hello_interval <= 0) - wireless_hello_interval = 4000; - wireless_hello_interval = MAX(wireless_hello_interval, 5); + if(default_wireless_hello_interval <= 0) + default_wireless_hello_interval = 4000; + default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5); - if(wired_hello_interval <= 0) - wired_hello_interval = 4000; - wired_hello_interval = MAX(wired_hello_interval, 5); + if(default_wired_hello_interval <= 0) + default_wired_hello_interval = 4000; + default_wired_hello_interval = MAX(default_wired_hello_interval, 5); + + resend_delay = 2000; + resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2); + resend_delay = MIN(resend_delay, default_wired_hello_interval / 2); + resend_delay = MAX(resend_delay, 20); - /* an assertion */ if(parasitic && allow_duplicates >= 0) { /* Too difficult to get right. */ zlog_err("Sorry, -P and -A are incompatible."); @@ -561,10 +562,6 @@ show_babel_main_configuration (struct vty *vty) "vty address = %s%s" "vty port = %d%s" "id = %s%s" - "idle time = %d%s" - "wireless hello interval = %d%s" - "wired hello interval = %d%s" - "idle hello interval = %d%s" "parasitic = %s%s" "split-horizon = %s%s" "allow_duplicates = %s%s" @@ -580,10 +577,6 @@ show_babel_main_configuration (struct vty *vty) VTY_NEWLINE, babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, - idle_time, VTY_NEWLINE, - wireless_hello_interval, VTY_NEWLINE, - wired_hello_interval, VTY_NEWLINE, - idle_hello_interval, VTY_NEWLINE, format_bool(parasitic), VTY_NEWLINE, format_bool(split_horizon), VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, diff --git a/babeld/babel_main.h b/babeld/babel_main.h index 2afebc9e..4c08e181 100644 --- a/babeld/babel_main.h +++ b/babeld/babel_main.h @@ -41,8 +41,8 @@ THE SOFTWARE. extern struct timeval babel_now; /* current time */ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; -extern int wireless_hello_interval, wired_hello_interval, idle_hello_interval; -extern int idle_time; +extern int default_wireless_hello_interval, default_wired_hello_interval; +extern int resend_delay; extern unsigned char myid[8]; diff --git a/babeld/message.c b/babeld/message.c index 8cd1db63..e86b4325 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -282,7 +282,6 @@ parse_packet(const unsigned char *from, struct interface *ifp, debugf(BABEL_DEBUG_COMMON,"Received hello %d (%d) from %s on %s.", seqno, interval, format_address(from), ifp->name); - babel_get_if_nfo(ifp)->activity_time = babel_now.tv_sec; changed = update_neighbour(neigh, seqno, interval); update_neighbour_metric(neigh, changed); if(interval > 0) @@ -466,7 +465,8 @@ parse_packet(const unsigned char *from, struct interface *ifp, update storm. Ignore a wildcard request that happens shortly after we sent a full update. */ if(babel_ifp->last_update_time < - babel_now.tv_sec - MAX(babel_ifp->hello_interval / 100, 1)) + (time_t)(babel_now.tv_sec - + MAX(babel_ifp->hello_interval / 100, 1))) send_update(neigh->ifp, 0, NULL, 0); } else { send_update(neigh->ifp, 0, prefix, plen); @@ -755,12 +755,10 @@ send_hello_noupdate(struct interface *ifp, unsigned interval) void send_hello(struct interface *ifp) { - int changed; - changed = update_hello_interval(ifp); babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); send_hello_noupdate(ifp, (babel_ifp->hello_interval + 9) / 10); /* Send full IHU every 3 hellos, and marginal IHU each time */ - if(changed || babel_ifp->hello_seqno % 3 == 0) + if(babel_ifp->hello_seqno % 3 == 0) send_ihu(NULL, ifp); else send_marginal_ihu(ifp); @@ -1161,13 +1159,11 @@ send_update(struct interface *ifp, int urgent, buffer_update(ifp, prefix, plen); } } else { - if(!interface_idle(babel_ifp)) { - send_self_update(ifp); - if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", - ifp->name); - for_all_installed_routes(buffer_update_callback, ifp); - } + send_self_update(ifp); + if(!parasitic) { + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", + ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); } set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; @@ -1179,17 +1175,10 @@ void send_update_resend(struct interface *ifp, const unsigned char *prefix, unsigned char plen) { - int delay; - assert(prefix != NULL); send_update(ifp, 1, prefix, plen); - - delay = 2000; - delay = MIN(delay, wireless_hello_interval / 2); - delay = MIN(delay, wired_hello_interval / 2); - delay = MAX(delay, 10); - record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, delay); + record_resend(RESEND_UPDATE, prefix, plen, 0, 0, NULL, resend_delay); } void @@ -1249,10 +1238,8 @@ send_self_update(struct interface *ifp) return; } - if(!interface_idle(babel_get_if_nfo(ifp))) { - debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); - for_all_xroutes(send_xroute_update_callback, ifp); - } + debugf(BABEL_DEBUG_COMMON,"Sending self update to %s.", ifp->name); + for_all_xroutes(send_xroute_update_callback, ifp); } void @@ -1501,19 +1488,13 @@ send_request_resend(struct neighbour *neigh, const unsigned char *prefix, unsigned char plen, unsigned short seqno, unsigned char *id) { - int delay; - if(neigh) send_unicast_multihop_request(neigh, prefix, plen, seqno, id, 127); else send_multihop_request(NULL, prefix, plen, seqno, id, 127); - delay = 2000; - delay = MIN(delay, wireless_hello_interval / 2); - delay = MIN(delay, wired_hello_interval / 2); - delay = MAX(delay, 10); record_resend(RESEND_REQUEST, prefix, plen, seqno, id, - neigh ? neigh->ifp : NULL, delay); + neigh ? neigh->ifp : NULL, resend_delay); } void diff --git a/babeld/resend.c b/babeld/resend.c index 5a786fcd..1cc6290e 100644 --- a/babeld/resend.c +++ b/babeld/resend.c @@ -123,7 +123,7 @@ record_resend(int kind, const unsigned char *prefix, unsigned char plen, else if(delay) resend->delay = delay; resend->time = babel_now; - resend->max = kind == RESEND_REQUEST ? 128 : UPDATE_MAX; + resend->max = RESEND_MAX; if(id && memcmp(resend->id, id, 8) == 0 && seqno_compare(resend->seqno, seqno) > 0) { return 0; @@ -140,7 +140,7 @@ record_resend(int kind, const unsigned char *prefix, unsigned char plen, if(resend == NULL) return -1; resend->kind = kind; - resend->max = kind == RESEND_REQUEST ? 128 : UPDATE_MAX; + resend->max = RESEND_MAX; resend->delay = delay; memcpy(resend->prefix, prefix, 16); resend->plen = plen; diff --git a/babeld/resend.h b/babeld/resend.h index fdb57300..a6755c0e 100644 --- a/babeld/resend.h +++ b/babeld/resend.h @@ -37,7 +37,7 @@ THE SOFTWARE. */ #define REQUEST_TIMEOUT 65000 -#define UPDATE_MAX 4 +#define RESEND_MAX 3 #define RESEND_REQUEST 1 #define RESEND_UPDATE 2 diff --git a/babeld/route.c b/babeld/route.c index a9ffc5d9..fe2b9ceb 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -682,7 +682,7 @@ update_route(const unsigned char *router_id, int hold_time = MAX((4 * interval) / 100 + interval / 50, 15); if(memcmp(router_id, myid, 8) == 0) - return NULL; /* I have announced the route */ + return NULL; if(martian_prefix(prefix, plen)) { zlog_err("Rejecting martian route to %s through %s.", -- cgit v1.2.1 From b58871ee4d54989c16a60a839a592c9c4ab19cc3 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 13:34:30 +0100 Subject: babeld: remove port and group setting commands. They didn't work anyway, since they're called too late. --- babeld/babeld.c | 47 ----------------------------------------------- 1 file changed, 47 deletions(-) (limited to 'babeld') diff --git a/babeld/babeld.c b/babeld/babeld.c index 14990a68..f42a81b6 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -629,53 +629,6 @@ DEFUN (no_router_babel, return CMD_SUCCESS; } -/* [Babel Command] */ -DEFUN (babel_set_protocol_group, - babel_set_protocol_group_cmd, - "protocol group ADDR", - "Set the protocol group, default is ff02::1:6.\n" - "IPv6 address") -{ - int ret; - struct prefix p; - - ret = str2prefix (argv[0], &p); - - /* Given string is: */ - if (ret) { /* an IPv4 or v6 network */ - if (p.family != AF_INET6) { - return CMD_WARNING; - } - in6addr_to_uchar(protocol_group, &p.u.prefix6); - } else { /* an interface name */ - return CMD_WARNING; - } - - if (ret < 0) { - vty_out (vty, "%s must be an ipv6 address%s", argv[0], - VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; -} - -/* [Babel Command] */ -DEFUN (babel_set_protocol_port, - babel_set_protocol_port_cmd, - "protocol port <1-65535>", - "Set the protocol port (default is defined in RFC).\n" - "IPv6 address") -{ - int port; - - VTY_GET_INTEGER_RANGE("port", port, argv[0], 1, 0xFFFF); - - protocol_port = port; - return CMD_SUCCESS; -} - - void babeld_quagga_init(void) { -- cgit v1.2.1 From c428edba5fb151844d28fbb41fce1df466a74e42 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 14:02:10 +0100 Subject: babeld: vty commands (hello-interval, update-interval, resend-delay). --- babeld/babel_interface.c | 67 +++++++++++++++++++++++++++++++----------------- babeld/babeld.c | 17 ++++++++++++ 2 files changed, 61 insertions(+), 23 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 0f254ecc..bc58b7e3 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -293,7 +293,7 @@ babel_enable_if_delete (const char *ifname) DEFUN (babel_network, babel_network_cmd, "network IF_OR_ADDR", - "Babel enable on specified interface or network.\n" + "Enable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; @@ -321,7 +321,7 @@ DEFUN (no_babel_network, no_babel_network_cmd, "no network IF_OR_ADDR", NO_STR - "Babel enable on specified interface or network.\n" + "Disable Babel protocol on specified interface or network.\n" "Interface or address") { int ret; @@ -348,8 +348,8 @@ DEFUN (no_babel_network, DEFUN (babel_set_wired, babel_set_wired_cmd, "babel wired", - "Set this interface as wired (default: wireless).\n" - "No attributes") + "Babel interface commands\n" + "Enable wired optimisations") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -366,9 +366,8 @@ DEFUN (babel_set_wired, DEFUN (babel_set_wireless, babel_set_wireless_cmd, "babel wireless", - NO_STR - "Set this interface as wireless (is default).\n" - "No attributes") + "Babel interface commands\n" + "Disable wired optimiations (assume wireless)") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -385,9 +384,8 @@ DEFUN (babel_set_wireless, DEFUN (babel_split_horizon, babel_split_horizon_cmd, "babel split-horizon", - IPV6_STR - "Perform split horizon\n" - "No attributes\n") + "Babel interface commands\n" + "Enable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -405,9 +403,8 @@ DEFUN (no_babel_split_horizon, no_babel_split_horizon_cmd, "no babel split-horizon", NO_STR - IPV6_STR - "Disable split horizon\n" - "No attributes\n") + "Babel interface commands\n" + "Disable split horizon processing") { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -423,15 +420,16 @@ DEFUN (no_babel_split_horizon, /* [Interface Command]. */ DEFUN (babel_set_hello_interval, babel_set_hello_interval_cmd, - "hello interval <5-1000000>", - "Set interface's hello interval (default: 4000).\n" - "Value in miliseconds\n") + "babel hello-interval <20-655340>", + "Babel interface commands\n" + "Time between scheduled hellos\n" + "Milliseconds\n") { struct interface *ifp; babel_interface_nfo *babel_ifp; int interval; - VTY_GET_INTEGER_RANGE("hello interval", interval, argv[0], 20, 10 * 0xFFFE); + VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); ifp = vty->index; babel_ifp = babel_get_if_nfo(ifp); @@ -441,12 +439,34 @@ DEFUN (babel_set_hello_interval, return CMD_SUCCESS; } +/* [Interface Command]. */ +DEFUN (babel_set_update_interval, + babel_set_update_interval_cmd, + "babel update-interval <20-655340>", + "Babel interface commands\n" + "Time between scheduled updates\n" + "Milliseconds\n") +{ + struct interface *ifp; + babel_interface_nfo *babel_ifp; + int interval; + + VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); + + ifp = vty->index; + babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); + + babel_ifp->update_interval = interval; + return CMD_SUCCESS; +} + /* [Interface Command]. */ DEFUN (babel_passive_interface, babel_passive_interface_cmd, - "passive-interface", - "The daemon will only announce redistributed routes\n" - "No attributes\n") + "babel passive-interface", + "Babel interface commands\n" + "Only announce redistributed routes on this interface\n") { if (allow_duplicates) { return CMD_WARNING; @@ -458,10 +478,10 @@ DEFUN (babel_passive_interface, /* [Interface Command]. */ DEFUN (no_babel_passive_interface, no_babel_passive_interface_cmd, - "no passive-interface", + "no babel passive-interface", NO_STR - "The daemon will announce all (filtred) routes\n" - "No attributes\n") + "Babel interface commands\n" + "Announce all routes on this interface\n") { parasitic = 0; return CMD_SUCCESS; @@ -899,6 +919,7 @@ babel_if_init () install_element(INTERFACE_NODE, &babel_set_wired_cmd); install_element(INTERFACE_NODE, &babel_set_wireless_cmd); install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); + install_element(INTERFACE_NODE, &babel_set_update_interval_cmd); install_element(INTERFACE_NODE, &babel_passive_interface_cmd); install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); diff --git a/babeld/babeld.c b/babeld/babeld.c index f42a81b6..07dd92a3 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -629,6 +629,22 @@ DEFUN (no_router_babel, return CMD_SUCCESS; } +/* [Babel Command] */ +DEFUN (babel_set_resend_delay, + babel_set_resend_delay_cmd, + "babel resend-delay <20-655340>", + "Babel commands\n" + "Time before resending a message\n" + "Milliseconds\n") +{ + int interval; + + VTY_GET_INTEGER_RANGE("milliseconds", interval, argv[0], 20, 10 * 0xFFFE); + + resend_delay = interval; + return CMD_SUCCESS; +} + void babeld_quagga_init(void) { @@ -639,6 +655,7 @@ babeld_quagga_init(void) install_element(CONFIG_NODE, &no_router_babel_cmd); install_default(BABEL_NODE); + install_element(BABEL_NODE, &babel_set_resend_delay_cmd); babel_if_init(); -- cgit v1.2.1 From 9c298c7119c1dba6c589b8f4c358debd8e694b72 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 14:06:24 +0100 Subject: babeld: display update-interval and resend-delay in show commands" --- babeld/babel_interface.c | 1 + babeld/babel_main.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index bc58b7e3..588fea70 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -732,6 +732,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp) vty_out (vty, " Split horizon mode is %s%s", CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON) ? "On" : "Off", VTY_NEWLINE); vty_out (vty, " Hello interval is %u ms%s", babel_ifp->hello_interval, VTY_NEWLINE); + vty_out (vty, " Update interval is %u ms%s", babel_ifp->update_interval, VTY_NEWLINE); } DEFUN (show_babel_interface, diff --git a/babeld/babel_main.c b/babeld/babel_main.c index f2db0b37..e5764942 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -563,7 +563,7 @@ show_babel_main_configuration (struct vty *vty) "vty port = %d%s" "id = %s%s" "parasitic = %s%s" - "split-horizon = %s%s" + "resend-delay = %d%s" "allow_duplicates = %s%s" "kernel_metric = %d%s", pidfile, VTY_NEWLINE, @@ -578,7 +578,7 @@ show_babel_main_configuration (struct vty *vty) babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, format_bool(parasitic), VTY_NEWLINE, - format_bool(split_horizon), VTY_NEWLINE, + resend_delay, VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, kernel_metric, VTY_NEWLINE); } -- cgit v1.2.1 From ce590ecd85b3cf32c5429f09e12d92248cc01ef2 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Sat, 11 Feb 2012 17:48:05 +0100 Subject: Remove dead variable reboot_time. Thanks to Denis Ovsienko. --- babeld/babel_main.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_main.c b/babeld/babel_main.c index e5764942..4cb2d83e 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -379,8 +379,6 @@ babel_replace_by_null(int fd) void babel_load_state_file(void) { - time_t reboot_time; - reboot_time = babel_now.tv_sec; int fd; int rc; @@ -422,9 +420,6 @@ babel_load_state_file(void) zlog_err("ID mismatch in babel-state. id=%s; old=%s", format_eui64(myid), format_eui64(sid)); - /* Convert realtime into monotonic time. */ - if(t >= 1176800000L && t <= realnow.tv_sec) - reboot_time = babel_now.tv_sec - (realnow.tv_sec - t); } } else { zlog_err("Couldn't parse babel-state."); -- cgit v1.2.1 From a14ef5eeccc8c76c41830475bbe3c31c9e14faa5 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Sat, 11 Feb 2012 21:06:16 +0400 Subject: babeld: justify "running-config" meaning in CLI The primary focus of this commit is to make "show running-config" command display more current configuration, including some of the bits previously seen in the output of "show babel running-config". Besides that, the following commands were renamed for consistency with the syntax of other components: "debug *" to "debug babel *" (and moved to top level) "show babel running-config" to "show babel parameters" * babel_interface.c * show_babel_running_config(): rename to show_babel_parameters(), update syntax pattern, don't call show_babeld_configuration() * babel_if_init(): update respectively * babel_enable_if_config_write(): new VTY helper for static babel_enable_if * babel_interface.h: add extern declaration * babel_main.c: unset all debug options by default * show_babel_main_configuration(): remove debug options decoder * babel_zebra.c * babel_debug(): rename to debug_babel(), update syntax pattern * no_babel_debug(): rename to no_debug_babel(), update syntax pattern * babelz_zebra_init(): update respectively * debug_babel_config_write() new VTY helper for static debug_type * babel_zebra.h: add extern declaration * babeld.c * babel_config_write(): add the code to output "debug babel *", "router babel", "redistribute *" and "network *" statements * show_babeld_configuration(): dismiss * babeld.h: remove extern declaration * babeld.texi: update for renamed commands * babeld.conf.sample: idem, add debug statements block --- babeld/babel_interface.c | 27 ++++++++++++++++++------ babeld/babel_interface.h | 2 ++ babeld/babel_main.c | 26 +---------------------- babeld/babel_zebra.c | 53 ++++++++++++++++++++++++++++++++++++++++------- babeld/babel_zebra.h | 7 +++++++ babeld/babeld.c | 28 ++++++++++++++++++------- babeld/babeld.conf.sample | 14 ++++++++++--- babeld/babeld.h | 1 - 8 files changed, 108 insertions(+), 50 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 588fea70..404be7a2 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -877,9 +877,9 @@ DEFUN (show_babel_database, return CMD_SUCCESS; } -DEFUN (show_babel_running_config, - show_babel_running_config_cmd, - "show babel running-config", +DEFUN (show_babel_parameters, + show_babel_parameters_cmd, + "show babel parameters", SHOW_STR IP_STR "Babel information\n" @@ -888,7 +888,6 @@ DEFUN (show_babel_running_config, { vty_out(vty, " -- Babel running configuration --%s", VTY_NEWLINE); show_babel_main_configuration(vty); - show_babeld_configuration(vty); vty_out(vty, " -- distribution lists --%s", VTY_NEWLINE); config_show_distribute(vty); @@ -931,8 +930,8 @@ babel_if_init () install_element(ENABLE_NODE, &show_babel_neighbour_cmd); install_element(VIEW_NODE, &show_babel_database_cmd); install_element(ENABLE_NODE, &show_babel_database_cmd); - install_element(VIEW_NODE, &show_babel_running_config_cmd); - install_element(ENABLE_NODE, &show_babel_running_config_cmd); + install_element(VIEW_NODE, &show_babel_parameters_cmd); + install_element(ENABLE_NODE, &show_babel_parameters_cmd); } /* hooks: functions called respectively when struct interface is @@ -980,6 +979,22 @@ interface_config_write (struct vty *vty) return write; } +/* Output a "network" statement line for each of the enabled interfaces. */ +int +babel_enable_if_config_write (struct vty * vty) +{ + unsigned int i, lines = 0; + char *str; + + for (i = 0; i < vector_active (babel_enable_if); i++) + if ((str = vector_slot (babel_enable_if, i)) != NULL) + { + vty_out (vty, " network %s%s", str, VTY_NEWLINE); + lines++; + } + return lines; +} + /* functions to allocate or free memory for a babel_interface_nfo, filling needed fields */ static babel_interface_nfo * diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index 579dc043..1761e3d9 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -41,6 +41,7 @@ THE SOFTWARE. #include #include "zclient.h" +#include "vty.h" #define CONFIG_DEFAULT 0 #define CONFIG_NO 1 @@ -147,6 +148,7 @@ unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent); int is_interface_ll_address(struct interface *ifp, const unsigned char *address); /* Send retraction to all, and reset all interfaces statistics. */ void babel_interface_close_all(void); +extern int babel_enable_if_config_write (struct vty *); #endif diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 4cb2d83e..3d83091b 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -77,7 +77,7 @@ struct thread_master *master; /* quagga's threads handler */ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ -int debug = BABEL_DEBUG_COMMON; +int debug = 0; int default_wireless_hello_interval = -1; int default_wired_hello_interval = -1; @@ -523,30 +523,6 @@ babel_save_state_file(void) void show_babel_main_configuration (struct vty *vty) { -#ifdef NO_DEBUG - vty_out(vty, "No debug.%s", VTY_NEWLINE); -#else - vty_out(vty, "Activated debug options:"); - if (debug == BABEL_DEBUG_ALL) { - vty_out(vty, " all%s", VTY_NEWLINE); - } else { - vty_out(vty, "%s%s%s%s%s%s%s%s%s%s%s%s%s", - debug & BABEL_DEBUG_COMMON ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_COMMON ? " common" : "", - debug & BABEL_DEBUG_KERNEL ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_KERNEL ? " kernel" : "", - debug & BABEL_DEBUG_FILTER ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_FILTER ? " filter" : "", - debug & BABEL_DEBUG_TIMEOUT ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_TIMEOUT ? " timeout" : "", - debug & BABEL_DEBUG_IF ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_IF ? " interface": "", - debug & BABEL_DEBUG_ROUTE ? VTY_NEWLINE : "", - debug & BABEL_DEBUG_ROUTE ? " route" : "", - VTY_NEWLINE); - } -#endif - vty_out(vty, "pid file = %s%s" "state file = %s%s" diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index ed6566f7..75a1e6a8 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -236,10 +236,11 @@ DEFUN (no_babel_redistribute_type, #ifndef NO_DEBUG /* [Babel Command] */ -DEFUN (babel_debug, - babel_debug_cmd, - "debug (common|kernel|filter|timeout|interface|route|all)", +DEFUN (debug_babel, + debug_babel_cmd, + "debug babel (common|kernel|filter|timeout|interface|route|all)", "Enable debug messages for specific or all part.\n" + "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" @@ -264,11 +265,12 @@ DEFUN (babel_debug, } /* [Babel Command] */ -DEFUN (no_babel_debug, - no_babel_debug_cmd, - "no debug (common|kernel|filter|timeout|interface|route|all)", +DEFUN (no_debug_babel, + no_debug_babel_cmd, + "no debug babel (common|kernel|filter|timeout|interface|route|all)", NO_STR "Disable debug messages for specific or all part.\n" + "Babel information\n" "Common messages (default)\n" "Kernel messages\n" "Filter messages\n" @@ -293,6 +295,39 @@ DEFUN (no_babel_debug, } #endif /* NO_DEBUG */ +/* Output "debug" statement lines, if necessary. */ +int +debug_babel_config_write (struct vty * vty) +{ +#ifdef NO_DEBUG + return 0; +#else + int i, lines = 0; + + if (debug == BABEL_DEBUG_ALL) + { + vty_out (vty, "debug babel all%s", VTY_NEWLINE); + lines++; + } + else + for (i = 0; debug_type[i].str != NULL; i++) + if + ( + debug_type[i].type != BABEL_DEBUG_ALL + && CHECK_FLAG (debug, debug_type[i].type) + ) + { + vty_out (vty, "debug babel %s%s", debug_type[i].str, VTY_NEWLINE); + lines++; + } + if (lines) + { + vty_out (vty, "!%s", VTY_NEWLINE); + lines++; + } + return lines; +#endif /* NO_DEBUG */ +} void babelz_zebra_init(void) { @@ -313,8 +348,10 @@ void babelz_zebra_init(void) install_node (&zebra_node, zebra_config_write); install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(BABEL_NODE, &no_babel_redistribute_type_cmd); - install_element(BABEL_NODE, &babel_debug_cmd); - install_element(BABEL_NODE, &no_babel_debug_cmd); + install_element(ENABLE_NODE, &debug_babel_cmd); + install_element(ENABLE_NODE, &no_debug_babel_cmd); + install_element(CONFIG_NODE, &debug_babel_cmd); + install_element(CONFIG_NODE, &no_debug_babel_cmd); } static int diff --git a/babeld/babel_zebra.h b/babeld/babel_zebra.h index 1b623f01..99601aa7 100644 --- a/babeld/babel_zebra.h +++ b/babeld/babel_zebra.h @@ -36,8 +36,15 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#ifndef BABEL_ZEBRA_H +#define BABEL_ZEBRA_H + +#include "vty.h" extern struct zclient *zclient; void babelz_zebra_init(void); void babel_zebra_close_connexion(void); +extern int debug_babel_config_write (struct vty *); + +#endif diff --git a/babeld/babeld.c b/babeld/babeld.c index 07dd92a3..9fea2e10 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -59,6 +59,7 @@ THE SOFTWARE. #include "message.h" #include "resend.h" #include "babel_filter.h" +#include "babel_zebra.h" static int babel_init_routing_process(struct thread *thread); @@ -92,7 +93,26 @@ static struct cmd_node cmd_babel_node = static int babel_config_write (struct vty *vty) { - return 0; + int lines = 0; + int i; + + /* list enabled debug modes */ + lines += debug_babel_config_write (vty); + + if (!babel_routing_process) + return lines; + vty_out (vty, "router babel%s", VTY_NEWLINE); + /* list enabled interfaces */ + lines = 1 + babel_enable_if_config_write (vty); + /* list redistributed protocols */ + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (i != zclient->redist_default && zclient->redist[i]) + { + vty_out (vty, " redistribute %s%s", zebra_route_string (i), VTY_NEWLINE); + lines++; + } + + return lines; } @@ -701,9 +721,3 @@ redistribute_filter(const unsigned char *prefix, unsigned short plen, return 0; } -void -show_babeld_configuration (struct vty *vty) -{ - vty_out(vty, "babeld running process %s.%s", - babel_routing_process ? "enable" : "disable", VTY_NEWLINE); -} diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample index e1585c1d..4eced433 100644 --- a/babeld/babeld.conf.sample +++ b/babeld/babeld.conf.sample @@ -1,13 +1,21 @@ +debug babel common +!debug babel kernel +!debug babel filter +!debug babel timeout +!debug babel interface +!debug babel route +!debug babel all + router babel ! network eth0 ! redistribute kernel ! no redistribute static !interface eth0 -! wired -! wireless +! babel wired +! babel wireless ! babel split-horizon ! no babel split-horizon ! log file /var/log/quagga/babeld.log -log stdout \ No newline at end of file +log stdout diff --git a/babeld/babeld.h b/babeld/babeld.h index 29bc5e8f..3c473230 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -132,7 +132,6 @@ extern int redistribute_filter(const unsigned char *prefix, unsigned short plen, unsigned int ifindex, int proto); extern int resize_receive_buffer(int size); extern void schedule_neighbours_check(int msecs, int override); -extern void show_babeld_configuration (struct vty *vty); #endif /* BABEL_BABELD_H */ -- cgit v1.2.1 From cb4b13d945a4b44282e59fa2be9ceda752420a13 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 13 Feb 2012 22:13:37 +0400 Subject: babeld: drive interface_config_write() forward --- babeld/babel_interface.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 404be7a2..24f56f38 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -951,7 +951,8 @@ babel_if_delete_hook (struct interface *ifp) return 0; } -/* Configuration write function for babeld. */ +/* Output an "interface" section for each of the known interfaces with +babeld-specific statement lines where appropriate. */ static int interface_config_write (struct vty *vty) { @@ -960,20 +961,27 @@ interface_config_write (struct vty *vty) int write = 0; for (ALL_LIST_ELEMENTS_RO (iflist, node, ifp)) { - /* Do not display the interface if there is no configuration about it */ - if (ifp->desc == NULL) - continue; - vty_out (vty, "interface %s%s", ifp->name, VTY_NEWLINE); if (ifp->desc) vty_out (vty, " description %s%s", ifp->desc, VTY_NEWLINE); - - /* TODO: to be completed... */ - + if (IS_ENABLE (ifp)) + { + babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); + /* wireless/no split-horizon is the default */ + if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) + { + vty_out (vty, " babel wired%s", VTY_NEWLINE); + write++; + } + if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) + { + vty_out (vty, " babel split-horizon%s", VTY_NEWLINE); + write++; + } + } vty_out (vty, "!%s", VTY_NEWLINE); - write++; } return write; -- cgit v1.2.1 From 36329c02c36703cc2158c1c99b86045fed26d4ae Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 08:49:57 +0100 Subject: babeld: remove remains of standalone babeld's configuration code. Standalone babeld has a configuration interface that is not used in Quagga. This removes a few bits of this code that survived the port to Quagga. --- babeld/babel_interface.c | 7 ++----- babeld/babel_interface.h | 2 -- babeld/babel_main.c | 15 +-------------- babeld/babel_main.h | 1 - babeld/babeld.h | 6 +++++- 5 files changed, 8 insertions(+), 23 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 24f56f38..2b5f9569 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -565,10 +565,6 @@ interface_recalculate(struct interface *ifp) babel_ifp->flags |= BABEL_IF_LQ; } - /* Since the interface was marked as active above, the - idle_hello_interval cannot be the one being used here. */ - babel_ifp->update_interval = babel_ifp->hello_interval * 4; - memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; @@ -1019,7 +1015,8 @@ babel_interface_allocate (void) babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (random() & 0xFFFF); - babel_ifp->hello_interval = BABELD_DEFAULT_HELLO_INTERVAL; + babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; + babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; return babel_ifp; diff --git a/babeld/babel_interface.h b/babeld/babel_interface.h index 1761e3d9..94fd8e5d 100644 --- a/babeld/babel_interface.h +++ b/babeld/babel_interface.h @@ -91,8 +91,6 @@ static inline babel_interface_nfo* babel_get_if_nfo(struct interface *ifp) return ((babel_interface_nfo*) ifp->info); } -#define IF_CONF(_ifp, _field) babel_get_if_nfo(_ifp)->_field - /* babel_interface_nfo flags */ #define BABEL_IF_IS_UP (1 << 0) #define BABEL_IF_WIRED (1 << 1) diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 3d83091b..0fcba749 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -79,8 +79,6 @@ struct timeval babel_now; /* current time */ unsigned char myid[8]; /* unique id (mac address of an interface) */ int debug = 0; -int default_wireless_hello_interval = -1; -int default_wired_hello_interval = -1; int resend_delay = -1; static const char *pidfile = PATH_BABELD_PID; @@ -258,18 +256,7 @@ babel_init(int argc, char **argv) vty_init (master); memory_init (); - if(default_wireless_hello_interval <= 0) - default_wireless_hello_interval = 4000; - default_wireless_hello_interval = MAX(default_wireless_hello_interval, 5); - - if(default_wired_hello_interval <= 0) - default_wired_hello_interval = 4000; - default_wired_hello_interval = MAX(default_wired_hello_interval, 5); - - resend_delay = 2000; - resend_delay = MIN(resend_delay, default_wireless_hello_interval / 2); - resend_delay = MIN(resend_delay, default_wired_hello_interval / 2); - resend_delay = MAX(resend_delay, 20); + resend_delay = BABEL_DEFAULT_RESEND_DELAY; if(parasitic && allow_duplicates >= 0) { /* Too difficult to get right. */ diff --git a/babeld/babel_main.h b/babeld/babel_main.h index 4c08e181..a4038dec 100644 --- a/babeld/babel_main.h +++ b/babeld/babel_main.h @@ -41,7 +41,6 @@ THE SOFTWARE. extern struct timeval babel_now; /* current time */ extern struct thread_master *master; /* quagga's threads handler */ extern int debug; -extern int default_wireless_hello_interval, default_wired_hello_interval; extern int resend_delay; extern unsigned char myid[8]; diff --git a/babeld/babeld.h b/babeld/babeld.h index 3c473230..b19ae0f2 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -107,7 +107,11 @@ THE SOFTWARE. #define BABEL_VTY_PORT 2609 #define BABEL_DEFAULT_CONFIG "babeld.conf" #define BABEL_VERSION "0.1 for quagga" -#define BABELD_DEFAULT_HELLO_INTERVAL 4000 /* miliseconds */ + +/* Values in milliseconds */ +#define BABEL_DEFAULT_HELLO_INTERVAL 4000 +#define BABEL_DEFAULT_UPDATE_INTERVAL 16000 +#define BABEL_DEFAULT_RESEND_DELAY 2000 /* Babel socket. */ -- cgit v1.2.1 From 46b92c043f1a83d8343a4a0345a7b69bac3cdf20 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 08:53:51 +0100 Subject: babeld: more helpful sample conf file. --- babeld/babeld.conf.sample | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/babeld.conf.sample b/babeld/babeld.conf.sample index 4eced433..a4924ec7 100644 --- a/babeld/babeld.conf.sample +++ b/babeld/babeld.conf.sample @@ -7,15 +7,24 @@ debug babel common !debug babel all router babel +! network wlan0 ! network eth0 ! redistribute kernel ! no redistribute static +! The defaults are fine for a wireless interface + +!interface wlan0 + +! A few optimisation tweaks are optional but recommended on a wired interface +! Disable link quality estimation, enable split horizon processing, and +! increase the hello and update intervals. + !interface eth0 ! babel wired -! babel wireless ! babel split-horizon -! no babel split-horizon +! babel hello-interval 12000 +! babel update-interval 36000 ! log file /var/log/quagga/babeld.log log stdout -- cgit v1.2.1 From 260948cdd6030b332137dfa0580d5a9ba651b145 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 09:09:32 +0100 Subject: babeld: set interface flags eagerly, not at interface up. --- babeld/babel_interface.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 2b5f9569..00d53bc6 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -288,7 +288,6 @@ babel_enable_if_delete (const char *ifname) return 1; } - /* [Babel Command] Babel enable on specified interface or matched network. */ DEFUN (babel_network, babel_network_cmd, @@ -344,6 +343,25 @@ DEFUN (no_babel_network, return CMD_SUCCESS; } +/* There are a number of interface parameters that must be changed when + an interface becomes wired/wireless. In Quagga, they cannot be + configured separately. */ + +static void +babel_set_wired_internal(babel_interface_nfo *babel_ifp, int wired) +{ + if(wired) { + babel_ifp->flags |= BABEL_IF_WIRED; + babel_ifp->cost = 96; + babel_ifp->flags &= ~BABEL_IF_LQ; + } else { + babel_ifp->flags &= ~BABEL_IF_WIRED; + babel_ifp->cost = 256; + babel_ifp->flags |= BABEL_IF_LQ; + } + +} + /* [Interface Command] Tell the interface is wire. */ DEFUN (babel_set_wired, babel_set_wired_cmd, @@ -358,7 +376,7 @@ DEFUN (babel_set_wired, babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); - babel_ifp->flags |= BABEL_IF_WIRED; + babel_set_wired_internal(babel_ifp, 1); return CMD_SUCCESS; } @@ -376,7 +394,7 @@ DEFUN (babel_set_wireless, babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); - babel_ifp->flags &= ~BABEL_IF_WIRED; + babel_set_wired_internal(babel_ifp, 0); return CMD_SUCCESS; } @@ -557,14 +575,6 @@ interface_recalculate(struct interface *ifp) resize_receive_buffer(mtu); - if(!(babel_ifp->flags & BABEL_IF_WIRED)) { /* if (wired) */ - babel_ifp->cost = 96; - babel_ifp->flags &= ~BABEL_IF_LQ; - } else { - babel_ifp->cost = 256; - babel_ifp->flags |= BABEL_IF_LQ; - } - memset(&mreq, 0, sizeof(mreq)); memcpy(&mreq.ipv6mr_multiaddr, protocol_group, 16); mreq.ipv6mr_interface = ifp->ifindex; @@ -1018,6 +1028,7 @@ babel_interface_allocate (void) babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; + babel_set_wired_internal(babel_ifp, 0); return babel_ifp; } -- cgit v1.2.1 From b63b4484c6d2c9d304d4ddd0756a4847c6dc5359 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 11:17:32 +0100 Subject: babeld: fix typo in kernel_route_add_v6. --- babeld/kernel_zebra.c | 1 + 1 file changed, 1 insertion(+) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index d262a86b..85ee1f8d 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -231,6 +231,7 @@ kernel_route_add_v6(const unsigned char *pref, unsigned short plen, api.safi = SAFI_UNICAST; SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); if(metric >= KERNEL_INFINITY) { + api.flags = ZEBRA_FLAG_BLACKHOLE; api.nexthop_num = 0; api.ifindex_num = 0; } else { -- cgit v1.2.1 From 5ca7986d546a1b65a4917aec0f1b594f950f7c27 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 11:22:29 +0100 Subject: babeld: consolidate zebra interface into fewer functions. --- babeld/kernel_zebra.c | 153 ++++++++++---------------------------------------- 1 file changed, 29 insertions(+), 124 deletions(-) (limited to 'babeld') diff --git a/babeld/kernel_zebra.c b/babeld/kernel_zebra.c index 85ee1f8d..db7d0b39 100644 --- a/babeld/kernel_zebra.c +++ b/babeld/kernel_zebra.c @@ -58,21 +58,13 @@ THE SOFTWARE. static int -kernel_route_add_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); +kernel_route_v4(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric); static int -kernel_route_add_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); -static int -kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); -static int -kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric); +kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, + unsigned int metric); int kernel_interface_operational(struct interface *interface) @@ -119,13 +111,13 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, switch (operation) { case ROUTE_ADD: return ipv4 ? - kernel_route_add_v4(pref, plen, gate, ifindex, metric): - kernel_route_add_v6(pref, plen, gate, ifindex, metric); + kernel_route_v4(1, pref, plen, gate, ifindex, metric): + kernel_route_v6(1, pref, plen, gate, ifindex, metric); break; case ROUTE_FLUSH: return ipv4 ? - kernel_route_delete_v4(pref, plen, gate, ifindex, metric): - kernel_route_delete_v6(pref, plen, gate, ifindex, metric); + kernel_route_v4(0, pref, plen, gate, ifindex, metric): + kernel_route_v6(0, pref, plen, gate, ifindex, metric); break; case ROUTE_MODIFY: if(newmetric == metric && memcmp(newgate, gate, 16) == 0 && @@ -133,15 +125,15 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, return 0; debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new."); rc = ipv4 ? - kernel_route_delete_v4(pref, plen, gate, ifindex, metric): - kernel_route_delete_v6(pref, plen, gate, ifindex, metric); + kernel_route_v4(0, pref, plen, gate, ifindex, metric): + kernel_route_v6(0, pref, plen, gate, ifindex, metric); if (rc < 0) return -1; rc = ipv4 ? - kernel_route_add_v4(pref, plen, newgate, newifindex, newmetric): - kernel_route_add_v6(pref, plen, newgate, newifindex, newmetric); + kernel_route_v4(1, pref, plen, newgate, newifindex, newmetric): + kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric); return rc; break; @@ -154,8 +146,9 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen, } static int -kernel_route_add_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) +kernel_route_v4(int add, + const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric) { struct zapi_ipv4 api; /* quagga's communication system */ struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ @@ -197,106 +190,16 @@ kernel_route_add_v4(const unsigned char *pref, unsigned short plen, api.metric = metric; } - debugf(BABEL_DEBUG_ROUTE, "adding route (ipv4) to zebra"); - return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_ADD, zclient, - &quagga_prefix, &api); -} - -static int -kernel_route_add_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, unsigned int metric) -{ - unsigned int tmp_ifindex = ifindex; /* (for typing) */ - struct zapi_ipv6 api; /* quagga's communication system */ - struct prefix_ipv6 quagga_prefix; /* quagga's prefix */ - struct in6_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in6_addr nexthop; /* next router to go */ - struct in6_addr *nexthop_pointer = &nexthop; - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_in6addr(&babel_prefix_addr, pref); - uchar_to_in6addr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET6; - IPV6_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen; - apply_mask_ipv6(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - api.ifindex_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX); - api.ifindex_num = 1; - api.ifindex = &tmp_ifindex; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "adding route (ipv6) to zebra"); - return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_ADD, zclient, - &quagga_prefix, &api); -} - -static int -kernel_route_delete_v4(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric) -{ - struct zapi_ipv4 api; /* quagga's communication system */ - struct prefix_ipv4 quagga_prefix; /* quagga's prefix */ - struct in_addr babel_prefix_addr; /* babeld's prefix addr */ - struct in_addr nexthop; /* next router to go */ - struct in_addr *nexthop_pointer = &nexthop; /* it's an array! */ - - /* convert to be understandable by quagga */ - /* convert given addresses */ - uchar_to_inaddr(&babel_prefix_addr, pref); - uchar_to_inaddr(&nexthop, gate); - - /* make prefix structure */ - memset (&quagga_prefix, 0, sizeof(quagga_prefix)); - quagga_prefix.family = AF_INET; - IPV4_ADDR_COPY (&quagga_prefix.prefix, &babel_prefix_addr); - quagga_prefix.prefixlen = plen - 96; - apply_mask_ipv4(&quagga_prefix); - - api.type = ZEBRA_ROUTE_BABEL; - api.flags = 0; - api.message = 0; - api.safi = SAFI_UNICAST; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); - api.ifindex_num = 0; - if(metric >= KERNEL_INFINITY) { - api.flags = ZEBRA_FLAG_BLACKHOLE; - api.nexthop_num = 0; - } else { - api.nexthop_num = 1; - api.nexthop = &nexthop_pointer; - SET_FLAG(api.message, ZAPI_MESSAGE_METRIC); - api.metric = metric; - } - - debugf(BABEL_DEBUG_ROUTE, "removing route (ipv4) to zebra"); - return zapi_ipv4_route (ZEBRA_IPV4_ROUTE_DELETE, zclient, - &quagga_prefix, &api); + debugf(BABEL_DEBUG_ROUTE, "%s route (ipv4) to zebra", + add ? "adding" : "removing" ); + return zapi_ipv4_route (add ? ZEBRA_IPV4_ROUTE_ADD : + ZEBRA_IPV4_ROUTE_DELETE, + zclient, &quagga_prefix, &api); } static int -kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, - const unsigned char *gate, int ifindex, - unsigned int metric) +kernel_route_v6(int add, const unsigned char *pref, unsigned short plen, + const unsigned char *gate, int ifindex, unsigned int metric) { unsigned int tmp_ifindex = ifindex; /* (for typing) */ struct zapi_ipv6 api; /* quagga's communication system */ @@ -336,9 +239,11 @@ kernel_route_delete_v6(const unsigned char *pref, unsigned short plen, api.metric = metric; } - debugf(BABEL_DEBUG_ROUTE, "removing route (ipv6) to zebra"); - return zapi_ipv6_route (ZEBRA_IPV6_ROUTE_DELETE, zclient, - &quagga_prefix, &api); + debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra", + add ? "adding" : "removing" ); + return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD : + ZEBRA_IPV6_ROUTE_DELETE, + zclient, &quagga_prefix, &api); } int -- cgit v1.2.1 From cbde15513ba47f6e7f6d02fcafcfb12cd5b1df77 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 14 Feb 2012 15:12:03 +0400 Subject: babeld: 3 more timing statements in config text This commit makes the following lines visible in running-config text, when respective intervals are configured to non-default values: * babel hello-interval * babel update-interval * babel resend-delay --- babeld/babel_interface.c | 10 ++++++++++ babeld/babel_main.c | 2 -- babeld/babeld.c | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 00d53bc6..958b1b98 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -986,6 +986,16 @@ interface_config_write (struct vty *vty) vty_out (vty, " babel split-horizon%s", VTY_NEWLINE); write++; } + if (babel_ifp->hello_interval != BABEL_DEFAULT_HELLO_INTERVAL) + { + vty_out (vty, " babel hello-interval %u%s", babel_ifp->hello_interval, VTY_NEWLINE); + write++; + } + if (babel_ifp->update_interval != BABEL_DEFAULT_UPDATE_INTERVAL) + { + vty_out (vty, " babel update-interval %u%s", babel_ifp->update_interval, VTY_NEWLINE); + write++; + } } vty_out (vty, "!%s", VTY_NEWLINE); write++; diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 0fcba749..003d746b 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -521,7 +521,6 @@ show_babel_main_configuration (struct vty *vty) "vty port = %d%s" "id = %s%s" "parasitic = %s%s" - "resend-delay = %d%s" "allow_duplicates = %s%s" "kernel_metric = %d%s", pidfile, VTY_NEWLINE, @@ -536,7 +535,6 @@ show_babel_main_configuration (struct vty *vty) babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, format_bool(parasitic), VTY_NEWLINE, - resend_delay, VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, kernel_metric, VTY_NEWLINE); } diff --git a/babeld/babeld.c b/babeld/babeld.c index 9fea2e10..1ae3f042 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -102,6 +102,11 @@ babel_config_write (struct vty *vty) if (!babel_routing_process) return lines; vty_out (vty, "router babel%s", VTY_NEWLINE); + if (resend_delay != BABEL_DEFAULT_RESEND_DELAY) + { + vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE); + lines++; + } /* list enabled interfaces */ lines = 1 + babel_enable_if_config_write (vty); /* list redistributed protocols */ -- cgit v1.2.1 From 6881f2698279f3c47a55e8969860eeac59e8c3d7 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 14 Feb 2012 15:43:34 +0100 Subject: babeld: remove "parasitic" mode. This is the functionality described in Appendix C of RFC 6126. Its main purpose is to avoid keeping a full source table, which makes it possible to implement a subset of Babel in just a few hundred lines of code. However, in Quagga the code for maintaining the source table is already there, and a parasitic implementation can be simulated using filtering -- so it makes little sense to keep the functionality. --- babeld/babel_interface.c | 28 ---------------------------- babeld/babel_main.c | 8 -------- babeld/message.c | 16 +++++----------- babeld/message.h | 1 - 4 files changed, 5 insertions(+), 48 deletions(-) (limited to 'babeld') diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 958b1b98..ace28127 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -479,32 +479,6 @@ DEFUN (babel_set_update_interval, return CMD_SUCCESS; } -/* [Interface Command]. */ -DEFUN (babel_passive_interface, - babel_passive_interface_cmd, - "babel passive-interface", - "Babel interface commands\n" - "Only announce redistributed routes on this interface\n") -{ - if (allow_duplicates) { - return CMD_WARNING; - } - parasitic = 1; - return CMD_SUCCESS; -} - -/* [Interface Command]. */ -DEFUN (no_babel_passive_interface, - no_babel_passive_interface_cmd, - "no babel passive-interface", - NO_STR - "Babel interface commands\n" - "Announce all routes on this interface\n") -{ - parasitic = 0; - return CMD_SUCCESS; -} - /* This should be no more than half the hello interval, so that hellos aren't sent late. The result is in milliseconds. */ unsigned @@ -926,8 +900,6 @@ babel_if_init () install_element(INTERFACE_NODE, &babel_set_wireless_cmd); install_element(INTERFACE_NODE, &babel_set_hello_interval_cmd); install_element(INTERFACE_NODE, &babel_set_update_interval_cmd); - install_element(INTERFACE_NODE, &babel_passive_interface_cmd); - install_element(INTERFACE_NODE, &no_babel_passive_interface_cmd); /* "show babel ..." commands */ install_element(VIEW_NODE, &show_babel_interface_cmd); diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 003d746b..2f3b5552 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -258,12 +258,6 @@ babel_init(int argc, char **argv) resend_delay = BABEL_DEFAULT_RESEND_DELAY; - if(parasitic && allow_duplicates >= 0) { - /* Too difficult to get right. */ - zlog_err("Sorry, -P and -A are incompatible."); - exit(1); - } - babel_replace_by_null(STDIN_FILENO); if (do_daemonise && daemonise() < 0) { @@ -520,7 +514,6 @@ show_babel_main_configuration (struct vty *vty) "vty address = %s%s" "vty port = %d%s" "id = %s%s" - "parasitic = %s%s" "allow_duplicates = %s%s" "kernel_metric = %d%s", pidfile, VTY_NEWLINE, @@ -534,7 +527,6 @@ show_babel_main_configuration (struct vty *vty) VTY_NEWLINE, babel_vty_port, VTY_NEWLINE, format_eui64(myid), VTY_NEWLINE, - format_bool(parasitic), VTY_NEWLINE, format_bool(allow_duplicates), VTY_NEWLINE, kernel_metric, VTY_NEWLINE); } diff --git a/babeld/message.c b/babeld/message.c index e86b4325..9dcfc677 100644 --- a/babeld/message.c +++ b/babeld/message.c @@ -54,7 +54,6 @@ THE SOFTWARE. unsigned char packet_header[4] = {42, 2}; -int parasitic = 0; int split_horizon = 1; unsigned short myseqno = 0; @@ -1153,18 +1152,13 @@ send_update(struct interface *ifp, int urgent, babel_ifp = babel_get_if_nfo(ifp); if(prefix) { - if(!parasitic || find_xroute(prefix, plen)) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", - ifp->name, format_prefix(prefix, plen)); - buffer_update(ifp, prefix, plen); - } + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for %s.", + ifp->name, format_prefix(prefix, plen)); + buffer_update(ifp, prefix, plen); } else { send_self_update(ifp); - if(!parasitic) { - debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", - ifp->name); - for_all_installed_routes(buffer_update_callback, ifp); - } + debugf(BABEL_DEBUG_COMMON,"Sending update to %s for any.", ifp->name); + for_all_installed_routes(buffer_update_callback, ifp); set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval); babel_ifp->last_update_time = babel_now.tv_sec; } diff --git a/babeld/message.h b/babeld/message.h index 1626a887..6a9aa104 100644 --- a/babeld/message.h +++ b/babeld/message.h @@ -62,7 +62,6 @@ THE SOFTWARE. extern unsigned short myseqno; extern struct timeval seqno_time; -extern int parasitic; extern int broadcast_ihu; extern int split_horizon; -- cgit v1.2.1