mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
*: Initial Import of Babeld into FRR
This is a direct copy of: https://github.com/boutier/quagga-merge From the branch babel-merge I copied the babeld directory into FRR and then fixed up everything to compile. Babeld at this point in time when run will more than likely crash and burn in it's interfactions with zebra. I might have messed up the cli, which will need to be looked at extract.pl.in and vtysh.c need to be fixed up. Additionally we probably need to work on DEFUN_NOSH conversion in babeld as well This code comes from: Matthieu Boutier <boutier@irif.fr> Juliusz Chroboczek <jch@irif.fr> Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com>
This commit is contained in:
parent
8d7bba2874
commit
ca10883edc
|
@ -2,13 +2,14 @@
|
|||
|
||||
SUBDIRS = lib qpb fpm @ZEBRA@ @LIBRFP@ @RFPTEST@ \
|
||||
@BGPD@ @RIPD@ @RIPNGD@ @OSPFD@ @OSPF6D@ @LDPD@ \
|
||||
@ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ \
|
||||
@ISISD@ @PIMD@ @NHRPD@ @EIGRPD@ @BABELD@ \
|
||||
@WATCHFRR@ @VTYSH@ @OSPFCLIENT@ @DOC@ m4 @pkgsrcdir@ \
|
||||
redhat @SOLARIS@ tests tools snapcraft
|
||||
|
||||
DIST_SUBDIRS = lib qpb fpm zebra bgpd ripd ripngd ospfd ospf6d ldpd \
|
||||
isisd watchfrr vtysh ospfclient doc m4 pkgsrc redhat tests \
|
||||
solaris pimd nhrpd eigrpd @LIBRFP@ @RFPTEST@ tools snapcraft
|
||||
solaris pimd nhrpd eigrpd @LIBRFP@ @RFPTEST@ tools snapcraft \
|
||||
babeld
|
||||
|
||||
EXTRA_DIST = aclocal.m4 SERVICES REPORTING-BUGS \
|
||||
update-autotools \
|
||||
|
|
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
|
19
babeld/LICENCE
Normal file
19
babeld/LICENCE
Normal file
|
@ -0,0 +1,19 @@
|
|||
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.
|
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.
|
||||
|
||||
AM_CPPFLAGS = -I.. -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir)/lib
|
||||
DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\"
|
||||
INSTALL_SDATA=@INSTALL@ -m 600
|
||||
|
||||
AM_CFLAGS = $(PICFLAGS) $(WERROR)
|
||||
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 babel_memory.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 babel_main.h babel_memory.h
|
||||
|
||||
babeld_SOURCES = \
|
||||
babel_main.c $(libbabel_a_SOURCES)
|
||||
|
||||
babeld_LDADD = ../lib/libfrr.la @LIBCAP@
|
||||
|
||||
examplesdir = $(exampledir)
|
||||
dist_examples_DATA = babeld.conf.sample
|
113
babeld/babel_filter.c
Normal file
113
babeld/babel_filter.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
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, VRF_DEFAULT);
|
||||
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 distribute;
|
||||
|
||||
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);
|
||||
distribute = output ? DISTRIBUTE_V4_OUT : DISTRIBUTE_V4_IN;
|
||||
} else {
|
||||
uchar_to_in6addr(&p.u.prefix6, prefix);
|
||||
distribute = output ? DISTRIBUTE_V6_OUT : DISTRIBUTE_V6_IN;
|
||||
}
|
||||
|
||||
if (babel_ifp != NULL && babel_ifp->list[distribute]) {
|
||||
if (access_list_apply (babel_ifp->list[distribute], &p)
|
||||
== FILTER_DENY) {
|
||||
debugf(BABEL_DEBUG_FILTER,
|
||||
"%s/%d filtered by distribute %s",
|
||||
p.family == AF_INET ?
|
||||
inet_ntoa(p.u.prefix4) :
|
||||
inet6_ntoa (p.u.prefix6),
|
||||
p.prefixlen,
|
||||
output ? "out" : "in");
|
||||
return INFINITY;
|
||||
}
|
||||
}
|
||||
if (babel_ifp != NULL && babel_ifp->prefix[distribute]) {
|
||||
if (prefix_list_apply (babel_ifp->prefix[distribute], &p)
|
||||
== PREFIX_DENY) {
|
||||
debugf(BABEL_DEBUG_FILTER, "%s/%d filtered by distribute %s",
|
||||
p.family == AF_INET ?
|
||||
inet_ntoa(p.u.prefix4) :
|
||||
inet6_ntoa (p.u.prefix6),
|
||||
p.prefixlen,
|
||||
output ? "out" : "in");
|
||||
return INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
/* All interface filter check. */
|
||||
dist = distribute_lookup (NULL);
|
||||
if (dist) {
|
||||
if (dist->list[distribute]) {
|
||||
alist = access_list_lookup (p.family, dist->list[distribute]);
|
||||
|
||||
if (alist) {
|
||||
if (access_list_apply (alist, &p) == FILTER_DENY) {
|
||||
debugf(BABEL_DEBUG_FILTER,"%s/%d filtered by distribute %s",
|
||||
p.family == AF_INET ?
|
||||
inet_ntoa(p.u.prefix4) :
|
||||
inet6_ntoa (p.u.prefix6),
|
||||
p.prefixlen,
|
||||
output ? "out" : "in");
|
||||
return INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dist->prefix[distribute]) {
|
||||
plist = prefix_list_lookup (p.family, dist->prefix[distribute]);
|
||||
if (plist) {
|
||||
if (prefix_list_apply (plist, &p) == PREFIX_DENY) {
|
||||
debugf(BABEL_DEBUG_FILTER,"%s/%d filtered by distribute %s",
|
||||
p.family == AF_INET ?
|
||||
inet_ntoa(p.u.prefix4) :
|
||||
inet6_ntoa (p.u.prefix6),
|
||||
p.prefixlen,
|
||||
output ? "out" : "in");
|
||||
return INFINITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
33
babeld/babel_filter.h
Normal file
33
babeld/babel_filter.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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 */
|
1436
babeld/babel_interface.c
Normal file
1436
babeld/babel_interface.c
Normal file
File diff suppressed because it is too large
Load diff
144
babeld/babel_interface.h
Normal file
144
babeld/babel_interface.h
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
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"
|
||||
#include "distribute.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;
|
||||
/* Relative position of the Hello message in the send buffer, or
|
||||
(-1) if there is none. */
|
||||
int 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;
|
||||
/* A higher value means we forget old RTT samples faster. Must be
|
||||
between 1 and 256, inclusive. */
|
||||
unsigned int rtt_decay;
|
||||
/* Parameters for computing the cost associated to RTT. */
|
||||
unsigned int rtt_min;
|
||||
unsigned int rtt_max;
|
||||
unsigned int max_rtt_penalty;
|
||||
|
||||
/* For filter type slot. */
|
||||
struct access_list *list[DISTRIBUTE_MAX]; /* Access-list. */
|
||||
struct prefix_list *prefix[DISTRIBUTE_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)
|
||||
#define BABEL_IF_TIMESTAMPS (1 << 5)
|
||||
|
||||
/* 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(vrf_iflist(VRF_DEFAULT), _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, vrf_id_t);
|
||||
int babel_interface_down (int, struct zclient *, zebra_size_t, vrf_id_t);
|
||||
int babel_interface_add (int, struct zclient *, zebra_size_t, vrf_id_t);
|
||||
int babel_interface_delete (int, struct zclient *, zebra_size_t, vrf_id_t);
|
||||
int babel_interface_address_add (int, struct zclient *, zebra_size_t, vrf_id_t);
|
||||
int babel_interface_address_delete (int, struct zclient *, zebra_size_t, vrf_id_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
|
410
babeld/babel_main.c
Normal file
410
babeld/babel_main.c
Normal file
|
@ -0,0 +1,410 @@
|
|||
/*
|
||||
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 "libfrr.h"
|
||||
|
||||
#include "babel_main.h"
|
||||
#include "babeld.h"
|
||||
#include "util.h"
|
||||
#include "kernel.h"
|
||||
#include "babel_interface.h"
|
||||
#include "neighbour.h"
|
||||
#include "route.h"
|
||||
#include "xroute.h"
|
||||
#include "message.h"
|
||||
#include "resend.h"
|
||||
#include "babel_zebra.h"
|
||||
|
||||
|
||||
static void babel_init (int argc, char **argv);
|
||||
static void babel_fail(void);
|
||||
static void babel_init_random(void);
|
||||
static void babel_replace_by_null(int fd);
|
||||
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;
|
||||
|
||||
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 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
|
||||
};
|
||||
|
||||
static void
|
||||
babel_sigexit(void)
|
||||
{
|
||||
zlog_notice("Terminating on signal");
|
||||
|
||||
babel_exit_properly();
|
||||
}
|
||||
|
||||
static void
|
||||
babel_sigusr1 (void)
|
||||
{
|
||||
zlog_rotate ();
|
||||
}
|
||||
|
||||
static struct quagga_signal_t babel_signals[] =
|
||||
{
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
.handler = &babel_sigusr1,
|
||||
},
|
||||
{
|
||||
.signal = SIGINT,
|
||||
.handler = &babel_sigexit,
|
||||
},
|
||||
{
|
||||
.signal = SIGTERM,
|
||||
.handler = &babel_sigexit,
|
||||
},
|
||||
};
|
||||
|
||||
struct option longopts[] =
|
||||
{
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
FRR_DAEMON_INFO(babeld, BABELD,
|
||||
.vty_port = BABEL_VTY_PORT,
|
||||
.proghelp = "Implementation of the BABEL routing protocol.",
|
||||
|
||||
.signals = babel_signals,
|
||||
.n_signals = array_size(babel_signals),
|
||||
|
||||
.privs = &babeld_privs,
|
||||
)
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
struct thread thread;
|
||||
/* and print banner too */
|
||||
babel_init(argc, argv);
|
||||
while (thread_fetch (master, &thread)) {
|
||||
thread_call (&thread);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* make initialisations witch don't need infos about kernel(interfaces, etc.) */
|
||||
static void
|
||||
babel_init(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
|
||||
frr_preinit (&babeld_di, argc, argv);
|
||||
frr_opt_add ("", longopts, "");
|
||||
|
||||
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) {
|
||||
int opt;
|
||||
|
||||
opt = frr_getopt (argc, argv, NULL);
|
||||
|
||||
if (opt == EOF)
|
||||
break;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
frr_help_exit (1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* create the threads handler */
|
||||
master = thread_master_create ();
|
||||
|
||||
/* Library inits. */
|
||||
zprivs_init (&babeld_privs);
|
||||
cmd_init (1);
|
||||
vty_init (master);
|
||||
|
||||
resend_delay = BABEL_DEFAULT_RESEND_DELAY;
|
||||
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
|
||||
|
||||
babel_replace_by_null(STDIN_FILENO);
|
||||
|
||||
/* 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 ();
|
||||
|
||||
/* Get zebra configuration file. */
|
||||
vty_read_config (babel_config_file, babel_config_default);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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_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.");
|
||||
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,
|
||||
"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"
|
||||
"kernel_metric = %d%s",
|
||||
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,
|
||||
kernel_metric, VTY_NEWLINE);
|
||||
}
|
46
babeld/babel_main.h
Normal file
46
babeld/babel_main.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
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_MAIN_H
|
||||
#define BABEL_MAIN_H
|
||||
|
||||
#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);
|
||||
|
||||
#endif /* BABEL_MAIN_H */
|
30
babeld/babel_memory.c
Normal file
30
babeld/babel_memory.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* babeld memory type definitions
|
||||
*
|
||||
* Copyright (C) 2017 Donald Sharp
|
||||
*
|
||||
* This file is part of FRR
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR 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 FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "babel_memory.h"
|
||||
|
||||
DEFINE_MGROUP(BABELD, "babeld")
|
||||
DEFINE_MTYPE(BABELD, BABEL, "Babel Structure")
|
||||
DEFINE_MTYPE(BABELD, BABEL_IF, "Babel Interface")
|
32
babeld/babel_memory.h
Normal file
32
babeld/babel_memory.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* babel memory type declarations
|
||||
*
|
||||
* Copyright (C) 2017 Donald Sharp
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* FRR is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2, or (at your option) any
|
||||
* later version.
|
||||
*
|
||||
* FRR 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 FRR; see the file COPYING. If not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _FRR_BABEL_MEMORY_H
|
||||
#define _FRR_BABEL_MEMORY_H
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
DECLARE_MGROUP(BABELD)
|
||||
DECLARE_MTYPE(BABEL)
|
||||
DECLARE_MTYPE(BABEL_IF)
|
||||
|
||||
#endif /* _FRR_BABELD_MEMORY_H */
|
394
babeld/babel_zebra.c
Normal file
394
babeld/babel_zebra.c
Normal file
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
/* FRR'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}
|
||||
};
|
||||
|
||||
static struct {
|
||||
int str_min_len;
|
||||
const char *str;
|
||||
} proto_redistnum_type[ZEBRA_ROUTE_MAX] = {
|
||||
[ZEBRA_ROUTE_BABEL] = {2, "babel"},
|
||||
[ZEBRA_ROUTE_BGP] = {2, "bgp"},
|
||||
[ZEBRA_ROUTE_CONNECT] = {1, "connected"},
|
||||
[ZEBRA_ROUTE_HSLS] = {1, "hsls"},
|
||||
[ZEBRA_ROUTE_ISIS] = {1, "isis"},
|
||||
[ZEBRA_ROUTE_KERNEL] = {1, "kernel"},
|
||||
[ZEBRA_ROUTE_OLSR] = {2, "olsr"},
|
||||
[ZEBRA_ROUTE_OSPF] = {2, "ospf"},
|
||||
[ZEBRA_ROUTE_OSPF6] = {5, "ospf6"},
|
||||
[ZEBRA_ROUTE_RIP] = {1, "rip"},
|
||||
[ZEBRA_ROUTE_RIPNG] = {4, "ripng"},
|
||||
[ZEBRA_ROUTE_STATIC] = {2, "static"},
|
||||
[ZEBRA_ROUTE_SYSTEM] = {2, "system"},
|
||||
};
|
||||
|
||||
/* 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_IPV4_ROUTE_ADD) {
|
||||
babel_ipv4_route_add(&api, &prefix, ifindex, &nexthop);
|
||||
} else {
|
||||
babel_ipv4_route_delete(&api, &prefix, ifindex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_proto_redistnum(const char *s)
|
||||
{
|
||||
int i;
|
||||
if (! s)
|
||||
return -1;
|
||||
int len = strlen(s);
|
||||
|
||||
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
|
||||
if (len <= (int)strlen(proto_redistnum_type[i].str) &&
|
||||
strncmp(proto_redistnum_type[i].str, s,
|
||||
proto_redistnum_type[i].str_min_len) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (babel_redistribute_type,
|
||||
babel_redistribute_type_cmd,
|
||||
"redistribute " FRR_REDIST_STR_BABELD,
|
||||
"Redistribute\n"
|
||||
FRR_REDIST_HELP_STR_BABELD)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = babel_proto_redistnum(argv[1]->arg);
|
||||
|
||||
if (type < 0) {
|
||||
vty_out(vty, "Invalid type %s%s", argv[1]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type, 0, VRF_DEFAULT);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (no_babel_redistribute_type,
|
||||
no_babel_redistribute_type_cmd,
|
||||
"no redistribute " FRR_REDIST_STR_BABELD,
|
||||
NO_STR
|
||||
"Redistribute\n"
|
||||
FRR_REDIST_HELP_STR_BABELD)
|
||||
{
|
||||
int type;
|
||||
|
||||
type = babel_proto_redistnum(argv[2]->arg);
|
||||
|
||||
if (type < 0) {
|
||||
vty_out(vty, "Invalid type %s%s", argv[2]->arg, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
zclient_redistribute (ZEBRA_REDISTRIBUTE_DELETE, zclient, AFI_IP, type, 0, VRF_DEFAULT);
|
||||
/* 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[2]->arg,
|
||||
debug_type[i].str_min_len) == 0) {
|
||||
debug |= debug_type[i].type;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[2]->arg, 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[3]->arg,
|
||||
debug_type[i].str_min_len) == 0) {
|
||||
debug &= ~debug_type[i].type;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
vty_out(vty, "Invalid type %s%s", argv[3]->arg, 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(master);
|
||||
zclient_init(zclient, ZEBRA_ROUTE_BABEL, 0);
|
||||
|
||||
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->redistribute_route_ipv4_add = babel_zebra_read_ipv4;
|
||||
zclient->redistribute_route_ipv4_del = babel_zebra_read_ipv4;
|
||||
zclient->redistribute_route_ipv6_add = babel_zebra_read_ipv6;
|
||||
zclient->redistribute_route_ipv6_del = 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);
|
||||
}
|
34
babeld/babel_zebra.h
Normal file
34
babeld/babel_zebra.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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
|
759
babeld/babeld.c
Normal file
759
babeld/babeld.c
Normal file
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
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 "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"
|
||||
#include "babel_memory.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 (diversity_kind != DIVERSITY_NONE)
|
||||
{
|
||||
vty_out (vty, " babel diversity%s", VTY_NEWLINE);
|
||||
lines++;
|
||||
}
|
||||
if (diversity_factor != BABEL_DEFAULT_DIVERSITY_FACTOR)
|
||||
{
|
||||
vty_out (vty, " babel diversity-factor %d%s", diversity_factor,
|
||||
VTY_NEWLINE);
|
||||
lines++;
|
||||
}
|
||||
if (resend_delay != BABEL_DEFAULT_RESEND_DELAY)
|
||||
{
|
||||
vty_out (vty, " babel resend-delay %u%s", resend_delay, VTY_NEWLINE);
|
||||
lines++;
|
||||
}
|
||||
if (smoothing_half_life != BABEL_DEFAULT_SMOOTHING_HALF_LIFE)
|
||||
{
|
||||
vty_out (vty, " babel smoothing-half-life %u%s",
|
||||
smoothing_half_life, 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++;
|
||||
}
|
||||
|
||||
lines += config_write_distribute (vty);
|
||||
|
||||
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. */
|
||||
thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
|
||||
/* wait a little: zebra will announce interfaces, addresses, routes... */
|
||||
thread_add_timer_msec(master, babel_init_routing_process, NULL, 200L, &babel_routing_process->t_update);
|
||||
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 == (ifindex_t)sin6.sin6_scope_id) {
|
||||
parse_packet((unsigned char*)&sin6.sin6_addr, ifp,
|
||||
receive_buffer, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* re-add thread */
|
||||
thread_add_read(master, &babel_read_protocol, NULL, protocol_socket, &babel_routing_process->t_read);
|
||||
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();
|
||||
/* Multiply by 3/2 to allow neighbours to expire. */
|
||||
msecs = MAX(3 * msecs / 2, 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);
|
||||
}
|
||||
thread_add_timer_msec(master, babel_main_loop, NULL, msecs, &babel_routing_process->t_update);
|
||||
}
|
||||
|
||||
void
|
||||
schedule_neighbours_check(int msecs, int override)
|
||||
{
|
||||
struct timeval timeout;
|
||||
|
||||
timeval_add_msec(&timeout, &babel_now, msecs);
|
||||
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;
|
||||
int type;
|
||||
int family;
|
||||
|
||||
if (! dist->ifname)
|
||||
return;
|
||||
|
||||
ifp = if_lookup_by_name (dist->ifname, VRF_DEFAULT);
|
||||
if (ifp == NULL)
|
||||
return;
|
||||
|
||||
babel_ifp = babel_get_if_nfo(ifp);
|
||||
|
||||
for (type = 0; type < DISTRIBUTE_MAX; type++) {
|
||||
family = type == DISTRIBUTE_V4_IN || type == DISTRIBUTE_V4_OUT ?
|
||||
AFI_IP : AFI_IP6;
|
||||
if (dist->list[type])
|
||||
babel_ifp->list[type] = access_list_lookup (family,
|
||||
dist->list[type]);
|
||||
else
|
||||
babel_ifp->list[type] = NULL;
|
||||
if (dist->prefix[type])
|
||||
babel_ifp->prefix[type] = prefix_list_lookup (family,
|
||||
dist->prefix[type]);
|
||||
else
|
||||
babel_ifp->prefix[type] = 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 (vrf_iflist(VRF_DEFAULT), 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_diversity,
|
||||
babel_diversity_cmd,
|
||||
"babel diversity",
|
||||
"Babel commands\n"
|
||||
"Enable diversity-aware routing.\n")
|
||||
{
|
||||
diversity_kind = DIVERSITY_CHANNEL;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (no_babel_diversity,
|
||||
no_babel_diversity_cmd,
|
||||
"no babel diversity",
|
||||
NO_STR
|
||||
"Babel commands\n"
|
||||
"Disable diversity-aware routing.\n")
|
||||
{
|
||||
diversity_kind = DIVERSITY_NONE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (babel_diversity_factor,
|
||||
babel_diversity_factor_cmd,
|
||||
"babel diversity-factor (1-256)",
|
||||
"Babel commands\n"
|
||||
"Set the diversity factor.\n"
|
||||
"Factor in units of 1/256.\n")
|
||||
{
|
||||
int factor;
|
||||
|
||||
VTY_GET_INTEGER_RANGE("factor", factor, argv[2]->arg, 1, 256);
|
||||
|
||||
diversity_factor = factor;
|
||||
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[2]->arg, 20, 10 * 0xFFFE);
|
||||
|
||||
resend_delay = interval;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* [Babel Command] */
|
||||
DEFUN (babel_set_smoothing_half_life,
|
||||
babel_set_smoothing_half_life_cmd,
|
||||
"babel smoothing-half-life (0-65534)",
|
||||
"Babel commands\n"
|
||||
"Smoothing half-life\n"
|
||||
"Seconds (0 to disable)\n")
|
||||
{
|
||||
int seconds;
|
||||
|
||||
VTY_GET_INTEGER_RANGE("seconds", seconds, argv[2]->arg, 0, 0xFFFE);
|
||||
|
||||
change_smoothing_half_life(seconds);
|
||||
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_diversity_cmd);
|
||||
install_element(BABEL_NODE, &no_babel_diversity_cmd);
|
||||
install_element(BABEL_NODE, &babel_diversity_factor_cmd);
|
||||
install_element(BABEL_NODE, &babel_set_resend_delay_cmd);
|
||||
install_element(BABEL_NODE, &babel_set_smoothing_half_life_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
|
129
babeld/babeld.h
Normal file
129
babeld/babeld.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
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 2613
|
||||
#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
|
||||
|
||||
/* In units of seconds */
|
||||
#define BABEL_DEFAULT_SMOOTHING_HALF_LIFE 4
|
||||
|
||||
/* In units of 1/256. */
|
||||
#define BABEL_DEFAULT_DIVERSITY_FACTOR 256
|
||||
|
||||
#define BABEL_DEFAULT_RXCOST_WIRED 96
|
||||
#define BABEL_DEFAULT_RXCOST_WIRELESS 256
|
||||
|
||||
/* 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 */
|
296
babeld/kernel.c
Normal file
296
babeld/kernel.c
Normal file
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
Copyright 2007, 2008 by Grégoire Henry, Julien Cristau and Juliusz Chroboczek
|
||||
Copyright 2011, 2012 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/time.h>
|
||||
#include <sys/param.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "babeld.h"
|
||||
|
||||
|
||||
#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_REJECT;
|
||||
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)
|
||||
{
|
||||
ifindex_t 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;
|
||||
if(metric >= KERNEL_INFINITY) {
|
||||
api.flags = ZEBRA_FLAG_REJECT;
|
||||
api.nexthop_num = 0;
|
||||
api.ifindex_num = 0;
|
||||
} else {
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
api.nexthop_num = 1;
|
||||
api.nexthop = &nexthop_pointer;
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_IFINDEX);
|
||||
api.ifindex_num = 1;
|
||||
api.ifindex = &tmp_ifindex;
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
|
||||
api.metric = metric;
|
||||
}
|
||||
|
||||
debugf(BABEL_DEBUG_ROUTE, "%s route (ipv6) to zebra",
|
||||
add ? "adding" : "removing" );
|
||||
return zapi_ipv6_route (add ? ZEBRA_IPV6_ROUTE_ADD :
|
||||
ZEBRA_IPV6_ROUTE_DELETE,
|
||||
zclient, &quagga_prefix, NULL, &api);
|
||||
}
|
||||
|
||||
int
|
||||
if_eui64(char *ifname, int ifindex, unsigned char *eui)
|
||||
{
|
||||
struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 monotime(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;
|
||||
}
|
47
babeld/kernel.h
Normal file
47
babeld/kernel.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
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_KERNEL_H
|
||||
#define BABEL_KERNEL_H
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include "babel_main.h"
|
||||
#include "if.h"
|
||||
|
||||
#define KERNEL_INFINITY 0xFFFF
|
||||
|
||||
#define ROUTE_FLUSH 0
|
||||
#define ROUTE_ADD 1
|
||||
#define ROUTE_MODIFY 2
|
||||
|
||||
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);
|
||||
|
||||
#endif /* BABEL_KERNEL_H */
|
1802
babeld/message.c
Normal file
1802
babeld/message.c
Normal file
File diff suppressed because it is too large
Load diff
101
babeld/message.h
Normal file
101
babeld/message.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
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
|
||||
|
||||
/* A registry of assigned TLV and sub-TLV types is available at
|
||||
http://www.pps.univ-paris-diderot.fr/~jch/software/babel/babel-tlv-registry.text
|
||||
*/
|
||||
#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
|
||||
#define MESSAGE_MAX 10
|
||||
|
||||
/* Protocol extension through sub-TLVs. */
|
||||
#define SUBTLV_PAD1 0
|
||||
#define SUBTLV_PADN 1
|
||||
#define SUBTLV_DIVERSITY 2 /* Also known as babelz. */
|
||||
#define SUBTLV_TIMESTAMP 3 /* Used to compute RTT. */
|
||||
|
||||
extern unsigned short myseqno;
|
||||
|
||||
extern int broadcast_ihu;
|
||||
extern int split_horizon;
|
||||
|
||||
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
|
366
babeld/neighbour.c
Normal file
366
babeld/neighbour.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
/*
|
||||
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)
|
||||
{
|
||||
debugf(BABEL_DEBUG_COMMON,"Flushing neighbour %s (reach 0x%04x)",
|
||||
format_address(neigh->address), neigh->reach);
|
||||
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->hello_send_us = 0;
|
||||
neigh->hello_rtt_receive_time = zero;
|
||||
neigh->rtt = 0;
|
||||
neigh->rtt_time = zero;
|
||||
neigh->ifp = ifp;
|
||||
neigh->next = neighs;
|
||||
neighs = neigh;
|
||||
send_hello(ifp);
|
||||
return neigh;
|
||||
}
|
||||
|
||||
/* Recompute a neighbour's rxcost. Return true if anything changed. */
|
||||
int
|
||||
update_neighbour(struct neighbour *neigh, int hello, int hello_interval)
|
||||
{
|
||||
int missed_hellos;
|
||||
int rc = 0;
|
||||
|
||||
if(hello < 0) {
|
||||
if(neigh->hello_interval <= 0)
|
||||
return rc;
|
||||
missed_hellos =
|
||||
((int)timeval_minus_msec(&babel_now, &neigh->hello_time) -
|
||||
neigh->hello_interval * 7) /
|
||||
(neigh->hello_interval * 10);
|
||||
if(missed_hellos <= 0)
|
||||
return rc;
|
||||
timeval_add_msec(&neigh->hello_time, &neigh->hello_time,
|
||||
missed_hellos * neigh->hello_interval * 10);
|
||||
} else {
|
||||
if(neigh->hello_seqno >= 0 && neigh->reach > 0) {
|
||||
missed_hellos = seqno_minus(hello, neigh->hello_seqno) - 1;
|
||||
if(missed_hellos < -8) {
|
||||
/* Probably a neighbour that rebooted and lost its seqno.
|
||||
Reboot the universe. */
|
||||
neigh->reach = 0;
|
||||
missed_hellos = 0;
|
||||
rc = 1;
|
||||
} else if(missed_hellos < 0) {
|
||||
if(hello_interval > neigh->hello_interval) {
|
||||
/* This neighbour has increased its hello interval,
|
||||
and we didn't notice. */
|
||||
neigh->reach <<= -missed_hellos;
|
||||
missed_hellos = 0;
|
||||
} else {
|
||||
/* Late hello. Probably due to the link layer buffering
|
||||
packets during a link outage. Ignore it, but reset
|
||||
the expected seqno. */
|
||||
neigh->hello_seqno = hello;
|
||||
hello = -1;
|
||||
missed_hellos = 0;
|
||||
}
|
||||
rc = 1;
|
||||
}
|
||||
} else {
|
||||
missed_hellos = 0;
|
||||
}
|
||||
neigh->hello_time = babel_now;
|
||||
neigh->hello_interval = hello_interval;
|
||||
}
|
||||
|
||||
if(missed_hellos > 0) {
|
||||
neigh->reach >>= missed_hellos;
|
||||
neigh->hello_seqno = seqno_plus(neigh->hello_seqno, missed_hellos);
|
||||
missed_hellos = 0;
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
if(hello >= 0) {
|
||||
neigh->hello_seqno = hello;
|
||||
neigh->reach >>= 1;
|
||||
neigh->reach |= 0x8000;
|
||||
if((neigh->reach & 0xFC00) != 0xFC00)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
/* Make sure to give neighbours some feedback early after association */
|
||||
if((neigh->reach & 0xBF00) == 0x8000) {
|
||||
/* A new neighbour */
|
||||
send_hello(neigh->ifp);
|
||||
} else {
|
||||
/* Don't send hellos, in order to avoid a positive feedback loop. */
|
||||
int a = (neigh->reach & 0xC000);
|
||||
int b = (neigh->reach & 0x3000);
|
||||
if((a == 0xC000 && b == 0) || (a == 0 && b == 0x3000)) {
|
||||
/* Reachability is either 1100 or 0011 */
|
||||
send_self_update(neigh->ifp);
|
||||
}
|
||||
}
|
||||
|
||||
if((neigh->reach & 0xFC00) == 0xC000) {
|
||||
/* This is a newish neighbour, let's request a full route dump.
|
||||
We ought to avoid this when the network is dense */
|
||||
send_unicast_request(neigh, NULL, 0);
|
||||
send_ihu(neigh, NULL);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
reset_txcost(struct neighbour *neigh)
|
||||
{
|
||||
unsigned delay;
|
||||
|
||||
delay = timeval_minus_msec(&babel_now, &neigh->ihu_time);
|
||||
|
||||
if(neigh->ihu_interval > 0 && delay < neigh->ihu_interval * 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_rttcost(struct neighbour *neigh)
|
||||
{
|
||||
struct interface *ifp = neigh->ifp;
|
||||
babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp);
|
||||
|
||||
if(!babel_ifp->max_rtt_penalty || !valid_rtt(neigh))
|
||||
return 0;
|
||||
|
||||
/* Function: linear behaviour between rtt_min and rtt_max. */
|
||||
if(neigh->rtt <= babel_ifp->rtt_min) {
|
||||
return 0;
|
||||
} else if(neigh->rtt <= babel_ifp->rtt_max) {
|
||||
unsigned long long tmp =
|
||||
(unsigned long long)babel_ifp->max_rtt_penalty *
|
||||
(neigh->rtt - babel_ifp->rtt_min) /
|
||||
(babel_ifp->rtt_max - babel_ifp->rtt_min);
|
||||
assert((tmp & 0x7FFFFFFF) == tmp);
|
||||
return tmp;
|
||||
} else {
|
||||
return babel_ifp->max_rtt_penalty;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
neighbour_cost(struct neighbour *neigh)
|
||||
{
|
||||
unsigned a, b, cost;
|
||||
|
||||
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)) {
|
||||
cost = 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. */
|
||||
cost = (a * b + 128) >> 8;
|
||||
}
|
||||
|
||||
cost += neighbour_rttcost(neigh);
|
||||
|
||||
return MIN(cost, INFINITY);
|
||||
}
|
||||
|
||||
int
|
||||
valid_rtt(struct neighbour *neigh)
|
||||
{
|
||||
return (timeval_minus_msec(&babel_now, &neigh->rtt_time) < 180000) ? 1 : 0;
|
||||
}
|
64
babeld/neighbour.h
Normal file
64
babeld/neighbour.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
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_NEIGHBOUR_H
|
||||
#define BABEL_NEIGHBOUR_H
|
||||
|
||||
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 */
|
||||
/* Used for RTT estimation. */
|
||||
/* Absolute time (modulo 2^32) at which the Hello was sent,
|
||||
according to remote clock. */
|
||||
unsigned int hello_send_us;
|
||||
struct timeval hello_rtt_receive_time;
|
||||
unsigned int rtt;
|
||||
struct timeval rtt_time;
|
||||
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_rttcost(struct neighbour *neigh);
|
||||
unsigned neighbour_cost(struct neighbour *neigh);
|
||||
int valid_rtt(struct neighbour *neigh);
|
||||
|
||||
#endif /* BABEL_NEIGHBOUR_H */
|
218
babeld/net.c
Normal file
218
babeld/net.c
Normal file
|
@ -0,0 +1,218 @@
|
|||
/*
|
||||
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 <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "babeld.h"
|
||||
#include "util.h"
|
||||
#include "net.h"
|
||||
#include "sockopt.h"
|
||||
|
||||
int
|
||||
babel_socket(int port)
|
||||
{
|
||||
struct sockaddr_in6 sin6;
|
||||
int s, rc;
|
||||
int saved_errno;
|
||||
int one = 1, zero = 0;
|
||||
|
||||
s = socket(PF_INET6, SOCK_DGRAM, 0);
|
||||
if(s < 0)
|
||||
return -1;
|
||||
|
||||
rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
|
||||
if(rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
if(rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
&zero, sizeof(zero));
|
||||
if(rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
|
||||
&one, sizeof(one));
|
||||
if(rc < 0)
|
||||
goto fail;
|
||||
|
||||
rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
||||
&one, sizeof(one));
|
||||
if(rc < 0)
|
||||
goto fail;
|
||||
|
||||
setsockopt_ipv6_tclass (s, IPTOS_PREC_INTERNETCONTROL);
|
||||
|
||||
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;
|
||||
}
|
33
babeld/net.h
Normal file
33
babeld/net.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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_NET_H
|
||||
#define BABEL_NET_H
|
||||
|
||||
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);
|
||||
|
||||
#endif /* BABEL_NET_H */
|
314
babeld/resend.c
Normal file
314
babeld/resend.c
Normal file
|
@ -0,0 +1,314 @@
|
|||
/*
|
||||
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();
|
||||
}
|
65
babeld/resend.h
Normal file
65
babeld/resend.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
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_RESEND_H
|
||||
#define BABEL_RESEND_H
|
||||
|
||||
#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);
|
||||
|
||||
#endif /* BABEL_RESEND_H */
|
1142
babeld/route.c
Normal file
1142
babeld/route.c
Normal file
File diff suppressed because it is too large
Load diff
126
babeld/route.h
Normal file
126
babeld/route.h
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
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 */
|
||||
unsigned short smoothed_metric; /* for route selection */
|
||||
time_t smoothed_metric_time;
|
||||
short installed;
|
||||
unsigned char channels[DIVERSITY_HOPS];
|
||||
struct babel_route *next;
|
||||
};
|
||||
|
||||
struct route_stream;
|
||||
|
||||
extern struct babel_route **routes;
|
||||
extern int kernel_metric;
|
||||
extern int diversity_kind, diversity_factor;
|
||||
extern int keep_unfeasible;
|
||||
extern int smoothing_half_life;
|
||||
|
||||
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);
|
||||
struct route_stream *route_stream(int installed);
|
||||
struct babel_route *route_stream_next(struct route_stream *stream);
|
||||
void route_stream_done(struct route_stream *stream);
|
||||
void install_route(struct babel_route *route);
|
||||
void uninstall_route(struct babel_route *route);
|
||||
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);
|
||||
void change_smoothing_half_life(int half_life);
|
||||
int route_smoothed_metric(struct babel_route *route);
|
||||
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
|
164
babeld/source.c
Normal file
164
babeld/source.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
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);
|
||||
}
|
||||
}
|
51
babeld/source.h
Normal file
51
babeld/source.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
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
|
459
babeld/util.c
Normal file
459
babeld/util.c
Normal file
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
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 <limits.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"
|
||||
|
||||
int
|
||||
roughly(int value)
|
||||
{
|
||||
if(value < 0)
|
||||
return -roughly(-value);
|
||||
else if(value <= 1)
|
||||
return value;
|
||||
else
|
||||
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, 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;
|
||||
}
|
||||
|
||||
/* There's no good name for a positive int in C, call it nat. */
|
||||
int
|
||||
parse_nat(const char *string)
|
||||
{
|
||||
long l;
|
||||
char *end;
|
||||
|
||||
l = strtol(string, &end, 0);
|
||||
|
||||
while(*end == ' ' || *end == '\t')
|
||||
end++;
|
||||
if(*end != '\0')
|
||||
return -1;
|
||||
|
||||
if(l < 0 || l > INT_MAX)
|
||||
return -1;
|
||||
|
||||
return (int)l;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_thousands(unsigned int value)
|
||||
{
|
||||
static char buf[4][15];
|
||||
static int i = 0;
|
||||
i = (i + 1) % 4;
|
||||
snprintf(buf[i], 15, "%d.%.3d", value / 1000, value % 1000);
|
||||
return buf[i];
|
||||
}
|
||||
|
||||
int
|
||||
parse_address(const char *address, unsigned char *addr_r, int *af_r)
|
||||
{
|
||||
struct in_addr ina;
|
||||
struct in6_addr ina6;
|
||||
int rc;
|
||||
|
||||
rc = inet_pton(AF_INET, address, &ina);
|
||||
if(rc > 0) {
|
||||
v4tov6(addr_r, (const unsigned char *)&ina);
|
||||
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)
|
||||
{
|
||||
v4tov6(dest, (const unsigned char *)src);
|
||||
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;
|
||||
}
|
164
babeld/util.h
Normal file
164
babeld/util.h
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
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_UTIL_H
|
||||
#define BABEL_UTIL_H
|
||||
|
||||
#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__*/
|
||||
#else
|
||||
#define DO_NTOHS(_d, _s) \
|
||||
do { short _dd; \
|
||||
memcpy(&(_dd), (_s), 2); \
|
||||
_d = ntohs(_dd); } while(0)
|
||||
#define DO_NTOHL(_d, _s) \
|
||||
do { int _dd; \
|
||||
memcpy(&(_dd), (_s), 4); \
|
||||
_d = ntohl(_dd); } while(0)
|
||||
#define DO_HTONS(_d, _s) \
|
||||
do { unsigned short _dd; \
|
||||
_dd = htons(_s); \
|
||||
memcpy((_d), &(_dd), 2); } while(0)
|
||||
#define DO_HTONL(_d, _s) \
|
||||
do { unsigned _dd; \
|
||||
_dd = htonl(_s); \
|
||||
memcpy((_d), &(_dd), 4); } 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);
|
||||
}
|
||||
|
||||
/* Returns a time in microseconds on 32 bits (thus modulo 2^32,
|
||||
i.e. about 4295 seconds). */
|
||||
static inline unsigned int
|
||||
time_us(const struct timeval t)
|
||||
{
|
||||
return (unsigned int) (t.tv_sec * 1000000 + t.tv_usec);
|
||||
}
|
||||
|
||||
int roughly(int 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, 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_nat(const char *string) ATTRIBUTE ((pure));
|
||||
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_thousands(unsigned int value);
|
||||
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);
|
||||
const unsigned char v4prefix[16];
|
||||
|
||||
/* 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 */
|
||||
|
||||
#endif /* BABEL_UTIL_H */
|
240
babeld/xroute.c
Normal file
240
babeld/xroute.c
Normal file
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
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 coming 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 coming 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;
|
||||
}
|
||||
|
||||
struct xroute_stream {
|
||||
int index;
|
||||
};
|
||||
|
||||
struct
|
||||
xroute_stream *
|
||||
xroute_stream()
|
||||
{
|
||||
struct xroute_stream *stream = malloc(sizeof(struct xroute_stream));
|
||||
if(stream == NULL)
|
||||
return NULL;
|
||||
|
||||
stream->index = 0;
|
||||
return stream;
|
||||
}
|
||||
|
||||
struct xroute *
|
||||
xroute_stream_next(struct xroute_stream *stream)
|
||||
{
|
||||
if(stream->index < numxroutes)
|
||||
return &xroutes[stream->index++];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
xroute_stream_done(struct xroute_stream *stream)
|
||||
{
|
||||
free(stream);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
uninstall_route(route);
|
||||
if(send_updates)
|
||||
send_update(NULL, 0, prefix, plen);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
52
babeld/xroute.h
Normal file
52
babeld/xroute.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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_XROUTE_H
|
||||
#define BABEL_XROUTE_H
|
||||
|
||||
struct xroute {
|
||||
unsigned char prefix[16];
|
||||
unsigned char plen;
|
||||
unsigned short metric;
|
||||
unsigned int ifindex;
|
||||
int proto;
|
||||
};
|
||||
|
||||
struct xroute_stream;
|
||||
|
||||
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);
|
||||
struct xroute_stream *xroute_stream();
|
||||
struct xroute *xroute_stream_next(struct xroute_stream *stream);
|
||||
void xroute_stream_done(struct xroute_stream *stream);
|
||||
|
||||
#endif /* BABEL_XROUTE_H */
|
10
configure.ac
10
configure.ac
|
@ -253,6 +253,8 @@ AC_ARG_ENABLE(nhrpd,
|
|||
AS_HELP_STRING([--disable-nhrpd], [do not build nhrpd]))
|
||||
AC_ARG_ENABLE(eigrpd,
|
||||
AS_HELP_STRING([--disable-eigrpd], [do not build eigrpd]))
|
||||
AC_ARG_ENABLE(babeld,
|
||||
AS_HELP_STRING([--disable-babeld], [do not build babeld]))
|
||||
AC_ARG_ENABLE(watchfrr,
|
||||
AS_HELP_STRING([--disable-watchfrr], [do not build watchfrr]))
|
||||
AC_ARG_ENABLE(isisd,
|
||||
|
@ -1345,6 +1347,12 @@ case "${enable_ripngd}" in
|
|||
esac
|
||||
AM_CONDITIONAL(RIPNGD, test "x$RIPNGD" = "xripngd")
|
||||
|
||||
case "${enable_babeld}" in
|
||||
"no" ) BABELD="";;
|
||||
* ) BABELD="babeld";;
|
||||
esac
|
||||
AM_CONDITIONAL(BABELD, test "x$BABELD" = "xbabeld")
|
||||
|
||||
case "${enable_ospf6d}" in
|
||||
"no" ) OSPF6D="";;
|
||||
* ) OSPF6D="ospf6d";;
|
||||
|
@ -1395,6 +1403,7 @@ AC_SUBST(ZEBRA)
|
|||
AC_SUBST(RFPTEST)
|
||||
AC_SUBST(LIBRFP)
|
||||
AC_SUBST(RFPINC)
|
||||
AC_SUBST(BABELD)
|
||||
AC_SUBST(BGPD)
|
||||
AC_SUBST(RIPD)
|
||||
AC_SUBST(RIPNGD)
|
||||
|
@ -1850,6 +1859,7 @@ AC_CONFIG_FILES([Makefile lib/Makefile qpb/Makefile zebra/Makefile ripd/Makefile
|
|||
ripngd/Makefile bgpd/Makefile ospfd/Makefile watchfrr/Makefile
|
||||
ospf6d/Makefile ldpd/Makefile isisd/Makefile vtysh/Makefile
|
||||
doc/Makefile ospfclient/Makefile tests/Makefile m4/Makefile
|
||||
babeld/Makefile
|
||||
pimd/Makefile
|
||||
eigrpd/Makefile
|
||||
nhrpd/Makefile
|
||||
|
|
|
@ -59,6 +59,7 @@ frr.pdf: $(info_TEXINFOS) $(figures_pdf) $(frr_TEXINFOS)
|
|||
|
||||
frr_TEXINFOS = appendix.texi basic.texi bgpd.texi isisd.texi filter.texi \
|
||||
vnc.texi \
|
||||
babeld.texi \
|
||||
install.texi ipv6.texi kernel.texi main.texi \
|
||||
nhrpd.texi \
|
||||
eigrpd.texi \
|
||||
|
|
|
@ -91,6 +91,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. */
|
||||
EIGRP_NODE, /* EIGRP protocol mode node. */
|
||||
BGP_NODE, /* BGP protocol mode which includes BGP4+ */
|
||||
BGP_VPNV4_NODE, /* BGP MPLS-VPN PE exchange. */
|
||||
|
|
|
@ -73,8 +73,10 @@ ZEBRA_ROUTE_VNC_DIRECT_RH, vnc-rn, NULL, 'V', 0, 0, "VNC-RN"
|
|||
ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
|
||||
# bgp unicast -> vnc
|
||||
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
|
||||
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
|
||||
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
|
||||
|
||||
|
||||
## help strings
|
||||
ZEBRA_ROUTE_SYSTEM, "Reserved route type, for internal use only"
|
||||
ZEBRA_ROUTE_KERNEL, "Kernel routes (not installed via the zebra RIB)"
|
||||
|
@ -95,3 +97,4 @@ ZEBRA_ROUTE_OLSR, "Optimised Link State Routing (OLSR)"
|
|||
ZEBRA_ROUTE_TABLE, "Non-main Kernel Routing Table"
|
||||
ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
|
||||
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
|
||||
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
|
||||
|
|
|
@ -118,6 +118,12 @@ vtysh_scan += $(top_srcdir)/eigrpd/eigrp_dump.c
|
|||
vtysh_scan += $(top_srcdir)/eigrpd/eigrp_vty.c
|
||||
endif
|
||||
|
||||
if BABELD
|
||||
vtysh_scan += $(top_srcdir)/babeld/babel_interface.c
|
||||
vtysh_scan += $(top_srcdir)/babeld/babel_zebra.c
|
||||
vtysh_scan += $(top_srcdir)/babeld/babeld.c
|
||||
endif
|
||||
|
||||
if SNMP
|
||||
vtysh_scan += $(top_srcdir)/lib/agentx.c
|
||||
endif
|
||||
|
|
|
@ -37,15 +37,16 @@ DECLARE_MGROUP(MVTYSH)
|
|||
#define VTYSH_WATCHFRR 0x400
|
||||
#define VTYSH_NHRPD 0x800
|
||||
#define VTYSH_EIGRPD 0x1000
|
||||
#define VTYSH_BABELD 0x2000
|
||||
|
||||
/* commands in REALLYALL are crucial to correct vtysh operation */
|
||||
#define VTYSH_REALLYALL ~0U
|
||||
/* watchfrr is not in ALL since library CLI functions should not be
|
||||
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||
* things like prefix lists are not even initialised) */
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD
|
||||
#define VTYSH_NS VTYSH_ZEBRA
|
||||
#define VTYSH_VRF VTYSH_ZEBRA
|
||||
|
||||
|
|
Loading…
Reference in a new issue