Compare commits

...

71 Commits

Author SHA1 Message Date
Ondrej Zajicek (work)
a6622bd204 NEWS and version update 2019-08-01 03:31:23 +02:00
Ondrej Zajicek (work)
aba51d80c0 Doc: Update documentation about VRFs and BFD 2019-08-01 01:02:31 +02:00
Ondrej Zajicek (work)
da8644d7d9 Nest: VRF of protocol can be explicitly specified as 'default'
Protocol can have specified VRF, in such case it is restricted to a set
of ifaces associated with the VRF, otherwise it can use all interfaces.

The patch allows to specify VRF as 'default', in which case it is
restricted to a set of iface not associated with any VRF.
2019-08-01 00:53:22 +02:00
Maria Matejka
d72d3891bf Log: Fixed race condition in reconfigure while BFD is running 2019-07-30 12:13:38 +02:00
Maria Matejka
46faedff29 Debug: growing message format buffer
This led in corner cases to undefined buffer content
and garbage output.
2019-07-18 12:41:45 +02:00
Ondrej Zajicek (work)
9d23aa7a80 Lib: Fix print of 64-bit router id
Mismatched types to printf(). The old code coincidentally worked on amd64
due to its calling conventions.

Thanks to Maximilian Eschenbacher for the bugreport.
2019-07-18 02:05:36 +02:00
Ondrej Zajicek (work)
f9deedf1f0 BFD: Support for VRFs
Allow multiple BFD instances in separate VRFs, dispatch BFD requests
according to VRFs.

Thanks to Alexander Zubkov for notice and patches.
2019-07-18 02:04:42 +02:00
Alexander Azimov
9ff6c8d83c BGP: Compliance with RFC8203bis 2019-07-11 15:44:52 +02:00
Ondrej Zajicek (work)
78c05cc159 OSPF: Update DR when local priority changes
When priority is reconfigured locally, we need to trigger DR election.
2019-07-11 15:44:05 +02:00
Ondrej Zajicek (work)
a92aee467e Avoid fallthrough warnings 2019-07-11 15:44:05 +02:00
Ondrej Zajicek (work)
6b72ea4c14 OSPF: N-bit should not be set for DBDES packets 2019-07-11 15:44:05 +02:00
Maria Jan Matejka
354afcab04 BGP: Prefix hash is too small, increase its max size.
This doesn't make any change for you until you have
millions of updates waiting to be sent. Increasing
the max hash size from 2^20 to 2^24.
2019-06-11 13:19:21 +00:00
Maria Jan Matejka
e989b901fc BGP: split tx explicitly
If BGP has too many data to send and BIRD is slower than the link, TX is
always possible until all data is sent. This patch limits maximum number
of generated BGP messages in one iteration of TX hook.
2019-06-11 09:39:00 +00:00
Ondrej Filip
5648f07e4d Small typo in doc. 2019-04-24 13:50:54 +02:00
Ondrej Zajicek (work)
b5d1903bf6 NEWS and version update 2019-02-26 18:10:04 +01:00
Ondrej Zajicek (work)
2e7ee1c9d3 Nest: Do not compare rte.flags during rte_update()
Route flags are mosty internal state of rtable, they are not significant
to whether a route has changed. With the old code, all routes received as
a part of enhanced route refresh are always re-announced to other peers
due to change in REF_STALE.
2019-02-22 02:33:01 +01:00
Ondrej Zajicek (work)
797969983d Doc: Detect SP/OpenSP automatically 2019-02-19 18:32:45 +01:00
Ondrej Zajicek (work)
b3fceeba30 Nest: Prevent withdraws from propagation back to source protocol (for accepted mode)
Update for one of previous patches, handles the the issue for
first-accepted mode of route propagation.
2019-02-19 16:21:52 +01:00
Ondrej Zajicek (work)
2dd9800ab5 Nest: Improve export counter handling
One of previous workarounds for phantom route avoidance breaks export
counters by expanding sending of spurious withdraws, which are send when
we are not sure whether we have advertised that routes in the past.
If not, then export counter is decreased, but it was not increased
before, so it overflows under zero.

The patch fixes that by sending spurious withdraws, but not counting them
on export counter. That may lead to error in the other direction, but
that happens only as a race condition (i.e., in normal operation filters
return proper values about old route export state).
2019-02-19 16:02:53 +01:00
Ondrej Zajicek (work)
b4438e40ef Nest: Prevent withdraws from propagation back to source protocol
The earlier fix loosen conditions for not running filters on old
route when deciding about route propagation to a protocol to avoid
issues with ghost routes in some race conditions.

Unfortunately, the fix also caused back-propagation of withdraws. For
regular updates, back-propagation is prevented in import_control hooks,
but these are not called on withdraws. For them, import_control hooks
are called on old routes instead, changing (old, NULL) notification
to (NULL, NULL), which is ignored. By not calling export processing
in some cases, the withdraw is not ignored and is back-propagated.

This patch fixes that by contract conditions so the earlier fix is not
applied to back-propagated updates.
2019-01-30 17:08:11 +01:00
Ondrej Zajicek (work)
ccb37330d0 Doc: Add documentation for OSPF retransmit delay option
Thanks to Igor Podlesny for notification.
2019-01-26 21:03:36 +01:00
Ondrej Filip
e99e7d1c2d Added documentation for 'disable after cease' 2019-01-07 12:26:21 +01:00
Ondrej Zajicek (work)
ef8974b7ca NEWS and version update 2019-01-05 00:44:26 +01:00
Ondrej Zajicek (work)
a93684b2d4 Configure: Fix lost suffix in bird.ctl
One of previous commits bacported from 2.0 removed suffix from bird.ctl
2019-01-04 19:11:54 +01:00
Ondrej Zajicek (work)
c30f00d4a8 BSD: Fix TCP-MD5 code on current FreeBSD kernels
Current FreeBSD kernels require SA records for both directions.

Thanks to Joseph Mulloy and Andrey V. Elsukov for reporting and
solving the issue.
2019-01-04 18:20:56 +01:00
Ondrej Zajicek (work)
968c31ec6d Doc: README and INSTALL update
Minor cleanups, updates and clarifications. Also removes (incomplete
and well-known) build steps from README, as they are better described
in INSTALL.
2019-01-03 17:26:57 +01:00
Ondrej Zajicek (work)
89bc266fe7 Doc: Fix documentation build with newer Linuxdoc-Tools 2019-01-03 17:17:08 +01:00
Robert Scheck
cdf2daae01 Doc: Allow overriding $SGML_CATALOG_FILES using distribution specific paths 2018-12-20 13:25:53 +01:00
Robert Scheck
7a53383a22 Doc: Add alternative path for SGML ISO entities 8879.1986 to $SGML_CATALOG_FILES
The existing paths are valid for Debian, alternative paths are necessary
for Fedora and RHEL/CentOS.
2018-12-20 13:25:31 +01:00
Ondrej Zajicek (work)
b47d33b344 Autoconf: Minor cleanup 2018-12-20 13:17:30 +01:00
Ondrej Zajicek (work)
16fb28e588 Configure: Use standard --runstatedir option
Newer Autoconf defines --runstatedir option for setting directory for
run-time variable data. Use it instead our old --with-runtimedir.
2018-12-20 13:15:53 +01:00
Ondrej Zajicek (work)
e7e3b335bf Nest: Fix crash in rta_show() for Babel routes
Some new route source values did not have associated string
in rta_show(), which might caused crash in some cases.
2018-12-20 13:06:18 +01:00
Ondrej Zajicek (work)
4df42f1a55 Lib: Force output type in ip4_addr constructor
Fixes type issue when u64 is pushed into it.
2018-12-20 13:01:15 +01:00
Ondrej Zajicek (work)
17450df314 Filter: Fix minor bug in accessing bgp_path
Not relevant for regular BGP paths, just for BGP paths added by filters
to e.g. static routes.
2018-12-20 12:59:55 +01:00
Ondrej Zajicek (work)
d82b1a1977 Nest: Fix 'show interfaces summary' command
The command showed interfaces that were removed / in shutdown.
2018-12-20 12:57:43 +01:00
Ondrej Zajicek (work)
257c7ce95d Doc: Fix description of 'description'
Thanks to Clemens Schrimpe for the bugreport.
2018-12-20 12:54:52 +01:00
Ondrej Zajicek (work)
04edf8f2f2 IO: Workaround for broken FreeBSD behavior
FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, even when
it is explicitly set to another value. That breaks TTL security sockets,
including BFD which always uses TTL 255. Bad FreeBSD!
2018-12-19 18:10:39 +01:00
Ondrej Zajicek (work)
c0ed32ee28 Doc: Generate MRT progdoc 2018-12-19 16:32:52 +01:00
Ondrej Zajicek (work)
523c5d9f2b Doc: Rename code documentation files back to Doc 2018-12-19 16:29:20 +01:00
Ondrej Zajicek (work)
d1c8f22bec Doc: Move root of code documentation to doc dir
It reduces clutter in root and also avoid collision with doc dir on
case-insensitive filesystems when name back to Doc.
2018-12-19 16:25:59 +01:00
Ondrej Zajicek (work)
81bc013dde Unix: Fix variable declarations 2018-12-19 15:52:13 +01:00
Ondrej Zajicek (work)
98b1486c48 OSPF: Fix wrong LSA collisions detection
In some circumstances (old LSA flushed but not acknowledged and not
removed) origination of a new LSA may wrongly triggers LSA collision
code. The patch fixes that.

Thanks to Asbjorn Mikkelsen for the bugreport and @mdelagueronniere
for the original patch.
2018-12-17 17:10:59 +01:00
Ondrej Zajicek (work)
8c0b12ac86 OSPF: Fix reconfiguration of vlinks
Fix crash during reconfiguration of OSPF config with vlinks. When vlink
is reconfigured, a generic iface-reconfiguration code is used, which in
one place supposes that it is running on a regular iface.

Thanks to Cybertinus for a bugreport.
2018-12-10 02:08:52 +01:00
Ondrej Zajicek (work)
ea59172cde Static: Fix reset neighbor entries for ECMP routes
Neighbor entries for static ECMP routes were not cleaned up during
reconfigure and pointed to the old instances, which leads to crash
after reconfigure.

Thanks to Vladimir Osmolovskiy for the bugreport.
2018-12-04 13:52:58 +01:00
Ondrej Zajicek (work)
93cec70361 MRT documentation 2018-11-21 15:59:53 +01:00
Ondrej Zajicek (work)
1453ab7552 MRT: Fix bug in MRT table dump requested from CLI 2018-11-20 17:40:47 +01:00
Ondrej Zajicek (work)
81489b79e0 Nest: Improve keeping track of IPv6 link-local addresses
Most protocols in IPv6 mode use link-local source addresses and expect
that there is one on each active interface. The old code depended on
assumption that if there is some IPv6 address on iface, there is also an
IPv6 link-local address on that iface (added by kernel when the iface
went up). Unfortunately, that is not generally true, as a configured
global address sometimes ceases to be tentative (finishes DOD) before
a link-local address on the same iface. In such case a protocol iface
(namely RAdv and Babel) is activated, but fails to found link-local
address and stays in failed state.

The patch fixes that by tracking 'primary' IPv6 link-local address,
sending iface restart notifications when it changes and making
protocols ignore iface-up notifications when no such address is
selected for an iface.
2018-11-08 20:43:04 +01:00
Ondrej Zajicek (work)
716b904f4e Filter: Make ifname attribute modifiable
Allow to change an interface associated with a route by setting
ifname attribute. It will also change the route to a direct one.
2018-11-05 21:55:18 +01:00
Ondrej Zajicek (work)
fff79b1c1e OSPF: Fix some trace messages
Missing argument in MTU change trace message can crash bird when MTU
change happens and trace messages are active.

Thanks to Alexander Velkov for the bugreport.
2018-10-25 17:21:06 +02:00
Ondrej Zajicek (work)
c0fc3e6718 The MRT protocol
The new MRT protocol is responsible for periodic RIB table dumps in the
MRT format (RFC 6396). Also the existing code for BGP4MP MRT dumps is
refactored and splitted between BGP to MRT protocols, will be more
integrated into MRT in the future.

Example:

protocol mrt {
	table "*";
	filename "%N_%F_%T.mrt";
	period 60;
}

It is partially based on the old MRT code from Pavel Tvrdik.
2018-09-18 17:50:45 +02:00
Jan Maria Matejka
afa14f1868 Conf: Show the line:char position where the syntax error happens 2018-09-11 16:58:09 +02:00
Ondrej Zajicek (work)
b1f6c439f5 BGP: Fix BFD/GR interaction
The old code does not cause GR if BFD failed when GR is running,
session is re-established but not yet synchronized.
2018-08-01 17:41:29 +02:00
Ondrej Zajicek (work)
4abccabd7b BGP: Minor fixes in long-lived graceful restart 2018-08-01 17:35:39 +02:00
Ondrej Zajicek (work)
6be71641ef BSD: Use MSG_DONTROUTE for unicast packets on FreeBSD
BSD systems cannot use SO_DONTROUTE, because it does not work properly
with multicast packets (perhaps it tries to find iface based on multicast
group address). But we can use MSG_DONTROUTE sendmsg() flag for unicast
packets. Works on FreeBSD, is ignored on OpenBSD and is broken on NetBSD
(i guess due to integrated routing table and ARP table).
2018-07-28 19:30:56 +02:00
Ondrej Zajicek (work)
3140c8b2ca Move FreeBSD CFLAGS and LDFLAGS to configure
Backport of commit 09c1e370b3084f7acb7c3777427670a69945368a.
2018-07-28 15:52:19 +02:00
Ondrej Zajicek (work)
aa2ec912f5 BGP: Long-lived graceful restart enhancements
When use of LLGR is negotiated, handle hold timeout by LLGR instead of by
hard restart. Allow to configure whether BFD session down event should be
handled by GR/LLGR or by hard restart.
2018-07-17 13:16:35 +02:00
Ondrej Zajicek (work)
a9d869c484 Doc: Documentation for long-lived graceful restart 2018-07-17 13:16:35 +02:00
Ondrej Zajicek (work)
68197386dd BGP: Long-lived graceful restart
The patch implements long-lived graceful restart for BGP, namely
draft-uttaro-idr-bgp-persistence-03.
2018-07-17 13:16:18 +02:00
Ondrej Zajicek (work)
470efcb98c Nest: Fix race condition during reconfiguration, part 2
If export filter is changed during reconfiguration and a route disappears
between reconfiguration and refeed (e.g., if the route is a static route
also removed during the reconfiguration), the route is not withdrawn.

The issue was fixed for regular channels by an earlier patch. This patch
fixes the issue for channels in RA_ACCEPTED mode (first-pass-the-filter),
used by BGP with 'secondary' option.
2018-07-06 02:17:59 +02:00
Ondrej Zajicek (work)
cbfdf6ed05 Nest: Fix race condition during reconfiguration
If export filter is changed during reconfiguration and a route disappears
between reconfiguration and refeed (e.g., if the route is a static route
also removed during the reconfiguration), the route is not withdrawn.
The patch fixes that by adding tx reconfiguration timestamp.
2018-07-03 19:21:59 +02:00
Maria Matejka
822a7ee6d5 Autotools: updated config.guess and config.sub
Updated to version 63b4ce2e8c28aee6a32133e400436e4ca885215a
from git://git.savannah.gnu.org/config.git

Previous version was 93b5037172b15ad28952481933517f1ba93d125b
2018-04-24 14:43:42 +02:00
Maria Matejka
0671e6c29a Netlink: removed dynamic length array as Clang won't support it. 2018-04-24 12:18:32 +02:00
Maria Matejka
1e921ec868 Android: check for extra libs needed for build 2018-04-24 12:18:32 +02:00
Maria Matejka
7904f409e2 Doc: renamed progdoc files Doc -> progdoc to fix collision with doc/ folder on case-insensitive filesystems 2018-04-23 11:29:13 +02:00
Ondrej Zajicek (work)
4c0b741ba7 Doc: Remove some superfluous slashes 2018-03-24 01:53:03 +01:00
Ondrej Zajicek (work)
f99c61b1f4 Doc: Be consistent in generating pdf output 2018-03-24 01:34:58 +01:00
Ondrej Filip
2ee6a89a8d Autoconf replaced by autoreconf 2018-03-23 17:22:55 +01:00
Ondrej Filip
f77fb3f00e Date added. 2018-03-22 13:33:12 +01:00
Ondrej Zajicek (work)
a71a75213d NEWS and version update 2018-03-21 16:26:39 +01:00
Ondrej Zajicek (work)
4dff1f32b5 Doc: Minor build fix 2018-03-21 16:26:39 +01:00
Ondrej Zajicek (work)
97b1b04d93 C99 loop declarations not allowed in 1.6.x 2018-03-19 19:51:11 +01:00
82 changed files with 3103 additions and 1289 deletions

View File

@ -211,9 +211,6 @@ docker_ubuntu-16_04-amd64:
# TODO We want to copy these BSDs to our own virtual machines, to make sure someone doesn't update them by accident.
.freebsd-11-i386: &freebsd-11-i386_env
variables:
CPPFLAGS: "-I/usr/local/include"
LDFLAGS: "-L/usr/local/lib"
tags:
- freebsd
- i386
@ -223,9 +220,6 @@ docker_ubuntu-16_04-amd64:
#- tags
.freebsd-11-amd64: &freebsd-11-amd64_env
variables:
CPPFLAGS: "-I/usr/local/include"
LDFLAGS: "-L/usr/local/lib"
tags:
- freebsd
- amd64

7
Doc
View File

@ -1,7 +0,0 @@
C doc
C nest
C conf
C filter
C proto
C sysdep
C lib

View File

@ -7,13 +7,15 @@ $ make
Default location for configuration file is /usr/local/etc/bird.conf and
for control socket is /usr/local/var/run/bird.ctl . You can change that
by --sysconfdir and --localstatedir configure options.
by --prefix, --sysconfdir and --runstatedir configure options, e.g.:
$ ./configure --prefix=/usr --sysconfdir=/etc --runstatedir=/run
To compile current development BIRD source code from Git repository, you
also need Git (to download the source code) and Autoconf (to generate
the configure script and associated files using 'autoreconf' tool):
$ git clone git://git.nic.cz/bird.git
$ git clone https://gitlab.labs.nic.cz/labs/bird/
$ cd bird
$ autoreconf
@ -32,7 +34,7 @@ For compiling BIRD you need these programs and libraries:
- Flex
- ncurses library
- GNU Readline library (2.1 or newer)
- GNU Readline library
For compiling BIRD documentation you also need:

27
NEWS
View File

@ -1,3 +1,30 @@
Version 1.6.7 (2019-08-01)
o BFD: Support for VRFs
o Several bugfixes
Version 1.6.6 (2019-02-27)
o Several bugfixes related to route propagation
Version 1.6.5 (2019-01-05)
o MRT table dumps (RFC 6396)
o BGP Long-lived graceful restart
o Filter: Make ifname attribute modifiable
o Improved keeping track of IPv6 link-local addresses
o Many bugfixes
Version 1.6.4 (2018-03-22)
o Basic VRF support
o Simplified autoconf scripts
o BGP: Shutdown communication (RFC 8203)
o BGP: Allow exchanging LOCAL_PREF with eBGP peers
o BGP: Allow to specify interface for regular sessions
o BGP: New option 'disable after cease'
o RAdv: Support for more specific routes (RFC 4191)
o RAdv: Proper handling of prefix retraction
o Filter: Allow silent filter execution
o Filter: Fixed stack overflow in BGP mask expressions
o Several bug fixes
Version 1.6.3 (2016-12-21)
o Large BGP communities
o BFD authentication (MD5, SHA1)

18
README
View File

@ -6,7 +6,7 @@
(c) 1998--2008 Martin Mares <mj@ucw.cz>
(c) 1998--2000 Pavel Machek <pavel@ucw.cz>
(c) 1998--2008 Ondrej Filip <feela@network.cz>
(c) 2009--2016 CZ.NIC z.s.p.o.
(c) 2009--2019 CZ.NIC z.s.p.o.
================================================================================
@ -48,20 +48,10 @@ How to install BIRD
ftp://bird.network.cz/pub/bird/redhat/
o From source code of the latest stable release version
ftp://bird.network.cz/pub/bird/
o From source code of the actual development version
git://git.nic.cz/bird.git
o From current development code in Git repository
https://gitlab.labs.nic.cz/labs/bird/
How to install BIRD from source code
------------------------------------
$ ./configure
$ make
$ su
# make install
# vi /usr/local/etc/bird.conf
See the file INSTALL for more information about installation from source code.
See the file INSTALL for information about installation from source code.
Documentation
=============
@ -69,7 +59,7 @@ Documentation
Online documentation is available at http://bird.network.cz/?get_doc or as HTML
files in the doc directory, you can install it by `make install-docs' and
rebuild it by `make docs', but you'll need SGMLtools and LaTeX to be installed
on your machine. You can also download a neatly formatted PostScript version as
on your machine. You can also download a neatly formatted PDF version as
a separate archive (bird-doc-*.tar.gz) from ftp://bird.network.cz/pub/bird/
User support

66
aclocal.m4 vendored
View File

@ -31,6 +31,72 @@ AC_DEFUN([BIRD_CHECK_PTHREADS],
CFLAGS="$bird_tmp_cflags"
])
AC_DEFUN([BIRD_CHECK_ANDROID_GLOB],
[
AC_CACHE_CHECK(
[for glob.h],
[bird_cv_lib_glob],
AC_LINK_IFELSE([
AC_LANG_PROGRAM(
[
#include <glob.h>
#include <stdlib.h>
],
[ glob(NULL, 0, NULL, NULL); ]
)
],
[bird_cv_lib_glob=yes],
[
bird_tmp_libs="$LIBS"
LIBS="$LIBS -landroid-glob"
AC_LINK_IFELSE([
AC_LANG_PROGRAM(
[
#include <glob.h>
#include <stdlib.h>
],
[ glob(NULL, 0, NULL, NULL); ]
)
],
[bird_cv_lib_glob=-landroid-glob],
[bird_cv_lib_glob=no]
)
LIBS="$bird_tmp_libs"
]
)
)
])
AC_DEFUN([BIRD_CHECK_ANDROID_LOG],
[
AC_CACHE_CHECK(
[for syslog lib flags],
[bird_cv_lib_log],
AC_LINK_IFELSE([
AC_LANG_PROGRAM(
[ #include <sys/syslog.h> ],
[ syslog(0, ""); ]
)
],
[bird_cv_lib_log=yes],
[
bird_tmp_libs="$LIBS"
LIBS="$LIBS -llog"
AC_LINK_IFELSE([
AC_LANG_PROGRAM(
[ #include <sys/syslog.h> ],
[ syslog(0, ""); ]
)
],
[bird_cv_lib_log=-llog],
[bird_cv_lib_log=no]
)
LIBS="$bird_tmp_libs"
]
)
)
])
AC_DEFUN([BIRD_CHECK_GCC_OPTION],
[
bird_tmp_cflags="$CFLAGS"

View File

@ -100,6 +100,7 @@ static struct include_file_stack *ifs_head;
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
#define YY_NO_UNPUT
#define YY_FATAL_ERROR(msg) cf_error(msg)
#define YY_USER_ACTION ifs->chno += yyleng; ifs->toklen = yyleng;
static void cf_include(char *arg, int alen);
static int check_eof(void);
@ -237,7 +238,7 @@ else: {
{WHITE}+
\n ifs->lino++;
\n ifs->lino++; ifs->chno = 0;
# BEGIN(COMMENT);
@ -247,13 +248,14 @@ else: {
<COMMENT>\n {
ifs->lino++;
ifs->chno = 0;
BEGIN(INITIAL);
}
<COMMENT>.
<CCOMM>\*\/ BEGIN(INITIAL);
<CCOMM>\n ifs->lino++;
<CCOMM>\n ifs->lino++; ifs->chno = 0;
<CCOMM>\/\* cf_error("Comment nesting not supported");
<CCOMM><<EOF>> cf_error("Unterminated comment");
<CCOMM>.

View File

@ -206,7 +206,7 @@ config_del_obstacle(struct config *c)
{
DBG("+++ deleting obstacle %d\n", c->obstacle_count);
c->obstacle_count--;
if (!c->obstacle_count)
if (!c->obstacle_count && (c != config))
ev_schedule(config_event);
}
@ -515,6 +515,7 @@ cf_error(char *msg, ...)
va_end(args);
new_config->err_msg = cfg_strdup(buf);
new_config->err_lino = ifs->lino;
new_config->err_chno = ifs->chno - ifs->toklen + 1;
new_config->err_file_name = ifs->file_name;
cf_lex_unwind();
longjmp(conf_jmpbuf, 1);

View File

@ -48,6 +48,7 @@ struct config {
u32 watchdog_timeout; /* Watchdog timeout (in seconds, 0 = disabled) */
char *err_msg; /* Parser error message */
int err_lino; /* Line containing error */
int err_chno; /* Character where the parser stopped */
char *err_file_name; /* File name containing error */
char *file_name; /* Name of main configuration file */
int file_fd; /* File descriptor of main configuration file */
@ -141,6 +142,8 @@ struct include_file_stack {
char *file_name; /* File name */
int fd; /* File descriptor */
int lino; /* Current line num */
int chno; /* Current char num (on current line) */
int toklen; /* Current token length */
int depth; /* Include depth, 0 = cannot include */
struct include_file_stack *prev; /* Previous record in stack */
@ -149,7 +152,6 @@ struct include_file_stack {
extern struct include_file_stack *ifs;
int cf_lex(void);
void cf_lex_init(int is_cli, struct config *c);
void cf_lex_unwind(void);

View File

@ -55,6 +55,7 @@ CF_DECLS
struct roa_show_data *ro;
struct sym_show_data *sd;
struct lsadb_show_data *ld;
struct mrt_dump_data *md;
struct iface *iface;
struct roa_table *rot;
void *g;

View File

@ -48,14 +48,12 @@ AC_ARG_WITH([suffix],
)
AC_ARG_WITH([sysconfig],
[AS_HELP_STRING([--with-sysconfig=FILE], [use specified BIRD system configuration file])],
[]
[AS_HELP_STRING([--with-sysconfig=FILE], [use specified BIRD system configuration file])]
)
AC_ARG_WITH([runtimedir],
[AS_HELP_STRING([--with-runtimedir=PATH], [path for runtime files @<:@LOCALSTATEDIR/run@:>@])],
[runtimedir="$with_runtimedir"],
[runtimedir="\$(localstatedir)/run"]
[AS_HELP_STRING([--with-runtimedir=PATH], [run-state data, obsolete variant of --runstatedir])],
[runstatedir="$with_runtimedir"]
)
AC_ARG_WITH([iproutedir],
@ -91,7 +89,11 @@ esac
AC_SUBST([objdir])
AC_SUBST([exedir])
AC_SUBST([srcdir_rel_mf])
AC_SUBST([runtimedir])
# Workaround for older Autoconfs that do not define runstatedir
AS_IF([test -z "${runstatedir}"], [runstatedir='${localstatedir}/run'])
AC_SUBST([runstatedir])
if test "$enable_ipv6" = yes ; then
ip=ipv6
@ -112,7 +114,7 @@ if test "$enable_debug" = yes ; then
CONTROL_SOCKET="bird$SUFFIX.ctl"
else
CONFIG_FILE="\$(sysconfdir)/bird$SUFFIX.conf"
CONTROL_SOCKET="$runtimedir/bird$SUFFIX.ctl"
CONTROL_SOCKET="\$(runstatedir)/bird$SUFFIX.ctl"
fi
AC_SUBST([CONFIG_FILE])
AC_SUBST([CONTROL_SOCKET])
@ -216,9 +218,13 @@ else
;;
ipv6:freebsd*)
sysdesc=bsd-v6
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
;;
ipv4:freebsd*)
sysdesc=bsd
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
;;
ipv6:dragonfly*)
sysdesc=bsd-v6
@ -266,7 +272,7 @@ fi
AC_SUBST([iproutedir])
all_protocols="$proto_bfd bgp ospf pipe $proto_radv rip static"
all_protocols="$proto_bfd bgp mrt ospf pipe $proto_radv rip static"
if test "$ip" = ipv6 ; then
all_protocols="$all_protocols babel"
fi
@ -279,6 +285,7 @@ fi
AH_TEMPLATE([CONFIG_BABEL], [Babel protocol])
AH_TEMPLATE([CONFIG_BFD], [BFD protocol])
AH_TEMPLATE([CONFIG_BGP], [BGP protocol])
AH_TEMPLATE([CONFIG_MRT], [MRT protocol])
AH_TEMPLATE([CONFIG_OSPF], [OSPF protocol])
AH_TEMPLATE([CONFIG_PIPE], [Pipe protocol])
AH_TEMPLATE([CONFIG_RADV], [RAdv protocol])
@ -321,6 +328,20 @@ AC_C_BIGENDIAN(
[AC_MSG_ERROR([Cannot determine CPU endianity.])]
)
BIRD_CHECK_ANDROID_GLOB
if test "$bird_cv_lib_glob" = no ; then
AC_MSG_ERROR([glob.h not found.])
elif test "$bird_cv_lib_glob" != yes ; then
LIBS="$LIBS $bird_cv_lib_glob"
fi
BIRD_CHECK_ANDROID_LOG
if test "$bird_cv_lib_log" = no ; then
AC_MSG_ERROR([don't know how to link syslog.])
elif test "$bird_cv_lib_log" != yes ; then
LIBS="$LIBS $bird_cv_lib_log"
fi
if test "$enable_debug" = yes ; then
AC_DEFINE([DEBUGGING], [1], [Define to 1 if debugging is enabled])
if test "$enable_memcheck" = yes ; then
@ -382,7 +403,7 @@ AC_SUBST([CLIENT_LIBS])
mkdir -p $objdir/sysdep
AC_CONFIG_HEADERS([$objdir/sysdep/autoconf.h:sysdep/autoconf.h.in])
AC_CONFIG_COMMANDS([merge],
[ export CPP="$CPP"; $srcdir/tools/mergedirs $srcdir $srcdir_rel $objdir $sysdep_dirs ],
[ export CPP="$CPP"; sh $srcdir/tools/mergedirs $srcdir $srcdir_rel $objdir $sysdep_dirs ],
[
srcdir=$srcdir
srcdir_rel=$srcdir_rel
@ -405,4 +426,5 @@ AC_MSG_RESULT([ Debugging: $enable_debug])
AC_MSG_RESULT([ POSIX threads: $enable_pthreads])
AC_MSG_RESULT([ Routing protocols: $protocols])
AC_MSG_RESULT([ Client: $enable_client])
rm -f $objdir/.*-stamp

View File

@ -1 +0,0 @@
D prog-intro.sgml

View File

@ -242,6 +242,7 @@ sub process_options
# removes iso-entites sub directory after doing make install.)
#
$ENV{SGML_CATALOG_FILES} .= (defined $ENV{SGML_CATALOG_FILES} ? ":" : "") .
"$main::prefix/share/sgml/sgml-iso-entities-8879.1986/catalog:" .
"$main::prefix/share/sgml/entities/sgml-iso-entities-8879.1986/catalog";
$ENV{SGML_CATALOG_FILES} .= ":$main::DataDir/linuxdoc-tools.catalog";
$ENV{SGML_CATALOG_FILES} .= ":$main::/etc/sgml.catalog";
@ -372,6 +373,8 @@ sub process_file
}
}
#
local $ENV{PATH} = "$ENV{PATH}:/usr/lib/linuxdoc-tools";
my($precmd) = "|sgmlpre output=$global->{format} $global->{define}";
#

View File

@ -8,11 +8,13 @@ srcdir=$(shell cd $(root-rel) ; pwd)
srcdir_abs=$(srcdir)
endif
export TEXINPUTS := $(TEXINPUTS):$(srcdir_abs)/doc/tex
# Force rebuilds
.PHONY: prog.sgml bird.sgml
docs: progdocs userdocs
progdocs: prog.html prog.ps
progdocs: prog.html prog.pdf
userdocs: bird.html bird.pdf
prog.sgml:

View File

@ -594,19 +594,28 @@ agreement").
<tag><label id="proto-description">description "<m/text/"</tag>
This is an optional description of the protocol. It is displayed as a
part of the output of 'show route all' command.
part of the output of 'show protocols all' command.
<tag><label id="proto-table">table <m/name/</tag>
Connect this protocol to a non-default routing table.
<tag><label id="proto-vrf">vrf "<m/text/"</tag>
<tag><label id="proto-vrf">vrf "<m/text/"|default</tag>
Associate the protocol with specific VRF. The protocol will be
restricted to interfaces assigned to the VRF and will use sockets bound
to the VRF. Appropriate VRF interface must exist on OS level. For kernel
protocol, an appropriate table still must be explicitly selected by
<cf/table/ option. Note that the VRF support in BIRD and Linux kernel
(4.11) is still in development and is currently problematic outside of
multihop BGP.
to the VRF. A corresponding VRF interface must exist on OS level. For
kernel protocol, an appropriate table still must be explicitly selected
by <cf/table/ option.
By selecting <cf/default/, the protocol is associated with the default
VRF; i.e., it will be restricted to interfaces not assigned to any
regular VRF. That is different from not specifying <cf/vrf/ at all, in
which case the protocol may use any interface regardless of its VRF
status.
Note that for proper VRF support it is necessary to use Linux kernel
version at least 4.14, older versions have limited VRF implementation.
Before Linux kernel 5.0, a socket bound to a port in default VRF collide
with others in regular VRFs.
</descrip>
<p>There are several options that give sense only with certain protocols:
@ -837,6 +846,10 @@ This argument can be omitted if there exists only a single instance.
number of networks, number of routes before and after filtering). If
you use <cf/count/ instead, only the statistics will be printed.
<tag><label id="cli-mrt-dump">mrt dump table <m/name/|"<m/pattern/" to "<m/filename/" [filter <m/f/|where <m/c/]</tag>
Dump content of a routing table to a specified file in MRT table dump
format. See <ref id="mrt" name="MRT protocol"> for details.
<tag><label id="cli-show-roa">show roa [<m/prefix/ | in <m/prefix/ | for <m/prefix/] [as <m/num/] [table <m/t/]</tag>
Show contents of a ROA table (by default of the first one). You can
specify a <m/prefix/ to print ROA entries for a specific network. If you
@ -1405,7 +1418,8 @@ clist for most purposes.
<tag><label id="rta-ifname"><m/string/ ifname</tag>
Name of the outgoing interface. Sink routes (like blackhole, unreachable
or prohibit) and multipath routes have no interface associated with
them, so <cf/ifname/ returns an empty string for such routes. Read-only.
them, so <cf/ifname/ returns an empty string for such routes. Setting it
would also change route to a direct one (remove gateway).
<tag><label id="rta-ifindex"><m/int/ ifindex</tag>
Index of the outgoing interface. System wide index of the interface. May
@ -1619,7 +1633,7 @@ in the future. Also note that we currently support at most one protocol instance
<p>BFD packets are sent with a dynamic source port number. Linux systems use by
default a bit different dynamic port range than the IANA approved one
(49152-65535). If you experience problems with compatibility, please adjust
<cf>/proc/sys/net/ipv4/ip_local_port_range</cf>
<cf>/proc/sys/net/ipv4/ip_local_port_range</cf>.
<sect1>Configuration
<label id="bfd-config">
@ -1636,6 +1650,14 @@ configuration is often sufficient.
<p>Note that to use BFD for other protocols like OSPF or BGP, these protocols
also have to be configured to request BFD sessions, usually by <cf/bfd/ option.
<p>A BFD instance not associated with any VRF handles session requests from all
other protocols, even ones associated with a VRF. Such setup would work for
single-hop BFD sessions if <cf/net.ipv4.udp_l3mdev_accept/ sysctl is enabled,
but does not currently work for multihop sessions. Another approach is to
configure multiple BFD instances, one for each VRF (including the default VRF).
Each BFD instance associated with a VRF (regular or default) only handles
session requests from protocols in the same VRF.
<p>Some of BFD session options require <m/time/ value, which has to be specified
with the appropriate unit: <m/num/ <cf/s/|<cf/ms/|<cf/us/. Although microseconds
are allowed as units, practical minimum values are usually in order of tens of
@ -1977,13 +1999,16 @@ using the following configuration parameters:
immediately shut down. Note that this option cannot be used with
multihop BGP. Default: disabled.
<tag><label id="bgp-bfd">bfd <M>switch</M></tag>
<tag><label id="bgp-bfd">bfd <M>switch</M>|graceful</tag>
BGP could use BFD protocol as an advisory mechanism for neighbor
liveness and failure detection. If enabled, BIRD setups a BFD session
for the BGP neighbor and tracks its liveness by it. This has an
advantage of an order of magnitude lower detection times in case of
failure. Note that BFD protocol also has to be configured, see
<ref id="bfd" name="BFD"> section for details. Default: disabled.
failure. When a neighbor failure is detected, the BGP session is
restarted. Optionally, it can be configured (by <cf/graceful/ argument)
to trigger graceful restart instead of regular restart. Note that BFD
protocol also has to be configured, see <ref id="bfd" name="BFD">
section for details. Default: disabled.
<tag><label id="bgp-ttl-security">ttl security <m/switch/</tag>
Use GTSM (<rfc id="5082"> - the generalized TTL security mechanism). GTSM
@ -2108,6 +2133,25 @@ using the following configuration parameters:
re-establish after a restart before deleting stale routes. Default:
120 seconds.
<tag><label id="bgp-long-lived-graceful-restart">long lived graceful restart <m/switch/|aware</tag>
The long-lived graceful restart is an extension of the traditional
<ref id="bgp-graceful-restart" name="BGP graceful restart">, where stale
routes are kept even after the <ref id="bgp-graceful-restart-time"
name="restart time"> expires for additional long-lived stale time, but
they are marked with the LLGR_STALE community, depreferenced, and
withdrawn from routers not supporting LLGR. Like traditional BGP
graceful restart, it has three states: disabled, aware (receiving-only),
and enabled. Note that long-lived graceful restart requires at least
aware level of traditional BGP graceful restart. Default: aware, unless
graceful restart is disabled.
<tag><label id="bgp-long-lived-stale-time">long lived stale time <m/number/</tag>
The long-lived stale time is announced in the BGP long-lived graceful
restart capability and specifies how long the neighbor would keep stale
routes depreferenced during long-lived graceful restart until either the
session is re-stablished and synchronized or the stale time expires and
routes are removed. Default: 3600 seconds.
<tag><label id="bgp-interpret-communities">interpret communities <m/switch/</tag>
<rfc id="1997"> demands that BGP speaker should process well-known
communities like no-export (65535, 65281) or no-advertise (65535,
@ -2159,6 +2203,19 @@ using the following configuration parameters:
disable the instance automatically and wait for an administrator to fix
the problem manually. Default: off.
<tag><label id="bgp-disable-after-cease">disable after cease <m/switch/|<m/set-of-flags/</tag>
When a Cease notification is received, disable the instance
automatically and wait for an administrator to fix the problem manually.
When used with <m/switch/ argument, it means handle every Cease subtype
with the exception of <cf/connection collision/. Default: off.
The <m/set-of-flags/ allows to narrow down relevant Cease subtypes. The
syntax is <cf>{<m/flag/ [, <m/.../] }</cf>, where flags are: <cf/cease/,
<cf/prefix limit hit/, <cf/administrative shutdown/,
<cf/peer deconfigured/, <cf/administrative reset/,
<cf/connection rejected/, <cf/configuration change/,
<cf/connection collision/, <cf/out of resources/.
<tag><label id="bgp-hold-time">hold time <m/number/</tag>
Time in seconds to wait for a Keepalive message from the other side
before considering the connection stale. Default: depends on agreement
@ -2249,17 +2306,17 @@ using the following configuration parameters:
some of them (marked with `<tt/O/') are optional.
<descrip>
<tag><label id="rta-bgp-path">bgppath bgp_path/</tag>
<tag><label id="rta-bgp-path">bgppath bgp_path</tag>
Sequence of AS numbers describing the AS path the packet will travel
through when forwarded according to the particular route. In case of
internal BGP it doesn't contain the number of the local AS.
<tag><label id="rta-bgp-local-pref">int bgp_local_pref/ [I]</tag>
<tag><label id="rta-bgp-local-pref">int bgp_local_pref [I]</tag>
Local preference value used for selection among multiple BGP routes (see
the selection rules above). It's used as an additional metric which is
propagated through the whole local AS.
<tag><label id="rta-bgp-med">int bgp_med/ [O]</tag>
<tag><label id="rta-bgp-med">int bgp_med [O]</tag>
The Multiple Exit Discriminator of the route is an optional attribute
which is used on external (inter-AS) links to convey to an adjacent AS
the optimal entry point into the local AS. The received attribute is
@ -2270,20 +2327,20 @@ some of them (marked with `<tt/O/') are optional.
external BGP instance. See <rfc id="4451"> for further discussion of
BGP MED attribute.
<tag><label id="rta-bgp-origin">enum bgp_origin/</tag>
<tag><label id="rta-bgp-origin">enum bgp_origin</tag>
Origin of the route: either <cf/ORIGIN_IGP/ if the route has originated
in an interior routing protocol or <cf/ORIGIN_EGP/ if it's been imported
from the <tt>EGP</tt> protocol (nowadays it seems to be obsolete) or
<cf/ORIGIN_INCOMPLETE/ if the origin is unknown.
<tag><label id="rta-bgp-next-hop">ip bgp_next_hop/</tag>
<tag><label id="rta-bgp-next-hop">ip bgp_next_hop</tag>
Next hop to be used for forwarding of packets to this destination. On
internal BGP connections, it's an address of the originating router if
it's inside the local AS or a boundary router the packet will leave the
AS through if it's an exterior route, so each BGP speaker within the AS
has a chance to use the shortest interior path possible to this point.
<tag><label id="rta-bgp-atomic-aggr">void bgp_atomic_aggr/ [O]</tag>
<tag><label id="rta-bgp-atomic-aggr">void bgp_atomic_aggr [O]</tag>
This is an optional attribute which carries no value, but the sole
presence of which indicates that the route has been aggregated from
multiple routes by some router on the path from the originator.
@ -2291,7 +2348,7 @@ some of them (marked with `<tt/O/') are optional.
<!-- we don't handle aggregators right since they are of a very obscure type
<tag>bgp_aggregator</tag>
-->
<tag><label id="rta-bgp-community">clist bgp_community/ [O]</tag>
<tag><label id="rta-bgp-community">clist bgp_community [O]</tag>
List of community values associated with the route. Each such value is a
pair (represented as a <cf/pair/ data type inside the filters) of 16-bit
integers, the first of them containing the number of the AS which
@ -2302,14 +2359,14 @@ some of them (marked with `<tt/O/') are optional.
freedom about which community attributes it defines and what will their
semantics be.
<tag><label id="rta-bgp-ext-community">eclist bgp_ext_community/ [O]</tag>
<tag><label id="rta-bgp-ext-community">eclist bgp_ext_community [O]</tag>
List of extended community values associated with the route. Extended
communities have similar usage as plain communities, but they have an
extended range (to allow 4B ASNs) and a nontrivial structure with a type
field. Individual community values are represented using an <cf/ec/ data
type inside the filters.
<tag><label id="rta-bgp-large-community">lclist <cf/bgp_large_community/ [O]</tag>
<tag><label id="rta-bgp-large-community">lclist bgp_large_community [O]</tag>
List of large community values associated with the route. Large BGP
communities is another variant of communities, but contrary to extended
communities they behave very much the same way as regular communities,
@ -2317,12 +2374,12 @@ some of them (marked with `<tt/O/') are optional.
Individual community values are represented using an <cf/lc/ data type
inside the filters.
<tag><label id="rta-bgp-originator-id">quad bgp_originator_id/ [I, O]</tag>
<tag><label id="rta-bgp-originator-id">quad bgp_originator_id [I, O]</tag>
This attribute is created by the route reflector when reflecting the
route and contains the router ID of the originator of the route in the
local AS.
<tag><label id="rta-bgp-cluster-list">clist bgp_cluster_list/ [I, O]</tag>
<tag><label id="rta-bgp-cluster-list">clist bgp_cluster_list [I, O]</tag>
This attribute contains a list of cluster IDs of route reflectors. Each
route reflector prepends its cluster ID when reflecting the route.
</descrip>
@ -2557,26 +2614,26 @@ translated to appropriate system (and OS-specific) route attributes. We support
these attributes:
<descrip>
<tag><label id="rta-krt-source">int krt_source/</tag>
<tag><label id="rta-krt-source">int krt_source</tag>
The original source of the imported kernel route. The value is
system-dependent. On Linux, it is a value of the protocol field of the
route. See /etc/iproute2/rt_protos for common values. On BSD, it is
based on STATIC and PROTOx flags. The attribute is read-only.
<tag><label id="rta-krt-metric">int krt_metric/</tag> (Linux)
<tag><label id="rta-krt-metric">int krt_metric</tag> (Linux)
The kernel metric of the route. When multiple same routes are in a
kernel routing table, the Linux kernel chooses one with lower metric.
Note that preferred way to set kernel metric is to use protocol option
<cf/metric/, unless per-route metric values are needed.
<tag><label id="rta-krt-prefsrc">ip krt_prefsrc/</tag> (Linux)
<tag><label id="rta-krt-prefsrc">ip krt_prefsrc</tag> (Linux)
The preferred source address. Used in source address selection for
outgoing packets. Has to be one of the IP addresses of the router.
<tag><label id="rta-krt-realm">int krt_realm/</tag> (Linux)
<tag><label id="rta-krt-realm">int krt_realm</tag> (Linux)
The realm of the route. Can be used for traffic classification.
<tag><label id="rta-krt-scope">int krt_scope/</tag> (Linux IPv4)
<tag><label id="rta-krt-scope">int krt_scope</tag> (Linux IPv4)
The scope of the route. Valid values are 0-254, although Linux kernel
may reject some values depending on route type and nexthop. It is
supposed to represent `indirectness' of the route, where nexthops of
@ -2630,6 +2687,81 @@ protocol kernel { # Secondary routing table
</code>
<sect>MRT
<label id="mrt">
<sect1>Introduction
<label id="mrt-intro">
<p>The MRT protocol is a component responsible for handling the Multi-Threaded
Routing Toolkit (MRT) routing information export format, which is mainly used
for collecting and analyzing of routing information from BGP routers. The MRT
protocol can be configured to do periodic dumps of routing tables, created MRT
files can be analyzed later by other tools. Independent MRT table dumps can also
be requested from BIRD client. There is also a feature to save incoming BGP
messages in MRT files, but it is controlled by <ref id="proto-mrtdump"
name="mrtdump"> options independently of MRT protocol, although that might
change in the future.
BIRD implements the main MRT format specification as defined in <rfc id="6396">
and the ADD_PATH extension (<rfc id="8050">).
<sect1>Configuration
<label id="mrt-config">
<p>MRT configuration consists of several statements describing routing table
dumps. Multiple independent periodic dumps can be done as multiple MRT protocol
instances. There are two mandatory statements: <cf/filename/ and <cf/period/.
The behavior can be modified by following configuration parameters:
<descrip>
<tag><label id="mrt-table">table <m/name/ | "<m/pattern/"</tag>
Specify a routing table (or a set of routing tables described by a
wildcard pattern) that are to be dumped by the MRT protocol instance.
Default: the master table.
<tag><label id="mrt-filter">filter { <m/filter commands/ }</tag>
The MRT protocol allows to specify a filter that is applied to routes as
they are dumped. Rejected routes are ignored and not saved to the MRT
dump file. Default: no filter.
<tag><label id="mrt-where">where <m/filter expression/</tag>
An alternative way to specify a filter for the MRT protocol.
<tag><label id="mrt-filename">filename "<m/filename/"</tag>
Specify a filename for MRT dump files. The filename may contain time
format sequences with <it/strftime(3)/ notation (see <it/man strftime/
for details), there is also a sequence "%N" that is expanded to the name
of dumped table. Therefore, each periodic dump of each table can be
saved to a different file. Mandatory, see example below.
<tag><label id="mrt-period">period <m/number/</tag>
Specify the time interval (in seconds) between periodic dumps.
Mandatory.
<tag><label id="mrt-always-add-path">always add path <m/switch/</tag>
The MRT format uses special records (specified in <rfc id="8050">) for
routes received using BGP ADD_PATH extension to keep Path ID, while
other routes use regular records. This has advantage of better
compatibility with tools that do not know special records, but it loses
information about which route is the best route. When this option is
enabled, both ADD_PATH and non-ADD_PATH routes are stored in ADD_PATH
records and order of routes for network is preserved. Default: disabled.
</descrip>
<sect1>Example
<label id="mrt-exam">
<p><code>
protocol mrt {
table "tab*";
where source = RTS_BGP;
filename "/var/log/bird/%N_%F_%T.mrt";
period 300;
}
</code>
<sect>OSPF
<label id="ospf">
@ -2936,6 +3068,11 @@ protocol ospf &lt;name&gt; {
Specifies interval in seconds between retransmissions of unacknowledged
updates. Default value is 5.
<tag><label id="ospf-transmit-delay">transmit delay <M>num</M></tag>
Specifies estimated transmission delay of link state updates send over
the interface. The value is added to LSA age of LSAs propagated through
it. Default value is 1.
<tag><label id="ospf-priority">priority <M>num</M></tag>
On every multiple access network (e.g., the Ethernet) Designated Router
and Backup Designated router are elected. These routers have some special
@ -3386,7 +3523,7 @@ definitions, prefix definitions and DNS definitions:
RAdv protocol could be configured to change its behavior based on
availability of routes. When this option is used, the protocol waits in
suppressed state until a <it/trigger route/ (for the specified network)
is exported to the protocol, the protocol also returnsd to suppressed
is exported to the protocol, the protocol also returns to suppressed
state if the <it/trigger route/ disappears. Note that route export
depends on specified export filter, as usual. This option could be used,
e.g., for handling failover in multihoming scenarios.
@ -3580,13 +3717,13 @@ definitions, prefix definitions and DNS definitions:
<p>RAdv defines two route attributes:
<descrip>
<tag><label id="rta-ra-preference">enum ra_preference/</tag>
<tag><label id="rta-ra-preference">enum ra_preference</tag>
The preference of the route. The value can be <it/RA_PREF_LOW/,
<it/RA_PREF_MEDIUM/ or <it/RA_PREF_HIGH/. If the attribute is not set,
the <ref id="radv-iface-route-preference" name="route preference">
option is used.
<tag><label id="rta-ra-lifetime">int ra_lifetime/</tag>
<tag><label id="rta-ra-lifetime">int ra_lifetime</tag>
The advertised lifetime of the route, in seconds. The special value of
0xffffffff represents infinity. If the attribute is not set, the
<ref id="radv-iface-route-lifetime" name="route lifetime">
@ -3888,13 +4025,13 @@ protocol rip [&lt;name&gt;] {
<p>RIP defines two route attributes:
<descrip>
<tag><label id="rta-rip-metric">int rip_metric/</tag>
<tag><label id="rta-rip-metric">int rip_metric</tag>
RIP metric of the route (ranging from 0 to <cf/infinity/). When routes
from different RIP instances are available and all of them have the same
preference, BIRD prefers the route with lowest <cf/rip_metric/. When a
non-RIP route is exported to RIP, the default metric is 1.
<tag><label id="rta-rip-tag">int rip_tag/</tag>
<tag><label id="rta-rip-tag">int rip_tag</tag>
RIP route tag: a 16-bit number which can be used to carry additional
information with the route (for example, an originating AS number in
case of external routes). When a non-RIP route is exported to RIP, the

9
doc/prog-root Normal file
View File

@ -0,0 +1,9 @@
D doc/prog-head.sgml
D doc/prog-intro.sgml
C nest
C conf
C filter
C proto
C sysdep
C lib
D doc/prog-foot.sgml

View File

@ -34,7 +34,12 @@ $progs = {
"GROFFMACRO" => "-ms",
"AWK" => "/usr/share/linuxdoc-tools/awkwhich"
};
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog";
if (! -x $progs->{"NSGMLS"})
{ $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
(defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
require "$FindBin::Bin/LinuxDocTools.pm";
&LinuxDocTools::init;

View File

@ -34,7 +34,12 @@ $progs = {
"GROFFMACRO" => "-ms",
"AWK" => "/usr/share/linuxdoc-tools/awkwhich"
};
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog";
if (! -x $progs->{"NSGMLS"})
{ $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
(defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
require "$FindBin::Bin/LinuxDocTools.pm";
&LinuxDocTools::init;

View File

@ -34,7 +34,12 @@ $progs = {
"GROFFMACRO" => "-ms",
"AWK" => "/usr/share/linuxdoc-tools/awkwhich"
};
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog";
if (! -x $progs->{"NSGMLS"})
{ $progs->{"NSGMLS"} = "/usr/bin/onsgmls"; }
$ENV{"SGML_CATALOG_FILES"} = "$DataDir/dtd/catalog" .
(defined $ENV{SGML_CATALOG_FILES} ? ":$ENV{SGML_CATALOG_FILES}" : "");
require "$FindBin::Bin/LinuxDocTools.pm";
&LinuxDocTools::init;

View File

@ -320,7 +320,8 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
static inline struct f_inst *
f_generate_path_mask(struct f_path_mask *t)
{
for (struct f_path_mask *tt = t; tt; tt = tt->next) {
struct f_path_mask *tt;
for (tt = t; tt; tt = tt->next) {
if (tt->kind == PM_ASN_EXPR) {
struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
mrv->a1.p = t;
@ -791,7 +792,7 @@ static_attr:
| SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
| CAST { $$ = f_new_static_attr(T_ENUM_RTC, SA_CAST, 0); }
| DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 1); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
;

View File

@ -1000,6 +1000,20 @@ interpret(struct f_inst *what)
rta->hostentry = NULL;
break;
case SA_IFNAME:
{
struct iface *ifa = if_find_by_name(v1.val.s);
if (!ifa)
runtime( "Invalid iface name" );
rta->dest = RTD_DEVICE;
rta->gw = IPA_NONE;
rta->iface = ifa;
rta->nexthops = NULL;
rta->hostentry = NULL;
}
break;
default:
bug("Invalid static attribute access (%x)", res.type);
}
@ -1513,7 +1527,7 @@ interpret(struct f_inst *what)
/* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
eattr *e = ea_find((*f_rte)->attrs->eattrs, EA_CODE(EAP_BGP, 0x02));
if (!e || e->type != EAF_TYPE_AS_PATH)
if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
runtime("Missing AS_PATH attribute");
as_path_get_last(e->u.ptr, &as);

View File

@ -36,5 +36,14 @@ ev_active(event *e)
return e->n.next != NULL;
}
static inline event*
ev_new_set(pool *p, void (*hook)(void *), void *data)
{
event *e = ev_new(p);
e->hook = hook;
e->data = data;
return e;
}
#endif

View File

@ -67,7 +67,7 @@ typedef struct ip4_addr {
typedef u32 ip4_addr;
#define _MI4(x) (x)
#define _MI4(x) ((u32) (x))
#define _I(x) (x)
#endif
@ -99,6 +99,7 @@ typedef ip6_addr ip_addr;
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
#define ipa_is_ip4(a) ip6_is_v4mapped(a)
#define ipa_is_ip6(a) (! ip6_is_v4mapped(a))
#else
@ -115,6 +116,7 @@ typedef ip4_addr ip_addr;
#define ipa_to_u32(x) ip4_to_u32(ipa_to_ip4(x))
#define ipa_is_ip4(a) 1
#define ipa_is_ip6(a) 0
#endif
@ -309,6 +311,9 @@ static inline int ip6_is_v4mapped(ip6_addr a)
#define ipa_is_link_local(x) 0
#endif
static inline int ip4_is_unicast(ip4_addr a)
{ return _I(a) < 0xe0000000; }
static inline int ipa_classify_net(ip_addr a)
{ return ipa_zero2(a) ? (IADDR_HOST | SCOPE_UNIVERSE) : ipa_classify(a); }

View File

@ -314,14 +314,14 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
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));
(uint) ((X >> 56) & 0xff),
(uint) ((X >> 48) & 0xff),
(uint) ((X >> 40) & 0xff),
(uint) ((X >> 32) & 0xff),
(uint) ((X >> 24) & 0xff),
(uint) ((X >> 16) & 0xff),
(uint) ((X >> 8) & 0xff),
(uint) (X & 0xff));
}
else
{
@ -342,6 +342,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
case 'X':
flags |= LARGE;
/* fallthrough */
case 'x':
base = 16;
break;

View File

@ -44,6 +44,12 @@ get_u64(const void *p)
return (((u64) ntohl(xh)) << 32) | ntohl(xl);
}
static inline void
put_u8(void *p, u8 x)
{
memcpy(p, &x, 1);
}
static inline void
put_u16(void *p, u16 x)
{

View File

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

View File

@ -19,6 +19,7 @@ struct bfd_request {
ip_addr addr;
ip_addr local;
struct iface *iface;
struct iface *vrf;
void (*hook)(struct bfd_request *);
void *data;
@ -40,13 +41,13 @@ struct bfd_request {
#ifdef CONFIG_BFD
struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data);
struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data);
static inline void cf_check_bfd(int use UNUSED) { }
#else
static inline struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data) { return NULL; }
static inline struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data) { return NULL; }
static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); }

View File

@ -55,7 +55,7 @@ get_passwords(void)
CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
@ -227,7 +227,8 @@ proto_item:
| IMPORT LIMIT limit_spec { this_proto->in_limit = $3; }
| EXPORT LIMIT limit_spec { this_proto->out_limit = $3; }
| IMPORT KEEP FILTERED bool { this_proto->in_keep_filtered = $4; }
| VRF text { this_proto->vrf = if_get_by_name($2); }
| VRF text { this_proto->vrf = if_get_by_name($2); this_proto->vrf_set = 1; }
| VRF DEFAULT { this_proto->vrf = NULL; this_proto->vrf_set = 1; }
| TABLE rtable { this_proto->table = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; }

View File

@ -140,7 +140,7 @@ if_copy(struct iface *to, struct iface *from)
static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{
if (p->ifa_notify && (!p->vrf || p->vrf == a->iface->master))
if (p->ifa_notify && (!p->vrf_set || p->vrf == a->iface->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s <%s address %I/%d on interface %s %s",
@ -177,7 +177,7 @@ ifa_notify_change(unsigned c, struct ifa *a)
static inline void
if_send_notify(struct proto *p, unsigned c, struct iface *i)
{
if (p->if_notify && (!p->vrf || p->vrf == i->master))
if (p->if_notify && (!p->vrf_set || p->vrf == i->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name,
@ -441,7 +441,7 @@ if_find_by_name(char *name)
struct iface *i;
WALK_LIST(i, iface_list)
if (!strcmp(i->name, name))
if (!strcmp(i->name, name) && !(i->flags & IF_SHUTDOWN))
return i;
return NULL;
}
@ -451,8 +451,9 @@ if_get_by_name(char *name)
{
struct iface *i;
if (i = if_find_by_name(name))
return i;
WALK_LIST(i, iface_list)
if (!strcmp(i->name, name))
return i;
/* No active iface, create a dummy */
i = mb_allocz(if_pool, sizeof(struct iface));
@ -469,10 +470,24 @@ struct ifa *kif_choose_primary(struct iface *i);
static int
ifa_recalc_primary(struct iface *i)
{
struct ifa *a = kif_choose_primary(i);
struct ifa *a;
int c = 0;
#ifdef IPV6
struct ifa *ll = NULL;
WALK_LIST(a, i->addrs)
if (ipa_is_link_local(a->ip) && (!ll || (a == i->llv6)))
ll = a;
c = (ll != i->llv6);
i->llv6 = ll;
#endif
a = kif_choose_primary(i);
if (a == i->addr)
return 0;
return c;
if (i->addr)
i->addr->flags &= ~IA_PRIMARY;
@ -576,7 +591,7 @@ ifa_delete(struct ifa *a)
b->flags &= ~IF_UP;
ifa_notify_change(IF_CHANGE_DOWN, b);
}
if (b->flags & IA_PRIMARY)
if ((b->flags & IA_PRIMARY) || (b == ifa_llv6(i)))
{
if_change_flags(i, i->flags | IF_TMP_DOWN);
ifa_recalc_primary(i);
@ -812,6 +827,9 @@ if_show_summary(void)
cli_msg(-2005, "interface state address");
WALK_LIST(i, iface_list)
{
if (i->flags & IF_SHUTDOWN)
continue;
if (i->addr)
bsprintf(addr, "%I/%d", i->addr->ip, i->addr->pxlen);
else

View File

@ -37,6 +37,9 @@ struct iface {
unsigned master_index; /* Interface index of master iface */
list addrs; /* Addresses assigned to this interface */
struct ifa *addr; /* Primary address */
#ifdef IPV6
struct ifa *llv6; /* Selected IPv6 link-local address */
#endif
struct iface *master; /* Master iface (e.g. for VRF) */
list neighbors; /* All neighbors on this interface */
};
@ -103,6 +106,16 @@ struct iface *if_find_by_name(char *);
struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void);
static inline struct ifa *
ifa_llv6(struct iface *i UNUSED4)
{
#ifdef IPV6
return i->llv6;
#else
return NULL;
#endif
}
/* The Neighbor Cache */

View File

@ -1,31 +0,0 @@
/*
* BIRD -- MRTdump handling
*
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef MRTDUMP_H
#define MRTDUMP_H
#include "nest/protocol.h"
/* MRTDump values */
#define MRTDUMP_HDR_LENGTH 12
/* MRTdump types */
#define BGP4MP 16
/* MRTdump subtypes */
#define BGP4MP_MESSAGE 1
#define BGP4MP_MESSAGE_AS4 4
#define BGP4MP_STATE_CHANGE_AS4 5
/* implemented in sysdep */
void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
#endif

View File

@ -153,7 +153,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
}
else
WALK_LIST(i, iface_list)
if ((!p->vrf || p->vrf == i->master) &&
if ((!p->vrf_set || p->vrf == i->master) &&
((scope = if_connected(a, i, &addr)) >= 0))
{
ifa = i;

View File

@ -387,6 +387,7 @@ proto_init(struct proto_config *c)
q->export_state = ES_DOWN;
q->last_state_change = now;
q->vrf = c->vrf;
q->vrf_set = c->vrf_set;
add_tail(&initial_proto_list, &q->n);
@ -411,6 +412,7 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if ((nc->protocol != oc->protocol) ||
(nc->disabled != p->disabled) ||
(nc->vrf != oc->vrf) ||
(nc->vrf_set != oc->vrf_set) ||
(nc->table->table != oc->table->table))
return 0;
@ -433,10 +435,17 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if (p->proto->multitable)
return 1;
int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
/* We treat a change in preferences by reimporting routes */
if (nc->preference != oc->preference)
import_changed = 1;
/* Update filters and limits in the main announce hook
Note that this also resets limit state */
if (p->main_ahook)
{
{
struct announce_hook *ah = p->main_ahook;
ah->in_filter = nc->in_filter;
ah->out_filter = nc->out_filter;
@ -445,6 +454,9 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
ah->out_limit = nc->out_limit;
ah->in_keep_filtered = nc->in_keep_filtered;
proto_verify_limits(ah);
if (export_changed)
ah->last_out_filter_change = now;
}
/* Update routes when filters changed. If the protocol in not UP,
@ -452,13 +464,6 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
if ((p->proto_state != PS_UP) || (type == RECONFIG_SOFT))
return 1;
int import_changed = ! filter_same(nc->in_filter, oc->in_filter);
int export_changed = ! filter_same(nc->out_filter, oc->out_filter);
/* We treat a change in preferences by reimporting routes */
if (nc->preference != oc->preference)
import_changed = 1;
if (import_changed || export_changed)
log(L_INFO "Reloading protocol %s", p->name);
@ -910,6 +915,9 @@ protos_build(void)
#ifdef CONFIG_STATIC
proto_build(&proto_static);
#endif
#ifdef CONFIG_MRT
proto_build(&proto_mrt);
#endif
#ifdef CONFIG_OSPF
proto_build(&proto_ospf);
#endif
@ -1561,6 +1569,9 @@ proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
if (p->cf->router_id)
cli_msg(-1006, " Router ID: %R", p->cf->router_id);
if (p->vrf_set)
cli_msg(-1006, " VRF: %s", p->vrf ? p->vrf->name : "default");
if (p->proto->show_proto_info)
p->proto->show_proto_info(p);
else

View File

@ -76,7 +76,7 @@ void protos_dump_all(void);
*/
extern struct protocol
proto_device, proto_radv, proto_rip, proto_static,
proto_device, proto_radv, proto_rip, proto_static, proto_mrt,
proto_ospf, proto_pipe, proto_bgp, proto_bfd, proto_babel;
/*
@ -93,6 +93,7 @@ struct proto_config {
int class; /* SYM_PROTO or SYM_TEMPLATE */
u32 debug, mrtdump; /* Debugging bitfields, both use D_* constants */
unsigned preference, disabled; /* Generic parameters */
int vrf_set; /* Related VRF instance (below) is defined */
int in_keep_filtered; /* Routes rejected in import filter are kept */
u32 router_id; /* Protocol specific router ID */
struct iface *vrf; /* Related VRF instance, NULL if global */
@ -149,6 +150,7 @@ struct proto {
unsigned preference; /* Default route preference */
byte accept_ra_types; /* Which types of route announcements are accepted (RA_OPTIMAL or RA_ANY) */
byte disabled; /* Manually disabled */
byte vrf_set; /* Related VRF instance (above) is defined */
byte proto_state; /* Protocol state machine (PS_*, see below) */
byte core_state; /* Core state machine (FS_*, see below) */
byte export_state; /* Route export state (ES_*, see below) */
@ -213,6 +215,7 @@ struct proto {
int (*rte_better)(struct rte *, struct rte *);
int (*rte_same)(struct rte *, struct rte *);
int (*rte_mergable)(struct rte *, struct rte *);
struct rte * (*rte_modify)(struct rte *, struct linpool *);
void (*rte_insert)(struct network *, struct rte *);
void (*rte_remove)(struct network *, struct rte *);
@ -471,6 +474,7 @@ struct announce_hook {
struct proto_stats *stats; /* Per-table protocol statistics */
struct announce_hook *next; /* Next hook for the same protocol */
int in_keep_filtered; /* Routes rejected in import filter are kept */
bird_clock_t last_out_filter_change; /* Last time when out_filter _changed_ */
};
struct announce_hook *proto_add_announce_hook(struct proto *p, struct rtable *t, struct proto_stats *stats);

View File

@ -219,6 +219,7 @@ typedef struct rte {
#ifdef CONFIG_BGP
struct {
u8 suppressed; /* Used for deterministic MED comparison */
s8 stale; /* Route is LLGR_STALE, -1 if unknown */
} bgp;
#endif
#ifdef CONFIG_BABEL
@ -241,6 +242,7 @@ typedef struct rte {
#define REF_FILTERED 2 /* Route is rejected by import filter */
#define REF_STALE 4 /* Route is stale in a refresh cycle */
#define REF_DISCARD 8 /* Route is scheduled for discard */
#define REF_MODIFY 16 /* Route is scheduled for modify */
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); }
@ -261,6 +263,7 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
#define RIC_REJECT -1 /* Rejected by protocol */
#define RIC_DROP -2 /* Silently dropped by protocol */
extern list routing_tables;
struct config;
void rt_init(void);
@ -279,6 +282,7 @@ int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct fil
rte *rt_export_merged(struct announce_hook *ah, net *net, rte **rt_free, struct ea_list **tmpa, linpool *pool, int silent);
void rt_refresh_begin(rtable *t, struct announce_hook *ah);
void rt_refresh_end(rtable *t, struct announce_hook *ah);
void rt_modify_stale(rtable *t, struct announce_hook *ah);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);

View File

@ -1251,7 +1251,7 @@ void
rta_show(struct cli *c, rta *a, ea_list *eal)
{
static char *src_names[] = { "dummy", "static", "inherit", "device", "static-device", "redirect",
"RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe" };
"RIP", "OSPF", "OSPF-IA", "OSPF-E1", "OSPF-E2", "BGP", "pipe", "babel" };
static char *cast_names[] = { "unicast", "broadcast", "multicast", "anycast" };
int i;

View File

@ -48,7 +48,7 @@ pool *rt_table_pool;
static slab *rte_slab;
static linpool *rte_update_pool;
static list routing_tables;
list routing_tables;
static byte *rt_format_via(rte *e);
static void rt_free_hostcache(rtable *tab);
@ -426,7 +426,8 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
* reconfiguration and the end of refeed - if a newly filtered
* route disappears during this period, proper withdraw is not
* sent (because old would be also filtered) and the route is
* not refeeded (because it disappeared before that).
* not refeeded (because it disappeared before that). This is
* handled below as a special case.
*/
if (new)
@ -439,19 +440,34 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
{
/*
* As mentioned above, 'old' value may be incorrect in some race conditions.
* We generally ignore it with the exception of withdraw to pipe protocol.
* In that case we rather propagate unfiltered withdraws regardless of
* export filters to ensure that when a protocol is flushed, its routes are
* removed from all tables. Possible spurious unfiltered withdraws are not
* problem here as they are ignored if there is no corresponding route at
* the other end of the pipe. We directly call rt_notify() hook instead of
* We generally ignore it with two exceptions:
*
* First, withdraw to pipe protocol. In that case we rather propagate
* unfiltered withdraws regardless of export filters to ensure that when a
* protocol is flushed, its routes are removed from all tables. Possible
* spurious unfiltered withdraws are not problem here as they are ignored if
* there is no corresponding route at the other end of the pipe.
*
* Second, recent filter change. If old route is older than filter change,
* then it was previously evaluated by a different filter and we do not know
* whether it was really propagated. In that case we rather send spurious
* withdraw than do nothing and possibly cause phantom routes.
*
* In both cases wqe directly call rt_notify() hook instead of
* do_rt_notify() to avoid logging and stat counters.
*/
int pipe_withdraw = 0, filter_change = 0;
#ifdef CONFIG_PIPE
if ((p->proto == &proto_pipe) && !new0 && (p != old0->sender->proto))
p->rt_notify(p, ah->table, net, NULL, old0, NULL);
pipe_withdraw = (p->proto == &proto_pipe) && !new0;
#endif
filter_change = old0 && (old0->lastmod <= ah->last_out_filter_change);
if ((pipe_withdraw || filter_change) && (p != old0->sender->proto))
{
stats->exp_withdraws_accepted++;
p->rt_notify(p, ah->table, net, NULL, old0, NULL);
}
return;
}
@ -468,7 +484,7 @@ rt_notify_basic(struct announce_hook *ah, net *net, rte *new0, rte *old0, int re
static void
rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
{
// struct proto *p = ah->proto;
struct proto *p = ah->proto;
struct proto_stats *stats = ah->stats;
rte *r;
@ -541,8 +557,20 @@ rt_notify_accepted(struct announce_hook *ah, net *net, rte *new_changed, rte *ol
*
* - We found new_best the same as new_changed, therefore it cannot
* be old_best and we have to continue search for old_best.
*
* There is also a hack to ensure consistency in case of changed filters.
* It does not find the proper old_best, just selects a non-NULL route.
*/
/* Hack for changed filters */
if (old_changed &&
(p != old_changed->sender->proto) &&
(old_changed->lastmod <= ah->last_out_filter_change))
{
old_best = old_changed;
goto found;
}
/* First case */
if (old_meet)
if (old_best = export_filter(ah, old_changed, &old_free, NULL, 1))
@ -837,12 +865,13 @@ rte_free_quick(rte *e)
static int
rte_same(rte *x, rte *y)
{
/* rte.flags are not checked, as they are mostly internal to rtable */
return
x->attrs == y->attrs &&
x->flags == y->flags &&
x->pflags == y->pflags &&
x->pref == y->pref &&
(!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y));
(!x->attrs->src->proto->rte_same || x->attrs->src->proto->rte_same(x, y)) &&
rte_is_filtered(x) == rte_is_filtered(y);
}
static inline int rte_is_ok(rte *e) { return e && !rte_is_filtered(e); }
@ -886,7 +915,9 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, struct rte_src *sr
if (new && rte_same(old, new))
{
/* No changes, ignore the new route */
/* No changes, ignore the new route and refresh the old one */
old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
if (!rte_is_filtered(new))
{
@ -1283,6 +1314,28 @@ rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collec
rte_update_unlock();
}
/* Modify existing route by protocol hook, used for long-lived graceful restart */
static inline void
rte_modify(rte *old)
{
rte_update_lock();
rte *new = old->sender->proto->rte_modify(old, rte_update_pool);
if (new != old)
{
if (new)
{
if (!rta_is_cached(new->attrs))
new->attrs = rta_lookup(new->attrs);
new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
}
rte_recalculate(old->sender, old->net, new, old->attrs->src);
}
rte_update_unlock();
}
/* Check rtable for best route to given net whether it would be exported do p */
int
rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter)
@ -1373,6 +1426,29 @@ rt_refresh_end(rtable *t, struct announce_hook *ah)
rt_schedule_prune(t);
}
void
rt_modify_stale(rtable *t, struct announce_hook *ah)
{
int prune = 0;
net *n;
rte *e;
FIB_WALK(&t->fib, fn)
{
n = (net *) fn;
for (e = n->routes; e; e = e->next)
if ((e->sender == ah) && (e->flags & REF_STALE) && !(e->flags & REF_FILTERED))
{
e->flags |= REF_MODIFY;
prune = 1;
}
}
FIB_WALK_END;
if (prune)
rt_schedule_prune(t);
}
/**
* rte_dump - dump a route
@ -1592,6 +1668,7 @@ again:
rescan:
for (e=n->routes; e; e=e->next)
{
if (e->sender->proto->flushing || (e->flags & REF_DISCARD))
{
if (*limit <= 0)
@ -1605,6 +1682,22 @@ again:
goto rescan;
}
if (e->flags & REF_MODIFY)
{
if (*limit <= 0)
{
FIB_ITERATE_PUT(fit, fn);
return 0;
}
rte_modify(e);
(*limit)--;
goto rescan;
}
}
if (!n->routes) /* Orphaned FIB entry */
{
FIB_ITERATE_PUT(fit, fn);

View File

@ -2,6 +2,7 @@ H Protocols
C babel
C bfd
C bgp
C mrt
C ospf
C pipe
C rip

View File

@ -1488,17 +1488,10 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
ifa->cf = ic;
ifa->pool = pool;
ifa->ifname = new->name;
ifa->addr = new->llv6->ip;
add_tail(&p->interfaces, NODE ifa);
struct ifa *addr;
WALK_LIST(addr, new->addrs)
if (ipa_is_link_local(addr->ip))
ifa->addr = addr->ip;
if (ipa_zero(ifa->addr))
log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name);
init_list(&ifa->neigh_list);
ifa->hello_seqno = 1;
@ -1551,6 +1544,10 @@ babel_if_notify(struct proto *P, unsigned flags, struct iface *iface)
if (!(iface->flags & IF_MULTICAST))
return;
/* Ignore ifaces without link-local address */
if (!iface->llv6)
return;
if (ic)
babel_add_iface(p, iface, ic);

View File

@ -1087,6 +1087,7 @@ babel_open_socket(struct babel_iface *ifa)
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
sk->saddr = ifa->addr;
sk->vrf = p->p.vrf;
sk->rx_hook = babel_rx_hook;

View File

@ -624,6 +624,9 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 diag)
static int
bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
{
if (p->p.vrf_set && (p->p.vrf != req->vrf))
return 0;
struct bfd_session *s = bfd_find_session_by_addr(p, req->addr);
u8 state, diag;
@ -685,7 +688,8 @@ bfd_drop_requests(struct bfd_proto *p)
static struct resclass bfd_request_class;
struct bfd_request *
bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface,
bfd_request_session(pool *p, ip_addr addr, ip_addr local,
struct iface *iface, struct iface *vrf,
void (*hook)(struct bfd_request *), void *data)
{
struct bfd_request *req = ralloc(p, &bfd_request_class);
@ -696,6 +700,7 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface,
req->addr = addr;
req->local = local;
req->iface = iface;
req->vrf = vrf;
bfd_submit_request(req);
@ -754,7 +759,7 @@ bfd_neigh_notify(struct neighbor *nb)
if ((nb->scope > 0) && !n->req)
{
ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip;
n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, NULL, NULL);
n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL);
}
if ((nb->scope <= 0) && n->req)
@ -771,7 +776,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n)
if (n->multihop)
{
n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, NULL, NULL);
n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL);
return;
}
@ -1052,15 +1057,6 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
return 1;
}
/* Ensure one instance */
struct bfd_config *bfd_cf;
static void
bfd_preconfig(struct protocol *P UNUSED, struct config *c UNUSED)
{
bfd_cf = NULL;
}
static void
bfd_copy_config(struct proto_config *dest, struct proto_config *src UNUSED)
{
@ -1123,6 +1119,5 @@ struct protocol proto_bfd = {
.start = bfd_start,
.shutdown = bfd_shutdown,
.reconfigure = bfd_reconfigure,
.preconfig = bfd_preconfig,
.copy_config = bfd_copy_config,
};

View File

@ -38,10 +38,6 @@ bfd_proto_start: proto_start BFD
this_proto = proto_config_new(&proto_bfd, $1);
init_list(&BFD_CFG->patt_list);
init_list(&BFD_CFG->neigh_list);
if (bfd_cf)
cf_error("Only one BFD instance allowed");
bfd_cf = BFD_CFG;
};
bfd_proto_item:

View File

@ -141,6 +141,7 @@ bfd_fill_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_c
case BFD_AUTH_METICULOUS_KEYED_MD5:
case BFD_AUTH_METICULOUS_KEYED_SHA1:
meticulous = 1;
/* fallthrough */
case BFD_AUTH_KEYED_MD5:
case BFD_AUTH_KEYED_SHA1:
@ -230,6 +231,7 @@ bfd_check_authentication(struct bfd_proto *p, struct bfd_session *s, struct bfd_
case BFD_AUTH_METICULOUS_KEYED_MD5:
case BFD_AUTH_METICULOUS_KEYED_SHA1:
meticulous = 1;
/* fallthrough */
case BFD_AUTH_KEYED_MD5:
case BFD_AUTH_KEYED_SHA1:
@ -410,6 +412,7 @@ bfd_open_rx_sk(struct bfd_proto *p, int multihop)
sock *sk = sk_new(p->tpool);
sk->type = SK_UDP;
sk->sport = !multihop ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
sk->vrf = p->p.vrf;
sk->data = p;
sk->rbsize = BFD_MAX_LEN;
@ -445,6 +448,7 @@ bfd_open_tx_sk(struct bfd_proto *p, ip_addr local, struct iface *ifa)
sk->saddr = local;
sk->dport = ifa ? BFD_CONTROL_PORT : BFD_MULTI_CTL_PORT;
sk->iface = ifa;
sk->vrf = p->p.vrf;
sk->data = p;
sk->tbsize = BFD_MAX_LEN;

View File

@ -471,7 +471,7 @@ bgp_get_attr_len(eattr *a)
/**
* bgp_encode_attrs - encode BGP attributes
* @p: BGP instance
* @p: BGP instance (or NULL)
* @w: buffer
* @attrs: a list of extended attributes
* @remains: remaining space in the buffer
@ -485,6 +485,7 @@ uint
bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
{
uint i, code, type, flags;
int as4_session = p ? p->as4_session : 1;
byte *start = w;
int len, rv;
@ -504,7 +505,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
* we have to convert our 4B AS_PATH to 2B AS_PATH and send our AS_PATH
* as optional AS4_PATH attribute.
*/
if ((code == BA_AS_PATH) && (! p->as4_session))
if ((code == BA_AS_PATH) && !as4_session)
{
len = a->u.ptr->length;
@ -546,7 +547,7 @@ bgp_encode_attrs(struct bgp_proto *p, byte *w, ea_list *attrs, int remains)
}
/* The same issue with AGGREGATOR attribute */
if ((code == BA_AGGREGATOR) && (! p->as4_session))
if ((code == BA_AGGREGATOR) && !as4_session)
{
int new_used;
@ -923,7 +924,7 @@ bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
#define PXH_FN(p,l,i) ipa_hash32(p) ^ u32_hash((l << 16) ^ i)
#define PXH_REHASH bgp_pxh_rehash
#define PXH_PARAMS /8, *2, 2, 2, 8, 20
#define PXH_PARAMS /8, *2, 2, 2, 8, 24
HASH_DEFINE_REHASH_FN(PXH, struct bgp_prefix)
@ -1173,6 +1174,9 @@ bgp_community_filter(struct bgp_proto *p, rte *e)
DBG("\tNO_EXPORT\n");
return 1;
}
if (!p->conn->peer_llgr_aware && int_set_contains(d, BGP_COMM_LLGR_STALE))
return 1;
}
return 0;
@ -1233,6 +1237,19 @@ rte_resolvable(rte *rt)
return (rd == RTD_ROUTER) || (rd == RTD_DEVICE) || (rd == RTD_MULTIPATH);
}
static inline int
rte_stale(rte *r)
{
if (r->u.bgp.stale < 0)
{
/* If staleness is unknown, compute and cache it */
eattr *a = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY));
r->u.bgp.stale = a && int_set_contains(a->u.ptr, BGP_COMM_LLGR_STALE);
}
return r->u.bgp.stale;
}
int
bgp_rte_better(rte *new, rte *old)
{
@ -1257,6 +1274,14 @@ bgp_rte_better(rte *new, rte *old)
if (n < o)
return 0;
/* LLGR draft - depreference stale routes */
n = rte_stale(new);
o = rte_stale(old);
if (n > o)
return 0;
if (n < o)
return 1;
/* Start with local preferences */
x = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
y = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
@ -1378,6 +1403,10 @@ bgp_rte_mergable(rte *pri, rte *sec)
if (!rte_resolvable(sec))
return 0;
/* LLGR draft - depreference stale routes */
if (rte_stale(pri) != rte_stale(sec))
return 0;
/* Start with local preferences */
x = ea_find(pri->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
y = ea_find(sec->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
@ -1580,6 +1609,27 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
return old_is_group_best;
}
struct rte *
bgp_rte_modify_stale(struct rte *r, struct linpool *pool)
{
eattr *a = ea_find(r->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY));
struct adata *ad = a ? a->u.ptr : NULL;
if (ad && int_set_contains(ad, BGP_COMM_NO_LLGR))
return NULL;
if (ad && int_set_contains(ad, BGP_COMM_LLGR_STALE))
return r;
r = rte_cow_rta(r, pool);
bgp_attach_attr(&(r->attrs->eattrs), pool, BA_COMMUNITY,
(uintptr_t) int_set_add(pool, ad, BGP_COMM_LLGR_STALE));
r->u.bgp.stale = 1;
return r;
}
static struct adata *
bgp_aggregator_convert_to_new(struct adata *old, struct linpool *pool)
{
@ -1589,7 +1639,6 @@ bgp_aggregator_convert_to_new(struct adata *old, struct linpool *pool)
return newa;
}
/* Take last req_as ASNs from path old2 (in 2B format), convert to 4B format
* and append path old4 (in 4B format).
*/
@ -1985,6 +2034,9 @@ bgp_get_route_info(rte *e, byte *buf, ea_list *attrs)
if (e->u.bgp.suppressed)
buf += bsprintf(buf, "-");
if (rte_stale(e))
buf += bsprintf(buf, "s");
if (e->attrs->hostentry)
{
if (!rte_resolvable(e))

View File

@ -352,7 +352,7 @@ static inline void
bgp_conn_set_state(struct bgp_conn *conn, unsigned new_state)
{
if (conn->bgp->p.mrtdump & MD_STATES)
mrt_dump_bgp_state_change(conn, conn->state, new_state);
bgp_dump_state_change(conn, conn->state, new_state);
conn->state = new_state;
}
@ -394,10 +394,17 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
if (p->p.gr_recovery && (p->cf->gr_mode == BGP_GR_ABLE) && peer_gr_ready)
p->p.gr_wait = 1;
if (p->gr_active)
if (p->gr_active == BGP_GRS_ACTIVE)
tm_stop(p->gr_timer);
if (p->gr_active && (!conn->peer_gr_able || !(conn->peer_gr_aflags & BGP_GRF_FORWARDING)))
/* Check F-bit for regular graceful restart */
if ((p->gr_active == BGP_GRS_ACTIVE) &&
(!conn->peer_gr_able || !(conn->peer_gr_aflags & BGP_GRF_FORWARDING)))
bgp_graceful_restart_done(p);
/* Check F-bit for long-lived graceful restart */
if (((p->gr_active == BGP_GRS_LLGR_1) || (p->gr_active == BGP_GRS_LLGR_2)) &&
(!conn->peer_llgr_able || !(conn->peer_llgr_aflags & BGP_LLGRF_FORWARDING)))
bgp_graceful_restart_done(p);
/* GR capability implies that neighbor will send End-of-RIB */
@ -474,11 +481,25 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
p->gr_active ? " - already pending" : "");
proto_notify_state(&p->p, PS_START);
if (p->gr_active)
switch (p->gr_active)
{
case BGP_GRS_ACTIVE:
rt_refresh_end(p->p.main_ahook->table, p->p.main_ahook);
break;
p->gr_active = 1;
bgp_start_timer(p->gr_timer, p->conn->peer_gr_time);
case BGP_GRS_LLGR_1:
rt_refresh_begin(p->p.main_ahook->table, p->p.main_ahook);
return;
case BGP_GRS_LLGR_2:
rt_refresh_begin(p->p.main_ahook->table, p->p.main_ahook);
rt_modify_stale(p->p.main_ahook->table, p->p.main_ahook);
return;
}
p->stale_time = p->cf->llgr_mode ? p->conn->peer_llgr_time : 0;
p->gr_active = !p->stale_time ? BGP_GRS_ACTIVE : BGP_GRS_LLGR_1;
tm_start(p->gr_timer, p->conn->peer_gr_time);
rt_refresh_begin(p->p.main_ahook->table, p->p.main_ahook);
}
@ -515,10 +536,27 @@ bgp_graceful_restart_timeout(timer *t)
{
struct bgp_proto *p = t->data;
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
bgp_stop(p, 0, NULL, 0);
}
switch (p->gr_active)
{
case BGP_GRS_ACTIVE:
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
bgp_stop(p, 0, NULL, 0);
return;
case BGP_GRS_LLGR_1:
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
p->gr_active = BGP_GRS_LLGR_2;
tm_start(p->gr_timer, p->stale_time);
rt_modify_stale(p->p.main_ahook->table, p->p.main_ahook);
return;
case BGP_GRS_LLGR_2:
BGP_TRACE(D_EVENTS, "Long-lived graceful restart timeout");
p->gr_active = 0;
rt_refresh_end(p->p.main_ahook->table, p->p.main_ahook);
return;
}
}
/**
* bgp_refresh_begin - start incoming enhanced route refresh sequence
@ -576,6 +614,10 @@ bgp_send_open(struct bgp_conn *conn)
conn->peer_gr_time = 0;
conn->peer_gr_flags = 0;
conn->peer_gr_aflags = 0;
conn->peer_llgr_aware = 0;
conn->peer_llgr_able = 0;
conn->peer_llgr_time = 0;
conn->peer_llgr_aflags = 0;
conn->peer_ext_messages_support = 0;
DBG("BGP: Sending open\n");
@ -662,6 +704,12 @@ bgp_hold_timeout(timer *t)
if (sk_rx_ready(conn->sk) > 0)
bgp_start_timer(conn->hold_timer, 10);
else if ((conn->state == BS_ESTABLISHED) && p->gr_ready && conn->peer_llgr_able)
{
BGP_TRACE(D_EVENTS, "Hold timer expired");
bgp_handle_graceful_restart(p);
bgp_conn_enter_idle_state(conn);
}
else
bgp_error(conn, 4, 0, NULL, 0);
}
@ -1004,13 +1052,30 @@ bgp_bfd_notify(struct bfd_request *req)
int ps = p->p.proto_state;
if (req->down && ((ps == PS_START) || (ps == PS_UP)))
{
BGP_TRACE(D_EVENTS, "BFD session down");
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
if (p->cf->bfd == BGP_BFD_GRACEFUL)
{
BGP_TRACE(D_EVENTS, "BFD session down");
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
/* Trigger graceful restart */
if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
bgp_handle_graceful_restart(p);
if (p->incoming_conn.state > BS_IDLE)
bgp_conn_enter_idle_state(&p->incoming_conn);
if (p->outgoing_conn.state > BS_IDLE)
bgp_conn_enter_idle_state(&p->outgoing_conn);
}
else
{
/* Trigger session down */
if (ps == PS_UP)
bgp_update_startup_delay(p);
bgp_stop(p, 0, NULL, 0);
}
}
}
static void
@ -1019,7 +1084,7 @@ bgp_update_bfd(struct bgp_proto *p, int use_bfd)
if (use_bfd && !p->bfd_req)
p->bfd_req = bfd_request_session(p->p.pool, p->cf->remote_ip, p->source_addr,
p->cf->multihop ? NULL : p->neigh->iface,
bgp_bfd_notify, p);
p->p.vrf, bgp_bfd_notify, p);
if (!use_bfd && p->bfd_req)
{
@ -1252,7 +1317,7 @@ bgp_shutdown(struct proto *P)
if (message)
{
uint msg_len = strlen(message);
msg_len = MIN(msg_len, 128);
msg_len = MIN(msg_len, 255);
/* Buffer will be freed automatically by protocol shutdown */
data = mb_alloc(p->p.pool, msg_len + 1);
@ -1297,6 +1362,7 @@ bgp_init(struct proto_config *C)
P->rte_better = bgp_rte_better;
P->rte_mergable = bgp_rte_mergable;
P->rte_recalculate = c->deterministic_med ? bgp_rte_recalculate : NULL;
P->rte_modify = bgp_rte_modify_stale;
p->cf = c;
p->local_as = c->local_as;
@ -1332,6 +1398,10 @@ bgp_check_config(struct bgp_config *c)
if (!c->missing_lladdr)
c->missing_lladdr = c->rs_client ? MLL_IGNORE : MLL_SELF;
/* LLGR mode default based on GR mode */
if (c->llgr_mode < 0)
c->llgr_mode = c->gr_mode ? BGP_LLGR_AWARE : 0;
/* Disable after error incompatible with restart limit action */
if (c->c.in_limit && (c->c.in_limit->action == PLA_RESTART) && c->disable_after_error)
c->c.in_limit->action = PLA_DISABLE;
@ -1382,6 +1452,9 @@ bgp_check_config(struct bgp_config *c)
if (c->secondary && !c->c.table->sorted)
cf_error("BGP with secondary option requires sorted table");
if (!c->gr_mode && c->llgr_mode)
cf_error("Long-lived graceful restart requires basic graceful restart");
}
static int
@ -1550,6 +1623,11 @@ bgp_show_proto_info(struct proto *P)
if (p->gr_active)
cli_msg(-1006, " Neighbor graceful restart active");
if (p->gr_active && p->gr_timer->expires)
cli_msg(-1006, " %-15s %d/-",
(p->gr_active != BGP_GRS_LLGR_2) ? "Restart timer:" : "LL stale timer:",
p->gr_timer->expires - now);
if (P->proto_state == PS_START)
{
struct bgp_conn *oc = &p->outgoing_conn;
@ -1563,9 +1641,6 @@ bgp_show_proto_info(struct proto *P)
(oc->connect_retry_timer->expires))
cli_msg(-1006, " Connect delay: %d/%d",
oc->connect_retry_timer->expires - now, p->cf->connect_delay_time);
if (p->gr_active && p->gr_timer->expires)
cli_msg(-1006, " Restart timer: %d/-", p->gr_timer->expires - now);
}
else if (P->proto_state == PS_UP)
{
@ -1574,6 +1649,7 @@ bgp_show_proto_info(struct proto *P)
c->peer_refresh_support ? " refresh" : "",
c->peer_enhanced_refresh_support ? " enhanced-refresh" : "",
c->peer_gr_able ? " restart-able" : (c->peer_gr_aware ? " restart-aware" : ""),
c->peer_llgr_able ? " llgr-able" : (c->peer_llgr_aware ? " llgr-aware" : ""),
c->peer_as4_support ? " AS4" : "",
(c->peer_add_path & ADD_PATH_RX) ? " add-path-rx" : "",
(c->peer_add_path & ADD_PATH_TX) ? " add-path-tx" : "",

View File

@ -52,8 +52,10 @@ struct bgp_config {
int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */
int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
int llgr_mode; /* Long-lived graceful restart mode (BGP_LLGR_*) */
int setkey; /* Set MD5 password to system SA/SP database */
unsigned gr_time; /* Graceful restart timeout */
unsigned llgr_time; /* Long-lived graceful restart timeout */
unsigned connect_delay_time; /* Minimum delay between connect attempts */
unsigned connect_retry_time; /* Timeout for connect attempts */
unsigned hold_time, initial_hold_time;
@ -90,6 +92,18 @@ struct bgp_config {
/* For peer_gr_aflags */
#define BGP_GRF_FORWARDING 0x80
#define BGP_LLGR_ABLE 1
#define BGP_LLGR_AWARE 2
#define BGP_LLGRF_FORWARDING 0x80
#define BGP_GRS_NONE 0 /* No GR */
#define BGP_GRS_ACTIVE 1 /* Graceful restart per RFC 4724 */
#define BGP_GRS_LLGR_1 2 /* Long-lived GR phase 1 (restart time) */
#define BGP_GRS_LLGR_2 3 /* Long-lived GR phase 2 (stale time) */
#define BGP_BFD_GRACEFUL 2 /* BFD down triggers graceful restart */
struct bgp_conn {
struct bgp_proto *bgp;
@ -113,6 +127,10 @@ struct bgp_conn {
u16 peer_gr_time;
u8 peer_gr_flags;
u8 peer_gr_aflags;
u8 peer_llgr_aware;
u8 peer_llgr_able;
uint peer_llgr_time;
u8 peer_llgr_aflags;
u8 peer_ext_messages_support; /* Peer supports extended message length [draft] */
unsigned hold_time, keepalive_time; /* Times calculated from my and neighbor's requirements */
};
@ -133,9 +151,10 @@ struct bgp_proto {
int rr_client; /* Whether neighbor is RR client of me */
int rs_client; /* Whether neighbor is RS client of me */
u8 gr_ready; /* Neighbor could do graceful restart */
u8 gr_active; /* Neighbor is doing graceful restart */
u8 gr_active; /* Neighbor is doing graceful restart (BGP_GRS_*) */
u8 feed_state; /* Feed state (TX) for EoR, RR packets, see BFS_* */
u8 load_state; /* Load state (RX) for EoR, RR packets, see BFS_* */
uint stale_time; /* Long-lived stale time for LLGR */
struct bgp_conn *conn; /* Connection we have established */
struct bgp_conn outgoing_conn; /* Outgoing connection we're working with */
struct bgp_conn incoming_conn; /* Incoming connection we have neither accepted nor rejected yet */
@ -252,6 +271,7 @@ int bgp_get_attr(struct eattr *e, byte *buf, int buflen);
int bgp_rte_better(struct rte *, struct rte *);
int bgp_rte_mergable(rte *pri, rte *sec);
int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best);
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
void bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
void bgp_init_bucket_table(struct bgp_proto *);
@ -268,7 +288,7 @@ inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool,
/* packets.c */
void mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new);
void bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new);
void bgp_schedule_packet(struct bgp_conn *conn, int type);
void bgp_kick_tx(void *vconn);
void bgp_tx(struct birdsock *sk);
@ -398,6 +418,9 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi
#define BGP_COMM_NO_ADVERTISE 0xffffff02 /* Don't export at all */
#define BGP_COMM_NO_EXPORT_SUBCONFED 0xffffff03 /* NO_EXPORT even in local confederation */
#define BGP_COMM_LLGR_STALE 0xffff0006 /* Route is stale according to LLGR */
#define BGP_COMM_NO_LLGR 0xffff0007 /* Do not treat the route according to LLGR */
/* Origins */
#define ORIGIN_IGP 0

View File

@ -27,7 +27,8 @@ 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, SETKEY, BGP_LARGE_COMMUNITY)
CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY, BGP_LARGE_COMMUNITY,
LONG, LIVED, STALE)
CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
@ -60,6 +61,8 @@ 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->llgr_mode = -1;
BGP_CFG->llgr_time = 3600;
BGP_CFG->setkey = 1;
}
;
@ -162,10 +165,14 @@ bgp_proto:
| bgp_proto GRACEFUL RESTART bool ';' { BGP_CFG->gr_mode = $4; }
| bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; }
| bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }
| bgp_proto LONG LIVED GRACEFUL RESTART bool ';' { BGP_CFG->llgr_mode = $6; }
| bgp_proto LONG LIVED GRACEFUL RESTART AWARE ';' { BGP_CFG->llgr_mode = BGP_LLGR_AWARE; }
| bgp_proto LONG LIVED STALE TIME expr ';' { BGP_CFG->llgr_time = $6; }
| bgp_proto IGP TABLE rtable ';' { BGP_CFG->igp_table = $4; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
| bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
| bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
| bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; cf_check_bfd(1); }
;
CF_ADDTO(dynamic_attr, BGP_ORIGIN

View File

@ -13,7 +13,7 @@
#include "nest/protocol.h"
#include "nest/route.h"
#include "nest/attrs.h"
#include "nest/mrtdump.h"
#include "proto/mrt/mrt.h"
#include "conf/conf.h"
#include "lib/unaligned.h"
#include "lib/socket.h"
@ -38,81 +38,45 @@ static byte fsm_err_subcode[BS_MAX] = {
[BS_ESTABLISHED] = 3
};
/*
* MRT Dump format is not semantically specified.
* We will use these values in appropriate fields:
*
* Local AS, Remote AS - configured AS numbers for given BGP instance.
* Local IP, Remote IP - IP addresses of the TCP connection (0 if no connection)
*
* We dump two kinds of MRT messages: STATE_CHANGE (for BGP state
* changes) and MESSAGE (for received BGP messages).
*
* STATE_CHANGE uses always AS4 variant, but MESSAGE uses AS4 variant
* only when AS4 session is established and even in that case MESSAGE
* does not use AS4 variant for initial OPEN message. This strange
* behavior is here for compatibility with Quagga and Bgpdump,
*/
static byte *
mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4)
static void
init_mrt_bgp_data(struct bgp_conn *conn, struct mrt_bgp_data *d)
{
struct bgp_proto *p = conn->bgp;
int p_ok = conn->state >= BS_OPENCONFIRM;
if (as4)
{
put_u32(buf+0, p->remote_as);
put_u32(buf+4, p->local_as);
buf+=8;
}
else
{
put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS);
put_u16(buf+2, (p->local_as <= 0xFFFF) ? p->local_as : AS_TRANS);
buf+=4;
}
put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0);
put_u16(buf+2, BGP_AF);
buf+=4;
buf = put_ipa(buf, conn->sk ? conn->sk->daddr : IPA_NONE);
buf = put_ipa(buf, conn->sk ? conn->sk->saddr : IPA_NONE);
return buf;
memset(d, 0, sizeof(struct mrt_bgp_data));
d->peer_as = p->remote_as;
d->local_as = p->local_as;
d->index = (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0;
d->af = BGP_AF;
d->peer_ip = conn->sk ? conn->sk->daddr : IPA_NONE;
d->local_ip = conn->sk ? conn->sk->saddr : IPA_NONE;
d->as4 = p_ok ? p->as4_session : 0;
d->add_path = p_ok ? p->add_path_rx : 0;
}
static void
mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len)
{
byte *buf = alloca(128+len); /* 128 is enough for MRT headers */
byte *bp = buf + MRTDUMP_HDR_LENGTH;
int as4 = conn->bgp->as4_session;
struct mrt_bgp_data d;
init_mrt_bgp_data(conn, &d);
bp = mrt_put_bgp4_hdr(bp, conn, as4);
memcpy(bp, pkt, len);
bp += len;
mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE,
buf, bp-buf);
}
d.message = pkt;
d.msg_len = len;
static inline u16
convert_state(unsigned state)
{
/* Convert state from our BS_* values to values used in MRTDump */
return (state == BS_CLOSE) ? 1 : state + 1;
mrt_dump_bgp_message(&d);
}
void
mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new)
bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new)
{
byte buf[128];
byte *bp = buf + MRTDUMP_HDR_LENGTH;
struct mrt_bgp_data d;
init_mrt_bgp_data(conn, &d);
bp = mrt_put_bgp4_hdr(bp, conn, 1);
put_u16(bp+0, convert_state(old));
put_u16(bp+2, convert_state(new));
bp += 4;
mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf);
d.old_state = old;
d.new_state = new;
mrt_dump_bgp_state_change(&d);
}
static byte *
@ -231,6 +195,32 @@ bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf)
return buf;
}
static byte *
bgp_put_cap_llgr1(struct bgp_proto *p, byte *buf)
{
*buf++ = 71; /* Capability 71: Support for long-lived graceful restart */
*buf++ = 7; /* Capability data length */
*buf++ = 0; /* Appropriate AF */
*buf++ = BGP_AF;
*buf++ = 1; /* and SAFI 1 */
/* Next is 8bit flags and 24bit time */
put_u32(buf, p->cf->llgr_time);
buf[0] = p->p.gr_recovery ? BGP_LLGRF_FORWARDING : 0;
buf += 4;
return buf;
}
static byte *
bgp_put_cap_llgr2(struct bgp_proto *p UNUSED, byte *buf)
{
*buf++ = 71; /* Capability 71: Support for long-lived graceful restart */
*buf++ = 0; /* Capability data length */
return buf;
}
static byte *
bgp_create_open(struct bgp_conn *conn, byte *buf)
@ -285,6 +275,11 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
if (p->cf->enable_extended_messages)
cap = bgp_put_cap_ext_msg(p, cap);
if (p->cf->llgr_mode == BGP_LLGR_ABLE)
cap = bgp_put_cap_llgr1(p, cap);
else if (p->cf->llgr_mode == BGP_LLGR_AWARE)
cap = bgp_put_cap_llgr2(p, cap);
cap_len = cap - buf - 12;
if (cap_len > 0)
{
@ -789,8 +784,12 @@ bgp_kick_tx(void *vconn)
struct bgp_conn *conn = vconn;
DBG("BGP: kicking TX\n");
while (bgp_fire_tx(conn) > 0)
uint max = 1024;
while (--max && (bgp_fire_tx(conn) > 0))
;
if (!max && !ev_active(conn->tx_ev))
ev_schedule(conn->tx_ev);
}
void
@ -799,8 +798,12 @@ bgp_tx(sock *sk)
struct bgp_conn *conn = sk->data;
DBG("BGP: TX hook\n");
while (bgp_fire_tx(conn) > 0)
uint max = 1024;
while (--max && (bgp_fire_tx(conn) > 0))
;
if (!max && !ev_active(conn->tx_ev))
ev_schedule(conn->tx_ev);
}
/* Capatibility negotiation as per RFC 2842 */
@ -872,11 +875,38 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
conn->peer_enhanced_refresh_support = 1;
break;
case 71: /* Long-lived graceful restart capability, RFC draft */
if (cl % 7)
goto err;
conn->peer_llgr_aware = 1;
conn->peer_llgr_able = 0;
conn->peer_llgr_time = 0;
conn->peer_llgr_aflags = 0;
for (i = 0; i < cl; i += 7)
if (opt[2+i+0] == 0 && opt[2+i+1] == BGP_AF && opt[2+i+2] == 1) /* Match AFI/SAFI */
{
conn->peer_llgr_able = 1;
conn->peer_llgr_time = get_u32(opt + 2+i+3) & 0xffffff;
conn->peer_llgr_aflags = opt[2+i+3];
}
break;
/* We can safely ignore all other capabilities */
}
len -= 2 + cl;
opt += 2 + cl;
}
/* The LLGR capability must be advertised together with the GR capability,
otherwise it must be disregarded */
if (!conn->peer_gr_aware && conn->peer_llgr_aware)
{
conn->peer_llgr_aware = 0;
conn->peer_llgr_able = 0;
conn->peer_llgr_time = 0;
conn->peer_llgr_aflags = 0;
}
return;
err:
@ -1034,7 +1064,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
p->as4_session = p->cf->enable_as4 && conn->peer_as4_support;
p->add_path_rx = (p->cf->add_path & ADD_PATH_RX) && (conn->peer_add_path & ADD_PATH_TX);
p->add_path_tx = (p->cf->add_path & ADD_PATH_TX) && (conn->peer_add_path & ADD_PATH_RX);
p->gr_ready = p->cf->gr_mode && conn->peer_gr_able;
p->gr_ready = (p->cf->gr_mode && conn->peer_gr_able) ||
(p->cf->llgr_mode && conn->peer_llgr_able);
p->ext_messages = p->cf->enable_extended_messages && conn->peer_ext_messages_support;
/* Update RA mode */
@ -1125,6 +1156,7 @@ bgp_rte_update(struct bgp_proto *p, ip_addr prefix, int pxlen,
e->net = n;
e->pflags = 0;
e->u.bgp.suppressed = 0;
e->u.bgp.stale = -1;
rte_update2(p->p.main_ahook, n, e, *src);
}
@ -1507,7 +1539,7 @@ bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
return 1;
/* Handle proper message */
if ((msg_len > 128) && (msg_len + 1 > len))
if ((msg_len > 255) && (msg_len + 1 > len))
return 0;
/* Some elementary cleanup */
@ -1704,7 +1736,7 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len)
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
if (conn->bgp->p.mrtdump & MD_MESSAGES)
mrt_dump_bgp_packet(conn, pkt, len);
bgp_dump_message(conn, pkt, len);
switch (type)
{

1
proto/mrt/Doc Normal file
View File

@ -0,0 +1 @@
S mrt.c

5
proto/mrt/Makefile Normal file
View File

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

67
proto/mrt/config.Y Normal file
View File

@ -0,0 +1,67 @@
/*
* BIRD -- Multi-Threaded Routing Toolkit (MRT) Protocol
*
* (c) 2017--2018 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2017--2018 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
CF_HDR
#include "proto/mrt/mrt.h"
CF_DEFINES
#define MRT_CFG ((struct mrt_config *) this_proto)
CF_DECLS
CF_KEYWORDS(MRT, TABLE, FILTER, FILENAME, PERIOD, ALWAYS, ADD, PATH, DUMP, TO)
%type <md> mrt_dump_args
CF_GRAMMAR
CF_ADDTO(proto, mrt_proto)
mrt_proto_start: proto_start MRT
{
this_proto = proto_config_new(&proto_mrt, $1);
};
mrt_proto_item:
proto_item
| TABLE TEXT { MRT_CFG->table_expr = $2; }
| FILTER filter { MRT_CFG->filter = $2; }
| where_filter { MRT_CFG->filter = $1; }
| FILENAME text { MRT_CFG->filename = $2; }
| PERIOD expr { MRT_CFG->period = $2; }
| ALWAYS ADD PATH bool { MRT_CFG->always_add_path = $4; }
;
mrt_proto_opts:
/* empty */
| mrt_proto_opts mrt_proto_item ';'
;
mrt_proto:
mrt_proto_start proto_name '{' mrt_proto_opts '}' { mrt_check_config(this_proto); };
CF_CLI_HELP(MRT DUMP, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>] , [[Save MRT Table Dump into a file]])
CF_CLI(MRT DUMP, mrt_dump_args, [table <name>|\"<pattern>\"] [to \"<file>\"] [filter <filter>|where <where filter>], [[Save mrt table dump v2 of table name <t> right now]])
{ mrt_dump_cmd($3); } ;
mrt_dump_args:
/* empty */ { $$ = cfg_allocz(sizeof(struct mrt_dump_data)); }
| mrt_dump_args TABLE rtable { $$ = $1; $$->table_ptr = $3->table; }
| mrt_dump_args TABLE TEXT { $$ = $1; $$->table_expr = $3; }
| mrt_dump_args FILTER filter { $$ = $1; $$->filter = $3; }
| mrt_dump_args where_filter { $$ = $1; $$->filter = $2; }
| mrt_dump_args TO text { $$ = $1; $$->filename = $3; }
;
CF_CODE
CF_END

883
proto/mrt/mrt.c Normal file
View File

@ -0,0 +1,883 @@
/*
* BIRD -- Multi-Threaded Routing Toolkit (MRT) Protocol
*
* (c) 2017--2018 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2017--2018 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Multi-Threaded Routing Toolkit (MRT) protocol
*
* The MRT protocol is implemented in just one file: |mrt.c|. It contains of
* several parts: Generic functions for preparing MRT messages in a buffer,
* functions for MRT table dump (called from timer or CLI), functions for MRT
* BGP4MP dump (called from BGP), and the usual protocol glue. For the MRT table
* dump, the key structure is struct mrt_table_dump_state, which contains all
* necessary data and created when the MRT dump cycle is started for the
* duration of the MRT dump. The MBGP4MP dump is currently not bound to MRT
* protocol instance and uses the config->mrtdump_file fd.
*
* The protocol is simple, just periodically scans routing table and export it
* to a file. It does not use the regular update mechanism, but a direct access
* in order to handle iteration through multiple routing tables. The table dump
* needs to dump all peers first and then use indexes to address the peers, we
* use a hash table (@peer_hash) to find peer index based on BGP protocol key
* attributes.
*
* One thing worth documenting is the locking. During processing, the currently
* processed table (@table field in the state structure) is locked and also the
* explicitly named table is locked (@table_ptr field in the state structure) if
* specified. Between dumps no table is locked. Also the current config is
* locked (by config_add_obstacle()) during table dumps as some data (strings,
* filters) are shared from the config and the running table dump may be
* interrupted by reconfiguration.
*
* Supported standards:
* - RFC 6396 - MRT format standard
* - RFC 8050 - ADD_PATH extension
*/
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include "mrt.h"
#include "nest/cli.h"
#include "filter/filter.h"
#include "proto/bgp/bgp.h"
#include "sysdep/unix/unix.h"
#ifdef PATH_MAX
#define BIRD_PATH_MAX PATH_MAX
#else
#define BIRD_PATH_MAX 4096
#endif
#define mrt_log(s, msg, args...) \
({ \
if (s->cli) \
cli_printf(s->cli, -8009, msg, ## args); \
if (s->proto) \
log(L_ERR "%s: " msg, s->proto->p.name, ## args); \
})
/*
* MRT buffer code
*/
static void
mrt_buffer_init(buffer *b, pool *pool, size_t n)
{
b->start = mb_alloc(pool, n);
b->pos = b->start;
b->end = b->start + n;
}
static void
mrt_buffer_grow(buffer *b, size_t n)
{
size_t used = b->pos - b->start;
size_t size = b->end - b->start;
size_t req = used + n;
while (size < req)
size = size * 3 / 2;
b->start = mb_realloc(b->start, size);
b->pos = b->start + used;
b->end = b->start + size;
}
static inline void
mrt_buffer_need(buffer *b, size_t n)
{
if (b->pos + n > b->end)
mrt_buffer_grow(b, n);
}
static inline uint
mrt_buffer_pos(buffer *b)
{
return b->pos - b->start;
}
static inline void
mrt_buffer_flush(buffer *b)
{
b->pos = b->start;
}
#define MRT_DEFINE_TYPE(S, T) \
static inline void mrt_put_##S##_(buffer *b, T x) \
{ \
put_##S(b->pos, x); \
b->pos += sizeof(T); \
} \
\
static inline void mrt_put_##S(buffer *b, T x) \
{ \
mrt_buffer_need(b, sizeof(T)); \
put_##S(b->pos, x); \
b->pos += sizeof(T); \
}
MRT_DEFINE_TYPE(u8, u8)
MRT_DEFINE_TYPE(u16, u16)
MRT_DEFINE_TYPE(u32, u32)
MRT_DEFINE_TYPE(u64, u64)
MRT_DEFINE_TYPE(ip4, ip4_addr)
MRT_DEFINE_TYPE(ip6, ip6_addr)
static inline void
mrt_put_ipa(buffer *b, ip_addr x)
{
if (ipa_is_ip4(x))
mrt_put_ip4(b, ipa_to_ip4(x));
else
mrt_put_ip6(b, ipa_to_ip6(x));
}
static inline void
mrt_put_data(buffer *b, const void *src, size_t n)
{
if (!n)
return;
mrt_buffer_need(b, n);
memcpy(b->pos, src, n);
b->pos += n;
}
static void
mrt_init_message(buffer *b, u16 type, u16 subtype)
{
/* Reset buffer */
mrt_buffer_flush(b);
mrt_buffer_need(b, MRT_HDR_LENGTH);
/* Prepare header */
mrt_put_u32_(b, now_real);
mrt_put_u16_(b, type);
mrt_put_u16_(b, subtype);
/* Message length, will be fixed later */
mrt_put_u32_(b, 0);
}
static void
mrt_dump_message(buffer *b, int fd)
{
uint len = mrt_buffer_pos(b);
/* Fix message length */
ASSERT(len >= MRT_HDR_LENGTH);
put_u32(b->start + 8, len - MRT_HDR_LENGTH);
if (fd < 0)
return;
if (write(fd, b->start, len) < 0)
log(L_ERR "Write to MRT file failed: %m"); /* TODO: name of file */
}
static int
bstrsub(char *dst, size_t n, const char *src, const char *key, const char *val)
{
const char *last, *next;
char *pos = dst;
size_t step, klen = strlen(key), vlen = strlen(val);
for (last = src; next = strstr(last, key); last = next + klen)
{
step = next - last;
if (n <= step + vlen)
return 0;
memcpy(pos, last, step);
ADVANCE(pos, n, step);
memcpy(pos, val, vlen);
ADVANCE(pos, n, vlen);
}
step = strlen(last);
if (n <= step)
return 0;
memcpy(pos, last, step);
ADVANCE(pos, n, step);
pos[0] = 0;
return 1;
}
static inline rtable *
mrt_next_table_(rtable *tab, rtable *tab_ptr, const char *pattern)
{
/* Handle explicit table, return it in the first pass */
if (tab_ptr)
return !tab ? tab_ptr : NULL;
/* Walk routing_tables list, starting after tab (if non-NULL) */
for (tab = !tab ? HEAD(routing_tables) : NODE_NEXT(tab);
NODE_VALID(tab);
tab = NODE_NEXT(tab))
if (patmatch(pattern, tab->name))
return tab;
return NULL;
}
static rtable *
mrt_next_table(struct mrt_table_dump_state *s)
{
rtable *tab = mrt_next_table_(s->table, s->table_ptr, s->table_expr);
if (s->table)
rt_unlock_table(s->table);
s->table = tab;
if (s->table)
rt_lock_table(s->table);
return s->table;
}
static int
mrt_open_file(struct mrt_table_dump_state *s)
{
char fmt1[BIRD_PATH_MAX];
char name[BIRD_PATH_MAX];
if (!bstrsub(fmt1, sizeof(fmt1), s->filename, "%N", s->table->name) ||
!tm_format_real_time(name, sizeof(name), fmt1, now_real))
{
mrt_log(s, "Invalid filename '%s'", s->filename);
return 0;
}
s->file = rf_open(s->pool, name, "a");
if (!s->file)
{
mrt_log(s, "Unable to open MRT file '%s': %m", name);
return 0;
}
s->fd = rf_fileno(s->file);
s->time_offset = now_real - now;
return 1;
}
static void
mrt_close_file(struct mrt_table_dump_state *s)
{
rfree(s->file);
s->file = NULL;
s->fd = -1;
}
/*
* MRT Table Dump: Peer Index Table
*/
#define PEER_KEY(n) n->peer_id, n->peer_as, n->peer_ip
#define PEER_NEXT(n) n->next
#define PEER_EQ(id1,as1,ip1,id2,as2,ip2) \
id1 == id2 && as1 == as2 && ipa_equal(ip1, ip2)
#define PEER_FN(id,as,ip) ipa_hash(ip)
static void
mrt_peer_table_header(struct mrt_table_dump_state *s, u32 router_id, const char *name)
{
buffer *b = &s->buf;
/* Collector BGP ID */
mrt_put_u32(b, router_id);
/* View Name */
uint name_length = name ? strlen(name) : 0;
name_length = MIN(name_length, 65535);
mrt_put_u16(b, name_length);
mrt_put_data(b, name, name_length);
/* Peer Count, will be fixed later */
s->peer_count = 0;
s->peer_count_offset = mrt_buffer_pos(b);
mrt_put_u16(b, 0);
HASH_INIT(s->peer_hash, s->pool, 10);
}
static void
mrt_peer_table_entry(struct mrt_table_dump_state *s, u32 peer_id, u32 peer_as, ip_addr peer_ip)
{
buffer *b = &s->buf;
uint type = MRT_PEER_TYPE_32BIT_ASN;
if (ipa_is_ip6(peer_ip))
type |= MRT_PEER_TYPE_IPV6;
/* Dump peer to buffer */
mrt_put_u8(b, type);
mrt_put_u32(b, peer_id);
mrt_put_ipa(b, peer_ip);
mrt_put_u32(b, peer_as);
/* Add peer to hash table */
struct mrt_peer_entry *n = lp_allocz(s->peer_lp, sizeof(struct mrt_peer_entry));
n->peer_id = peer_id;
n->peer_as = peer_as;
n->peer_ip = peer_ip;
n->index = s->peer_count++;
HASH_INSERT(s->peer_hash, PEER, n);
}
static void
mrt_peer_table_dump(struct mrt_table_dump_state *s)
{
mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, MRT_PEER_INDEX_TABLE);
mrt_peer_table_header(s, config->router_id, s->table->name);
/* 0 is fake peer for non-BGP routes */
mrt_peer_table_entry(s, 0, 0, IPA_NONE);
#ifdef CONFIG_BGP
struct proto *P;
WALK_LIST(P, active_proto_list)
if (P->proto == &proto_bgp)
{
struct bgp_proto *p = (void *) P;
mrt_peer_table_entry(s, p->remote_id, p->remote_as, p->cf->remote_ip);
}
#endif
/* Fix Peer Count */
put_u16(s->buf.start + s->peer_count_offset, s->peer_count);
mrt_dump_message(&s->buf, s->fd);
}
static void
mrt_peer_table_flush(struct mrt_table_dump_state *s)
{
lp_flush(s->peer_lp);
HASH_FREE(s->peer_hash);
}
/*
* MRT Table Dump: RIB Table
*/
static void
mrt_rib_table_header(struct mrt_table_dump_state *s, net *n)
{
buffer *b = &s->buf;
/* Sequence Number */
mrt_put_u32(b, s->seqnum);
/* Network Prefix */
ip_addr a = n->n.prefix;
ipa_hton(a);
mrt_put_u8(b, n->n.pxlen);
mrt_put_data(b, &a, BYTES(n->n.pxlen));
/* Entry Count, will be fixed later */
s->entry_count = 0;
s->entry_count_offset = mrt_buffer_pos(b);
mrt_put_u16(b, 0);
}
static void
mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r, struct ea_list *tmpa)
{
buffer *b = &s->buf;
uint peer = 0;
#ifdef CONFIG_BGP
/* Find peer index */
if (r->attrs->src->proto->proto == &proto_bgp)
{
struct bgp_proto *p = (void *) r->attrs->src->proto;
struct mrt_peer_entry *n =
HASH_FIND(s->peer_hash, PEER, p->remote_id, p->remote_as, p->cf->remote_ip);
peer = n ? n->index : 0;
}
#endif
/* Peer Index and Originated Time */
mrt_put_u16(b, peer);
mrt_put_u32(b, r->lastmod + s->time_offset);
/* Path Identifier */
if (s->add_path)
mrt_put_u32(b, r->attrs->src->private_id);
/* Route Attributes */
mrt_put_u16(b, 0);
#ifdef CONFIG_BGP
if (r->attrs->eattrs || tmpa)
{
struct ea_list *eattrs = r->attrs->eattrs;
if (!rta_is_cached(r->attrs) || tmpa)
{
/* Attributes must be merged and sorted for bgp_encode_attrs() */
tmpa = ea_append(tmpa, eattrs);
eattrs = alloca(ea_scan(tmpa));
ea_merge(tmpa, eattrs);
ea_sort(eattrs);
}
mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
int alen = bgp_encode_attrs(NULL, b->pos, eattrs, MRT_ATTR_BUFFER_SIZE);
if (alen < 0)
{
mrt_log(s, "Attribute list too long for %I/%d",
r->net->n.prefix, r->net->n.pxlen);
alen = 0;
}
put_u16(b->pos - 2, alen);
b->pos += alen;
}
#endif
s->entry_count++;
}
static void
mrt_rib_table_dump(struct mrt_table_dump_state *s, net *n, int add_path)
{
rte *rt, *rt0;
int subtype;
s->add_path = add_path;
#ifndef IPV6
subtype = !add_path ? MRT_RIB_IPV4_UNICAST : MRT_RIB_IPV4_UNICAST_ADDPATH;
#else
subtype = !add_path ? MRT_RIB_IPV6_UNICAST : MRT_RIB_IPV6_UNICAST_ADDPATH;
#endif
mrt_init_message(&s->buf, MRT_TABLE_DUMP_V2, subtype);
mrt_rib_table_header(s, n);
for (rt0 = n->routes; rt = rt0; rt0 = rt0->next)
{
if (rte_is_filtered(rt))
continue;
/* Skip routes that should be reported in the other phase */
if (!s->always_add_path && (!rt->attrs->src->private_id != !s->add_path))
{
s->want_add_path = 1;
continue;
}
struct ea_list *tmp_attrs = rte_make_tmp_attrs(rt, s->linpool);
if (f_run(s->filter, &rt, &tmp_attrs, s->linpool, 0) <= F_ACCEPT)
mrt_rib_table_entry(s, rt, tmp_attrs);
if (rt != rt0)
rte_free(rt);
lp_flush(s->linpool);
}
/* Fix Entry Count */
put_u16(s->buf.start + s->entry_count_offset, s->entry_count);
/* Update max counter */
s->max -= 1 + s->entry_count;
/* Skip empty entries */
if (!s->entry_count)
return;
s->seqnum++;
mrt_dump_message(&s->buf, s->fd);
}
/*
* MRT Table Dump: main logic
*/
static struct mrt_table_dump_state *
mrt_table_dump_init(pool *pp)
{
pool *pool = rp_new(pp, "MRT Table Dump");
struct mrt_table_dump_state *s = mb_allocz(pool, sizeof(struct mrt_table_dump_state));
s->pool = pool;
s->linpool = lp_new(pool, 4080);
s->peer_lp = lp_new(pool, 4080);
mrt_buffer_init(&s->buf, pool, 2 * MRT_ATTR_BUFFER_SIZE);
/* We lock the current config as we may reference it indirectly by filter */
s->config = config;
config_add_obstacle(s->config);
s->fd = -1;
return s;
}
static void
mrt_table_dump_free(struct mrt_table_dump_state *s)
{
if (s->table_open)
FIB_ITERATE_UNLINK(&s->fit, &s->table->fib);
if (s->table)
rt_unlock_table(s->table);
if (s->table_ptr)
rt_unlock_table(s->table_ptr);
config_del_obstacle(s->config);
rfree(s->pool);
}
static int
mrt_table_dump_step(struct mrt_table_dump_state *s)
{
s->max = 2048;
if (s->table_open)
goto step;
while (mrt_next_table(s))
{
if (!mrt_open_file(s))
continue;
mrt_peer_table_dump(s);
FIB_ITERATE_INIT(&s->fit, &s->table->fib);
s->table_open = 1;
step:
FIB_ITERATE_START(&s->table->fib, &s->fit, fn)
{
if (s->max < 0)
{
FIB_ITERATE_PUT(&s->fit, fn);
return 0;
}
/* With Always ADD_PATH option, we jump directly to second phase */
s->want_add_path = s->always_add_path;
if (s->want_add_path == 0)
mrt_rib_table_dump(s, (net *) fn, 0);
if (s->want_add_path == 1)
mrt_rib_table_dump(s, (net *) fn, 1);
}
FIB_ITERATE_END(fn);
s->table_open = 0;
mrt_close_file(s);
mrt_peer_table_flush(s);
}
return 1;
}
static void
mrt_timer(timer *t)
{
struct mrt_proto *p = t->data;
struct mrt_config *cf = (void *) (p->p.cf);
if (p->table_dump)
{
log(L_WARN "%s: Earlier RIB table dump still not finished, skipping next one", p->p.name);
return;
}
TRACE(D_EVENTS, "RIB table dump started");
struct mrt_table_dump_state *s = mrt_table_dump_init(p->p.pool);
s->proto = p;
s->table_expr = cf->table_expr;
s->table_ptr = cf->table_cf ? cf->table_cf->table : NULL;
s->filter = cf->filter;
s->filename = cf->filename;
s->always_add_path = cf->always_add_path;
if (s->table_ptr)
rt_lock_table(s->table_ptr);
p->table_dump = s;
ev_schedule(p->event);
}
static void
mrt_event(void *P)
{
struct mrt_proto *p = P;
if (!p->table_dump)
return;
if (!mrt_table_dump_step(p->table_dump))
{
ev_schedule(p->event);
return;
}
mrt_table_dump_free(p->table_dump);
p->table_dump = NULL;
TRACE(D_EVENTS, "RIB table dump done");
if (p->p.proto_state == PS_STOP)
proto_notify_state(&p->p, PS_DOWN);
}
/*
* MRT Table Dump: CLI command
*/
static void
mrt_dump_cont(struct cli *c)
{
if (!mrt_table_dump_step(c->rover))
return;
cli_printf(c, 0, "");
mrt_table_dump_free(c->rover);
c->cont = c->cleanup = c->rover = NULL;
}
static void
mrt_dump_cleanup(struct cli *c)
{
mrt_table_dump_free(c->rover);
c->rover = NULL;
}
void
mrt_dump_cmd(struct mrt_dump_data *d)
{
if (cli_access_restricted())
return;
if (!d->table_expr && !d->table_ptr)
cf_error("Table not specified");
if (!d->filename)
cf_error("File not specified");
struct mrt_table_dump_state *s = mrt_table_dump_init(this_cli->pool);
s->cli = this_cli;
s->table_expr = d->table_expr;
s->table_ptr = d->table_ptr;
s->filter = d->filter;
s->filename = d->filename;
if (s->table_ptr)
rt_lock_table(s->table_ptr);
this_cli->cont = mrt_dump_cont;
this_cli->cleanup = mrt_dump_cleanup;
this_cli->rover = s;
}
/*
* MRT BGP4MP dump
*/
static buffer *
mrt_bgp_buffer(void)
{
/* Static buffer for BGP4MP dump, TODO: change to use MRT protocol */
static buffer b;
if (!b.start)
mrt_buffer_init(&b, &root_pool, 1024);
return &b;
}
static void
mrt_bgp_header(buffer *b, struct mrt_bgp_data *d)
{
if (d->as4)
{
mrt_put_u32(b, d->peer_as);
mrt_put_u32(b, d->local_as);
}
else
{
mrt_put_u16(b, (d->peer_as <= 0xFFFF) ? d->peer_as : AS_TRANS);
mrt_put_u16(b, (d->local_as <= 0xFFFF) ? d->local_as : AS_TRANS);
}
mrt_put_u16(b, (d->index <= 0xFFFF) ? d->index : 0);
mrt_put_u16(b, d->af);
if (d->af == BGP_AF_IPV4)
{
mrt_put_ip4(b, ipa_to_ip4(d->peer_ip));
mrt_put_ip4(b, ipa_to_ip4(d->local_ip));
}
else
{
mrt_put_ip6(b, ipa_to_ip6(d->peer_ip));
mrt_put_ip6(b, ipa_to_ip6(d->local_ip));
}
}
void
mrt_dump_bgp_message(struct mrt_bgp_data *d)
{
const u16 subtypes[] = {
MRT_BGP4MP_MESSAGE, MRT_BGP4MP_MESSAGE_AS4,
MRT_BGP4MP_MESSAGE_LOCAL, MRT_BGP4MP_MESSAGE_AS4_LOCAL,
MRT_BGP4MP_MESSAGE_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_ADDPATH,
MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH, MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
};
buffer *b = mrt_bgp_buffer();
mrt_init_message(b, MRT_BGP4MP, subtypes[d->as4 + 4*d->add_path]);
mrt_bgp_header(b, d);
mrt_put_data(b, d->message, d->msg_len);
mrt_dump_message(b, config->mrtdump_file);
}
void
mrt_dump_bgp_state_change(struct mrt_bgp_data *d)
{
/* Convert state from our BS_* values to values used in MRTDump */
const u16 states[BS_MAX] = {1, 2, 3, 4, 5, 6, 1};
if (states[d->old_state] == states[d->new_state])
return;
/* Always use AS4 mode for STATE_CHANGE */
d->as4 = 1;
buffer *b = mrt_bgp_buffer();
mrt_init_message(b, MRT_BGP4MP, MRT_BGP4MP_STATE_CHANGE_AS4);
mrt_bgp_header(b, d);
mrt_put_u16(b, states[d->old_state]);
mrt_put_u16(b, states[d->new_state]);
mrt_dump_message(b, config->mrtdump_file);
}
/*
* MRT protocol glue
*/
void
mrt_check_config(struct proto_config *C)
{
struct mrt_config *cf = (void *) C;
/* c.table must be always defined, but it is relevant only if table_expr is not set */
if (!cf->table_expr)
cf->table_cf = cf->c.table;
if (!cf->table_expr && !cf->table_cf)
cf_error("Table not specified");
if (!cf->filename)
cf_error("File not specified");
if (!cf->period)
cf_error("Period not specified");
}
static struct proto *
mrt_init(struct proto_config *C)
{
struct proto *P = proto_new(C, sizeof(struct mrt_proto));
return P;
}
static int
mrt_start(struct proto *P)
{
struct mrt_proto *p = (void *) P;
struct mrt_config *cf = (void *) (P->cf);
p->timer = tm_new_set(P->pool, mrt_timer, p, 0, cf->period);
p->event = ev_new_set(P->pool, mrt_event, p);
tm_start(p->timer, cf->period);
return PS_UP;
}
static int
mrt_shutdown(struct proto *P)
{
struct mrt_proto *p = (void *) P;
return p->table_dump ? PS_STOP : PS_DOWN;
}
static int
mrt_reconfigure(struct proto *P, struct proto_config *CF)
{
struct mrt_proto *p = (void *) P;
struct mrt_config *old = (void *) (P->cf);
struct mrt_config *new = (void *) CF;
if (new->period != old->period)
{
TRACE(D_EVENTS, "Changing period from %d to %d s", old->period, new->period);
bird_clock_t new_time = p->timer->expires - old->period + new->period;
tm_start(p->timer, (new_time > now) ? (new_time - now) : 0);
p->timer->recurrent = new->period;
}
return 1;
}
static void
mrt_copy_config(struct proto_config *dest, struct proto_config *src)
{
/* Just a shallow copy, not many items here */
proto_copy_rest(dest, src, sizeof(struct mrt_config));
}
struct protocol proto_mrt = {
.name = "MRT",
.template = "mrt%d",
.config_size = sizeof(struct mrt_config),
.init = mrt_init,
.start = mrt_start,
.shutdown = mrt_shutdown,
.reconfigure = mrt_reconfigure,
.copy_config = mrt_copy_config,
};

156
proto/mrt/mrt.h Normal file
View File

@ -0,0 +1,156 @@
/*
* BIRD -- Multi-Threaded Routing Toolkit (MRT) Protocol
*
* (c) 2017--2018 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2017--2018 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_MRT_H_
#define _BIRD_MRT_H_
#include "nest/bird.h"
#include "nest/protocol.h"
#include "lib/lists.h"
#include "nest/route.h"
#include "lib/event.h"
#include "lib/hash.h"
struct mrt_config {
struct proto_config c;
struct rtable_config *table_cf;
const char *table_expr;
struct filter *filter;
const char *filename;
uint period;
int always_add_path;
};
struct mrt_proto {
struct proto p;
timer *timer;
event *event;
struct mrt_target *file;
struct mrt_table_dump_state *table_dump;
};
struct mrt_dump_data {
const char *table_expr;
struct rtable *table_ptr;
struct filter *filter;
char *filename;
};
struct mrt_peer_entry {
u32 index;
u32 peer_id;
u32 peer_as;
ip_addr peer_ip;
struct mrt_peer_entry *next;
};
struct mrt_table_dump_state {
struct mrt_proto *proto; /* Protocol for regular MRT dumps (or NULL) */
struct cli *cli; /* CLI for irregular MRT dumps (or NULL) */
struct config *config; /* Config valid during start of dump, locked */
/* Configuration information */
const char *table_expr; /* Wildcard for table name (or NULL) */
struct rtable *table_ptr; /* Explicit table (or NULL) */
struct filter *filter; /* Optional filter */
const char *filename; /* Filename pattern */
int always_add_path; /* Always use *_ADDPATH message subtypes */
/* Allocated by mrt_table_dump_init() */
pool *pool; /* Pool for table dump */
linpool *linpool; /* Temporary linear pool */
linpool *peer_lp; /* Linear pool for peer entries in peer_hash */
buffer buf; /* Buffer for MRT messages */
HASH(struct mrt_peer_entry) peer_hash; /* Hash for peers to find the index */
struct rtable *table; /* Processed table, NULL initially */
struct fib_iterator fit; /* Iterator in processed table */
int table_open; /* Whether iterator is linked */
int add_path; /* Current message subtype is *_ADDPATH */
int want_add_path; /* Want *_ADDPATH message later */
int max; /* Decreasing counter of dumped routes */
u32 seqnum; /* MRT message sequence number */
bird_clock_t time_offset; /* Time offset between monotonic and real time */
u16 peer_count; /* Number of peers */
u32 peer_count_offset; /* Buffer offset to store peer_count later */
u16 entry_count; /* Number of RIB Entries */
u32 entry_count_offset; /* Buffer offset to store entry_count later */
struct rfile *file; /* tracking for mrt table dump file */
int fd;
};
struct mrt_bgp_data {
uint peer_as;
uint local_as;
uint index;
uint af;
ip_addr peer_ip;
ip_addr local_ip;
byte *message;
uint msg_len;
uint old_state;
uint new_state;
u8 as4;
u8 add_path;
};
#define MRT_HDR_LENGTH 12 /* MRT Timestamp + MRT Type + MRT Subtype + MRT Load Length */
#define MRT_PEER_TYPE_32BIT_ASN 2 /* MRT Table Dump: Peer Index Table: Peer Type: Use 32bit ASN */
#define MRT_PEER_TYPE_IPV6 1 /* MRT Table Dump: Peer Index Table: Peer Type: Use IPv6 IP Address */
#define MRT_ATTR_BUFFER_SIZE 65536
/* MRT Types */
#define MRT_TABLE_DUMP_V2 13
#define MRT_BGP4MP 16
/* MRT Table Dump v2 Subtypes */
#define MRT_PEER_INDEX_TABLE 1
#define MRT_RIB_IPV4_UNICAST 2
#define MRT_RIB_IPV4_MULTICAST 3
#define MRT_RIB_IPV6_UNICAST 4
#define MRT_RIB_IPV6_MULTICAST 5
#define MRT_RIB_GENERIC 6
#define MRT_RIB_IPV4_UNICAST_ADDPATH 8
#define MRT_RIB_IPV4_MULTICAST_ADDPATH 9
#define MRT_RIB_IPV6_UNICAST_ADDPATH 10
#define MRT_RIB_IPV6_MULTICAST_ADDPATH 11
#define MRT_RIB_GENERIC_ADDPATH 12
/* MRT BGP4MP Subtypes */
#define MRT_BGP4MP_MESSAGE 1
#define MRT_BGP4MP_MESSAGE_AS4 4
#define MRT_BGP4MP_STATE_CHANGE_AS4 5
#define MRT_BGP4MP_MESSAGE_LOCAL 6
#define MRT_BGP4MP_MESSAGE_AS4_LOCAL 7
#define MRT_BGP4MP_MESSAGE_ADDPATH 8
#define MRT_BGP4MP_MESSAGE_AS4_ADDPATH 9
#define MRT_BGP4MP_MESSAGE_LOCAL_ADDPATH 10
#define MRT_BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH 11
#ifdef CONFIG_MRT
void mrt_dump_cmd(struct mrt_dump_data *d);
void mrt_dump_bgp_message(struct mrt_bgp_data *d);
void mrt_dump_bgp_state_change(struct mrt_bgp_data *d);
void mrt_check_config(struct proto_config *C);
#else
static inline void mrt_dump_bgp_message(struct mrt_bgp_data *d UNUSED) { }
static inline void mrt_dump_bgp_state_change(struct mrt_bgp_data *d UNUSED) { }
#endif
#endif /* _BIRD_MRT_H_ */

View File

@ -121,7 +121,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
{
struct ospf_dbdes2_packet *ps = (void *) pkt;
ps->iface_mtu = htons(iface_mtu);
ps->options = ifa->oa->options;
ps->options = ifa->oa->options & ~OPT_N;
ps->imms = 0; /* Will be set later */
ps->ddseq = htonl(n->dds);
length = sizeof(struct ospf_dbdes2_packet);
@ -129,7 +129,7 @@ ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
else /* OSPFv3 */
{
struct ospf_dbdes3_packet *ps = (void *) pkt;
ps->options = htonl(ifa->oa->options);
ps->options = htonl(ifa->oa->options & ~OPT_N);
ps->iface_mtu = htons(iface_mtu);
ps->padding = 0;
ps->imms = 0; /* Will be set later */
@ -347,6 +347,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
ospf_neigh_sm(n, INM_2WAYREC);
if (n->state != NEIGHBOR_EXSTART)
return;
/* fallthrough */
case NEIGHBOR_EXSTART:
if ((ifa->type != OSPF_IT_VLINK) &&

View File

@ -283,7 +283,7 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
if (!ipa_equal(faddr, n->ip))
{
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s changed IP address to %I",
n->rid, ifa->ifname, n->ip, faddr);
n->rid, ifa->ifname, faddr);
n->ip = faddr;
}
}

View File

@ -524,6 +524,10 @@ add_nbma_node(struct ospf_iface *ifa, struct nbma_node *src, int found)
static int
ospf_iface_stubby(struct ospf_iface_patt *ip, struct ifa *addr)
{
/* vlink cannot be stub */
if (ip->type == OSPF_IT_VLINK)
return 0;
/* a host address */
if (addr->flags & IA_HOST)
return 1;
@ -861,6 +865,7 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifname, ifa->priority, new->priority);
ifa->priority = new->priority;
ospf_iface_sm(ifa, ISM_NEICH);
ospf_notify_link_lsa(ifa);
}
@ -1256,7 +1261,8 @@ ospf_iface_change_mtu(struct ospf_proto *p, struct ospf_iface *ifa)
{
/* ifa is not vlink */
OSPF_TRACE(D_EVENTS, "Interface %s changed MTU to %d", ifa->iface->mtu);
OSPF_TRACE(D_EVENTS, "Interface %s changed MTU to %d",
ifa->ifname, ifa->iface->mtu);
ifa->tx_length = ifa_tx_length(ifa);

View File

@ -584,8 +584,11 @@ ospf_neigh_bfd_hook(struct bfd_request *req)
void
ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
{
struct ospf_proto *p = n->ifa->oa->po;
if (use_bfd && !n->bfd_req)
n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip, n->ifa->iface,
n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip,
n->ifa->iface, p->p.vrf,
ospf_neigh_bfd_hook, n);
if (!use_bfd && n->bfd_req)

View File

@ -1203,6 +1203,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
he->domain = 1; /* Abuse domain field to mark the LSA */
hex[jx++] = he;
}
/* fallthrough */
default:
accept = 0;
}

View File

@ -56,6 +56,7 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
return;
}
strncpy(auth->password, pass->password, sizeof(auth->password));
/* fallthrough */
case OSPF_AUTH_NONE:
{

View File

@ -404,6 +404,8 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
void
ospf_flush_lsa(struct ospf_proto *p, struct top_hash_entry *en)
{
en->nf = NULL;
if (en->next_lsa_body)
{
mb_free(en->next_lsa_body);

View File

@ -89,6 +89,12 @@ pipe_rt_notify(struct proto *P, rtable *src_table, net *n, rte *new, rte *old, e
memcpy(&(e->u), &(new->u), sizeof(e->u));
e->pref = new->pref;
e->pflags = new->pflags;
#ifdef CONFIG_BGP
/* Hack to cleanup cached value */
if (e->attrs->src->proto->proto == &proto_bgp)
e->u.bgp.stale = -1;
#endif
}
src = a.src;
@ -230,12 +236,18 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
if ((oc->peer->table != nc->peer->table) || (oc->mode != nc->mode))
return 0;
int import_changed = ! filter_same(new->in_filter, old->in_filter);
int export_changed = ! filter_same(new->out_filter, old->out_filter);
/* Update output filters in ahooks */
if (P->main_ahook)
{
P->main_ahook->out_filter = new->out_filter;
P->main_ahook->in_limit = new->in_limit;
proto_verify_limits(P->main_ahook);
if (export_changed)
P->main_ahook->last_out_filter_change = now;
}
if (p->peer_ahook)
@ -243,14 +255,15 @@ pipe_reconfigure(struct proto *P, struct proto_config *new)
p->peer_ahook->out_filter = new->in_filter;
p->peer_ahook->in_limit = new->out_limit;
proto_verify_limits(p->peer_ahook);
if (import_changed)
p->peer_ahook->last_out_filter_change = now;
}
if ((P->proto_state != PS_UP) || (proto_reconfig_type == RECONFIG_SOFT))
return 1;
if ((new->preference != old->preference)
|| ! filter_same(new->in_filter, old->in_filter)
|| ! filter_same(new->out_filter, old->out_filter))
if (import_changed || export_changed || (new->preference != old->preference))
proto_request_feeding(P);
return 1;

View File

@ -281,17 +281,6 @@ radv_iface_add(struct object_lock *lock)
radv_iface_notify(ifa, RA_EV_INIT);
}
static inline struct ifa *
find_lladdr(struct iface *iface)
{
struct ifa *a;
WALK_LIST(a, iface->addrs)
if (a->scope == SCOPE_LINK)
return a;
return NULL;
}
static void
radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
{
@ -305,18 +294,12 @@ radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_conf
ifa->ra = p;
ifa->cf = cf;
ifa->iface = iface;
ifa->addr = iface->llv6;
init_list(&ifa->prefixes);
ifa->prune_time = TIME_INFINITY;
add_tail(&p->iface_list, NODE ifa);
ifa->addr = find_lladdr(iface);
if (!ifa->addr)
{
log(L_ERR "%s: Missing link-local address on interface %s", p->p.name, iface->name);
return;
}
timer *tm = tm_new(pool);
tm->hook = radv_timer;
tm->data = ifa;
@ -360,6 +343,10 @@ radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
struct radv_iface_config *ic = (struct radv_iface_config *)
iface_patt_find(&cf->patt_list, iface, NULL);
/* Ignore ifaces without link-local address */
if (!iface->llv6)
return;
if (ic)
radv_iface_new(p, iface, ic);

View File

@ -739,16 +739,9 @@ rip_open_socket(struct rip_iface *ifa)
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
sk->saddr = rip_is_v2(p) ? ifa->iface->addr->ip : ifa_llv6(ifa->iface)->ip;
sk->vrf = p->p.vrf;
/*
* For RIPv2, we explicitly choose a primary address, mainly to ensure that
* RIP and BFD uses the same one. For RIPng, we left it to kernel, which
* should choose some link-local address based on the same scope rule.
*/
if (rip_is_v2(p))
sk->saddr = ifa->iface->addr->ip;
sk->rx_hook = rip_rx_hook;
sk->tx_hook = rip_tx_hook;
sk->err_hook = rip_err_hook;

View File

@ -504,7 +504,8 @@ rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
*/
ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
n->nbr->iface, rip_bfd_notify, n);
n->nbr->iface, p->p.vrf,
rip_bfd_notify, n);
}
if (!use_bfd && n->bfd_req)
@ -764,6 +765,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
/* For RIPng, ignore ifaces without link-local address */
if (rip_is_ng(p) && !ifa_llv6(iface))
return;
if (ic)
rip_add_iface(p, iface, ic);

View File

@ -150,7 +150,7 @@ static_update_bfd(struct proto *p, struct static_route *r)
if (bfd_up && !r->bfd_req)
{
// ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip;
r->bfd_req = bfd_request_session(p->pool, r->via, nb->ifa->ip, nb->iface,
r->bfd_req = bfd_request_session(p->pool, r->via, nb->ifa->ip, nb->iface, p->vrf,
static_bfd_notify, r);
}
@ -518,6 +518,11 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n)
if (r->neigh)
r->neigh->data = NULL;
if (r->dest == RTD_MULTIPATH)
for (t = r->mp_next; t; t = t->mp_next)
if (t->neigh)
t->neigh->data = NULL;
WALK_LIST(t, n->iface_routes)
if (static_same_net(r, t))
goto found;

View File

@ -158,12 +158,14 @@ sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa,
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)
if ((setkey_md5(&src, &dst, passwd, SADB_ADD) < 0) ||
(setkey_md5(&dst, &src, 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)
if ((setkey_md5(&src, &dst, NULL, SADB_DELETE) < 0) ||
(setkey_md5(&dst, &src, NULL, SADB_DELETE) < 0))
ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
}
return 0;

View File

@ -12,6 +12,11 @@
#include <sys/param.h>
#ifdef __FreeBSD__
/* Should be defined in sysdep/cf/bsd.h, but it is flavor-specific */
#define CONFIG_DONTROUTE_UNICAST
#endif
#ifdef __NetBSD__
#ifndef IP_RECVTTL

View File

@ -11,6 +11,7 @@ CONFIG_MC_PROPER_SRC Multicast packets have source address according to socket s
CONFIG_SKIP_MC_BIND Don't call bind on multicast socket (def for *BSD)
CONFIG_NO_IFACE_BIND Bind to iface is not available, use workarounds (def for *BSD)
CONFIG_UNIX_DONTROUTE Use setsockopts DONTROUTE (undef for *BSD)
CONFIG_DONTROUTE_UNICAST Use MSG_DONTROUTE flag for unicast packets (def for FreeBSD)
CONFIG_USE_HDRINCL Use IP_HDRINCL instead of control messages for source address on raw IP sockets.
CONFIG_RESTRICTED_PRIVILEGES Implements restricted privileges using drop_uid()

View File

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

View File

@ -939,22 +939,25 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
struct {
struct nlmsghdr h;
struct rtmsg r;
char buf[128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops)];
} r;
char buf[0];
} *r;
uint rsize = sizeof(*r) + 128 + KRT_METRICS_MAX*8 + nh_bufsize(a->nexthops);
r = alloca(rsize);
DBG("nl_send_route(%I/%d,op=%x)\n", net->n.prefix, net->n.pxlen, op);
bzero(&r.h, sizeof(r.h));
bzero(&r.r, sizeof(r.r));
r.h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
r.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
r.h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
bzero(&r->h, sizeof(r->h));
bzero(&r->r, sizeof(r->r));
r->h.nlmsg_type = op ? RTM_NEWROUTE : RTM_DELROUTE;
r->h.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
r.r.rtm_family = BIRD_AF;
r.r.rtm_dst_len = net->n.pxlen;
r.r.rtm_protocol = RTPROT_BIRD;
r.r.rtm_scope = RT_SCOPE_NOWHERE;
nl_add_attr_ipa(&r.h, sizeof(r), RTA_DST, net->n.prefix);
r->r.rtm_family = BIRD_AF;
r->r.rtm_dst_len = net->n.pxlen;
r->r.rtm_protocol = RTPROT_BIRD;
r->r.rtm_scope = RT_SCOPE_NOWHERE;
nl_add_attr_ipa(&r->h, rsize, RTA_DST, net->n.prefix);
/*
* Strange behavior for RTM_DELROUTE:
@ -964,9 +967,9 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
*/
if (krt_table_id(p) < 256)
r.r.rtm_table = krt_table_id(p);
r->r.rtm_table = krt_table_id(p);
else
nl_add_attr_u32(&r.h, sizeof(r), RTA_TABLE, krt_table_id(p));
nl_add_attr_u32(&r->h, rsize, RTA_TABLE, krt_table_id(p));
if (a->source == RTS_DUMMY)
priority = e->u.krt.metric;
@ -976,7 +979,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
priority = ea->u.data;
if (priority)
nl_add_attr_u32(&r.h, sizeof(r), RTA_PRIORITY, priority);
nl_add_attr_u32(&r->h, rsize, RTA_PRIORITY, priority);
/* For route delete, we do not specify remaining route attributes */
if (op == NL_OP_DELETE)
@ -984,15 +987,15 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
/* Default scope is LINK for device routes, UNIVERSE otherwise */
if (ea = ea_find(eattrs, EA_KRT_SCOPE))
r.r.rtm_scope = ea->u.data;
r->r.rtm_scope = ea->u.data;
else
r.r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
r->r.rtm_scope = (dest == RTD_DEVICE) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
if (ea = ea_find(eattrs, EA_KRT_PREFSRC))
nl_add_attr_ipa(&r.h, sizeof(r), RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
if (ea = ea_find(eattrs, EA_KRT_REALM))
nl_add_attr_u32(&r.h, sizeof(r), RTA_FLOW, ea->u.data);
nl_add_attr_u32(&r->h, rsize, RTA_FLOW, ea->u.data);
u32 metrics[KRT_METRICS_MAX];
@ -1007,7 +1010,7 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
}
if (metrics[0])
nl_add_metrics(&r.h, sizeof(r), metrics, KRT_METRICS_MAX);
nl_add_metrics(&r->h, rsize, metrics, KRT_METRICS_MAX);
dest:
@ -1015,26 +1018,26 @@ dest:
switch (dest)
{
case RTD_ROUTER:
r.r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
nl_add_attr_ipa(&r.h, sizeof(r), RTA_GATEWAY, gw);
r->r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
nl_add_attr_ipa(&r->h, rsize, RTA_GATEWAY, gw);
break;
case RTD_DEVICE:
r.r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r.h, sizeof(r), RTA_OIF, iface->index);
r->r.rtm_type = RTN_UNICAST;
nl_add_attr_u32(&r->h, rsize, RTA_OIF, iface->index);
break;
case RTD_BLACKHOLE:
r.r.rtm_type = RTN_BLACKHOLE;
r->r.rtm_type = RTN_BLACKHOLE;
break;
case RTD_UNREACHABLE:
r.r.rtm_type = RTN_UNREACHABLE;
r->r.rtm_type = RTN_UNREACHABLE;
break;
case RTD_PROHIBIT:
r.r.rtm_type = RTN_PROHIBIT;
r->r.rtm_type = RTN_PROHIBIT;
break;
case RTD_MULTIPATH:
r.r.rtm_type = RTN_UNICAST;
nl_add_multipath(&r.h, sizeof(r), a->nexthops);
r->r.rtm_type = RTN_UNICAST;
nl_add_multipath(&r->h, rsize, a->nexthops);
break;
case RTD_NONE:
break;
@ -1043,7 +1046,7 @@ dest:
}
/* Ignore missing for DELETE */
return nl_exchange(&r.h, (op == NL_OP_DELETE));
return nl_exchange(&r->h, (op == NL_OP_DELETE));
}
static inline int
@ -1750,4 +1753,4 @@ kif_sys_start(struct kif_proto *p UNUSED)
void
kif_sys_shutdown(struct kif_proto *p UNUSED)
{
}
}

View File

@ -42,9 +42,9 @@ syslog_name:
log_file:
text {
FILE *f = tracked_fopen(new_config->pool, $1, "a");
struct rfile *f = rf_open(new_config->pool, $1, "a");
if (!f) cf_error("Unable to open log file `%s': %m", $1);
$$ = f;
$$ = rf_file(f);
}
| SYSLOG syslog_name { $$ = NULL; new_config->syslog_name = $2; }
| STDERR { $$ = stderr; }
@ -78,9 +78,9 @@ CF_ADDTO(conf, mrtdump_base)
mrtdump_base:
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
| MRTDUMP text ';' {
FILE *f = tracked_fopen(new_config->pool, $2, "a");
struct rfile *f = rf_open(new_config->pool, $2, "a");
if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
new_config->mrtdump_file = fileno(f);
new_config->mrtdump_file = rf_fileno(f);
}
;

View File

@ -54,6 +54,7 @@
this to gen small latencies */
#define MAX_RX_STEPS 4
/*
* Tracked Files
*/
@ -88,19 +89,32 @@ static struct resclass rf_class = {
NULL
};
void *
tracked_fopen(pool *p, char *name, char *mode)
struct rfile *
rf_open(pool *p, char *name, char *mode)
{
FILE *f = fopen(name, mode);
if (f)
{
struct rfile *r = ralloc(p, &rf_class);
r->f = f;
}
return f;
if (!f)
return NULL;
struct rfile *r = ralloc(p, &rf_class);
r->f = f;
return r;
}
void *
rf_file(struct rfile *f)
{
return f->f;
}
int
rf_fileno(struct rfile *f)
{
return fileno(f->f);
}
/**
* DOC: Timers
*
@ -478,6 +492,20 @@ tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t)
strcpy(x, "<too-long>");
}
int
tm_format_real_time(char *x, size_t max, const char *fmt, bird_clock_t t)
{
struct tm tm;
if (!localtime_r(&t, &tm))
return 0;
if (!strftime(x, max, fmt, &tm))
return 0;
return 1;
}
/**
* DOC: Sockets
@ -1574,6 +1602,7 @@ sk_sendmsg(sock *s)
struct iovec iov = {s->tbuf, s->tpos - s->tbuf};
byte cmsg_buf[CMSG_TX_SPACE];
sockaddr dst;
int flags = 0;
sockaddr_fill(&dst, s->af, s->daddr, s->iface, s->dport);
@ -1584,6 +1613,13 @@ sk_sendmsg(sock *s)
.msg_iovlen = 1
};
#ifdef CONFIG_DONTROUTE_UNICAST
/* FreeBSD silently changes TTL to 1 when MSG_DONTROUTE is used, therefore we
cannot use it for other cases (e.g. when TTL security is used). */
if (ipa_is_ip4(s->daddr) && ip4_is_unicast(ipa_to_ip4(s->daddr)) && (s->ttl == 1))
flags = MSG_DONTROUTE;
#endif
#ifdef CONFIG_USE_HDRINCL
byte hdr[20];
struct iovec iov2[2] = { {hdr, 20}, iov };
@ -1599,7 +1635,7 @@ sk_sendmsg(sock *s)
if (s->flags & SKF_PKTINFO)
sk_prepare_cmsgs(s, &msg, cmsg_buf, sizeof(cmsg_buf));
return sendmsg(s->fd, &msg, 0);
return sendmsg(s->fd, &msg, flags);
}
static inline int

View File

@ -24,7 +24,7 @@
#include "nest/bird.h"
#include "nest/cli.h"
#include "nest/mrtdump.h"
#include "conf/conf.h"
#include "lib/string.h"
#include "lib/lists.h"
#include "lib/unix.h"
@ -242,14 +242,23 @@ die(const char *msg, ...)
void
debug(const char *msg, ...)
{
#define MAX_DEBUG_BUFSIZE 65536
va_list args;
char buf[1024];
static uint bufsize = 4096;
static char *buf = NULL;
if (!buf)
buf = mb_alloc(&root_pool, bufsize);
va_start(args, msg);
if (dbgf)
{
if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
while (bvsnprintf(buf, bufsize, msg, args) < 0)
if (bufsize >= MAX_DEBUG_BUFSIZE)
bug("Extremely long debug output, split it.");
else
buf = mb_realloc(buf, (bufsize *= 2));
fputs(buf, dbgf);
}
va_end(args);
@ -285,12 +294,14 @@ log_switch(int debug, list *l, char *new_syslog_name)
if (!l || EMPTY_LIST(*l))
l = default_log_list(debug, !l, &new_syslog_name);
log_lock();
current_log_list = l;
#ifdef HAVE_SYSLOG_H
if (current_syslog_name && new_syslog_name &&
!strcmp(current_syslog_name, new_syslog_name))
return;
goto done;
if (current_syslog_name)
{
@ -305,6 +316,9 @@ log_switch(int debug, list *l, char *new_syslog_name)
openlog(current_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
}
#endif
done:
log_unlock();
}
@ -327,16 +341,3 @@ log_init_debug(char *f)
if (dbgf)
setvbuf(dbgf, NULL, _IONBF, 0);
}
void
mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
{
/* Prepare header */
put_u32(buf+0, now_real);
put_u16(buf+4, type);
put_u16(buf+6, subtype);
put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
if (p->cf->global->mrtdump_file != -1)
write(p->cf->global->mrtdump_file, buf, len);
}

View File

@ -212,7 +212,7 @@ read_config(void)
if (!unix_read_config(&conf, config_name))
{
if (conf->err_msg)
die("%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
die("%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
else
die("Unable to open configuration file %s: %m", config_name);
}
@ -229,7 +229,7 @@ async_config(void)
if (!unix_read_config(&conf, config_name))
{
if (conf->err_msg)
log(L_ERR "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
log(L_ERR "%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
else
log(L_ERR "Unable to open configuration file %s: %m", config_name);
config_free(conf);
@ -250,7 +250,7 @@ cmd_read_config(char *name)
if (!unix_read_config(&conf, name))
{
if (conf->err_msg)
cli_msg(8002, "%s, line %d: %s", conf->err_file_name, conf->err_lino, conf->err_msg);
cli_msg(8002, "%s:%d:%d %s", conf->err_file_name, conf->err_lino, conf->err_chno, conf->err_msg);
else
cli_msg(8002, "%s: %m", name);
config_free(conf);

View File

@ -74,8 +74,9 @@ bird_clock_t tm_parse_date(char *); /* Convert date to bird_clock_t */
bird_clock_t tm_parse_datetime(char *); /* Convert date to bird_clock_t */
#define TM_DATETIME_BUFFER_SIZE 32 /* Buffer size required by tm_format_datetime */
void
tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t);
void tm_format_datetime(char *x, struct timeformat *fmt_spec, bird_clock_t t);
int tm_format_real_time(char *x, size_t max, const char *fmt, bird_clock_t t);
#define TIME_T_IS_64BIT (sizeof(time_t) == 8)
#define TIME_T_IS_SIGNED ((time_t) -1 < 0)

View File

@ -14,6 +14,7 @@
struct pool;
struct iface;
struct birdsock;
struct rfile;
/* main.c */
@ -95,15 +96,17 @@ int sockaddr_read(sockaddr *sa, int af, ip_addr *a, struct iface **ifa, uint *po
#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path))
#endif
volatile int async_config_flag;
volatile int async_dump_flag;
volatile int async_shutdown_flag;
extern volatile int async_config_flag;
extern volatile int async_dump_flag;
extern volatile int async_shutdown_flag;
void io_init(void);
void io_loop(void);
void io_log_dump(void);
int sk_open_unix(struct birdsock *s, char *name);
void *tracked_fopen(struct pool *, char *name, char *mode);
struct rfile *rf_open(struct pool *, char *name, char *mode);
void *rf_file(struct rfile *f);
int rf_fileno(struct rfile *f);
void test_old_bird(char *path);

View File

@ -71,7 +71,7 @@ tags:
cd $(srcdir) ; etags -lc `find $(static-dirs) $(addprefix $(objdir)/,$(dynamic-dirs)) $(client-dirs) -name *.[chY]`
install: all
$(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/@runtimedir@
$(INSTALL) -d $(DESTDIR)/$(sbindir) $(DESTDIR)/$(sysconfdir) $(DESTDIR)/$(runstatedir)
$(INSTALL_PROGRAM) $(exedir)/bird $(DESTDIR)/$(sbindir)/bird@SUFFIX@
$(INSTALL_PROGRAM) $(exedir)/birdcl $(DESTDIR)/$(sbindir)/birdcl@SUFFIX@
if test -n "@CLIENT@" ; then \

View File

@ -39,6 +39,7 @@ bindir=@bindir@
sbindir=@sbindir@
sysconfdir=@sysconfdir@
localstatedir=@localstatedir@
runstatedir=@runstatedir@
docdir=@prefix@/doc
ifdef source

1233
tools/config.guess vendored

File diff suppressed because it is too large Load Diff

583
tools/config.sub vendored

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
#
set -e
AC=`if [ -x /usr/bin/autoconf2.50 ] ; then echo autoconf2.50 ; else echo autoconf ; fi`
AC=autoreconf
$AC
./configure
make distclean
@ -22,7 +22,7 @@ mkdir -p $T/$REL $T/$DREL $T/$DREL/doc
cp -a . $T/$REL
echo Generating ChangeLog
git log >$T/$REL/ChangeLog
mv $T/$REL/doc/*.ps $T/$DREL/doc
mv $T/$REL/doc/*.pdf $T/$DREL/doc
rm -f $T/$REL/bird.conf*
rm -rf $T/$REL/.git/
rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides}

View File

@ -3,9 +3,7 @@
$srcdir = $ARGV[0];
open(OUT, ">prog.sgml") || die "Cannot create output file";
include("doc/prog-head.sgml");
process("");
include("doc/prog-foot.sgml");
process("", "doc/prog-root");
close OUT;
exit 0;
@ -20,8 +18,9 @@ sub include {
sub process {
my $dir = shift @_;
print "$dir/Doc\n";
open(IN, "$srcdir/$dir/Doc") || die "Unable to read $dir/Doc";
my $doc = "$dir/" . shift @_;
print "$doc\n";
open(IN, "$srcdir/$doc") || die "Unable to read $doc";
my @docfile = <IN>;
close IN;
foreach $_ (@docfile) {
@ -30,7 +29,7 @@ sub process {
/^([A-Z]+)\s*(.*)/ || die "Parse error: $_";
$cmd = $1;
$arg = $2;
if ($cmd eq "C") { process("$dir/$arg"); }
if ($cmd eq "C") { process("$dir/$arg", "Doc"); }
elsif ($cmd eq "H") {
push @stack, "H";
print OUT "<chapt>$arg\n";