aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@debian.org>2019-09-16 16:01:02 +0200
committerOndřej Surý <ondrej@debian.org>2019-09-16 16:01:02 +0200
commitc76f25056e140470b62a6494eb29a2e19d06c739 (patch)
tree69847344945c07dbde5cfe4378b90fc5697cdd5d
parent35d302e9115c26cc136fcc1b89fa77f73d87978e (diff)
downloadbird-c76f25056e140470b62a6494eb29a2e19d06c739.tar.gz
New upstream version 2.0.6
-rw-r--r--ChangeLog165
-rw-r--r--NEWS7
-rwxr-xr-xconfigure179
-rw-r--r--configure.ac27
-rw-r--r--doc/bird.pdfbin0 -> 356743 bytes
-rw-r--r--doc/bird.sgml19
-rw-r--r--doc/prog.pdfbin0 -> 456876 bytes
-rw-r--r--filter/config.Y32
-rw-r--r--filter/f-inst.c12
-rw-r--r--filter/f-util.c29
-rw-r--r--filter/test.conf14
-rw-r--r--lib/birdlib.h2
-rw-r--r--lib/bitops.h2
-rw-r--r--lib/socket.h2
-rw-r--r--nest/a-path.c31
-rw-r--r--nest/attrs.h6
-rw-r--r--nest/config.Y11
-rw-r--r--nest/proto.c36
-rw-r--r--nest/protocol.h8
-rw-r--r--nest/route.h1
-rw-r--r--nest/rt-table.c124
-rw-r--r--proto/bgp/attrs.c40
-rw-r--r--proto/bgp/bgp.c33
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/config.Y3
-rw-r--r--proto/bgp/packets.c135
-rw-r--r--proto/ospf/config.Y7
-rw-r--r--proto/radv/config.Y15
-rw-r--r--proto/radv/packets.c47
-rw-r--r--proto/radv/radv.c19
-rw-r--r--proto/radv/radv.h10
-rw-r--r--sysdep/config.h2
-rw-r--r--sysdep/unix/main.c3
33 files changed, 710 insertions, 313 deletions
diff --git a/ChangeLog b/ChangeLog
index 465e84e2..05608841 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,168 @@
+commit 5235c3f78da15826b0654ba68dc7a897faa42c98
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Sep 10 17:34:41 2019 +0200
+
+ NEWS and version update
+
+commit 532471967e6d92ae7a480367cc6d935cca75c7b2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Sep 10 17:28:06 2019 +0200
+
+ Doc: Update BGP mask documentation
+
+commit 452e90ba72f57c44b44f9940ac951d2fde417583
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Sep 10 13:45:18 2019 +0200
+
+ Filter: Fix crash with 'where' filters and function calls
+
+ The old 'where' code computed size value incorrectly, which leads
+ to invalid instruction lines and filter errors or crashes.
+
+commit 1127887a8b111dab18c592f1f3f575920f38bfe3
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Sep 9 13:17:30 2019 +0200
+
+ BGP: Fix handling of bgp_aggregator atttribute
+
+ The attribute should not be modifiable by filters as we do not
+ support its type.
+
+commit 8388f5a7e14108a1458fea35bfbb5a453e2c563c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Sep 9 03:13:35 2019 +0200
+
+ BGP: Fix bugs in handling of shutdown messages
+
+ There is an improper check for valid message size, which may lead to
+ stack overflow and buffer leaks to log when a large message is received.
+
+ Thanks to Daniel McCarney for bugreport and analysis.
+
+commit 56d8b1e7f6252158caf0ecd3147376b858b16d97
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Aug 29 20:58:16 2019 +0200
+
+ OSPF: Fix 'show ospf lsadb' cmd without proto arg
+
+ It crashed when used without protocol argument.
+
+ Thanks to Alexander for the bugreport.
+
+commit 32a254050d3da57ca6d7627aa606a8dce11907ee
+Author: Maria Matejka <mq@ucw.cz>
+Date: Mon Aug 26 21:53:56 2019 +0200
+
+ Channel refeed with import table splitting between routes for one prefix
+
+commit 5ab3447de18235de566eb5116c0aec24050f5f85
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Aug 21 17:30:00 2019 +0200
+
+ Sysdep: Drop supplementary groups when dropping GID
+
+ We forgot to do that. Oops.
+
+commit 4fa0e472cf3e8c61a3f67e91d201dbc12ea94221
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Aug 21 17:16:08 2019 +0200
+
+ BGP: Use reallocation for capability structure
+
+ Instead of having large stack buffer for max amount of AFI/SAFI pairs.
+ The old code is not correct w.r.t. extendeded option length, as more
+ AFI/SAFI pairs may fit into the capability option.
+
+commit 524d2538537b2530bf031daa1d5c8e4653f92c5c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 20 19:12:59 2019 +0200
+
+ BGP: Implement extended optional parameters length
+
+ Extends BGP options/capabilities data length to 16bit, to avoid issues
+ with too many capabilities. See draft-ietf-idr-ext-opt-param-07
+
+commit a297a4f044bcc7c38549710a720bc1f97df9ba65
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 13 18:57:40 2019 +0200
+
+ Nest: Fix crash in route reload when some channels are not up.
+
+ Only channels that are up can be reloaded.
+
+commit b7d7599ce3576f28310af18b403fed49a0840b67
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 13 18:22:07 2019 +0200
+
+ BGP: implement Adj-RIB-Out
+
+ The patch implements optional internal export table to a channel and
+ hooks it to BGP so it can be used as Adj-RIB-Out. When enabled, all
+ exported (post-filtered) routes are stored there. An export table can be
+ examined using e.g. 'show route export table bgp1.ipv4'.
+
+commit dfe63ed84d42178a53b01071c64f23250e74d6d9
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Aug 13 16:45:27 2019 +0200
+
+ Filter: Fixing empty block and never-executed-statement bug
+
+commit 70a4320bdd44122d7a93bc71c77a9d684b3c9adc
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Aug 12 00:41:36 2019 +0200
+
+ RAdv: Allow solicited RAs to be sent as unicast
+
+ Add option to send solicited router advertisements as unicast directly
+ to soliciting nodes instead of as multicast to all-nodes group.
+
+commit 9f3e09832081bc029dc98ae6dda49ee86d138fde
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 6 18:54:19 2019 +0200
+
+ Filter: Allow to use set constants / expressions in path masks
+
+ Allow to not only use set literals in path masks, but also existing
+ set constants or set expressions.
+
+commit ef113c6f725349a2ab52f3cbef18403f82c84134
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 6 16:58:13 2019 +0200
+
+ Filter: Allow to use sets in path masks
+
+commit e2b530aa729f9c5973e498b45dd6f55ab669d1ac
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 6 15:29:06 2019 +0200
+
+ BGP: Improve reconfiguration
+
+ Several BGP channel options (including 'next hop self') could be
+ reconfigured without session reset, with just route refeed/refresh.
+ The patch improves reconfiguration code to do it that way.
+
+commit f6a6a77640a9749c79a91300d130ba6b5941d408
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 6 15:09:42 2019 +0200
+
+ BGP: Fix 'deterministic med' to work with 'merge paths'
+
+ The 'deterministic med' option is implemented by suppressing other than
+ best-in-group routes (grouped by ASN) from best route selection. This
+ interferes with 'merge paths' as supressed routes are no longer mergable
+ with best route. This is fixed by suppressing only those routes that are
+ not mergable with best-in-group route.
+
+commit 8c42205e35e24537122a4c821bd3128d698abf1b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Aug 6 14:53:02 2019 +0200
+
+ Configure: CFLAGS update
+
+ - add -flto only to default CFLAGS
+ - add -fno-strict-aliasing, -fno-strict-overflow always
+ - remove -Wno-implicit-fallthrough
+
commit cc02da816fb062c93b4f0d61b0cfa02b673a5e00
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu Aug 1 14:49:03 2019 +0200
diff --git a/NEWS b/NEWS
index 4cf72365..a8caf519 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+Version 2.0.6 (2019-09-10)
+ o RAdv: Solicited unicast RAs
+ o BGP: Optional Adj-RIB-Out
+ o BGP: Extended optional parameters length
+ o Filter: Sets and set expressions in path masks
+ o Several important bugfixes
+
Version 2.0.5 (2019-08-01)
o OSPF Graceful restart (RFC 3623, RFC 5187)
o BGP: Dynamic BGP
diff --git a/configure b/configure
index 017d8092..7bc33b44 100755
--- a/configure
+++ b/configure
@@ -654,7 +654,6 @@ CFLAGS
CC
CONTROL_SOCKET
CONFIG_FILE
-runstatedir
srcdir
exedir
objdir
@@ -680,6 +679,7 @@ infodir
docdir
oldincludedir
includedir
+runstatedir
localstatedir
sharedstatedir
sysconfdir
@@ -764,6 +764,7 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
includedir='${prefix}/include'
oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}'
@@ -1016,6 +1017,15 @@ do
| -silent | --silent | --silen | --sile | --sil)
silent=yes ;;
+ -runstatedir | --runstatedir | --runstatedi | --runstated \
+ | --runstate | --runstat | --runsta | --runst | --runs \
+ | --run | --ru | --r)
+ ac_prev=runstatedir ;;
+ -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+ | --run=* | --ru=* | --r=*)
+ runstatedir=$ac_optarg ;;
+
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1153,7 +1163,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
- libdir localedir mandir
+ libdir localedir mandir runstatedir
do
eval ac_val=\$$ac_var
# Remove trailing slashes.
@@ -1306,6 +1316,7 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include]
@@ -4047,6 +4058,9 @@ $as_echo "#define USE_PTHREADS 1" >>confdefs.h
fi
fi
+# This is assumed to be necessary for proper BIRD build
+CFLAGS="$CFLAGS -fno-strict-aliasing -fno-strict-overflow"
+
if test "$bird_cflags_default" = yes ; then
bird_tmp_cflags="$CFLAGS"
@@ -4121,102 +4135,7 @@ $as_echo "$bird_cv_c_option_wno_missing_init" >&6; }
CFLAGS="$bird_tmp_cflags"
- bird_tmp_cflags="$CFLAGS"
- CFLAGS=" -fno-strict-aliasing"
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -fno-strict-aliasing" >&5
-$as_echo_n "checking whether CC supports -fno-strict-aliasing... " >&6; }
-if ${bird_cv_c_option_fno_strict_aliasing+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- bird_cv_c_option_fno_strict_aliasing=yes
-else
- bird_cv_c_option_fno_strict_aliasing=no
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_fno_strict_aliasing" >&5
-$as_echo "$bird_cv_c_option_fno_strict_aliasing" >&6; }
-
- CFLAGS="$bird_tmp_cflags"
-
-
- bird_tmp_cflags="$CFLAGS"
- CFLAGS=" -fno-strict-overflow"
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -fno-strict-overflow" >&5
-$as_echo_n "checking whether CC supports -fno-strict-overflow... " >&6; }
-if ${bird_cv_c_option_fno_strict_overflow+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- bird_cv_c_option_fno_strict_overflow=yes
-else
- bird_cv_c_option_fno_strict_overflow=no
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_fno_strict_overflow" >&5
-$as_echo "$bird_cv_c_option_fno_strict_overflow" >&6; }
-
- CFLAGS="$bird_tmp_cflags"
-
-
- CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses"
-
- if test "$bird_cv_c_option_wno_pointer_sign" = yes ; then
- CFLAGS="$CFLAGS -Wno-pointer-sign"
- fi
-
-
- if test "$bird_cv_c_option_wno_missing_init" = yes ; then
- CFLAGS="$CFLAGS -Wno-missing-field-initializers"
- fi
-
-
- if test "$bird_cv_c_option_fno_strict_aliasing" = yes ; then
- CFLAGS="$CFLAGS -fno-strict-aliasing"
- fi
-
-
- if test "$bird_cv_c_option_fno_strict_overflow" = yes ; then
- CFLAGS="$CFLAGS -fno-strict-overflow"
- fi
-
-fi
-
-if test "$enable_debug" = no; then
+ if test "$enable_debug" = no; then
bird_tmp_cflags="$CFLAGS"
bird_tmp_ldflags="$LDFLAGS"
@@ -4257,13 +4176,27 @@ $as_echo "$bird_cv_c_lto" >&6; }
CFLAGS="$bird_tmp_cflags"
LDFLAGS="$bird_tmp_ldflags"
-fi
+ fi
+
+ if test "$bird_cv_c_lto" = yes; then
+ CFLAGS="$CFLAGS -flto"
+ LDFLAGS="$LDFLAGS -flto=4"
+ fi
+
+ CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses"
+
+ if test "$bird_cv_c_option_wno_pointer_sign" = yes ; then
+ CFLAGS="$CFLAGS -Wno-pointer-sign"
+ fi
+
+
+ if test "$bird_cv_c_option_wno_missing_init" = yes ; then
+ CFLAGS="$CFLAGS -Wno-missing-field-initializers"
+ fi
-if test "$bird_cv_c_lto" = yes; then
- CFLAGS="$CFLAGS -flto"
- LDFLAGS="$LDFLAGS -flto=4"
fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS" >&5
$as_echo_n "checking CFLAGS... " >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLAGS" >&5
@@ -5901,48 +5834,6 @@ fi
fi
fi
-else
-
- bird_tmp_cflags="$CFLAGS"
- CFLAGS=" -Wno-implicit-fallthrough"
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-implicit-fallthrough" >&5
-$as_echo_n "checking whether CC supports -Wno-implicit-fallthrough... " >&6; }
-if ${bird_cv_c_option_wno_implicit_fallthrough+:} false; then :
- $as_echo_n "(cached) " >&6
-else
-
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- bird_cv_c_option_wno_implicit_fallthrough=yes
-else
- bird_cv_c_option_wno_implicit_fallthrough=no
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_implicit_fallthrough" >&5
-$as_echo "$bird_cv_c_option_wno_implicit_fallthrough" >&6; }
-
- CFLAGS="$bird_tmp_cflags"
-
-
- if test "$bird_cv_c_option_wno_implicit_fallthrough" = yes ; then
- CFLAGS="$CFLAGS -Wno-implicit-fallthrough"
- fi
-
fi
CLIENT=birdcl
diff --git a/configure.ac b/configure.ac
index 14dbcd52..7e8578ab 100644
--- a/configure.ac
+++ b/configure.ac
@@ -137,27 +137,27 @@ if test "$enable_pthreads" != no ; then
fi
fi
+# This is assumed to be necessary for proper BIRD build
+CFLAGS="$CFLAGS -fno-strict-aliasing -fno-strict-overflow"
+
if test "$bird_cflags_default" = yes ; then
BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_pointer_sign], [-Wno-pointer-sign], [-Wall])
BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers], [-Wall -Wextra])
- BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing])
- BIRD_CHECK_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow])
+
+ if test "$enable_debug" = no; then
+ BIRD_CHECK_LTO
+ fi
+
+ if test "$bird_cv_c_lto" = yes; then
+ CFLAGS="$CFLAGS -flto"
+ LDFLAGS="$LDFLAGS -flto=4"
+ fi
CFLAGS="$CFLAGS -Wall -Wextra -Wstrict-prototypes -Wno-parentheses"
BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_pointer_sign], [-Wno-pointer-sign])
BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_missing_init], [-Wno-missing-field-initializers])
- BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_aliasing], [-fno-strict-aliasing])
- BIRD_ADD_GCC_OPTION([bird_cv_c_option_fno_strict_overflow], [-fno-strict-overflow])
fi
-if test "$enable_debug" = no; then
- BIRD_CHECK_LTO
-fi
-
-if test "$bird_cv_c_lto" = yes; then
- CFLAGS="$CFLAGS -flto"
- LDFLAGS="$LDFLAGS -flto=4"
-fi
AC_MSG_CHECKING([CFLAGS])
AC_MSG_RESULT([$CFLAGS])
@@ -387,9 +387,6 @@ if test "$enable_debug" = yes ; then
AC_CHECK_LIB([efence], [malloc])
fi
fi
-else
- BIRD_CHECK_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough])
- BIRD_ADD_GCC_OPTION([bird_cv_c_option_wno_implicit_fallthrough], [-Wno-implicit-fallthrough])
fi
CLIENT=birdcl
diff --git a/doc/bird.pdf b/doc/bird.pdf
new file mode 100644
index 00000000..113c0ec2
--- /dev/null
+++ b/doc/bird.pdf
Binary files differ
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 83dec4f8..cb90e615 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -1473,7 +1473,8 @@ foot).
but <tt>bgp_path &tilde; [= * 4 5 * =]</tt> is false. BGP mask
expressions can also contain integer expressions enclosed in parenthesis
and integer variables, for example <tt>[= * 4 (1+2) a =]</tt>. You can
- also use ranges, for example <tt>[= * 3..5 2 100..200 * =]</tt>.
+ also use ranges (e.g. <tt>[= * 3..5 2 100..200 * =]</tt>) and sets
+ (e.g. <tt>[= 1 2 [3, 5, 7] * =]</tt>).
<tag><label id="type-clist">clist</tag>
Clist is similar to a set, except that unlike other sets, it can be
@@ -2705,6 +2706,16 @@ be used in explicit configuration.
be examined later by <cf/show route/, and can be used to reconfigure
import filters without full route refresh. Default: off.
+ <tag><label id="bgp-export-table">export table <m/switch/</tag>
+ A BGP export table contains all routes sent to given BGP neighbor, after
+ application of export filters. It is also called <em/Adj-RIB-Out/ in BGP
+ terminology. BIRD BGP by default operates without export tables, in
+ which case routes from master table are just processed by export filters
+ and then announced by BGP. Enabling <cf/export table/ allows to store
+ routes after export filter processing, so they can be examined later by
+ <cf/show route/, and can be used to eliminate unnecessary updates or
+ withdraws. Default: off.
+
<tag><label id="bgp-secondary">secondary <m/switch/</tag>
Usually, if an export filter rejects a selected route, no other route is
propagated for that network. This option allows to try the next route in
@@ -4121,6 +4132,12 @@ definitions, prefix definitions and DNS definitions:
The minimum delay between two consecutive router advertisements, in
seconds. Default: 3
+ <tag><label id="radv-solicited-ra-unicast">solicited ra unicast <m/switch/</tag>
+ Solicited router advertisements are usually sent to all-nodes multicast
+ group like unsolicited ones, but the router can be configured to send
+ them as unicast directly to soliciting nodes instead. This is especially
+ useful on wireless networks (see <rfc id="7772">). Default: no
+
<tag><label id="radv-iface-managed">managed <m/switch/</tag>
This option specifies whether hosts should use DHCPv6 for IP address
configuration. Default: no
diff --git a/doc/prog.pdf b/doc/prog.pdf
new file mode 100644
index 00000000..3d2ba378
--- /dev/null
+++ b/doc/prog.pdf
Binary files differ
diff --git a/filter/config.Y b/filter/config.Y
index 8171a7c2..340053ba 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -446,7 +446,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN
%nonassoc ELSE
-%type <xp> cmds_int
+%type <xp> cmds_int cmd_prep
%type <x> term block cmd cmds constant constructor print_list var_list function_call symbol_value bgp_path_expr bgp_path bgp_path_tail
%type <fda> dynamic_attr
%type <fsa> static_attr
@@ -624,17 +624,25 @@ cmds: /* EMPTY */ { $$ = NULL; }
| cmds_int { $$ = $1.begin; }
;
-cmds_int: cmd {
+cmd_prep: cmd {
$$.begin = $$.end = $1;
- while ($$.end->next)
- $$.end = $$.end->next;
+ if ($1)
+ while ($$.end->next)
+ $$.end = $$.end->next;
+}
+ ;
+
+cmds_int: cmd_prep
+ | cmds_int cmd_prep {
+ if (!$1.begin)
+ $$ = $2;
+ else if (!$2.begin)
+ $$ = $1;
+ else {
+ $$.begin = $1.begin;
+ $$.end = $2.end;
+ $1.end->next = $2.begin;
}
- | cmds_int cmd {
- $$.begin = $1.begin;
- $1.end->next = $2;
- $$.end = $2;
- while ($$.end->next)
- $$.end = $$.end->next;
}
;
@@ -801,6 +809,10 @@ bgp_path:
bgp_path_tail:
NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .asn = $1, .kind = PM_ASN, }, }); $$->next = $2; }
| NUM DDOT NUM bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .from = $1, .to = $3, .kind = PM_ASN_RANGE }, }); $$->next = $4; }
+ | '[' set_items ']' bgp_path_tail {
+ if ($2->from.type != T_INT) cf_error("Only integer sets allowed in path mask");
+ $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .set = build_tree($2), .kind = PM_ASN_SET }, }); $$->next = $4;
+ }
| '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
| '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
| bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 0867ac4a..49ae993a 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -308,12 +308,24 @@
case T_PATH_MASK_ITEM:
pm->item[i] = vv(i).val.pmi;
break;
+
case T_INT:
pm->item[i] = (struct f_path_mask_item) {
.asn = vv(i).val.i,
.kind = PM_ASN,
};
break;
+
+ case T_SET:
+ if (vv(i).val.t->from.type != T_INT)
+ runtime("Only integer sets allowed in path mask");
+
+ pm->item[i] = (struct f_path_mask_item) {
+ .set = vv(i).val.t,
+ .kind = PM_ASN_SET,
+ };
+ break;
+
default:
runtime( "Error resolving path mask template: value not an integer" );
}
diff --git a/filter/f-util.c b/filter/f-util.c
index e61949f2..410999a6 100644
--- a/filter/f-util.c
+++ b/filter/f-util.c
@@ -32,33 +32,12 @@ filter_name(const struct filter *filter)
struct filter *f_new_where(struct f_inst *where)
{
- struct f_inst acc = {
- .fi_code = FI_DIE,
- .lineno = ifs->lino,
- .size = 1,
- .i_FI_DIE = { .fret = F_ACCEPT, },
- };
-
- struct f_inst rej = {
- .fi_code = FI_DIE,
- .lineno = ifs->lino,
- .size = 1,
- .i_FI_DIE = { .fret = F_REJECT, },
- };
-
- struct f_inst i = {
- .fi_code = FI_CONDITION,
- .lineno = ifs->lino,
- .size = 3 + where->size,
- .i_FI_CONDITION = {
- .f1 = where,
- .f2 = &acc,
- .f3 = &rej,
- },
- };
+ struct f_inst *cond = f_new_inst(FI_CONDITION, where,
+ f_new_inst(FI_DIE, F_ACCEPT),
+ f_new_inst(FI_DIE, F_REJECT));
struct filter *f = cfg_allocz(sizeof(struct filter));
- f->root = f_linearize(&i);
+ f->root = f_linearize(cond);
return f;
}
diff --git a/filter/test.conf b/filter/test.conf
index 9abd76f3..b1342819 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -597,11 +597,15 @@ function mkpath(int a; int b)
return [= a b 3 2 1 =];
}
+define set35 = [3 .. 5];
+
function t_path()
bgpmask pm1;
bgppath p2;
+int set set12;
{
pm1 = [= 4 3 2 1 =];
+ set12 = [1, 2];
bt_assert(format(pm1) = "[= 4 3 2 1 =]");
@@ -626,6 +630,8 @@ bgppath p2;
bt_assert(p2 !~ [8, ten..(2*ten)]);
bt_assert(p2 ~ [= * 4 3 * 1 =]);
bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]);
+ bt_assert(p2 ~ [= 5 [2, 4, 6] 3 [1..2] 1 =]);
+ bt_assert(p2 ~ [= 5 set35 3 set12 set12 =]);
bt_assert(p2 ~ mkpath(5, 4));
bt_assert(p2.len = 5);
@@ -1172,6 +1178,10 @@ bt_test_suite(t_include, "Testing including another config file");
function t_if_else()
int i;
{
+ /* Empty blocks regression test */
+ if true then {}
+ else {}
+
if true then
bt_assert(true);
@@ -1181,6 +1191,10 @@ int i;
bt_assert(true);
else
bt_assert(false);
+
+ /* Empty blocks regression test */
+ if true then {}
+ else {}
}
bt_test_suite(t_if_else, "Testing if-else statement");
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 30ea433c..5202b0c8 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -38,7 +38,7 @@ struct align_probe { char x; long int y; };
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
#define BYTES(n) ((((uint) (n)) + 7) / 8)
#define CALL(fn, args...) ({ if (fn) fn(args); })
-#define ADVANCE(w, r, l) ({ r -= l; w += l; })
+#define ADVANCE(w, r, l) ({ r -= (l); w += (l); })
static inline int uint_cmp(uint i1, uint i2)
{ return (int)(i1 > i2) - (int)(i1 < i2); }
diff --git a/lib/bitops.h b/lib/bitops.h
index af648c26..39ade388 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -29,4 +29,6 @@ static inline u32 u32_hash(u32 v) { return v * 2902958171u; }
static inline u8 u32_popcount(u32 v) { return __builtin_popcount(v); }
+static inline int uint_is_pow2(uint n) { return n && !(n & (n-1)); }
+
#endif
diff --git a/lib/socket.h b/lib/socket.h
index e53ec5ba..03c15dcd 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -97,7 +97,7 @@ void sk_dump_all(void);
int sk_is_ipv4(sock *s); /* True if socket is IPv4 */
int sk_is_ipv6(sock *s); /* True if socket is IPv6 */
-static inline int sk_send_buffer_empty(sock *sk)
+static inline int sk_tx_buffer_empty(sock *sk)
{ return sk->tbuf == sk->tpos; }
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
diff --git a/nest/a-path.c b/nest/a-path.c
index a1b7c42f..b6a30f54 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -740,6 +740,31 @@ pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
return 0;
}
+static int
+pm_match_set(struct pm_pos *pos, const struct f_tree *set)
+{
+ struct f_val asn = { .type = T_INT };
+
+ if (! pos->set)
+ {
+ asn.val.i = pos->val.asn;
+ return !!find_tree(set, &asn);
+ }
+
+ const u8 *p = pos->val.sp;
+ int len = *p++;
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ asn.val.i = get_as(p + i * BS);
+ if (find_tree(set, &asn))
+ return 1;
+ }
+
+ return 0;
+}
+
static void
pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
{
@@ -824,13 +849,17 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
val2 = mask->item[m].to;
goto step;
case PM_QUESTION:
+ case PM_ASN_SET:
step:
nh = nl = -1;
for (i = h; i >= l; i--)
if (pos[i].mark)
{
pos[i].mark = 0;
- if ((mask->item[m].kind == PM_QUESTION) || pm_match(pos + i, val, val2))
+ if ((mask->item[m].kind == PM_QUESTION) ||
+ ((mask->item[m].kind != PM_ASN_SET) ?
+ pm_match(pos + i, val, val2) :
+ pm_match_set(pos + i, mask->item[m].set)))
pm_mark(pos, i, plen, &nl, &nh);
}
diff --git a/nest/attrs.h b/nest/attrs.h
index 4efcff79..6fb0a8fa 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -60,16 +60,18 @@ static inline struct adata *as_path_prepend(struct linpool *pool, const struct a
#define PM_ASTERISK 2
#define PM_ASN_EXPR 3
#define PM_ASN_RANGE 4
+#define PM_ASN_SET 5
struct f_path_mask_item {
union {
u32 asn; /* PM_ASN */
- struct f_line *expr; /* PM_ASN_EXPR */
+ const struct f_line *expr; /* PM_ASN_EXPR */
+ const struct f_tree *set; /* PM_ASN_SET */
struct { /* PM_ASN_RANGE */
u32 from;
u32 to;
};
- };
+ };
int kind;
};
diff --git a/nest/config.Y b/nest/config.Y
index e1a932d4..c62501a3 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -567,6 +567,17 @@ r_args:
rt_show_add_table($$, c->in_table);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
+ | r_args EXPORT TABLE CF_SYM_KNOWN '.' r_args_channel {
+ cf_assert_symbol($4, SYM_PROTO);
+ $$ = $1;
+ struct proto_config *cf = $4->proto;
+ if (!cf->proto) cf_error("%s is not a protocol", $4->name);
+ struct channel *c = proto_find_channel_by_name(cf->proto, $6);
+ if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
+ if (!c->out_table) cf_error("No export table in channel %s.%s", $4->name, $6);
+ rt_show_add_table($$, c->out_table);
+ $$->tables_defined_by = RSD_TDB_DIRECT;
+ }
| r_args FILTER filter {
$$ = $1;
if ($$->filter != FILTER_ACCEPT) cf_error("Filter specified twice");
diff --git a/nest/proto.c b/nest/proto.c
index 2fb4e96f..6beca56d 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -317,6 +317,13 @@ channel_reset_import(struct channel *c)
rt_prune_sync(c->in_table, 1);
}
+static void
+channel_reset_export(struct channel *c)
+{
+ /* Just free the routes */
+ rt_prune_sync(c->out_table, 1);
+}
+
/* Called by protocol to activate in_table */
void
channel_setup_in_table(struct channel *c)
@@ -331,6 +338,18 @@ channel_setup_in_table(struct channel *c)
c->reload_event = ev_new_init(c->proto->pool, channel_reload_loop, c);
}
+/* Called by protocol to activate out_table */
+void
+channel_setup_out_table(struct channel *c)
+{
+ struct rtable_config *cf = mb_allocz(c->proto->pool, sizeof(struct rtable_config));
+ cf->name = "export";
+ cf->addr_type = c->net_type;
+
+ c->out_table = mb_allocz(c->proto->pool, sizeof(struct rtable));
+ rt_setup(c->proto->pool, c->out_table, cf);
+}
+
static void
channel_do_start(struct channel *c)
@@ -376,6 +395,7 @@ channel_do_down(struct channel *c)
c->in_table = NULL;
c->reload_event = NULL;
+ c->out_table = NULL;
CALL(c->channel->cleanup, c);
@@ -411,6 +431,9 @@ channel_set_state(struct channel *c, uint state)
if (c->in_table && (cs == CS_UP))
channel_reset_import(c);
+ if (c->out_table && (cs == CS_UP))
+ channel_reset_export(c);
+
break;
case CS_UP:
@@ -433,6 +456,9 @@ channel_set_state(struct channel *c, uint state)
if (c->in_table && (cs == CS_UP))
channel_reset_import(c);
+ if (c->out_table && (cs == CS_UP))
+ channel_reset_export(c);
+
channel_do_flush(c);
break;
@@ -619,7 +645,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
c->last_tx_filter_change = current_time();
/* Execute channel-specific reconfigure hook */
- if (c->channel->reconfigure && !c->channel->reconfigure(c, cf))
+ if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
return 0;
/* If the channel is not open, it has no routes and we cannot reload it anyways */
@@ -1926,7 +1952,7 @@ proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
/* All channels must support reload */
if (dir != CMD_RELOAD_OUT)
WALK_LIST(c, p->channels)
- if (!channel_reloadable(c))
+ if ((c->channel_state == CS_UP) && !channel_reloadable(c))
{
cli_msg(-8006, "%s: reload failed", p->name);
return;
@@ -1937,12 +1963,14 @@ proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
/* re-importing routes */
if (dir != CMD_RELOAD_OUT)
WALK_LIST(c, p->channels)
- channel_request_reload(c);
+ if (c->channel_state == CS_UP)
+ channel_request_reload(c);
/* re-exporting routes */
if (dir != CMD_RELOAD_IN)
WALK_LIST(c, p->channels)
- channel_request_feeding(c);
+ if (c->channel_state == CS_UP)
+ channel_request_feeding(c);
cli_msg(-15, "%s: reloading", p->name);
}
diff --git a/nest/protocol.h b/nest/protocol.h
index da12c771..c664c1e6 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -451,7 +451,7 @@ struct channel_class {
uint config_size; /* Size of channel config data structure */
void (*init)(struct channel *, struct channel_config *); /* Create new instance */
- int (*reconfigure)(struct channel *, struct channel_config *); /* Try to reconfigure instance, returns success */
+ int (*reconfigure)(struct channel *, struct channel_config *, int *import_changed, int *export_changed); /* Try to reconfigure instance, returns success */
int (*start)(struct channel *); /* Start the instance */
void (*shutdown)(struct channel *); /* Stop the instance */
void (*cleanup)(struct channel *); /* Channel finished flush */
@@ -537,8 +537,11 @@ struct channel {
struct rtable *in_table; /* Internal table for received routes */
struct event *reload_event; /* Event responsible for reloading from in_table */
- struct fib_iterator reload_fit; /* Iterator in in_table used during reloading */
+ struct fib_iterator reload_fit; /* FIB iterator in in_table used during reloading */
+ struct rte *reload_next_rte; /* Route iterator in in_table used during reloading */
u8 reload_active; /* Iterator reload_fit is linked */
+
+ struct rtable *out_table; /* Internal table for exported routes */
};
@@ -607,6 +610,7 @@ int proto_configure_channel(struct proto *p, struct channel **c, struct channel_
void channel_set_state(struct channel *c, uint state);
void channel_setup_in_table(struct channel *c);
+void channel_setup_out_table(struct channel *c);
void channel_schedule_reload(struct channel *c);
static inline void channel_init(struct channel *c) { channel_set_state(c, CS_START); }
diff --git a/nest/route.h b/nest/route.h
index 8d799454..f4f32ce0 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -320,6 +320,7 @@ int rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src
int rt_reload_channel(struct channel *c);
void rt_reload_channel_abort(struct channel *c);
void rt_prune_sync(rtable *t, int all);
+int rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 53f5d979..318ec2ee 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -633,7 +633,6 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
-
/*
* First, apply export limit.
*
@@ -679,6 +678,8 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
}
}
+ if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
+ return;
if (new)
stats->exp_updates_accepted++;
@@ -2507,6 +2508,10 @@ rt_feed_channel_abort(struct channel *c)
}
+/*
+ * Import table
+ */
+
int
rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
@@ -2548,6 +2553,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
goto drop_update;
}
+ /* Move iterator if needed */
+ if (old == c->reload_next_rte)
+ c->reload_next_rte = old->next;
+
/* Remove the old rte */
*pos = old->next;
rte_free_quick(old);
@@ -2615,21 +2624,32 @@ rt_reload_channel(struct channel *c)
c->reload_active = 1;
}
- FIB_ITERATE_START(&tab->fib, fit, net, n)
- {
- if (max_feed <= 0)
+ do {
+ for (rte *e = c->reload_next_rte; e; e = e->next)
{
- FIB_ITERATE_PUT(fit);
- return 0;
+ if (max_feed-- <= 0)
+ {
+ c->reload_next_rte = e;
+ debug("%s channel reload burst split (max_feed=%d)", c->proto->name, max_feed);
+ return 0;
+ }
+
+ rte_update2(c, e->net->n.addr, rte_do_cow(e), e->attrs->src);
}
- for (rte *e = n->routes; e; e = e->next)
+ c->reload_next_rte = NULL;
+
+ FIB_ITERATE_START(&tab->fib, fit, net, n)
{
- rte_update2(c, n->n.addr, rte_do_cow(e), e->attrs->src);
- max_feed--;
+ if (c->reload_next_rte = n->routes)
+ {
+ FIB_ITERATE_PUT_NEXT(fit, &tab->fib);
+ break;
+ }
}
+ FIB_ITERATE_END;
}
- FIB_ITERATE_END;
+ while (c->reload_next_rte);
c->reload_active = 0;
return 1;
@@ -2642,6 +2662,7 @@ rt_reload_channel_abort(struct channel *c)
{
/* Unlink the iterator */
fit_get(&c->in_table->fib, &c->reload_fit);
+ c->reload_next_rte = NULL;
c->reload_active = 0;
}
}
@@ -2668,6 +2689,89 @@ rt_prune_sync(rtable *t, int all)
}
+/*
+ * Export table
+ */
+
+int
+rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int refeed)
+{
+ struct rtable *tab = c->out_table;
+ struct rte_src *src;
+ rte *old, **pos;
+ net *net;
+
+ if (new)
+ {
+ net = net_get(tab, n);
+ src = new->attrs->src;
+ }
+ else
+ {
+ net = net_find(tab, n);
+ src = old0->attrs->src;
+
+ if (!net)
+ goto drop_withdraw;
+ }
+
+ /* Find the old rte */
+ for (pos = &net->routes; old = *pos; pos = &old->next)
+ if (old->attrs->src == src)
+ {
+ if (new && rte_same(old, new))
+ {
+ /* REF_STALE / REF_DISCARD not used in export table */
+ /*
+ if (old->flags & (REF_STALE | REF_DISCARD | REF_MODIFY))
+ {
+ old->flags &= ~(REF_STALE | REF_DISCARD | REF_MODIFY);
+ return 1;
+ }
+ */
+
+ goto drop_update;
+ }
+
+ /* Remove the old rte */
+ *pos = old->next;
+ rte_free_quick(old);
+ tab->rt_count--;
+
+ break;
+ }
+
+ if (!new)
+ {
+ if (!old)
+ goto drop_withdraw;
+
+ return 1;
+ }
+
+ /* Insert the new rte */
+ rte *e = rte_do_cow(new);
+ e->flags |= REF_COW;
+ e->net = net;
+ e->sender = c;
+ e->lastmod = current_time();
+ e->next = *pos;
+ *pos = e;
+ tab->rt_count++;
+ return 1;
+
+drop_update:
+ return refeed;
+
+drop_withdraw:
+ return 0;
+}
+
+
+/*
+ * Hostcache
+ */
+
static inline u32
hc_hash(ip_addr a, rtable *dep)
{
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 69c4b172..886ee6ba 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -1747,7 +1747,7 @@ bgp_rte_mergable(rte *pri, rte *sec)
return 0;
/* RFC 4271 9.1.2.1. Route resolvability test */
- if (!rte_resolvable(sec))
+ if (rte_resolvable(pri) != rte_resolvable(sec))
return 0;
/* LLGR draft - depreference stale routes */
@@ -1833,7 +1833,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
rte *key = new ? new : old;
u32 lpref = key->pref;
u32 lasn = bgp_get_neighbor(key);
- int old_is_group_best = 0;
+ int old_suppressed = old ? old->u.bgp.suppressed : 0;
/*
* Proper RFC 4271 path selection is a bit complicated, it cannot be
@@ -1880,7 +1880,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
* We could find the best-in-group and then make some shortcuts like
* in rte_recalculate, but as we would have to walk through all
* net->routes just to find it, it is probably not worth. So we
- * just have two simpler fast cases that use just the old route.
+ * just have one simple fast case that use just the old route.
* We also set suppressed flag to avoid using it in bgp_rte_better().
*/
@@ -1889,23 +1889,11 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
if (old)
{
- old_is_group_best = !old->u.bgp.suppressed;
old->u.bgp.suppressed = 1;
- int new_is_better = new && bgp_rte_better(new, old);
- /* The first case - replace not best with worse (or remove not best) */
- if (!old_is_group_best && !new_is_better)
+ /* The fast case - replace not best with worse (or remove not best) */
+ if (old_suppressed && !(new && bgp_rte_better(new, old)))
return 0;
-
- /* The second case - replace the best with better */
- if (old_is_group_best && new_is_better)
- {
- /* new is best-in-group, the see discussion below - this is
- a special variant of NBG && OBG. From OBG we can deduce
- that same_group(old_best) iff (old == old_best) */
- new->u.bgp.suppressed = 0;
- return (old == old_best);
- }
}
/* The default case - find a new best-in-group route */
@@ -1922,6 +1910,16 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
if (!r)
return 0;
+ /* Found if new is mergable with best-in-group */
+ if (new && (new != r) && bgp_rte_mergable(r, new))
+ new->u.bgp.suppressed = 0;
+
+ /* Found all existing routes mergable with best-in-group */
+ for (s=net->routes; rte_is_valid(s); s=s->next)
+ if (use_deterministic_med(s) && same_group(s, lpref, lasn))
+ if ((s != r) && bgp_rte_mergable(r, s))
+ s->u.bgp.suppressed = 0;
+
/* Found best-in-group */
r->u.bgp.suppressed = 0;
@@ -1935,9 +1933,9 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
* rte_recalculate() without ignore that possibility).
*
* There are three possible cases according to whether the old route
- * was the best in group (OBG, stored in old_is_group_best) and
- * whether the new route is the best in group (NBG, tested by r == new).
- * These cases work even if old or new is NULL.
+ * was the best in group (OBG, i.e. !old_suppressed) and whether the
+ * new route is the best in group (NBG, tested by r == new). These
+ * cases work even if old or new is NULL.
*
* NBG -> new is a possible candidate for the best route, so we just
* check for the first reason using same_group().
@@ -1952,7 +1950,7 @@ bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_best)
if (r == new)
return old_best && same_group(old_best, lpref, lasn);
else
- return old_is_group_best;
+ return !old_suppressed;
}
struct rte *
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 5a403b40..b26e5e87 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -100,6 +100,7 @@
* RFC 8203 - BGP Administrative Shutdown Communication
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
* draft-ietf-idr-bgp-extended-messages-27
+ * draft-ietf-idr-ext-opt-param-07
* draft-uttaro-idr-bgp-persistence-04
*/
@@ -1721,6 +1722,9 @@ bgp_channel_start(struct channel *C)
if (c->cf->import_table)
channel_setup_in_table(C);
+ if (c->cf->export_table)
+ channel_setup_out_table(C);
+
c->stale_timer = tm_new_init(c->pool, bgp_long_lived_stale_timeout, c, 0, 0);
c->next_hop_addr = c->cf->next_hop_addr;
@@ -2054,23 +2058,36 @@ bgp_reconfigure(struct proto *P, struct proto_config *CF)
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
static int
-bgp_channel_reconfigure(struct channel *C, struct channel_config *CC)
+bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *import_changed, int *export_changed)
{
struct bgp_channel *c = (void *) C;
struct bgp_channel_config *new = (void *) CC;
struct bgp_channel_config *old = c->cf;
- if (memcmp(((byte *) old) + sizeof(struct channel_config),
- ((byte *) new) + sizeof(struct channel_config),
- /* Remaining items must be checked separately */
- OFFSETOF(struct bgp_channel_config, rest) - sizeof(struct channel_config)))
+ if ((new->secondary != old->secondary) ||
+ (new->gr_able != old->gr_able) ||
+ (new->llgr_able != old->llgr_able) ||
+ (new->llgr_time != old->llgr_time) ||
+ (new->ext_next_hop != old->ext_next_hop) ||
+ (new->add_path != old->add_path) ||
+ (new->import_table != old->import_table) ||
+ (new->export_table != old->export_table) ||
+ (IGP_TABLE(new, ip4) != IGP_TABLE(old, ip4)) ||
+ (IGP_TABLE(new, ip6) != IGP_TABLE(old, ip6)))
return 0;
- /* Check change in IGP tables */
- if ((IGP_TABLE(old, ip4) != IGP_TABLE(new, ip4)) ||
- (IGP_TABLE(old, ip6) != IGP_TABLE(new, ip6)))
+ if (new->mandatory && !old->mandatory && (C->channel_state != CS_UP))
return 0;
+ if (new->gw_mode != old->gw_mode)
+ *import_changed = 1;
+
+ if (!ipa_equal(new->next_hop_addr, old->next_hop_addr) ||
+ (new->next_hop_self != old->next_hop_self) ||
+ (new->next_hop_keep != old->next_hop_keep) ||
+ (new->missing_lladdr != old->missing_lladdr))
+ *export_changed = 1;
+
c->cf = new;
return 1;
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 075e1bb9..f9a19d53 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -150,8 +150,8 @@ struct bgp_channel_config {
u8 ext_next_hop; /* Allow both IPv4 and IPv6 next hops */
u8 add_path; /* Use ADD-PATH extension [RFC 7911] */
u8 import_table; /* Use c.in_table as Adj-RIB-In */
+ u8 export_table; /* Use c.out_table as Adj-RIB-Out */
- uint rest[0]; /* Remaining items are reconfigured separately */
struct rtable_config *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
struct rtable_config *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
};
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index bbc7d9a4..8222024d 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -255,6 +255,7 @@ bgp_channel_item:
| ADD PATHS TX { BGP_CC->add_path = BGP_ADD_PATH_TX; }
| ADD PATHS bool { BGP_CC->add_path = $3 ? BGP_ADD_PATH_FULL : 0; }
| IMPORT TABLE bool { BGP_CC->import_table = $3; }
+ | EXPORT TABLE bool { BGP_CC->export_table = $3; }
| IGP TABLE rtable {
if (BGP_CC->desc->no_igp)
cf_error("IGP table not allowed here");
@@ -302,7 +303,7 @@ dynamic_attr: BGP_LOCAL_PREF
dynamic_attr: BGP_ATOMIC_AGGR
{ $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_ATOMIC_AGGR)); } ;
dynamic_attr: BGP_AGGREGATOR
- { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
+ { $$ = f_new_dynamic_attr(EAF_TYPE_OPAQUE, T_ENUM_EMPTY, EA_CODE(PROTOCOL_BGP, BA_AGGREGATOR)); } ;
dynamic_attr: BGP_COMMUNITY
{ $$ = f_new_dynamic_attr(EAF_TYPE_INT_SET, T_CLIST, EA_CODE(PROTOCOL_BGP, BA_COMMUNITY)); } ;
dynamic_attr: BGP_ORIGINATOR_ID
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index daa88630..4632e4ad 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -185,14 +185,20 @@ bgp_find_af_caps(struct bgp_caps *caps, u32 afi)
}
static struct bgp_af_caps *
-bgp_get_af_caps(struct bgp_caps *caps, u32 afi)
+bgp_get_af_caps(struct bgp_caps **pcaps, u32 afi)
{
+ struct bgp_caps *caps = *pcaps;
struct bgp_af_caps *ac;
WALK_AF_CAPS(caps, ac)
if (ac->afi == afi)
return ac;
+ uint n = caps->af_count;
+ if (uint_is_pow2(n))
+ *pcaps = caps = mb_realloc(caps, sizeof(struct bgp_caps) +
+ (2 * n) * sizeof(struct bgp_af_caps));
+
ac = &caps->af_data[caps->af_count++];
memset(ac, 0, sizeof(struct bgp_af_caps));
ac->afi = afi;
@@ -294,8 +300,8 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
/*
* Note that max length is ~ 22+21*af_count. With max 12 channels that is
- * 274. Option limit is 253 and buffer size is 4096, so we cannot overflow
- * unless we add new capabilities or more AFs. XXXXX
+ * 274. We are limited just by buffer size (4096, minus header), as we support
+ * extended optional parameres. Therefore, we have enough space for expansion.
*/
WALK_AF_CAPS(caps, ac)
@@ -411,14 +417,23 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
return buf;
}
-static void
-bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, int len)
+static int
+bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
{
struct bgp_proto *p = conn->bgp;
+ struct bgp_caps *caps;
struct bgp_af_caps *ac;
int i, cl;
u32 af;
+ if (!conn->remote_caps)
+ caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + sizeof(struct bgp_af_caps));
+ else
+ {
+ caps = conn->remote_caps;
+ conn->remote_caps = NULL;
+ }
+
caps->length += len;
while (len > 0)
@@ -437,7 +452,7 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
goto err;
af = get_af4(pos+2);
- ac = bgp_get_af_caps(caps, af);
+ ac = bgp_get_af_caps(&caps, af);
ac->ready = 1;
break;
@@ -460,7 +475,7 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
continue;
af = get_af4(pos+2+i);
- ac = bgp_get_af_caps(caps, af);
+ ac = bgp_get_af_caps(&caps, af);
ac->ext_next_hop = 1;
}
break;
@@ -490,7 +505,7 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
for (i = 2; i < cl; i += 4)
{
af = get_af3(pos+2+i);
- ac = bgp_get_af_caps(caps, af);
+ ac = bgp_get_af_caps(&caps, af);
ac->gr_able = 1;
ac->gr_af_flags = pos[2+i+3];
}
@@ -522,7 +537,7 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
for (i = 0; i < cl; i += 4)
{
af = get_af3(pos+2+i);
- ac = bgp_get_af_caps(caps, af);
+ ac = bgp_get_af_caps(&caps, af);
ac->add_path = pos[2+i+3];
}
break;
@@ -551,7 +566,7 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
for (i = 0; i < cl; i += 7)
{
af = get_af3(pos+2+i);
- ac = bgp_get_af_caps(caps, af);
+ ac = bgp_get_af_caps(&caps, af);
ac->llgr_able = 1;
ac->llgr_flags = pos[2+i+3];
ac->llgr_time = get_u24(pos + 2+i+4);
@@ -577,11 +592,13 @@ bgp_read_capabilities(struct bgp_conn *conn, struct bgp_caps *caps, byte *pos, i
}
}
- return;
+ conn->remote_caps = caps;
+ return 0;
err:
+ mb_free(caps);
bgp_error(conn, 2, 0, NULL, 0);
- return;
+ return -1;
}
static int
@@ -621,43 +638,68 @@ bgp_check_capabilities(struct bgp_conn *conn)
}
static int
-bgp_read_options(struct bgp_conn *conn, byte *pos, int len)
+bgp_read_options(struct bgp_conn *conn, byte *pos, uint len, uint rest)
{
struct bgp_proto *p = conn->bgp;
- struct bgp_caps *caps;
- int ol;
+ int ext = 0;
- /* Max number of announced AFIs is limited by max option length (255) */
- caps = alloca(sizeof(struct bgp_caps) + 64 * sizeof(struct bgp_af_caps));
- memset(caps, 0, sizeof(struct bgp_caps));
+ /* Handle extended length (draft-ietf-idr-ext-opt-param-07) */
+ if ((len > 0) && (rest > 0) && (pos[0] == 255))
+ {
+ if (rest < 3)
+ goto err;
+
+ /* Update pos/len to describe optional data */
+ len = get_u16(pos+1);
+ ext = 1;
+ pos += 3;
+ rest -= 3;
+ }
+
+ /* Verify that optional data fits into OPEN packet */
+ if (len > rest)
+ goto err;
+
+ /* Length of option parameter header */
+ uint hlen = ext ? 3 : 2;
while (len > 0)
{
- if ((len < 2) || (len < (2 + pos[1])))
- { bgp_error(conn, 2, 0, NULL, 0); return -1; }
+ if (len < hlen)
+ goto err;
+
+ uint otype = get_u8(pos);
+ uint olen = ext ? get_u16(pos+1) : get_u8(pos+1);
+
+ if (len < (hlen + olen))
+ goto err;
- ol = pos[1];
- if (pos[0] == 2)
+ if (otype == 2)
{
/* BGP capabilities, RFC 5492 */
if (p->cf->capabilities)
- bgp_read_capabilities(conn, caps, pos + 2, ol);
+ if (bgp_read_capabilities(conn, pos + hlen, olen) < 0)
+ return -1;
}
else
{
/* Unknown option */
- bgp_error(conn, 2, 4, pos, ol); /* FIXME: ol or ol+2 ? */
+ bgp_error(conn, 2, 4, pos, hlen + olen);
return -1;
}
- ADVANCE(pos, len, 2 + ol);
+ ADVANCE(pos, len, hlen + olen);
}
- uint n = sizeof(struct bgp_caps) + caps->af_count * sizeof(struct bgp_af_caps);
- conn->remote_caps = mb_allocz(p->p.pool, n);
- memcpy(conn->remote_caps, caps, n);
+ /* Prepare empty caps if no capability option was announced */
+ if (!conn->remote_caps)
+ conn->remote_caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps));
return 0;
+
+err:
+ bgp_error(conn, 2, 0, NULL, 0);
+ return -1;
}
static byte *
@@ -676,12 +718,29 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
if (p->cf->capabilities)
{
/* Prepare local_caps and write capabilities to buffer */
- byte *end = bgp_write_capabilities(conn, buf+12);
- uint len = end - (buf+12);
+ byte *pos = buf+12;
+ byte *end = bgp_write_capabilities(conn, pos);
+ uint len = end - pos;
- buf[9] = len + 2; /* Optional parameters length */
- buf[10] = 2; /* Option 2: Capability list */
- buf[11] = len; /* Option data length */
+ if (len < 254)
+ {
+ buf[9] = len + 2; /* Optional parameters length */
+ buf[10] = 2; /* Option 2: Capability list */
+ buf[11] = len; /* Option data length */
+ }
+ else /* draft-ietf-idr-ext-opt-param-07 */
+ {
+ /* Move capabilities 4 B forward */
+ memmove(buf + 16, pos, len);
+ pos = buf + 16;
+ end = pos + len;
+
+ buf[9] = 255; /* Non-ext OP length, fake */
+ buf[10] = 255; /* Non-ext OP type, signals extended length */
+ put_u16(buf+11, len + 3); /* Extended optional parameters length */
+ buf[13] = 2; /* Option 2: Capability list */
+ put_u16(buf+14, len); /* Option extended data length */
+ }
return end;
}
@@ -705,8 +764,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
if (conn->state != BS_OPENSENT)
{ bgp_error(conn, 5, fsm_err_subcode[conn->state], NULL, 0); return; }
- /* Check message contents */
- if (len < 29 || len != 29 + (uint) pkt[28])
+ /* Check message length */
+ if (len < 29)
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
if (pkt[19] != BGP_VERSION)
@@ -717,7 +776,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
id = get_u32(pkt+24);
BGP_TRACE(D_PACKETS, "Got OPEN(as=%d,hold=%d,id=%R)", asn, hold, id);
- if (bgp_read_options(conn, pkt+29, pkt[28]) < 0)
+ if (bgp_read_options(conn, pkt+29, pkt[28], len-29) < 0)
return;
if (hold > 0 && hold < 3)
@@ -2900,7 +2959,7 @@ bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
return 1;
/* Handle proper message */
- if ((msg_len > 255) && (msg_len + 1 > len))
+ if (msg_len + 1 > len)
return 0;
/* Some elementary cleanup */
@@ -2916,7 +2975,7 @@ bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
void
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, uint code, uint subcode, byte *data, uint len)
{
- byte argbuf[256], *t = argbuf;
+ byte argbuf[256+16], *t = argbuf;
uint i;
/* Don't report Cease messages generated by myself */
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index 2ec8c0b6..f631a649 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -537,7 +537,12 @@ CF_CLI(SHOW OSPF STATE ALL, optproto opttext, [<name>], [[Show information about
CF_CLI_HELP(SHOW OSPF LSADB, ..., [[Show content of OSPF LSA database]]);
CF_CLI(SHOW OSPF LSADB, lsadb_args, [global | area <id> | link] [type <num>] [lsid <id>] [self | router <id>] [<proto>], [[Show content of OSPF LSA database]])
-{ ospf_sh_lsadb($4); };
+{
+ if (!$4->proto)
+ $4->proto = (struct ospf_proto *) proto_get_named(NULL, &proto_ospf);
+
+ ospf_sh_lsadb($4);
+};
lsadb_args:
/* empty */ {
diff --git a/proto/radv/config.Y b/proto/radv/config.Y
index 53715f77..dda9cfcd 100644
--- a/proto/radv/config.Y
+++ b/proto/radv/config.Y
@@ -1,6 +1,8 @@
/*
* BIRD -- Router Advertisement Configuration
*
+ * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2011--2019 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -26,12 +28,12 @@ static u8 radv_mult_val; /* Used by radv_mult for second return value */
CF_DECLS
-CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
- MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, RETRANS,
- TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
- LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
- LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE,
- ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME)
+CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED,
+ UNICAST, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME,
+ RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
+ LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL,
+ TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE,
+ ROUTES, RA_PREFERENCE, RA_LIFETIME)
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
@@ -98,6 +100,7 @@ radv_iface_item:
MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
| MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); }
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
+ | SOLICITED RA UNICAST bool { RADV_IFACE->solicited_ra_unicast = $4; }
| MANAGED bool { RADV_IFACE->managed = $2; }
| OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
| LINK MTU expr { RADV_IFACE->link_mtu = $3; }
diff --git a/proto/radv/packets.c b/proto/radv/packets.c
index b12d3a12..3139d321 100644
--- a/proto/radv/packets.c
+++ b/proto/radv/packets.c
@@ -1,6 +1,8 @@
/*
* BIRD -- RAdv Packet Processing
*
+ * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2011--2019 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -370,19 +372,49 @@ radv_prepare_ra(struct radv_iface *ifa)
void
-radv_send_ra(struct radv_iface *ifa)
+radv_send_ra(struct radv_iface *ifa, ip_addr to)
{
struct radv_proto *p = ifa->ra;
+ /* TX queue is already full */
+ if (!sk_tx_buffer_empty(ifa->sk))
+ return;
+
+ if (ifa->valid_time <= current_time())
+ radv_invalidate(ifa);
+
/* We store prepared RA in tbuf */
if (!ifa->plen)
radv_prepare_ra(ifa);
- RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
- sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
+ if (ipa_zero(to))
+ {
+ to = IP6_ALL_NODES;
+ RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
+ }
+ else
+ {
+ RADV_TRACE(D_PACKETS, "Sending RA to %I via %s", to, ifa->iface->name);
+ }
+
+ int done = sk_send_to(ifa->sk, ifa->plen, to, 0);
+ if (!done)
+ log(L_WARN "%s: TX queue full on %s", p->p.name, ifa->iface->name);
}
+static void
+radv_receive_rs(struct radv_proto *p, struct radv_iface *ifa, ip_addr from)
+{
+ RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
+ from, ifa->iface->name);
+
+ if (ifa->cf->solicited_ra_unicast && ipa_nonzero(from))
+ radv_send_ra(ifa, from);
+ else
+ radv_iface_notify(ifa, RA_EV_RS);
+}
+
static int
radv_rx_hook(sock *sk, uint size)
{
@@ -410,9 +442,7 @@ radv_rx_hook(sock *sk, uint size)
switch (buf[0])
{
case ICMPV6_RS:
- RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
- sk->faddr, ifa->iface->name);
- radv_iface_notify(ifa, RA_EV_RS);
+ radv_receive_rs(p, ifa, sk->faddr);
return 1;
case ICMPV6_RA:
@@ -430,7 +460,10 @@ static void
radv_tx_hook(sock *sk)
{
struct radv_iface *ifa = sk->data;
- log(L_WARN "%s: TX hook called", ifa->ra->p.name);
+ log(L_INFO "%s: TX queue ready on %s", ifa->ra->p.name, ifa->iface->name);
+
+ /* Some RAs may be missed due to full TX queue */
+ radv_iface_notify(ifa, RA_EV_RS);
}
static void
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 990b6024..622b3c3c 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -1,6 +1,8 @@
/*
* BIRD -- Router Advertisement
*
+ * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2011--2019 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -35,18 +37,14 @@
* case of the specified trigger prefix was changed.
*
* Supported standards:
- * - RFC 4861 - main RA standard
- * - RFC 4191 - Default Router Preferences and More-Specific Routes
- * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
+ * RFC 4861 - main RA standard
+ * RFC 4191 - Default Router Preferences and More-Specific Routes
+ * RFC 6106 - DNS extensions (RDDNS, DNSSL)
*/
static void radv_prune_prefixes(struct radv_iface *ifa);
static void radv_prune_routes(struct radv_proto *p);
-/* Invalidate cached RA packet */
-static inline void radv_invalidate(struct radv_iface *ifa)
-{ ifa->plen = 0; }
-
static void
radv_timer(timer *tm)
{
@@ -56,16 +54,13 @@ radv_timer(timer *tm)
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
- if (ifa->valid_time <= now)
- radv_invalidate(ifa);
-
if (ifa->prune_time <= now)
radv_prune_prefixes(ifa);
if (p->prune_time <= now)
radv_prune_routes(p);
- radv_send_ra(ifa);
+ radv_send_ra(ifa, IPA_NONE);
/* Update timer */
ifa->last = now;
@@ -627,7 +622,7 @@ radv_iface_shutdown(struct radv_iface *ifa)
if (ifa->sk)
{
radv_invalidate(ifa);
- radv_send_ra(ifa);
+ radv_send_ra(ifa, IPA_NONE);
}
}
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 719948d5..2c8ad7d4 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -1,6 +1,8 @@
/*
* BIRD -- Router Advertisement
*
+ * (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2011--2019 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@@ -66,6 +68,8 @@ struct radv_iface_config
u32 max_ra_int;
u32 min_delay;
+ u8 solicited_ra_unicast; /* Send solicited RAs as unicast */
+
u32 prefix_linger_time; /* How long we advertise dead prefixes with lifetime 0 */
u32 route_linger_time; /* How long we advertise dead routes with lifetime 0 */
@@ -204,12 +208,16 @@ struct radv_iface
log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
+/* Invalidate cached RA packet */
+static inline void radv_invalidate(struct radv_iface *ifa)
+{ ifa->plen = 0; }
+
/* radv.c */
void radv_iface_notify(struct radv_iface *ifa, int event);
/* packets.c */
int radv_process_domain(struct radv_dnssl_config *cf);
-void radv_send_ra(struct radv_iface *ifa);
+void radv_send_ra(struct radv_iface *ifa, ip_addr to);
int radv_sk_open(struct radv_iface *ifa);
diff --git a/sysdep/config.h b/sysdep/config.h
index 7165fb43..4ca01297 100644
--- a/sysdep/config.h
+++ b/sysdep/config.h
@@ -13,7 +13,7 @@
#ifdef GIT_LABEL
#define BIRD_VERSION XSTR1(GIT_LABEL)
#else
-#define BIRD_VERSION "2.0.5"
+#define BIRD_VERSION "2.0.6"
#endif
/* Include parameters determined by configure script */
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 05becbe7..db848033 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -83,6 +83,9 @@ drop_gid(gid_t gid)
{
if (setgid(gid) < 0)
die("setgid: %m");
+
+ if (setgroups(0, NULL) < 0)
+ die("setgroups: %m");
}
/*