mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-17 08:38:42 +00:00
Merge commit '98bb80a243b58c43453e9be69d19d0350286549c' into int-new
This commit is contained in:
commit
4ff15a75c5
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@
|
||||
/config.status
|
||||
/configure
|
||||
/sysdep/autoconf.h.in
|
||||
/sysdep/autoconf.h.in~
|
||||
|
349
.gitlab-ci.yml
Normal file
349
.gitlab-ci.yml
Normal file
@ -0,0 +1,349 @@
|
||||
variables:
|
||||
DEBIAN_FRONTEND: noninteractive
|
||||
LC_ALL: C
|
||||
GIT_STRATEGY: fetch
|
||||
DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/"
|
||||
IMG_BASE: registry.labs.nic.cz/labs/bird
|
||||
|
||||
stages:
|
||||
- image
|
||||
- build
|
||||
|
||||
.docker: &docker_build
|
||||
stage: image
|
||||
allow_failure: true
|
||||
script:
|
||||
- $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz
|
||||
# Make sure we refresh the base image if it updates (eg. security updates, etc)
|
||||
# If we do just the build, cache is always reused and the freshness of the
|
||||
# base image is never checked. However, pull always asks and updates the
|
||||
# image only if it changed ‒ therefore, the cache is used unless there's a
|
||||
# change.
|
||||
- $DOCKER_CMD pull `sed -ne 's/^FROM //p' "misc/docker/$IMG_NAME/Dockerfile"`
|
||||
- $DOCKER_CMD build -t "bird:$IMG_NAME" "misc/docker/$IMG_NAME"
|
||||
- $DOCKER_CMD tag "bird:$IMG_NAME" "$IMG_BASE:$IMG_NAME"
|
||||
- $DOCKER_CMD push "$IMG_BASE:$IMG_NAME"
|
||||
after_script:
|
||||
- rm -f "$HOME/.docker/$CI_JOB_ID/" # cleanup the credentials
|
||||
tags:
|
||||
# That's Docker in Docker
|
||||
- dind
|
||||
|
||||
docker_debian-7-amd64:
|
||||
variables:
|
||||
IMG_NAME: "debian-7-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-8-amd64:
|
||||
variables:
|
||||
IMG_NAME: "debian-8-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-9-amd64:
|
||||
variables:
|
||||
IMG_NAME: "debian-9-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-testing-amd64:
|
||||
variables:
|
||||
IMG_NAME: "debian-testing-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-7-i386:
|
||||
variables:
|
||||
IMG_NAME: "debian-7-i386"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-8-i386:
|
||||
variables:
|
||||
IMG_NAME: "debian-8-i386"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-9-i386:
|
||||
variables:
|
||||
IMG_NAME: "debian-9-i386"
|
||||
<<: *docker_build
|
||||
|
||||
docker_debian-testing-i386:
|
||||
variables:
|
||||
IMG_NAME: "debian-testing-i386"
|
||||
<<: *docker_build
|
||||
|
||||
docker_fedora-25-amd64:
|
||||
variables:
|
||||
IMG_NAME: "fedora-25-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_fedora-26-amd64:
|
||||
variables:
|
||||
IMG_NAME: "fedora-26-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_centos-6-amd64:
|
||||
variables:
|
||||
IMG_NAME: "centos-6-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_centos-7-amd64:
|
||||
variables:
|
||||
IMG_NAME: "centos-7-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_opensuse-42_3-amd64:
|
||||
variables:
|
||||
IMG_NAME: "opensuse-42.3-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_ubuntu-14_04-amd64:
|
||||
variables:
|
||||
IMG_NAME: "ubuntu-14.04-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
docker_ubuntu-16_04-amd64:
|
||||
variables:
|
||||
IMG_NAME: "ubuntu-16.04-amd64"
|
||||
<<: *docker_build
|
||||
|
||||
.debian-7-i386: &debian-7-i386_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-7-i386
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-8-i386: &debian-8-i386_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-8-i386
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-9-i386: &debian-9-i386_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-9-i386
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-testing-i386: &debian-testing-i386_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-testing-i386
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-7-amd64: &debian-7-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-7-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-8-amd64: &debian-8-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-8-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-9-amd64: &debian-9-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-9-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.debian-testing-amd64: &debian-testing-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:debian-testing-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.fedora-25-amd64: &fedora-25-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:fedora-25-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.fedora-26-amd64: &fedora-26-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:fedora-26-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.centos-6-amd64: ¢os-6-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:centos-6-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.centos-7-amd64: ¢os-7-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:centos-7-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.opensuse-42_3-amd64: &opensuse-42_3-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:opensuse-42.3-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.ubuntu-14_04-amd64: &ubuntu-14_04-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:ubuntu-14.04-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
.ubuntu-16_04-amd64: &ubuntu-16_04-amd64_env
|
||||
image: registry.labs.nic.cz/labs/bird:ubuntu-16.04-amd64
|
||||
tags:
|
||||
- docker
|
||||
- linux
|
||||
- amd64
|
||||
|
||||
# TODO We want to copy these BSDs to our own virtual machines, to make sure someone doesn't update them by accident.
|
||||
.freebsd-11-i386: &freebsd-11-i386_env
|
||||
variables:
|
||||
CPPFLAGS: "-I/usr/local/include"
|
||||
LDFLAGS: "-L/usr/local/lib"
|
||||
tags:
|
||||
- freebsd
|
||||
- i386
|
||||
#only:
|
||||
#- master
|
||||
#- triggers
|
||||
#- tags
|
||||
|
||||
.freebsd-11-amd64: &freebsd-11-amd64_env
|
||||
variables:
|
||||
CPPFLAGS: "-I/usr/local/include"
|
||||
LDFLAGS: "-L/usr/local/lib"
|
||||
tags:
|
||||
- freebsd
|
||||
- amd64
|
||||
#only:
|
||||
#- master
|
||||
#- triggers
|
||||
#- tags
|
||||
|
||||
.build: &build_job
|
||||
stage: build
|
||||
script:
|
||||
- autoreconf
|
||||
- ./configure CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS"
|
||||
# Detect which make is available
|
||||
- MAKE=make
|
||||
- which gmake 2>/dev/null >/dev/null && MAKE=gmake
|
||||
- $MAKE
|
||||
# Run tests if they are available (eg. don't fail if "check" isn't a valid make target)
|
||||
- $MAKE check || [ "$?" = 2 ]
|
||||
|
||||
build-debian-7-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-7-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-8-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-8-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-9-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-9-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-testing-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-testing-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-fedora-25-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *fedora-25-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-fedora-26-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *fedora-26-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-6-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *centos-6-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-7-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *centos-7-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-opensuse-42_3-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *opensuse-42_3-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-ubuntu-14_04-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *ubuntu-14_04-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-ubuntu-16_04-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *ubuntu-16_04-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-7-i386:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-7-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-8-i386:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-8-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-9-i386:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-9-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-testing-i386:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *debian-testing-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-freebsd-11-amd64:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *freebsd-11-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-freebsd-11-i386:
|
||||
variables:
|
||||
IPV6: "no"
|
||||
<<: *freebsd-11-i386_env
|
||||
<<: *build_job
|
45
TODO
45
TODO
@ -1,45 +0,0 @@
|
||||
Core
|
||||
~~~~
|
||||
- socket open failure should not be fatal
|
||||
- &&,||: priorities
|
||||
- static: allow specifying a per-route filter program for setting route attributes?
|
||||
|
||||
Globals
|
||||
~~~~~~~
|
||||
- right usage of DBG vs. debug
|
||||
- logging and tracing; use appropriate log levels
|
||||
- check incoming packets and log errors!!
|
||||
- check log calls for trailing newlines and log levels followed by comma
|
||||
- check if all protocols set proper packet priorities and TTL's.
|
||||
- try compiling with -Wunused
|
||||
- does everybody test return value of sk_open?
|
||||
- protocols: implement CLI hooks and per-procotol CLI commands
|
||||
- protocols: implement reconfigure hook
|
||||
- protocols: use locking
|
||||
- check use of system includes and sprintf()
|
||||
|
||||
Various ideas
|
||||
~~~~~~~~~~~~~
|
||||
- client: Ctrl-R eats one more enter
|
||||
- bgp: timing of updates?
|
||||
- netlink: import Linux route attributes to our rta's, so that they can be filtered?
|
||||
- config: executable config files
|
||||
- filters: user defined attributes?
|
||||
- io: use poll if available
|
||||
- route recalculation timing and flap dampening [see RFC2439 for algorithms]
|
||||
- aggregate engine: standard route aggregation and summarization [RFC2519]
|
||||
- aggregate engine: injection of manually configured pseudo-static routes
|
||||
- generate default route if any working BGP connection exists (aggregate engine again?)
|
||||
- generate default route to IGP's (aggregate engine yet another time?)
|
||||
- look at RFC 2386 (QoS-based routing)
|
||||
- cli: show tables?
|
||||
|
||||
OSPF
|
||||
~~~~
|
||||
- check incoming packets using neighbor cache
|
||||
- RFC2328 appendix E: Use a better algorithm
|
||||
- automatic generation of external route tags (RFC1403)
|
||||
- RFC2370 opaque LSA's
|
||||
- Limit export rate of external LSAs (like Gated does)
|
||||
- Bugfix in link state retransmission list (aging)
|
||||
- Graceful OSPF restart - RFC3623
|
@ -25,9 +25,10 @@
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/resource.h"
|
||||
|
@ -3660,6 +3660,12 @@ dsc-iface
|
||||
as a default router. For <cf/sensitive/ option, see <ref id="radv-trigger" name="trigger">.
|
||||
Default: 3 * <cf/max ra interval/, <cf/sensitive/ yes.
|
||||
|
||||
<tag><label id="radv-iface-linger-time">linger time <m/expr/</tag>
|
||||
When a prefix disappears, it is advertised for some time with 0
|
||||
lifetime, to inform clients the prefix is no longer usable. This option
|
||||
sets the time for how long it is advertised (in seconds). Maximum is
|
||||
3600, 0 means disabled. Default: 300.
|
||||
|
||||
<tag><label id="radv-iface-default-preference-low">default preference low|medium|high</tag>
|
||||
This option specifies the Default Router Preference value to advertise
|
||||
to hosts. Default: medium.
|
||||
|
12
lib/net.h
12
lib/net.h
@ -526,6 +526,18 @@ int net_classify(const net_addr *N);
|
||||
int net_format(const net_addr *N, char *buf, int buflen);
|
||||
int rd_format(const u64 rd, char *buf, int buflen);
|
||||
|
||||
static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
|
||||
{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); }
|
||||
|
||||
static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); }
|
||||
|
||||
static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
|
||||
{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); }
|
||||
|
||||
static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
|
||||
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); }
|
||||
|
||||
int ipa_in_netX(const ip_addr A, const net_addr *N);
|
||||
int net_in_netX(const net_addr *A, const net_addr *N);
|
||||
|
||||
|
11
misc/docker/centos-6-amd64/Dockerfile
Normal file
11
misc/docker/centos-6-amd64/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM centos:6
|
||||
RUN yum -y upgrade
|
||||
RUN yum -y install \
|
||||
autoconf \
|
||||
flex \
|
||||
bison \
|
||||
pkgconfig \
|
||||
'readline-devel' \
|
||||
'pkgconfig(ncurses)' \
|
||||
gcc \
|
||||
make
|
11
misc/docker/centos-7-amd64/Dockerfile
Normal file
11
misc/docker/centos-7-amd64/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM centos:7
|
||||
RUN yum -y upgrade
|
||||
RUN yum -y install \
|
||||
autoconf \
|
||||
flex \
|
||||
bison \
|
||||
pkgconfig \
|
||||
'readline-devel' \
|
||||
'pkgconfig(ncurses)' \
|
||||
gcc \
|
||||
make
|
12
misc/docker/debian-7-amd64/Dockerfile
Normal file
12
misc/docker/debian-7-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM debian:wheezy-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-7-i386/Dockerfile
Normal file
12
misc/docker/debian-7-i386/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM i386/debian:wheezy-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-8-amd64/Dockerfile
Normal file
12
misc/docker/debian-8-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM debian:jessie-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-8-i386/Dockerfile
Normal file
12
misc/docker/debian-8-i386/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM i386/debian:jessie-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-9-amd64/Dockerfile
Normal file
12
misc/docker/debian-9-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM debian:stretch-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-9-i386/Dockerfile
Normal file
12
misc/docker/debian-9-i386/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM i386/debian:stretch-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-testing-amd64/Dockerfile
Normal file
12
misc/docker/debian-testing-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM debian:testing-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/debian-testing-i386/Dockerfile
Normal file
12
misc/docker/debian-testing-i386/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM i386/debian:testing-slim
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
10
misc/docker/fedora-25-amd64/Dockerfile
Normal file
10
misc/docker/fedora-25-amd64/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM fedora:25
|
||||
RUN dnf -y upgrade
|
||||
RUN dnf -y install \
|
||||
autoconf \
|
||||
flex \
|
||||
bison \
|
||||
pkgconfig \
|
||||
'readline-devel' \
|
||||
'pkgconfig(ncurses)' \
|
||||
gcc
|
10
misc/docker/fedora-26-amd64/Dockerfile
Normal file
10
misc/docker/fedora-26-amd64/Dockerfile
Normal file
@ -0,0 +1,10 @@
|
||||
FROM fedora:26
|
||||
RUN dnf -y upgrade
|
||||
RUN dnf -y install \
|
||||
autoconf \
|
||||
flex \
|
||||
bison \
|
||||
pkgconfig \
|
||||
'readline-devel' \
|
||||
'pkgconfig(ncurses)' \
|
||||
gcc
|
11
misc/docker/opensuse-42.3-amd64/Dockerfile
Normal file
11
misc/docker/opensuse-42.3-amd64/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM opensuse:42.3
|
||||
RUN zypper -n up
|
||||
RUN zypper -n install \
|
||||
autoconf \
|
||||
flex \
|
||||
bison \
|
||||
pkgconfig \
|
||||
readline-devel \
|
||||
ncurses-devel \
|
||||
gcc \
|
||||
gmake
|
12
misc/docker/ubuntu-14.04-amd64/Dockerfile
Normal file
12
misc/docker/ubuntu-14.04-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM ubuntu:14.04
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
12
misc/docker/ubuntu-16.04-amd64/Dockerfile
Normal file
12
misc/docker/ubuntu-16.04-amd64/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM ubuntu:16.04
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
|
||||
RUN apt-get -y update
|
||||
RUN apt-get -y upgrade
|
||||
RUN apt-get -y install \
|
||||
autoconf \
|
||||
build-essential \
|
||||
flex \
|
||||
bison \
|
||||
ncurses-dev \
|
||||
libreadline-dev
|
@ -145,9 +145,9 @@ ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
if (p->ifa_notify && (p->proto_state != PS_DOWN))
|
||||
{
|
||||
if (p->debug & D_IFACES)
|
||||
log(L_TRACE "%s < %s address %N on interface %s %s",
|
||||
p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary",
|
||||
&a->prefix, a->iface->name, (c & IF_CHANGE_UP) ? "added" : "removed");
|
||||
log(L_TRACE "%s < address %N on interface %s %s",
|
||||
p->name, &a->prefix, a->iface->name,
|
||||
(c & IF_CHANGE_UP) ? "added" : "removed");
|
||||
p->ifa_notify(p, c, a);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ 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, LINK, MTU, REACHABLE, TIME, RETRANS,
|
||||
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)
|
||||
@ -80,6 +80,7 @@ radv_iface_start:
|
||||
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
|
||||
RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
|
||||
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
|
||||
RADV_IFACE->linger_time = DEFAULT_LINGER_TIME;
|
||||
RADV_IFACE->default_lifetime = -1;
|
||||
RADV_IFACE->default_lifetime_sensitive = 1;
|
||||
RADV_IFACE->default_preference = RA_PREF_MEDIUM;
|
||||
@ -94,6 +95,7 @@ radv_iface_item:
|
||||
| LINK MTU expr { RADV_IFACE->link_mtu = $3; }
|
||||
| REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if ($3 > 3600000) cf_error("Reachable time must be in range 0-3600000"); }
|
||||
| RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; }
|
||||
| LINGER TIME expr { RADV_IFACE->linger_time = $3; if ($3 > 3600) cf_error("Linger time must be in range 0-3600"); }
|
||||
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if ($4 > 255) cf_error("Current hop limit must be in range 0-255"); }
|
||||
| DEFAULT LIFETIME expr radv_sensitive {
|
||||
RADV_IFACE->default_lifetime = $3;
|
||||
|
@ -70,36 +70,6 @@ struct radv_opt_dnssl
|
||||
char domain[];
|
||||
};
|
||||
|
||||
|
||||
static struct radv_prefix_config default_prefix = {
|
||||
.onlink = 1,
|
||||
.autonomous = 1,
|
||||
.valid_lifetime = DEFAULT_VALID_LIFETIME,
|
||||
.preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
|
||||
};
|
||||
|
||||
|
||||
static struct radv_prefix_config *
|
||||
radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
|
||||
{
|
||||
struct radv_proto *p = ifa->ra;
|
||||
struct radv_config *cf = (struct radv_config *) (p->p.cf);
|
||||
struct radv_prefix_config *pc;
|
||||
|
||||
if (a->scope <= SCOPE_LINK)
|
||||
return NULL;
|
||||
|
||||
WALK_LIST(pc, ifa->cf->pref_list)
|
||||
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix))
|
||||
return pc;
|
||||
|
||||
WALK_LIST(pc, cf->pref_list)
|
||||
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix))
|
||||
return pc;
|
||||
|
||||
return &default_prefix;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_prepare_rdnss(struct radv_iface *ifa, list *rdnss_list, char **buf, char *bufend)
|
||||
{
|
||||
@ -234,6 +204,36 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
|
||||
char **buf, char *bufend)
|
||||
{
|
||||
struct radv_prefix_config *pc = px->cf;
|
||||
|
||||
if (*buf + sizeof(struct radv_opt_prefix) > bufend)
|
||||
{
|
||||
log(L_WARN "%s: Too many prefixes on interface %s",
|
||||
ifa->ra->p.name, ifa->iface->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct radv_opt_prefix *op = (void *) *buf;
|
||||
op->type = OPT_PREFIX;
|
||||
op->length = 4;
|
||||
op->pxlen = px->prefix.pxlen;
|
||||
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
|
||||
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
|
||||
op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ?
|
||||
htonl(pc->valid_lifetime) : 0;
|
||||
op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ?
|
||||
htonl(pc->preferred_lifetime) : 0;
|
||||
op->reserved = 0;
|
||||
op->prefix = ip6_hton(px->prefix.prefix);
|
||||
*buf += sizeof(*op);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
radv_prepare_ra(struct radv_iface *ifa)
|
||||
{
|
||||
@ -269,37 +269,11 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||
buf += sizeof (*om);
|
||||
}
|
||||
|
||||
struct ifa *addr;
|
||||
WALK_LIST(addr, ifa->iface->addrs)
|
||||
struct radv_prefix *prefix;
|
||||
WALK_LIST(prefix, ifa->prefixes)
|
||||
{
|
||||
if (addr->prefix.type != NET_IP6)
|
||||
continue;
|
||||
|
||||
struct radv_prefix_config *pc;
|
||||
pc = radv_prefix_match(ifa, addr);
|
||||
|
||||
if (!pc || pc->skip)
|
||||
continue;
|
||||
|
||||
if (buf + sizeof(struct radv_opt_prefix) > bufend)
|
||||
{
|
||||
log(L_WARN "%s: Too many prefixes on interface %s", p->p.name, ifa->iface->name);
|
||||
if (radv_prepare_prefix(ifa, prefix, &buf, bufend) < 0)
|
||||
goto done;
|
||||
}
|
||||
|
||||
struct radv_opt_prefix *op = (void *) buf;
|
||||
op->type = OPT_PREFIX;
|
||||
op->length = 4;
|
||||
op->pxlen = net6_pxlen(&addr->prefix);
|
||||
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
|
||||
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
|
||||
op->valid_lifetime = (p->active || !pc->valid_lifetime_sensitive) ?
|
||||
htonl(pc->valid_lifetime) : 0;
|
||||
op->preferred_lifetime = (p->active || !pc->preferred_lifetime_sensitive) ?
|
||||
htonl(pc->preferred_lifetime) : 0;
|
||||
op->reserved = 0;
|
||||
op->prefix = ip6_hton(net6_prefix(&addr->prefix));
|
||||
buf += sizeof(*op);
|
||||
}
|
||||
|
||||
if (! ic->rdnss_local)
|
||||
@ -408,7 +382,7 @@ radv_err_hook(sock *sk, int err)
|
||||
int
|
||||
radv_sk_open(struct radv_iface *ifa)
|
||||
{
|
||||
sock *sk = sk_new(ifa->ra->p.pool);
|
||||
sock *sk = sk_new(ifa->pool);
|
||||
sk->type = SK_IP;
|
||||
sk->subtype = SK_IPV6;
|
||||
sk->dport = ICMPV6_PROTO;
|
||||
|
@ -51,6 +51,16 @@ radv_timer(timer *tm)
|
||||
|
||||
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
|
||||
|
||||
/*
|
||||
* If some dead prefixes expired, regenerate the prefix list and the packet.
|
||||
* We do so by pretending there was a change on the interface.
|
||||
*
|
||||
* This sets the timer, but we replace it just at the end of this function
|
||||
* (replacing a timer is fine).
|
||||
*/
|
||||
if (ifa->prefix_expires && (ifa->prefix_expires <= current_time()))
|
||||
radv_iface_notify(ifa, RA_EV_GC);
|
||||
|
||||
radv_send_ra(ifa, 0);
|
||||
|
||||
/* Update timer */
|
||||
@ -68,7 +78,136 @@ radv_timer(timer *tm)
|
||||
tm_start(ifa->timer, t);
|
||||
}
|
||||
|
||||
static char* ev_name[] = { NULL, "Init", "Change", "RS" };
|
||||
static struct radv_prefix_config default_prefix = {
|
||||
.onlink = 1,
|
||||
.autonomous = 1,
|
||||
.valid_lifetime = DEFAULT_VALID_LIFETIME,
|
||||
.preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
|
||||
};
|
||||
|
||||
static struct radv_prefix_config dead_prefix = {
|
||||
};
|
||||
|
||||
/* Find a corresponding config for the given prefix */
|
||||
static struct radv_prefix_config *
|
||||
radv_prefix_match(struct radv_iface *ifa, net_addr_ip6 *px)
|
||||
{
|
||||
struct radv_proto *p = ifa->ra;
|
||||
struct radv_config *cf = (struct radv_config *) (p->p.cf);
|
||||
struct radv_prefix_config *pc;
|
||||
|
||||
WALK_LIST(pc, ifa->cf->pref_list)
|
||||
if (net_in_net_ip6(px, &pc->prefix))
|
||||
return pc;
|
||||
|
||||
WALK_LIST(pc, cf->pref_list)
|
||||
if (net_in_net_ip6(px, &pc->prefix))
|
||||
return pc;
|
||||
|
||||
return &default_prefix;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the list of prefixes, compare them with configs and decide if we
|
||||
* want them or not.
|
||||
*/
|
||||
static void
|
||||
radv_prepare_prefixes(struct radv_iface *ifa)
|
||||
{
|
||||
struct radv_proto *p = ifa->ra;
|
||||
struct radv_iface_config *cf = ifa->cf;
|
||||
struct radv_prefix *pfx;
|
||||
|
||||
/* First mark all the prefixes as unused */
|
||||
WALK_LIST(pfx, ifa->prefixes)
|
||||
pfx->mark = 0;
|
||||
|
||||
/* Find all the prefixes we want to use and make sure they are in the list. */
|
||||
struct ifa *addr;
|
||||
WALK_LIST(addr, ifa->iface->addrs)
|
||||
{
|
||||
if ((addr->prefix.type != NET_IP6) ||
|
||||
(addr->scope <= SCOPE_LINK))
|
||||
continue;
|
||||
|
||||
net_addr_ip6 *prefix = (void *) &addr->prefix;
|
||||
struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix);
|
||||
|
||||
if (!pc || pc->skip)
|
||||
continue;
|
||||
|
||||
/* Do we have it already? */
|
||||
struct radv_prefix *existing = NULL;
|
||||
WALK_LIST(pfx, ifa->prefixes)
|
||||
if (net_equal_ip6(&pfx->prefix, prefix))
|
||||
{
|
||||
existing = pfx;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!existing)
|
||||
{
|
||||
RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s",
|
||||
prefix, ifa->iface->name);
|
||||
|
||||
existing = mb_allocz(ifa->pool, sizeof *existing);
|
||||
net_copy_ip6(&existing->prefix, prefix);
|
||||
add_tail(&ifa->prefixes, NODE existing);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the information (it may have changed, or even bring a prefix back
|
||||
* to life).
|
||||
*/
|
||||
existing->alive = 1;
|
||||
existing->mark = 1;
|
||||
existing->cf = pc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Garbage-collect the prefixes. If something isn't used, it dies (but isn't
|
||||
* dropped just yet). If something is dead and rots there for long enough,
|
||||
* clean it up.
|
||||
*/
|
||||
btime now_ = current_time();
|
||||
btime expires = now_ + cf->linger_time S;
|
||||
btime expires_min = 0;
|
||||
struct radv_prefix *next;
|
||||
WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
|
||||
{
|
||||
if (pfx->alive && !pfx->mark)
|
||||
{
|
||||
RADV_TRACE(D_EVENTS, "Marking prefix %N on %s as dead",
|
||||
pfx->prefix, ifa->iface->name);
|
||||
|
||||
pfx->alive = 0;
|
||||
pfx->expires = expires;
|
||||
pfx->cf = &dead_prefix;
|
||||
}
|
||||
|
||||
if (!pfx->alive)
|
||||
{
|
||||
if (pfx->expires <= now_)
|
||||
{
|
||||
RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
|
||||
pfx->prefix, ifa->iface->name);
|
||||
|
||||
rem_node(NODE pfx);
|
||||
mb_free(pfx);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Find minimum expiration time */
|
||||
if (!expires_min || (pfx->expires < expires_min))
|
||||
expires_min = pfx->expires;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ifa->prefix_expires = expires_min;
|
||||
}
|
||||
|
||||
static char* ev_name[] = { NULL, "Init", "Change", "RS", "Garbage collect" };
|
||||
|
||||
void
|
||||
radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
@ -83,6 +222,7 @@ radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
switch (event)
|
||||
{
|
||||
case RA_EV_CHANGE:
|
||||
case RA_EV_GC:
|
||||
ifa->plen = 0;
|
||||
case RA_EV_INIT:
|
||||
ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
|
||||
@ -92,6 +232,8 @@ radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
break;
|
||||
}
|
||||
|
||||
radv_prepare_prefixes(ifa);
|
||||
|
||||
/* Update timer */
|
||||
btime t = ifa->last + ifa->cf->min_delay S - current_time();
|
||||
tm_start(ifa->timer, t);
|
||||
@ -137,16 +279,18 @@ radv_iface_add(struct object_lock *lock)
|
||||
static void
|
||||
radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
|
||||
{
|
||||
pool *pool = p->p.pool;
|
||||
struct radv_iface *ifa;
|
||||
|
||||
RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
|
||||
|
||||
pool *pool = rp_new(p->p.pool, iface->name);
|
||||
ifa = mb_allocz(pool, sizeof(struct radv_iface));
|
||||
ifa->pool = pool;
|
||||
ifa->ra = p;
|
||||
ifa->cf = cf;
|
||||
ifa->iface = iface;
|
||||
ifa->addr = iface->llv6;
|
||||
init_list(&ifa->prefixes);
|
||||
|
||||
add_tail(&p->iface_list, NODE ifa);
|
||||
|
||||
@ -172,11 +316,7 @@ radv_iface_remove(struct radv_iface *ifa)
|
||||
|
||||
rem_node(NODE ifa);
|
||||
|
||||
rfree(ifa->sk);
|
||||
rfree(ifa->timer);
|
||||
rfree(ifa->lock);
|
||||
|
||||
mb_free(ifa);
|
||||
rfree(ifa->pool);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -35,6 +35,7 @@
|
||||
#define DEFAULT_MAX_RA_INT 600
|
||||
#define DEFAULT_MIN_DELAY 3
|
||||
#define DEFAULT_CURRENT_HOP_LIMIT 64
|
||||
#define DEFAULT_LINGER_TIME 300
|
||||
|
||||
#define DEFAULT_VALID_LIFETIME 86400
|
||||
#define DEFAULT_PREFERRED_LIFETIME 14400
|
||||
@ -64,6 +65,9 @@ struct radv_iface_config
|
||||
u32 max_ra_int;
|
||||
u32 min_delay;
|
||||
|
||||
u32 linger_time; /* How long a dead prefix should still be advertised with 0
|
||||
lifetime */
|
||||
|
||||
u8 rdnss_local; /* Global list is not used for RDNSS */
|
||||
u8 dnssl_local; /* Global list is not used for DNSSL */
|
||||
|
||||
@ -75,7 +79,7 @@ struct radv_iface_config
|
||||
u32 current_hop_limit;
|
||||
u32 default_lifetime;
|
||||
u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
|
||||
u8 default_preference; /* Default Router Preference (RFC 4191) */
|
||||
u8 default_preference; /* Default Router Preference (RFC 4191) */
|
||||
};
|
||||
|
||||
struct radv_prefix_config
|
||||
@ -118,6 +122,19 @@ struct radv_proto
|
||||
u8 active; /* Whether radv is active w.r.t. triggers */
|
||||
};
|
||||
|
||||
struct radv_prefix /* One prefix we advertise */
|
||||
{
|
||||
node n;
|
||||
net_addr_ip6 prefix;
|
||||
|
||||
u8 alive; /* Is the prefix alive? If not, we advertise it
|
||||
with 0 lifetime, so clients stop using it */
|
||||
u8 mark; /* A temporary mark for processing */
|
||||
btime expires; /* The time when we drop this prefix from
|
||||
advertising. It is valid only if !alive. */
|
||||
struct radv_prefix_config *cf; /* The config tied to this prefix */
|
||||
};
|
||||
|
||||
struct radv_iface
|
||||
{
|
||||
node n;
|
||||
@ -125,6 +142,9 @@ struct radv_iface
|
||||
struct radv_iface_config *cf; /* Related config, must be updated in reconfigure */
|
||||
struct iface *iface;
|
||||
struct ifa *addr; /* Link-local address of iface */
|
||||
struct pool *pool; /* A pool for interface-specific things */
|
||||
list prefixes; /* The prefixes we advertise (struct radv_prefix) */
|
||||
btime prefix_expires; /* When the soonest prefix expires (0 = none dead) */
|
||||
|
||||
timer *timer;
|
||||
struct object_lock *lock;
|
||||
@ -132,12 +152,13 @@ struct radv_iface
|
||||
|
||||
btime last; /* Time of last sending of RA */
|
||||
u16 plen; /* Length of prepared RA in tbuf, or 0 if not valid */
|
||||
byte initial; /* List of active ifaces */
|
||||
byte initial; /* How many RAs are still to be sent as initial */
|
||||
};
|
||||
|
||||
#define RA_EV_INIT 1 /* Switch to initial mode */
|
||||
#define RA_EV_CHANGE 2 /* Change of options or prefixes */
|
||||
#define RA_EV_RS 3 /* Received RS */
|
||||
#define RA_EV_GC 4 /* Internal garbage collection of prefixes */
|
||||
|
||||
/* Default Router Preferences (RFC 4191) */
|
||||
#define RA_PREF_LOW 0x18
|
||||
|
@ -165,7 +165,7 @@ struct ks_msg
|
||||
{
|
||||
struct rt_msghdr rtm;
|
||||
struct sockaddr_storage buf[RTAX_MAX];
|
||||
};
|
||||
} PACKED;
|
||||
|
||||
#define ROUNDUP(a) \
|
||||
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
|
||||
|
@ -83,22 +83,26 @@ struct rtvia {
|
||||
/*
|
||||
* Structure nl_parse_state keeps state of received route processing. Ideally,
|
||||
* we could just independently parse received Netlink messages and immediately
|
||||
* propagate received routes to the rest of BIRD, but Linux kernel represents
|
||||
* and announces IPv6 ECMP routes not as one route with multiple next hops (like
|
||||
* RTA_MULTIPATH in IPv4 ECMP), but as a set of routes with the same prefix.
|
||||
* propagate received routes to the rest of BIRD, but older Linux kernel (before
|
||||
* version 4.11) represents and announces IPv6 ECMP routes not as one route with
|
||||
* multiple next hops (like RTA_MULTIPATH in IPv4 ECMP), but as a sequence of
|
||||
* routes with the same prefix. More recent kernels work as with IPv4.
|
||||
*
|
||||
* Therefore, BIRD keeps currently processed route in nl_parse_state structure
|
||||
* and postpones its propagation until we expect it to be final; i.e., when
|
||||
* non-matching route is received or when the scan ends. When another matching
|
||||
* route is received, it is merged with the already processed route to form an
|
||||
* ECMP route. Note that merging is done only for IPv6 (merge == 1), but the
|
||||
* postponing is done in both cases (for simplicity). All IPv4 routes are just
|
||||
* considered non-matching.
|
||||
* postponing is done in both cases (for simplicity). All IPv4 routes or IPv6
|
||||
* routes with RTA_MULTIPATH set are just considered non-matching.
|
||||
*
|
||||
* This is ignored for asynchronous notifications (every notification is handled
|
||||
* as a separate route). It is not an issue for our routes, as we ignore such
|
||||
* notifications anyways. But importing alien IPv6 ECMP routes does not work
|
||||
* properly.
|
||||
* properly with older kernels.
|
||||
*
|
||||
* Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes
|
||||
* for the same prefix.
|
||||
*/
|
||||
|
||||
struct nl_parse_state
|
||||
@ -348,6 +352,12 @@ static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
|
||||
[RTA_ENCAP] = { 1, 0, 0 },
|
||||
};
|
||||
|
||||
static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = {
|
||||
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
|
||||
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
|
||||
[RTA_ENCAP] = { 1, 0, 0 },
|
||||
};
|
||||
|
||||
static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
|
||||
[RTA_DST] = { 1, 0, 0 },
|
||||
};
|
||||
@ -374,6 +384,7 @@ static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
|
||||
[RTA_PRIORITY] = { 1, 1, sizeof(u32) },
|
||||
[RTA_PREFSRC] = { 1, 1, sizeof(ip6_addr) },
|
||||
[RTA_METRICS] = { 1, 0, 0 },
|
||||
[RTA_MULTIPATH] = { 1, 0, 0 },
|
||||
[RTA_FLOW] = { 1, 1, sizeof(u32) },
|
||||
[RTA_TABLE] = { 1, 1, sizeof(u32) },
|
||||
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
|
||||
@ -631,7 +642,7 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
|
||||
}
|
||||
|
||||
static struct nexthop *
|
||||
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||
nl_parse_multipath(struct krt_proto *p, struct rtattr *ra, int af)
|
||||
{
|
||||
/* Temporary buffer for multicast nexthops */
|
||||
static struct nexthop *nh_buffer;
|
||||
@ -670,7 +681,22 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
|
||||
|
||||
/* Nonexistent RTNH_PAYLOAD ?? */
|
||||
nl_attr_len = nh->rtnh_len - RTNH_LENGTH(0);
|
||||
nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a));
|
||||
switch (af)
|
||||
{
|
||||
case AF_INET:
|
||||
if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want4, a, sizeof(a)))
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case AF_INET6:
|
||||
if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want6, a, sizeof(a)))
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (a[RTA_GATEWAY])
|
||||
{
|
||||
rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
|
||||
@ -1520,9 +1546,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
case RTN_UNICAST:
|
||||
ra->dest = RTD_UNICAST;
|
||||
|
||||
if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
|
||||
{
|
||||
struct nexthop *nh = nl_parse_multipath(p, a[RTA_MULTIPATH]);
|
||||
if (a[RTA_MULTIPATH])
|
||||
{
|
||||
struct nexthop *nh = nl_parse_multipath(p, a[RTA_MULTIPATH], i->rtm_family);
|
||||
if (!nh)
|
||||
{
|
||||
log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
|
||||
@ -1699,8 +1725,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
|
||||
/*
|
||||
* Ideally, now we would send the received route to the rest of kernel code.
|
||||
* But IPv6 ECMP routes are sent as a sequence of routes, so we postpone it
|
||||
* and merge next hops until the end of the sequence.
|
||||
* But IPv6 ECMP routes before 4.11 are sent as a sequence of routes, so we
|
||||
* postpone it and merge next hops until the end of the sequence. Note that
|
||||
* proper multipath updates are rejected by nl_mergable_route(), so it is
|
||||
* always the first case for them.
|
||||
*/
|
||||
|
||||
if (!s->net)
|
||||
|
Loading…
Reference in New Issue
Block a user