0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Merge branch 'int-new' of gitlab.labs.nic.cz:labs/bird into int-new

This commit is contained in:
Jan Moskyto Matejka 2016-05-13 13:48:04 +02:00
commit 5af7b59660
51 changed files with 4210 additions and 122 deletions

17
NEWS
View File

@ -1,3 +1,20 @@
Version 1.6.0 (2016-04-29)
o Major RIP protocol redesign
o New Babel routing protocol
o BGP multipath support
o KRT: Add support for plenty of kernel route metrics
o KRT: Allow more than 256 routing tables
o Static: Allow to specify attributes for static routes
o Static: Support for BFD controlled static routes
o FreeBSD: Setup password for BGP MD5 authentication
o IO: Remove socket number limit
o Plenty of bug fixes
Upgrade notes:
For RIP, most protocol options were moved to interface blocks.
Version 1.5.0 (2015-04-20)
o Major OSPF protocol redesign.
o OSPFv2 multi-instance extension (RFC 6549).

View File

@ -153,7 +153,7 @@ input_init(void)
// readline library does strange things when stdin is nonblocking.
// if (fcntl(0, F_SETFL, O_NONBLOCK) < 0)
// die("fcntl: %m");
// DIE("fcntl");
}
static void

View File

@ -11,6 +11,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <signal.h>
@ -109,7 +110,7 @@ more_begin(void)
tty.c_lflag &= (~ICANON);
if (tcsetattr (0, TCSANOW, &tty) < 0)
die("tcsetattr: %m");
DIE("tcsetattr");
more_active = 1;
}
@ -120,7 +121,7 @@ more_end(void)
more_active = 0;
if (tcsetattr (0, TCSANOW, &stored_tty) < 0)
die("tcsetattr: %m");
DIE("tcsetattr");
}
static void
@ -137,7 +138,7 @@ input_init(void)
return;
if (tcgetattr(0, &stored_tty) < 0)
die("tcgetattr: %m");
DIE("tcgetattr");
if (signal(SIGINT, sig_handler) == SIG_IGN)
signal(SIGINT, SIG_IGN);

View File

@ -37,7 +37,7 @@
#define SERVER_READ_BUF_LEN 4096
static char *opt_list = "s:vr";
static char *opt_list = "s:vrl";
static int verbose, restricted, once;
static char *init_cmd;
@ -59,13 +59,14 @@ int term_lns, term_cls;
static void
usage(char *name)
{
fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r]\n", name);
fprintf(stderr, "Usage: %s [-s <control-socket>] [-v] [-r] [-l]\n", name);
exit(1);
}
static void
parse_args(int argc, char **argv)
{
int server_changed = 0;
int c;
while ((c = getopt(argc, argv, opt_list)) >= 0)
@ -73,6 +74,7 @@ parse_args(int argc, char **argv)
{
case 's':
server_path = optarg;
server_changed = 1;
break;
case 'v':
verbose++;
@ -80,6 +82,10 @@ parse_args(int argc, char **argv)
case 'r':
restricted = 1;
break;
case 'l':
if (!server_changed)
server_path = xbasename(server_path);
break;
default:
usage(argv[0]);
}
@ -242,7 +248,7 @@ server_connect(void)
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (server_fd < 0)
die("Cannot create socket: %m");
DIE("Cannot create socket");
if (strlen(server_path) >= sizeof(sa.sun_path))
die("server_connect: path too long");
@ -251,9 +257,9 @@ server_connect(void)
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path, server_path);
if (connect(server_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) < 0)
die("Unable to connect to server control socket (%s): %m", server_path);
DIE("Unable to connect to server control socket (%s)", server_path);
if (fcntl(server_fd, F_SETFL, O_NONBLOCK) < 0)
die("fcntl: %m");
DIE("fcntl");
}
@ -303,13 +309,13 @@ server_read(void)
redo:
c = read(server_fd, server_read_pos, server_read_buf + sizeof(server_read_buf) - server_read_pos);
if (!c)
die("Connection closed by server.");
die("Connection closed by server");
if (c < 0)
{
if (errno == EINTR)
goto redo;
else
die("Server read error: %m");
DIE("Server read error");
}
start = server_read_buf;
@ -360,7 +366,7 @@ select_loop(void)
if (errno == EINTR)
continue;
else
die("select: %m");
DIE("select");
}
if (FD_ISSET(0, &select_fds))
@ -393,7 +399,7 @@ wait_for_write(int fd)
if (errno == EINTR)
continue;
else
die("select: %m");
DIE("select");
}
if (FD_ISSET(server_fd, &set))
@ -420,7 +426,7 @@ server_send(char *cmd)
else if (errno == EINTR)
continue;
else
die("Server write error: %m");
DIE("Server write error");
}
else
{
@ -430,19 +436,6 @@ server_send(char *cmd)
}
}
/* XXXX
get_term_size();
if (tcgetattr(0, &tty_save) != 0)
{
perror("tcgetattr error");
return(EXIT_FAILURE);
}
}
*/
int
main(int argc, char **argv)
{

View File

@ -34,3 +34,6 @@ char *cmd_expand(char *cmd);
/* client.c */
void submit_command(char *cmd_raw);
/* die() with system error messages */
#define DIE(x, y...) die(x ": %s", ##y, strerror(errno))

View File

@ -60,7 +60,7 @@ cmd_build_tree(void)
if (!new)
{
int size = sizeof(struct cmd_node) + c-d;
new = xmalloc(size);
new = malloc(size);
bzero(new, size);
*old->plastson = new;
old->plastson = &new->sibling;
@ -314,7 +314,7 @@ cmd_expand(char *cmd)
puts("No such command. Press `?' for help.");
return NULL;
}
b = xmalloc(strlen(n->cmd->command) + strlen(args) + 1);
b = malloc(strlen(n->cmd->command) + strlen(args) + 1);
sprintf(b, "%s%s", n->cmd->command, args);
return b;
}

View File

@ -21,8 +21,11 @@ vlog(const char *msg, va_list args)
{
char buf[1024];
if (bvsnprintf(buf, sizeof(buf)-1, msg, args) < 0)
bsprintf(buf + sizeof(buf) - 100, " ... <too long>");
int n = vsnprintf(buf, sizeof(buf), msg, args);
if (n < 0)
snprintf(buf, sizeof(buf), "???");
if (n >= sizeof(buf))
snprintf(buf + sizeof(buf) - 100, 100, " ... <too long>");
fputs(buf, stderr);
fputc('\n', stderr);
}

View File

@ -563,6 +563,7 @@ cf_lex_init_kh(void)
/**
* cf_lex_init - initialize the lexer
* @is_cli: true if we're going to parse CLI command, false for configuration
* @c: configuration structure
*
* cf_lex_init() initializes the lexical analyzer and prepares it for
* parsing of a new input.

View File

@ -167,7 +167,7 @@ fi
AC_SUBST(iproutedir)
# all_protocols="$proto_bfd bgp ospf pipe radv rip static"
# all_protocols="$proto_bfd babel bgp ospf pipe radv rip static"
all_protocols="$proto_bfd ospf pipe radv rip static"
all_protocols=`echo $all_protocols | sed 's/ /,/g'`

View File

@ -171,6 +171,11 @@ BIRD executable by configuring out routing protocols you don't use, and
<tag>-f</tag>
run bird in foreground.
<tag>-l</tag>
look for a configuration file and a communication socket in the current
working directory instead of in default system locations. However, paths
specified by options <cf/-c/, <cf/-s/ have higher priority.
<tag>-R</tag>
apply graceful restart recovery after start.
</descrip>
@ -190,7 +195,7 @@ privileges (capabilities CAP_NET_*). Note that the control socket is created
before the privileges are dropped, but the config file is read after that. The
privilege restriction is not implemented in BSD port of BIRD.
<p>A nonprivileged user (as an argument to <cf/-u/ options) may be the user
<p>An unprivileged user (as an argument to <cf/-u/ options) may be the user
<cf/nobody/, but it is suggested to use a new dedicated user account (like
<cf/bird/). The similar considerations apply for the group option, but there is
one more condition -- the users in the same group can use <file/birdc/ to
@ -283,7 +288,7 @@ extensive way.
a comment, whitespace characters are treated as a single space. If there's a
variable number of options, they are grouped using the <cf/{ }/ brackets. Each
option is terminated by a <cf/;/. Configuration is case sensitive. There are two
ways how to name symbols (like protocol names, filter names, constats etc.). You
ways how to name symbols (like protocol names, filter names, constants etc.). You
can either use a simple string starting with a letter followed by any
combination of letters and numbers (e.g. "R123", "myfilter", "bgp5") or you can
enclose the name into apostrophes (<cf/'/) and than you can use any combination
@ -712,6 +717,10 @@ This argument can be omitted if there exists only a single instance.
Show router status, that is BIRD version, uptime and time from last
reconfiguration.
<tag>show interfaces [summary]</tag>
Show the list of interfaces. For each interface, print its type, state,
MTU and addresses assigned.
<tag>show protocols [all]</tag>
Show list of protocol instances along with tables they are connected to
and protocol status, possibly giving verbose information, if <cf/all/ is
@ -739,16 +748,18 @@ This argument can be omitted if there exists only a single instance.
Show contents of an OSPF LSA database. Options could be used to filter
entries.
<tag>show rip interfaces [<m/name/] ["<m/interface/"]</tag>
Show detailed information about RIP interfaces.
<tag>show rip neighbors [<m/name/] ["<m/interface/"]</tag>
Show a list of RIP neighbors and associated state.
<tag>show static [<m/name/]</tag>
Show detailed information about static routes.
<tag>show bfd sessions [<m/name/]</tag>
Show information about BFD sessions.
<tag>show interfaces [summary]</tag>
Show the list of interfaces. For each interface, print its type, state,
MTU and addresses assigned.
<tag>show symbols [table|filter|function|protocol|template|roa|<m/symbol/]</tag>
Show the list of symbols defined in the configuration (names of
protocols, routing tables etc.).
@ -824,7 +835,7 @@ This argument can be omitted if there exists only a single instance.
configuration could be either confirmed using <cf/configure confirm/
command, or it will be reverted to the old one when the config timer
expires. This is useful for cases when reconfiguration breaks current
routing and a router becames inaccessible for an administrator. The
routing and a router becomes inaccessible for an administrator. The
config timeout expiration is equivalent to <cf/configure undo/
command. The timeout duration could be specified, default is 300 s.
@ -1005,7 +1016,7 @@ foot).
of type <cf/string/, print such variables, use standard string
comparison operations (e.g. <cf/=, !=, &lt;, &gt;, &lt;=, &gt;=/), but
you can't concatenate two strings. String literals are written as
<cf/"This is a string constant"/. Additionaly matching <cf/&tilde;/
<cf/"This is a string constant"/. Additionally matching <cf/&tilde;/
operator could be used to match a string value against a shell pattern
(represented also as a string).
@ -1369,6 +1380,102 @@ corresponding protocol sections.
<chapt>Protocols
<sect>Babel
<sect1>Introduction
<p>The Babel protocol (RFC6126) is a loop-avoiding distance-vector routing
protocol that is robust and efficient both in ordinary wired networks and in
wireless mesh networks. Babel is conceptually very simple in its operation and
"just works" in its default configuration, though some configuration is possible
and in some cases desirable.
<p>While the Babel protocol is dual stack (i.e., can carry both IPv4 and IPv6
routes over the same IPv6 transport), BIRD presently implements only the IPv6
subset of the protocol. No Babel extensions are implemented, but the BIRD
implementation can coexist with implementations using the extensions (and will
just ignore extension messages).
<p>The Babel protocol implementation in BIRD is currently in alpha stage.
<sect1>Configuration
<p>Babel supports no global configuration options apart from those common to all
other protocols, but supports the following per-interface configuration options:
<code>
protocol babel [<name>] {
interface <interface pattern> {
type <wired|wireless>;
rxcost <number>;
hello interval <number>;
update interval <number>;
port <number>;
tx class|dscp <number>;
tx priority <number>;
rx buffer <number>;
tx length <number>;
check link <switch>;
};
}
</code>
<descrip>
<tag>type wired|wireless </tag>
This option specifies the interface type: Wired or wireless. Wired
interfaces are considered more reliable, and so the default hello
interval is higher, and a neighbour is considered unreachable after only
a small number of "hello" packets are lost. On wireless interfaces,
hello packets are sent more often, and the ETX link quality estimation
technique is used to compute the metrics of routes discovered over this
interface. This technique will gradually degrade the metric of routes
when packets are lost rather than the more binary up/down mechanism of
wired type links. Default: <cf/wired/.
<tag>rxcost <m/num/</tag>
This specifies the RX cost of the interface. The route metrics will be
computed from this value with a mechanism determined by the interface
<cf/type/. Default: 96 for wired interfaces, 256 for wireless.
<tag>hello interval <m/num/</tag>
Interval at which periodic "hello" messages are sent on this interface,
in seconds. Default: 4 seconds.
<tag>update interval <m/num/</tag>
Interval at which periodic (full) updates are sent. Default: 4 times the
hello interval.
<tag>port <m/number/</tag>
This option selects an UDP port to operate on. The default is to operate
on port 6696 as specified in the Babel RFC.
<tag>tx class|dscp|priority <m/number/</tag>
These options specify the ToS/DiffServ/Traffic class/Priority of the
outgoing Babel packets. See <ref id="dsc-prio" name="tx class"> common
option for detailed description.
<tag>rx buffer <m/number/</tag>
This option specifies the size of buffers used for packet processing.
The buffer size should be bigger than maximal size of received packets.
The default value is the interface MTU, and the value will be clamped to a
minimum of 512 bytes + IP packet overhead.
<tag>tx length <m/number/</tag>
This option specifies the maximum length of generated Babel packets. To
avoid IP fragmentation, it should not exceed the interface MTU value.
The default value is the interface MTU value, and the value will be
clamped to a minimum of 512 bytes + IP packet overhead.
<tag>check link <m/switch/</tag>
If set, the hardware link state (as reported by OS) is taken into
consideration. When the link disappears (e.g. an ethernet cable is
unplugged), neighbors are immediately considered unreachable and all
routes received from them are withdrawn. It is possible that some
hardware drivers or platforms do not implement this feature. Default:
yes.
</descrip>
<sect><label id="sect-bfd">BFD
<sect1>Introduction
@ -1472,7 +1579,7 @@ protocol bfd [&lt;name&gt;] {
The session is identified by the IP address of the neighbor, with
optional specification of used interface and local IP. By default
the neighbor must be directly connected, unless the the session is
the neighbor must be directly connected, unless the session is
configured as multihop. Note that local IP must be specified for
multihop sessions.
</descrip>
@ -1515,7 +1622,7 @@ protocol bfd [&lt;name&gt;] {
Default: 5.
<tag>passive <m/switch/</tag>
Generally, both BFD session endpoinds try to establish the session by
Generally, both BFD session endpoints try to establish the session by
sending control packets to the other side. This option allows to enable
passive mode, which means that the router does not send BFD packets
until it has received one from the other side. Default: disabled.
@ -1753,9 +1860,20 @@ using the following configuration parameters:
only. Default: disabled.
<tag>password <m/string/</tag>
Use this password for MD5 authentication of BGP sessions. Default: no
authentication. Password has to be set by external utility
(e.g. setkey(8)) on BSD systems.
Use this password for MD5 authentication of BGP sessions (RFC 2385).
When used on BSD systems, see also <cf/setkey/ option below. Default:
no authentication.
<tag>setkey <m/switch/</tag>
On BSD systems, keys for TCP MD5 authentication are stored in the global
SA/SP database, which can be accessed by external utilities (e.g.
setkey(8)). BIRD configures security associations in the SA/SP database
automatically based on <cf/password/ options (see above), this option
allows to disable automatic updates by BIRD when manual configuration by
external utilities is preferred. Note that automatic SA/SP database
updates are currently implemented only for FreeBSD. Passwords have to be
set manually by an external utility on NetBSD and OpenBSD. Default:
enabled (ignored on non-FreeBSD).
<tag>passive <m/switch/</tag>
Standard BGP behavior is both initiating outgoing connections and
@ -2150,7 +2268,7 @@ conditions, because a lower priority IGP route for the same network is not
exported to the kernel routing table. This is an issue on BSD systems only, as
on Linux systems BIRD cannot change non-BIRD route in the kernel routing table.
<p>The only configurable thing about direct is what interfaces it watches:
<p>There are just few configuration options for the Direct protocol:
<p><descrip>
<tag>interface <m/pattern [, ...]/</tag>
@ -2161,6 +2279,12 @@ on Linux systems BIRD cannot change non-BIRD route in the kernel routing table.
interfaces), just use this clause. See <ref id="dsc-iface" name="interface">
common option for detailed description. The Direct protocol uses
extended interface clauses.
<tag>check link <m/switch/</tag>
If enabled, a hardware link state (reported by OS) is taken into
consideration. Routes for directly connected networks are generated only
if link up is reported and they are withdrawn when link disappears
(e.g., an ethernet cable is unplugged). Default value is no.
</descrip>
<p>Direct device routes don't contain any specific attributes.
@ -2634,7 +2758,7 @@ protocol ospf &lt;name&gt; {
<tag>dead <M>num</M></tag>
When the router does not receive any messages from a neighbor in
<m/dead/ seconds, it will consider the neighbor down. If both directives
<cf/dead count/ and <cf/dead/ are used, <cf/dead/ has precendence.
<cf/dead count/ and <cf/dead/ are used, <cf/dead/ has precedence.
<tag>secondary <M>switch</M></tag>
On BSD systems, older versions of BIRD supported OSPFv2 only for the
@ -3365,6 +3489,11 @@ protocol rip [&lt;name&gt;] {
RIP, the option is not supported for RIPng, as no further versions are
defined.
<tag>version only <m/switch/</tag>
Regardless of RIP version configured for the interface, BIRD accepts
incoming packets of any RIP version. This option restrict accepted
packets to the configured version. Default: no.
<tag>split horizon <m/switch/</tag>
Split horizon is a scheme for preventing routing loops. When split
horizon is active, routes are not regularly propagated back to the
@ -3509,7 +3638,7 @@ default route to prevent routing loops).
packets to a neighboring router, multipath routes specifying several (possibly
weighted) neighboring routers, device routes specifying forwarding to hosts on a
directly connected network, recursive routes computing their nexthops by doing
route table lookups for a given IP and special routes (sink, blackhole etc.)
route table lookups for a given IP, and special routes (sink, blackhole etc.)
which specify a special action to be done instead of forwarding the packet.
<p>When the particular destination is not available (the interface is down or
@ -3517,8 +3646,26 @@ the next hop of the route is not a neighbor at the moment), Static just
uninstalls the route from the table it is connected to and adds it again as soon
as the destination becomes adjacent again.
<p>The Static protocol does not have many configuration options. The definition
of the protocol contains mainly a list of static routes:
<p>There are three classes of definitions in Static protocol configuration --
global options, static route definitions, and per-route options. Usually, the
definition of the protocol contains mainly a list of static routes.
<p>Global options:
<descrip>
<tag>check link <m/switch/</tag>
If set, hardware link states of network interfaces are taken into
consideration. When link disappears (e.g. ethernet cable is unplugged),
static routes directing to that interface are removed. It is possible
that some hardware drivers or platforms do not implement this feature.
Default: off.
<tag>igp table <m/name/</tag>
Specifies a table that is used for route table lookups of recursive
routes. Default: the same table as the protocol is connected to.
</descrip>
<p>Route definitions (each may also contain a block of per-route options):
<descrip>
<tag>route <m/prefix/ via <m/ip/</tag>
@ -3526,7 +3673,7 @@ of the protocol contains mainly a list of static routes:
interface can be specified as a part of the address (e.g.,
<cf/via fe80::1234%eth0/).
<tag>route <m/prefix/ multipath via <m/ip/ [weight <m/num/] [via ...]</tag>
<tag>route <m/prefix/ multipath via <m/ip/ [weight <m/num/] [bfd <m/switch/] [via ...]</tag>
Static multipath route. Contains several nexthops (gateways), possibly
with their weights.
@ -3542,17 +3689,33 @@ of the protocol contains mainly a list of static routes:
Special routes specifying to silently drop the packet, return it as
unreachable or return it as administratively prohibited. First two
targets are also known as <cf/drop/ and <cf/reject/.
</descrip>
<tag>check link <m/switch/</tag>
If set, hardware link states of network interfaces are taken into
consideration. When link disappears (e.g. ethernet cable is unplugged),
static routes directing to that interface are removed. It is possible
that some hardware drivers or platforms do not implement this feature.
Default: off.
<p>Per-route options:
<tag>igp table <m/name/</tag>
Specifies a table that is used for route table lookups of recursive
routes. Default: the same table as the protocol is connected to.
<descrip>
<tag>bfd <m/switch/</tag>
The Static protocol could use BFD protocol for next hop liveness
detection. If enabled, a BFD session to the route next hop is created
and the static route is BFD-controlled -- the static route is announced
only if the next hop liveness is confirmed by BFD. If the BFD session
fails, the static route is removed. Note that this is a bit different
compared to other protocols, which may use BFD as an advisory mechanism
for fast failure detection but ignores it if a BFD session is not even
established.
This option can be used for static routes with a direct next hop, or
also for for individual next hops in a static multipath route (see
above). Note that BFD protocol also has to be configured, see
<ref id="sect-bfd" name="BFD"> section for details. Default value is no.
<tag><m/filter expression/</tag>
This is a special option that allows filter expressions to be configured
on per-route basis. Can be used multiple times. These expressions are
evaluated when the route is originated, similarly to the import filter
of the static protocol. This is especially useful for configuring route
attributes, e.g., <cf/ospf_metric1 = 100;/ for a route that will be
exported to the OSPF protocol.
</descrip>
<p>Static routes have no specific attributes.
@ -3562,13 +3725,22 @@ of the protocol contains mainly a list of static routes:
<p><code>
protocol static {
table testable; # Connect to a non-default routing table
check link; # Advertise routes only if link is up
route 0.0.0.0/0 via 198.51.100.130; # Default route
route 10.0.0.0/8 multipath # Multipath route
via 198.51.100.10 weight 2
via 198.51.100.20
via 198.51.100.20 bfd # BFD-controlled next hop
via 192.0.2.1;
route 203.0.113.0/24 unreachable; # Sink route
route 10.2.0.0/24 via "arc0"; # Secondary network
route 192.168.10.0/24 via 198.51.100.100 {
ospf_metric1 = 20; # Set extended attribute
}
route 192.168.10.0/24 via 198.51.100.100 {
ospf_metric2 = 100; # Set extended attribute
ospf_tag = 2; # Set extended attribute
bfd; # BFD-controlled route
}
}
</code>

View File

@ -57,6 +57,9 @@ Reply codes of BIRD command-line interface
1020 Show BFD sessions
1021 Show RIP interface
1022 Show RIP neighbors
1023 Show Babel interfaces
1024 Show Babel neighbors
1025 Show Babel entries
8000 Reply too long
8001 Route not found

View File

@ -1,7 +1,3 @@
src := bitops.c checksum.c ip.c lists.c md5.c net.c patmatch.c printf.c sha1.c sha256.c sha512.c slists.c xmalloc.c
obj := $(src-o-files)
$(all-client)
src := bitops.c checksum.c event.c idm.c ip.c lists.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)

View File

@ -61,6 +61,7 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define NORET __attribute__((noreturn))
#define UNUSED __attribute__((unused))
#define PACKED __attribute__((packed))
/* Microsecond time */

View File

@ -25,5 +25,6 @@ u32 u32_log2(u32 v);
static inline u32 u32_hash(u32 v) { return v * 2902958171u; }
#endif
static inline u8 u32_popcount(u32 v) { return __builtin_popcount(v); }
#endif

View File

@ -26,6 +26,7 @@
#define IP6_OSPF_ALL_ROUTERS ipa_build6(0xFF020000, 0, 0, 5)
#define IP6_OSPF_DES_ROUTERS ipa_build6(0xFF020000, 0, 0, 6)
#define IP6_RIP_ROUTERS ipa_build6(0xFF020000, 0, 0, 9)
#define IP6_BABEL_ROUTERS ipa_build6(0xFF020000, 0, 0, 0x00010006)
#define IP4_NONE _MI4(0)
#define IP6_NONE _MI6(0,0,0,0)

View File

@ -124,9 +124,10 @@ static char * number(char * str, long num, int base, int size, int precision,
* standard IP address width which depends on whether we use IPv4 or IPv6; |%I4|
* or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
* generic network addresses (net_addr *), |%R| for Router / Network ID (u32
* value printed as IPv4 address) and |%m| resp. |%M| for error messages (uses
* strerror() to translate @errno code to message text). On the other hand, it
* doesn't support floating point numbers.
* value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
* value printed as eight :-separated octets) and |%m| resp. |%M| for error
* messages (uses strerror() to translate @errno code to message text). On the
* other hand, it doesn't support floating point numbers.
*
* Result: number of characters of the output string or -1 if
* the buffer space was insufficient.
@ -137,6 +138,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
unsigned long num;
int i, base;
u32 x;
u64 X;
char *str, *start;
const char *s;
char ipbuf[NET_MAX_TEXT_LENGTH+1];
@ -338,8 +340,23 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
/* Router/Network ID - essentially IPv4 address in u32 value */
case 'R':
if (qualifier == 'l') {
X = va_arg(args, u64);
bsprintf(ipbuf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
((X >> 56) & 0xff),
((X >> 48) & 0xff),
((X >> 40) & 0xff),
((X >> 32) & 0xff),
((X >> 24) & 0xff),
((X >> 16) & 0xff),
((X >> 8) & 0xff),
(X & 0xff));
}
else
{
x = va_arg(args, u32);
ip4_ntop(ip4_from_u32(x), ipbuf);
}
s = ipbuf;
goto str;

View File

@ -79,7 +79,7 @@ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface
int sk_setup_broadcast(sock *s);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
int sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd);
int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey);
int sk_set_ipv6_checksum(sock *s, int offset);
int sk_set_icmp6_filter(sock *s, int p1, int p2);
void sk_log_error(sock *s, const char *p);

View File

@ -24,4 +24,12 @@ void buffer_puts(buffer *buf, const char *str);
int patmatch(const byte *pat, const byte *str);
static inline char *xbasename(const char *str)
{
char *s = strrchr(str, '/');
return s ? s+1 : (char *) str;
}
#define ROUTER_ID_64_LENGTH 23
#endif

View File

@ -1,6 +1,6 @@
Summary: BIRD Internet Routing Daemon
Name: bird
Version: 1.5.0
Version: 1.6.0
Release: 1
Copyright: GPL
Group: Networking/Daemons

View File

@ -357,6 +357,7 @@ dev_proto:
| dev_proto proto_item ';'
| dev_proto proto_channel ';'
| dev_proto dev_iface_patt ';'
| dev_proto CHECK LINK bool ';' { DIRECT_CFG->check_link = $4; }
;
dev_iface_init:

View File

@ -340,7 +340,7 @@ neigh_if_link(struct iface *i)
/**
* neigh_ifa_update: notify neighbor cache about interface address add or remove event
* @ifa: interface address in question
* @a: interface address in question
*
* Tell the neighbor cache that an address was added or removed.
*

View File

@ -148,6 +148,7 @@ void get_route_info(rte *e, byte *buf, ea_list *attrs)
* get_attr - get attribute information
* @a: an extended attribute
* @buf: buffer to be filled with attribute information
* @buflen: a length of the @buf parameter
*
* The get_attr() hook is called by the core to obtain a user friendly
* representation of an extended route attribute. It can either leave

View File

@ -1068,6 +1068,7 @@ graceful_restart_init(void)
/**
* graceful_restart_done - finalize graceful restart
* @t: unused
*
* When there are no locks on graceful restart, the functions finalizes the
* graceful restart recovery. Protocols postponing route export until the end of
@ -1258,6 +1259,9 @@ protos_build(void)
proto_build(&proto_bfd);
bfd_init_all();
#endif
#ifdef CONFIG_BABEL
proto_build(&proto_babel);
#endif
proto_pool = rp_new(&root_pool, "Protocols");
proto_shutdown_timer = tm_new(proto_pool);

View File

@ -81,7 +81,7 @@ void protos_dump_all(void);
extern struct protocol
proto_device, proto_radv, proto_rip, proto_static,
proto_ospf, proto_pipe, proto_bgp, proto_bfd;
proto_ospf, proto_pipe, proto_bgp, proto_bfd, proto_babel;
/*
* Routing Protocol Instance

View File

@ -228,6 +228,12 @@ typedef struct rte {
struct {
u8 suppressed; /* Used for deterministic MED comparison */
} bgp;
#endif
#ifdef CONFIG_BABEL
struct {
u16 metric; /* Babel metric */
u64 router_id; /* Babel router id */
} babel;
#endif
struct { /* Routes generated by krt sync (both temporary and inherited ones) */
s8 src; /* Alleged route source (see krt.h) */
@ -377,6 +383,7 @@ typedef struct rta {
#define RTS_OSPF_EXT2 10 /* OSPF external route type 2 */
#define RTS_BGP 11 /* BGP route */
#define RTS_PIPE 12 /* Inter-table wormhole */
#define RTS_BABEL 13 /* Babel route */
#define RTC_UNICAST 0
#define RTC_BROADCAST 1
@ -425,7 +432,8 @@ typedef struct eattr {
#define EAP_RIP 2 /* RIP */
#define EAP_OSPF 3 /* OSPF */
#define EAP_KRT 4 /* Kernel route attributes */
#define EAP_MAX 5
#define EAP_BABEL 5 /* Babel attributes */
#define EAP_MAX 6
#define EA_CODE(proto,id) (((proto) << 8) | (id))
#define EA_PROTO(ea) ((ea) >> 8)
@ -550,6 +558,7 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX];
#define DEF_PREF_DIRECT 240 /* Directly connected */
#define DEF_PREF_STATIC 200 /* Static route */
#define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */
#define DEF_PREF_BABEL 130 /* Babel */
#define DEF_PREF_RIP 120 /* RIP */
#define DEF_PREF_BGP 100 /* BGP */
#define DEF_PREF_INHERITED 10 /* Routes inherited from other routing daemons */

View File

@ -353,7 +353,7 @@ ea_find(ea_list *e, unsigned id)
* for first occurrences of attributes with ID in specified interval from @id to
* (@id + @max - 1), returning pointers to found &eattr structures, storing its
* walk state in @s for subsequent calls.
*
* The function ea_walk() is supposed to be called in a loop, with initially
* zeroed walk state structure @s with filled the initial extended attribute
* list, returning one found attribute in each call or %NULL when no other

View File

@ -68,6 +68,9 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
DBG("dev_if_notify: %s:%I going up\n", ad->iface->name, ad->ip);
if (cf->check_link && !(ad->iface->flags & IF_LINK_UP))
return;
/* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(P, ad->iface->index);
@ -87,6 +90,25 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
}
}
static void
dev_if_notify(struct proto *p, uint c, struct iface *iface)
{
struct rt_dev_config *cf = (void *) p->cf;
if (c & (IF_CHANGE_UP | IF_CHANGE_DOWN))
return;
if ((c & IF_CHANGE_LINK) && cf->check_link)
{
uint ac = (iface->flags & IF_LINK_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN;
struct ifa *a;
WALK_LIST(a, iface->addrs)
dev_ifa_notify(p, ac, a);
}
}
static struct proto *
dev_init(struct proto_config *CF)
{
@ -97,6 +119,7 @@ dev_init(struct proto_config *CF)
proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
P->if_notify = dev_if_notify;
P->ifa_notify = dev_ifa_notify;
return P;
@ -109,7 +132,8 @@ dev_reconfigure(struct proto *P, struct proto_config *CF)
struct rt_dev_config *o = (void *) P->cf;
struct rt_dev_config *n = (void *) CF;
if (!iface_patts_equal(&o->iface_list, &n->iface_list, NULL))
if (!iface_patts_equal(&o->iface_list, &n->iface_list, NULL) ||
(o->check_link != n->check_link))
return 0;
return
@ -131,6 +155,8 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
* old nodes cannot be modified (although they contain internal lists).
*/
cfg_copy_list(&d->iface_list, &s->iface_list, sizeof(struct iface_patt));
d->check_link = s->check_link;
}
struct protocol proto_device = {

View File

@ -12,6 +12,7 @@
struct rt_dev_config {
struct proto_config c;
list iface_list; /* list of struct iface_patt */
int check_link;
};
struct rt_dev_proto {

View File

@ -834,16 +834,20 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
* @net: network in question
* @new: the new route to be announced
* @old: the previous route for the same network
* @new_best: the new best route for the same network
* @old_best: the previous best route for the same network
* @before_old: The previous route before @old for the same network.
* If @before_old is NULL @old was the first.
*
* This function gets a routing table update and announces it
* to all protocols that acccepts given type of route announcement
* and are connected to the same table by their announcement hooks.
*
* Route announcement of type RA_OPTIMAL si generated when optimal
* Route announcement of type %RA_OPTIMAL si generated when optimal
* route (in routing table @tab) changes. In that case @old stores the
* old optimal route.
*
* Route announcement of type RA_ANY si generated when any route (in
* Route announcement of type %RA_ANY si generated when any route (in
* routing table @tab) changes In that case @old stores the old route
* from the same protocol.
*

View File

@ -1,4 +1,5 @@
H Protocols
C babel
C bfd
C bgp
C ospf

2
proto/babel/Doc Normal file
View File

@ -0,0 +1,2 @@
S babel.c
S packets.c

5
proto/babel/Makefile Normal file
View File

@ -0,0 +1,5 @@
source=babel.c packets.c
root-rel=../../
dir-name=proto/babel
include ../../Rules

2055
proto/babel/babel.c Normal file

File diff suppressed because it is too large Load Diff

335
proto/babel/babel.h Normal file
View File

@ -0,0 +1,335 @@
/*
* BIRD -- The Babel protocol
*
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
* This file contains the data structures used by Babel.
*/
#ifndef _BIRD_BABEL_H_
#define _BIRD_BABEL_H_
#include "nest/bird.h"
#include "nest/cli.h"
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/locks.h"
#include "lib/resource.h"
#include "lib/lists.h"
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/timer.h"
#ifndef IPV6
#error "The Babel protocol only speaks IPv6"
#endif
#define EA_BABEL_METRIC EA_CODE(EAP_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1)
#define BABEL_MAGIC 42
#define BABEL_VERSION 2
#define BABEL_PORT 6696
#define BABEL_INFINITY 0xFFFF
#define BABEL_HELLO_INTERVAL_WIRED 4 /* Default hello intervals in seconds */
#define BABEL_HELLO_INTERVAL_WIRELESS 4
#define BABEL_UPDATE_INTERVAL_FACTOR 4
#define BABEL_IHU_INTERVAL_FACTOR 3
#define BABEL_IHU_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((X)*7/2) /* 3.5 */
#define BABEL_ROUTE_REFRESH_INTERVAL 2 /* Seconds before route expiry to send route request */
#define BABEL_HOLD_TIME 10 /* Expiry time for our own routes */
#define BABEL_RXCOST_WIRED 96
#define BABEL_RXCOST_WIRELESS 256
#define BABEL_INITIAL_HOP_COUNT 255
#define BABEL_MAX_SEND_INTERVAL 5
#define BABEL_TIME_UNITS 100 /* On-wire times are counted in centiseconds */
#define BABEL_SEQNO_REQUEST_EXPIRY 60
#define BABEL_GARBAGE_INTERVAL 300
#define BABEL_OVERHEAD (SIZE_OF_IP_HEADER+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
enum babel_tlv_type {
BABEL_TLV_PAD1 = 0,
BABEL_TLV_PADN = 1,
BABEL_TLV_ACK_REQ = 2,
BABEL_TLV_ACK = 3,
BABEL_TLV_HELLO = 4,
BABEL_TLV_IHU = 5,
BABEL_TLV_ROUTER_ID = 6,
BABEL_TLV_NEXT_HOP = 7,
BABEL_TLV_UPDATE = 8,
BABEL_TLV_ROUTE_REQUEST = 9,
BABEL_TLV_SEQNO_REQUEST = 10,
/* extensions - not implemented
BABEL_TLV_TS_PC = 11,
BABEL_TLV_HMAC = 12,
BABEL_TLV_SS_UPDATE = 13,
BABEL_TLV_SS_REQUEST = 14,
BABEL_TLV_SS_SEQNO_REQUEST = 15,
*/
BABEL_TLV_MAX
};
enum babel_iface_type {
/* In practice, UNDEF and WIRED give equivalent behaviour */
BABEL_IFACE_TYPE_UNDEF = 0,
BABEL_IFACE_TYPE_WIRED = 1,
BABEL_IFACE_TYPE_WIRELESS = 2,
BABEL_IFACE_TYPE_MAX
};
enum babel_ae_type {
BABEL_AE_WILDCARD = 0,
BABEL_AE_IP4 = 1,
BABEL_AE_IP6 = 2,
BABEL_AE_IP6_LL = 3,
BABEL_AE_MAX
};
struct babel_config {
struct proto_config c;
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */
};
struct babel_iface_config {
struct iface_patt i;
u16 rxcost;
u8 type;
u8 check_link;
int port;
u16 hello_interval;
u16 ihu_interval;
u16 update_interval;
u16 rx_buffer; /* RX buffer size, 0 for MTU */
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos;
int tx_priority;
};
struct babel_proto {
struct proto p;
timer *timer;
struct fib rtable;
list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id;
u16 update_seqno; /* To be increased on request */
u8 triggered; /* For triggering global updates */
slab *route_slab;
slab *source_slab;
slab *msg_slab;
slab *seqno_slab;
list seqno_cache; /* Seqno requests in the cache (struct babel_seqno_request) */
struct tbf log_pkt_tbf; /* TBF for packet messages */
};
struct babel_iface {
node n;
struct babel_proto *proto;
struct iface *iface;
struct babel_iface_config *cf;
u8 up;
pool *pool;
char *ifname;
sock *sk;
ip_addr addr;
int tx_length;
list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */
list msg_queue;
u16 hello_seqno; /* To be increased on each hello */
bird_clock_t next_hello;
bird_clock_t next_regular;
bird_clock_t next_triggered;
bird_clock_t want_triggered;
timer *timer;
event *send_event;
};
struct babel_neighbor {
node n;
struct babel_iface *ifa;
ip_addr addr;
u16 txcost;
u8 hello_cnt;
u16 hello_map;
u16 next_hello_seqno;
/* expiry timers */
bird_clock_t hello_expiry;
bird_clock_t ihu_expiry;
list routes; /* Routes this neighbour has sent us (struct babel_route) */
};
struct babel_source {
node n;
u64 router_id;
u16 seqno;
u16 metric;
bird_clock_t expires;
};
struct babel_route {
node n;
node neigh_route;
struct babel_entry *e;
struct babel_neighbor *neigh;
u16 seqno;
u16 advert_metric;
u16 metric;
u64 router_id;
ip_addr next_hop;
bird_clock_t refresh_time;
bird_clock_t expires;
u16 expiry_interval;
};
struct babel_entry {
struct fib_node n;
struct babel_proto *proto;
struct babel_route *selected_in;
struct babel_route *selected_out;
bird_clock_t updated;
list sources; /* Source entries for this prefix (struct babel_source). */
list routes; /* Routes for this prefix (struct babel_route) */
};
/* Stores forwarded seqno requests for duplicate suppression. */
struct babel_seqno_request {
node n;
ip_addr prefix;
u8 plen;
u64 router_id;
u16 seqno;
bird_clock_t updated;
};
/*
* Internal TLV messages
*/
struct babel_msg_ack_req {
u8 type;
u16 nonce;
u16 interval;
ip_addr sender;
};
struct babel_msg_ack {
u8 type;
u16 nonce;
};
struct babel_msg_hello {
u8 type;
u16 seqno;
u16 interval;
ip_addr sender;
};
struct babel_msg_ihu {
u8 type;
u8 ae;
u16 rxcost;
u16 interval;
ip_addr addr;
ip_addr sender;
};
struct babel_msg_update {
u8 type;
u8 ae;
u8 plen;
u16 interval;
u16 seqno;
u16 metric;
ip_addr prefix;
u64 router_id;
ip_addr next_hop;
ip_addr sender;
};
struct babel_msg_route_request {
u8 type;
u8 full;
u8 plen;
ip_addr prefix;
};
struct babel_msg_seqno_request {
u8 type;
u8 plen;
u16 seqno;
u8 hop_count;
u64 router_id;
ip_addr prefix;
ip_addr sender;
};
union babel_msg {
u8 type;
struct babel_msg_ack_req ack_req;
struct babel_msg_ack ack;
struct babel_msg_hello hello;
struct babel_msg_ihu ihu;
struct babel_msg_update update;
struct babel_msg_route_request route_request;
struct babel_msg_seqno_request seqno_request;
};
struct babel_msg_node {
node n;
union babel_msg msg;
};
/* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_ack(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_hello(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_ihu(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_router_id(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_update(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_route_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_show_interfaces(struct proto *P, char *iff);
void babel_show_neighbors(struct proto *P, char *iff);
void babel_show_entries(struct proto *P);
/* packets.c */
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);
void babel_send_unicast(union babel_msg *msg, struct babel_iface *ifa, ip_addr dest);
int babel_open_socket(struct babel_iface *ifa);
void babel_send_queue(void *arg);
#endif

129
proto/babel/config.Y Normal file
View File

@ -0,0 +1,129 @@
/*
* BIRD -- Babel Configuration
*
* Copyright (c) 2015-2016 Toke Hoiland-Jorgensen
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
CF_HDR
#include "proto/babel/babel.h"
#include "nest/iface.h"
CF_DEFINES
#define BABEL_CFG ((struct babel_config *) this_proto)
#define BABEL_IFACE ((struct babel_iface_config *) this_ipatt)
CF_DECLS
CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED,
WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC)
CF_GRAMMAR
CF_ADDTO(proto, babel_proto)
babel_proto_start: proto_start BABEL
{
this_proto = proto_config_new(&proto_babel, $1);
init_list(&BABEL_CFG->iface_list);
};
babel_proto_item:
proto_item
| INTERFACE babel_iface
;
babel_proto_opts:
/* empty */
| babel_proto_opts babel_proto_item ';'
;
babel_proto:
babel_proto_start proto_name '{' babel_proto_opts '}';
babel_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct babel_iface_config));
add_tail(&BABEL_CFG->iface_list, NODE this_ipatt);
init_list(&this_ipatt->ipn_list);
BABEL_IFACE->port = BABEL_PORT;
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
BABEL_IFACE->tx_priority = sk_priority_control;
BABEL_IFACE->check_link = 1;
};
babel_iface_finish:
{
if (BABEL_IFACE->type == BABEL_IFACE_TYPE_WIRELESS)
{
if (!BABEL_IFACE->hello_interval)
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRELESS;
if (!BABEL_IFACE->rxcost)
BABEL_IFACE->rxcost = BABEL_RXCOST_WIRELESS;
}
else
{
if (!BABEL_IFACE->hello_interval)
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
if (!BABEL_IFACE->rxcost)
BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED;
}
if (!BABEL_IFACE->update_interval)
BABEL_IFACE->update_interval = BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR;
BABEL_IFACE->ihu_interval = BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR;
};
babel_iface_item:
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
| HELLO INTERVAL expr { BABEL_IFACE->hello_interval = $3; if (($3<1) || ($3>65535)) cf_error("Invalid hello interval"); }
| UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>65535)) cf_error("Invalid hello interval"); }
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
| RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
| TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
| TX tos { BABEL_IFACE->tx_tos = $2; }
| TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; }
| CHECK LINK bool { BABEL_IFACE->check_link = $3; }
;
babel_iface_opts:
/* empty */
| babel_iface_opts babel_iface_item ';'
;
babel_iface_opt_list:
/* empty */
| '{' babel_iface_opts '}'
;
babel_iface:
babel_iface_start iface_patt_list_nopx babel_iface_opt_list babel_iface_finish;
CF_ADDTO(dynamic_attr, BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_BABEL_METRIC); })
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
CF_CLI(SHOW BABEL INTERFACES, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
CF_CODE
CF_END

1093
proto/babel/packets.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -121,7 +121,8 @@ bgp_open(struct bgp_proto *p)
bgp_counter++;
if (p->cf->password)
if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, p->cf->password) < 0)
if (sk_set_md5_auth(bgp_listen_sk, p->cf->source_addr, p->cf->remote_ip,
p->cf->iface, p->cf->password, p->cf->setkey) < 0)
{
sk_log_error(bgp_listen_sk, p->p.name);
bgp_close(p, 0);
@ -191,7 +192,8 @@ bgp_close(struct bgp_proto *p, int apply_md5)
bgp_counter--;
if (p->cf->password && apply_md5)
if (sk_set_md5_auth(bgp_listen_sk, p->cf->remote_ip, p->cf->iface, NULL) < 0)
if (sk_set_md5_auth(bgp_listen_sk, p->cf->source_addr, p->cf->remote_ip,
p->cf->iface, NULL, p->cf->setkey) < 0)
sk_log_error(bgp_listen_sk, p->p.name);
if (!bgp_counter)

View File

@ -51,6 +51,7 @@ struct bgp_config {
int add_path; /* Use ADD-PATH extension [draft] */
int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
int setkey; /* Set MD5 password to system SA/SP database */
unsigned gr_time; /* Graceful restart timeout */
unsigned connect_delay_time; /* Minimum delay between connect attempts */
unsigned connect_retry_time; /* Timeout for connect attempts */

View File

@ -27,7 +27,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY,
INTERPRET, COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP,
TABLE, GATEWAY, DIRECT, RECURSIVE, MED, TTL, SECURITY, DETERMINISTIC,
SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX, GRACEFUL, RESTART, AWARE,
CHECK, LINK, PORT, EXTENDED, MESSAGES)
CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY)
CF_GRAMMAR
@ -54,6 +54,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->default_local_pref = 100;
BGP_CFG->gr_mode = BGP_GR_AWARE;
BGP_CFG->gr_time = 120;
BGP_CFG->setkey = 1;
}
;
@ -112,6 +113,7 @@ bgp_proto:
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
| bgp_proto INTERPRET COMMUNITIES bool ';' { BGP_CFG->interpret_communities = $4; }
| bgp_proto SECONDARY bool ';' { BGP_CFG->secondary = $3; }

View File

@ -192,6 +192,7 @@ ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
/**
* ospf_send_dbdes - transmit database description packet
* @p: OSPF protocol instance
* @n: neighbor
*
* Sending of a database description packet is described in 10.8 of RFC 2328.

View File

@ -552,12 +552,13 @@ lsa_validate_prefix(struct ospf_lsa_header *lsa, struct ospf_lsa_prefix *body)
/**
* lsa_validate - check whether given LSA is valid
* @lsa: LSA header
* @lsa_type: internal LSA type (%LSA_T_xxx)
* @ospf2: %true for OSPFv2, %false for OSPFv3
* @body: pointer to LSA body
*
* Checks internal structure of given LSA body (minimal length,
* consistency). Returns true if valid.
*/
int
lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body)
{

View File

@ -207,7 +207,7 @@ drop:
/**
* ospf_rx_hook
* @sk: socket we received the packet.
* @size: size of the packet
* @len: length of the packet
*
* This is the entry point for messages from neighbors. Many checks (like
* authentication, checksums, size) are done before the packet is passed to

View File

@ -43,6 +43,7 @@
#undef CONFIG_BGP
#undef CONFIG_OSPF
#undef CONFIG_PIPE
#undef CONFIG_BABEL
/* We use multithreading */
#undef USE_PTHREADS

170
sysdep/bsd/setkey.h Normal file
View File

@ -0,0 +1,170 @@
/*
* BIRD -- Manipulation the IPsec SA/SP database using setkey(8) utility
*
* (c) 2016 CZ.NIC z.s.p.o.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/pfkeyv2.h>
#include <netipsec/ipsec.h>
#include "nest/bird.h"
#include "lib/unix.h"
/*
* Open a socket for manage the IPsec SA/SP database entries
*/
static int
setkey_open_socket(void)
{
int s = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
if (s < 0)
{
log(L_ERR "SETKEY: socket: %m");
return -1;
}
return s;
}
static int
setkey_send(struct sadb_msg *msg, uint len)
{
int s = setkey_open_socket();
if (s < 0)
return -1;
if (msg->sadb_msg_type == SADB_ADD)
{
/* Delete possible current key in the IPsec SA/SP database */
msg->sadb_msg_type = SADB_DELETE;
send(s, msg, len, 0);
msg->sadb_msg_type = SADB_ADD;
}
if (send(s, msg, len, 0) < 0)
{
log(L_ERR "SETKEY: send: %m");
close(s);
return -1;
}
close(s);
return 0;
}
/*
* Perform setkey(8)-like operation for set the password for TCP MD5 Signature.
* Could be called with SABD_ADD or SADB_DELETE argument. Note that SADB_ADD
* argument is internally processed as a pair of SADB_ADD and SADB_DELETE
* operations to implement replace.
*/
static int
setkey_md5(sockaddr *src, sockaddr *dst, char *passwd, uint type)
{
uint passwd_len = passwd ? strlen(passwd) : 0;
uint total =
sizeof(struct sadb_msg) +
sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len) +
sizeof(struct sadb_sa) +
sizeof(struct sadb_x_sa2) +
sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len) +
sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len);
char *buf = alloca(total);
char *pos = buf;
uint len;
memset(buf, 0, total);
struct sadb_msg *msg = (void *) pos;
len = sizeof(struct sadb_msg);
msg->sadb_msg_version = PF_KEY_V2;
msg->sadb_msg_type = type;
msg->sadb_msg_satype = SADB_X_SATYPE_TCPSIGNATURE;
msg->sadb_msg_len = 0; /* Fix it later */
msg->sadb_msg_pid = getpid();
pos += len;
/* Set authentication algorithm and password */
struct sadb_key *key = (void *) pos;
len = sizeof(struct sadb_key) + PFKEY_ALIGN8(passwd_len);
key->sadb_key_len = PFKEY_UNIT64(len);
key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
key->sadb_key_bits = passwd_len * 8;
memcpy(pos + sizeof(struct sadb_key), passwd, passwd_len);
pos += len;
struct sadb_sa *sa = (void *) pos;
len = sizeof(struct sadb_sa);
sa->sadb_sa_len = PFKEY_UNIT64(len);
sa->sadb_sa_exttype = SADB_EXT_SA;
sa->sadb_sa_spi = htonl((u32) TCP_SIG_SPI);
sa->sadb_sa_auth = SADB_X_AALG_TCP_MD5;
sa->sadb_sa_encrypt = SADB_EALG_NONE;
sa->sadb_sa_flags = SADB_X_EXT_CYCSEQ;
pos += len;
struct sadb_x_sa2 *sa2 = (void *) pos;
len = sizeof(struct sadb_x_sa2);
sa2->sadb_x_sa2_len = PFKEY_UNIT64(len);
sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
sa2->sadb_x_sa2_mode = IPSEC_MODE_ANY;
pos += len;
/* Set source address */
struct sadb_address *saddr = (void *) pos;
len = sizeof(struct sadb_address) + PFKEY_ALIGN8(src->sa.sa_len);
saddr->sadb_address_len = PFKEY_UNIT64(len);
saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
saddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
saddr->sadb_address_prefixlen = MAX_PREFIX_LENGTH;
memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len);
pos += len;
/* Set destination address */
struct sadb_address *daddr = (void *) pos;
len = sizeof(struct sadb_address) + PFKEY_ALIGN8(dst->sa.sa_len);
daddr->sadb_address_len = PFKEY_UNIT64(len);
daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
daddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
daddr->sadb_address_prefixlen = MAX_PREFIX_LENGTH;
memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len);
pos += len;
len = pos - buf;
msg->sadb_msg_len = PFKEY_UNIT64(len);
return setkey_send(msg, len);
}
/*
* Manipulation with the IPsec SA/SP database
*/
static int
sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd)
{
sockaddr src, dst;
sockaddr_fill(&src, s->af, local, ifa, 0);
sockaddr_fill(&dst, s->af, remote, ifa, 0);
if (passwd && *passwd)
{
int len = strlen(passwd);
if (len > TCP_KEYLEN_MAX)
ERR_MSG("The password for TCP MD5 Signature is too long");
if (setkey_md5(&src, &dst, passwd, SADB_ADD) < 0)
ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database");
}
else
{
if (setkey_md5(&src, &dst, NULL, SADB_DELETE) < 0)
ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
}
return 0;
}

View File

@ -189,30 +189,26 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen)
#ifndef TCP_KEYLEN_MAX
#define TCP_KEYLEN_MAX 80
#endif
#ifndef TCP_SIG_SPI
#define TCP_SIG_SPI 0x1000
#endif
/*
* FIXME: Passwords has to be set by setkey(8) command. This is the same
* behaviour like Quagga. We need to add code for SA/SP entries
* management.
*/
#if defined(__FreeBSD__)
#define USE_MD5SIG_SETKEY
#include "lib/setkey.h"
#endif
int
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED)
{
int enable = 0;
if (passwd && *passwd)
{
int len = strlen(passwd);
enable = TCP_SIG_SPI;
if (len > TCP_KEYLEN_MAX)
ERR_MSG("MD5 password too long");
}
#ifdef USE_MD5SIG_SETKEY
if (setkey)
if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0)
return -1;
#endif
int enable = (passwd && *passwd) ? TCP_SIG_SPI : 0;
if (setsockopt(s->fd, IPPROTO_TCP, TCP_MD5SIG, &enable, sizeof(enable)) < 0)
{
if (errno == ENOPROTOOPT)

View File

@ -7,7 +7,7 @@
#define _BIRD_CONFIG_H_
/* BIRD version */
#define BIRD_VERSION "1.5.0"
#define BIRD_VERSION "1.6.0"
/* Include parameters determined by configure script */
#include "sysdep/autoconf.h"

View File

@ -126,7 +126,12 @@ nl_get_reply(struct nl_sock *nl)
{
struct iovec iov = { nl->rx_buffer, NL_RX_SIZE };
struct sockaddr_nl sa;
struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
struct msghdr m = {
.msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
.msg_iovlen = 1,
};
int x = recvmsg(nl->fd, &m, 0);
if (x < 0)
die("nl_get_reply: %m");
@ -1343,7 +1348,12 @@ nl_async_hook(sock *sk, int size UNUSED)
{
struct iovec iov = { nl_async_rx_buffer, NL_RX_SIZE };
struct sockaddr_nl sa;
struct msghdr m = { (struct sockaddr *) &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
struct msghdr m = {
.msg_name = &sa,
.msg_namelen = sizeof(sa),
.msg_iov = &iov,
.msg_iovlen = 1,
};
struct nlmsghdr *h;
int x;
uint len;

View File

@ -179,19 +179,19 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
*/
int
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED)
{
struct tcp_md5sig md5;
memset(&md5, 0, sizeof(md5));
sockaddr_fill((sockaddr *) &md5.tcpm_addr, fam_to_af[s->fam], a, ifa, 0);
sockaddr_fill((sockaddr *) &md5.tcpm_addr, fam_to_af[s->fam], remote, ifa, 0);
if (passwd)
{
int len = strlen(passwd);
if (len > TCP_MD5SIG_MAXKEYLEN)
ERR_MSG("MD5 password too long");
ERR_MSG("The password for TCP MD5 Signature is too long");
md5.tcpm_keylen = len;
memcpy(&md5.tcpm_key, passwd, len);

View File

@ -448,6 +448,7 @@ tm_format_reltime(char *x, struct tm *tm, bird_clock_t delta)
/**
* tm_format_datetime - convert date and time to textual representation
* @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
* @fmt_spec: specification of resulting textual representation of the time
* @t: time
*
* This function formats the given relative time value @t to a textual
@ -952,23 +953,32 @@ sk_set_min_ttl(sock *s, int ttl)
/**
* sk_set_md5_auth - add / remove MD5 security association for given socket
* @s: socket
* @a: IP address of the other side
* @local: IP address of local side
* @remote: IP address of remote side
* @ifa: Interface for link-local IP address
* @passwd: password used for MD5 authentication
* @passwd: Password used for MD5 authentication
* @setkey: Update also system SA/SP database
*
* In TCP MD5 handling code in kernel, there is a set of pairs (address,
* password) used to choose password according to address of the other side.
* This function is useful for listening socket, for active sockets it is enough
* to set s->password field.
* In TCP MD5 handling code in kernel, there is a set of security associations
* used for choosing password and other authentication parameters according to
* the local and remote address. This function is useful for listening socket,
* for active sockets it may be enough to set s->password field.
*
* When called with passwd != NULL, the new pair is added,
* When called with passwd == NULL, the existing pair is removed.
*
* Note that while in Linux, the MD5 SAs are specific to socket, in BSD they are
* stored in global SA/SP database (but the behavior also must be enabled on
* per-socket basis). In case of multiple sockets to the same neighbor, the
* socket-specific state must be configured for each socket while global state
* just once per src-dst pair. The @setkey argument controls whether the global
* state (SA/SP database) is also updated.
*
* Result: 0 for success, -1 for an error.
*/
int
sk_set_md5_auth(sock *s, ip_addr a, struct iface *ifa, char *passwd)
sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey)
{ DUMMY; }
#endif
@ -1436,7 +1446,7 @@ sk_open(sock *s)
}
if (s->password)
if (sk_set_md5_auth(s, s->daddr, s->iface, s->password) < 0)
if (sk_set_md5_auth(s, s->saddr, s->daddr, s->iface, s->password, 0) < 0)
goto err;
switch (s->type)

View File

@ -89,6 +89,7 @@ static char *class_names[] = {
/**
* log_commit - commit a log message
* @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
* @buf: message to write
*
* This function writes a message prepared in the log buffer to the
* log file (as specified in the configuration). The log buffer is

View File

@ -621,7 +621,7 @@ signal_init(void)
* Parsing of command-line arguments
*/
static char *opt_list = "c:dD:ps:P:u:g:fR";
static char *opt_list = "c:dD:ps:P:u:g:flR";
static int parse_and_exit;
char *bird_name;
static char *use_user;
@ -631,7 +631,7 @@ static int run_in_foreground = 0;
static void
usage(void)
{
fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-R]\n", bird_name);
fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-P <pid-file>] [-u <user>] [-g <group>] [-f] [-l] [-R]\n", bird_name);
exit(1);
}
@ -698,6 +698,8 @@ get_gid(const char *s)
static void
parse_args(int argc, char **argv)
{
int config_changed = 0;
int socket_changed = 0;
int c;
bird_name = get_bird_name(argv[0], "bird");
@ -716,6 +718,7 @@ parse_args(int argc, char **argv)
{
case 'c':
config_name = optarg;
config_changed = 1;
break;
case 'd':
debug_flag |= 1;
@ -729,6 +732,7 @@ parse_args(int argc, char **argv)
break;
case 's':
path_control_socket = optarg;
socket_changed = 1;
break;
case 'P':
pid_file = optarg;
@ -742,6 +746,12 @@ parse_args(int argc, char **argv)
case 'f':
run_in_foreground = 1;
break;
case 'l':
if (!config_changed)
config_name = xbasename(config_name);
if (!socket_changed)
path_control_socket = xbasename(path_control_socket);
break;
case 'R':
graceful_restart_recovery();
break;