mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-27 10:04:18 +00:00
Merge branch 'babeld-merge' into master-copy
This commit is contained in:
commit
81c3e5006e
@ -1,10 +1,10 @@
|
||||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ \
|
||||
SUBDIRS = lib @ZEBRA@ @BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @BABELD@ \
|
||||
@ISISD@ @WATCHQUAGGA@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
|
||||
redhat @SOLARIS@
|
||||
|
||||
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d \
|
||||
DIST_SUBDIRS = lib zebra bgpd ripd ripngd ospfd ospf6d babeld \
|
||||
isisd watchquagga vtysh ospfclient doc m4 pkgsrc redhat tests \
|
||||
solaris
|
||||
|
||||
|
7
babeld/.gitignore
vendored
Normal file
7
babeld/.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
*
|
||||
!*.c
|
||||
!*.h
|
||||
!LICENCE
|
||||
!Makefile.am
|
||||
!babeld.conf.sample
|
||||
!.gitignore
|
36
babeld/LICENCE
Normal file
36
babeld/LICENCE
Normal file
@ -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 <year> <Author name>, <author contact details>
|
||||
|
||||
line to the existing copyright assertion lines in the MIT/X11 licence text
|
||||
above in this file.
|
29
babeld/Makefile.am
Normal file
29
babeld/Makefile.am
Normal file
@ -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
|
124
babeld/babel_filter.c
Normal file
124
babeld/babel_filter.c
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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(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);
|
||||
|
||||
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 INFINITY;
|
||||
}
|
||||
}
|
||||
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 INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
/* All interface filter check. */
|
||||
dist = distribute_lookup (NULL);
|
||||
if (dist) {
|
||||
if (dist->list[distribute]) {
|
||||
alist = access_list_lookup (AFI_IP6, dist->list[distribute]);
|
||||
|
||||
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 INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dist->prefix[distribute]) {
|
||||
plist = prefix_list_lookup (AFI_IP6, dist->prefix[distribute]);
|
||||
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 INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
49
babeld/babel_filter.h
Normal file
49
babeld/babel_filter.h
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#include "prefix.h"
|
||||
#include "babel_interface.h"
|
||||
|
||||
int babel_filter(int output, const unsigned char *prefix, unsigned short plen,
|
||||
unsigned int index);
|
||||
|
||||
#endif /* BABELD_BABEL_FILTER_H */
|
1022
babeld/babel_interface.c
Normal file
1022
babeld/babel_interface.c
Normal file
File diff suppressed because it is too large
Load Diff
152
babeld/babel_interface.h
Normal file
152
babeld/babel_interface.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#include "zclient.h"
|
||||
#include "vty.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;
|
||||
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 last_update_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_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_FARAWAY (1 << 4)
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return (if_is_operative(ifp) &&
|
||||
ifp->connected != NULL &&
|
||||
(babel_get_if_nfo(ifp)->flags & BABEL_IF_IS_UP));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
extern int babel_enable_if_config_write (struct vty *);
|
||||
|
||||
|
||||
#endif
|
532
babeld/babel_main.c
Normal file
532
babeld/babel_main.c
Normal file
@ -0,0 +1,532 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#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 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_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 = 0;
|
||||
|
||||
int resend_delay = -1;
|
||||
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 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 */
|
||||
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'},
|
||||
{ "socket", required_argument, NULL, 'z'},
|
||||
{ "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;
|
||||
}
|
||||
|
||||
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\
|
||||
-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\
|
||||
-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)
|
||||
{
|
||||
int rc, opt;
|
||||
int do_daemonise = 0;
|
||||
char *progname = NULL;
|
||||
|
||||
/* 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:z: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 'z':
|
||||
zclient_serv_path_set (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 = 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, 0);
|
||||
break;
|
||||
default:
|
||||
babel_usage (progname, 1);
|
||||
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 ();
|
||||
|
||||
resend_delay = BABEL_DEFAULT_RESEND_DELAY;
|
||||
|
||||
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);
|
||||
|
||||
/* 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_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"
|
||||
*/
|
||||
void
|
||||
babel_load_state_file(void)
|
||||
{
|
||||
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. id=%s; old=%s",
|
||||
format_eui64(myid),
|
||||
format_eui64(sid));
|
||||
}
|
||||
} 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.");
|
||||
flush_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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
show_babel_main_configuration (struct vty *vty)
|
||||
{
|
||||
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"
|
||||
"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,
|
||||
format_bool(allow_duplicates), VTY_NEWLINE,
|
||||
kernel_metric, VTY_NEWLINE);
|
||||
}
|
57
babeld/babel_main.h
Normal file
57
babeld/babel_main.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 "vty.h"
|
||||
|
||||
extern struct timeval babel_now; /* current time */
|
||||
extern struct thread_master *master; /* quagga's threads handler */
|
||||
extern int debug;
|
||||
extern int resend_delay;
|
||||
|
||||
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;
|
||||
|
||||
void babel_load_state_file(void);
|
||||
void show_babel_main_configuration (struct vty *vty);
|
378
babeld/babel_zebra.c
Normal file
378
babeld/babel_zebra.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#include "command.h"
|
||||
#include "zclient.h"
|
||||
#include "stream.h"
|
||||
|
||||
/* babel's includes*/
|
||||
#include "babel_zebra.h"
|
||||
#include "babel_interface.h"
|
||||
#include "xroute.h"
|
||||
#include "util.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);
|
||||
|
||||
/* 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 =
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (babel_redistribute_type,
|
||||
babel_redistribute_type_cmd,
|
||||
"redistribute " QUAGGA_REDIST_STR_BABELD,
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_BABELD)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
|
||||
if (type < 0)
|
||||
type = proto_redistnum(AFI_IP, argv[0]);
|
||||
|
||||
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 " QUAGGA_REDIST_STR_BABELD,
|
||||
NO_STR
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_BABELD)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
|
||||
if (type < 0)
|
||||
type = proto_redistnum(AFI_IP, argv[0]);
|
||||
|
||||
if (type < 0) {
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, type);
|
||||
/* perhaps should we remove xroutes having the same type... */
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
#ifndef NO_DEBUG
|
||||
/* [Babel Command] */
|
||||
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"
|
||||
"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_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"
|
||||
"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;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
|
||||
return CMD_WARNING;
|
||||
}
|
||||
#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)
|
||||
{
|
||||
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);
|
||||
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
|
||||
zebra_config_write (struct vty *vty)
|
||||
{
|
||||
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);
|
||||
}
|
50
babeld/babel_zebra.h
Normal file
50
babeld/babel_zebra.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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_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
|
728
babeld/babeld.c
Normal file
728
babeld/babeld.c
Normal file
@ -0,0 +1,728 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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.h>
|
||||
#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"
|
||||
#include "babel_zebra.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)
|
||||
{
|
||||
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);
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
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()
|
||||
{
|
||||
flush_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;
|
||||
}
|
||||
}
|
||||
|
||||
static 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"
|
||||
"No attributes\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_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
"No attributes\n")
|
||||
{
|
||||
if(babel_routing_process)
|
||||
babel_clean_routing_process();
|
||||
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)
|
||||
{
|
||||
|
||||
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);
|
||||
install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return babel_filter(0, prefix, plen, ifindex);
|
||||
}
|
||||
|
||||
int
|
||||
output_filter(const unsigned char *id, const unsigned char *prefix,
|
||||
unsigned short plen, unsigned int ifindex)
|
||||
{
|
||||
return babel_filter(1, prefix, plen, ifindex);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
30
babeld/babeld.conf.sample
Normal file
30
babeld/babeld.conf.sample
Normal file
@ -0,0 +1,30 @@
|
||||
debug babel common
|
||||
!debug babel kernel
|
||||
!debug babel filter
|
||||
!debug babel timeout
|
||||
!debug babel interface
|
||||
!debug babel route
|
||||
!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 split-horizon
|
||||
! babel hello-interval 12000
|
||||
! babel update-interval 36000
|
||||
|
||||
! log file /var/log/quagga/babeld.log
|
||||
log stdout
|
141
babeld/babeld.h
Normal file
141
babeld/babeld.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#include "vty.h"
|
||||
|
||||
#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 <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_VALGRIND
|
||||
#include <valgrind/memcheck.h>
|
||||
#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"
|
||||
|
||||
/* Values in milliseconds */
|
||||
#define BABEL_DEFAULT_HELLO_INTERVAL 4000
|
||||
#define BABEL_DEFAULT_UPDATE_INTERVAL 16000
|
||||
#define BABEL_DEFAULT_RESEND_DELAY 2000
|
||||
|
||||
|
||||
/* 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 */
|
76
babeld/kernel.c
Normal file
76
babeld/kernel.c
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
return quagga_gettime(QUAGGA_CLK_MONOTONIC, tv);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
69
babeld/kernel.h
Normal file
69
babeld/kernel.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <netinet/in.h>
|
||||
#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
|
||||
|
||||
extern int export_table, import_table;
|
||||
|
||||
int kernel_interface_operational(struct interface *interface);
|
||||
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 if_eui64(char *ifname, int ifindex, unsigned char *eui);
|
||||
int gettime(struct timeval *tv);
|
||||
int read_random_bytes(void *buf, size_t len);
|
275
babeld/kernel_zebra.c
Normal file
275
babeld/kernel_zebra.c
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <zebra.h>
|
||||
#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_v4(int add, const unsigned char *pref, unsigned short plen,
|
||||
const unsigned char *gate, int ifindex,
|
||||
unsigned int metric);
|
||||
static int
|
||||
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)
|
||||
{
|
||||
return if_is_operative(interface);
|
||||
}
|
||||
|
||||
int
|
||||
kernel_interface_mtu(struct interface *interface)
|
||||
{
|
||||
return MIN(interface->mtu, interface->mtu6);
|
||||
}
|
||||
|
||||
int
|
||||
kernel_interface_wireless(struct interface *interface)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 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_v4(1, pref, plen, gate, ifindex, metric):
|
||||
kernel_route_v6(1, pref, plen, gate, ifindex, metric);
|
||||
break;
|
||||
case ROUTE_FLUSH:
|
||||
return ipv4 ?
|
||||
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 &&
|
||||
newifindex == ifindex)
|
||||
return 0;
|
||||
debugf(BABEL_DEBUG_ROUTE, "Modify route: delete old; add new.");
|
||||
rc = ipv4 ?
|
||||
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_v4(1, pref, plen, newgate, newifindex, newmetric):
|
||||
kernel_route_v6(1, pref, plen, newgate, newifindex, newmetric);
|
||||
|
||||
return rc;
|
||||
break;
|
||||
default:
|
||||
zlog_err("this should never appens (false value - kernel_route)");
|
||||
assert(0);
|
||||
exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
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 */
|
||||
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; /* our plen is for v4mapped's addr */
|
||||
apply_mask_ipv4(&quagga_prefix);
|
||||
|
||||
api.type = ZEBRA_ROUTE_BABEL;
|
||||
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.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, "%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_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 */
|
||||
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, "%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
|
||||
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 {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
1561
babeld/message.c
Normal file
1561
babeld/message.c
Normal file
File diff suppressed because it is too large
Load Diff
111
babeld/message.h
Normal file
111
babeld/message.h
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 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
|
343
babeld/neighbour.c
Normal file
343
babeld/neighbour.c
Normal file
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <zebra.h>
|
||||
#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.
|
||||
This does not call local_notify_neighbour, see update_neighbour_metric. */
|
||||
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 * 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 * 10U * 10U)) {
|
||||
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 * 10U);
|
||||
if(neigh->ihu_interval > 0)
|
||||
msecs = MIN(msecs, neigh->ihu_interval * 10U);
|
||||
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;
|
||||
}
|
||||
}
|
66
babeld/neighbour.h
Normal file
66
babeld/neighbour.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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);
|
239
babeld/net.c
Normal file
239
babeld/net.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#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;
|
||||
const int ds = 0xc0; /* CS6 - Network Control */
|
||||
|
||||
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;
|
||||
|
||||
#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;
|
||||
|
||||
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,
|
||||
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 = buf1;
|
||||
iovec[0].iov_len = buflen1;
|
||||
iovec[1].iov_base = 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;
|
||||
}
|
44
babeld/net.h
Normal file
44
babeld/net.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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,
|
||||
void *buf1, int buflen1, void *buf2, int buflen2,
|
||||
struct sockaddr *sin, int slen);
|
||||
int tcp_server_socket(int port, int local);
|
330
babeld/resend.c
Normal file
330
babeld/resend.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <zebra.h>
|
||||
#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 = RESEND_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 = RESEND_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();
|
||||
}
|
77
babeld/resend.h
Normal file
77
babeld/resend.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 RESEND_MAX 3
|
||||
|
||||
#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);
|
1019
babeld/route.c
Normal file
1019
babeld/route.c
Normal file
File diff suppressed because it is too large
Load Diff
135
babeld/route.h
Normal file
135
babeld/route.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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_ROUTE_H
|
||||
#define BABEL_ROUTE_H
|
||||
|
||||
#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 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;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
int m = (int)route->refmetric + route->cost + route->add_metric;
|
||||
return MIN(m, INFINITY);
|
||||
}
|
||||
|
||||
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,
|
||||
int feasible, struct neighbour *exclude);
|
||||
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 babel_route *route);
|
||||
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 *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,
|
||||
struct source *src);
|
||||
void send_triggered_update(struct babel_route *route,
|
||||
struct source *oldsrc, unsigned oldmetric);
|
||||
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);
|
||||
|
||||
#endif
|
180
babeld/source.c
Normal file
180
babeld/source.c
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#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(src->plen != plen)
|
||||
continue;
|
||||
if(memcmp(src->prefix, p, 16) == 0)
|
||||
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->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)
|
||||
{
|
||||
if(src->route_count > 0)
|
||||
/* The source is in use by a route. */
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
update_source(struct source *src,
|
||||
unsigned short seqno, unsigned short metric)
|
||||
{
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
67
babeld/source.h
Normal file
67
babeld/source.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
unsigned short route_count;
|
||||
time_t time;
|
||||
};
|
||||
|
||||
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
|
445
babeld/util.c
Normal file
445
babeld/util.c
Normal file
@ -0,0 +1,445 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
const char *format_bool(const int b) {
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
165
babeld/util.h
Normal file
165
babeld/util.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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(*(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__*/
|
||||
#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));
|
||||
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);
|
||||
const char *format_bool(const int b);
|
||||
int parse_address(const char *address, unsigned char *addr_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)) zlog_debug(__VA_ARGS__); \
|
||||
} while(0)
|
||||
#elif defined __GNUC__
|
||||
#define debugf(level, _args...) \
|
||||
do { \
|
||||
if(UNLIKELY(debug & level)) zlog_debug(_args); \
|
||||
} while(0)
|
||||
#else
|
||||
static inline void debugf(int level, const char *format, ...) { return; }
|
||||
#endif
|
||||
|
||||
#endif /* NO_DEBUG */
|
||||
|
237
babeld/xroute.c
Normal file
237
babeld/xroute.c
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 <zebra.h>
|
||||
#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"
|
||||
|
||||
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
|
||||
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 + 96,
|
||||
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 + 96);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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 babel_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;
|
||||
}
|
59
babeld/xroute.h
Normal file
59
babeld/xroute.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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;
|
||||
};
|
||||
|
||||
struct xroute *find_xroute(const unsigned char *prefix, unsigned char plen);
|
||||
void flush_xroute(struct xroute *xroute);
|
||||
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);
|
||||
int xroutes_estimate(void);
|
||||
void for_all_xroutes(void (*f)(struct xroute*, void*), void *closure);
|
16
configure.ac
16
configure.ac
@ -207,6 +207,8 @@ AC_ARG_ENABLE(ospfd,
|
||||
[ --disable-ospfd do not build ospfd])
|
||||
AC_ARG_ENABLE(ospf6d,
|
||||
[ --disable-ospf6d do not build ospf6d])
|
||||
AC_ARG_ENABLE(babeld,
|
||||
[ --disable-babeld do not build babeld])
|
||||
AC_ARG_ENABLE(watchquagga,
|
||||
[ --disable-watchquagga do not build watchquagga])
|
||||
AC_ARG_ENABLE(isisd,
|
||||
@ -1245,6 +1247,12 @@ else
|
||||
OSPFD="ospfd"
|
||||
fi
|
||||
|
||||
if test "${enable_babeld}" = "no";then
|
||||
BABELD=""
|
||||
else
|
||||
BABELD="babeld"
|
||||
fi
|
||||
|
||||
if test "${enable_watchquagga}" = "no";then
|
||||
WATCHQUAGGA=""
|
||||
else
|
||||
@ -1301,6 +1309,7 @@ AC_SUBST(RIPD)
|
||||
AC_SUBST(RIPNGD)
|
||||
AC_SUBST(OSPFD)
|
||||
AC_SUBST(OSPF6D)
|
||||
AC_SUBST(BABELD)
|
||||
AC_SUBST(WATCHQUAGGA)
|
||||
AC_SUBST(ISISD)
|
||||
AC_SUBST(SOLARIS)
|
||||
@ -1544,6 +1553,7 @@ AC_DEFINE_UNQUOTED(PATH_RIPNGD_PID, "$quagga_statedir/ripngd.pid",ripngd PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_BGPD_PID, "$quagga_statedir/bgpd.pid",bgpd PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_OSPFD_PID, "$quagga_statedir/ospfd.pid",ospfd PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_OSPF6D_PID, "$quagga_statedir/ospf6d.pid",ospf6d PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_BABELD_PID, "$quagga_statedir/babeld.pid",babeld PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_ISISD_PID, "$quagga_statedir/isisd.pid",isisd PID)
|
||||
AC_DEFINE_UNQUOTED(PATH_WATCHQUAGGA_PID, "$quagga_statedir/watchquagga.pid",watchquagga PID)
|
||||
AC_DEFINE_UNQUOTED(ZEBRA_SERV_PATH, "$quagga_statedir/zserv.api",zebra api socket)
|
||||
@ -1553,6 +1563,7 @@ AC_DEFINE_UNQUOTED(RIPNG_VTYSH_PATH, "$quagga_statedir/ripngd.vty",ripng vty soc
|
||||
AC_DEFINE_UNQUOTED(BGP_VTYSH_PATH, "$quagga_statedir/bgpd.vty",bgpd vty socket)
|
||||
AC_DEFINE_UNQUOTED(OSPF_VTYSH_PATH, "$quagga_statedir/ospfd.vty",ospfd vty socket)
|
||||
AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty socket)
|
||||
AC_DEFINE_UNQUOTED(BABEL_VTYSH_PATH, "$quagga_statedir/babeld.vty",babeld vty socket)
|
||||
AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)
|
||||
AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
|
||||
|
||||
@ -1577,8 +1588,9 @@ AC_MSG_RESULT($ac_cv_htonl_works)
|
||||
|
||||
AC_CONFIG_FILES([Makefile lib/Makefile zebra/Makefile ripd/Makefile
|
||||
ripngd/Makefile bgpd/Makefile ospfd/Makefile watchquagga/Makefile
|
||||
ospf6d/Makefile isisd/Makefile vtysh/Makefile doc/Makefile
|
||||
ospfclient/Makefile tests/Makefile m4/Makefile redhat/Makefile
|
||||
ospf6d/Makefile isisd/Makefile babeld/Makefile vtysh/Makefile
|
||||
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
|
||||
redhat/Makefile
|
||||
pkgsrc/Makefile
|
||||
redhat/quagga.spec
|
||||
lib/version.h
|
||||
|
@ -46,11 +46,11 @@ info_TEXINFOS = quagga.texi
|
||||
quagga.pdf: $(info_TEXINFOS) $(figures_pdf) $(quagga_TEXINFOS)
|
||||
$(TEXI2PDF) -o "$@" $<
|
||||
|
||||
quagga_TEXINFOS = appendix.texi basic.texi bgpd.texi filter.texi install.texi \
|
||||
ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi overview.texi \
|
||||
protocol.texi ripd.texi ripngd.texi routemap.texi snmp.texi \
|
||||
vtysh.texi routeserver.texi defines.texi $(figures_png) snmptrap.texi \
|
||||
$(figures_txt)
|
||||
quagga_TEXINFOS = appendix.texi babeld.texi basic.texi bgpd.texi filter.texi \
|
||||
install.texi ipv6.texi kernel.texi main.texi ospf6d.texi ospfd.texi \
|
||||
overview.texi protocol.texi ripd.texi ripngd.texi routemap.texi \
|
||||
snmp.texi vtysh.texi routeserver.texi defines.texi $(figures_png) \
|
||||
snmptrap.texi $(figures_txt)
|
||||
|
||||
.png.eps:
|
||||
$(PNGTOEPS) $< "$@"
|
||||
|
118
doc/babeld.texi
Normal file
118
doc/babeld.texi
Normal file
@ -0,0 +1,118 @@
|
||||
@c -*-texinfo-*-
|
||||
@c This is part of the Quagga Manual.
|
||||
@c @value{COPYRIGHT_STR}
|
||||
@c See file quagga.texi for copying conditions.
|
||||
@node Babel
|
||||
@chapter Babel
|
||||
|
||||
Babel is an interior gateway protocol that is suitable both for wired
|
||||
networks and for wireless mesh networks. Babel has been described as
|
||||
``RIP on speed'' --- it is based on the same principles as RIP, but
|
||||
includes a number of refinements that make it react much faster to
|
||||
topology changes without ever counting to infinity, and allow it to
|
||||
perform reliable link quality estimation on wireless links. Babel is
|
||||
a double-stack routing protocol, meaning that a single Babel instance
|
||||
is able to perform routing for both IPv4 and IPv6.
|
||||
|
||||
Quagga implements Babel as described in RFC6126.
|
||||
|
||||
@menu
|
||||
* Configuring babeld::
|
||||
* Babel configuration::
|
||||
* Babel redistribution::
|
||||
* Show Babel information::
|
||||
* Babel debugging commands::
|
||||
@end menu
|
||||
|
||||
@node Configuring babeld, Babel configuration, Babel, Babel
|
||||
@section Configuring babeld
|
||||
|
||||
The @command{babeld} daemon can be invoked with any of the common
|
||||
options (@pxref{Common Invocation Options}).
|
||||
|
||||
The @command{zebra} daemon must be running before @command{babeld} is
|
||||
invoked. Also, if @command{zebra} is restarted then @command{babeld}
|
||||
must be too.
|
||||
|
||||
Configuration of @command{babeld} is done in its configuration file
|
||||
@file{babeld.conf}.
|
||||
|
||||
@node Babel configuration, Babel redistribution, Configuring babeld, Babel
|
||||
@section Babel configuration
|
||||
|
||||
@deffn Command {router babel} {}
|
||||
@deffnx Command {no router babel} {}
|
||||
Enable or disable Babel routing.
|
||||
@end deffn
|
||||
|
||||
@deffn {Babel Command} {network @var{ifname}} {}
|
||||
@deffnx {Babel Command} {no network @var{ifname}} {}
|
||||
Enable or disable Babel on the given interface.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel wired} {}
|
||||
@deffnx {Interface Command} {babel wireless} {}
|
||||
Specifies whether this interface is wireless, which disables a number
|
||||
of optimisations that are only correct on wired interfaces.
|
||||
Specifying @code{wireless} (the default) is always correct, but may
|
||||
cause slower convergence and extra routing traffic.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel split-horizon}
|
||||
@deffnx {Interface Command} {no babel split-horizon}
|
||||
Specifies whether to perform split-horizon on the interface.
|
||||
Specifying @code{no babel split-horizon} (the default) is always
|
||||
correct, while @code{babel split-horizon} is an optimisation that
|
||||
should only be used on symmetric and transitive (wired) networks.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel hello-interval <20-655340>}
|
||||
Specifies the time in milliseconds between two scheduled hellos. On
|
||||
wired links, Babel notices a link failure within two hello intervals;
|
||||
on wireless links, the link quality value is reestimated at every
|
||||
hello interval. The default is 4000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Interface Command} {babel update-interval <20-655340>}
|
||||
Specifies the time in milliseconds between two scheduled updates.
|
||||
Since Babel makes extensive use of triggered updates, this can be set
|
||||
to fairly high values on links with little packet loss. The default
|
||||
is 20000@dmn{ms}.
|
||||
@end deffn
|
||||
|
||||
@deffn {Babel Command} {babel resend-delay <20-655340>}
|
||||
Specifies the time in milliseconds after which an ``important''
|
||||
request or update will be resent. The default is 2000@dmn{ms}. You
|
||||
probably don't want to tweak this value.
|
||||
@end deffn
|
||||
|
||||
@node Babel redistribution, Show Babel information, Babel configuration, Babel
|
||||
@section Babel redistribution
|
||||
|
||||
@deffn {Babel command} {redistribute @var{kind}}
|
||||
@deffnx {Babel command} {no redistribute @var{kind}}
|
||||
Specify which kind of routes should be redistributed into Babel.
|
||||
@end deffn
|
||||
|
||||
@node Show Babel information, Babel debugging commands, Babel redistribution, Babel
|
||||
@section Show Babel information
|
||||
|
||||
@deffn {Command} {show babel database} {}
|
||||
@deffnx {Command} {show babel interface} {}
|
||||
@deffnx {Command} {show babel neighbour} {}
|
||||
@deffnx {Command} {show babel parameters} {}
|
||||
These commands dump various parts of @command{babeld}'s internal
|
||||
state. They are mostly useful for troubleshooting.
|
||||
@end deffn
|
||||
|
||||
@node Babel debugging commands, , Show Babel information, Babel
|
||||
@section Babel debugging commands
|
||||
|
||||
@deffn {Babel Command} {debug babel @var{kind}} {}
|
||||
@deffnx {Babel Command} {no debug babel @var{kind}} {}
|
||||
Enable or disable debugging messages of a given kind. @var{kind} can
|
||||
be one of @samp{common}, @samp{kernel}, @samp{filter}, @samp{timeout},
|
||||
@samp{interface}, @samp{route} or @samp{all}. Note that if you have
|
||||
compiled with the NO_DEBUG flag, then these commands aren't available.
|
||||
@end deffn
|
||||
|
@ -2,7 +2,7 @@
|
||||
@chapter IPv6 Support
|
||||
|
||||
Quagga fully supports IPv6 routing. As described so far, Quagga supports
|
||||
RIPng, OSPFv3 and BGP-4+. You can give IPv6 addresses to an interface
|
||||
RIPng, OSPFv3, Babel and BGP-4+. You can give IPv6 addresses to an interface
|
||||
and configure static IPv6 routing information. Quagga IPv6 also provides
|
||||
automatic address configuration via a feature called @code{address
|
||||
auto configuration}. To do it, the router must send router advertisement
|
||||
|
@ -86,6 +86,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of
|
||||
* RIPng::
|
||||
* OSPFv2::
|
||||
* OSPFv3::
|
||||
* Babel::
|
||||
* BGP::
|
||||
* Configuring Quagga as a Route Server::
|
||||
* VTY shell::
|
||||
@ -110,6 +111,7 @@ for @value{PACKAGE_STRING}. @uref{http://www.quagga.net,,Quagga} is a fork of
|
||||
@include ripngd.texi
|
||||
@include ospfd.texi
|
||||
@include ospf6d.texi
|
||||
@include babeld.texi
|
||||
@include bgpd.texi
|
||||
@include routeserver.texi
|
||||
@include vtysh.texi
|
||||
|
@ -2400,6 +2400,7 @@ DEFUN (config_exit,
|
||||
case BGP_NODE:
|
||||
case RIP_NODE:
|
||||
case RIPNG_NODE:
|
||||
case BABEL_NODE:
|
||||
case OSPF_NODE:
|
||||
case OSPF6_NODE:
|
||||
case ISIS_NODE:
|
||||
@ -2449,6 +2450,7 @@ DEFUN (config_end,
|
||||
case ZEBRA_NODE:
|
||||
case RIP_NODE:
|
||||
case RIPNG_NODE:
|
||||
case BABEL_NODE:
|
||||
case BGP_NODE:
|
||||
case BGP_VPNV4_NODE:
|
||||
case BGP_IPV4_NODE:
|
||||
|
@ -78,6 +78,7 @@ enum node_type
|
||||
TABLE_NODE, /* rtm_table selection node. */
|
||||
RIP_NODE, /* RIP protocol mode node. */
|
||||
RIPNG_NODE, /* RIPng protocol mode node. */
|
||||
BABEL_NODE, /* Babel protocol mode node. */
|
||||
BGP_NODE, /* BGP protocol mode which includes BGP4+ */
|
||||
BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
|
||||
BGP_IPV4_NODE, /* BGP IPv4 unicast address family. */
|
||||
|
@ -758,22 +758,25 @@ distribute_list_init (int node)
|
||||
(int (*) (const void *, const void *)) distribute_cmp);
|
||||
|
||||
if(node==RIP_NODE) {
|
||||
install_element (RIP_NODE, &distribute_list_all_cmd);
|
||||
install_element (RIP_NODE, &no_distribute_list_all_cmd);
|
||||
install_element (RIP_NODE, &distribute_list_cmd);
|
||||
install_element (RIP_NODE, &no_distribute_list_cmd);
|
||||
install_element (RIP_NODE, &distribute_list_prefix_all_cmd);
|
||||
install_element (RIP_NODE, &no_distribute_list_prefix_all_cmd);
|
||||
install_element (RIP_NODE, &distribute_list_prefix_cmd);
|
||||
install_element (RIP_NODE, &no_distribute_list_prefix_cmd);
|
||||
} else {
|
||||
install_element (RIPNG_NODE, &ipv6_distribute_list_all_cmd);
|
||||
install_element (RIPNG_NODE, &no_ipv6_distribute_list_all_cmd);
|
||||
install_element (RIPNG_NODE, &ipv6_distribute_list_cmd);
|
||||
install_element (RIPNG_NODE, &no_ipv6_distribute_list_cmd);
|
||||
install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_all_cmd);
|
||||
install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_all_cmd);
|
||||
install_element (RIPNG_NODE, &ipv6_distribute_list_prefix_cmd);
|
||||
install_element (RIPNG_NODE, &no_ipv6_distribute_list_prefix_cmd);
|
||||
install_element (node, &distribute_list_all_cmd);
|
||||
install_element (node, &no_distribute_list_all_cmd);
|
||||
install_element (node, &distribute_list_cmd);
|
||||
install_element (node, &no_distribute_list_cmd);
|
||||
install_element (node, &distribute_list_prefix_all_cmd);
|
||||
install_element (node, &no_distribute_list_prefix_all_cmd);
|
||||
install_element (node, &distribute_list_prefix_cmd);
|
||||
install_element (node, &no_distribute_list_prefix_cmd);
|
||||
} else if (node == RIPNG_NODE || node == BABEL_NODE) {
|
||||
/* WARNING: two identical commands installed do a crash, so be worry with
|
||||
aliases. For this reason, and because all these commands are aliases, Babel
|
||||
is not set with RIP. */
|
||||
install_element (node, &ipv6_distribute_list_all_cmd);
|
||||
install_element (node, &no_ipv6_distribute_list_all_cmd);
|
||||
install_element (node, &ipv6_distribute_list_cmd);
|
||||
install_element (node, &no_ipv6_distribute_list_cmd);
|
||||
install_element (node, &ipv6_distribute_list_prefix_all_cmd);
|
||||
install_element (node, &no_ipv6_distribute_list_prefix_all_cmd);
|
||||
install_element (node, &ipv6_distribute_list_prefix_cmd);
|
||||
install_element (node, &no_ipv6_distribute_list_prefix_cmd);
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
#ifndef _ZEBRA_DISTRIBUTE_H
|
||||
#define _ZEBRA_DISTRIBUTE_H
|
||||
|
||||
#include <zebra.h>
|
||||
#include "if.h"
|
||||
|
||||
/* Disctirubte list types. */
|
||||
enum distribute_type
|
||||
{
|
||||
|
@ -48,6 +48,7 @@ const char *zlog_proto_names[] =
|
||||
"BGP",
|
||||
"OSPF",
|
||||
"RIPNG",
|
||||
"BABEL",
|
||||
"OSPF6",
|
||||
"ISIS",
|
||||
"MASC",
|
||||
@ -932,8 +933,10 @@ proto_redistnum(int afi, const char *s)
|
||||
return ZEBRA_ROUTE_OSPF;
|
||||
else if (strncmp (s, "i", 1) == 0)
|
||||
return ZEBRA_ROUTE_ISIS;
|
||||
else if (strncmp (s, "b", 1) == 0)
|
||||
else if (strncmp (s, "bg", 2) == 0)
|
||||
return ZEBRA_ROUTE_BGP;
|
||||
else if (strncmp (s, "ba", 2) == 0)
|
||||
return ZEBRA_ROUTE_BABEL;
|
||||
}
|
||||
if (afi == AFI_IP6)
|
||||
{
|
||||
@ -949,8 +952,10 @@ proto_redistnum(int afi, const char *s)
|
||||
return ZEBRA_ROUTE_OSPF6;
|
||||
else if (strncmp (s, "i", 1) == 0)
|
||||
return ZEBRA_ROUTE_ISIS;
|
||||
else if (strncmp (s, "b", 1) == 0)
|
||||
else if (strncmp (s, "bg", 2) == 0)
|
||||
return ZEBRA_ROUTE_BGP;
|
||||
else if (strncmp (s, "ba", 2) == 0)
|
||||
return ZEBRA_ROUTE_BABEL;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ typedef enum
|
||||
ZLOG_BGP,
|
||||
ZLOG_OSPF,
|
||||
ZLOG_RIPNG,
|
||||
ZLOG_BABEL,
|
||||
ZLOG_OSPF6,
|
||||
ZLOG_ISIS,
|
||||
ZLOG_MASC
|
||||
|
14
lib/memory.c
14
lib/memory.c
@ -466,6 +466,17 @@ DEFUN (show_memory_ripng,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_memory_babel,
|
||||
show_memory_babel_cmd,
|
||||
"show memory babel",
|
||||
SHOW_STR
|
||||
"Memory statistics\n"
|
||||
"Babel memory\n")
|
||||
{
|
||||
show_memory_vty (vty, memory_list_babel);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (show_memory_bgp,
|
||||
show_memory_bgp_cmd,
|
||||
"show memory bgp",
|
||||
@ -518,6 +529,7 @@ memory_init (void)
|
||||
install_element (RESTRICTED_NODE, &show_memory_lib_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_rip_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_ripng_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_babel_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_bgp_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_ospf_cmd);
|
||||
install_element (RESTRICTED_NODE, &show_memory_ospf6_cmd);
|
||||
@ -528,6 +540,7 @@ memory_init (void)
|
||||
install_element (VIEW_NODE, &show_memory_lib_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_rip_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_ripng_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_babel_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_bgp_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_ospf_cmd);
|
||||
install_element (VIEW_NODE, &show_memory_ospf6_cmd);
|
||||
@ -539,6 +552,7 @@ memory_init (void)
|
||||
install_element (ENABLE_NODE, &show_memory_zebra_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_rip_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_ripng_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_babel_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_bgp_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_ospf_cmd);
|
||||
install_element (ENABLE_NODE, &show_memory_ospf6_cmd);
|
||||
|
@ -174,6 +174,13 @@ struct memory_list memory_list_ripng[] =
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
struct memory_list memory_list_babel[] =
|
||||
{
|
||||
{ MTYPE_BABEL, "Babel structure" },
|
||||
{ MTYPE_BABEL_IF, "Babel interface" },
|
||||
{ -1, NULL }
|
||||
};
|
||||
|
||||
struct memory_list memory_list_ospf[] =
|
||||
{
|
||||
{ MTYPE_OSPF_TOP, "OSPF top" },
|
||||
|
@ -58,6 +58,7 @@ ZEBRA_ROUTE_BGP, bgp, bgpd, 'B', 1, 1, "BGP"
|
||||
# possible).
|
||||
ZEBRA_ROUTE_HSLS, hsls, hslsd, 'H', 0, 0, "HSLS"
|
||||
ZEBRA_ROUTE_OLSR, olsr, olsrd, 'o', 0, 0, "OLSR"
|
||||
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
|
||||
|
||||
## help strings
|
||||
ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
|
||||
@ -72,3 +73,4 @@ ZEBRA_ROUTE_ISIS, "Intermediate System to Intermediate System (IS-IS)"
|
||||
ZEBRA_ROUTE_BGP, "Border Gateway Protocol (BGP)"
|
||||
ZEBRA_ROUTE_HSLS, "Hazy-Sighted Link State Protocol (HSLS)"
|
||||
ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
|
||||
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
|
||||
|
@ -43,6 +43,7 @@ typedef enum
|
||||
{
|
||||
RMAP_RIP,
|
||||
RMAP_RIPNG,
|
||||
RMAP_BABEL,
|
||||
RMAP_OSPF,
|
||||
RMAP_OSPF6,
|
||||
RMAP_BGP,
|
||||
|
@ -23,6 +23,8 @@
|
||||
#ifndef _ZEBRA_THREAD_H
|
||||
#define _ZEBRA_THREAD_H
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
struct rusage_t
|
||||
{
|
||||
#ifdef HAVE_RUSAGE
|
||||
|
@ -699,6 +699,7 @@ vty_end_config (struct vty *vty)
|
||||
case ZEBRA_NODE:
|
||||
case RIP_NODE:
|
||||
case RIPNG_NODE:
|
||||
case BABEL_NODE:
|
||||
case BGP_NODE:
|
||||
case BGP_VPNV4_NODE:
|
||||
case BGP_IPV4_NODE:
|
||||
@ -1107,6 +1108,7 @@ vty_stop_input (struct vty *vty)
|
||||
case ZEBRA_NODE:
|
||||
case RIP_NODE:
|
||||
case RIPNG_NODE:
|
||||
case BABEL_NODE:
|
||||
case BGP_NODE:
|
||||
case RMAP_NODE:
|
||||
case OSPF_NODE:
|
||||
|
@ -22,6 +22,9 @@
|
||||
#ifndef _ZEBRA_ZCLIENT_H
|
||||
#define _ZEBRA_ZCLIENT_H
|
||||
|
||||
/* For struct zapi_ipv{4,6}. */
|
||||
#include "prefix.h"
|
||||
|
||||
/* For struct interface and struct connected. */
|
||||
#include "if.h"
|
||||
|
||||
|
@ -207,7 +207,8 @@ static struct {
|
||||
{ZEBRA_ROUTE_CONNECT, 1, "connected"},
|
||||
{ZEBRA_ROUTE_STATIC, 1, "static"},
|
||||
{ZEBRA_ROUTE_OSPF, 1, "ospf"},
|
||||
{ZEBRA_ROUTE_BGP, 1, "bgp"},
|
||||
{ZEBRA_ROUTE_BGP, 2, "bgp"},
|
||||
{ZEBRA_ROUTE_BABEL, 2, "babel"},
|
||||
{0, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -217,7 +217,8 @@ static struct {
|
||||
{ZEBRA_ROUTE_CONNECT, 1, "connected"},
|
||||
{ZEBRA_ROUTE_STATIC, 1, "static"},
|
||||
{ZEBRA_ROUTE_OSPF6, 1, "ospf6"},
|
||||
{ZEBRA_ROUTE_BGP, 1, "bgp"},
|
||||
{ZEBRA_ROUTE_BGP, 2, "bgp"},
|
||||
{ZEBRA_ROUTE_BABEL, 2, "babel"},
|
||||
{0, 0, NULL}
|
||||
};
|
||||
|
||||
@ -289,198 +290,147 @@ DEFUN (no_ripng_redistribute_ripng,
|
||||
|
||||
DEFUN (ripng_redistribute_type,
|
||||
ripng_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_RIPNGD,
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_RIPNGD)
|
||||
{
|
||||
int i;
|
||||
int type;
|
||||
|
||||
for(i = 0; redist_type[i].str; i++)
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
|
||||
if (type < 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
|
||||
return CMD_WARNING;
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_ripng_redistribute_type,
|
||||
no_ripng_redistribute_type_cmd,
|
||||
"no redistribute (kernel|connected|static|ospf6|bgp)",
|
||||
"no redistribute " QUAGGA_REDIST_STR_RIPNGD,
|
||||
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_RIPNGD)
|
||||
{
|
||||
int i;
|
||||
int type;
|
||||
|
||||
for (i = 0; redist_type[i].str; i++)
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
|
||||
if (type < 0)
|
||||
{
|
||||
if (strncmp(redist_type[i].str, argv[0],
|
||||
redist_type[i].str_min_len) == 0)
|
||||
{
|
||||
ripng_redistribute_metric_unset (redist_type[i].type);
|
||||
ripng_redistribute_routemap_unset (redist_type[i].type);
|
||||
return ripng_redistribute_unset (redist_type[i].type);
|
||||
}
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
|
||||
return CMD_WARNING;
|
||||
ripng_redistribute_metric_unset (type);
|
||||
ripng_redistribute_routemap_unset (type);
|
||||
return ripng_redistribute_unset (type);
|
||||
}
|
||||
|
||||
|
||||
DEFUN (ripng_redistribute_type_metric,
|
||||
ripng_redistribute_type_metric_cmd,
|
||||
"redistribute (kernel|connected|static|ospf6|bgp) metric <0-16>",
|
||||
"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_RIPNGD " metric <0-16>",
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_RIPNGD
|
||||
"Metric\n"
|
||||
"Metric value\n")
|
||||
{
|
||||
int i;
|
||||
int type;
|
||||
int metric;
|
||||
|
||||
metric = atoi (argv[1]);
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
|
||||
for (i = 0; redist_type[i].str; i++) {
|
||||
if (strncmp(redist_type[i].str, argv[0],
|
||||
redist_type[i].str_min_len) == 0)
|
||||
{
|
||||
ripng_redistribute_metric_set (redist_type[i].type, metric);
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (type < 0)
|
||||
{
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
|
||||
return CMD_WARNING;
|
||||
ripng_redistribute_metric_set (type, metric);
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ALIAS (no_ripng_redistribute_type,
|
||||
no_ripng_redistribute_type_metric_cmd,
|
||||
"no redistribute (kernel|connected|static|ospf6|bgp) metric <0-16>",
|
||||
"no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16>",
|
||||
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_RIPNGD
|
||||
"Metric\n"
|
||||
"Metric value\n")
|
||||
|
||||
DEFUN (ripng_redistribute_type_routemap,
|
||||
ripng_redistribute_type_routemap_cmd,
|
||||
"redistribute (kernel|connected|static|ospf6|bgp) route-map WORD",
|
||||
"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_RIPNGD " route-map WORD",
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_RIPNGD
|
||||
"Route map reference\n"
|
||||
"Pointer to route-map entries\n")
|
||||
{
|
||||
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)
|
||||
{
|
||||
ripng_redistribute_routemap_set (redist_type[i].type, argv[1]);
|
||||
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)
|
||||
{
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_WARNING;
|
||||
ripng_redistribute_routemap_set (type, argv[1]);
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ALIAS (no_ripng_redistribute_type,
|
||||
no_ripng_redistribute_type_routemap_cmd,
|
||||
"no redistribute (kernel|connected|static|ospf6|bgp) route-map WORD",
|
||||
"no redistribute " QUAGGA_REDIST_STR_RIPNGD " route-map WORD",
|
||||
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_RIPNGD
|
||||
"Route map reference\n"
|
||||
"Pointer to route-map entries\n")
|
||||
|
||||
DEFUN (ripng_redistribute_type_metric_routemap,
|
||||
ripng_redistribute_type_metric_routemap_cmd,
|
||||
"redistribute (kernel|connected|static|ospf6|bgp) metric <0-16> route-map WORD",
|
||||
"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_RIPNGD " metric <0-16> route-map WORD",
|
||||
"Redistribute\n"
|
||||
QUAGGA_REDIST_HELP_STR_RIPNGD
|
||||
"Metric\n"
|
||||
"Metric value\n"
|
||||
"Route map reference\n"
|
||||
"Pointer to route-map entries\n")
|
||||
{
|
||||
int i;
|
||||
int type;
|
||||
int metric;
|
||||
|
||||
type = proto_redistnum(AFI_IP6, argv[0]);
|
||||
metric = atoi (argv[1]);
|
||||
|
||||
for (i = 0; redist_type[i].str; i++) {
|
||||
if (strncmp(redist_type[i].str, argv[0],
|
||||
redist_type[i].str_min_len) == 0)
|
||||
{
|
||||
ripng_redistribute_metric_set (redist_type[i].type, metric);
|
||||
ripng_redistribute_routemap_set (redist_type[i].type, argv[2]);
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, redist_type[i].type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
if (type < 0)
|
||||
{
|
||||
vty_out(vty, "Invalid type %s%s", argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[0],
|
||||
VTY_NEWLINE);
|
||||
|
||||
return CMD_WARNING;
|
||||
ripng_redistribute_metric_set (type, metric);
|
||||
ripng_redistribute_routemap_set (type, argv[2]);
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, type);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ALIAS (no_ripng_redistribute_type,
|
||||
no_ripng_redistribute_type_metric_routemap_cmd,
|
||||
"no redistribute (kernel|connected|static|ospf6|bgp) metric <0-16> route-map WORD",
|
||||
"no redistribute " QUAGGA_REDIST_STR_RIPNGD " metric <0-16> route-map WORD",
|
||||
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_RIPNGD
|
||||
"Route map reference\n"
|
||||
"Pointer to route-map entries\n")
|
||||
|
||||
|
@ -24,6 +24,7 @@ EXTRA_DIST = extract.pl
|
||||
vtysh_cmd_FILES = $(top_srcdir)/bgpd/*.c $(top_srcdir)/isisd/*.c \
|
||||
$(top_srcdir)/ospfd/*.c $(top_srcdir)/ospf6d/*.c \
|
||||
$(top_srcdir)/ripd/*.c $(top_srcdir)/ripngd/*.c \
|
||||
$(top_srcdir)/babeld/*.c \
|
||||
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
|
||||
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
|
||||
$(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \
|
||||
|
@ -37,6 +37,7 @@ $ignore{'"router ripng"'} = "ignore";
|
||||
$ignore{'"router ospf"'} = "ignore";
|
||||
$ignore{'"router ospf <0-65535>"'} = "ignore";
|
||||
$ignore{'"router ospf6"'} = "ignore";
|
||||
$ignore{'"router babel"'} = "ignore";
|
||||
$ignore{'"router bgp " "<1-4294967295>"'} = "ignore";
|
||||
$ignore{'"router bgp " "<1-4294967295>" " view WORD"'} = "ignore";
|
||||
$ignore{'"router isis WORD"'} = "ignore";
|
||||
@ -68,7 +69,7 @@ foreach (@ARGV) {
|
||||
close (FH);
|
||||
|
||||
@defun = ($line =~ /(?:DEFUN|ALIAS)\s*\((.+?)\);?\s?\s?\n/sg);
|
||||
@install = ($line =~ /install_element \(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg);
|
||||
@install = ($line =~ /install_element\s*\(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg);
|
||||
|
||||
# DEFUN process
|
||||
foreach (@defun) {
|
||||
|
@ -58,6 +58,7 @@ struct vtysh_client
|
||||
{ .fd = -1, .name = "ospf6d", .flag = VTYSH_OSPF6D, .path = OSPF6_VTYSH_PATH},
|
||||
{ .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH},
|
||||
{ .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH},
|
||||
{ .fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .path = BABEL_VTYSH_PATH},
|
||||
};
|
||||
|
||||
#define VTYSH_INDEX_MAX (sizeof(vtysh_client)/sizeof(vtysh_client[0]))
|
||||
@ -797,6 +798,12 @@ static struct cmd_node ospf6_node =
|
||||
"%s(config-ospf6)# "
|
||||
};
|
||||
|
||||
static struct cmd_node babel_node =
|
||||
{
|
||||
BABEL_NODE,
|
||||
"%s(config-babel)# "
|
||||
};
|
||||
|
||||
static struct cmd_node keychain_node =
|
||||
{
|
||||
KEYCHAIN_NODE,
|
||||
@ -1009,6 +1016,17 @@ DEFUNSH (VTYSH_OSPF6D,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_BABELD,
|
||||
router_babel,
|
||||
router_babel_cmd,
|
||||
"router babel",
|
||||
ROUTER_STR
|
||||
"Babel")
|
||||
{
|
||||
vty->node = BABEL_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ISISD,
|
||||
router_isis,
|
||||
router_isis_cmd,
|
||||
@ -1097,6 +1115,7 @@ vtysh_exit (struct vty *vty)
|
||||
case RIPNG_NODE:
|
||||
case OSPF_NODE:
|
||||
case OSPF6_NODE:
|
||||
case BABEL_NODE:
|
||||
case ISIS_NODE:
|
||||
case MASC_NODE:
|
||||
case RMAP_NODE:
|
||||
@ -2252,6 +2271,7 @@ vtysh_init_vty (void)
|
||||
install_node (&ripng_node, NULL);
|
||||
install_node (&ospf6_node, NULL);
|
||||
/* #endif */
|
||||
install_node (&babel_node, NULL);
|
||||
install_node (&keychain_node, NULL);
|
||||
install_node (&keychain_key_node, NULL);
|
||||
install_node (&isis_node, NULL);
|
||||
@ -2273,6 +2293,7 @@ vtysh_init_vty (void)
|
||||
vtysh_install_default (OSPF_NODE);
|
||||
vtysh_install_default (RIPNG_NODE);
|
||||
vtysh_install_default (OSPF6_NODE);
|
||||
vtysh_install_default (BABEL_NODE);
|
||||
vtysh_install_default (ISIS_NODE);
|
||||
vtysh_install_default (KEYCHAIN_NODE);
|
||||
vtysh_install_default (KEYCHAIN_KEY_NODE);
|
||||
@ -2327,6 +2348,7 @@ vtysh_init_vty (void)
|
||||
install_element (RIPNG_NODE, &vtysh_end_all_cmd);
|
||||
install_element (OSPF_NODE, &vtysh_end_all_cmd);
|
||||
install_element (OSPF6_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BABEL_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_IPV4_NODE, &vtysh_end_all_cmd);
|
||||
install_element (BGP_IPV4M_NODE, &vtysh_end_all_cmd);
|
||||
@ -2352,6 +2374,7 @@ vtysh_init_vty (void)
|
||||
#ifdef HAVE_IPV6
|
||||
install_element (CONFIG_NODE, &router_ospf6_cmd);
|
||||
#endif
|
||||
install_element (CONFIG_NODE, &router_babel_cmd);
|
||||
install_element (CONFIG_NODE, &router_isis_cmd);
|
||||
install_element (CONFIG_NODE, &router_bgp_cmd);
|
||||
install_element (CONFIG_NODE, &router_bgp_view_cmd);
|
||||
|
@ -29,9 +29,10 @@
|
||||
#define VTYSH_OSPF6D 0x10
|
||||
#define VTYSH_BGPD 0x20
|
||||
#define VTYSH_ISISD 0x40
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD
|
||||
#define VTYSH_BABELD 0x80
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_BABELD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_BABELD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_BABELD
|
||||
|
||||
/* vtysh local configuration file. */
|
||||
#define VTYSH_DEFAULT_CONFIG "vtysh.conf"
|
||||
|
@ -198,6 +198,8 @@ vtysh_config_parse_line (const char *line)
|
||||
config = config_get (OSPF_NODE, line);
|
||||
else if (strncmp (line, "router ospf6", strlen ("router ospf6")) == 0)
|
||||
config = config_get (OSPF6_NODE, line);
|
||||
else if (strncmp (line, "router babel", strlen ("router babel")) == 0)
|
||||
config = config_get (BABEL_NODE, line);
|
||||
else if (strncmp (line, "router bgp", strlen ("router bgp")) == 0)
|
||||
config = config_get (BGP_NODE, line);
|
||||
else if (strncmp (line, "router isis", strlen ("router isis")) == 0)
|
||||
|
@ -115,6 +115,7 @@ struct zebra_info
|
||||
{ "static", ZEBRA_ROUTE_STATIC },
|
||||
{ "rip", ZEBRA_ROUTE_RIP },
|
||||
{ "ripng", ZEBRA_ROUTE_RIPNG },
|
||||
{ "babel", ZEBRA_ROUTE_BABEL },
|
||||
{ "ospf", ZEBRA_ROUTE_OSPF },
|
||||
{ "ospf6", ZEBRA_ROUTE_OSPF6 },
|
||||
{ "bgp", ZEBRA_ROUTE_BGP },
|
||||
|
@ -55,18 +55,19 @@ static const struct
|
||||
{
|
||||
int key;
|
||||
int distance;
|
||||
} route_info[] =
|
||||
} route_info[ZEBRA_ROUTE_MAX] =
|
||||
{
|
||||
{ZEBRA_ROUTE_SYSTEM, 0},
|
||||
{ZEBRA_ROUTE_KERNEL, 0},
|
||||
{ZEBRA_ROUTE_CONNECT, 0},
|
||||
{ZEBRA_ROUTE_STATIC, 1},
|
||||
{ZEBRA_ROUTE_RIP, 120},
|
||||
{ZEBRA_ROUTE_RIPNG, 120},
|
||||
{ZEBRA_ROUTE_OSPF, 110},
|
||||
{ZEBRA_ROUTE_OSPF6, 110},
|
||||
{ZEBRA_ROUTE_ISIS, 115},
|
||||
{ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */}
|
||||
[ZEBRA_ROUTE_SYSTEM] = {ZEBRA_ROUTE_SYSTEM, 0},
|
||||
[ZEBRA_ROUTE_KERNEL] = {ZEBRA_ROUTE_KERNEL, 0},
|
||||
[ZEBRA_ROUTE_CONNECT] = {ZEBRA_ROUTE_CONNECT, 0},
|
||||
[ZEBRA_ROUTE_STATIC] = {ZEBRA_ROUTE_STATIC, 1},
|
||||
[ZEBRA_ROUTE_RIP] = {ZEBRA_ROUTE_RIP, 120},
|
||||
[ZEBRA_ROUTE_RIPNG] = {ZEBRA_ROUTE_RIPNG, 120},
|
||||
[ZEBRA_ROUTE_OSPF] = {ZEBRA_ROUTE_OSPF, 110},
|
||||
[ZEBRA_ROUTE_OSPF6] = {ZEBRA_ROUTE_OSPF6, 110},
|
||||
[ZEBRA_ROUTE_ISIS] = {ZEBRA_ROUTE_ISIS, 115},
|
||||
[ZEBRA_ROUTE_BGP] = {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */},
|
||||
[ZEBRA_ROUTE_BABEL] = {ZEBRA_ROUTE_BABEL, 95},
|
||||
/* no entry/default: 150 */
|
||||
};
|
||||
|
||||
@ -1235,6 +1236,7 @@ static const u_char meta_queue_map[ZEBRA_ROUTE_MAX] = {
|
||||
[ZEBRA_ROUTE_ISIS] = 2,
|
||||
[ZEBRA_ROUTE_BGP] = 3,
|
||||
[ZEBRA_ROUTE_HSLS] = 4,
|
||||
[ZEBRA_ROUTE_BABEL] = 2,
|
||||
};
|
||||
|
||||
/* Look into the RN and queue it into one or more priority queues,
|
||||
|
@ -556,6 +556,7 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn)
|
||||
#define ONE_WEEK_SECOND 60*60*24*7
|
||||
if (rib->type == ZEBRA_ROUTE_RIP
|
||||
|| rib->type == ZEBRA_ROUTE_OSPF
|
||||
|| rib->type == ZEBRA_ROUTE_BABEL
|
||||
|| rib->type == ZEBRA_ROUTE_ISIS
|
||||
|| rib->type == ZEBRA_ROUTE_BGP)
|
||||
{
|
||||
@ -774,6 +775,7 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib)
|
||||
|
||||
if (rib->type == ZEBRA_ROUTE_RIP
|
||||
|| rib->type == ZEBRA_ROUTE_OSPF
|
||||
|| rib->type == ZEBRA_ROUTE_BABEL
|
||||
|| rib->type == ZEBRA_ROUTE_ISIS
|
||||
|| rib->type == ZEBRA_ROUTE_BGP)
|
||||
{
|
||||
@ -1532,6 +1534,7 @@ vty_show_ipv6_route_detail (struct vty *vty, struct route_node *rn)
|
||||
#define ONE_WEEK_SECOND 60*60*24*7
|
||||
if (rib->type == ZEBRA_ROUTE_RIPNG
|
||||
|| rib->type == ZEBRA_ROUTE_OSPF6
|
||||
|| rib->type == ZEBRA_ROUTE_BABEL
|
||||
|| rib->type == ZEBRA_ROUTE_ISIS
|
||||
|| rib->type == ZEBRA_ROUTE_BGP)
|
||||
{
|
||||
@ -1711,6 +1714,7 @@ vty_show_ipv6_route (struct vty *vty, struct route_node *rn,
|
||||
|
||||
if (rib->type == ZEBRA_ROUTE_RIPNG
|
||||
|| rib->type == ZEBRA_ROUTE_OSPF6
|
||||
|| rib->type == ZEBRA_ROUTE_BABEL
|
||||
|| rib->type == ZEBRA_ROUTE_ISIS
|
||||
|| rib->type == ZEBRA_ROUTE_BGP)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user