mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 01:31:55 +00:00
Merge commit '5121101136cb80151a9361c63dc4822afeb44eef' into thread-next
This commit is contained in:
commit
767b7b22a0
@ -60,14 +60,6 @@ stages:
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
build-debian-8-amd64:
|
||||
<<: *build-linux
|
||||
image: registry.nic.cz/labs/bird:debian-8-amd64
|
||||
|
||||
build-debian-8-i386:
|
||||
<<: *build-linux
|
||||
image: registry.nic.cz/labs/bird:debian-8-i386
|
||||
|
||||
build-debian-9-amd64:
|
||||
<<: *build-linux
|
||||
image: registry.nic.cz/labs/bird:debian-9-amd64
|
||||
@ -224,28 +216,6 @@ build-opensuse-15.3-amd64:
|
||||
paths:
|
||||
- pkg/pkgs/*
|
||||
|
||||
# Dpkg error: PATH is not set
|
||||
#pkg-debian-8-amd64:
|
||||
# <<: *pkg-deb
|
||||
# needs: [build-debian-8-amd64]
|
||||
# image: registry.nic.cz/labs/bird:debian-8-amd64
|
||||
|
||||
# Dpkg error: PATH is not set
|
||||
#pkg-debian-8-i386:
|
||||
# <<: *pkg-deb
|
||||
# needs: [build-debian-8-i386]
|
||||
# image: registry.nic.cz/labs/bird:debian-8-i386
|
||||
|
||||
pkg-debian-9-amd64:
|
||||
<<: *pkg-deb
|
||||
needs: [build-debian-9-amd64]
|
||||
image: registry.nic.cz/labs/bird:debian-9-amd64
|
||||
|
||||
pkg-debian-9-i386:
|
||||
<<: *pkg-deb
|
||||
needs: [build-debian-9-i386]
|
||||
image: registry.nic.cz/labs/bird:debian-9-i386
|
||||
|
||||
pkg-debian-10-amd64:
|
||||
<<: *pkg-deb
|
||||
needs: [build-debian-10-amd64]
|
||||
@ -284,7 +254,7 @@ pkg-fedora-33-amd64:
|
||||
pkg-fedora-34-amd64:
|
||||
<<: *pkg-rpm
|
||||
needs: [build-fedora-34-amd64]
|
||||
image: registry.labs.nic.cz/labs/bird:fedora-34-amd64
|
||||
image: registry.nic.cz/labs/bird:fedora-34-amd64
|
||||
|
||||
pkg-centos-8-amd64:
|
||||
<<: *pkg-rpm-wa
|
||||
|
6
NEWS
6
NEWS
@ -29,6 +29,12 @@ Version 3.0-alpha0 (2022-02-07)
|
||||
o Lots of refactoring
|
||||
o Bugfixes and improvements as they came along
|
||||
|
||||
Version 2.13.1 (2023-06-23)
|
||||
o BGP: Fix role check when no capability option is present
|
||||
o Filter: Fixed segfault when a case option had an empty block
|
||||
|
||||
This is a bugfix version.
|
||||
|
||||
Version 2.13 (2023-04-21)
|
||||
o Babel: IPv4 via IPv6 extension (RFC 9229)
|
||||
o Babel: Improve authentication on lossy networks
|
||||
|
@ -258,12 +258,17 @@ WHITE [ \t]
|
||||
return IP4;
|
||||
}
|
||||
|
||||
{XIGIT}{2}((:{XIGIT}{2}){15,}|({XIGIT}{2}){15,}) {
|
||||
char *s = yytext;
|
||||
({XIGIT}{2}){16,}|{XIGIT}{2}(:{XIGIT}{2}){15,}|hex:({XIGIT}{2}(:?{XIGIT}{2})*)? {
|
||||
char *s, *sb = yytext;
|
||||
size_t len = 0, i;
|
||||
struct bytestring *bytes;
|
||||
byte *b;
|
||||
|
||||
/* skip 'hex:' prefix */
|
||||
if (sb[0] == 'h' && sb[1] == 'e' && sb[2] == 'x' && sb[3] == ':')
|
||||
sb += 4;
|
||||
|
||||
s = sb;
|
||||
while (*s) {
|
||||
len++;
|
||||
s += 2;
|
||||
@ -274,7 +279,7 @@ WHITE [ \t]
|
||||
|
||||
bytes->length = len;
|
||||
b = &bytes->data[0];
|
||||
s = yytext;
|
||||
s = sb;
|
||||
errno = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
*b = bstrtobyte16(s);
|
||||
|
@ -96,7 +96,7 @@ CF_DECLS
|
||||
struct timeformat *tf;
|
||||
struct settle_config settle;
|
||||
struct adata *ad;
|
||||
struct bytestring *bs;
|
||||
const struct bytestring *bs;
|
||||
}
|
||||
|
||||
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
|
||||
|
@ -6,3 +6,7 @@ make_archive_script = "tools/make-dev-archive"
|
||||
[upstream]
|
||||
# needed for get-archive
|
||||
archive_url = "https://bird.network.cz/download/bird-{{ version }}.tar.gz"
|
||||
|
||||
[apkg]
|
||||
# apkg compat level
|
||||
compat = 3
|
||||
|
@ -65,11 +65,23 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
<email>&dhemail;</email>
|
||||
</address>
|
||||
</author>
|
||||
<author>
|
||||
<firstname>Jakub</firstname>
|
||||
<surname>Ružička</surname>
|
||||
<contrib>Updated this manpage for birdcl.</contrib>
|
||||
<address>
|
||||
<email>jakub.ruzicka@nic.cz</email>
|
||||
</address>
|
||||
</author>
|
||||
</authorgroup>
|
||||
<copyright>
|
||||
<year>2010</year>
|
||||
<holder>&dhusername;</holder>
|
||||
</copyright>
|
||||
<copyright>
|
||||
<year>2022</year>
|
||||
<holder>Jakub Ružička</holder>
|
||||
</copyright>
|
||||
<legalnotice>
|
||||
<para>This manual page was written for the Debian system
|
||||
(and may be used by others).</para>
|
||||
@ -95,6 +107,10 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
<refname>birdc</refname>
|
||||
<refpurpose>BIRD Internet Routing Daemon remote control</refpurpose>
|
||||
</refnamediv>
|
||||
<refnamediv>
|
||||
<refname>birdcl</refname>
|
||||
<refpurpose>BIRD Internet Routing Daemon remote control light</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
@ -118,6 +134,13 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
<arg choice="opt"><option>-s <replaceable>control-socket</replaceable></option></arg>
|
||||
<arg choice="opt"><option>-v</option></arg>
|
||||
</cmdsynopsis>
|
||||
<cmdsynopsis>
|
||||
<command>birdcl</command>
|
||||
<arg choice="opt"><option>-l</option></arg>
|
||||
<arg choice="opt"><option>-r</option></arg>
|
||||
<arg choice="opt"><option>-s <replaceable>control-socket</replaceable></option></arg>
|
||||
<arg choice="opt"><option>-v</option></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1 id="description">
|
||||
@ -136,7 +159,10 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
communicate. Once started, <command>bird</command> will give access
|
||||
to an interactive shell: commands can be completed with TAB and help
|
||||
can be requested by pressing the key `?'. More documentation on
|
||||
the available commands can be foung on the website, see below.</para>
|
||||
the available commands can be found on the website, see below.</para>
|
||||
<para><command>birdcl</command> is a light version of <command>birdc</command>
|
||||
remote control for <command>bird</command> without readline/ncurses support.
|
||||
TAB completion isn't available.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="options">
|
||||
@ -230,7 +256,7 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>The <command>birdc</command> accepts these options:</para>
|
||||
<para><command>birdc</command> and <command>birdcl</command> accept these options:</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-l</option></term>
|
||||
@ -279,8 +305,7 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/
|
||||
|
||||
<refsect1 id="see_also">
|
||||
<title>SEE ALSO</title>
|
||||
<para>More documentation con be found on the website:
|
||||
<para>More documentation can be found on the website:
|
||||
https://bird.network.cz/.</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
bird2: binary-without-manpage usr/sbin/birdcl
|
@ -1,2 +1,3 @@
|
||||
bird.8
|
||||
birdc.8
|
||||
birdcl.8
|
||||
|
@ -2,4 +2,4 @@ bird2 ({{ version }}-cznic.{{ release }}) unstable; urgency=medium
|
||||
|
||||
* upstream package
|
||||
|
||||
-- Jakub Ružička <jakub.ruzicka@nic.cz> Mon, 29 Mar 2021 14:15:50 +0000
|
||||
-- Jakub Ružička <jakub.ruzicka@nic.cz> {{ now }}
|
||||
|
@ -1 +1 @@
|
||||
9
|
||||
11
|
||||
|
@ -5,18 +5,18 @@ Build-Depends: bison,
|
||||
debhelper,
|
||||
docbook-xsl,
|
||||
flex,
|
||||
libncurses5-dev,
|
||||
libncurses-dev,
|
||||
libreadline-dev | libreadline6-dev | libreadline5-dev,
|
||||
libssh-gcrypt-dev,
|
||||
linuxdoc-tools-latex,
|
||||
m4,
|
||||
opensp,
|
||||
quilt,
|
||||
texlive-latex-extra,
|
||||
xsltproc
|
||||
Build-Depends-Indep: linuxdoc-tools-latex,
|
||||
opensp,
|
||||
texlive-latex-extra
|
||||
Maintainer: Jakub Ružička <jakub.ruzicka@nic.cz>
|
||||
Uploaders: Ondřej Surý <ondrej@debian.org>
|
||||
Standards-Version: 4.3.0
|
||||
Standards-Version: 4.6.2
|
||||
Vcs-Browser: https://salsa.debian.org/debian/bird2
|
||||
Vcs-Git: https://salsa.debian.org/debian/bird2.git
|
||||
Homepage: https://bird.network.cz/
|
||||
@ -26,7 +26,6 @@ Architecture: kfreebsd-any linux-any
|
||||
Pre-Depends: init-system-helpers,
|
||||
${misc:Pre-Depends}
|
||||
Depends: adduser,
|
||||
lsb-base,
|
||||
ucf,
|
||||
${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
|
@ -23,8 +23,7 @@ LDFLAGS += -g -O2 -fno-strict-aliasing -fno-strict-overflow -fPIC -Wl,-z,defs -W
|
||||
override_dh_auto_configure:
|
||||
CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" dh_auto_configure -- $(COMMON_FLAGS) --with-protocols=all
|
||||
|
||||
override_dh_auto_build:
|
||||
dh_auto_build
|
||||
override_dh_auto_build-indep:
|
||||
dh_auto_build -- docs
|
||||
|
||||
override_dh_auto_install:
|
||||
@ -47,10 +46,10 @@ override_dh_installman: bird.8
|
||||
|
||||
override_dh_clean:
|
||||
dh_clean
|
||||
-rm -f bird.8 birdc.8
|
||||
-rm -f bird.8 birdc.8 birdcl.8
|
||||
|
||||
override_dh_missing:
|
||||
dh_missing --fail-missing
|
||||
dh_missing
|
||||
|
||||
override_dh_compress:
|
||||
dh_compress -X.conf
|
||||
|
@ -1,2 +1,2 @@
|
||||
version=3
|
||||
version=4
|
||||
https://bird.network.cz/download/bird-(2\.[\d.]+).tar.gz
|
||||
|
@ -1,17 +1,21 @@
|
||||
%global _hardened_build 1
|
||||
%global _without_doc 1
|
||||
%{!?_rundir:%global _rundir %%{_localstatedir}/run}
|
||||
|
||||
Name: bird
|
||||
Version: {{ version }}
|
||||
Release: cznic.{{ release }}%{?dist}
|
||||
Summary: BIRD Internet Routing Daemon
|
||||
|
||||
Group: System Environment/Daemons
|
||||
License: GPL-2.0-or-later
|
||||
URL: https://bird.network.cz/
|
||||
Source0: https://bird.network.cz/download/bird-%{version}.tar.gz
|
||||
Source1: bird.service
|
||||
Source2: bird.tmpfilesd
|
||||
Source3: bird.sysusersd
|
||||
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: flex
|
||||
BuildRequires: bison
|
||||
BuildRequires: ncurses-devel
|
||||
@ -20,14 +24,13 @@ BuildRequires: sed
|
||||
BuildRequires: gcc
|
||||
BuildRequires: make
|
||||
BuildRequires: libssh-devel
|
||||
%if 0%{?fedora} || (0%{?rhel} && 0%{?rhel} > 7)
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%else
|
||||
BuildRequires: systemd
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
# http://trubka.network.cz/pipermail/bird-users/2019-August/013631.html
|
||||
BuildRequires: devtoolset-8-toolchain
|
||||
%endif
|
||||
|
||||
Obsoletes: bird6 < 2.0.2-1
|
||||
Provides: bird6 = %{version}-%{release}
|
||||
BuildRequires: systemd-rpm-macros
|
||||
%{?systemd_requires}
|
||||
%{?sysusers_requires_compat}
|
||||
|
||||
%description
|
||||
BIRD is a dynamic IP routing daemon supporting both, IPv4 and IPv6, Border
|
||||
@ -41,6 +44,7 @@ powerful language for route filtering.
|
||||
%if 0%{!?_without_doc:1}
|
||||
%package doc
|
||||
Summary: Documentation for BIRD Internet Routing Daemon
|
||||
Group: Documentation
|
||||
BuildRequires: linuxdoc-tools sgml-common perl(FindBin)
|
||||
BuildArch: noarch
|
||||
|
||||
@ -57,9 +61,13 @@ powerful language for route filtering.
|
||||
%endif
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
%setup -q -n bird-%{version}
|
||||
|
||||
%build
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
. /opt/rh/devtoolset-8/enable
|
||||
%endif
|
||||
|
||||
%configure --runstatedir=%{_rundir}/bird
|
||||
%make_build all %{!?_without_doc:docs}
|
||||
|
||||
@ -70,17 +78,18 @@ powerful language for route filtering.
|
||||
install -d %{buildroot}{%{_localstatedir}/lib/bird,%{_rundir}/bird}
|
||||
install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_unitdir}/bird.service
|
||||
install -D -p -m 0644 %{SOURCE2} %{buildroot}%{_tmpfilesdir}/bird.conf
|
||||
install -D -p -m 0644 %{SOURCE3} %{buildroot}%{_sysusersdir}/bird.conf
|
||||
{% endraw %}
|
||||
|
||||
%check
|
||||
%if 0%{?rhel} && 0%{?rhel} < 8
|
||||
. /opt/rh/devtoolset-8/enable
|
||||
%endif
|
||||
|
||||
make test
|
||||
|
||||
%pre
|
||||
getent group bird >/dev/null || groupadd -r bird
|
||||
getent passwd bird >/dev/null || \
|
||||
useradd -r -g bird -d %{_localstatedir}/lib/bird -s /sbin/nologin \
|
||||
-c "BIRD daemon user" bird
|
||||
exit 0
|
||||
%sysusers_create_compat %{SOURCE3}
|
||||
|
||||
%post
|
||||
%systemd_post bird.service
|
||||
@ -95,12 +104,13 @@ exit 0
|
||||
%doc NEWS README
|
||||
%attr(0640,root,bird) %config(noreplace) %{_sysconfdir}/bird.conf
|
||||
%{_unitdir}/bird.service
|
||||
%{_sysusersdir}/bird.conf
|
||||
%{_tmpfilesdir}/bird.conf
|
||||
%{_sbindir}/bird
|
||||
%{_sbindir}/birdc
|
||||
%{_sbindir}/birdcl
|
||||
%dir %attr(0750,bird,bird) %{_localstatedir}/lib/bird
|
||||
%dir %attr(0750,bird,bird) %ghost %{_rundir}/bird
|
||||
%dir %attr(0750,bird,bird) %{_rundir}/bird
|
||||
|
||||
%if 0%{!?_without_doc:1}
|
||||
%files doc
|
||||
|
2
distro/pkg/rpm/bird.sysusersd
Normal file
2
distro/pkg/rpm/bird.sysusersd
Normal file
@ -0,0 +1,2 @@
|
||||
#Type Name ID GECOS Home directory Shell
|
||||
u bird - "BIRD daemon user" /var/lib/bird -
|
3
distro/tests/control
Normal file
3
distro/tests/control
Normal file
@ -0,0 +1,3 @@
|
||||
Tests: test-bird.sh
|
||||
Restrictions: needs-root
|
||||
Depends: bird2, iproute2
|
105
distro/tests/test-bird.sh
Executable file
105
distro/tests/test-bird.sh
Executable file
@ -0,0 +1,105 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
LOCAL=2001:db8:dead::
|
||||
|
||||
EXTERNAL=2001:db8:beef::
|
||||
EXTERNAL_NET=${EXTERNAL}/48
|
||||
EXTERNAL_NH=${LOCAL}beef
|
||||
|
||||
LEARN=2001:db8:feed::
|
||||
LEARN_NET=${LEARN}/48
|
||||
LEARN_NH=${LOCAL}feed
|
||||
|
||||
IFACE=bird-test-dummy
|
||||
IFACE_EXISTS=false
|
||||
|
||||
BIRD_RUNNING=false
|
||||
|
||||
D=$(mktemp -d)
|
||||
pushd ${D} >/dev/null
|
||||
|
||||
stop_bird() {
|
||||
birdc -l down >/dev/null
|
||||
sleep 1
|
||||
grep -q "<FATAL> Shutdown completed" bird.log
|
||||
[ ! -e bird.pid ]
|
||||
[ ! -e bird.ctl ]
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
if ${BIRD_RUNNING}; then
|
||||
stop_bird
|
||||
if [ -e bird.pid ]; then
|
||||
kill -9 $(<bird.pid)
|
||||
fi
|
||||
fi
|
||||
|
||||
if ${IFACE_EXISTS}; then
|
||||
ip link del ${IFACE}
|
||||
fi
|
||||
|
||||
|
||||
popd > /dev/null
|
||||
rm -rf ${D}
|
||||
}
|
||||
|
||||
failed() {
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
|
||||
trap failed ERR
|
||||
trap failed INT
|
||||
trap failed HUP
|
||||
|
||||
ip link add ${IFACE} type dummy
|
||||
IFACE_EXISTS=true
|
||||
|
||||
ip link set ${IFACE} up
|
||||
ip -6 addr add ${LOCAL}/64 dev bird-test-dummy
|
||||
|
||||
ip -6 route add ${LEARN_NET} via ${LEARN_NH}
|
||||
|
||||
cat >bird.conf <<EOF
|
||||
log "bird.log" all;
|
||||
|
||||
protocol device {}
|
||||
|
||||
protocol kernel {
|
||||
ipv6 { import all; export all; };
|
||||
learn;
|
||||
}
|
||||
|
||||
protocol static {
|
||||
ipv6;
|
||||
route ${EXTERNAL_NET} via ${EXTERNAL_NH};
|
||||
}
|
||||
EOF
|
||||
|
||||
bird -l -P bird.pid
|
||||
|
||||
if [ ! -S bird.ctl ] || [ ! -f bird.pid ] || [ ! -f bird.log ]; then
|
||||
failed
|
||||
fi
|
||||
|
||||
BIRD_RUNNING=true
|
||||
|
||||
ROUTE_INSERTED=false
|
||||
for _ in $(seq 10); do
|
||||
if ip -6 route show ${EXTERNAL_NET} | egrep -q "${EXTERNAL_NET} via ${EXTERNAL_NH} dev ${IFACE} proto bird metric [0-9]+ pref medium"; then
|
||||
ROUTE_INSERTED=true
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
$ROUTE_INSERTED || failed
|
||||
|
||||
if birdc -l show route "${LEARN_NET}" | egrep -q "Network not found"; then
|
||||
failed
|
||||
fi
|
||||
|
||||
cleanup
|
||||
exit 0
|
@ -1951,7 +1951,7 @@ protocol babel [<name>] {
|
||||
ipv6 [sadr] { <channel config> };
|
||||
randomize router id <switch>;
|
||||
interface <interface pattern> {
|
||||
type <wired|wireless>;
|
||||
type <wired|wireless|tunnel>;
|
||||
rxcost <number>;
|
||||
limit <number>;
|
||||
hello interval <time>;
|
||||
@ -1965,6 +1965,11 @@ protocol babel [<name>] {
|
||||
next hop ipv4 <address>;
|
||||
next hop ipv6 <address>;
|
||||
extended next hop <switch>;
|
||||
rtt cost <number>;
|
||||
rtt min <time>;
|
||||
rtt max <time>;
|
||||
rtt decay <number>;
|
||||
send timestamps <switch>;
|
||||
authentication none|mac [permissive];
|
||||
password "<text>";
|
||||
password "<text>" {
|
||||
@ -1995,15 +2000,16 @@ protocol babel [<name>] {
|
||||
router ID every time it starts up, which avoids this problem at the cost
|
||||
of not having stable router IDs in the network. Default: no.
|
||||
|
||||
<tag><label id="babel-type">type wired|wireless </tag>
|
||||
This option specifies the interface type: Wired or wireless. On wired
|
||||
interfaces a neighbor is considered unreachable after a small number of
|
||||
Hello packets are lost, as described by <cf/limit/ option. On wireless
|
||||
<tag><label id="babel-type">type wired|wireless|tunnel </tag>
|
||||
This option specifies the interface type: Wired, wireless or tunnel. On
|
||||
wired interfaces a neighbor is considered unreachable after a small number
|
||||
of Hello packets are lost, as described by <cf/limit/ option. On wireless
|
||||
interfaces the ETX link quality estimation technique is used to compute
|
||||
the metrics of routes discovered over this interface. This technique will
|
||||
gradually degrade the metric of routes when packets are lost rather than
|
||||
the more binary up/down mechanism of wired type links. Default:
|
||||
<cf/wired/.
|
||||
the more binary up/down mechanism of wired type links. A tunnel is like a
|
||||
wired interface, but turns on RTT-based metrics with a default cost of 96.
|
||||
Default: <cf/wired/.
|
||||
|
||||
<tag><label id="babel-rxcost">rxcost <m/num/</tag>
|
||||
This option specifies the nominal RX cost of the interface. The effective
|
||||
@ -2074,6 +2080,37 @@ protocol babel [<name>] {
|
||||
hop when IPv4 addresses are absent from the interface as described in
|
||||
<rfc id="9229">. Default: yes.
|
||||
|
||||
<tag><label id="babel-rtt-cost">rtt cost <m/number/</tag>
|
||||
The RTT-based cost that will be applied to all routes from each neighbour
|
||||
based on the measured RTT to that neighbour. If this value is set,
|
||||
timestamps will be included in generated Babel Hello and IHU messages, and
|
||||
(if the neighbours also have timestamps enabled), the RTT to each
|
||||
neighbour will be computed. An additional cost is added to a neighbour if
|
||||
its RTT is above the <ref id="babel-rtt-min" name="rtt min"> value
|
||||
configured on the interface. The added cost scales linearly from 0 up to
|
||||
the RTT cost configured in this option; the full cost is applied if the
|
||||
neighbour RTT reaches the RTT configured in the <ref id="babel-rtt-max"
|
||||
name="rtt max"> option (and for all RTTs above this value). Default: 0
|
||||
(disabled), except for tunnel interfaces, where it is 96.
|
||||
|
||||
<tag><label id="babel-rtt-min">rtt min <m/time/ s|ms</tag>
|
||||
The minimum RTT above which the RTT cost will start to be applied (scaling
|
||||
linearly from zero up to the full cost). Default: 10 ms
|
||||
|
||||
<tag><label id="babel-rtt-max">rtt max <m/time/ s|ms</tag>
|
||||
The maximum RTT above which the full RTT cost will start be applied.
|
||||
Default: 120 ms
|
||||
|
||||
<tag><label id="babel-rtt-decay">rtt decay <m/number/</tag>
|
||||
The decay factor used for the exponentional moving average of the RTT
|
||||
samples from each neighbour, in units of 1/256. Higher values discards old
|
||||
RTT samples faster. Must be between 1 and 256. Default: 42
|
||||
|
||||
<tag><label id="babel-send-timestamps">send timestamps <m/switch/</tag>
|
||||
Whether to send the timestamps used for RTT calculation on this interface.
|
||||
Sending the timestamps enables peers to calculate an RTT to this node,
|
||||
even if no RTT cost is applied to the route metrics. Default: yes.
|
||||
|
||||
<tag><label id="babel-authentication">authentication none|mac [permissive]</tag>
|
||||
Selects authentication method to be used. <cf/none/ means that packets
|
||||
are not authenticated at all, <cf/mac/ means MAC authentication is
|
||||
@ -2421,7 +2458,6 @@ avoid routing loops.
|
||||
<item> <rfc id="5065"> - AS confederations for BGP
|
||||
<item> <rfc id="5082"> - Generalized TTL Security Mechanism
|
||||
<item> <rfc id="5492"> - Capabilities Advertisement with BGP
|
||||
<item> <rfc id="5549"> - Advertising IPv4 NLRI with an IPv6 Next Hop
|
||||
<item> <rfc id="5575"> - Dissemination of Flow Specification Rules
|
||||
<item> <rfc id="5668"> - 4-Octet AS Specific BGP Extended Community
|
||||
<item> <rfc id="6286"> - AS-Wide Unique BGP Identifier
|
||||
@ -2436,6 +2472,7 @@ avoid routing loops.
|
||||
<item> <rfc id="8203"> - BGP Administrative Shutdown Communication
|
||||
<item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
|
||||
<item> <rfc id="8654"> - Extended Message Support for BGP
|
||||
<item> <rfc id="8950"> - Advertising IPv4 NLRI with an IPv6 Next Hop
|
||||
<item> <rfc id="9072"> - Extended Optional Parameters Length for BGP OPEN Message
|
||||
<item> <rfc id="9117"> - Revised Validation Procedure for BGP Flow Specifications
|
||||
<item> <rfc id="9234"> - Route Leak Prevention and Detection Using Roles
|
||||
@ -3089,7 +3126,7 @@ be used in explicit configuration.
|
||||
associated network prefixes. This option provides an extension to use
|
||||
IPv4 next hops with IPv6 prefixes and vice versa. For IPv4 / VPNv4
|
||||
channels, the behavior is controlled by the Extended Next Hop Encoding
|
||||
capability, as described in <rfc id="5549">. For IPv6 / VPNv6 channels,
|
||||
capability, as described in <rfc id="8950">. For IPv6 / VPNv6 channels,
|
||||
just IPv4-mapped IPv6 addresses are used, as described in
|
||||
<rfc id="4798"> and <rfc id="4659">. Default: off.
|
||||
|
||||
@ -5367,8 +5404,8 @@ as the destination becomes adjacent again.
|
||||
(i.e., they can be used multiple times for a route, one time for each nexthop).
|
||||
Syntactically, they are not separate options but just parts of <cf/route/
|
||||
statement after each <cf/via/ statement, not separated by semicolons. E.g.,
|
||||
statement <cf/route 10.0.0.0/8 via 192.0.2.1 bfd weight 1 via 192.0.2.2 weight
|
||||
2;/ describes a route with two nexthops, the first nexthop has two per-nexthop
|
||||
statement <cf>route 10.0.0.0/8 via 192.0.2.1 bfd weight 1 via 192.0.2.2 weight
|
||||
2;</cf> describes a route with two nexthops, the first nexthop has two per-nexthop
|
||||
options (<cf/bfd/ and <cf/weight 1/), the second nexthop has just <cf/weight 2/.
|
||||
|
||||
<descrip>
|
||||
|
@ -200,7 +200,7 @@ FID_INTERPRET_BODY()')
|
||||
# Executing another filter line. This replaces the recursion
|
||||
# that was needed in the former implementation.
|
||||
m4_define(LINEX, `FID_INTERPRET_EXEC()LINEX_($1)FID_INTERPRET_NEW()return $1 FID_INTERPRET_BODY()')
|
||||
m4_define(LINEX_, `do {
|
||||
m4_define(LINEX_, `do if ($1) {
|
||||
if (fstk->ecnt + 1 >= fstk->elen) runtime("Filter execution stack overflow");
|
||||
fstk->estk[fstk->ecnt].pos = 0;
|
||||
fstk->estk[fstk->ecnt].line = $1;
|
||||
@ -228,9 +228,7 @@ if (!f_same(f1->fl$1, f2->fl$1)) return 0;
|
||||
FID_ITERATE_BODY()m4_dnl
|
||||
if (whati->fl$1) BUFFER_PUSH(fit->lines) = whati->fl$1;
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
do { if (whati->fl$1) {
|
||||
LINEX_(whati->fl$1);
|
||||
} } while(0)
|
||||
LINEX_(whati->fl$1)
|
||||
FID_INTERPRET_NEW()m4_dnl
|
||||
return whati->f$1
|
||||
FID_INTERPRET_BODY()')
|
||||
|
@ -1302,7 +1302,6 @@
|
||||
FID_HIC(,break,return NULL);
|
||||
}
|
||||
}
|
||||
/* It is actually possible to have t->data NULL */
|
||||
|
||||
LINEX(t->data);
|
||||
}
|
||||
|
@ -140,6 +140,18 @@ bt_test_same(onef, onef, 1);
|
||||
bt_test_same(onef, oneg, 1);
|
||||
bt_test_same(onef, twof, 0);
|
||||
|
||||
/*
|
||||
* Testing filter corner cases
|
||||
* ---------------------------
|
||||
*/
|
||||
|
||||
function t_nothing() {}
|
||||
bt_test_suite(t_nothing, "Testing nothing");
|
||||
|
||||
function t_metanothing() { t_nothing(); }
|
||||
bt_test_suite(t_metanothing, "Testing meta nothing");
|
||||
|
||||
|
||||
/*
|
||||
* Testing boolean expressions
|
||||
* ---------------------------
|
||||
@ -178,6 +190,14 @@ bt_test_suite(t_bool, "Testing boolean expressions");
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
function aux_t_int(int t; int u)
|
||||
{
|
||||
case t {
|
||||
1: {}
|
||||
else: {}
|
||||
}
|
||||
}
|
||||
|
||||
define four = 4;
|
||||
define xyzzy = (120+10);
|
||||
define '1a-a1' = (xyzzy-100);
|
||||
@ -230,7 +250,10 @@ function t_int()
|
||||
else: bt_assert(false);
|
||||
}
|
||||
|
||||
|
||||
aux_t_int(1, 2);
|
||||
aux_t_int(1, 3);
|
||||
aux_t_int(2, 3);
|
||||
aux_t_int(2, 2);
|
||||
}
|
||||
|
||||
bt_test_suite(t_int, "Testing integers");
|
||||
|
@ -28,12 +28,6 @@ struct f_prefix_node {
|
||||
struct f_prefix prefix;
|
||||
};
|
||||
|
||||
static u32
|
||||
xrandom(u32 max)
|
||||
{
|
||||
return (bt_random() % max);
|
||||
}
|
||||
|
||||
static inline uint
|
||||
get_exp_random(void)
|
||||
{
|
||||
@ -95,27 +89,10 @@ is_prefix_included(list *prefixes, const net_addr *needle)
|
||||
return 0; /* FAIL */
|
||||
}
|
||||
|
||||
static void
|
||||
get_random_net(net_addr *net, int v6)
|
||||
{
|
||||
if (!v6)
|
||||
{
|
||||
uint pxlen = xrandom(24)+8;
|
||||
ip4_addr ip4 = ip4_from_u32((u32) bt_random());
|
||||
net_fill_ip4(net, ip4_and(ip4, ip4_mkmask(pxlen)), pxlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint pxlen = xrandom(120)+8;
|
||||
ip6_addr ip6 = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
|
||||
net_fill_ip6(net, ip6_and(ip6, ip6_mkmask(pxlen)), pxlen);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_random_prefix(struct f_prefix *px, int v6, int tight)
|
||||
{
|
||||
get_random_net(&px->net, v6);
|
||||
bt_random_net(&px->net, !v6 ? NET_IP4 : NET_IP6);
|
||||
|
||||
if (tight)
|
||||
{
|
||||
@ -379,7 +356,7 @@ select_random_prefix_subset(list *src[], net_addr dst[], int sn, int dn)
|
||||
struct f_prefix_node *px;
|
||||
WALK_LIST(px, *src[i])
|
||||
{
|
||||
if (xrandom(rnd) != 0)
|
||||
if (bt_random_n(rnd) != 0)
|
||||
continue;
|
||||
|
||||
net_copy(&dst[n], &px->prefix.net);
|
||||
@ -395,7 +372,7 @@ done:
|
||||
/* Shuffle networks */
|
||||
for (int i = 0; i < dn; i++)
|
||||
{
|
||||
int j = xrandom(dn);
|
||||
int j = bt_random_n(dn);
|
||||
|
||||
if (i == j)
|
||||
continue;
|
||||
@ -441,7 +418,7 @@ t_match_random_net(void)
|
||||
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
|
||||
{
|
||||
net_addr net;
|
||||
get_random_net(&net, v6);
|
||||
bt_random_net(&net, !v6 ? NET_IP4 : NET_IP6);
|
||||
test_match_net(prefixes, trie, &net);
|
||||
}
|
||||
|
||||
@ -795,7 +772,7 @@ t_trie_walk_to_root(void)
|
||||
for (i = 0; i < (PREFIX_TESTS_NUM / 10); i++)
|
||||
{
|
||||
net_addr from;
|
||||
get_random_net(&from, v6);
|
||||
bt_random_net(&from, !v6 ? NET_IP4 : NET_IP6);
|
||||
|
||||
net_addr found[129];
|
||||
int found_num = find_covering_nets(pxset, num, &from, found);
|
||||
|
@ -239,10 +239,36 @@ asm(
|
||||
);
|
||||
#endif
|
||||
|
||||
|
||||
/* Pseudorandom numbers */
|
||||
|
||||
u32 random_u32(void);
|
||||
void random_init(void);
|
||||
void random_bytes(void *buf, size_t size);
|
||||
|
||||
|
||||
/* Hashing */
|
||||
|
||||
/* Constant parameter for non-parametrized hashes */
|
||||
#define HASH_PARAM 2902958171u
|
||||
|
||||
/* Precomputed powers of HASH_PARAM */
|
||||
#define HASH_PARAM1 ((u64) HASH_PARAM)
|
||||
#define HASH_PARAM2 (HASH_PARAM1 * HASH_PARAM)
|
||||
#define HASH_PARAM3 (HASH_PARAM2 * HASH_PARAM)
|
||||
#define HASH_PARAM4 (HASH_PARAM3 * HASH_PARAM)
|
||||
|
||||
/* Reduce intermediate 64-bit value to final 32-bit value */
|
||||
static inline u32 hash_value(u64 a)
|
||||
{ return ((u32) a) ^ ((u32) (a >> 32)); }
|
||||
|
||||
static inline u64 u32_hash0(u32 v, u32 p, u64 acc)
|
||||
{ return (acc + v) * p; }
|
||||
|
||||
static inline u64 u64_hash0(u64 v, u32 p, u64 acc)
|
||||
{ return u32_hash0(v >> 32, p, u32_hash0(v, p, acc)); }
|
||||
|
||||
static inline u32 u64_hash(u64 v)
|
||||
{ return hash_value(u64_hash0(v, HASH_PARAM, 0)); }
|
||||
|
||||
#endif
|
||||
|
31
lib/ip.h
31
lib/ip.h
@ -194,14 +194,37 @@ static inline int ipa_nonzero2(ip_addr a)
|
||||
* Hash and compare functions
|
||||
*/
|
||||
|
||||
static inline u64 ip4_hash0(ip4_addr a, u32 p, u64 acc)
|
||||
{ return (acc + _I(a)) * p; }
|
||||
|
||||
static inline u32 ip4_hash(ip4_addr a)
|
||||
{ return u32_hash(_I(a)); }
|
||||
{
|
||||
// return hash_value(ip4_hash0(a, HASH_PARAM, 0));
|
||||
|
||||
/* For some reason, the old hash works slightly better */
|
||||
return u32_hash(_I(a));
|
||||
}
|
||||
|
||||
static inline u64 ip6_hash0(ip6_addr a, u32 p, u64 acc)
|
||||
{
|
||||
acc += _I0(a); acc *= p;
|
||||
acc += _I1(a); acc *= p;
|
||||
acc += _I2(a); acc *= p;
|
||||
acc += _I3(a); acc *= p;
|
||||
return acc;
|
||||
}
|
||||
|
||||
static inline u32 ip6_hash(ip6_addr a)
|
||||
{
|
||||
/* Returns a 32-bit hash key, although low-order bits are not mixed */
|
||||
u32 x = _I0(a) ^ _I1(a) ^ _I2(a) ^ _I3(a);
|
||||
return x ^ (x << 16) ^ (x << 24);
|
||||
// return hash_value(ip6_hash0(a, HASH_PARAM, 0));
|
||||
|
||||
/* Just use the expanded form */
|
||||
u64 acc =
|
||||
_I0(a) * HASH_PARAM4 +
|
||||
_I1(a) * HASH_PARAM3 +
|
||||
_I2(a) * HASH_PARAM2 +
|
||||
_I3(a) * HASH_PARAM1;
|
||||
return hash_value(acc);
|
||||
}
|
||||
|
||||
static inline int ip4_compare(ip4_addr a, ip4_addr b)
|
||||
|
34
lib/net.h
34
lib/net.h
@ -479,39 +479,47 @@ static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
|
||||
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
|
||||
|
||||
|
||||
/* XXXX */
|
||||
static inline u32 u64_hash(u64 a)
|
||||
{ return u32_hash(a); }
|
||||
static inline u32 px4_hash(ip4_addr prefix, u32 pxlen)
|
||||
{ return ip4_hash(prefix) ^ (pxlen << 26); }
|
||||
|
||||
static inline u32 px6_hash(ip6_addr prefix, u32 pxlen)
|
||||
{ return ip6_hash(prefix) ^ (pxlen << 26); }
|
||||
|
||||
static inline u32 net_hash_ip4(const net_addr_ip4 *n)
|
||||
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px4_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_ip6(const net_addr_ip6 *n)
|
||||
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px6_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
|
||||
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
|
||||
{
|
||||
u64 acc = ip4_hash0(n->prefix, HASH_PARAM, 0) ^ (n->pxlen << 26);
|
||||
return hash_value(u64_hash0(n->rd, HASH_PARAM, acc));
|
||||
}
|
||||
|
||||
static inline u32 net_hash_vpn6(const net_addr_vpn6 *n)
|
||||
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
|
||||
{
|
||||
u64 acc = ip6_hash0(n->prefix, HASH_PARAM, 0) ^ (n->pxlen << 26);
|
||||
return hash_value(u64_hash0(n->rd, HASH_PARAM, acc));
|
||||
}
|
||||
|
||||
static inline u32 net_hash_roa4(const net_addr_roa4 *n)
|
||||
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px4_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_roa6(const net_addr_roa6 *n)
|
||||
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px6_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_flow4(const net_addr_flow4 *n)
|
||||
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px4_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_flow6(const net_addr_flow6 *n)
|
||||
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
|
||||
{ return px6_hash(n->prefix, n->pxlen); }
|
||||
|
||||
static inline u32 net_hash_ip6_sadr(const net_addr_ip6_sadr *n)
|
||||
{ return net_hash_ip6((net_addr_ip6 *) n); }
|
||||
{ return px6_hash(n->dst_prefix, n->dst_pxlen); }
|
||||
|
||||
static inline u32 net_hash_mpls(const net_addr_mpls *n)
|
||||
{ return n->label; }
|
||||
{ return u32_hash(n->label); }
|
||||
|
||||
u32 net_hash(const net_addr *a);
|
||||
|
||||
|
@ -55,6 +55,9 @@ static inline timer *timers_first(struct timeloop *loop)
|
||||
#define current_time() atomic_load_explicit(&last_time, memory_order_acquire)
|
||||
#define current_real_time() atomic_load_explicit(&real_time, memory_order_acquire)
|
||||
|
||||
/* In sysdep code */
|
||||
btime current_time_now(void);
|
||||
|
||||
//#define now (current_time() TO_S)
|
||||
//#define now_real (current_real_time() TO_S)
|
||||
extern btime boot_time;
|
||||
|
@ -13,6 +13,6 @@ $(o)proto-build.c: Makefile $(lastword $(MAKEFILE_LIST)) $(objdir)/.dir-stamp
|
||||
|
||||
prepare: $(o)proto-build.c
|
||||
|
||||
tests_src :=
|
||||
tests_src := rt-fib_test.c
|
||||
tests_targets := $(tests_targets) $(tests-target-files)
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
||||
|
240
nest/rt-fib_test.c
Normal file
240
nest/rt-fib_test.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* BIRD -- Forwarding Information Base -- Tests
|
||||
*
|
||||
* (c) 2023 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#include "test/birdtest.h"
|
||||
#include "test/bt-utils.h"
|
||||
|
||||
#include "nest/rt.h"
|
||||
|
||||
|
||||
#define TESTS_NUM 10
|
||||
#define PREFIXES_NUM 400000
|
||||
#define PREFIX_TESTS_NUM 200000
|
||||
#define PREFIX_BENCH_MAX 1000000
|
||||
#define PREFIX_BENCH_NUM 10000000
|
||||
|
||||
struct test_node
|
||||
{
|
||||
int pos;
|
||||
struct fib_node n;
|
||||
};
|
||||
|
||||
static inline int net_match(struct test_node *tn, net_addr *query, net_addr *data)
|
||||
{ return (tn->pos < PREFIXES_NUM) && net_equal(query, &data[tn->pos]); }
|
||||
|
||||
static int
|
||||
t_match_random_net(void)
|
||||
{
|
||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||
|
||||
for (int round = 0; round < TESTS_NUM; round++)
|
||||
{
|
||||
int type = !(round & 1) ? NET_IP4 : NET_IP6;
|
||||
|
||||
pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool");
|
||||
net_addr *nets = bt_random_nets(type, PREFIXES_NUM);
|
||||
|
||||
/* Make FIB structure */
|
||||
struct fib f;
|
||||
fib_init(&f, &root_pool, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 4, NULL);
|
||||
|
||||
for (int i = 0; i < PREFIXES_NUM; i++)
|
||||
{
|
||||
struct test_node *tn = fib_get(&f, &nets[i]);
|
||||
bt_assert(!tn->pos || net_match(tn, &nets[i], nets));
|
||||
tn->pos = i;
|
||||
}
|
||||
|
||||
/* Test (mostly) negative matches */
|
||||
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
|
||||
{
|
||||
net_addr net;
|
||||
bt_random_net(&net, type);
|
||||
|
||||
struct test_node *tn = fib_find(&f, &net);
|
||||
bt_assert(!tn || net_match(tn, &net, nets));
|
||||
}
|
||||
|
||||
/* Test positive matches */
|
||||
for (int i = 0; i < PREFIX_TESTS_NUM; i++)
|
||||
{
|
||||
int j = bt_random_n(PREFIXES_NUM);
|
||||
|
||||
struct test_node *tn = fib_find(&f, &nets[j]);
|
||||
bt_assert(tn && net_match(tn, &nets[j], nets));
|
||||
}
|
||||
|
||||
rfree(p);
|
||||
tmp_flush();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
t_fib_walk(void)
|
||||
{
|
||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||
|
||||
for (int round = 0; round < TESTS_NUM; round++)
|
||||
{
|
||||
int type = !(round & 1) ? NET_IP4 : NET_IP6;
|
||||
|
||||
pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool");
|
||||
net_addr *nets = bt_random_nets(type, PREFIXES_NUM);
|
||||
byte *marks = tmp_allocz(PREFIXES_NUM);
|
||||
|
||||
/* Make FIB structure */
|
||||
struct fib f;
|
||||
fib_init(&f, p, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 4, NULL);
|
||||
|
||||
for (int i = 1; i < PREFIXES_NUM; i++)
|
||||
{
|
||||
struct test_node *tn = fib_get(&f, &nets[i]);
|
||||
bt_assert(!tn->pos || net_match(tn, &nets[i], nets));
|
||||
if (tn->pos)
|
||||
{
|
||||
/* Mark dupicate nets */
|
||||
bt_assert(!marks[tn->pos]);
|
||||
marks[tn->pos] = 1;
|
||||
}
|
||||
tn->pos = i;
|
||||
}
|
||||
|
||||
/* Walk FIB and mark nets */
|
||||
FIB_WALK(&f, struct test_node, tn)
|
||||
{
|
||||
bt_assert(!marks[tn->pos]);
|
||||
marks[tn->pos] = 1;
|
||||
}
|
||||
FIB_WALK_END;
|
||||
|
||||
/* Check in all nets are marked */
|
||||
for (int i = 1; i < PREFIXES_NUM; i++)
|
||||
bt_assert(marks[i]);
|
||||
|
||||
rfree(p);
|
||||
tmp_flush();
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
benchmark_fib_dataset(const char *filename, int type)
|
||||
{
|
||||
net_addr *nets, *test_r, *test_s;
|
||||
uint n = PREFIX_BENCH_MAX;
|
||||
int tn = PREFIX_BENCH_NUM;
|
||||
int match;
|
||||
|
||||
bt_reset_suite_case_timer();
|
||||
bt_log_suite_case_result(1, "Reading %s", filename, n);
|
||||
nets = bt_read_net_file(filename, type, &n);
|
||||
bt_log_suite_case_result(1, "Read net data, %u nets", n);
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
pool *p = rp_new(&root_pool, the_bird_domain.the_bird, "FIB pool");
|
||||
|
||||
/* Make FIB structure */
|
||||
struct fib f;
|
||||
fib_init(&f, p, type, sizeof(struct test_node), OFFSETOF(struct test_node, n), 0, NULL);
|
||||
|
||||
for (int i = 0; i < (int) n; i++)
|
||||
{
|
||||
struct test_node *tn = fib_get(&f, &nets[i]);
|
||||
tn->pos = i;
|
||||
}
|
||||
|
||||
bt_log_suite_case_result(1, "Fill FIB structure, %u nets, order %u", n, f.hash_order);
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
/* Compute FIB size */
|
||||
size_t fib_size = rmemsize(p).effective * 1000 / (1024*1024);
|
||||
bt_log_suite_case_result(1, "FIB size: %u.%03u MB", (uint) (fib_size / 1000), (uint) (fib_size % 1000));
|
||||
|
||||
/* Compute FIB histogram */
|
||||
uint hist[16] = {};
|
||||
uint sum = 0;
|
||||
for (uint i = 0; i < f.hash_size; i++)
|
||||
{
|
||||
int len = 0;
|
||||
for (struct fib_node *fn = f.hash_table[i]; fn; fn = fn->next)
|
||||
len++;
|
||||
|
||||
sum += len;
|
||||
len = MIN(len, 15);
|
||||
hist[len]++;
|
||||
}
|
||||
bt_log_suite_case_result(1, "FIB histogram:");
|
||||
for (uint i = 0; i < 16; i++)
|
||||
if (hist[i])
|
||||
bt_log_suite_case_result(1, "%02u: %8u", i, hist[i]);
|
||||
|
||||
uint avg = (sum * 1000) / (f.hash_size - hist[0]);
|
||||
bt_log_suite_case_result(1, "FIB chain length: %u.%03u", (uint) (avg / 1000), (uint) (avg % 1000));
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
/* Make test data */
|
||||
test_r = bt_random_nets(type, tn);
|
||||
test_s = bt_random_net_subset(nets, n, tn);
|
||||
|
||||
bt_log_suite_case_result(1, "Make test data, 2x %u nets", tn);
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
/* Test (mostly negative) random matches */
|
||||
match = 0;
|
||||
for (int i = 0; i < tn; i++)
|
||||
if (fib_find(&f, &test_r[i]))
|
||||
match++;
|
||||
|
||||
bt_log_suite_case_result(1, "Random match, %d / %d matches", match, tn);
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
/* Test (positive) subset matches */
|
||||
match = 0;
|
||||
for (int i = 0; i < tn; i++)
|
||||
if (fib_find(&f, &test_s[i]))
|
||||
match++;
|
||||
|
||||
bt_log_suite_case_result(1, "Subset match, %d / %d matches", match, tn);
|
||||
bt_log_suite_case_result(1, "");
|
||||
bt_reset_suite_case_timer();
|
||||
|
||||
rfree(p);
|
||||
tmp_flush();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int UNUSED
|
||||
t_bench_fib_datasets(void)
|
||||
{
|
||||
bt_config_parse(BT_CONFIG_SIMPLE);
|
||||
|
||||
/* Specific datasets, not included */
|
||||
benchmark_fib_dataset("fib-data-bgp-v4-1", NET_IP4);
|
||||
benchmark_fib_dataset("fib-data-bgp-v4-10", NET_IP4);
|
||||
benchmark_fib_dataset("fib-data-bgp-v6-1", NET_IP6);
|
||||
benchmark_fib_dataset("fib-data-bgp-v6-10", NET_IP6);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
bt_init(argc, argv);
|
||||
bt_bird_init();
|
||||
|
||||
bt_test_suite(t_match_random_net, "Testing random prefix matching");
|
||||
bt_test_suite(t_fib_walk, "Testing FIB_WALK() on random FIB");
|
||||
|
||||
// bt_test_suite(t_bench_fib_datasets, "Benchmark FIB from datasets by random subset of nets");
|
||||
|
||||
return bt_exit_value();
|
||||
}
|
@ -599,6 +599,7 @@ babel_update_cost(struct babel_neighbor *nbr)
|
||||
switch (cf->type)
|
||||
{
|
||||
case BABEL_IFACE_TYPE_WIRED:
|
||||
case BABEL_IFACE_TYPE_TUNNEL:
|
||||
/* k-out-of-j selection - Appendix 2.1 in the RFC. */
|
||||
|
||||
/* Link is bad if less than cf->limit/16 of expected hellos were received */
|
||||
@ -627,6 +628,24 @@ babel_update_cost(struct babel_neighbor *nbr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cf->rtt_cost && nbr->srtt > cf->rtt_min)
|
||||
{
|
||||
uint rtt_cost = cf->rtt_cost;
|
||||
|
||||
if (nbr->srtt < cf->rtt_max)
|
||||
{
|
||||
uint rtt_interval = cf->rtt_max TO_US - cf->rtt_min TO_US;
|
||||
uint rtt_diff = (nbr->srtt TO_US - cf->rtt_min TO_US);
|
||||
|
||||
rtt_cost = (rtt_cost * rtt_diff) / rtt_interval;
|
||||
}
|
||||
|
||||
txcost = MIN(txcost + rtt_cost, BABEL_INFINITY);
|
||||
|
||||
TRACE(D_EVENTS, "Added RTT cost %u to nbr %I on %s with srtt %t ms",
|
||||
rtt_cost, nbr->addr, nbr->ifa->iface->name, nbr->srtt * 1000);
|
||||
}
|
||||
|
||||
done:
|
||||
/* If RX cost changed, send IHU with next Hello */
|
||||
if (rxcost != nbr->rxcost)
|
||||
@ -853,6 +872,12 @@ babel_build_ihu(union babel_msg *msg, struct babel_iface *ifa, struct babel_neig
|
||||
msg->ihu.rxcost = n->rxcost;
|
||||
msg->ihu.interval = ifa->cf->ihu_interval;
|
||||
|
||||
if (n->last_tstamp_rcvd && ifa->cf->rtt_send)
|
||||
{
|
||||
msg->ihu.tstamp = n->last_tstamp;
|
||||
msg->ihu.tstamp_rcvd = n->last_tstamp_rcvd TO_US;
|
||||
}
|
||||
|
||||
TRACE(D_PACKETS, "Sending IHU for %I with rxcost %d interval %t",
|
||||
msg->ihu.addr, msg->ihu.rxcost, (btime) msg->ihu.interval);
|
||||
}
|
||||
@ -892,6 +917,9 @@ babel_send_hello(struct babel_iface *ifa, uint interval)
|
||||
msg.hello.seqno = ifa->hello_seqno++;
|
||||
msg.hello.interval = interval ?: ifa->cf->hello_interval;
|
||||
|
||||
if (ifa->cf->rtt_send)
|
||||
msg.hello.tstamp = 1; /* real timestamp will be set on TLV write */
|
||||
|
||||
TRACE(D_PACKETS, "Sending hello on %s with seqno %d interval %t",
|
||||
ifa->ifname, msg.hello.seqno, (btime) msg.hello.interval);
|
||||
|
||||
@ -1198,14 +1226,26 @@ babel_handle_hello(union babel_msg *m, struct babel_iface *ifa)
|
||||
msg->seqno, (btime) msg->interval);
|
||||
|
||||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||
struct babel_iface_config *cf = n->ifa->cf;
|
||||
int first_hello = !n->hello_cnt;
|
||||
|
||||
if (msg->tstamp)
|
||||
{
|
||||
n->last_tstamp = msg->tstamp;
|
||||
n->last_tstamp_rcvd = msg->pkt_received;
|
||||
}
|
||||
babel_update_hello_history(n, msg->seqno, msg->interval);
|
||||
babel_update_cost(n);
|
||||
|
||||
/* Speed up session establishment by sending IHU immediately */
|
||||
if (first_hello)
|
||||
babel_send_ihu(ifa, n);
|
||||
{
|
||||
/* if using RTT, all IHUs must be paired with hellos */
|
||||
if(cf->rtt_send)
|
||||
babel_send_hello(ifa, 0);
|
||||
else
|
||||
babel_send_ihu(ifa, n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -1224,6 +1264,39 @@ babel_handle_ihu(union babel_msg *m, struct babel_iface *ifa)
|
||||
struct babel_neighbor *n = babel_get_neighbor(ifa, msg->sender);
|
||||
n->txcost = msg->rxcost;
|
||||
n->ihu_expiry = current_time() + BABEL_IHU_EXPIRY_FACTOR(msg->interval);
|
||||
|
||||
if (msg->tstamp)
|
||||
{
|
||||
u32 rtt_sample = 0, pkt_received = msg->pkt_received TO_US;
|
||||
int remote_time, full_time;
|
||||
|
||||
/* processing time reported by peer */
|
||||
remote_time = (n->last_tstamp - msg->tstamp_rcvd);
|
||||
/* time since we sent the last timestamp - RTT including remote time */
|
||||
full_time = (pkt_received - msg->tstamp);
|
||||
|
||||
/* sanity checks */
|
||||
if (remote_time < 0 || full_time < 0 ||
|
||||
remote_time US_ > BABEL_RTT_MAX_VALUE || full_time US_ > BABEL_RTT_MAX_VALUE)
|
||||
goto out;
|
||||
|
||||
if (remote_time < full_time)
|
||||
rtt_sample = full_time - remote_time;
|
||||
|
||||
if (n->srtt)
|
||||
{
|
||||
uint decay = n->ifa->cf->rtt_decay;
|
||||
|
||||
n->srtt = (decay * rtt_sample + (256 - decay) * n->srtt) / 256;
|
||||
}
|
||||
else
|
||||
n->srtt = rtt_sample;
|
||||
|
||||
TRACE(D_EVENTS, "RTT sample for neighbour %I on %s: %u us (srtt %t ms)",
|
||||
n->addr, ifa->ifname, rtt_sample, n->srtt * 1000);
|
||||
}
|
||||
|
||||
out:
|
||||
babel_update_cost(n);
|
||||
}
|
||||
|
||||
@ -2203,8 +2276,8 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
||||
}
|
||||
|
||||
cli_msg(-1024, "%s:", p->p.name);
|
||||
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s",
|
||||
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth");
|
||||
cli_msg(-1024, "%-25s %-10s %6s %6s %6s %7s %4s %9s",
|
||||
"IP address", "Interface", "Metric", "Routes", "Hellos", "Expires", "Auth", "RTT (ms)");
|
||||
|
||||
WALK_LIST(ifa, p->interfaces)
|
||||
{
|
||||
@ -2219,9 +2292,10 @@ babel_show_neighbors(struct proto *P, const char *iff)
|
||||
|
||||
uint hellos = u32_popcount(n->hello_map);
|
||||
btime timer = (n->hello_expiry ?: n->init_expiry) - current_time();
|
||||
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t %-4s",
|
||||
cli_msg(-1024, "%-25I %-10s %6u %6u %6u %7t %-4s %9t",
|
||||
n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0),
|
||||
n->auth_passed ? "Yes" : "No");
|
||||
n->auth_passed ? "Yes" : "No",
|
||||
n->srtt * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -49,10 +49,16 @@
|
||||
#define BABEL_GARBAGE_INTERVAL (300 S_)
|
||||
#define BABEL_RXCOST_WIRED 96
|
||||
#define BABEL_RXCOST_WIRELESS 256
|
||||
#define BABEL_RXCOST_RTT 96
|
||||
#define BABEL_INITIAL_HOP_COUNT 255
|
||||
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
|
||||
#define BABEL_INITIAL_NEIGHBOR_TIMEOUT (60 S_)
|
||||
|
||||
#define BABEL_RTT_MAX_VALUE (600 S_)
|
||||
#define BABEL_RTT_MIN (10 MS_)
|
||||
#define BABEL_RTT_MAX (120 MS_)
|
||||
#define BABEL_RTT_DECAY 42
|
||||
|
||||
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
||||
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
|
||||
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
|
||||
@ -92,6 +98,8 @@ enum babel_tlv_type {
|
||||
enum babel_subtlv_type {
|
||||
BABEL_SUBTLV_PAD1 = 0,
|
||||
BABEL_SUBTLV_PADN = 1,
|
||||
BABEL_SUBTLV_DIVERSITY = 2, /* we don't support this */
|
||||
BABEL_SUBTLV_TIMESTAMP = 3,
|
||||
|
||||
/* Mandatory subtlvs */
|
||||
BABEL_SUBTLV_SOURCE_PREFIX = 128,
|
||||
@ -102,6 +110,7 @@ enum babel_iface_type {
|
||||
BABEL_IFACE_TYPE_UNDEF = 0,
|
||||
BABEL_IFACE_TYPE_WIRED = 1,
|
||||
BABEL_IFACE_TYPE_WIRELESS = 2,
|
||||
BABEL_IFACE_TYPE_TUNNEL = 3,
|
||||
BABEL_IFACE_TYPE_MAX
|
||||
};
|
||||
|
||||
@ -137,6 +146,12 @@ struct babel_iface_config {
|
||||
uint ihu_interval; /* IHU interval, in us */
|
||||
uint update_interval; /* Update interval, in us */
|
||||
|
||||
btime rtt_min; /* rtt above which to start penalising metric */
|
||||
btime rtt_max; /* max rtt metric penalty applied above this */
|
||||
u16 rtt_cost; /* metric penalty to apply at rtt_max */
|
||||
u16 rtt_decay; /* decay of neighbour RTT (units of 1/256) */
|
||||
u8 rtt_send; /* whether to send timestamps on this interface */
|
||||
|
||||
u16 rx_buffer; /* RX buffer size, 0 for MTU */
|
||||
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
||||
int tx_tos;
|
||||
@ -225,6 +240,10 @@ struct babel_neighbor {
|
||||
u16 next_hello_seqno;
|
||||
uint last_hello_int;
|
||||
|
||||
u32 last_tstamp;
|
||||
btime last_tstamp_rcvd;
|
||||
btime srtt;
|
||||
|
||||
u32 auth_pc_unicast;
|
||||
u32 auth_pc_multicast;
|
||||
u8 auth_passed;
|
||||
@ -323,6 +342,8 @@ struct babel_msg_hello {
|
||||
u16 seqno;
|
||||
uint interval;
|
||||
ip_addr sender;
|
||||
u32 tstamp;
|
||||
btime pkt_received;
|
||||
};
|
||||
|
||||
struct babel_msg_ihu {
|
||||
@ -332,6 +353,9 @@ struct babel_msg_ihu {
|
||||
uint interval;
|
||||
ip_addr addr;
|
||||
ip_addr sender;
|
||||
u32 tstamp;
|
||||
u32 tstamp_rcvd;
|
||||
btime pkt_received;
|
||||
};
|
||||
|
||||
struct babel_msg_update {
|
||||
|
@ -26,7 +26,7 @@ CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
|
||||
TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
|
||||
NEXT, HOP, IPV4, IPV6, SHOW, INTERFACES, NEIGHBORS,
|
||||
ENTRIES, RANDOMIZE, ROUTER, ID, AUTHENTICATION, NONE, MAC, PERMISSIVE,
|
||||
EXTENDED)
|
||||
EXTENDED, TUNNEL, RTT, MIN, MAX, DECAY, SEND, TIMESTAMPS)
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -67,6 +67,10 @@ babel_iface_start:
|
||||
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
|
||||
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||
BABEL_IFACE->tx_priority = sk_priority_control;
|
||||
BABEL_IFACE->rtt_min = BABEL_RTT_MIN;
|
||||
BABEL_IFACE->rtt_max = BABEL_RTT_MAX;
|
||||
BABEL_IFACE->rtt_decay = BABEL_RTT_DECAY;
|
||||
BABEL_IFACE->rtt_send = 1;
|
||||
BABEL_IFACE->check_link = 1;
|
||||
BABEL_IFACE->ext_next_hop = 1;
|
||||
};
|
||||
@ -87,8 +91,16 @@ babel_iface_finish:
|
||||
BABEL_IFACE->hello_interval = BABEL_HELLO_INTERVAL_WIRED;
|
||||
if (!BABEL_IFACE->rxcost)
|
||||
BABEL_IFACE->rxcost = BABEL_RXCOST_WIRED;
|
||||
if (BABEL_IFACE->type == BABEL_IFACE_TYPE_TUNNEL && !BABEL_IFACE->rtt_cost)
|
||||
BABEL_IFACE->rtt_cost = BABEL_RXCOST_RTT;
|
||||
}
|
||||
|
||||
if (BABEL_IFACE->rtt_cost && !BABEL_IFACE->rtt_send)
|
||||
cf_error("Can't set RTT cost when sending timestamps is disabled");
|
||||
|
||||
if (BABEL_IFACE->rtt_min >= BABEL_IFACE->rtt_max)
|
||||
cf_error("Min RTT must be smaller than max RTT");
|
||||
|
||||
/* Make sure we do not overflow the 16-bit centisec fields */
|
||||
if (!BABEL_IFACE->update_interval)
|
||||
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
|
||||
@ -136,6 +148,7 @@ babel_iface_item:
|
||||
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
|
||||
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
|
||||
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
|
||||
| TYPE TUNNEL { BABEL_IFACE->type = BABEL_IFACE_TYPE_TUNNEL; }
|
||||
| HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
|
||||
| UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); }
|
||||
| RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
|
||||
@ -149,6 +162,11 @@ babel_iface_item:
|
||||
| AUTHENTICATION NONE { BABEL_IFACE->auth_type = BABEL_AUTH_NONE; }
|
||||
| AUTHENTICATION MAC { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 0; }
|
||||
| AUTHENTICATION MAC PERMISSIVE { BABEL_IFACE->auth_type = BABEL_AUTH_MAC; BABEL_IFACE->auth_permissive = 1; }
|
||||
| RTT MIN expr_us { BABEL_IFACE->rtt_min = $3; }
|
||||
| RTT MAX expr_us { BABEL_IFACE->rtt_max = $3; }
|
||||
| RTT COST expr { BABEL_IFACE->rtt_cost = $3; if ($3 >= BABEL_INFINITY) cf_error("RTT cost must be < 65535"); }
|
||||
| RTT DECAY expr { BABEL_IFACE->rtt_decay = $3; if (($3 < 1) || ($3 > 256)) cf_error("RTT decay must be between 1-256"); }
|
||||
| SEND TIMESTAMPS bool { BABEL_IFACE->rtt_send = $3; }
|
||||
| password_list
|
||||
;
|
||||
|
||||
|
@ -58,6 +58,13 @@ struct babel_tlv_ihu {
|
||||
u8 addr[0];
|
||||
} PACKED;
|
||||
|
||||
struct babel_subtlv_timestamp {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u32 tstamp;
|
||||
u32 tstamp_rcvd; /* only used in IHU */
|
||||
} PACKED;
|
||||
|
||||
struct babel_tlv_router_id {
|
||||
u8 type;
|
||||
u8 length;
|
||||
@ -161,6 +168,7 @@ struct babel_parse_state {
|
||||
const struct babel_tlv_data* (*get_subtlv_data)(u8 type);
|
||||
struct babel_proto *proto;
|
||||
struct babel_iface *ifa;
|
||||
btime received_time;
|
||||
ip_addr saddr;
|
||||
ip_addr next_hop_ip4;
|
||||
ip_addr next_hop_ip6;
|
||||
@ -172,6 +180,7 @@ struct babel_parse_state {
|
||||
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
|
||||
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
|
||||
u8 def_ip4_via_ip6_prefix_seen; /* def_ip4_via_ip6_prefix is valid */
|
||||
u8 hello_tstamp_seen; /* pkt contains a hello timestamp */
|
||||
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
|
||||
u8 sadr_enabled;
|
||||
u8 is_unicast;
|
||||
@ -336,6 +345,7 @@ static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct
|
||||
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
static int babel_read_timestamp(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
|
||||
|
||||
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
@ -344,6 +354,7 @@ static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, stru
|
||||
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
|
||||
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
|
||||
static int babel_write_timestamp(struct babel_tlv *hdr, u32 tstamp, u32 tstamp_rcvd, uint max_len);
|
||||
|
||||
static const struct babel_tlv_data tlv_data[BABEL_TLV_MAX] = {
|
||||
[BABEL_TLV_ACK_REQ] = {
|
||||
@ -419,6 +430,13 @@ static const struct babel_tlv_data *get_packet_tlv_data(u8 type)
|
||||
return type < sizeof(tlv_data) / sizeof(*tlv_data) ? &tlv_data[type] : NULL;
|
||||
}
|
||||
|
||||
static const struct babel_tlv_data timestamp_tlv_data = {
|
||||
sizeof(struct babel_subtlv_timestamp),
|
||||
babel_read_timestamp,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct babel_tlv_data source_prefix_tlv_data = {
|
||||
sizeof(struct babel_subtlv_source_prefix),
|
||||
babel_read_source_prefix,
|
||||
@ -430,6 +448,8 @@ static const struct babel_tlv_data *get_packet_subtlv_data(u8 type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case BABEL_SUBTLV_TIMESTAMP:
|
||||
return ×tamp_tlv_data;
|
||||
case BABEL_SUBTLV_SOURCE_PREFIX:
|
||||
return &source_prefix_tlv_data;
|
||||
|
||||
@ -491,16 +511,34 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
|
||||
|
||||
static uint
|
||||
babel_write_hello(struct babel_tlv *hdr, union babel_msg *m,
|
||||
struct babel_write_state *state UNUSED, uint max_len UNUSED)
|
||||
struct babel_write_state *state UNUSED, uint max_len)
|
||||
{
|
||||
struct babel_tlv_hello *tlv = (void *) hdr;
|
||||
struct babel_msg_hello *msg = &m->hello;
|
||||
uint len = sizeof(struct babel_tlv_hello);
|
||||
|
||||
TLV_HDR0(tlv, BABEL_TLV_HELLO);
|
||||
put_u16(&tlv->seqno, msg->seqno);
|
||||
put_time16(&tlv->interval, msg->interval);
|
||||
|
||||
return sizeof(struct babel_tlv_hello);
|
||||
if (msg->tstamp)
|
||||
{
|
||||
/*
|
||||
* There can be a substantial delay between when the babel_msg was created
|
||||
* and when it is serialised. We don't want this included in the RTT
|
||||
* measurement, so replace the timestamp with the current time to get as
|
||||
* close as possible to on-wire time for the packet.
|
||||
*/
|
||||
u32 tstamp = current_time_now() TO_US;
|
||||
|
||||
int l = babel_write_timestamp(hdr, tstamp, 0, max_len);
|
||||
if (l < 0)
|
||||
return 0;
|
||||
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -565,6 +603,7 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
||||
{
|
||||
struct babel_tlv_ihu *tlv = (void *) hdr;
|
||||
struct babel_msg_ihu *msg = &m->ihu;
|
||||
uint len = sizeof(*tlv);
|
||||
|
||||
if (ipa_is_link_local(msg->addr) && max_len < sizeof(struct babel_tlv_ihu) + 8)
|
||||
return 0;
|
||||
@ -576,12 +615,24 @@ babel_write_ihu(struct babel_tlv *hdr, union babel_msg *m,
|
||||
if (!ipa_is_link_local(msg->addr))
|
||||
{
|
||||
tlv->ae = BABEL_AE_WILDCARD;
|
||||
return sizeof(struct babel_tlv_ihu);
|
||||
goto out;
|
||||
}
|
||||
put_ip6_ll(&tlv->addr, msg->addr);
|
||||
tlv->ae = BABEL_AE_IP6_LL;
|
||||
hdr->length += 8;
|
||||
return sizeof(struct babel_tlv_ihu) + 8;
|
||||
len += 8;
|
||||
|
||||
out:
|
||||
if (msg->tstamp)
|
||||
{
|
||||
int l = babel_write_timestamp(hdr, msg->tstamp, msg->tstamp_rcvd, max_len);
|
||||
if (l < 0)
|
||||
return 0;
|
||||
|
||||
len += l;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1249,6 +1300,66 @@ babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_read_timestamp(struct babel_tlv *hdr, union babel_msg *msg,
|
||||
struct babel_parse_state *state)
|
||||
{
|
||||
struct babel_subtlv_timestamp *tlv = (void *) hdr;
|
||||
|
||||
switch (msg->type)
|
||||
{
|
||||
case BABEL_TLV_HELLO:
|
||||
if (tlv->length < 4)
|
||||
return PARSE_ERROR;
|
||||
|
||||
msg->hello.tstamp = get_u32(&tlv->tstamp);
|
||||
msg->hello.pkt_received = state->received_time;
|
||||
state->hello_tstamp_seen = 1;
|
||||
break;
|
||||
|
||||
case BABEL_TLV_IHU:
|
||||
if (tlv->length < 8)
|
||||
return PARSE_ERROR;
|
||||
|
||||
/* RTT calculation relies on a Hello always being present with an IHU */
|
||||
if (!state->hello_tstamp_seen)
|
||||
break;
|
||||
|
||||
msg->ihu.tstamp = get_u32(&tlv->tstamp);
|
||||
msg->ihu.tstamp_rcvd = get_u32(&tlv->tstamp_rcvd);
|
||||
msg->ihu.pkt_received = state->received_time;
|
||||
break;
|
||||
|
||||
default:
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
|
||||
return PARSE_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
babel_write_timestamp(struct babel_tlv *hdr, u32 tstamp, u32 tstamp_rcvd, uint max_len)
|
||||
{
|
||||
struct babel_subtlv_timestamp *tlv = (void *) NEXT_TLV(hdr);
|
||||
uint len = sizeof(*tlv);
|
||||
|
||||
if (hdr->type == BABEL_TLV_HELLO)
|
||||
len -= 4;
|
||||
|
||||
if (len > max_len)
|
||||
return -1;
|
||||
|
||||
TLV_HDR(tlv, BABEL_SUBTLV_TIMESTAMP, len);
|
||||
hdr->length += len;
|
||||
|
||||
put_u32(&tlv->tstamp, tstamp);
|
||||
|
||||
if (hdr->type == BABEL_TLV_IHU)
|
||||
put_u32(&tlv->tstamp_rcvd, tstamp_rcvd);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int
|
||||
babel_read_subtlvs(struct babel_tlv *hdr,
|
||||
union babel_msg *msg,
|
||||
@ -1518,6 +1629,13 @@ babel_process_packet(struct babel_iface *ifa,
|
||||
.saddr = saddr,
|
||||
.next_hop_ip6 = saddr,
|
||||
.sadr_enabled = babel_sadr_enabled(p),
|
||||
|
||||
/*
|
||||
* The core updates current_time() after returning from poll(), so this is
|
||||
* actually the time the packet was received, even though there may have
|
||||
* been a bit of delay before we got to process it
|
||||
*/
|
||||
.received_time = current_time(),
|
||||
};
|
||||
|
||||
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
|
||||
|
@ -86,7 +86,6 @@
|
||||
* RFC 5065 - AS confederations for BGP
|
||||
* RFC 5082 - Generalized TTL Security Mechanism
|
||||
* RFC 5492 - Capabilities Advertisement with BGP
|
||||
* RFC 5549 - Advertising IPv4 NLRI with an IPv6 Next Hop
|
||||
* RFC 5575 - Dissemination of Flow Specification Rules
|
||||
* RFC 5668 - 4-Octet AS Specific BGP Extended Community
|
||||
* RFC 6286 - AS-Wide Unique BGP Identifier
|
||||
@ -101,6 +100,7 @@
|
||||
* RFC 8203 - BGP Administrative Shutdown Communication
|
||||
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
|
||||
* RFC 8654 - Extended Message Support for BGP
|
||||
* RFC 8950 - Advertising IPv4 NLRI with an IPv6 Next Hop
|
||||
* RFC 9072 - Extended Optional Parameters Length for BGP OPEN Message
|
||||
* RFC 9117 - Revised Validation Procedure for BGP Flow Specifications
|
||||
* RFC 9234 - Route Leak Prevention and Detection Using Roles
|
||||
|
@ -230,7 +230,7 @@ struct bgp_af_caps {
|
||||
u8 llgr_able; /* Long-lived GR, RFC draft */
|
||||
u32 llgr_time; /* Long-lived GR stale time */
|
||||
u8 llgr_flags; /* Long-lived GR per-AF flags */
|
||||
u8 ext_next_hop; /* Extended IPv6 next hop, RFC 5549 */
|
||||
u8 ext_next_hop; /* Extended IPv6 next hop, RFC 8950 */
|
||||
u8 add_path; /* Multiple paths support, RFC 7911 */
|
||||
};
|
||||
|
||||
|
@ -216,6 +216,13 @@ bgp_af_caps_cmp(const void *X, const void *Y)
|
||||
return (x->afi < y->afi) ? -1 : (x->afi > y->afi) ? 1 : 0;
|
||||
}
|
||||
|
||||
struct bgp_caps *
|
||||
bgp_alloc_capabilities(struct bgp_proto *p, int n)
|
||||
{
|
||||
struct bgp_caps *caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + n * sizeof(struct bgp_af_caps));
|
||||
caps->role = BGP_ROLE_UNDEFINED;
|
||||
return caps;
|
||||
}
|
||||
|
||||
void
|
||||
bgp_prepare_capabilities(struct bgp_conn *conn)
|
||||
@ -228,13 +235,13 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
|
||||
if (!p->cf->capabilities)
|
||||
{
|
||||
/* Just prepare empty local_caps */
|
||||
conn->local_caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps));
|
||||
conn->local_caps = bgp_alloc_capabilities(p, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Prepare bgp_caps structure */
|
||||
int n = list_length(&p->p.channels);
|
||||
caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + n * sizeof(struct bgp_af_caps));
|
||||
caps = bgp_alloc_capabilities(p, n);
|
||||
conn->local_caps = caps;
|
||||
|
||||
caps->as4_support = p->cf->enable_as4;
|
||||
@ -465,10 +472,7 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||
u32 af;
|
||||
|
||||
if (!conn->remote_caps)
|
||||
{
|
||||
caps = mb_allocz(p->p.pool, sizeof(struct bgp_caps) + sizeof(struct bgp_af_caps));
|
||||
caps->role = BGP_ROLE_UNDEFINED;
|
||||
}
|
||||
caps = bgp_alloc_capabilities(p, 1);
|
||||
else
|
||||
{
|
||||
caps = conn->remote_caps;
|
||||
@ -504,7 +508,7 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||
caps->route_refresh = 1;
|
||||
break;
|
||||
|
||||
case 5: /* Extended next hop encoding capability, RFC 5549 */
|
||||
case 5: /* Extended next hop encoding capability, RFC 8950 */
|
||||
if (cl % 6)
|
||||
goto err;
|
||||
|
||||
@ -764,7 +768,7 @@ bgp_read_options(struct bgp_conn *conn, byte *pos, uint len, uint rest)
|
||||
|
||||
/* 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));
|
||||
conn->remote_caps = bgp_alloc_capabilities(p, 0);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1275,7 +1279,7 @@ bgp_encode_next_hop_ip(struct bgp_write_state *s, eattr *a, byte *buf, uint size
|
||||
|
||||
/*
|
||||
* Both IPv4 and IPv6 next hops can be used (with ext_next_hop enabled). This
|
||||
* is specified in RFC 5549 for IPv4 and in RFC 4798 for IPv6. The difference
|
||||
* is specified in RFC 8950 for IPv4 and in RFC 4798 for IPv6. The difference
|
||||
* is that IPv4 address is directly encoded with IPv4 NLRI, but as IPv4-mapped
|
||||
* IPv6 address with IPv6 NLRI.
|
||||
*/
|
||||
@ -1350,7 +1354,7 @@ bgp_encode_next_hop_vpn(struct bgp_write_state *s, eattr *a, byte *buf, uint siz
|
||||
|
||||
/*
|
||||
* Both IPv4 and IPv6 next hops can be used (with ext_next_hop enabled). This
|
||||
* is specified in RFC 5549 for VPNv4 and in RFC 4659 for VPNv6. The difference
|
||||
* is specified in RFC 8950 for VPNv4 and in RFC 4659 for VPNv6. The difference
|
||||
* is that IPv4 address is directly encoded with VPNv4 NLRI, but as IPv4-mapped
|
||||
* IPv6 address with VPNv6 NLRI.
|
||||
*/
|
||||
|
@ -25,6 +25,15 @@ static struct radv_dnssl_config this_radv_dnssl;
|
||||
static list radv_dns_list; /* Used by radv_rdnss and radv_dnssl */
|
||||
static u8 radv_mult_val; /* Used by radv_mult for second return value */
|
||||
|
||||
static inline void
|
||||
radv_add_to_custom_list(list *l, int type, const struct bytestring *payload)
|
||||
{
|
||||
if (type < 0 || type > 255) cf_error("RA cusom type must be in range 0-255");
|
||||
struct radv_custom_config *cf = cfg_allocz(sizeof(struct radv_custom_config));
|
||||
add_tail(l, NODE cf);
|
||||
cf->type = type;
|
||||
cf->payload = payload;
|
||||
}
|
||||
|
||||
CF_DECLS
|
||||
|
||||
@ -33,7 +42,7 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED,
|
||||
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)
|
||||
ROUTES, CUSTOM, OPTION, TYPE, VALUE)
|
||||
|
||||
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
|
||||
|
||||
@ -52,6 +61,7 @@ radv_proto_start: proto_start RADV
|
||||
init_list(&RADV_CFG->pref_list);
|
||||
init_list(&RADV_CFG->rdnss_list);
|
||||
init_list(&RADV_CFG->dnssl_list);
|
||||
init_list(&RADV_CFG->custom_list);
|
||||
};
|
||||
|
||||
radv_proto_item:
|
||||
@ -61,6 +71,7 @@ radv_proto_item:
|
||||
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
|
||||
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
|
||||
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
|
||||
| CUSTOM OPTION TYPE expr VALUE BYTESTRING { radv_add_to_custom_list(&RADV_CFG->custom_list, $4, $6); }
|
||||
| TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
|
||||
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
|
||||
;
|
||||
@ -82,6 +93,7 @@ radv_iface_start:
|
||||
init_list(&RADV_IFACE->pref_list);
|
||||
init_list(&RADV_IFACE->rdnss_list);
|
||||
init_list(&RADV_IFACE->dnssl_list);
|
||||
init_list(&RADV_IFACE->custom_list);
|
||||
|
||||
RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
|
||||
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
|
||||
@ -124,8 +136,10 @@ radv_iface_item:
|
||||
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
|
||||
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
|
||||
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
|
||||
| CUSTOM OPTION TYPE expr VALUE BYTESTRING { radv_add_to_custom_list(&RADV_IFACE->custom_list, $4, $6); }
|
||||
| RDNSS LOCAL bool { RADV_IFACE->rdnss_local = $3; }
|
||||
| DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
|
||||
| CUSTOM OPTION LOCAL bool { RADV_IFACE->custom_local = $4; }
|
||||
;
|
||||
|
||||
radv_preference:
|
||||
|
@ -82,6 +82,13 @@ struct radv_opt_dnssl
|
||||
char domain[];
|
||||
};
|
||||
|
||||
struct radv_opt_custom
|
||||
{
|
||||
u8 type;
|
||||
u8 length;
|
||||
u8 payload[];
|
||||
};
|
||||
|
||||
static int
|
||||
radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
|
||||
char **buf, char *bufend)
|
||||
@ -254,6 +261,34 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_prepare_custom(struct radv_iface *ifa, list *custom_list, char **buf, char *bufend)
|
||||
{
|
||||
struct radv_custom_config *ccf;
|
||||
WALK_LIST(ccf, *custom_list)
|
||||
{
|
||||
struct radv_opt_custom *op = (void *) *buf;
|
||||
/* Add 2 octets for type and size and 8 - 1 for ceiling the division up to 8 octets */
|
||||
int size = (ccf->payload->length + 2 + 8 - 1) / 8;
|
||||
if (bufend - *buf < size * 8)
|
||||
goto too_much;
|
||||
|
||||
memset(op, 0, size * 8); /* Clear buffer so there is no tail garbage */
|
||||
op->type = ccf->type;
|
||||
op->length = size;
|
||||
memcpy(op->payload, ccf->payload->data, ccf->payload->length);
|
||||
|
||||
*buf += 8 * op->length;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
too_much:
|
||||
log(L_WARN "%s: Too many RA options on interface %s",
|
||||
ifa->ra->p.name, ifa->iface->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
|
||||
char **buf, char *bufend)
|
||||
@ -352,6 +387,14 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
|
||||
goto done;
|
||||
|
||||
if (! ic->custom_local)
|
||||
if (radv_prepare_custom(ifa, &cf->custom_list, &buf, bufend) < 0)
|
||||
goto done;
|
||||
|
||||
if (radv_prepare_custom(ifa, &ic->custom_list, &buf, bufend) < 0)
|
||||
goto done;
|
||||
|
||||
|
||||
if (p->fib_up)
|
||||
{
|
||||
FIB_WALK(&p->routes, struct radv_route, rt)
|
||||
|
@ -51,6 +51,7 @@ struct radv_config
|
||||
list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
|
||||
list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
|
||||
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
|
||||
list custom_list; /* Global list of custom configs (struct radv_custom_config) */
|
||||
|
||||
net_addr trigger; /* Prefix of a trigger route, if defined */
|
||||
u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */
|
||||
@ -63,6 +64,7 @@ struct radv_iface_config
|
||||
list pref_list; /* Local list of prefix configs (struct radv_prefix_config) */
|
||||
list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */
|
||||
list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */
|
||||
list custom_list; /* Local list of custom configs (struct radv_custom_config) */
|
||||
|
||||
u32 min_ra_int; /* Standard options from RFC 4861 */
|
||||
u32 max_ra_int;
|
||||
@ -75,6 +77,7 @@ struct radv_iface_config
|
||||
|
||||
u8 rdnss_local; /* Global list is not used for RDNSS */
|
||||
u8 dnssl_local; /* Global list is not used for DNSSL */
|
||||
u8 custom_local; /* Global list is not used for custom */
|
||||
|
||||
u8 managed; /* Standard options from RFC 4861 */
|
||||
u8 other_config;
|
||||
@ -122,6 +125,13 @@ struct radv_dnssl_config
|
||||
const char *domain; /* Domain for DNS search list, in processed form */
|
||||
};
|
||||
|
||||
struct radv_custom_config
|
||||
{
|
||||
node n;
|
||||
u8 type; /* Identifier of the type of option */
|
||||
const struct bytestring *payload; /* Payload of the option */
|
||||
};
|
||||
|
||||
/*
|
||||
* One more specific route as per RFC 4191.
|
||||
*
|
||||
|
@ -581,7 +581,6 @@ static inline ip_addr rta_get_ipa(struct rtattr *a)
|
||||
return ipa_from_ip6(rta_get_ip6(a));
|
||||
}
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
static inline ip_addr rta_get_via(struct rtattr *a)
|
||||
{
|
||||
struct rtvia *v = RTA_DATA(a);
|
||||
@ -592,6 +591,7 @@ static inline ip_addr rta_get_via(struct rtattr *a)
|
||||
return IPA_NONE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
static u32 rta_mpls_stack[MPLS_MAX_LABEL_STACK];
|
||||
static inline int rta_get_mpls(struct rtattr *a, u32 *stack)
|
||||
{
|
||||
@ -872,10 +872,8 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr
|
||||
if (a[RTA_FLOW])
|
||||
s->rta_flow = rta_get_u32(a[RTA_FLOW]);
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
if (a[RTA_VIA])
|
||||
rv->gw = rta_get_via(a[RTA_VIA]);
|
||||
#endif
|
||||
|
||||
if (nh->rtnh_flags & RTNH_F_ONLINK)
|
||||
rv->flags |= RNF_ONLINK;
|
||||
@ -1762,10 +1760,8 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
if (a[RTA_GATEWAY])
|
||||
nhad.nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
if (a[RTA_VIA])
|
||||
nhad.nh.gw = rta_get_via(a[RTA_VIA]);
|
||||
#endif
|
||||
|
||||
if (i->rtm_flags & RTNH_F_ONLINK)
|
||||
nhad.nh.flags |= RNF_ONLINK;
|
||||
|
@ -278,6 +278,19 @@ times_update(void)
|
||||
DBG("Time update collision: real_time");
|
||||
}
|
||||
|
||||
btime
|
||||
current_time_now(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rv < 0)
|
||||
die("clock_gettime: %m");
|
||||
|
||||
return ts.tv_sec S + ts.tv_nsec NS;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: Sockets
|
||||
*
|
||||
|
@ -37,6 +37,10 @@ int bt_test_suite_base(int (*test_fn)(const void *), const char *test_id, const
|
||||
static inline u64 bt_random(void)
|
||||
{ return ((u64) random() & 0xffffffff) | ((u64) random() << 32); }
|
||||
|
||||
static inline u32 bt_random_n(u32 max)
|
||||
{ return random() % max; }
|
||||
|
||||
|
||||
void bt_log_suite_result(int result, const char *fmt, ...);
|
||||
void bt_log_suite_case_result(int result, const char *fmt, ...);
|
||||
|
||||
|
132
test/bt-utils.c
132
test/bt-utils.c
@ -212,3 +212,135 @@ bt_bytes_to_hex(char *buf, const byte *in_data, size_t size)
|
||||
sprintf(buf + i*2, "%02x", in_data[i]);
|
||||
}
|
||||
|
||||
void
|
||||
bt_random_net(net_addr *net, int type)
|
||||
{
|
||||
ip4_addr ip4;
|
||||
ip6_addr ip6;
|
||||
uint pxlen;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NET_IP4:
|
||||
pxlen = bt_random_n(24)+8;
|
||||
ip4 = ip4_from_u32((u32) bt_random());
|
||||
net_fill_ip4(net, ip4_and(ip4, ip4_mkmask(pxlen)), pxlen);
|
||||
break;
|
||||
|
||||
case NET_IP6:
|
||||
pxlen = bt_random_n(120)+8;
|
||||
ip6 = ip6_build(bt_random(), bt_random(), bt_random(), bt_random());
|
||||
net_fill_ip6(net, ip6_and(ip6, ip6_mkmask(pxlen)), pxlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Net type %d not implemented", type);
|
||||
}
|
||||
}
|
||||
|
||||
net_addr *
|
||||
bt_random_nets(int type, uint n)
|
||||
{
|
||||
net_addr *nets = tmp_alloc(n * sizeof(net_addr));
|
||||
|
||||
for (uint i = 0; i < n; i++)
|
||||
bt_random_net(&nets[i], type);
|
||||
|
||||
return nets;
|
||||
}
|
||||
|
||||
net_addr *
|
||||
bt_random_net_subset(net_addr *src, uint sn, uint dn)
|
||||
{
|
||||
net_addr *nets = tmp_alloc(dn * sizeof(net_addr));
|
||||
|
||||
for (uint i = 0; i < dn; i++)
|
||||
net_copy(&nets[i], &src[bt_random_n(sn)]);
|
||||
|
||||
return nets;
|
||||
}
|
||||
|
||||
void
|
||||
bt_read_net(const char *str, net_addr *net, int type)
|
||||
{
|
||||
ip4_addr ip4;
|
||||
ip6_addr ip6;
|
||||
uint pxlen;
|
||||
char addr[64];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NET_IP4:
|
||||
if (sscanf(str, "%[0-9.]/%u", addr, &pxlen) != 2)
|
||||
goto err;
|
||||
|
||||
if (!ip4_pton(addr, &ip4))
|
||||
goto err;
|
||||
|
||||
if (!net_validate_px4(ip4, pxlen))
|
||||
goto err;
|
||||
|
||||
net_fill_ip4(net, ip4, pxlen);
|
||||
break;
|
||||
|
||||
case NET_IP6:
|
||||
if (sscanf(str, "%[0-9a-fA-F:.]/%u", addr, &pxlen) != 2)
|
||||
goto err;
|
||||
|
||||
if (!ip6_pton(addr, &ip6))
|
||||
goto err;
|
||||
|
||||
if (!net_validate_px6(ip6, pxlen))
|
||||
goto err;
|
||||
|
||||
net_fill_ip6(net, ip6, pxlen);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Net type %d not implemented", type);
|
||||
}
|
||||
return;
|
||||
|
||||
err:
|
||||
bt_abort_msg("Invalid network '%s'", str);
|
||||
}
|
||||
|
||||
net_addr *
|
||||
bt_read_nets(FILE *f, int type, uint *n)
|
||||
{
|
||||
char str[80];
|
||||
|
||||
net_addr *nets = tmp_alloc(*n * sizeof(net_addr));
|
||||
uint i = 0;
|
||||
|
||||
errno = 0;
|
||||
while (fgets(str, sizeof(str), f))
|
||||
{
|
||||
if (str[0] == '\n')
|
||||
break;
|
||||
|
||||
if (i >= *n)
|
||||
bt_abort_msg("Too many networks");
|
||||
|
||||
bt_read_net(str, &nets[i], type);
|
||||
bt_debug("ADD %s\n", str);
|
||||
i++;
|
||||
}
|
||||
bt_syscall(errno, "fgets()");
|
||||
|
||||
bt_debug("DONE reading %u nets\n", i);
|
||||
|
||||
*n = i;
|
||||
return nets;
|
||||
}
|
||||
|
||||
net_addr *
|
||||
bt_read_net_file(const char *filename, int type, uint *n)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
bt_syscall(!f, "fopen(%s)", filename);
|
||||
net_addr *nets = bt_read_nets(f, type, n);
|
||||
fclose(f);
|
||||
|
||||
return nets;
|
||||
}
|
||||
|
@ -26,6 +26,12 @@
|
||||
|
||||
uint bt_naive_pow(uint base, uint power);
|
||||
void bt_bytes_to_hex(char *buf, const byte *in_data, size_t size);
|
||||
void bt_random_net(net_addr *net, int type);
|
||||
net_addr *bt_random_nets(int type, uint n);
|
||||
net_addr *bt_random_net_subset(net_addr *src, uint sn, uint dn);
|
||||
void bt_read_net(const char *str, net_addr *net, int type);
|
||||
net_addr *bt_read_nets(FILE *f, int type, uint *n);
|
||||
net_addr *bt_read_net_file(const char *filename, int type, uint *n);
|
||||
|
||||
void bt_bird_init(void);
|
||||
struct config *bt_config_parse(const char *cfg);
|
||||
|
Loading…
Reference in New Issue
Block a user