mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 12:48:43 +00:00
Merge branch 'int-new' into bash-completion
This commit is contained in:
commit
b7e2e8bc41
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,3 +11,4 @@
|
||||
/config.status
|
||||
/configure
|
||||
/sysdep/autoconf.h.in
|
||||
/sysdep/autoconf.h.in~
|
||||
|
315
.gitlab-ci.yml
Normal file
315
.gitlab-ci.yml
Normal file
@ -0,0 +1,315 @@
|
||||
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
|
||||
- $MAKE check
|
||||
|
||||
build-debian-7-amd64:
|
||||
<<: *debian-7-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-8-amd64:
|
||||
<<: *debian-8-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-9-amd64:
|
||||
<<: *debian-9-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-testing-amd64:
|
||||
<<: *debian-testing-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-fedora-25-amd64:
|
||||
<<: *fedora-25-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-fedora-26-amd64:
|
||||
<<: *fedora-26-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-6-amd64:
|
||||
<<: *centos-6-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-centos-7-amd64:
|
||||
<<: *centos-7-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-opensuse-42_3-amd64:
|
||||
<<: *opensuse-42_3-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-ubuntu-14_04-amd64:
|
||||
<<: *ubuntu-14_04-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-ubuntu-16_04-amd64:
|
||||
<<: *ubuntu-16_04-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-7-i386:
|
||||
<<: *debian-7-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-8-i386:
|
||||
<<: *debian-8-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-9-i386:
|
||||
<<: *debian-9-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-debian-testing-i386:
|
||||
<<: *debian-testing-i386_env
|
||||
<<: *build_job
|
||||
|
||||
build-freebsd-11-amd64:
|
||||
<<: *freebsd-11-amd64_env
|
||||
<<: *build_job
|
||||
|
||||
build-freebsd-11-i386:
|
||||
<<: *freebsd-11-i386_env
|
||||
<<: *build_job
|
57
NEWS
57
NEWS
@ -1,45 +1,46 @@
|
||||
Version 2.0.0-pre1 (2017-04-29)
|
||||
Version 2.0.0 (2017-12-11)
|
||||
o Integrated IPv4 + IPv6 design
|
||||
o Support for MPLS next hops
|
||||
o VPNv4 and VPNv6 network types
|
||||
o Support for VPNv4 and VPNv6 networks
|
||||
o Microsecond timers infrastructure
|
||||
o Basic VRF support
|
||||
o Babel: Support for dual-stack IPv4/IPv6
|
||||
o Babel: Many improvements and bugfixes
|
||||
o Major BGP protocol redesign
|
||||
o Full support for Multiprotocol BGP
|
||||
o BGP multicast support (SAFI 2)
|
||||
o BGP flowspec support (RFC 5575)
|
||||
o BGP with MPLS labels (RFC 3107)
|
||||
o BGP MPLS/VPN support (RFC 4364)
|
||||
o BGP 6PE - IPv6 NLRI over IPv4 MPLS (RFC 4798)
|
||||
o BGP IPv4 NLRI with an IPv6 Next Hop (RFC 5549)
|
||||
o BGP Confederations (RFC 5065)
|
||||
o BGP: Simplify igp table options
|
||||
o BGP Shutdown communication (RFC 8203)
|
||||
o BGP: Allow exchanging LOCAL_PREF with eBGP peers
|
||||
o BGP: Allow to specify interface for regular sessions
|
||||
o Babel support restored
|
||||
o Static: Minor overhaul
|
||||
o Netlink: Default kernel metric changed to 32
|
||||
o Flowspec: Limit tcp mask length to 12 bits
|
||||
o Update of show route command
|
||||
|
||||
Notes:
|
||||
|
||||
Definitions of OSPFv2, OSPFv3 and RIP NG protocols now use keywords
|
||||
'ospf v2', 'ospf v3' and 'rip ng' instead of 'ospf2', 'ospf3' and 'ripng'.
|
||||
|
||||
Flows and ROAs no longer use phony next hops, so there is no need to use
|
||||
'drop' or 'unreachable' in their static route definitions.
|
||||
|
||||
See doc/bird.conf.example2 for configuration examples.
|
||||
|
||||
|
||||
Version 2.0.0-pre0 (2016-12-07)
|
||||
o Integrated IPv4 + IPv6 design
|
||||
o Major BGP protocol redesign
|
||||
o BGP multicast support (SAFI 2)
|
||||
o BGP flowspec support (RFC 5575)
|
||||
o OSPF: Support of address families in OSPFv3
|
||||
o OSPF: Enable ECMP and Link detection by default
|
||||
o RAdv: Support for more specific routes (RFC 4191)
|
||||
o RAdv: Proper handling of prefix retraction
|
||||
o RIP: Enable ECMP and Link detection by default
|
||||
o Redesign of RPKI handling
|
||||
o New RPKI-Router protocol
|
||||
o Static: Minor overhaul
|
||||
o Static: Support for all new route types
|
||||
o Kenrel: Default Linux kernel metric changed to 32
|
||||
o Kernel: Fix IPv6 ECMP handling with Linux 4.11+
|
||||
o Update of show route command
|
||||
o BIRD client persistent history
|
||||
o New build system
|
||||
o Unit tests
|
||||
o ...
|
||||
|
||||
Notes:
|
||||
|
||||
Protocols and tables are now connected using explicit channels, most related
|
||||
protocol options (table, import, export, ...) are now channel options. See
|
||||
doc/bird.conf.example2 for configuration examples.
|
||||
Tables are now defined with appropriate net type keyword. Protocols and tables
|
||||
are now connected by explicit channels, most related protocol options (table,
|
||||
import, export, ...) are now channel options. See doc/bird.conf.example2 for
|
||||
configuration examples. Some options were removed/replaced.
|
||||
|
||||
|
||||
Version 1.6.3 (2016-12-21)
|
||||
|
4
README
4
README
@ -6,7 +6,7 @@
|
||||
(c) 1998--2008 Martin Mares <mj@ucw.cz>
|
||||
(c) 1998--2000 Pavel Machek <pavel@ucw.cz>
|
||||
(c) 1998--2008 Ondrej Filip <feela@network.cz>
|
||||
(c) 2009--2016 CZ.NIC z.s.p.o.
|
||||
(c) 2009--2017 CZ.NIC z.s.p.o.
|
||||
|
||||
================================================================================
|
||||
|
||||
@ -19,7 +19,7 @@ Public License.
|
||||
What do we support
|
||||
==================
|
||||
|
||||
o Both IPv4 and IPv6 (use --enable-ipv6 when configuring)
|
||||
o Both IPv4 and IPv6
|
||||
o Multiple routing tables
|
||||
o Border Gateway Protocol (BGPv4)
|
||||
o Routing Information Protocol (RIPv2, RIPng)
|
||||
|
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
|
35
aclocal.m4
vendored
35
aclocal.m4
vendored
@ -31,6 +31,41 @@ AC_DEFUN([BIRD_CHECK_PTHREADS],
|
||||
CFLAGS="$bird_tmp_cflags"
|
||||
])
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_MPLS_KERNEL],
|
||||
[
|
||||
AC_CACHE_CHECK(
|
||||
[for Linux MPLS headers],
|
||||
[bird_cv_mpls_kernel],
|
||||
[
|
||||
AC_COMPILE_IFELSE(
|
||||
[
|
||||
AC_LANG_PROGRAM(
|
||||
[
|
||||
#include <linux/lwtunnel.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <sys/socket.h>
|
||||
void t(int arg);
|
||||
],
|
||||
[
|
||||
t(AF_MPLS);
|
||||
t(RTA_VIA);
|
||||
t(RTA_NEWDST);
|
||||
t(RTA_ENCAP_TYPE);
|
||||
t(RTA_ENCAP);
|
||||
struct rtvia rtvia;
|
||||
t(LWTUNNEL_ENCAP_MPLS);
|
||||
]
|
||||
)
|
||||
],
|
||||
[bird_cv_mpls_kernel=yes],
|
||||
[bird_cv_mpls_kernel=no]
|
||||
)
|
||||
]
|
||||
)
|
||||
])
|
||||
|
||||
|
||||
AC_DEFUN([BIRD_CHECK_GCC_OPTION],
|
||||
[
|
||||
bird_tmp_cflags="$CFLAGS"
|
||||
|
@ -52,6 +52,6 @@ protocol rip {
|
||||
ipv4;
|
||||
}
|
||||
|
||||
protocol ripng {
|
||||
protocol rip ng {
|
||||
ipv6;
|
||||
}
|
||||
|
@ -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"
|
||||
|
23
conf/conf.c
23
conf/conf.c
@ -52,7 +52,7 @@
|
||||
#include "lib/resource.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/event.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
|
||||
@ -102,9 +102,9 @@ config_alloc(const char *name)
|
||||
c->pool = p;
|
||||
c->mem = l;
|
||||
c->file_name = ndup;
|
||||
c->load_time = now;
|
||||
c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600};
|
||||
c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0};
|
||||
c->load_time = current_time();
|
||||
c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
|
||||
c->tf_base = c->tf_log = TM_ISO_LONG_MS;
|
||||
c->gr_wait = DEFAULT_GR_WAIT;
|
||||
|
||||
return c;
|
||||
@ -219,11 +219,6 @@ global_commit(struct config *new, struct config *old)
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
if (!ipa_equal(old->listen_bgp_addr, new->listen_bgp_addr) ||
|
||||
(old->listen_bgp_port != new->listen_bgp_port) ||
|
||||
(old->listen_bgp_flags != new->listen_bgp_flags))
|
||||
log(L_WARN "Reconfiguration of BGP listening socket not implemented, please restart BIRD.");
|
||||
|
||||
if (!new->router_id)
|
||||
{
|
||||
new->router_id = old->router_id;
|
||||
@ -307,7 +302,7 @@ config_done(void *unused UNUSED)
|
||||
* config_commit - commit a configuration
|
||||
* @c: new configuration
|
||||
* @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
|
||||
* @timeout: timeout for undo (or 0 for no timeout)
|
||||
* @timeout: timeout for undo (in seconds; or 0 for no timeout)
|
||||
*
|
||||
* When a configuration is parsed and prepared for use, the
|
||||
* config_commit() function starts the process of reconfiguration.
|
||||
@ -331,7 +326,7 @@ config_done(void *unused UNUSED)
|
||||
* are accepted.
|
||||
*/
|
||||
int
|
||||
config_commit(struct config *c, int type, int timeout)
|
||||
config_commit(struct config *c, int type, uint timeout)
|
||||
{
|
||||
if (shutting_down)
|
||||
{
|
||||
@ -340,8 +335,8 @@ config_commit(struct config *c, int type, int timeout)
|
||||
}
|
||||
|
||||
undo_available = 1;
|
||||
if (timeout > 0)
|
||||
tm_start(config_timer, timeout);
|
||||
if (timeout)
|
||||
tm_start(config_timer, timeout S);
|
||||
else
|
||||
tm_stop(config_timer);
|
||||
|
||||
@ -453,7 +448,7 @@ extern void cmd_reconfig_undo_notify(void);
|
||||
extern void cmd_reconfig_msg(int r);
|
||||
|
||||
static void
|
||||
config_timeout(struct timer *t UNUSED)
|
||||
config_timeout(timer *t UNUSED)
|
||||
{
|
||||
log(L_INFO "Config timeout expired, starting undo");
|
||||
cmd_reconfig_undo_notify();
|
||||
|
11
conf/conf.h
11
conf/conf.h
@ -13,7 +13,7 @@
|
||||
#include "lib/ip.h"
|
||||
#include "lib/hash.h"
|
||||
#include "lib/resource.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
|
||||
/* Configuration structure */
|
||||
@ -32,16 +32,13 @@ struct config {
|
||||
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
|
||||
|
||||
u32 router_id; /* Our Router ID */
|
||||
ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */
|
||||
unsigned listen_bgp_port; /* Listening BGP socket should use this port (0 is default) */
|
||||
u32 listen_bgp_flags; /* Listening BGP socket should use these flags */
|
||||
unsigned proto_default_debug; /* Default protocol debug mask */
|
||||
unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */
|
||||
struct timeformat tf_route; /* Time format for 'show route' */
|
||||
struct timeformat tf_proto; /* Time format for 'show protocol' */
|
||||
struct timeformat tf_log; /* Time format for the logfile */
|
||||
struct timeformat tf_base; /* Time format for other purposes */
|
||||
u32 gr_wait; /* Graceful restart wait timeout */
|
||||
u32 gr_wait; /* Graceful restart wait timeout (sec) */
|
||||
|
||||
int cli_debug; /* Tracing of CLI connections and commands */
|
||||
int latency_debug; /* I/O loop tracks duration of each event */
|
||||
@ -57,7 +54,7 @@ struct config {
|
||||
struct config *fallback; /* Link to regular config for CLI parsing */
|
||||
int obstacle_count; /* Number of items blocking freeing of this config */
|
||||
int shutdown; /* This is a pseudo-config for daemon shutdown */
|
||||
bird_clock_t load_time; /* When we've got this configuration */
|
||||
btime load_time; /* When we've got this configuration */
|
||||
};
|
||||
|
||||
/* Please don't use these variables in protocols. Use proto_config->global instead. */
|
||||
@ -68,7 +65,7 @@ struct config *config_alloc(const char *name);
|
||||
int config_parse(struct config *);
|
||||
int cli_parse(struct config *);
|
||||
void config_free(struct config *);
|
||||
int config_commit(struct config *, int type, int timeout);
|
||||
int config_commit(struct config *, int type, uint timeout);
|
||||
int config_confirm(void);
|
||||
int config_undo(void);
|
||||
void config_init(void);
|
||||
|
@ -14,7 +14,7 @@ CF_HDR
|
||||
#include "conf/conf.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/socket.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/string.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
@ -60,7 +60,7 @@ CF_DECLS
|
||||
struct lsadb_show_data *ld;
|
||||
struct iface *iface;
|
||||
void *g;
|
||||
bird_clock_t time;
|
||||
btime time;
|
||||
struct f_prefix px;
|
||||
struct proto_spec ps;
|
||||
struct channel_limit cl;
|
||||
@ -80,11 +80,10 @@ CF_DECLS
|
||||
%type <iface> ipa_scope
|
||||
|
||||
%type <i> expr bool pxlen4
|
||||
%type <i32> expr_us
|
||||
%type <time> datetime
|
||||
%type <time> expr_us time
|
||||
%type <a> ipa
|
||||
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
|
||||
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
|
||||
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_
|
||||
%type <mls> label_stack_start label_stack
|
||||
|
||||
%type <t> text opttext
|
||||
@ -97,7 +96,7 @@ CF_DECLS
|
||||
%left '!'
|
||||
%nonassoc '.'
|
||||
|
||||
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN)
|
||||
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS)
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -137,9 +136,9 @@ expr:
|
||||
|
||||
|
||||
expr_us:
|
||||
expr S { $$ = (u32) $1 * 1000000; }
|
||||
| expr MS { $$ = (u32) $1 * 1000; }
|
||||
| expr US { $$ = (u32) $1 * 1; }
|
||||
expr S { $$ = $1 S_; }
|
||||
| expr MS { $$ = $1 MS_; }
|
||||
| expr US { $$ = $1 US_; }
|
||||
;
|
||||
|
||||
/* Switches */
|
||||
@ -235,6 +234,12 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
|
||||
cf_error("Invalid max prefix length %u", $3);
|
||||
};
|
||||
|
||||
net_mpls_: MPLS NUM
|
||||
{
|
||||
$$ = cfg_alloc(sizeof(net_addr_roa6));
|
||||
net_fill_mpls($$, $2);
|
||||
}
|
||||
|
||||
net_ip_: net_ip4_ | net_ip6_ ;
|
||||
net_vpn_: net_vpn4_ | net_vpn6_ ;
|
||||
net_roa_: net_roa4_ | net_roa6_ ;
|
||||
@ -244,6 +249,7 @@ net_:
|
||||
| net_vpn_
|
||||
| net_roa_
|
||||
| net_flow_
|
||||
| net_mpls_
|
||||
;
|
||||
|
||||
|
||||
@ -308,11 +314,11 @@ label_stack:
|
||||
}
|
||||
;
|
||||
|
||||
datetime:
|
||||
time:
|
||||
TEXT {
|
||||
$$ = tm_parse_datetime($1);
|
||||
$$ = tm_parse_time($1);
|
||||
if (!$$)
|
||||
cf_error("Invalid date and time");
|
||||
cf_error("Invalid date/time");
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -11,16 +11,6 @@ CF_HDR
|
||||
#define PARSER 1
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "conf/conf.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/socket.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/string.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
#include "nest/route.h"
|
||||
#include "nest/cli.h"
|
||||
#include "filter/filter.h"
|
||||
#include "lib/flowspec.h"
|
||||
|
||||
|
||||
|
35
configure.ac
35
configure.ac
@ -36,6 +36,12 @@ AC_ARG_ENABLE([libssh],
|
||||
[enable_libssh=try]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE([mpls-kernel],
|
||||
[AS_HELP_STRING([--enable-mpls-kernel], [enable MPLS support in kernel protocol @<:@try@:>@])],
|
||||
[],
|
||||
[enable_mpls_kernel=try]
|
||||
)
|
||||
|
||||
AC_ARG_WITH([protocols],
|
||||
[AS_HELP_STRING([--with-protocols=LIST], [include specified routing protocols @<:@all@:>@])],
|
||||
[],
|
||||
@ -239,6 +245,20 @@ if test "$enable_libssh" != no ; then
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$enable_mpls_kernel" != no ; then
|
||||
BIRD_CHECK_MPLS_KERNEL
|
||||
|
||||
if test "$bird_cv_mpls_kernel" = yes ; then
|
||||
AC_DEFINE([HAVE_MPLS_KERNEL], [1], [Define to 1 if kernel is MPLS capable])
|
||||
elif test "$enable_mpls_kernel" = yes ; then
|
||||
AC_MSG_ERROR([Kernel MPLS support not found.])
|
||||
fi
|
||||
|
||||
if test "$enable_mpls_kernel" = try ; then
|
||||
enable_mpls_kernel="$bird_cv_mpls_kernel"
|
||||
fi
|
||||
fi
|
||||
|
||||
all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static"
|
||||
|
||||
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
||||
@ -287,18 +307,6 @@ esac
|
||||
AC_CHECK_HEADERS_ONCE([alloca.h syslog.h])
|
||||
AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/socket.h>])
|
||||
|
||||
AC_CHECK_HEADERS([linux/lwtunnel.h],
|
||||
[AC_DEFINE([HAVE_LWTUNNEL], [1], [Define to 1 if you have the <linux/lwtunnel.h> header file.])],
|
||||
[],
|
||||
[] dnl Force new AC_CHECK_HEADER semantics
|
||||
)
|
||||
|
||||
AC_CHECK_MEMBERS([struct rtvia.rtvia_family],
|
||||
[AC_DEFINE([HAVE_STRUCT_RTVIA], [1], [Define to 1 if you have rtvia structure.])],
|
||||
[],
|
||||
[#include <linux/rtnetlink.h>]
|
||||
)
|
||||
|
||||
AC_C_BIGENDIAN(
|
||||
[AC_DEFINE([CPU_BIG_ENDIAN], [1], [Define to 1 if cpu is big endian])],
|
||||
[AC_DEFINE([CPU_LITTLE_ENDIAN], [1], [Define to 1 if cpu is little endian])],
|
||||
@ -314,7 +322,7 @@ if test "$enable_debug" = yes ; then
|
||||
[
|
||||
AC_DEFINE([HAVE_EXECINFO_H], [1], [Define to 1 if you have the <execinfo.h> header file.])
|
||||
AC_SEARCH_LIBS([backtrace], [execinfo],
|
||||
[]
|
||||
[],
|
||||
[AC_MSG_ERROR([Function backtrace not available.])]
|
||||
)
|
||||
]
|
||||
@ -396,6 +404,7 @@ AC_MSG_RESULT([ System configuration: $sysdesc])
|
||||
AC_MSG_RESULT([ Debugging: $enable_debug])
|
||||
AC_MSG_RESULT([ POSIX threads: $enable_pthreads])
|
||||
AC_MSG_RESULT([ Routing protocols: $protocols])
|
||||
AC_MSG_RESULT([ Kernel MPLS support: $enable_mpls_kernel])
|
||||
AC_MSG_RESULT([ Client: $enable_client])
|
||||
|
||||
rm -f $objdir/.*-stamp
|
||||
|
1395
doc/bird.sgml
1395
doc/bird.sgml
File diff suppressed because it is too large
Load Diff
@ -112,7 +112,7 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
|
||||
{
|
||||
u64 fm, to;
|
||||
|
||||
if (ipv4_used || (key >= 0x10000)) {
|
||||
if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
|
||||
check_u16(vf);
|
||||
if (vt == EC_ALL)
|
||||
vt = 0xFFFF;
|
||||
@ -421,7 +421,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
||||
%type <v> set_atom switch_atom fipa
|
||||
%type <px> fprefix
|
||||
%type <s> decls declsn one_decl function_params
|
||||
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
|
||||
%type <h> bgp_path bgp_path_tail
|
||||
%type <t> get_cf_position
|
||||
|
||||
CF_GRAMMAR
|
||||
@ -763,25 +763,18 @@ bgp_path_expr:
|
||||
;
|
||||
|
||||
bgp_path:
|
||||
PO bgp_path_tail1 PC { $$ = $2; }
|
||||
| '/' bgp_path_tail2 '/' { $$ = $2; }
|
||||
PO bgp_path_tail PC { $$ = $2; }
|
||||
;
|
||||
|
||||
bgp_path_tail1:
|
||||
NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
|
||||
| NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
|
||||
| '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
|
||||
| '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
|
||||
| bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
|
||||
bgp_path_tail:
|
||||
NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
|
||||
| NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
|
||||
| '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
|
||||
| '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
|
||||
| bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
|
||||
| { $$ = NULL; }
|
||||
;
|
||||
|
||||
bgp_path_tail2:
|
||||
NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
|
||||
| '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
|
||||
| { $$ = NULL; }
|
||||
;
|
||||
|
||||
constant:
|
||||
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
|
||||
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }
|
||||
|
@ -1089,7 +1089,8 @@ interpret(struct f_inst *what)
|
||||
|
||||
switch (what->aux & EAF_TYPE_MASK) {
|
||||
case EAF_TYPE_INT:
|
||||
if (v1.type != T_INT)
|
||||
// Enums are also ints, so allow them in.
|
||||
if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
|
||||
runtime( "Setting int attribute to non-int value" );
|
||||
l->attrs[0].u.data = v1.val.i;
|
||||
break;
|
||||
|
@ -147,6 +147,7 @@ void val_format(struct f_val v, buffer *buf);
|
||||
#define T_ENUM_RTD 0x34
|
||||
#define T_ENUM_ROA 0x35
|
||||
#define T_ENUM_NETTYPE 0x36
|
||||
#define T_ENUM_RA_PREFERENCE 0x37
|
||||
|
||||
/* new enums go here */
|
||||
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
|
||||
|
@ -589,14 +589,11 @@ function mkpath(int a; int b)
|
||||
|
||||
function t_path()
|
||||
bgpmask pm1;
|
||||
bgpmask pm2;
|
||||
bgppath p2;
|
||||
{
|
||||
pm1 = / 4 3 2 1 /;
|
||||
pm2 = [= 4 3 2 1 =];
|
||||
pm1 = [= 4 3 2 1 =];
|
||||
|
||||
bt_assert(pm1 = pm2);
|
||||
bt_assert(format(pm2) = "[= 4 3 2 1 =]");
|
||||
bt_assert(format(pm1) = "[= 4 3 2 1 =]");
|
||||
|
||||
bt_assert(+empty+ = +empty+);
|
||||
bt_assert(10 !~ +empty+);
|
||||
@ -609,17 +606,14 @@ bgppath p2;
|
||||
bt_assert(format(p2) = "(path 4 3 2 1)");
|
||||
bt_assert(p2.len = 4);
|
||||
bt_assert(p2 ~ pm1);
|
||||
bt_assert(p2 ~ pm2);
|
||||
bt_assert(3 ~ p2);
|
||||
bt_assert(p2 ~ [2, 10..20]);
|
||||
bt_assert(p2 ~ [4, 10..20]);
|
||||
|
||||
p2 = prepend(p2, 5);
|
||||
bt_assert(p2 !~ pm1);
|
||||
bt_assert(p2 !~ pm2);
|
||||
bt_assert(10 !~ p2);
|
||||
bt_assert(p2 !~ [8, ten..(2*ten)]);
|
||||
bt_assert(p2 ~ / ? 4 3 2 1 /);
|
||||
bt_assert(p2 ~ [= * 4 3 * 1 =]);
|
||||
bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]);
|
||||
bt_assert(p2 ~ mkpath(5, 4));
|
||||
|
@ -1,4 +1,4 @@
|
||||
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
|
||||
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c timer.c xmalloc.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#ifndef _BIRD_BIRDLIB_H_
|
||||
#define _BIRD_BIRDLIB_H_
|
||||
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/alloca.h"
|
||||
|
||||
/* Ugly structure offset handling macros */
|
||||
@ -70,10 +69,11 @@ static inline int u64_cmp(u64 i1, u64 i2)
|
||||
/* Microsecond time */
|
||||
|
||||
typedef s64 btime;
|
||||
//typedef s64 bird_clock_t;
|
||||
|
||||
#define S_ *1000000
|
||||
#define MS_ *1000
|
||||
#define US_ *1
|
||||
#define S_ * (btime) 1000000
|
||||
#define MS_ * (btime) 1000
|
||||
#define US_ * (btime) 1
|
||||
#define TO_S /1000000
|
||||
#define TO_MS /1000
|
||||
#define TO_US /1
|
||||
@ -82,39 +82,26 @@ typedef s64 btime;
|
||||
#define S S_
|
||||
#define MS MS_
|
||||
#define US US_
|
||||
#define NS /1000
|
||||
#endif
|
||||
|
||||
#define TIME_INFINITY ((s64) 0x7fffffffffffffff)
|
||||
|
||||
|
||||
/* Rate limiting */
|
||||
|
||||
struct tbf {
|
||||
bird_clock_t timestamp; /* Last update */
|
||||
u16 count; /* Available tokens */
|
||||
btime timestamp; /* Last update */
|
||||
u64 count; /* Available micro-tokens */
|
||||
u16 burst; /* Max number of tokens */
|
||||
u16 rate; /* Rate of replenishment */
|
||||
u16 mark; /* Whether last op was limited */
|
||||
u16 rate; /* Rate of replenishment (tokens / sec) */
|
||||
u32 drop; /* Number of failed request since last successful */
|
||||
};
|
||||
|
||||
/* Default TBF values for rate limiting log messages */
|
||||
#define TBF_DEFAULT_LOG_LIMITS { .rate = 1, .burst = 5 }
|
||||
|
||||
void tbf_update(struct tbf *f);
|
||||
|
||||
static inline int
|
||||
tbf_limit(struct tbf *f)
|
||||
{
|
||||
tbf_update(f);
|
||||
|
||||
if (!f->count)
|
||||
{
|
||||
f->mark = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
f->count--;
|
||||
f->mark = 0;
|
||||
return 0;
|
||||
}
|
||||
int tbf_limit(struct tbf *f);
|
||||
|
||||
|
||||
/* Logging and dying */
|
||||
|
@ -13,10 +13,14 @@
|
||||
#include "lib/resource.h"
|
||||
#include "sysdep/config.h"
|
||||
|
||||
#define BUFFER(type) struct { type *data; uint used, size; }
|
||||
#define BUFFER_(type) struct { type *data; uint used, size; }
|
||||
#define BUFFER_TYPE(v) typeof(* (v).data)
|
||||
#define BUFFER_SIZE(v) ((v).size * sizeof(* (v).data))
|
||||
|
||||
#ifndef PARSER
|
||||
#define BUFFER(type) BUFFER_(type)
|
||||
#endif
|
||||
|
||||
#define BUFFER_INIT(v,pool,isize) \
|
||||
({ \
|
||||
(v).used = 0; \
|
||||
|
@ -55,6 +55,7 @@ t_ev_run_list(void)
|
||||
|
||||
resource_init();
|
||||
olock_init();
|
||||
timer_init();
|
||||
io_init();
|
||||
rt_init();
|
||||
if_init();
|
||||
|
@ -91,7 +91,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end);
|
||||
|
||||
/* A data structure for keep a state of flow builder */
|
||||
struct flow_builder {
|
||||
BUFFER(byte) data;
|
||||
BUFFER_(byte) data;
|
||||
enum flow_type this_type;
|
||||
enum flow_type last_type;
|
||||
u16 last_op_offset; /* Position of last operator in data.data */
|
||||
|
@ -70,8 +70,8 @@ t_first_part(void)
|
||||
net_addr_flow4 *f;
|
||||
NET_ADDR_FLOW4_(f, ip4_build(10,0,0,1), 24, ((byte[]) { 0x00, 0x00, 0xab }));
|
||||
|
||||
const byte const *under240 = &f->data[1];
|
||||
const byte const *above240 = &f->data[2];
|
||||
const byte *under240 = &f->data[1];
|
||||
const byte *above240 = &f->data[2];
|
||||
|
||||
/* Case 0x00 0x00 */
|
||||
bt_assert(flow4_first_part(f) == NULL);
|
||||
|
@ -11,7 +11,7 @@
|
||||
*
|
||||
* Linear memory pools are collections of memory blocks which
|
||||
* support very fast allocation of new blocks, but are able to free only
|
||||
* the whole collection at once.
|
||||
* the whole collection at once (or in stack order).
|
||||
*
|
||||
* Example: Each configuration is described by a complex system of structures,
|
||||
* linked lists and function trees which are all allocated from a single linear
|
||||
@ -37,7 +37,7 @@ const int lp_chunk_size = sizeof(struct lp_chunk);
|
||||
struct linpool {
|
||||
resource r;
|
||||
byte *ptr, *end;
|
||||
struct lp_chunk *first, *current, **plast; /* Normal (reusable) chunks */
|
||||
struct lp_chunk *first, *current; /* Normal (reusable) chunks */
|
||||
struct lp_chunk *first_large; /* Large chunks */
|
||||
uint chunk_size, threshold, total, total_large;
|
||||
};
|
||||
@ -69,7 +69,6 @@ linpool
|
||||
*lp_new(pool *p, uint blk)
|
||||
{
|
||||
linpool *m = ralloc(p, &lp_class);
|
||||
m->plast = &m->first;
|
||||
m->chunk_size = blk;
|
||||
m->threshold = 3*blk/4;
|
||||
return m;
|
||||
@ -114,22 +113,25 @@ lp_alloc(linpool *m, uint size)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m->current)
|
||||
if (m->current && m->current->next)
|
||||
{
|
||||
/* Still have free chunks from previous incarnation (before lp_flush()) */
|
||||
c = m->current;
|
||||
m->current = c->next;
|
||||
c = m->current->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to allocate a new chunk */
|
||||
c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
|
||||
m->total += m->chunk_size;
|
||||
*m->plast = c;
|
||||
m->plast = &c->next;
|
||||
c->next = NULL;
|
||||
c->size = m->chunk_size;
|
||||
|
||||
if (m->current)
|
||||
m->current->next = c;
|
||||
else
|
||||
m->first = c;
|
||||
}
|
||||
m->current = c;
|
||||
m->ptr = c->data + size;
|
||||
m->end = c->data + m->chunk_size;
|
||||
}
|
||||
@ -190,9 +192,11 @@ lp_flush(linpool *m)
|
||||
{
|
||||
struct lp_chunk *c;
|
||||
|
||||
/* Relink all normal chunks to free list and free all large chunks */
|
||||
m->ptr = m->end = NULL;
|
||||
m->current = m->first;
|
||||
/* Move ptr to the first chunk and free all large chunks */
|
||||
m->current = c = m->first;
|
||||
m->ptr = c ? c->data : NULL;
|
||||
m->end = c ? c->data + m->chunk_size : NULL;
|
||||
|
||||
while (c = m->first_large)
|
||||
{
|
||||
m->first_large = c->next;
|
||||
@ -201,6 +205,49 @@ lp_flush(linpool *m)
|
||||
m->total_large = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lp_save - save the state of a linear memory pool
|
||||
* @m: linear memory pool
|
||||
* @p: state buffer
|
||||
*
|
||||
* This function saves the state of a linear memory pool. Saved state can be
|
||||
* used later to restore the pool (to free memory allocated since).
|
||||
*/
|
||||
void
|
||||
lp_save(linpool *m, lp_state *p)
|
||||
{
|
||||
p->current = m->current;
|
||||
p->large = m->first_large;
|
||||
p->ptr = m->ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* lp_restore - restore the state of a linear memory pool
|
||||
* @m: linear memory pool
|
||||
* @p: saved state
|
||||
*
|
||||
* This function restores the state of a linear memory pool, freeing all memory
|
||||
* allocated since the state was saved. Note that the function cannot un-free
|
||||
* the memory, therefore the function also invalidates other states that were
|
||||
* saved between (on the same pool).
|
||||
*/
|
||||
void
|
||||
lp_restore(linpool *m, lp_state *p)
|
||||
{
|
||||
struct lp_chunk *c;
|
||||
|
||||
/* Move ptr to the saved pos and free all newer large chunks */
|
||||
m->current = c = p->current;
|
||||
m->ptr = p->ptr;
|
||||
m->end = c ? c->data + m->chunk_size : NULL;
|
||||
|
||||
while ((c = m->first_large) && (c != p->large))
|
||||
{
|
||||
m->first_large = c->next;
|
||||
xfree(c);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lp_free(resource *r)
|
||||
{
|
||||
|
18
lib/net.c
18
lib/net.c
@ -288,3 +288,21 @@ net_in_netX(const net_addr *a, const net_addr *n)
|
||||
|
||||
return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n);
|
||||
}
|
||||
|
||||
#define CHECK_NET(T,S) \
|
||||
({ if (sizeof(T) != S) die("sizeof %s is %d/%d", #T, (int) sizeof(T), S); })
|
||||
|
||||
void
|
||||
net_init(void)
|
||||
{
|
||||
CHECK_NET(net_addr, 24);
|
||||
CHECK_NET(net_addr_ip4, 8);
|
||||
CHECK_NET(net_addr_ip6, 20);
|
||||
CHECK_NET(net_addr_vpn4, 16);
|
||||
CHECK_NET(net_addr_vpn6, 32);
|
||||
CHECK_NET(net_addr_roa4, 16);
|
||||
CHECK_NET(net_addr_roa6, 28);
|
||||
CHECK_NET(net_addr_flow4, 8);
|
||||
CHECK_NET(net_addr_flow6, 20);
|
||||
CHECK_NET(net_addr_mpls, 8);
|
||||
}
|
||||
|
29
lib/net.h
29
lib/net.h
@ -45,7 +45,7 @@ typedef struct net_addr {
|
||||
u8 type;
|
||||
u8 pxlen;
|
||||
u16 length;
|
||||
u8 data[16];
|
||||
u8 data[20];
|
||||
u64 align[0];
|
||||
} net_addr;
|
||||
|
||||
@ -76,6 +76,7 @@ typedef struct net_addr_vpn6 {
|
||||
u8 pxlen;
|
||||
u16 length;
|
||||
ip6_addr prefix;
|
||||
u32 padding;
|
||||
u64 rd;
|
||||
} net_addr_vpn6;
|
||||
|
||||
@ -152,7 +153,7 @@ extern const u16 net_max_text_length[];
|
||||
((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd })
|
||||
|
||||
#define NET_ADDR_VPN6(prefix,pxlen,rd) \
|
||||
((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, rd })
|
||||
((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, 0, rd })
|
||||
|
||||
#define NET_ADDR_ROA4(prefix,pxlen,max_pxlen,asn) \
|
||||
((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn })
|
||||
@ -230,11 +231,14 @@ static inline int net_type_match(const net_addr *a, u32 mask)
|
||||
static inline int net_is_ip(const net_addr *a)
|
||||
{ return (a->type == NET_IP4) || (a->type == NET_IP6); }
|
||||
|
||||
static inline int net_is_vpn(const net_addr *a)
|
||||
{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
|
||||
|
||||
static inline int net_is_roa(const net_addr *a)
|
||||
{ return (a->type == NET_ROA4) || (a->type == NET_ROA6); }
|
||||
|
||||
static inline int net_is_vpn(const net_addr *a)
|
||||
{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
|
||||
static inline int net_is_flow(const net_addr *a)
|
||||
{ return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); }
|
||||
|
||||
|
||||
static inline ip4_addr net4_prefix(const net_addr *a)
|
||||
@ -354,10 +358,10 @@ static inline int net_zero_roa6(const net_addr_roa6 *a)
|
||||
{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
|
||||
|
||||
static inline int net_zero_flow4(const net_addr_flow4 *a)
|
||||
{ return !a->pxlen && ip4_zero(a->prefix) && !a->data; }
|
||||
{ return !a->pxlen && ip4_zero(a->prefix) && (a->length == sizeof(net_addr_flow4)); }
|
||||
|
||||
static inline int net_zero_flow6(const net_addr_flow6 *a)
|
||||
{ return !a->pxlen && ip6_zero(a->prefix) && !a->data; }
|
||||
{ return !a->pxlen && ip6_zero(a->prefix) && (a->length == sizeof(net_addr_flow6)); }
|
||||
|
||||
static inline int net_zero_mpls(const net_addr_mpls *a)
|
||||
{ return !a->label; }
|
||||
@ -526,8 +530,21 @@ 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);
|
||||
|
||||
void net_init(void);
|
||||
|
||||
#endif
|
||||
|
55
lib/printf.c
55
lib/printf.c
@ -125,9 +125,10 @@ static char * number(char * str, long num, int base, int size, int precision,
|
||||
* or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
|
||||
* generic network addresses (net_addr *), |%R| for Router / Network ID (u32
|
||||
* value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
|
||||
* value printed as eight :-separated octets) and |%m| resp. |%M| for error
|
||||
* messages (uses strerror() to translate @errno code to message text). On the
|
||||
* other hand, it doesn't support floating point numbers.
|
||||
* value printed as eight :-separated octets), |%t| for time values (btime) with
|
||||
* specified subsecond precision, and |%m| resp. |%M| for error messages (uses
|
||||
* strerror() to translate @errno code to message text). On the other hand, it
|
||||
* doesn't support floating point numbers.
|
||||
*
|
||||
* Result: number of characters of the output string or -1 if
|
||||
* the buffer space was insufficient.
|
||||
@ -139,6 +140,8 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||
int i, base;
|
||||
u32 x;
|
||||
u64 X;
|
||||
btime t;
|
||||
s64 t1, t2;
|
||||
char *str, *start;
|
||||
const char *s;
|
||||
char ipbuf[NET_MAX_TEXT_LENGTH+1];
|
||||
@ -279,7 +282,6 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||
return -1;
|
||||
continue;
|
||||
|
||||
|
||||
case 'n':
|
||||
if (qualifier == 'l') {
|
||||
long * ip = va_arg(args, long *);
|
||||
@ -360,6 +362,50 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||
s = ipbuf;
|
||||
goto str;
|
||||
|
||||
case 't':
|
||||
t = va_arg(args, btime);
|
||||
t1 = t TO_S;
|
||||
t2 = t - t1 S;
|
||||
|
||||
if (precision < 0)
|
||||
precision = 3;
|
||||
|
||||
if (precision > 6)
|
||||
precision = 6;
|
||||
|
||||
/* Compute field_width for second part */
|
||||
if ((precision > 0) && (field_width > 0))
|
||||
field_width -= (1 + precision);
|
||||
|
||||
if (field_width < 0)
|
||||
field_width = 0;
|
||||
|
||||
/* Print seconds */
|
||||
flags |= SIGN;
|
||||
str = number(str, t1, 10, field_width, 0, flags, size);
|
||||
if (!str)
|
||||
return -1;
|
||||
|
||||
if (precision > 0)
|
||||
{
|
||||
size -= (str-start);
|
||||
start = str;
|
||||
|
||||
if ((1 + precision) > size)
|
||||
return -1;
|
||||
|
||||
/* Convert microseconds to requested precision */
|
||||
for (i = precision; i < 6; i++)
|
||||
t2 /= 10;
|
||||
|
||||
/* Print sub-seconds */
|
||||
*str++ = '.';
|
||||
str = number(str, t2, 10, precision, 0, ZEROPAD, size - 1);
|
||||
if (!str)
|
||||
return -1;
|
||||
}
|
||||
goto done;
|
||||
|
||||
/* integer number formats - set up the flags and "break" */
|
||||
case 'o':
|
||||
base = 8;
|
||||
@ -401,6 +447,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
|
||||
str = number(str, num, base, field_width, precision, flags, size);
|
||||
if (!str)
|
||||
return -1;
|
||||
done: ;
|
||||
}
|
||||
if (!size)
|
||||
return -1;
|
||||
|
@ -56,6 +56,15 @@ t_simple(void)
|
||||
BSPRINTF(2, "-1", buf, "%d", -1);
|
||||
BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
|
||||
|
||||
BSPRINTF(7, "123.456", buf, "%t", (btime) 123456789);
|
||||
BSPRINTF(7, "123.456", buf, "%2t", (btime) 123456789);
|
||||
BSPRINTF(8, " 123.456", buf, "%8t", (btime) 123456789);
|
||||
BSPRINTF(4, " 123", buf, "%4.0t", (btime) 123456789);
|
||||
BSPRINTF(8, "123.4567", buf, "%8.4t", (btime) 123456789);
|
||||
BSPRINTF(9, "0123.4567", buf, "%09.4t", (btime) 123456789);
|
||||
BSPRINTF(12, " 123.456789", buf, "%12.10t", (btime) 123456789);
|
||||
BSPRINTF(8, " 123.004", buf, "%8t", (btime) 123004 MS);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -59,11 +59,18 @@ void mb_free(void *);
|
||||
|
||||
typedef struct linpool linpool;
|
||||
|
||||
typedef struct lp_state {
|
||||
void *current, *large;
|
||||
byte *ptr;
|
||||
} lp_state;
|
||||
|
||||
linpool *lp_new(pool *, unsigned blk);
|
||||
void *lp_alloc(linpool *, unsigned size); /* Aligned */
|
||||
void *lp_allocu(linpool *, unsigned size); /* Unaligned */
|
||||
void *lp_allocz(linpool *, unsigned size); /* With clear */
|
||||
void lp_flush(linpool *); /* Free everything, but leave linpool */
|
||||
void lp_save(linpool *m, lp_state *p); /* Save state */
|
||||
void lp_restore(linpool *m, lp_state *p); /* Restore state */
|
||||
|
||||
extern const int lp_chunk_size;
|
||||
#define LP_GAS 1024
|
||||
|
@ -50,6 +50,7 @@ typedef struct birdsock {
|
||||
int ttl; /* Time To Live, -1 = default */
|
||||
u32 flags;
|
||||
struct iface *iface; /* Interface; specify this for broad/multicast sockets */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
byte *rbuf, *rpos; /* NULL=allocate automatically */
|
||||
uint fast_rx; /* RX has higher priority in event loop */
|
||||
|
32
lib/tbf.c
32
lib/tbf.c
@ -8,22 +8,30 @@
|
||||
*/
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
void
|
||||
tbf_update(struct tbf *f)
|
||||
int
|
||||
tbf_limit(struct tbf *f)
|
||||
{
|
||||
bird_clock_t delta = now - f->timestamp;
|
||||
btime delta = current_time() - f->timestamp;
|
||||
|
||||
if (delta == 0)
|
||||
return;
|
||||
|
||||
f->timestamp = now;
|
||||
|
||||
if ((0 < delta) && (delta < f->burst))
|
||||
if (delta > 0)
|
||||
{
|
||||
u32 next = f->count + delta * f->rate;
|
||||
f->count = MIN(next, f->burst);
|
||||
u64 next = f->count + delta * f->rate;
|
||||
u64 burst = (u64) f->burst << 20;
|
||||
f->count = MIN(next, burst);
|
||||
f->timestamp += delta;
|
||||
}
|
||||
|
||||
if (f->count < 1000000)
|
||||
{
|
||||
f->drop++;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
f->count = f->burst;
|
||||
{
|
||||
f->count -= 1000000;
|
||||
f->drop = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
377
lib/timer.c
Normal file
377
lib/timer.c
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* BIRD -- Timers
|
||||
*
|
||||
* (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2013--2017 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Timers
|
||||
*
|
||||
* Timers are resources which represent a wish of a module to call a function at
|
||||
* the specified time. The timer code does not guarantee exact timing, only that
|
||||
* a timer function will not be called before the requested time.
|
||||
*
|
||||
* In BIRD, time is represented by values of the &btime type which is signed
|
||||
* 64-bit integer interpreted as a relative number of microseconds since some
|
||||
* fixed time point in past. The current time can be obtained by current_time()
|
||||
* function with reasonable accuracy and is monotonic. There is also a current
|
||||
* 'wall-clock' real time obtainable by current_real_time() reported by OS.
|
||||
*
|
||||
* Each timer is described by a &timer structure containing a pointer to the
|
||||
* handler function (@hook), data private to this function (@data), time the
|
||||
* function should be called at (@expires, 0 for inactive timers), for the other
|
||||
* fields see |timer.h|.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
|
||||
#include "lib/heap.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
|
||||
struct timeloop main_timeloop;
|
||||
|
||||
|
||||
#ifdef USE_PTHREADS
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
/* Data accessed and modified from proto/bfd/io.c */
|
||||
pthread_key_t current_time_key;
|
||||
|
||||
static inline struct timeloop *
|
||||
timeloop_current(void)
|
||||
{
|
||||
return pthread_getspecific(current_time_key);
|
||||
}
|
||||
|
||||
static inline void
|
||||
timeloop_init_current(void)
|
||||
{
|
||||
pthread_key_create(¤t_time_key, NULL);
|
||||
pthread_setspecific(current_time_key, &main_timeloop);
|
||||
}
|
||||
|
||||
void wakeup_kick_current(void);
|
||||
|
||||
#else
|
||||
|
||||
/* Just use main timelooop */
|
||||
static inline struct timeloop * timeloop_current(void) { return &main_timeloop; }
|
||||
static inline void timeloop_init_current(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
btime
|
||||
current_time(void)
|
||||
{
|
||||
return timeloop_current()->last_time;
|
||||
}
|
||||
|
||||
btime
|
||||
current_real_time(void)
|
||||
{
|
||||
struct timeloop *loop = timeloop_current();
|
||||
|
||||
if (!loop->real_time)
|
||||
times_update_real_time(loop);
|
||||
|
||||
return loop->real_time;
|
||||
}
|
||||
|
||||
|
||||
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
|
||||
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
|
||||
heap[a]->index = (a), heap[b]->index = (b))
|
||||
|
||||
|
||||
static void
|
||||
tm_free(resource *r)
|
||||
{
|
||||
timer *t = (void *) r;
|
||||
|
||||
tm_stop(t);
|
||||
}
|
||||
|
||||
static void
|
||||
tm_dump(resource *r)
|
||||
{
|
||||
timer *t = (void *) r;
|
||||
|
||||
debug("(code %p, data %p, ", t->hook, t->data);
|
||||
if (t->randomize)
|
||||
debug("rand %d, ", t->randomize);
|
||||
if (t->recurrent)
|
||||
debug("recur %d, ", t->recurrent);
|
||||
if (t->expires)
|
||||
debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
|
||||
else
|
||||
debug("inactive)\n");
|
||||
}
|
||||
|
||||
|
||||
static struct resclass tm_class = {
|
||||
"Timer",
|
||||
sizeof(timer),
|
||||
tm_free,
|
||||
tm_dump,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
timer *
|
||||
tm_new(pool *p)
|
||||
{
|
||||
timer *t = ralloc(p, &tm_class);
|
||||
t->index = -1;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
tm_set(timer *t, btime when)
|
||||
{
|
||||
struct timeloop *loop = timeloop_current();
|
||||
uint tc = timers_count(loop);
|
||||
|
||||
if (!t->expires)
|
||||
{
|
||||
t->index = ++tc;
|
||||
t->expires = when;
|
||||
BUFFER_PUSH(loop->timers) = t;
|
||||
HEAP_INSERT(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP);
|
||||
}
|
||||
else if (t->expires < when)
|
||||
{
|
||||
t->expires = when;
|
||||
HEAP_INCREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
}
|
||||
else if (t->expires > when)
|
||||
{
|
||||
t->expires = when;
|
||||
HEAP_DECREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BFD
|
||||
/* Hack to notify BFD loops */
|
||||
if ((loop != &main_timeloop) && (t->index == 1))
|
||||
wakeup_kick_current();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
tm_start(timer *t, btime after)
|
||||
{
|
||||
tm_set(t, current_time() + MAX(after, 0));
|
||||
}
|
||||
|
||||
void
|
||||
tm_stop(timer *t)
|
||||
{
|
||||
if (!t->expires)
|
||||
return;
|
||||
|
||||
struct timeloop *loop = timeloop_current();
|
||||
uint tc = timers_count(loop);
|
||||
|
||||
HEAP_DELETE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
BUFFER_POP(loop->timers);
|
||||
|
||||
t->index = -1;
|
||||
t->expires = 0;
|
||||
}
|
||||
|
||||
void
|
||||
timers_init(struct timeloop *loop, pool *p)
|
||||
{
|
||||
times_init(loop);
|
||||
|
||||
BUFFER_INIT(loop->timers, p, 4);
|
||||
BUFFER_PUSH(loop->timers) = NULL;
|
||||
}
|
||||
|
||||
void io_log_event(void *hook, void *data);
|
||||
|
||||
void
|
||||
timers_fire(struct timeloop *loop)
|
||||
{
|
||||
btime base_time;
|
||||
timer *t;
|
||||
|
||||
times_update(loop);
|
||||
base_time = loop->last_time;
|
||||
|
||||
while (t = timers_first(loop))
|
||||
{
|
||||
if (t->expires > base_time)
|
||||
return;
|
||||
|
||||
if (t->recurrent)
|
||||
{
|
||||
btime when = t->expires + t->recurrent;
|
||||
|
||||
if (when <= loop->last_time)
|
||||
when = loop->last_time + t->recurrent;
|
||||
|
||||
if (t->randomize)
|
||||
when += random() % (t->randomize + 1);
|
||||
|
||||
tm_set(t, when);
|
||||
}
|
||||
else
|
||||
tm_stop(t);
|
||||
|
||||
/* This is ugly hack, we want to log just timers executed from the main I/O loop */
|
||||
if (loop == &main_timeloop)
|
||||
io_log_event(t->hook, t->data);
|
||||
|
||||
t->hook(t);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
timer_init(void)
|
||||
{
|
||||
timers_init(&main_timeloop, &root_pool);
|
||||
timeloop_init_current();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tm_parse_time - parse a date and time
|
||||
* @x: time string
|
||||
*
|
||||
* tm_parse_time() takes a textual representation of a date and time
|
||||
* (yyyy-mm-dd[ hh:mm:ss[.sss]]) and converts it to the corresponding value of
|
||||
* type &btime.
|
||||
*/
|
||||
btime
|
||||
tm_parse_time(char *x)
|
||||
{
|
||||
struct tm tm;
|
||||
int usec, n1, n2, n3, r;
|
||||
|
||||
r = sscanf(x, "%d-%d-%d%n %d:%d:%d%n.%d%n",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &n1,
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n2,
|
||||
&usec, &n3);
|
||||
|
||||
if ((r == 3) && !x[n1])
|
||||
tm.tm_hour = tm.tm_min = tm.tm_sec = usec = 0;
|
||||
else if ((r == 6) && !x[n2])
|
||||
usec = 0;
|
||||
else if ((r == 7) && !x[n3])
|
||||
{
|
||||
/* Convert subsecond digits to proper precision */
|
||||
int digits = n3 - n2 - 1;
|
||||
if ((usec < 0) || (usec > 999999) || (digits < 1) || (digits > 6))
|
||||
return 0;
|
||||
|
||||
while (digits++ < 6)
|
||||
usec *= 10;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
tm.tm_mon--;
|
||||
tm.tm_year -= 1900;
|
||||
s64 ts = mktime(&tm);
|
||||
if ((ts == (s64) (time_t) -1) || (ts < 0) || (ts > ((s64) 1 << 40)))
|
||||
return 0;
|
||||
|
||||
return ts S + usec;
|
||||
}
|
||||
|
||||
/**
|
||||
* tm_format_time - convert date and time to textual representation
|
||||
* @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
|
||||
* @fmt: specification of resulting textual representation of the time
|
||||
* @t: time
|
||||
*
|
||||
* This function formats the given relative time value @t to a textual
|
||||
* date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
|
||||
*/
|
||||
void
|
||||
tm_format_time(char *x, struct timeformat *fmt, btime t)
|
||||
{
|
||||
btime dt = current_time() - t;
|
||||
btime rt = current_real_time() - dt;
|
||||
int v1 = !fmt->limit || (dt < fmt->limit);
|
||||
|
||||
tm_format_real_time(x, v1 ? fmt->fmt1 : fmt->fmt2, rt);
|
||||
}
|
||||
|
||||
/* Replace %f in format string with usec scaled to requested precision */
|
||||
static int
|
||||
strfusec(char *buf, int size, const char *fmt, uint usec)
|
||||
{
|
||||
char *str = buf;
|
||||
int parity = 0;
|
||||
|
||||
while (*fmt)
|
||||
{
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
if ((fmt[0] == '%') && (!parity) &&
|
||||
((fmt[1] == 'f') || (fmt[1] >= '1') && (fmt[1] <= '6') && (fmt[2] == 'f')))
|
||||
{
|
||||
int digits = (fmt[1] == 'f') ? 6 : (fmt[1] - '0');
|
||||
uint d = digits, u = usec;
|
||||
|
||||
/* Convert microseconds to requested precision */
|
||||
while (d++ < 6)
|
||||
u /= 10;
|
||||
|
||||
int num = bsnprintf(str, size, "%0*u", digits, u);
|
||||
if (num < 0)
|
||||
return 0;
|
||||
|
||||
fmt += (fmt[1] == 'f') ? 2 : 3;
|
||||
ADVANCE(str, size, num);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Handle '%%' expression */
|
||||
parity = (*fmt == '%') ? !parity : 0;
|
||||
*str++ = *fmt++;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
|
||||
*str = 0;
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
void
|
||||
tm_format_real_time(char *x, const char *fmt, btime t)
|
||||
{
|
||||
s64 t1 = t TO_S;
|
||||
s64 t2 = t - t1 S;
|
||||
|
||||
time_t ts = t1;
|
||||
struct tm tm;
|
||||
if (!localtime_r(&ts, &tm))
|
||||
goto err;
|
||||
|
||||
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||
if (!strfusec(tbuf, TM_DATETIME_BUFFER_SIZE, fmt, t2))
|
||||
goto err;
|
||||
|
||||
if (!strftime(x, TM_DATETIME_BUFFER_SIZE, tbuf, &tm))
|
||||
goto err;
|
||||
|
||||
return;
|
||||
|
||||
err:
|
||||
strcpy(x, "<error>");
|
||||
}
|
127
lib/timer.h
Normal file
127
lib/timer.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* BIRD -- Timers
|
||||
*
|
||||
* (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2013--2017 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_TIMER_H_
|
||||
#define _BIRD_TIMER_H_
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "lib/buffer.h"
|
||||
#include "lib/resource.h"
|
||||
|
||||
|
||||
typedef struct timer
|
||||
{
|
||||
resource r;
|
||||
void (*hook)(struct timer *);
|
||||
void *data;
|
||||
|
||||
btime expires; /* 0=inactive */
|
||||
uint randomize; /* Amount of randomization */
|
||||
uint recurrent; /* Timer recurrence */
|
||||
|
||||
int index;
|
||||
} timer;
|
||||
|
||||
struct timeloop
|
||||
{
|
||||
BUFFER_(timer *) timers;
|
||||
btime last_time;
|
||||
btime real_time;
|
||||
};
|
||||
|
||||
static inline uint timers_count(struct timeloop *loop)
|
||||
{ return loop->timers.used - 1; }
|
||||
|
||||
static inline timer *timers_first(struct timeloop *loop)
|
||||
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
|
||||
|
||||
extern struct timeloop main_timeloop;
|
||||
|
||||
btime current_time(void);
|
||||
btime current_real_time(void);
|
||||
|
||||
//#define now (current_time() TO_S)
|
||||
//#define now_real (current_real_time() TO_S)
|
||||
extern btime boot_time;
|
||||
|
||||
timer *tm_new(pool *p);
|
||||
void tm_set(timer *t, btime when);
|
||||
void tm_start(timer *t, btime after);
|
||||
void tm_stop(timer *t);
|
||||
|
||||
static inline int
|
||||
tm_active(timer *t)
|
||||
{
|
||||
return t->expires != 0;
|
||||
}
|
||||
|
||||
static inline btime
|
||||
tm_remains(timer *t)
|
||||
{
|
||||
btime now_ = current_time();
|
||||
return (t->expires > now_) ? (t->expires - now_) : 0;
|
||||
}
|
||||
|
||||
static inline timer *
|
||||
tm_new_init(pool *p, void (*hook)(struct timer *), void *data, uint rec, uint rand)
|
||||
{
|
||||
timer *t = tm_new(p);
|
||||
t->hook = hook;
|
||||
t->data = data;
|
||||
t->recurrent = rec;
|
||||
t->randomize = rand;
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tm_set_max(timer *t, btime when)
|
||||
{
|
||||
if (when > t->expires)
|
||||
tm_set(t, when);
|
||||
}
|
||||
|
||||
static inline void
|
||||
tm_start_max(timer *t, btime after)
|
||||
{
|
||||
btime rem = tm_remains(t);
|
||||
tm_start(t, MAX_(rem, after));
|
||||
}
|
||||
|
||||
/* In sysdep code */
|
||||
void times_init(struct timeloop *loop);
|
||||
void times_update(struct timeloop *loop);
|
||||
void times_update_real_time(struct timeloop *loop);
|
||||
|
||||
/* For I/O loop */
|
||||
void timers_init(struct timeloop *loop, pool *p);
|
||||
void timers_fire(struct timeloop *loop);
|
||||
|
||||
void timer_init(void);
|
||||
|
||||
|
||||
struct timeformat {
|
||||
char *fmt1, *fmt2;
|
||||
btime limit;
|
||||
};
|
||||
|
||||
#define TM_ISO_SHORT_S (struct timeformat){"%T", "%F", (s64) (20*3600) S_}
|
||||
#define TM_ISO_SHORT_MS (struct timeformat){"%T.%3f", "%F", (s64) (20*3600) S_}
|
||||
#define TM_ISO_SHORT_US (struct timeformat){"%T.%6f", "%F", (s64) (20*3600) S_}
|
||||
|
||||
#define TM_ISO_LONG_S (struct timeformat){"%F %T", NULL, 0}
|
||||
#define TM_ISO_LONG_MS (struct timeformat){"%F %T.%3f", NULL, 0}
|
||||
#define TM_ISO_LONG_US (struct timeformat){"%F %T.%6f", NULL, 0}
|
||||
|
||||
#define TM_DATETIME_BUFFER_SIZE 32 /* Buffer size required by tm_format_time() */
|
||||
|
||||
btime tm_parse_time(char *x);
|
||||
void tm_format_time(char *x, struct timeformat *fmt, btime t);
|
||||
void tm_format_real_time(char *x, const char *fmt, btime t);
|
||||
|
||||
#endif
|
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
|
@ -27,12 +27,12 @@ cmd_show_status(void)
|
||||
byte tim[TM_DATETIME_BUFFER_SIZE];
|
||||
|
||||
cli_msg(-1000, "BIRD " BIRD_VERSION);
|
||||
tm_format_datetime(tim, &config->tf_base, now);
|
||||
tm_format_time(tim, &config->tf_base, current_time());
|
||||
cli_msg(-1011, "Router ID is %R", config->router_id);
|
||||
cli_msg(-1011, "Current server time is %s", tim);
|
||||
tm_format_datetime(tim, &config->tf_base, boot_time);
|
||||
tm_format_time(tim, &config->tf_base, boot_time);
|
||||
cli_msg(-1011, "Last reboot on %s", tim);
|
||||
tm_format_datetime(tim, &config->tf_base, config->load_time);
|
||||
tm_format_time(tim, &config->tf_base, config->load_time);
|
||||
cli_msg(-1011, "Last reconfiguration on %s", tim);
|
||||
|
||||
graceful_restart_show_status();
|
||||
|
@ -65,14 +65,15 @@ proto_postconfig(void)
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
|
||||
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
|
||||
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
|
||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
||||
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
|
||||
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
|
||||
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
|
||||
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
|
||||
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
|
||||
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
|
||||
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
|
||||
CF_KEYWORDS(REFRESH)
|
||||
|
||||
@ -124,24 +125,6 @@ idval:
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
CF_ADDTO(conf, listen)
|
||||
|
||||
listen: LISTEN BGP listen_opts ';' ;
|
||||
|
||||
listen_opts:
|
||||
/* Nothing */
|
||||
| listen_opts listen_opt
|
||||
;
|
||||
|
||||
listen_opt:
|
||||
ADDRESS ipa { new_config->listen_bgp_addr = $2; }
|
||||
| PORT expr { new_config->listen_bgp_port = $2; }
|
||||
| V6ONLY { new_config->listen_bgp_flags = 0; }
|
||||
| DUAL { new_config->listen_bgp_flags = 1; }
|
||||
;
|
||||
|
||||
|
||||
CF_ADDTO(conf, gr_opts)
|
||||
|
||||
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
|
||||
@ -158,6 +141,7 @@ net_type:
|
||||
| ROA6 { $$ = NET_ROA6; }
|
||||
| FLOW4{ $$ = NET_FLOW4; }
|
||||
| FLOW6{ $$ = NET_FLOW6; }
|
||||
| MPLS { $$ = NET_MPLS; }
|
||||
;
|
||||
|
||||
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
|
||||
@ -225,6 +209,7 @@ proto_item:
|
||||
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
|
||||
| ROUTER ID idval { this_proto->router_id = $3; }
|
||||
| DESCRIPTION text { this_proto->dsc = $2; }
|
||||
| VRF text { this_proto->vrf = if_get_by_name($2); }
|
||||
;
|
||||
|
||||
|
||||
@ -296,6 +281,7 @@ limit_spec:
|
||||
| OFF { $$ = (struct channel_limit){}; }
|
||||
;
|
||||
|
||||
|
||||
CF_ADDTO(conf, debug_default)
|
||||
|
||||
debug_default:
|
||||
@ -305,6 +291,31 @@ debug_default:
|
||||
|
||||
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
|
||||
|
||||
CF_ADDTO(conf, timeformat_base)
|
||||
|
||||
timeformat_which:
|
||||
ROUTE { $$ = &new_config->tf_route; }
|
||||
| PROTOCOL { $$ = &new_config->tf_proto; }
|
||||
| BASE { $$ = &new_config->tf_base; }
|
||||
| LOG { $$ = &new_config->tf_log; }
|
||||
;
|
||||
|
||||
timeformat_spec:
|
||||
timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
|
||||
| timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
|
||||
| timeformat_which ISO SHORT { *$1 = TM_ISO_SHORT_S; }
|
||||
| timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
|
||||
| timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
|
||||
| timeformat_which ISO LONG { *$1 = TM_ISO_LONG_S; }
|
||||
| timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
|
||||
| timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
|
||||
;
|
||||
|
||||
timeformat_base:
|
||||
TIMEFORMAT timeformat_spec ';'
|
||||
;
|
||||
|
||||
|
||||
/* Interface patterns */
|
||||
|
||||
iface_patt_node_init:
|
||||
@ -463,12 +474,12 @@ password_item_begin:
|
||||
|
||||
password_item_params:
|
||||
/* empty */ { }
|
||||
| GENERATE FROM datetime ';' password_item_params { this_p_item->genfrom = $3; }
|
||||
| GENERATE TO datetime ';' password_item_params { this_p_item->gento = $3; }
|
||||
| ACCEPT FROM datetime ';' password_item_params { this_p_item->accfrom = $3; }
|
||||
| ACCEPT TO datetime ';' password_item_params { this_p_item->accto = $3; }
|
||||
| FROM datetime ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
|
||||
| TO datetime ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
|
||||
| GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
|
||||
| GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
|
||||
| ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
|
||||
| ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
|
||||
| FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
|
||||
| TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
|
||||
| ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
|
||||
| ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
|
||||
;
|
||||
@ -747,12 +758,12 @@ echo_size:
|
||||
}
|
||||
;
|
||||
|
||||
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
|
||||
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
|
||||
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
|
||||
CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
|
||||
CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
|
||||
CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
|
||||
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
|
||||
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
|
||||
|
261
nest/iface.c
261
nest/iface.c
@ -32,11 +32,14 @@
|
||||
#include "lib/resource.h"
|
||||
#include "lib/string.h"
|
||||
#include "conf/conf.h"
|
||||
#include "sysdep/unix/krt.h"
|
||||
|
||||
static pool *if_pool;
|
||||
|
||||
list iface_list;
|
||||
|
||||
static void if_recalc_preferred(struct iface *i);
|
||||
|
||||
/**
|
||||
* ifa_dump - dump interface address
|
||||
* @a: interface address descriptor
|
||||
@ -46,10 +49,11 @@ list iface_list;
|
||||
void
|
||||
ifa_dump(struct ifa *a)
|
||||
{
|
||||
debug("\t%I, net %N bc %I -> %I%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
|
||||
(a->flags & IF_UP) ? "" : " DOWN",
|
||||
(a->flags & IA_PRIMARY) ? "" : " SEC",
|
||||
(a->flags & IA_PEER) ? "PEER" : "");
|
||||
debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
|
||||
(a->flags & IA_PRIMARY) ? " PRIMARY" : "",
|
||||
(a->flags & IA_SECONDARY) ? " SEC" : "",
|
||||
(a->flags & IA_HOST) ? " HOST" : "",
|
||||
(a->flags & IA_PEER) ? " PEER" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -116,7 +120,7 @@ if_what_changed(struct iface *i, struct iface *j)
|
||||
unsigned c;
|
||||
|
||||
if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
|
||||
|| i->index != j->index)
|
||||
|| (i->index != j->index) || (i->master != j->master))
|
||||
return IF_CHANGE_TOO_MUCH;
|
||||
c = 0;
|
||||
if ((i->flags ^ j->flags) & IF_UP)
|
||||
@ -133,17 +137,21 @@ if_copy(struct iface *to, struct iface *from)
|
||||
{
|
||||
to->flags = from->flags | (to->flags & IF_TMP_DOWN);
|
||||
to->mtu = from->mtu;
|
||||
to->master_index = from->master_index;
|
||||
to->master = from->master;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
|
||||
{
|
||||
if (p->ifa_notify && (p->proto_state != PS_DOWN))
|
||||
if (p->ifa_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == a->iface->master))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -174,7 +182,9 @@ ifa_notify_change(unsigned c, struct ifa *a)
|
||||
static inline void
|
||||
if_send_notify(struct proto *p, unsigned c, struct iface *i)
|
||||
{
|
||||
if (p->if_notify && (p->proto_state != PS_DOWN))
|
||||
if (p->if_notify &&
|
||||
(p->proto_state != PS_DOWN) &&
|
||||
(!p->vrf || p->vrf == i->master))
|
||||
{
|
||||
if (p->debug & D_IFACES)
|
||||
log(L_TRACE "%s < interface %s %s", p->name, i->name,
|
||||
@ -182,6 +192,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
|
||||
(c & IF_CHANGE_DOWN) ? "goes down" :
|
||||
(c & IF_CHANGE_MTU) ? "changes MTU" :
|
||||
(c & IF_CHANGE_LINK) ? "changes link" :
|
||||
(c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
|
||||
(c & IF_CHANGE_CREATE) ? "created" :
|
||||
"sends unknown event");
|
||||
p->if_notify(p, c, i);
|
||||
@ -210,10 +221,7 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
neigh_if_down(i);
|
||||
|
||||
WALK_LIST(a, i->addrs)
|
||||
{
|
||||
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
ifa_notify_change_(IF_CHANGE_DOWN, a);
|
||||
}
|
||||
ifa_notify_change_(IF_CHANGE_DOWN, a);
|
||||
|
||||
cli_notify_all_clients();
|
||||
}
|
||||
@ -224,10 +232,7 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
if (c & IF_CHANGE_UP)
|
||||
{
|
||||
WALK_LIST(a, i->addrs)
|
||||
{
|
||||
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
ifa_notify_change_(IF_CHANGE_UP, a);
|
||||
}
|
||||
ifa_notify_change_(IF_CHANGE_UP, a);
|
||||
|
||||
neigh_if_up(i);
|
||||
cli_notify_all_clients();
|
||||
@ -237,24 +242,25 @@ if_notify_change(unsigned c, struct iface *i)
|
||||
neigh_if_link(i);
|
||||
}
|
||||
|
||||
static unsigned
|
||||
if_recalc_flags(struct iface *i, unsigned flags)
|
||||
static uint
|
||||
if_recalc_flags(struct iface *i UNUSED, uint flags)
|
||||
{
|
||||
if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) ||
|
||||
!(flags & IF_ADMIN_UP) ||
|
||||
!i->addr)
|
||||
flags &= ~IF_UP;
|
||||
else
|
||||
if ((flags & IF_ADMIN_UP) &&
|
||||
!(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
|
||||
!(i->master_index && !i->master))
|
||||
flags |= IF_UP;
|
||||
else
|
||||
flags &= ~IF_UP;
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void
|
||||
if_change_flags(struct iface *i, unsigned flags)
|
||||
if_change_flags(struct iface *i, uint flags)
|
||||
{
|
||||
unsigned of = i->flags;
|
||||
|
||||
uint of = i->flags;
|
||||
i->flags = if_recalc_flags(i, flags);
|
||||
|
||||
if ((i->flags ^ of) & IF_UP)
|
||||
if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
|
||||
}
|
||||
@ -302,7 +308,6 @@ if_update(struct iface *new)
|
||||
WALK_LIST(i, iface_list)
|
||||
if (!strcmp(new->name, i->name))
|
||||
{
|
||||
new->addr = i->addr;
|
||||
new->flags = if_recalc_flags(new, new->flags);
|
||||
c = if_what_changed(i, new);
|
||||
if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */
|
||||
@ -310,10 +315,13 @@ if_update(struct iface *new)
|
||||
DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
rem_node(&i->n);
|
||||
new->addr = i->addr;
|
||||
new->addr4 = i->addr4;
|
||||
new->addr6 = i->addr6;
|
||||
new->llv6 = i->llv6;
|
||||
new->sysdep = i->sysdep;
|
||||
memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
|
||||
memcpy(i, new, sizeof(*i));
|
||||
i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
|
||||
i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
|
||||
goto newif;
|
||||
}
|
||||
|
||||
@ -344,13 +352,16 @@ if_start_update(void)
|
||||
{
|
||||
i->flags &= ~IF_UPDATED;
|
||||
WALK_LIST(a, i->addrs)
|
||||
a->flags &= ~IF_UPDATED;
|
||||
a->flags &= ~IA_UPDATED;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
if_end_partial_update(struct iface *i)
|
||||
{
|
||||
if (i->flags & IF_NEEDS_RECALC)
|
||||
if_recalc_preferred(i);
|
||||
|
||||
if (i->flags & IF_TMP_DOWN)
|
||||
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
|
||||
}
|
||||
@ -368,7 +379,7 @@ if_end_update(void)
|
||||
else
|
||||
{
|
||||
WALK_LIST_DELSAFE(a, b, i->addrs)
|
||||
if (!(a->flags & IF_UPDATED))
|
||||
if (!(a->flags & IA_UPDATED))
|
||||
ifa_delete(a);
|
||||
if_end_partial_update(i);
|
||||
}
|
||||
@ -465,40 +476,99 @@ if_get_by_name(char *name)
|
||||
return i;
|
||||
}
|
||||
|
||||
struct ifa *kif_choose_primary(struct iface *i);
|
||||
|
||||
static int
|
||||
ifa_recalc_primary(struct iface *i)
|
||||
static inline void
|
||||
if_set_preferred(struct ifa **pos, struct ifa *new)
|
||||
{
|
||||
struct ifa *a = kif_choose_primary(i);
|
||||
if (*pos)
|
||||
(*pos)->flags &= ~IA_PRIMARY;
|
||||
if (new)
|
||||
new->flags |= IA_PRIMARY;
|
||||
|
||||
if (a == i->addr)
|
||||
return 0;
|
||||
*pos = new;
|
||||
}
|
||||
|
||||
if (i->addr)
|
||||
i->addr->flags &= ~IA_PRIMARY;
|
||||
static void
|
||||
if_recalc_preferred(struct iface *i)
|
||||
{
|
||||
/*
|
||||
* Preferred address selection priority:
|
||||
* 1) Address configured in Device protocol
|
||||
* 2) Sysdep IPv4 address (BSD)
|
||||
* 3) Old preferred address
|
||||
* 4) First address in list
|
||||
*/
|
||||
|
||||
if (a)
|
||||
struct kif_iface_config *ic = kif_get_iface_config(i);
|
||||
struct ifa *a4 = i->addr4, *a6 = i->addr6, *ll = i->llv6;
|
||||
ip_addr pref_v4 = ic->pref_v4;
|
||||
uint change = 0;
|
||||
|
||||
if (kif_update_sysdep_addr(i))
|
||||
change |= IF_CHANGE_SYSDEP;
|
||||
|
||||
/* BSD sysdep address */
|
||||
if (ipa_zero(pref_v4) && ip4_nonzero(i->sysdep))
|
||||
pref_v4 = ipa_from_ip4(i->sysdep);
|
||||
|
||||
struct ifa *a;
|
||||
WALK_LIST(a, i->addrs)
|
||||
{
|
||||
a->flags |= IA_PRIMARY;
|
||||
rem_node(&a->n);
|
||||
add_head(&i->addrs, &a->n);
|
||||
/* Secondary address is never selected */
|
||||
if (a->flags & IA_SECONDARY)
|
||||
continue;
|
||||
|
||||
if (ipa_is_ip4(a->ip)) {
|
||||
if (!a4 || ipa_equal(a->ip, pref_v4))
|
||||
a4 = a;
|
||||
} else if (!ipa_is_link_local(a->ip)) {
|
||||
if (!a6 || ipa_equal(a->ip, ic->pref_v6))
|
||||
a6 = a;
|
||||
} else {
|
||||
if (!ll || ipa_equal(a->ip, ic->pref_ll))
|
||||
ll = a;
|
||||
}
|
||||
}
|
||||
|
||||
i->addr = a;
|
||||
return 1;
|
||||
if (a4 != i->addr4)
|
||||
{
|
||||
if_set_preferred(&i->addr4, a4);
|
||||
change |= IF_CHANGE_ADDR4;
|
||||
}
|
||||
|
||||
if (a6 != i->addr6)
|
||||
{
|
||||
if_set_preferred(&i->addr6, a6);
|
||||
change |= IF_CHANGE_ADDR6;
|
||||
}
|
||||
|
||||
if (ll != i->llv6)
|
||||
{
|
||||
if_set_preferred(&i->llv6, ll);
|
||||
change |= IF_CHANGE_LLV6;
|
||||
}
|
||||
|
||||
i->flags &= ~IF_NEEDS_RECALC;
|
||||
|
||||
/*
|
||||
* FIXME: There should be proper notification instead of iface restart:
|
||||
* if_notify_change(change, i)
|
||||
*/
|
||||
if (change)
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
}
|
||||
|
||||
void
|
||||
ifa_recalc_all_primary_addresses(void)
|
||||
if_recalc_all_preferred_addresses(void)
|
||||
{
|
||||
struct iface *i;
|
||||
|
||||
WALK_LIST(i, iface_list)
|
||||
{
|
||||
if (ifa_recalc_primary(i))
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
}
|
||||
{
|
||||
if_recalc_preferred(i);
|
||||
|
||||
if (i->flags & IF_TMP_DOWN)
|
||||
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -530,7 +600,7 @@ ifa_update(struct ifa *a)
|
||||
b->scope == a->scope &&
|
||||
!((b->flags ^ a->flags) & IA_PEER))
|
||||
{
|
||||
b->flags |= IF_UPDATED;
|
||||
b->flags |= IA_UPDATED;
|
||||
return b;
|
||||
}
|
||||
ifa_delete(b);
|
||||
@ -538,15 +608,15 @@ ifa_update(struct ifa *a)
|
||||
}
|
||||
|
||||
if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd))
|
||||
log(L_ERR "Missing broadcast address for interface %s", i->name);
|
||||
log(L_WARN "Missing broadcast address for interface %s", i->name);
|
||||
|
||||
b = mb_alloc(if_pool, sizeof(struct ifa));
|
||||
memcpy(b, a, sizeof(struct ifa));
|
||||
add_tail(&i->addrs, &b->n);
|
||||
b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
|
||||
if (ifa_recalc_primary(i))
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
if (b->flags & IF_UP)
|
||||
b->flags |= IA_UPDATED;
|
||||
|
||||
i->flags |= IF_NEEDS_RECALC;
|
||||
if (i->flags & IF_UP)
|
||||
ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
|
||||
return b;
|
||||
}
|
||||
@ -569,16 +639,24 @@ ifa_delete(struct ifa *a)
|
||||
if (ifa_same(b, a))
|
||||
{
|
||||
rem_node(&b->n);
|
||||
if (b->flags & IF_UP)
|
||||
{
|
||||
b->flags &= ~IF_UP;
|
||||
ifa_notify_change(IF_CHANGE_DOWN, b);
|
||||
}
|
||||
|
||||
if (b->flags & IA_PRIMARY)
|
||||
{
|
||||
if_change_flags(i, i->flags | IF_TMP_DOWN);
|
||||
ifa_recalc_primary(i);
|
||||
/*
|
||||
* We unlink deleted preferred address and mark for recalculation.
|
||||
* FIXME: This could break if we make iface scan non-atomic, as
|
||||
* protocols still could use the freed address until they get
|
||||
* if_notify from preferred route recalculation.
|
||||
*/
|
||||
if (b == i->addr4) i->addr4 = NULL;
|
||||
if (b == i->addr6) i->addr6 = NULL;
|
||||
if (b == i->llv6) i->llv6 = NULL;
|
||||
i->flags |= IF_NEEDS_RECALC;
|
||||
}
|
||||
|
||||
if (i->flags & IF_UP)
|
||||
ifa_notify_change(IF_CHANGE_DOWN, b);
|
||||
|
||||
mb_free(b);
|
||||
return;
|
||||
}
|
||||
@ -745,16 +823,17 @@ iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct ifac
|
||||
static void
|
||||
if_show_addr(struct ifa *a)
|
||||
{
|
||||
byte opp[IPA_MAX_TEXT_LENGTH + 16];
|
||||
byte *flg, opp[IPA_MAX_TEXT_LENGTH + 16];
|
||||
|
||||
flg = (a->flags & IA_PRIMARY) ? "Preferred, " : (a->flags & IA_SECONDARY) ? "Secondary, " : "";
|
||||
|
||||
if (ipa_nonzero(a->opposite))
|
||||
bsprintf(opp, ", opposite %I", a->opposite);
|
||||
bsprintf(opp, "opposite %I, ", a->opposite);
|
||||
else
|
||||
opp[0] = 0;
|
||||
cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
|
||||
a->ip, a->prefix.pxlen,
|
||||
(a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected",
|
||||
opp, ip_scope_text(a->scope));
|
||||
|
||||
cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
|
||||
a->ip, a->prefix.pxlen, flg, opp, ip_scope_text(a->scope));
|
||||
}
|
||||
|
||||
void
|
||||
@ -769,7 +848,13 @@ if_show(void)
|
||||
if (i->flags & IF_SHUTDOWN)
|
||||
continue;
|
||||
|
||||
cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
|
||||
char mbuf[16 + sizeof(i->name)] = {};
|
||||
if (i->master)
|
||||
bsprintf(mbuf, " master=%s", i->master->name);
|
||||
else if (i->master_index)
|
||||
bsprintf(mbuf, " master=#%u", i->master_index);
|
||||
|
||||
cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "up" : "down", i->index, mbuf);
|
||||
if (!(i->flags & IF_MULTIACCESS))
|
||||
type = "PtP";
|
||||
else
|
||||
@ -783,10 +868,13 @@ if_show(void)
|
||||
(i->flags & IF_LOOPBACK) ? " Loopback" : "",
|
||||
(i->flags & IF_IGNORE) ? " Ignored" : "",
|
||||
i->mtu);
|
||||
if (i->addr)
|
||||
if_show_addr(i->addr);
|
||||
|
||||
WALK_LIST(a, i->addrs)
|
||||
if (a != i->addr)
|
||||
if (a->prefix.type == NET_IP4)
|
||||
if_show_addr(a);
|
||||
|
||||
WALK_LIST(a, i->addrs)
|
||||
if (a->prefix.type == NET_IP6)
|
||||
if_show_addr(a);
|
||||
}
|
||||
cli_msg(0, "");
|
||||
@ -796,16 +884,25 @@ void
|
||||
if_show_summary(void)
|
||||
{
|
||||
struct iface *i;
|
||||
byte addr[IPA_MAX_TEXT_LENGTH + 16];
|
||||
|
||||
cli_msg(-2005, "interface state address");
|
||||
cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
|
||||
WALK_LIST(i, iface_list)
|
||||
{
|
||||
if (i->addr)
|
||||
bsprintf(addr, "%I/%d", i->addr->ip, i->addr->prefix.pxlen);
|
||||
byte a4[IPA_MAX_TEXT_LENGTH + 17];
|
||||
byte a6[IPA_MAX_TEXT_LENGTH + 17];
|
||||
|
||||
if (i->addr4)
|
||||
bsprintf(a4, "%I/%d", i->addr4->ip, i->addr4->prefix.pxlen);
|
||||
else
|
||||
addr[0] = 0;
|
||||
cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
|
||||
a4[0] = 0;
|
||||
|
||||
if (i->addr6)
|
||||
bsprintf(a6, "%I/%d", i->addr6->ip, i->addr6->prefix.pxlen);
|
||||
else
|
||||
a6[0] = 0;
|
||||
|
||||
cli_msg(-1005, "%-10s %-6s %-18s %s",
|
||||
i->name, (i->flags & IF_UP) ? "up" : "down", a4, a6);
|
||||
}
|
||||
cli_msg(0, "");
|
||||
}
|
||||
|
22
nest/iface.h
22
nest/iface.h
@ -34,12 +34,17 @@ struct iface {
|
||||
unsigned flags;
|
||||
unsigned mtu;
|
||||
unsigned index; /* OS-dependent interface index */
|
||||
unsigned master_index; /* Interface index of master iface */
|
||||
struct iface *master; /* Master iface (e.g. for VRF) */
|
||||
list addrs; /* Addresses assigned to this interface */
|
||||
struct ifa *addr; /* Primary address */
|
||||
struct ifa *addr4; /* Primary address for IPv4 */
|
||||
struct ifa *addr6; /* Primary address for IPv6 */
|
||||
struct ifa *llv6; /* Primary link-local address for IPv6 */
|
||||
ip4_addr sysdep; /* Arbitrary IPv4 address for internal sysdep use */
|
||||
list neighbors; /* All neighbors on this interface */
|
||||
};
|
||||
|
||||
#define IF_UP 1 /* IF_ADMIN_UP and IP address known */
|
||||
#define IF_UP 1 /* Currently just IF_ADMIN_UP */
|
||||
#define IF_MULTIACCESS 2
|
||||
#define IF_BROADCAST 4
|
||||
#define IF_MULTICAST 8
|
||||
@ -70,7 +75,10 @@ struct iface {
|
||||
|
||||
#define IF_JUST_CREATED 0x10000000 /* Send creation event as soon as possible */
|
||||
#define IF_TMP_DOWN 0x20000000 /* Temporary shutdown due to interface reconfiguration */
|
||||
#define IF_UPDATED 0x40000000 /* Touched in last scan */
|
||||
#define IF_UPDATED 0x40000000 /* Iface touched in last scan */
|
||||
#define IF_NEEDS_RECALC 0x80000000 /* Preferred address recalculation is needed */
|
||||
|
||||
#define IA_UPDATED IF_UPDATED /* Address touched in last scan */
|
||||
|
||||
/* Interface change events */
|
||||
|
||||
@ -79,8 +87,14 @@ struct iface {
|
||||
#define IF_CHANGE_MTU 4
|
||||
#define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */
|
||||
#define IF_CHANGE_LINK 0x10
|
||||
#define IF_CHANGE_ADDR4 0x100 /* Change of iface->addr4 */
|
||||
#define IF_CHANGE_ADDR6 0x200 /* ... */
|
||||
#define IF_CHANGE_LLV6 0x400
|
||||
#define IF_CHANGE_SYSDEP 0x800
|
||||
#define IF_CHANGE_TOO_MUCH 0x40000000 /* Used internally */
|
||||
|
||||
#define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
|
||||
|
||||
void if_init(void);
|
||||
void if_dump(struct iface *);
|
||||
void if_dump_all(void);
|
||||
@ -99,7 +113,7 @@ void if_feed_baby(struct proto *);
|
||||
struct iface *if_find_by_index(unsigned);
|
||||
struct iface *if_find_by_name(char *);
|
||||
struct iface *if_get_by_name(char *);
|
||||
void ifa_recalc_all_primary_addresses(void);
|
||||
void if_recalc_all_preferred_addresses(void);
|
||||
|
||||
|
||||
/* The Neighbor Cache */
|
||||
|
@ -45,6 +45,7 @@ olock_same(struct object_lock *x, struct object_lock *y)
|
||||
return
|
||||
x->type == y->type &&
|
||||
x->iface == y->iface &&
|
||||
x->vrf == y->vrf &&
|
||||
x->port == y->port &&
|
||||
x->inst == y->inst &&
|
||||
ipa_equal(x->addr, y->addr);
|
||||
|
@ -30,6 +30,7 @@ struct object_lock {
|
||||
uint port; /* ... port number */
|
||||
uint inst; /* ... instance ID */
|
||||
struct iface *iface; /* ... interface */
|
||||
struct iface *vrf; /* ... or VRF (if iface is unknown) */
|
||||
void (*hook)(struct object_lock *); /* Called when the lock succeeds */
|
||||
void *data; /* User data */
|
||||
/* ... internal to lock manager, don't touch ... */
|
||||
|
@ -30,7 +30,8 @@
|
||||
* when the protocol has explicitly requested it via the %NEF_STICKY
|
||||
* flag because it wishes to be notified when the node will again become
|
||||
* a neighbor. Such entries are enqueued in a special list which is walked
|
||||
* whenever an interface changes its state to up.
|
||||
* whenever an interface changes its state to up. Neighbor entry VRF
|
||||
* association is implied by respective protocol.
|
||||
*
|
||||
* When a neighbor event occurs (a neighbor gets disconnected or a sticky
|
||||
* inactive neighbor becomes connected), the protocol hook neigh_notify()
|
||||
@ -153,8 +154,9 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
|
||||
}
|
||||
else
|
||||
WALK_LIST(i, iface_list)
|
||||
if ((scope = if_connected(a, i, &addr)) >= 0)
|
||||
{
|
||||
if ((!p->vrf || p->vrf == i->master) &&
|
||||
((scope = if_connected(a, i, &addr)) >= 0))
|
||||
{
|
||||
ifa = i;
|
||||
break;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "nest/bird.h"
|
||||
#include "nest/password.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/mac.h"
|
||||
|
||||
struct password_item *last_password_item = NULL;
|
||||
@ -19,12 +20,13 @@ password_find(list *l, int first_fit)
|
||||
{
|
||||
struct password_item *pi;
|
||||
struct password_item *pf = NULL;
|
||||
btime now_ = current_real_time();
|
||||
|
||||
if (l)
|
||||
{
|
||||
WALK_LIST(pi, *l)
|
||||
{
|
||||
if ((pi->genfrom < now_real) && (pi->gento > now_real))
|
||||
if ((pi->genfrom < now_) && (pi->gento > now_))
|
||||
{
|
||||
if (first_fit)
|
||||
return pi;
|
||||
@ -41,12 +43,13 @@ struct password_item *
|
||||
password_find_by_id(list *l, uint id)
|
||||
{
|
||||
struct password_item *pi;
|
||||
btime now_ = current_real_time();
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
WALK_LIST(pi, *l)
|
||||
if ((pi->id == id) && (pi->accfrom <= now_real) && (now_real < pi->accto))
|
||||
if ((pi->id == id) && (pi->accfrom <= now_) && (now_ < pi->accto))
|
||||
return pi;
|
||||
|
||||
return NULL;
|
||||
@ -56,12 +59,13 @@ struct password_item *
|
||||
password_find_by_value(list *l, char *pass, uint size)
|
||||
{
|
||||
struct password_item *pi;
|
||||
btime now_ = current_real_time();
|
||||
|
||||
if (!l)
|
||||
return NULL;
|
||||
|
||||
WALK_LIST(pi, *l)
|
||||
if (password_verify(pi, pass, size) && (pi->accfrom <= now_real) && (now_real < pi->accto))
|
||||
if (password_verify(pi, pass, size) && (pi->accfrom <= now_) && (now_ < pi->accto))
|
||||
return pi;
|
||||
|
||||
return NULL;
|
||||
|
@ -10,15 +10,13 @@
|
||||
#ifndef PASSWORD_H
|
||||
#define PASSWORD_H
|
||||
|
||||
#include "sysdep/unix/timer.h"
|
||||
|
||||
struct password_item {
|
||||
node n;
|
||||
char *password; /* Key data, null terminated */
|
||||
uint length; /* Key length, without null */
|
||||
uint id; /* Key ID */
|
||||
uint alg; /* MAC algorithm */
|
||||
bird_clock_t accfrom, accto, genfrom, gento;
|
||||
btime accfrom, accto, genfrom, gento;
|
||||
};
|
||||
|
||||
extern struct password_item *last_password_item;
|
||||
|
100
nest/proto.c
100
nest/proto.c
@ -13,6 +13,7 @@
|
||||
#include "lib/resource.h"
|
||||
#include "lib/lists.h"
|
||||
#include "lib/event.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/string.h"
|
||||
#include "conf/conf.h"
|
||||
#include "nest/route.h"
|
||||
@ -43,7 +44,7 @@ static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" };
|
||||
|
||||
extern struct protocol proto_unix_iface;
|
||||
|
||||
static void proto_shutdown_loop(struct timer *);
|
||||
static void proto_shutdown_loop(timer *);
|
||||
static void proto_rethink_goal(struct proto *p);
|
||||
static char *proto_state_name(struct proto *p);
|
||||
static void channel_verify_limits(struct channel *c);
|
||||
@ -162,7 +163,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
|
||||
|
||||
c->channel_state = CS_DOWN;
|
||||
c->export_state = ES_DOWN;
|
||||
c->last_state_change = now;
|
||||
c->last_state_change = current_time();
|
||||
c->reloadable = 1;
|
||||
|
||||
CALL(c->channel->init, c, cf);
|
||||
@ -341,7 +342,7 @@ channel_set_state(struct channel *c, uint state)
|
||||
return;
|
||||
|
||||
c->channel_state = state;
|
||||
c->last_state_change = now;
|
||||
c->last_state_change = current_time();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
@ -672,7 +673,8 @@ proto_init(struct proto_config *c, node *n)
|
||||
struct proto *p = pr->init(c);
|
||||
|
||||
p->proto_state = PS_DOWN;
|
||||
p->last_state_change = now;
|
||||
p->last_state_change = current_time();
|
||||
p->vrf = c->vrf;
|
||||
insert_node(&p->n, n);
|
||||
|
||||
p->event = ev_new(proto_pool);
|
||||
@ -819,7 +821,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
|
||||
/* If there is a too big change in core attributes, ... */
|
||||
if ((nc->protocol != oc->protocol) ||
|
||||
(nc->net_type != oc->net_type) ||
|
||||
(nc->disabled != p->disabled))
|
||||
(nc->disabled != p->disabled) ||
|
||||
(nc->vrf != oc->vrf))
|
||||
return 0;
|
||||
|
||||
p->name = nc->name;
|
||||
@ -977,6 +980,7 @@ proto_rethink_goal(struct proto *p)
|
||||
proto_remove_channels(p);
|
||||
rem_node(&p->n);
|
||||
rfree(p->event);
|
||||
mb_free(p->message);
|
||||
mb_free(p);
|
||||
if (!nc)
|
||||
return;
|
||||
@ -1046,7 +1050,7 @@ proto_rethink_goal(struct proto *p)
|
||||
*
|
||||
*/
|
||||
|
||||
static void graceful_restart_done(struct timer *t);
|
||||
static void graceful_restart_done(timer *t);
|
||||
|
||||
/**
|
||||
* graceful_restart_recovery - request initial graceful restart recovery
|
||||
@ -1083,9 +1087,8 @@ graceful_restart_init(void)
|
||||
}
|
||||
|
||||
graceful_restart_state = GRS_ACTIVE;
|
||||
gr_wait_timer = tm_new(proto_pool);
|
||||
gr_wait_timer->hook = graceful_restart_done;
|
||||
tm_start(gr_wait_timer, config->gr_wait);
|
||||
gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0);
|
||||
tm_start(gr_wait_timer, config->gr_wait S);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1099,7 +1102,7 @@ graceful_restart_init(void)
|
||||
* restart wait timer fires (but there are still some locks).
|
||||
*/
|
||||
static void
|
||||
graceful_restart_done(struct timer *t UNUSED)
|
||||
graceful_restart_done(timer *t UNUSED)
|
||||
{
|
||||
log(L_INFO "Graceful restart done");
|
||||
graceful_restart_state = GRS_DONE;
|
||||
@ -1136,7 +1139,7 @@ graceful_restart_show_status(void)
|
||||
|
||||
cli_msg(-24, "Graceful restart recovery in progress");
|
||||
cli_msg(-24, " Waiting for %d channels to recover", graceful_restart_locks);
|
||||
cli_msg(-24, " Wait timer is %d/%d", tm_remains(gr_wait_timer), config->gr_wait);
|
||||
cli_msg(-24, " Wait timer is %t/%u", tm_remains(gr_wait_timer), config->gr_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1298,7 +1301,7 @@ protos_build(void)
|
||||
int proto_restart;
|
||||
|
||||
static void
|
||||
proto_shutdown_loop(struct timer *t UNUSED)
|
||||
proto_shutdown_loop(timer *t UNUSED)
|
||||
{
|
||||
struct proto *p, *p_next;
|
||||
|
||||
@ -1329,7 +1332,40 @@ proto_schedule_down(struct proto *p, byte restart, byte code)
|
||||
|
||||
p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
|
||||
p->down_code = code;
|
||||
tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
|
||||
tm_start_max(proto_shutdown_timer, restart ? 250 MS : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* proto_set_message - set administrative message to protocol
|
||||
* @p: protocol
|
||||
* @msg: message
|
||||
* @len: message length (-1 for NULL-terminated string)
|
||||
*
|
||||
* The function sets administrative message (string) related to protocol state
|
||||
* change. It is called by the nest code for manual enable/disable/restart
|
||||
* commands all routes to the protocol, and by protocol-specific code when the
|
||||
* protocol state change is initiated by the protocol. Using NULL message clears
|
||||
* the last message. The message string may be either NULL-terminated or with an
|
||||
* explicit length.
|
||||
*/
|
||||
void
|
||||
proto_set_message(struct proto *p, char *msg, int len)
|
||||
{
|
||||
mb_free(p->message);
|
||||
p->message = NULL;
|
||||
|
||||
if (!msg || !len)
|
||||
return;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(msg);
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
p->message = mb_alloc(proto_pool, len + 1);
|
||||
memcpy(p->message, msg, len);
|
||||
p->message[len] = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1500,7 +1536,7 @@ proto_notify_state(struct proto *p, uint state)
|
||||
return;
|
||||
|
||||
p->proto_state = state;
|
||||
p->last_state_change = now;
|
||||
p->last_state_change = current_time();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
@ -1620,19 +1656,20 @@ channel_show_info(struct channel *c)
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_show(struct proto *p, uint verbose, int cnt)
|
||||
proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
|
||||
{
|
||||
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||
|
||||
/* First protocol - show header */
|
||||
if (!cnt)
|
||||
cli_msg(-2002, "name proto table state since info");
|
||||
cli_msg(-2002, "%-10s %-10s %-10s %-6s %-12s %s",
|
||||
"Name", "Proto", "Table", "State", "Since", "Info");
|
||||
|
||||
buf[0] = 0;
|
||||
if (p->proto->get_status)
|
||||
p->proto->get_status(p, buf);
|
||||
tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
|
||||
cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
|
||||
tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
|
||||
cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
|
||||
p->name,
|
||||
p->proto->name,
|
||||
p->main_channel ? p->main_channel->table->name : "---",
|
||||
@ -1644,8 +1681,12 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
|
||||
{
|
||||
if (p->cf->dsc)
|
||||
cli_msg(-1006, " Description: %s", p->cf->dsc);
|
||||
if (p->message)
|
||||
cli_msg(-1006, " Message: %s", p->message);
|
||||
if (p->cf->router_id)
|
||||
cli_msg(-1006, " Router ID: %R", p->cf->router_id);
|
||||
if (p->vrf)
|
||||
cli_msg(-1006, " VRF: %s", p->vrf->name);
|
||||
|
||||
if (p->proto->show_proto_info)
|
||||
p->proto->show_proto_info(p);
|
||||
@ -1661,7 +1702,7 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
proto_cmd_disable(struct proto *p, uintptr_t arg, int cnt UNUSED)
|
||||
{
|
||||
if (p->disabled)
|
||||
{
|
||||
@ -1672,12 +1713,13 @@ proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
log(L_INFO "Disabling protocol %s", p->name);
|
||||
p->disabled = 1;
|
||||
p->down_code = PDC_CMD_DISABLE;
|
||||
proto_set_message(p, (char *) arg, -1);
|
||||
proto_rethink_goal(p);
|
||||
cli_msg(-9, "%s: disabled", p->name);
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
proto_cmd_enable(struct proto *p, uintptr_t arg, int cnt UNUSED)
|
||||
{
|
||||
if (!p->disabled)
|
||||
{
|
||||
@ -1687,12 +1729,13 @@ proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
|
||||
log(L_INFO "Enabling protocol %s", p->name);
|
||||
p->disabled = 0;
|
||||
proto_set_message(p, (char *) arg, -1);
|
||||
proto_rethink_goal(p);
|
||||
cli_msg(-11, "%s: enabled", p->name);
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
proto_cmd_restart(struct proto *p, uintptr_t arg, int cnt UNUSED)
|
||||
{
|
||||
if (p->disabled)
|
||||
{
|
||||
@ -1703,6 +1746,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
log(L_INFO "Restarting protocol %s", p->name);
|
||||
p->disabled = 1;
|
||||
p->down_code = PDC_CMD_RESTART;
|
||||
proto_set_message(p, (char *) arg, -1);
|
||||
proto_rethink_goal(p);
|
||||
p->disabled = 0;
|
||||
proto_rethink_goal(p);
|
||||
@ -1710,7 +1754,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
|
||||
proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
|
||||
{
|
||||
struct channel *c;
|
||||
|
||||
@ -1749,19 +1793,19 @@ proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_debug(struct proto *p, uint mask, int cnt UNUSED)
|
||||
proto_cmd_debug(struct proto *p, uintptr_t mask, int cnt UNUSED)
|
||||
{
|
||||
p->debug = mask;
|
||||
}
|
||||
|
||||
void
|
||||
proto_cmd_mrtdump(struct proto *p, uint mask, int cnt UNUSED)
|
||||
proto_cmd_mrtdump(struct proto *p, uintptr_t mask, int cnt UNUSED)
|
||||
{
|
||||
p->mrtdump = mask;
|
||||
}
|
||||
|
||||
static void
|
||||
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int), uint arg)
|
||||
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
|
||||
{
|
||||
if (s->class != SYM_PROTO)
|
||||
{
|
||||
@ -1774,7 +1818,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int)
|
||||
}
|
||||
|
||||
static void
|
||||
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint arg)
|
||||
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
|
||||
{
|
||||
struct proto *p;
|
||||
int cnt = 0;
|
||||
@ -1790,8 +1834,8 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint a
|
||||
}
|
||||
|
||||
void
|
||||
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int),
|
||||
int restricted, uint arg)
|
||||
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int),
|
||||
int restricted, uintptr_t arg)
|
||||
{
|
||||
if (restricted && cli_access_restricted())
|
||||
return;
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/event.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "nest/route.h"
|
||||
#include "conf/conf.h"
|
||||
|
||||
@ -101,6 +100,7 @@ struct proto_config {
|
||||
u32 router_id; /* Protocol specific router ID */
|
||||
|
||||
list channels; /* List of channel configs (struct channel_config) */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
|
||||
|
||||
@ -143,6 +143,7 @@ struct proto {
|
||||
list channels; /* List of channels to rtables (struct channel) */
|
||||
struct channel *main_channel; /* Primary channel */
|
||||
struct rte_src *main_source; /* Primary route source */
|
||||
struct iface *vrf; /* Related VRF instance, NULL if global */
|
||||
|
||||
char *name; /* Name of this instance (== cf->name) */
|
||||
u32 debug; /* Debugging flags */
|
||||
@ -159,8 +160,9 @@ struct proto {
|
||||
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
|
||||
byte down_code; /* Reason for shutdown (PDC_* codes) */
|
||||
u32 hash_key; /* Random key used for hashing of neighbors */
|
||||
bird_clock_t last_state_change; /* Time of last state transition */
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
char *last_state_name_announced; /* Last state name we've announced to the user */
|
||||
char *message; /* State-change message, allocated from proto_pool */
|
||||
|
||||
/*
|
||||
* General protocol hooks:
|
||||
@ -237,6 +239,7 @@ struct proto_spec {
|
||||
void *proto_new(struct proto_config *);
|
||||
void *proto_config_new(struct protocol *, int class);
|
||||
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
|
||||
void proto_set_message(struct proto *p, char *msg, int len);
|
||||
|
||||
void graceful_restart_recovery(void);
|
||||
void graceful_restart_init(void);
|
||||
@ -249,15 +252,15 @@ void channel_graceful_restart_unlock(struct channel *c);
|
||||
void channel_show_limit(struct channel_limit *l, const char *dsc);
|
||||
void channel_show_info(struct channel *c);
|
||||
|
||||
void proto_cmd_show(struct proto *, uint, int);
|
||||
void proto_cmd_disable(struct proto *, uint, int);
|
||||
void proto_cmd_enable(struct proto *, uint, int);
|
||||
void proto_cmd_restart(struct proto *, uint, int);
|
||||
void proto_cmd_reload(struct proto *, uint, int);
|
||||
void proto_cmd_debug(struct proto *, uint, int);
|
||||
void proto_cmd_mrtdump(struct proto *, uint, int);
|
||||
void proto_cmd_show(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_disable(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_enable(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_restart(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_reload(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_debug(struct proto *, uintptr_t, int);
|
||||
void proto_cmd_mrtdump(struct proto *, uintptr_t, int);
|
||||
|
||||
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int), int restricted, uint arg);
|
||||
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg);
|
||||
struct proto *proto_get_named(struct symbol *, struct protocol *);
|
||||
|
||||
#define CMD_RELOAD 0
|
||||
@ -508,7 +511,7 @@ struct channel {
|
||||
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
|
||||
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
|
||||
|
||||
bird_clock_t last_state_change; /* Time of last state transition */
|
||||
btime last_state_change; /* Time of last state transition */
|
||||
};
|
||||
|
||||
|
||||
|
11
nest/route.h
11
nest/route.h
@ -11,7 +11,6 @@
|
||||
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/net.h"
|
||||
|
||||
struct ea_list;
|
||||
@ -159,8 +158,8 @@ typedef struct rtable {
|
||||
* obstacle from this routing table.
|
||||
*/
|
||||
struct event *rt_event; /* Routing table event */
|
||||
btime gc_time; /* Time of last GC */
|
||||
int gc_counter; /* Number of operations since last GC */
|
||||
bird_clock_t gc_time; /* Time of last GC */
|
||||
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
|
||||
byte hcu_scheduled; /* Hostcache update is scheduled */
|
||||
byte nhu_state; /* Next Hop Update state */
|
||||
@ -213,7 +212,7 @@ typedef struct rte {
|
||||
byte flags; /* Flags (REF_...) */
|
||||
byte pflags; /* Protocol-specific flags */
|
||||
word pref; /* Route preference */
|
||||
bird_clock_t lastmod; /* Last modified */
|
||||
btime lastmod; /* Last modified */
|
||||
union { /* Protocol-dependent data (metrics etc.) */
|
||||
#ifdef CONFIG_RIP
|
||||
struct {
|
||||
@ -236,6 +235,7 @@ typedef struct rte {
|
||||
#endif
|
||||
#ifdef CONFIG_BABEL
|
||||
struct {
|
||||
u16 seqno; /* Babel seqno */
|
||||
u16 metric; /* Babel metric */
|
||||
u64 router_id; /* Babel router id */
|
||||
} babel;
|
||||
@ -309,6 +309,8 @@ int rt_feed_channel(struct channel *c);
|
||||
void rt_feed_channel_abort(struct channel *c);
|
||||
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
|
||||
|
||||
/* Default limit for ECMP next hops, defined in sysdep code */
|
||||
extern const int rt_default_ecmp;
|
||||
|
||||
struct rt_show_data_rtable {
|
||||
node n;
|
||||
@ -470,7 +472,8 @@ typedef struct eattr {
|
||||
#define EAP_OSPF 3 /* OSPF */
|
||||
#define EAP_KRT 4 /* Kernel route attributes */
|
||||
#define EAP_BABEL 5 /* Babel attributes */
|
||||
#define EAP_MAX 6
|
||||
#define EAP_RADV 6 /* Router advertisment attributes */
|
||||
#define EAP_MAX 7
|
||||
|
||||
#define EA_CODE(proto,id) (((proto) << 8) | (id))
|
||||
#define EA_PROTO(ea) ((ea) >> 8)
|
||||
|
@ -33,7 +33,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
|
||||
struct channel *c;
|
||||
|
||||
if (!EMPTY_LIST(cf->iface_list) &&
|
||||
!iface_patt_find(&cf->iface_list, ad->iface, ad->iface->addr))
|
||||
!iface_patt_find(&cf->iface_list, ad->iface, ad))
|
||||
/* Empty list is automatically treated as "*" */
|
||||
return;
|
||||
|
||||
|
@ -32,6 +32,24 @@
|
||||
* Basic FIB operations are performed by functions defined by this module,
|
||||
* enumerating of FIB contents is accomplished by using the FIB_WALK() macro
|
||||
* or FIB_ITERATE_START() if you want to do it asynchronously.
|
||||
*
|
||||
* For simple iteration just place the body of the loop between FIB_WALK() and
|
||||
* FIB_WALK_END(). You can't modify the FIB during the iteration (you can modify
|
||||
* data in the node, but not add or remove nodes).
|
||||
*
|
||||
* If you need more freedom, you can use the FIB_ITERATE_*() group of macros.
|
||||
* First, you initialize an iterator with FIB_ITERATE_INIT(). Then you can put
|
||||
* the loop body in between FIB_ITERATE_START() and FIB_ITERATE_END(). In
|
||||
* addition, the iteration can be suspended by calling FIB_ITERATE_PUT().
|
||||
* This'll link the iterator inside the FIB. While suspended, you may modify the
|
||||
* FIB, exit the current function, etc. To resume the iteration, enter the loop
|
||||
* again. You can use FIB_ITERATE_UNLINK() to unlink the iterator (while
|
||||
* iteration is suspended) in cases like premature end of FIB iteration.
|
||||
*
|
||||
* Note that the iterator must not be destroyed when the iteration is suspended,
|
||||
* the FIB would then contain a pointer to invalid memory. Therefore, after each
|
||||
* FIB_ITERATE_INIT() or FIB_ITERATE_PUT() there must be either
|
||||
* FIB_ITERATE_START() or FIB_ITERATE_UNLINK() before the iterator is destroyed.
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
@ -195,6 +213,7 @@ fib_hash(struct fib *f, const net_addr *a)
|
||||
case NET_ROA6: return FIB_HASH(f, a, roa6);
|
||||
case NET_FLOW4: return FIB_HASH(f, a, flow4);
|
||||
case NET_FLOW6: return FIB_HASH(f, a, flow6);
|
||||
case NET_MPLS: return FIB_HASH(f, a, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
}
|
||||
@ -231,6 +250,7 @@ fib_find(struct fib *f, const net_addr *a)
|
||||
case NET_ROA6: return FIB_FIND(f, a, roa6);
|
||||
case NET_FLOW4: return FIB_FIND(f, a, flow4);
|
||||
case NET_FLOW6: return FIB_FIND(f, a, flow6);
|
||||
case NET_MPLS: return FIB_FIND(f, a, mpls);
|
||||
default: bug("invalid type");
|
||||
}
|
||||
}
|
||||
@ -250,6 +270,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
|
||||
case NET_ROA6: FIB_INSERT(f, a, e, roa6); return;
|
||||
case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
|
||||
case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
|
||||
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
|
||||
default: bug("invalid type");
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
|
||||
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
|
||||
struct nexthop *nh;
|
||||
|
||||
tm_format_datetime(tm, &config->tf_route, e->lastmod);
|
||||
tm_format_time(tm, &config->tf_route, e->lastmod);
|
||||
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
|
||||
bsprintf(from, " from %I", a->from);
|
||||
else
|
||||
@ -63,7 +63,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
|
||||
if (d->last_table != d->tab)
|
||||
rt_show_table(c, d);
|
||||
|
||||
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
|
||||
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
|
||||
a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
|
||||
|
||||
if (a->dest == RTD_UNICAST)
|
||||
@ -71,6 +71,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
|
||||
{
|
||||
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
|
||||
char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
|
||||
char weight[16] = "";
|
||||
|
||||
if (nh->labels)
|
||||
{
|
||||
@ -81,11 +82,14 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
|
||||
*lsp = '\0';
|
||||
|
||||
if (a->nh.next)
|
||||
cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d",
|
||||
nh->gw, mpls, nh->iface->name, onlink, nh->weight + 1);
|
||||
bsprintf(weight, " weight %d", nh->weight + 1);
|
||||
|
||||
if (ipa_nonzero(nh->gw))
|
||||
cli_printf(c, -1007, "\tvia %I on %s%s%s%s",
|
||||
nh->gw, nh->iface->name, mpls, onlink, weight);
|
||||
else
|
||||
cli_printf(c, -1007, "\tvia %I%s on %s%s",
|
||||
nh->gw, mpls, nh->iface->name, onlink);
|
||||
cli_printf(c, -1007, "\tdev %s%s%s",
|
||||
nh->iface->name, mpls, onlink, weight);
|
||||
}
|
||||
|
||||
if (d->verbose)
|
||||
|
@ -897,7 +897,9 @@ rte_validate(rte *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
c = net_classify(n->n.addr);
|
||||
/* FIXME: better handling different nettypes */
|
||||
c = !net_is_flow(n->n.addr) ?
|
||||
net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE);
|
||||
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
|
||||
{
|
||||
log(L_WARN "Ignoring bogus route %N received via %s",
|
||||
@ -1173,7 +1175,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
||||
}
|
||||
|
||||
if (new)
|
||||
new->lastmod = now;
|
||||
new->lastmod = current_time();
|
||||
|
||||
/* Log the route change */
|
||||
if (p->debug & D_ROUTES)
|
||||
@ -1201,7 +1203,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
||||
|
||||
if (!net->routes &&
|
||||
(table->gc_counter++ >= table->config->gc_max_ops) &&
|
||||
(table->gc_time + table->config->gc_min_time <= now))
|
||||
(table->gc_time + table->config->gc_min_time <= current_time()))
|
||||
rt_schedule_prune(table);
|
||||
|
||||
if (old_ok && p->rte_remove)
|
||||
@ -1497,7 +1499,7 @@ rte_dump(rte *e)
|
||||
{
|
||||
net *n = e->net;
|
||||
debug("%-1N ", n->n.addr);
|
||||
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
|
||||
debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
|
||||
rta_dump(e->attrs);
|
||||
if (e->attrs->src->proto->proto->dump_attrs)
|
||||
e->attrs->src->proto->proto->dump_attrs(e);
|
||||
@ -1609,7 +1611,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
|
||||
t->rt_event = ev_new(p);
|
||||
t->rt_event->hook = rt_event;
|
||||
t->rt_event->data = t;
|
||||
t->gc_time = now;
|
||||
t->gc_time = current_time();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1708,7 +1710,7 @@ again:
|
||||
#endif
|
||||
|
||||
tab->gc_counter = 0;
|
||||
tab->gc_time = now;
|
||||
tab->gc_time = current_time();
|
||||
|
||||
/* state change 2->0, 3->1 */
|
||||
tab->prune_state &= 1;
|
||||
|
1319
proto/babel/babel.c
1319
proto/babel/babel.c
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,8 @@
|
||||
* BIRD -- The Babel protocol
|
||||
*
|
||||
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
|
||||
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2016--2017 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
@ -21,7 +23,7 @@
|
||||
#include "lib/lists.h"
|
||||
#include "lib/socket.h"
|
||||
#include "lib/string.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
#define EA_BABEL_METRIC EA_CODE(EAP_BABEL, 0)
|
||||
#define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1)
|
||||
@ -32,25 +34,28 @@
|
||||
#define BABEL_INFINITY 0xFFFF
|
||||
|
||||
|
||||
#define BABEL_HELLO_INTERVAL_WIRED 4 /* Default hello intervals in seconds */
|
||||
#define BABEL_HELLO_INTERVAL_WIRELESS 4
|
||||
#define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
|
||||
#define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
|
||||
#define BABEL_HELLO_LIMIT 12
|
||||
#define BABEL_UPDATE_INTERVAL_FACTOR 4
|
||||
#define BABEL_IHU_INTERVAL_FACTOR 3
|
||||
#define BABEL_IHU_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
|
||||
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
|
||||
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((X)*7/2) /* 3.5 */
|
||||
#define BABEL_ROUTE_REFRESH_INTERVAL 2 /* Seconds before route expiry to send route request */
|
||||
#define BABEL_HOLD_TIME 10 /* Expiry time for our own routes */
|
||||
#define BABEL_HOLD_TIME_FACTOR 4 /* How long we keep unreachable route relative to update interval */
|
||||
#define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
|
||||
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
|
||||
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
|
||||
#define BABEL_ROUTE_REFRESH_FACTOR(X) ((btime)(X)*5/2) /* 2.5 */
|
||||
#define BABEL_SEQNO_REQUEST_RETRY 4
|
||||
#define BABEL_SEQNO_REQUEST_EXPIRY (2 S_)
|
||||
#define BABEL_GARBAGE_INTERVAL (300 S_)
|
||||
#define BABEL_RXCOST_WIRED 96
|
||||
#define BABEL_RXCOST_WIRELESS 256
|
||||
#define BABEL_INITIAL_HOP_COUNT 255
|
||||
#define BABEL_MAX_SEND_INTERVAL 5
|
||||
#define BABEL_TIME_UNITS 100 /* On-wire times are counted in centiseconds */
|
||||
#define BABEL_SEQNO_REQUEST_EXPIRY 60
|
||||
#define BABEL_GARBAGE_INTERVAL 300
|
||||
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
|
||||
|
||||
/* Max interval that will not overflow when carried as 16-bit centiseconds */
|
||||
#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS)
|
||||
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
|
||||
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
|
||||
#define BABEL_MAX_INTERVAL (0xFFFF * BABEL_TIME_UNITS)
|
||||
|
||||
#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
|
||||
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
|
||||
@ -102,8 +107,8 @@ enum babel_ae_type {
|
||||
|
||||
struct babel_config {
|
||||
struct proto_config c;
|
||||
|
||||
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */
|
||||
list iface_list; /* List of iface configs (struct babel_iface_config) */
|
||||
uint hold_time; /* Time to hold stale entries and unreachable routes */
|
||||
};
|
||||
|
||||
struct babel_iface_config {
|
||||
@ -111,11 +116,12 @@ struct babel_iface_config {
|
||||
|
||||
u16 rxcost;
|
||||
u8 type;
|
||||
u8 limit; /* Minimum number of Hellos to keep link up */
|
||||
u8 check_link;
|
||||
uint port;
|
||||
u16 hello_interval;
|
||||
u16 ihu_interval;
|
||||
u16 update_interval;
|
||||
uint hello_interval; /* Hello interval, in us */
|
||||
uint ihu_interval; /* IHU interval, in us */
|
||||
uint update_interval; /* Update interval, in us */
|
||||
|
||||
u16 rx_buffer; /* RX buffer size, 0 for MTU */
|
||||
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
||||
@ -138,14 +144,13 @@ struct babel_proto {
|
||||
list interfaces; /* Interfaces we really know about (struct babel_iface) */
|
||||
u64 router_id;
|
||||
u16 update_seqno; /* To be increased on request */
|
||||
u8 update_seqno_inc; /* Request for update_seqno increase */
|
||||
u8 triggered; /* For triggering global updates */
|
||||
|
||||
slab *route_slab;
|
||||
slab *source_slab;
|
||||
slab *msg_slab;
|
||||
|
||||
slab *seqno_slab;
|
||||
list seqno_cache; /* Seqno requests in the cache (struct babel_seqno_request) */
|
||||
|
||||
struct tbf log_pkt_tbf; /* TBF for packet messages */
|
||||
};
|
||||
@ -172,10 +177,10 @@ struct babel_iface {
|
||||
|
||||
u16 hello_seqno; /* To be increased on each hello */
|
||||
|
||||
bird_clock_t next_hello;
|
||||
bird_clock_t next_regular;
|
||||
bird_clock_t next_triggered;
|
||||
bird_clock_t want_triggered;
|
||||
btime next_hello;
|
||||
btime next_regular;
|
||||
btime next_triggered;
|
||||
btime want_triggered;
|
||||
|
||||
timer *timer;
|
||||
event *send_event;
|
||||
@ -186,13 +191,18 @@ struct babel_neighbor {
|
||||
struct babel_iface *ifa;
|
||||
|
||||
ip_addr addr;
|
||||
u16 txcost;
|
||||
uint uc; /* Reference counter for seqno requests */
|
||||
u16 rxcost; /* Sent in last IHU */
|
||||
u16 txcost; /* Received in last IHU */
|
||||
u16 cost; /* Computed neighbor cost */
|
||||
s8 ihu_cnt; /* IHU countdown, 0 to send it */
|
||||
u8 hello_cnt;
|
||||
u16 hello_map;
|
||||
u16 next_hello_seqno;
|
||||
uint last_hello_int;
|
||||
/* expiry timers */
|
||||
bird_clock_t hello_expiry;
|
||||
bird_clock_t ihu_expiry;
|
||||
btime hello_expiry;
|
||||
btime ihu_expiry;
|
||||
|
||||
list routes; /* Routes this neighbour has sent us (struct babel_route) */
|
||||
};
|
||||
@ -203,7 +213,7 @@ struct babel_source {
|
||||
u64 router_id;
|
||||
u16 seqno;
|
||||
u16 metric;
|
||||
bird_clock_t expires;
|
||||
btime expires;
|
||||
};
|
||||
|
||||
struct babel_route {
|
||||
@ -212,37 +222,46 @@ struct babel_route {
|
||||
struct babel_entry *e;
|
||||
struct babel_neighbor *neigh;
|
||||
|
||||
u8 feasible;
|
||||
u16 seqno;
|
||||
u16 advert_metric;
|
||||
u16 metric;
|
||||
u16 advert_metric;
|
||||
u64 router_id;
|
||||
ip_addr next_hop;
|
||||
bird_clock_t refresh_time;
|
||||
bird_clock_t expires;
|
||||
u16 expiry_interval;
|
||||
btime refresh_time;
|
||||
btime expires;
|
||||
};
|
||||
|
||||
struct babel_seqno_request {
|
||||
node n;
|
||||
u64 router_id;
|
||||
u16 seqno;
|
||||
u8 hop_count;
|
||||
u8 count;
|
||||
btime expires;
|
||||
struct babel_neighbor *nbr;
|
||||
};
|
||||
|
||||
struct babel_entry {
|
||||
struct babel_proto *proto;
|
||||
struct babel_route *selected_in;
|
||||
struct babel_route *selected_out;
|
||||
struct babel_route *selected;
|
||||
|
||||
bird_clock_t updated;
|
||||
|
||||
list sources; /* Source entries for this prefix (struct babel_source). */
|
||||
list routes; /* Routes for this prefix (struct babel_route) */
|
||||
list sources; /* Source entries for this prefix (struct babel_source). */
|
||||
list requests;
|
||||
|
||||
u8 valid; /* Entry validity state (BABEL_ENTRY_*) */
|
||||
u8 unreachable; /* Unreachable route is announced */
|
||||
u16 seqno; /* Outgoing seqno */
|
||||
u16 metric; /* Outgoing metric */
|
||||
u64 router_id; /* Outgoing router ID */
|
||||
btime updated; /* Last change of outgoing rte, for triggered updates */
|
||||
|
||||
struct fib_node n;
|
||||
};
|
||||
|
||||
/* Stores forwarded seqno requests for duplicate suppression. */
|
||||
struct babel_seqno_request {
|
||||
node n;
|
||||
net_addr net;
|
||||
u64 router_id;
|
||||
u16 seqno;
|
||||
bird_clock_t updated;
|
||||
};
|
||||
#define BABEL_ENTRY_DUMMY 0 /* No outgoing route */
|
||||
#define BABEL_ENTRY_VALID 1 /* Valid outgoing route */
|
||||
#define BABEL_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */
|
||||
|
||||
|
||||
/*
|
||||
@ -252,7 +271,7 @@ struct babel_seqno_request {
|
||||
struct babel_msg_ack_req {
|
||||
u8 type;
|
||||
u16 nonce;
|
||||
u16 interval;
|
||||
uint interval;
|
||||
ip_addr sender;
|
||||
};
|
||||
|
||||
@ -264,7 +283,7 @@ struct babel_msg_ack {
|
||||
struct babel_msg_hello {
|
||||
u8 type;
|
||||
u16 seqno;
|
||||
u16 interval;
|
||||
uint interval;
|
||||
ip_addr sender;
|
||||
};
|
||||
|
||||
@ -272,7 +291,7 @@ struct babel_msg_ihu {
|
||||
u8 type;
|
||||
u8 ae;
|
||||
u16 rxcost;
|
||||
u16 interval;
|
||||
uint interval;
|
||||
ip_addr addr;
|
||||
ip_addr sender;
|
||||
};
|
||||
@ -280,7 +299,7 @@ struct babel_msg_ihu {
|
||||
struct babel_msg_update {
|
||||
u8 type;
|
||||
u8 wildcard;
|
||||
u16 interval;
|
||||
uint interval;
|
||||
u16 seqno;
|
||||
u16 metric;
|
||||
u64 router_id;
|
||||
@ -334,6 +353,7 @@ void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
|
||||
void babel_show_interfaces(struct proto *P, char *iff);
|
||||
void babel_show_neighbors(struct proto *P, char *iff);
|
||||
void babel_show_entries(struct proto *P);
|
||||
void babel_show_routes(struct proto *P);
|
||||
|
||||
/* packets.c */
|
||||
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- Babel Configuration
|
||||
*
|
||||
* Copyright (c) 2015-2016 Toke Hoiland-Jorgensen
|
||||
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2016--2017 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
@ -32,6 +34,7 @@ babel_proto_start: proto_start BABEL
|
||||
{
|
||||
this_proto = proto_config_new(&proto_babel, $1);
|
||||
init_list(&BABEL_CFG->iface_list);
|
||||
BABEL_CFG->hold_time = 1 S_;
|
||||
};
|
||||
|
||||
babel_proto_item:
|
||||
@ -56,6 +59,7 @@ babel_iface_start:
|
||||
init_list(&this_ipatt->ipn_list);
|
||||
BABEL_IFACE->port = BABEL_PORT;
|
||||
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
|
||||
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
|
||||
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||
BABEL_IFACE->tx_priority = sk_priority_control;
|
||||
BABEL_IFACE->check_link = 1;
|
||||
@ -83,16 +87,19 @@ babel_iface_finish:
|
||||
if (!BABEL_IFACE->update_interval)
|
||||
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
|
||||
BABEL_IFACE->ihu_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
|
||||
|
||||
BABEL_CFG->hold_time = MAX_(BABEL_CFG->hold_time, BABEL_IFACE->update_interval*BABEL_HOLD_TIME_FACTOR);
|
||||
};
|
||||
|
||||
|
||||
babel_iface_item:
|
||||
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
|
||||
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
|
||||
| HELLO INTERVAL expr { BABEL_IFACE->hello_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid hello interval"); }
|
||||
| UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid update interval"); }
|
||||
| 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; }
|
||||
| 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"); }
|
||||
| TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
|
||||
| TX tos { BABEL_IFACE->tx_tos = $2; }
|
||||
@ -129,6 +136,9 @@ CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show
|
||||
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
|
||||
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
|
||||
|
||||
CF_CLI(SHOW BABEL ROUTES, optsym opttext, [<name>], [[Show information about Babel route entries]])
|
||||
{ babel_show_routes(proto_get_named($4, &proto_babel)); };
|
||||
|
||||
CF_CODE
|
||||
|
||||
CF_END
|
||||
|
@ -2,6 +2,8 @@
|
||||
* BIRD -- The Babel protocol
|
||||
*
|
||||
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
|
||||
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
|
||||
* (c) 2016--2017 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*
|
||||
@ -40,7 +42,7 @@ struct babel_tlv_ack {
|
||||
struct babel_tlv_hello {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u16 reserved;
|
||||
u16 flags;
|
||||
u16 seqno;
|
||||
u16 interval;
|
||||
} PACKED;
|
||||
@ -104,8 +106,12 @@ struct babel_tlv_seqno_request {
|
||||
} PACKED;
|
||||
|
||||
|
||||
#define BABEL_FLAG_DEF_PREFIX 0x80
|
||||
#define BABEL_FLAG_ROUTER_ID 0x40
|
||||
/* Hello flags */
|
||||
#define BABEL_HF_UNICAST 0x8000
|
||||
|
||||
/* Update flags */
|
||||
#define BABEL_UF_DEF_PREFIX 0x80
|
||||
#define BABEL_UF_ROUTER_ID 0x40
|
||||
|
||||
|
||||
struct babel_parse_state {
|
||||
@ -162,17 +168,17 @@ bytes_equal(u8 *b1, u8 *b2, uint maxlen)
|
||||
return i;
|
||||
}
|
||||
|
||||
static inline u16
|
||||
static inline uint
|
||||
get_time16(const void *p)
|
||||
{
|
||||
u16 v = get_u16(p) / BABEL_TIME_UNITS;
|
||||
return MAX(1, v);
|
||||
uint v = get_u16(p) * BABEL_TIME_UNITS;
|
||||
return MAX(BABEL_MIN_INTERVAL, v);
|
||||
}
|
||||
|
||||
static inline void
|
||||
put_time16(void *p, u16 v)
|
||||
put_time16(void *p, uint v)
|
||||
{
|
||||
put_u16(p, v * BABEL_TIME_UNITS);
|
||||
put_u16(p, v / BABEL_TIME_UNITS);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -341,6 +347,11 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
|
||||
struct babel_tlv_hello *tlv = (void *) hdr;
|
||||
struct babel_msg_hello *msg = &m->hello;
|
||||
|
||||
/* We currently don't support unicast Hello */
|
||||
u16 flags = get_u16(&tlv->flags);
|
||||
if (flags & BABEL_HF_UNICAST)
|
||||
return PARSE_IGNORE;
|
||||
|
||||
msg->type = BABEL_TLV_HELLO;
|
||||
msg->seqno = get_u16(&tlv->seqno);
|
||||
msg->interval = get_time16(&tlv->interval);
|
||||
@ -593,8 +604,8 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
if (tlv->omitted && !state->def_ip4_prefix_seen)
|
||||
return PARSE_ERROR;
|
||||
|
||||
/* Need next hop for v4 routes */
|
||||
if (ipa_zero(state->next_hop_ip4))
|
||||
/* Update must have next hop, unless it is retraction */
|
||||
if (ipa_zero(state->next_hop_ip4) && (msg->metric != BABEL_INFINITY))
|
||||
return PARSE_ERROR;
|
||||
|
||||
/* Merge saved prefix and received prefix parts */
|
||||
@ -604,7 +615,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
ip4_addr prefix4 = get_ip4(buf);
|
||||
net_fill_ip4(&msg->net, prefix4, tlv->plen);
|
||||
|
||||
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
|
||||
if (tlv->flags & BABEL_UF_DEF_PREFIX)
|
||||
{
|
||||
put_ip4(state->def_ip4_prefix, prefix4);
|
||||
state->def_ip4_prefix_seen = 1;
|
||||
@ -629,13 +640,13 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
ip6_addr prefix6 = get_ip6(buf);
|
||||
net_fill_ip6(&msg->net, prefix6, tlv->plen);
|
||||
|
||||
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
|
||||
if (tlv->flags & BABEL_UF_DEF_PREFIX)
|
||||
{
|
||||
put_ip6(state->def_ip6_prefix, prefix6);
|
||||
state->def_ip6_prefix_seen = 1;
|
||||
}
|
||||
|
||||
if (tlv->flags & BABEL_FLAG_ROUTER_ID)
|
||||
if (tlv->flags & BABEL_UF_ROUTER_ID)
|
||||
{
|
||||
state->router_id = ((u64) _I2(prefix6)) << 32 | _I3(prefix6);
|
||||
state->router_id_seen = 1;
|
||||
@ -748,7 +759,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
|
||||
else
|
||||
{
|
||||
put_ip6_px(tlv->addr, &msg->net);
|
||||
tlv->flags |= BABEL_FLAG_DEF_PREFIX;
|
||||
tlv->flags |= BABEL_UF_DEF_PREFIX;
|
||||
|
||||
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
|
||||
state->def_ip6_pxlen = tlv->plen;
|
||||
@ -1294,7 +1305,7 @@ babel_rx_hook(sock *sk, uint len)
|
||||
sk->iface->name, sk->faddr, sk->laddr);
|
||||
|
||||
/* Silently ignore my own packets */
|
||||
if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
|
||||
if (ipa_equal(sk->faddr, sk->saddr))
|
||||
return 1;
|
||||
|
||||
if (!ipa_is_link_local(sk->faddr))
|
||||
@ -1329,6 +1340,8 @@ babel_open_socket(struct babel_iface *ifa)
|
||||
sk->sport = ifa->cf->port;
|
||||
sk->dport = ifa->cf->port;
|
||||
sk->iface = ifa->iface;
|
||||
sk->saddr = ifa->addr;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->rx_hook = babel_rx_hook;
|
||||
sk->tx_hook = babel_tx_hook;
|
||||
|
@ -64,16 +64,15 @@
|
||||
* ready, the protocol just creates a BFD request like any other protocol.
|
||||
*
|
||||
* The protocol uses a new generic event loop (structure &birdloop) from |io.c|,
|
||||
* which supports sockets, timers and events like the main loop. Timers
|
||||
* (structure &timer2) are new microsecond based timers, while sockets and
|
||||
* events are the same. A birdloop is associated with a thread (field @thread)
|
||||
* in which event hooks are executed. Most functions for setting event sources
|
||||
* (like sk_start() or tm2_start()) must be called from the context of that
|
||||
* thread. Birdloop allows to temporarily acquire the context of that thread for
|
||||
* the main thread by calling birdloop_enter() and then birdloop_leave(), which
|
||||
* also ensures mutual exclusion with all event hooks. Note that resources
|
||||
* associated with a birdloop (like timers) should be attached to the
|
||||
* independent resource pool, detached from the main resource tree.
|
||||
* which supports sockets, timers and events like the main loop. A birdloop is
|
||||
* associated with a thread (field @thread) in which event hooks are executed.
|
||||
* Most functions for setting event sources (like sk_start() or tm_start()) must
|
||||
* be called from the context of that thread. Birdloop allows to temporarily
|
||||
* acquire the context of that thread for the main thread by calling
|
||||
* birdloop_enter() and then birdloop_leave(), which also ensures mutual
|
||||
* exclusion with all event hooks. Note that resources associated with a
|
||||
* birdloop (like timers) should be attached to the independent resource pool,
|
||||
* detached from the main resource tree.
|
||||
*
|
||||
* There are two kinds of interaction between the BFD core (running in the BFD
|
||||
* thread) and the rest of BFD (running in the main thread). The first kind are
|
||||
@ -145,6 +144,7 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
|
||||
bfd_lock_sessions(p);
|
||||
s->loc_state = state;
|
||||
s->loc_diag = diag;
|
||||
s->last_state_change = current_time();
|
||||
|
||||
notify = !NODE_VALID(&s->n);
|
||||
if (notify)
|
||||
@ -176,7 +176,7 @@ bfd_session_update_tx_interval(struct bfd_session *s)
|
||||
return;
|
||||
|
||||
/* Set timer relative to last tx_timer event */
|
||||
tm2_set(s->tx_timer, s->last_tx + tx_int_l);
|
||||
tm_set(s->tx_timer, s->last_tx + tx_int_l);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -190,7 +190,7 @@ bfd_session_update_detection_time(struct bfd_session *s, int kick)
|
||||
if (!s->last_rx)
|
||||
return;
|
||||
|
||||
tm2_set(s->hold_timer, s->last_rx + timeout);
|
||||
tm_set(s->hold_timer, s->last_rx + timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -211,16 +211,16 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset)
|
||||
goto stop;
|
||||
|
||||
/* So TX timer should run */
|
||||
if (reset || !tm2_active(s->tx_timer))
|
||||
if (reset || !tm_active(s->tx_timer))
|
||||
{
|
||||
s->last_tx = 0;
|
||||
tm2_start(s->tx_timer, 0);
|
||||
tm_start(s->tx_timer, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
stop:
|
||||
tm2_stop(s->tx_timer);
|
||||
tm_stop(s->tx_timer);
|
||||
s->last_tx = 0;
|
||||
}
|
||||
|
||||
@ -379,7 +379,7 @@ bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr)
|
||||
}
|
||||
|
||||
static void
|
||||
bfd_tx_timer_hook(timer2 *t)
|
||||
bfd_tx_timer_hook(timer *t)
|
||||
{
|
||||
struct bfd_session *s = t->data;
|
||||
|
||||
@ -388,7 +388,7 @@ bfd_tx_timer_hook(timer2 *t)
|
||||
}
|
||||
|
||||
static void
|
||||
bfd_hold_timer_hook(timer2 *t)
|
||||
bfd_hold_timer_hook(timer *t)
|
||||
{
|
||||
bfd_session_timeout(t->data);
|
||||
}
|
||||
@ -432,13 +432,13 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
|
||||
s->passive = ifa->cf->passive;
|
||||
s->tx_csn = random_u32();
|
||||
|
||||
s->tx_timer = tm2_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0);
|
||||
s->hold_timer = tm2_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0);
|
||||
s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0);
|
||||
s->hold_timer = tm_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0);
|
||||
bfd_session_update_tx_interval(s);
|
||||
bfd_session_control_tx_timer(s, 1);
|
||||
|
||||
init_list(&s->request_list);
|
||||
s->last_state_change = now;
|
||||
s->last_state_change = current_time();
|
||||
|
||||
TRACE(D_EVENTS, "Session to %I added", s->addr);
|
||||
|
||||
@ -879,9 +879,6 @@ bfd_notify_hook(sock *sk, uint len UNUSED)
|
||||
diag = s->loc_diag;
|
||||
bfd_unlock_sessions(p);
|
||||
|
||||
/* FIXME: convert to btime and move to bfd_session_update_state() */
|
||||
s->last_state_change = now;
|
||||
|
||||
s->notify_running = 1;
|
||||
WALK_LIST_DELSAFE(n, nn, s->request_list)
|
||||
bfd_request_notify(SKIP_BACK(struct bfd_request, n, n), state, diag);
|
||||
@ -1080,7 +1077,7 @@ bfd_show_sessions(struct proto *P)
|
||||
byte tbuf[TM_DATETIME_BUFFER_SIZE];
|
||||
struct bfd_proto *p = (struct bfd_proto *) P;
|
||||
uint state, diag UNUSED;
|
||||
u32 tx_int, timeout;
|
||||
btime tx_int, timeout;
|
||||
const char *ifname;
|
||||
|
||||
if (p->p.proto_state != PS_UP)
|
||||
@ -1101,15 +1098,14 @@ bfd_show_sessions(struct proto *P)
|
||||
state = s->loc_state;
|
||||
diag = s->loc_diag;
|
||||
ifname = (s->ifa && s->ifa->iface) ? s->ifa->iface->name : "---";
|
||||
tx_int = s->last_tx ? (MAX(s->des_min_tx_int, s->rem_min_rx_int) TO_MS) : 0;
|
||||
timeout = (MAX(s->req_min_rx_int, s->rem_min_tx_int) TO_MS) * s->rem_detect_mult;
|
||||
tx_int = s->last_tx ? MAX(s->des_min_tx_int, s->rem_min_rx_int) : 0;
|
||||
timeout = (btime) MAX(s->req_min_rx_int, s->rem_min_tx_int) * s->rem_detect_mult;
|
||||
|
||||
state = (state < 4) ? state : 0;
|
||||
tm_format_datetime(tbuf, &config->tf_proto, s->last_state_change);
|
||||
tm_format_time(tbuf, &config->tf_proto, s->last_state_change);
|
||||
|
||||
cli_msg(-1020, "%-25I %-10s %-10s %-10s %3u.%03u %3u.%03u",
|
||||
s->addr, ifname, bfd_state_names[state], tbuf,
|
||||
tx_int / 1000, tx_int % 1000, timeout / 1000, timeout % 1000);
|
||||
cli_msg(-1020, "%-25I %-10s %-10s %-10s %7t %7t",
|
||||
s->addr, ifname, bfd_state_names[state], tbuf, tx_int, timeout);
|
||||
}
|
||||
HASH_WALK_END;
|
||||
|
||||
|
@ -140,11 +140,11 @@ struct bfd_session
|
||||
btime last_tx; /* Time of last sent periodic control packet */
|
||||
btime last_rx; /* Time of last received valid control packet */
|
||||
|
||||
timer2 *tx_timer; /* Periodic control packet timer */
|
||||
timer2 *hold_timer; /* Timer for session down detection time */
|
||||
timer *tx_timer; /* Periodic control packet timer */
|
||||
timer *hold_timer; /* Timer for session down detection time */
|
||||
|
||||
list request_list; /* List of client requests (struct bfd_request) */
|
||||
bird_clock_t last_state_change; /* Time of last state change */
|
||||
btime last_state_change; /* Time of last state change */
|
||||
u8 notify_running; /* 1 if notify hooks are running */
|
||||
|
||||
u8 rx_csn_known; /* Received crypto sequence number is known */
|
||||
|
281
proto/bfd/io.c
281
proto/bfd/io.c
@ -18,10 +18,10 @@
|
||||
#include "proto/bfd/io.h"
|
||||
|
||||
#include "lib/buffer.h"
|
||||
#include "lib/heap.h"
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/event.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/socket.h"
|
||||
|
||||
|
||||
@ -31,16 +31,12 @@ struct birdloop
|
||||
pthread_t thread;
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
btime last_time;
|
||||
btime real_time;
|
||||
u8 use_monotonic_clock;
|
||||
|
||||
u8 stop_called;
|
||||
u8 poll_active;
|
||||
u8 wakeup_masked;
|
||||
int wakeup_fds[2];
|
||||
|
||||
BUFFER(timer2 *) timers;
|
||||
struct timeloop time;
|
||||
list event_list;
|
||||
list sock_list;
|
||||
uint sock_num;
|
||||
@ -57,6 +53,7 @@ struct birdloop
|
||||
*/
|
||||
|
||||
static pthread_key_t current_loop_key;
|
||||
extern pthread_key_t current_time_key;
|
||||
|
||||
static inline struct birdloop *
|
||||
birdloop_current(void)
|
||||
@ -68,6 +65,7 @@ static inline void
|
||||
birdloop_set_current(struct birdloop *loop)
|
||||
{
|
||||
pthread_setspecific(current_loop_key, loop);
|
||||
pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -77,98 +75,6 @@ birdloop_init_current(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Time clock
|
||||
*/
|
||||
|
||||
static void times_update_alt(struct birdloop *loop);
|
||||
|
||||
static void
|
||||
times_init(struct birdloop *loop)
|
||||
{
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rv < 0)
|
||||
{
|
||||
log(L_WARN "Monotonic clock is missing");
|
||||
|
||||
loop->use_monotonic_clock = 0;
|
||||
loop->last_time = 0;
|
||||
loop->real_time = 0;
|
||||
times_update_alt(loop);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40)))
|
||||
log(L_WARN "Monotonic clock is crazy");
|
||||
|
||||
loop->use_monotonic_clock = 1;
|
||||
loop->last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
|
||||
loop->real_time = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
times_update_pri(struct birdloop *loop)
|
||||
{
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
if (rv < 0)
|
||||
die("clock_gettime: %m");
|
||||
|
||||
btime new_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
|
||||
|
||||
if (new_time < loop->last_time)
|
||||
log(L_ERR "Monotonic clock is broken");
|
||||
|
||||
loop->last_time = new_time;
|
||||
loop->real_time = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
times_update_alt(struct birdloop *loop)
|
||||
{
|
||||
struct timeval tv;
|
||||
int rv;
|
||||
|
||||
rv = gettimeofday(&tv, NULL);
|
||||
if (rv < 0)
|
||||
die("gettimeofday: %m");
|
||||
|
||||
btime new_time = ((s64) tv.tv_sec S) + tv.tv_usec;
|
||||
btime delta = new_time - loop->real_time;
|
||||
|
||||
if ((delta < 0) || (delta > (60 S)))
|
||||
{
|
||||
if (loop->real_time)
|
||||
log(L_WARN "Time jump, delta %d us", (int) delta);
|
||||
|
||||
delta = 100 MS;
|
||||
}
|
||||
|
||||
loop->last_time += delta;
|
||||
loop->real_time = new_time;
|
||||
}
|
||||
|
||||
static void
|
||||
times_update(struct birdloop *loop)
|
||||
{
|
||||
if (loop->use_monotonic_clock)
|
||||
times_update_pri(loop);
|
||||
else
|
||||
times_update_alt(loop);
|
||||
}
|
||||
|
||||
btime
|
||||
current_time(void)
|
||||
{
|
||||
return birdloop_current()->last_time;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Wakeup code for birdloop
|
||||
*/
|
||||
@ -238,7 +144,7 @@ wakeup_drain(struct birdloop *loop)
|
||||
}
|
||||
|
||||
static inline void
|
||||
wakeup_do_kick(struct birdloop *loop)
|
||||
wakeup_do_kick(struct birdloop *loop)
|
||||
{
|
||||
pipe_kick(loop->wakeup_fds[1]);
|
||||
}
|
||||
@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
|
||||
loop->wakeup_masked = 2;
|
||||
}
|
||||
|
||||
/* For notifications from outside */
|
||||
void
|
||||
wakeup_kick_current(void)
|
||||
{
|
||||
struct birdloop *loop = birdloop_current();
|
||||
|
||||
if (loop && loop->poll_active)
|
||||
wakeup_kick(loop);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Events
|
||||
@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
|
||||
static void
|
||||
events_fire(struct birdloop *loop)
|
||||
{
|
||||
times_update(loop);
|
||||
times_update(&loop->time);
|
||||
ev_run_list(&loop->event_list);
|
||||
}
|
||||
|
||||
@ -291,154 +207,6 @@ ev2_schedule(event *e)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Timers
|
||||
*/
|
||||
|
||||
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
|
||||
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
|
||||
heap[a]->index = (a), heap[b]->index = (b))
|
||||
|
||||
static inline uint timers_count(struct birdloop *loop)
|
||||
{ return loop->timers.used - 1; }
|
||||
|
||||
static inline timer2 *timers_first(struct birdloop *loop)
|
||||
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
|
||||
|
||||
|
||||
static void
|
||||
tm2_free(resource *r)
|
||||
{
|
||||
timer2 *t = (timer2 *) r;
|
||||
|
||||
tm2_stop(t);
|
||||
}
|
||||
|
||||
static void
|
||||
tm2_dump(resource *r)
|
||||
{
|
||||
timer2 *t = (timer2 *) r;
|
||||
|
||||
debug("(code %p, data %p, ", t->hook, t->data);
|
||||
if (t->randomize)
|
||||
debug("rand %d, ", t->randomize);
|
||||
if (t->recurrent)
|
||||
debug("recur %d, ", t->recurrent);
|
||||
if (t->expires)
|
||||
debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
|
||||
else
|
||||
debug("inactive)\n");
|
||||
}
|
||||
|
||||
|
||||
static struct resclass tm2_class = {
|
||||
"Timer",
|
||||
sizeof(timer2),
|
||||
tm2_free,
|
||||
tm2_dump,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
timer2 *
|
||||
tm2_new(pool *p)
|
||||
{
|
||||
timer2 *t = ralloc(p, &tm2_class);
|
||||
t->index = -1;
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
tm2_set(timer2 *t, btime when)
|
||||
{
|
||||
struct birdloop *loop = birdloop_current();
|
||||
uint tc = timers_count(loop);
|
||||
|
||||
if (!t->expires)
|
||||
{
|
||||
t->index = ++tc;
|
||||
t->expires = when;
|
||||
BUFFER_PUSH(loop->timers) = t;
|
||||
HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP);
|
||||
}
|
||||
else if (t->expires < when)
|
||||
{
|
||||
t->expires = when;
|
||||
HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
}
|
||||
else if (t->expires > when)
|
||||
{
|
||||
t->expires = when;
|
||||
HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
}
|
||||
|
||||
if (loop->poll_active && (t->index == 1))
|
||||
wakeup_kick(loop);
|
||||
}
|
||||
|
||||
void
|
||||
tm2_start(timer2 *t, btime after)
|
||||
{
|
||||
tm2_set(t, current_time() + MAX(after, 0));
|
||||
}
|
||||
|
||||
void
|
||||
tm2_stop(timer2 *t)
|
||||
{
|
||||
if (!t->expires)
|
||||
return;
|
||||
|
||||
struct birdloop *loop = birdloop_current();
|
||||
uint tc = timers_count(loop);
|
||||
|
||||
HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
|
||||
BUFFER_POP(loop->timers);
|
||||
|
||||
t->index = -1;
|
||||
t->expires = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
timers_init(struct birdloop *loop)
|
||||
{
|
||||
BUFFER_INIT(loop->timers, loop->pool, 4);
|
||||
BUFFER_PUSH(loop->timers) = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
timers_fire(struct birdloop *loop)
|
||||
{
|
||||
btime base_time;
|
||||
timer2 *t;
|
||||
|
||||
times_update(loop);
|
||||
base_time = loop->last_time;
|
||||
|
||||
while (t = timers_first(loop))
|
||||
{
|
||||
if (t->expires > base_time)
|
||||
return;
|
||||
|
||||
if (t->recurrent)
|
||||
{
|
||||
btime when = t->expires + t->recurrent;
|
||||
|
||||
if (when <= loop->last_time)
|
||||
when = loop->last_time + t->recurrent;
|
||||
|
||||
if (t->randomize)
|
||||
when += random() % (t->randomize + 1);
|
||||
|
||||
tm2_set(t, when);
|
||||
}
|
||||
else
|
||||
tm2_stop(t);
|
||||
|
||||
t->hook(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sockets
|
||||
*/
|
||||
@ -586,7 +354,7 @@ sockets_fire(struct birdloop *loop)
|
||||
sock **psk = loop->poll_sk.data;
|
||||
int poll_num = loop->poll_fd.used - 1;
|
||||
|
||||
times_update(loop);
|
||||
times_update(&loop->time);
|
||||
|
||||
/* Last fd is internal wakeup fd */
|
||||
if (pfd[poll_num].revents & POLLIN)
|
||||
@ -634,11 +402,10 @@ birdloop_new(void)
|
||||
loop->pool = p;
|
||||
pthread_mutex_init(&loop->mutex, NULL);
|
||||
|
||||
times_init(loop);
|
||||
wakeup_init(loop);
|
||||
|
||||
events_init(loop);
|
||||
timers_init(loop);
|
||||
timers_init(&loop->time, p);
|
||||
sockets_init(loop);
|
||||
|
||||
return loop;
|
||||
@ -710,7 +477,7 @@ static void *
|
||||
birdloop_main(void *arg)
|
||||
{
|
||||
struct birdloop *loop = arg;
|
||||
timer2 *t;
|
||||
timer *t;
|
||||
int rv, timeout;
|
||||
|
||||
birdloop_set_current(loop);
|
||||
@ -719,13 +486,13 @@ birdloop_main(void *arg)
|
||||
while (1)
|
||||
{
|
||||
events_fire(loop);
|
||||
timers_fire(loop);
|
||||
timers_fire(&loop->time);
|
||||
|
||||
times_update(loop);
|
||||
times_update(&loop->time);
|
||||
if (events_waiting(loop))
|
||||
timeout = 0;
|
||||
else if (t = timers_first(loop))
|
||||
timeout = (tm2_remains(t) TO_MS) + 1;
|
||||
else if (t = timers_first(&loop->time))
|
||||
timeout = (tm_remains(t) TO_MS) + 1;
|
||||
else
|
||||
timeout = -1;
|
||||
|
||||
@ -756,7 +523,7 @@ birdloop_main(void *arg)
|
||||
if (rv)
|
||||
sockets_fire(loop);
|
||||
|
||||
timers_fire(loop);
|
||||
timers_fire(&loop->time);
|
||||
}
|
||||
|
||||
loop->stop_called = 0;
|
||||
|
@ -11,80 +11,15 @@
|
||||
#include "lib/lists.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/event.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/socket.h"
|
||||
// #include "sysdep/unix/timer.h"
|
||||
|
||||
|
||||
typedef struct timer2
|
||||
{
|
||||
resource r;
|
||||
void (*hook)(struct timer2 *);
|
||||
void *data;
|
||||
|
||||
btime expires; /* 0=inactive */
|
||||
uint randomize; /* Amount of randomization */
|
||||
uint recurrent; /* Timer recurrence */
|
||||
|
||||
int index;
|
||||
} timer2;
|
||||
|
||||
|
||||
btime current_time(void);
|
||||
|
||||
void ev2_schedule(event *e);
|
||||
|
||||
|
||||
timer2 *tm2_new(pool *p);
|
||||
void tm2_set(timer2 *t, btime when);
|
||||
void tm2_start(timer2 *t, btime after);
|
||||
void tm2_stop(timer2 *t);
|
||||
|
||||
static inline int
|
||||
tm2_active(timer2 *t)
|
||||
{
|
||||
return t->expires != 0;
|
||||
}
|
||||
|
||||
static inline btime
|
||||
tm2_remains(timer2 *t)
|
||||
{
|
||||
btime now = current_time();
|
||||
return (t->expires > now) ? (t->expires - now) : 0;
|
||||
}
|
||||
|
||||
static inline timer2 *
|
||||
tm2_new_init(pool *p, void (*hook)(struct timer2 *), void *data, uint rec, uint rand)
|
||||
{
|
||||
timer2 *t = tm2_new(p);
|
||||
t->hook = hook;
|
||||
t->data = data;
|
||||
t->recurrent = rec;
|
||||
t->randomize = rand;
|
||||
return t;
|
||||
}
|
||||
|
||||
static inline void
|
||||
tm2_set_max(timer2 *t, btime when)
|
||||
{
|
||||
if (when > t->expires)
|
||||
tm2_set(t, when);
|
||||
}
|
||||
|
||||
/*
|
||||
static inline void
|
||||
tm2_start_max(timer2 *t, btime after)
|
||||
{
|
||||
btime rem = tm2_remains(t);
|
||||
tm2_start(t, MAX_(rem, after));
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void sk_start(sock *s);
|
||||
void sk_stop(sock *s);
|
||||
|
||||
|
||||
|
||||
struct birdloop *birdloop_new(void);
|
||||
void birdloop_start(struct birdloop *loop);
|
||||
void birdloop_stop(struct birdloop *loop);
|
||||
|
@ -64,8 +64,6 @@
|
||||
* format - Optional hook that converts eattr to textual representation.
|
||||
*/
|
||||
|
||||
// XXXX review pool usage : c->c.proto->pool
|
||||
|
||||
|
||||
struct bgp_attr_desc {
|
||||
const char *name;
|
||||
@ -1175,6 +1173,22 @@ bgp_init_bucket_table(struct bgp_channel *c)
|
||||
c->withdraw_bucket = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
bgp_free_bucket_table(struct bgp_channel *c)
|
||||
{
|
||||
HASH_FREE(c->bucket_hash);
|
||||
|
||||
struct bgp_bucket *b;
|
||||
WALK_LIST_FIRST(b, c->bucket_queue)
|
||||
{
|
||||
rem_node(&b->send_node);
|
||||
mb_free(b);
|
||||
}
|
||||
|
||||
mb_free(c->withdraw_bucket);
|
||||
c->withdraw_bucket = NULL;
|
||||
}
|
||||
|
||||
static struct bgp_bucket *
|
||||
bgp_get_bucket(struct bgp_channel *c, ea_list *new)
|
||||
{
|
||||
|
179
proto/bgp/bgp.c
179
proto/bgp/bgp.c
@ -98,11 +98,14 @@
|
||||
* <item> <rfc id="7911"> - Advertisement of Multiple Paths in BGP
|
||||
* <item> <rfc id="7947"> - Internet Exchange BGP Route Server
|
||||
* <item> <rfc id="8092"> - BGP Large Communities Attribute
|
||||
* <item> <rfc id="8203"> - BGP Administrative Shutdown Communication
|
||||
* </itemize>
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "nest/iface.h"
|
||||
#include "nest/protocol.h"
|
||||
@ -312,20 +315,21 @@ err1:
|
||||
/**
|
||||
* bgp_start_timer - start a BGP timer
|
||||
* @t: timer
|
||||
* @value: time to fire (0 to disable the timer)
|
||||
* @value: time (in seconds) to fire (0 to disable the timer)
|
||||
*
|
||||
* This functions calls tm_start() on @t with time @value and the amount of
|
||||
* randomization suggested by the BGP standard. Please use it for all BGP
|
||||
* timers.
|
||||
*/
|
||||
void
|
||||
bgp_start_timer(timer *t, int value)
|
||||
bgp_start_timer(timer *t, uint value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
/* The randomization procedure is specified in RFC 1771: 9.2.3.3 */
|
||||
t->randomize = value / 4;
|
||||
tm_start(t, value - t->randomize);
|
||||
/* The randomization procedure is specified in RFC 4271 section 10 */
|
||||
btime time = value S;
|
||||
btime randomize = random() % ((time / 4) + 1);
|
||||
tm_start(t, time - randomize);
|
||||
}
|
||||
else
|
||||
tm_stop(t);
|
||||
@ -381,10 +385,10 @@ bgp_update_startup_delay(struct bgp_proto *p)
|
||||
|
||||
DBG("BGP: Updating startup delay\n");
|
||||
|
||||
if (p->last_proto_error && ((now - p->last_proto_error) >= (int) cf->error_amnesia_time))
|
||||
if (p->last_proto_error && ((current_time() - p->last_proto_error) >= cf->error_amnesia_time S))
|
||||
p->startup_delay = 0;
|
||||
|
||||
p->last_proto_error = now;
|
||||
p->last_proto_error = current_time();
|
||||
|
||||
if (cf->disable_after_error)
|
||||
{
|
||||
@ -400,7 +404,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
|
||||
}
|
||||
|
||||
static void
|
||||
bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
|
||||
bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint len)
|
||||
{
|
||||
switch (conn->state)
|
||||
{
|
||||
@ -416,7 +420,7 @@ bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
|
||||
case BS_OPENSENT:
|
||||
case BS_OPENCONFIRM:
|
||||
case BS_ESTABLISHED:
|
||||
bgp_error(conn, 6, subcode, NULL, 0);
|
||||
bgp_error(conn, 6, subcode, data, len);
|
||||
return;
|
||||
|
||||
default:
|
||||
@ -456,11 +460,11 @@ bgp_decision(void *vp)
|
||||
}
|
||||
|
||||
void
|
||||
bgp_stop(struct bgp_proto *p, uint subcode)
|
||||
bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
|
||||
{
|
||||
proto_notify_state(&p->p, PS_STOP);
|
||||
bgp_graceful_close_conn(&p->outgoing_conn, subcode);
|
||||
bgp_graceful_close_conn(&p->incoming_conn, subcode);
|
||||
bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
|
||||
bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
|
||||
ev_schedule(p->event);
|
||||
}
|
||||
|
||||
@ -598,12 +602,8 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
|
||||
BGP_TRACE(D_EVENTS, "BGP session closed");
|
||||
p->conn = NULL;
|
||||
|
||||
// XXXX free these tables to avoid memory leak during graceful restart
|
||||
// bgp_free_prefix_table(p);
|
||||
// bgp_free_bucket_table(p);
|
||||
|
||||
if (p->p.proto_state == PS_UP)
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -661,6 +661,10 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
|
||||
struct bgp_channel *c;
|
||||
WALK_LIST(c, p->p.channels)
|
||||
{
|
||||
/* FIXME: perhaps check for channel state instead of disabled flag? */
|
||||
if (c->c.disabled)
|
||||
continue;
|
||||
|
||||
if (c->gr_ready)
|
||||
{
|
||||
if (c->gr_active)
|
||||
@ -676,6 +680,13 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
|
||||
rt_refresh_begin(c->c.table, &c->c);
|
||||
rt_refresh_end(c->c.table, &c->c);
|
||||
}
|
||||
|
||||
/* Reset bucket and prefix tables */
|
||||
bgp_free_bucket_table(c);
|
||||
bgp_free_prefix_table(c);
|
||||
bgp_init_bucket_table(c);
|
||||
bgp_init_prefix_table(c);
|
||||
c->packets_to_send = 0;
|
||||
}
|
||||
|
||||
proto_notify_state(&p->p, PS_START);
|
||||
@ -722,7 +733,7 @@ bgp_graceful_restart_timeout(timer *t)
|
||||
struct bgp_proto *p = t->data;
|
||||
|
||||
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -885,9 +896,9 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
|
||||
conn->last_channel = 0;
|
||||
conn->last_channel_count = 0;
|
||||
|
||||
conn->connect_timer = tm_new_set(p->p.pool, bgp_connect_timeout, conn, 0, 0);
|
||||
conn->hold_timer = tm_new_set(p->p.pool, bgp_hold_timeout, conn, 0, 0);
|
||||
conn->keepalive_timer = tm_new_set(p->p.pool, bgp_keepalive_timeout, conn, 0, 0);
|
||||
conn->connect_timer = tm_new_init(p->p.pool, bgp_connect_timeout, conn, 0, 0);
|
||||
conn->hold_timer = tm_new_init(p->p.pool, bgp_hold_timeout, conn, 0, 0);
|
||||
conn->keepalive_timer = tm_new_init(p->p.pool, bgp_keepalive_timeout, conn, 0, 0);
|
||||
|
||||
conn->tx_ev = ev_new(p->p.pool);
|
||||
conn->tx_ev->hook = bgp_kick_tx;
|
||||
@ -936,6 +947,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
|
||||
s->daddr = p->cf->remote_ip;
|
||||
s->dport = p->cf->remote_port;
|
||||
s->iface = p->neigh ? p->neigh->iface : NULL;
|
||||
s->vrf = p->p.vrf;
|
||||
s->ttl = p->cf->ttl_security ? 255 : hops;
|
||||
s->rbsize = p->cf->enable_extended_messages ? BGP_RX_BUFFER_EXT_SIZE : BGP_RX_BUFFER_SIZE;
|
||||
s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
|
||||
@ -1094,19 +1106,8 @@ bgp_start_neighbor(struct bgp_proto *p)
|
||||
|
||||
if (ipa_is_link_local(p->source_addr))
|
||||
p->link_addr = p->source_addr;
|
||||
else
|
||||
{
|
||||
/* Find some link-local address for given iface */
|
||||
struct ifa *a;
|
||||
WALK_LIST(a, p->neigh->iface->addrs)
|
||||
if (a->scope == SCOPE_LINK)
|
||||
{
|
||||
p->link_addr = a->ip;
|
||||
break;
|
||||
}
|
||||
|
||||
DBG("%s: Selected link-local address %I\n", p->p.name, p->link_addr);
|
||||
}
|
||||
else if (p->neigh->iface->llv6)
|
||||
p->link_addr = p->neigh->iface->llv6->ip;
|
||||
|
||||
bgp_initiate(p);
|
||||
}
|
||||
@ -1132,7 +1133,7 @@ bgp_neigh_notify(neighbor *n)
|
||||
BGP_TRACE(D_EVENTS, "Neighbor lost");
|
||||
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST);
|
||||
/* Perhaps also run bgp_update_startup_delay(p)? */
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP))
|
||||
@ -1143,7 +1144,7 @@ bgp_neigh_notify(neighbor *n)
|
||||
bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN);
|
||||
if (ps == PS_UP)
|
||||
bgp_update_startup_delay(p);
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1168,7 +1169,7 @@ bgp_bfd_notify(struct bfd_request *req)
|
||||
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
|
||||
if (ps == PS_UP)
|
||||
bgp_update_startup_delay(p);
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1311,13 +1312,8 @@ bgp_start(struct proto *P)
|
||||
p->event->hook = bgp_decision;
|
||||
p->event->data = p;
|
||||
|
||||
p->startup_timer = tm_new(p->p.pool);
|
||||
p->startup_timer->hook = bgp_startup_timeout;
|
||||
p->startup_timer->data = p;
|
||||
|
||||
p->gr_timer = tm_new(p->p.pool);
|
||||
p->gr_timer->hook = bgp_graceful_restart_timeout;
|
||||
p->gr_timer->data = p;
|
||||
p->startup_timer = tm_new_init(p->p.pool, bgp_startup_timeout, p, 0, 0);
|
||||
p->gr_timer = tm_new_init(p->p.pool, bgp_graceful_restart_timeout, p, 0, 0);
|
||||
|
||||
p->local_id = proto_get_router_id(P->cf);
|
||||
if (p->rr_client)
|
||||
@ -1327,7 +1323,7 @@ bgp_start(struct proto *P)
|
||||
p->source_addr = p->cf->local_ip;
|
||||
p->link_addr = IPA_NONE;
|
||||
|
||||
/* XXXX */
|
||||
/* Lock all channels when in GR recovery mode */
|
||||
if (p->p.gr_recovery && p->cf->gr_mode)
|
||||
{
|
||||
struct bgp_channel *c;
|
||||
@ -1344,6 +1340,7 @@ bgp_start(struct proto *P)
|
||||
lock->addr = p->cf->remote_ip;
|
||||
lock->port = p->cf->remote_port;
|
||||
lock->iface = p->cf->iface;
|
||||
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
|
||||
lock->type = OBJLOCK_TCP;
|
||||
lock->hook = bgp_start_locked;
|
||||
lock->data = p;
|
||||
@ -1360,6 +1357,10 @@ bgp_shutdown(struct proto *P)
|
||||
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||
uint subcode = 0;
|
||||
|
||||
char *message = NULL;
|
||||
byte *data = NULL;
|
||||
uint len = 0;
|
||||
|
||||
BGP_TRACE(D_EVENTS, "Shutdown requested");
|
||||
|
||||
switch (P->down_code)
|
||||
@ -1376,10 +1377,12 @@ bgp_shutdown(struct proto *P)
|
||||
case PDC_CMD_DISABLE:
|
||||
case PDC_CMD_SHUTDOWN:
|
||||
subcode = 2; // Errcode 6, 2 - administrative shutdown
|
||||
message = P->message;
|
||||
break;
|
||||
|
||||
case PDC_CMD_RESTART:
|
||||
subcode = 4; // Errcode 6, 4 - administrative reset
|
||||
message = P->message;
|
||||
break;
|
||||
|
||||
case PDC_RX_LIMIT_HIT:
|
||||
@ -1404,8 +1407,22 @@ bgp_shutdown(struct proto *P)
|
||||
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
|
||||
p->startup_delay = 0;
|
||||
|
||||
/* RFC 8203 - shutdown communication */
|
||||
if (message)
|
||||
{
|
||||
uint msg_len = strlen(message);
|
||||
msg_len = MIN(msg_len, 128);
|
||||
|
||||
/* Buffer will be freed automatically by protocol shutdown */
|
||||
data = mb_alloc(p->p.pool, msg_len + 1);
|
||||
len = msg_len + 1;
|
||||
|
||||
data[0] = msg_len;
|
||||
memcpy(data+1, message, msg_len);
|
||||
}
|
||||
|
||||
done:
|
||||
bgp_stop(p, subcode);
|
||||
bgp_stop(p, subcode, data, len);
|
||||
return p->p.proto_state;
|
||||
}
|
||||
|
||||
@ -1495,6 +1512,20 @@ bgp_channel_start(struct channel *C)
|
||||
c->next_hop_addr = src;
|
||||
}
|
||||
|
||||
/* Use preferred addresses associated with interface / source address */
|
||||
if (ipa_zero(c->next_hop_addr))
|
||||
{
|
||||
/* We know the iface for single-hop, we make lookup for multihop */
|
||||
struct neighbor *nbr = p->neigh ?: neigh_find2(&p->p, &src, NULL, 0);
|
||||
struct iface *iface = nbr ? nbr->iface : NULL;
|
||||
|
||||
if (bgp_channel_is_ipv4(c) && iface && iface->addr4)
|
||||
c->next_hop_addr = iface->addr4->ip;
|
||||
|
||||
if (bgp_channel_is_ipv6(c) && iface && iface->addr6)
|
||||
c->next_hop_addr = iface->addr6->ip;
|
||||
}
|
||||
|
||||
/* Exit if no feasible next hop address is found */
|
||||
if (ipa_zero(c->next_hop_addr))
|
||||
{
|
||||
@ -1523,10 +1554,9 @@ bgp_channel_shutdown(struct channel *C)
|
||||
{
|
||||
struct bgp_channel *c = (void *) C;
|
||||
|
||||
/* XXXX: cleanup bucket and prefix tables */
|
||||
|
||||
c->next_hop_addr = IPA_NONE;
|
||||
c->link_addr = IPA_NONE;
|
||||
c->packets_to_send = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1598,6 +1628,10 @@ bgp_postconfig(struct proto_config *CF)
|
||||
if (cf->multihop < 0)
|
||||
cf->multihop = internal ? 64 : 0;
|
||||
|
||||
/* Link check for single-hop BGP by default */
|
||||
if (cf->check_link < 0)
|
||||
cf->check_link = !cf->multihop;
|
||||
|
||||
|
||||
if (!cf->local_as)
|
||||
cf_error("Local AS number must be set");
|
||||
@ -1796,7 +1830,7 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len)
|
||||
if (code != 6)
|
||||
{
|
||||
bgp_update_startup_delay(p);
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2017,17 +2051,18 @@ bgp_show_proto_info(struct proto *P)
|
||||
struct bgp_conn *oc = &p->outgoing_conn;
|
||||
|
||||
if ((p->start_state < BSS_CONNECT) &&
|
||||
(p->startup_timer->expires))
|
||||
cli_msg(-1006, " Error wait: %d/%d",
|
||||
p->startup_timer->expires - now, p->startup_delay);
|
||||
(tm_active(p->startup_timer)))
|
||||
cli_msg(-1006, " Error wait: %t/%u",
|
||||
tm_remains(p->startup_timer), p->startup_delay);
|
||||
|
||||
if ((oc->state == BS_ACTIVE) &&
|
||||
(oc->connect_timer->expires))
|
||||
cli_msg(-1006, " Connect delay: %d/%d",
|
||||
oc->connect_timer->expires - now, p->cf->connect_delay_time);
|
||||
(tm_active(oc->connect_timer)))
|
||||
cli_msg(-1006, " Connect delay: %t/%u",
|
||||
tm_remains(oc->connect_timer), p->cf->connect_delay_time);
|
||||
|
||||
if (p->gr_active_num && p->gr_timer->expires)
|
||||
cli_msg(-1006, " Restart timer: %d/-", p->gr_timer->expires - now);
|
||||
if (p->gr_active_num && tm_active(p->gr_timer))
|
||||
cli_msg(-1006, " Restart timer: %t/-",
|
||||
tm_remains(p->gr_timer));
|
||||
}
|
||||
else if (P->proto_state == PS_UP)
|
||||
{
|
||||
@ -2036,21 +2071,16 @@ bgp_show_proto_info(struct proto *P)
|
||||
bgp_show_capabilities(p, p->conn->local_caps);
|
||||
cli_msg(-1006, " Neighbor capabilities");
|
||||
bgp_show_capabilities(p, p->conn->remote_caps);
|
||||
/* XXXX
|
||||
cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s",
|
||||
p->is_internal ? "internal" : "external",
|
||||
p->cf->multihop ? " multihop" : "",
|
||||
p->rr_client ? " route-reflector" : "",
|
||||
p->rs_client ? " route-server" : "",
|
||||
p->as4_session ? " AS4" : "",
|
||||
p->add_path_rx ? " add-path-rx" : "",
|
||||
p->add_path_tx ? " add-path-tx" : "",
|
||||
p->ext_messages ? " ext-messages" : "");
|
||||
*/
|
||||
cli_msg(-1006, " Session: %s%s%s%s%s",
|
||||
p->is_internal ? "internal" : "external",
|
||||
p->cf->multihop ? " multihop" : "",
|
||||
p->rr_client ? " route-reflector" : "",
|
||||
p->rs_client ? " route-server" : "",
|
||||
p->as4_session ? " AS4" : "");
|
||||
cli_msg(-1006, " Source address: %I", p->source_addr);
|
||||
cli_msg(-1006, " Hold timer: %d/%d",
|
||||
cli_msg(-1006, " Hold timer: %t/%u",
|
||||
tm_remains(p->conn->hold_timer), p->conn->hold_time);
|
||||
cli_msg(-1006, " Keepalive timer: %d/%d",
|
||||
cli_msg(-1006, " Keepalive timer: %t/%u",
|
||||
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
||||
}
|
||||
|
||||
@ -2063,12 +2093,19 @@ bgp_show_proto_info(struct proto *P)
|
||||
}
|
||||
|
||||
{
|
||||
/* XXXX ?? */
|
||||
struct bgp_channel *c;
|
||||
WALK_LIST(c, p->p.channels)
|
||||
{
|
||||
channel_show_info(&c->c);
|
||||
|
||||
if (c->c.channel_state == CS_UP)
|
||||
{
|
||||
if (ipa_zero(c->link_addr))
|
||||
cli_msg(-1006, " BGP Next hop: %I", c->next_hop_addr);
|
||||
else
|
||||
cli_msg(-1006, " BGP Next hop: %I %I", c->next_hop_addr, c->link_addr);
|
||||
}
|
||||
|
||||
if (c->igp_table_ip4)
|
||||
cli_msg(-1006, " IGP IPv4 table: %s", c->igp_table_ip4->name);
|
||||
|
||||
|
@ -108,6 +108,7 @@ struct bgp_config {
|
||||
int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */
|
||||
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
|
||||
int setkey; /* Set MD5 password to system SA/SP database */
|
||||
/* Times below are in seconds */
|
||||
unsigned gr_time; /* Graceful restart timeout */
|
||||
unsigned connect_delay_time; /* Minimum delay between connect attempts */
|
||||
unsigned connect_retry_time; /* Timeout for connect attempts */
|
||||
@ -210,10 +211,10 @@ struct bgp_conn {
|
||||
|
||||
struct bgp_caps *local_caps;
|
||||
struct bgp_caps *remote_caps;
|
||||
struct timer *connect_timer;
|
||||
struct timer *hold_timer;
|
||||
struct timer *keepalive_timer;
|
||||
struct event *tx_ev;
|
||||
timer *connect_timer;
|
||||
timer *hold_timer;
|
||||
timer *keepalive_timer;
|
||||
event *tx_ev;
|
||||
u32 packets_to_send; /* Bitmap of packet types to be sent */
|
||||
u32 channels_to_send; /* Bitmap of channels with packets to be sent */
|
||||
u8 last_channel; /* Channel used last time for TX */
|
||||
@ -254,11 +255,11 @@ struct bgp_proto {
|
||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||
ip_addr source_addr; /* Local address used as an advertised next hop */
|
||||
ip_addr link_addr; /* Link-local version of source_addr */
|
||||
struct event *event; /* Event for respawning and shutting process */
|
||||
struct timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
|
||||
struct timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
|
||||
unsigned startup_delay; /* Time to delay protocol startup by due to errors */
|
||||
bird_clock_t last_proto_error; /* Time of last error that leads to protocol stop */
|
||||
event *event; /* Event for respawning and shutting process */
|
||||
timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
|
||||
timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
|
||||
uint startup_delay; /* Delay (in seconds) of protocol startup due to previous errors */
|
||||
btime last_proto_error; /* Time of last error that leads to protocol stop */
|
||||
u8 last_error_class; /* Error class of last error */
|
||||
u32 last_error_code; /* Error code of last error. BGP protocol errors
|
||||
are encoded as (bgp_err_code << 16 | bgp_err_subcode) */
|
||||
@ -422,7 +423,7 @@ extern struct linpool *bgp_linpool;
|
||||
extern struct linpool *bgp_linpool2;
|
||||
|
||||
|
||||
void bgp_start_timer(struct timer *t, int value);
|
||||
void bgp_start_timer(timer *t, uint value);
|
||||
void bgp_check_config(struct bgp_config *c);
|
||||
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
|
||||
void bgp_close_conn(struct bgp_conn *c);
|
||||
@ -436,7 +437,7 @@ void bgp_graceful_restart_done(struct bgp_channel *c);
|
||||
void bgp_refresh_begin(struct bgp_channel *c);
|
||||
void bgp_refresh_end(struct bgp_channel *c);
|
||||
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
|
||||
void bgp_stop(struct bgp_proto *p, unsigned subcode);
|
||||
void bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len);
|
||||
|
||||
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
|
||||
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
|
||||
@ -491,11 +492,13 @@ int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte
|
||||
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
|
||||
|
||||
void bgp_init_bucket_table(struct bgp_channel *c);
|
||||
void bgp_free_bucket_table(struct bgp_channel *c);
|
||||
void bgp_free_bucket(struct bgp_channel *c, struct bgp_bucket *b);
|
||||
void bgp_defer_bucket(struct bgp_channel *c, struct bgp_bucket *b);
|
||||
void bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b);
|
||||
|
||||
void bgp_init_prefix_table(struct bgp_channel *c);
|
||||
void bgp_free_prefix_table(struct bgp_channel *c);
|
||||
void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
|
||||
|
||||
int bgp_rte_better(struct rte *, struct rte *);
|
||||
|
@ -58,6 +58,7 @@ bgp_proto_start: proto_start BGP {
|
||||
BGP_CFG->gr_mode = BGP_GR_AWARE;
|
||||
BGP_CFG->gr_time = 120;
|
||||
BGP_CFG->setkey = 1;
|
||||
BGP_CFG->check_link = -1;
|
||||
}
|
||||
;
|
||||
|
||||
|
@ -1483,7 +1483,8 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
|
||||
ADVANCE(pos, size, 1);
|
||||
|
||||
/* Encode MPLS labels */
|
||||
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
|
||||
if (s->mpls)
|
||||
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
|
||||
|
||||
/* Encode route distinguisher */
|
||||
put_u64(pos, net->rd);
|
||||
@ -1636,8 +1637,8 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
|
||||
uint pxlen = data[1];
|
||||
|
||||
// FIXME: Use some generic function
|
||||
memcpy(&px, data, BYTES(pxlen));
|
||||
px = ip4_and(px, ip4_mkmask(pxlen));
|
||||
memcpy(&px, data+2, BYTES(pxlen));
|
||||
px = ip4_and(ip4_ntoh(px), ip4_mkmask(pxlen));
|
||||
|
||||
/* Prepare the flow */
|
||||
net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen);
|
||||
@ -1728,8 +1729,8 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
|
||||
uint pxlen = data[1];
|
||||
|
||||
// FIXME: Use some generic function
|
||||
memcpy(&px, data, BYTES(pxlen));
|
||||
px = ip6_and(px, ip6_mkmask(pxlen));
|
||||
memcpy(&px, data+2, BYTES(pxlen));
|
||||
px = ip6_and(ip6_ntoh(px), ip6_mkmask(pxlen));
|
||||
|
||||
/* Prepare the flow */
|
||||
net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
|
||||
@ -2678,38 +2679,72 @@ bgp_error_dsc(uint code, uint subcode)
|
||||
return buff;
|
||||
}
|
||||
|
||||
/* RFC 8203 - shutdown communication message */
|
||||
static int
|
||||
bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
|
||||
{
|
||||
byte *msg = data + 1;
|
||||
uint msg_len = data[0];
|
||||
uint i;
|
||||
|
||||
/* Handle zero length message */
|
||||
if (msg_len == 0)
|
||||
return 1;
|
||||
|
||||
/* Handle proper message */
|
||||
if ((msg_len > 128) && (msg_len + 1 > len))
|
||||
return 0;
|
||||
|
||||
/* Some elementary cleanup */
|
||||
for (i = 0; i < msg_len; i++)
|
||||
if (msg[i] < ' ')
|
||||
msg[i] = ' ';
|
||||
|
||||
proto_set_message(&p->p, msg, msg_len);
|
||||
*bp += bsprintf(*bp, ": \"%s\"", p->p.message);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, uint code, uint subcode, byte *data, uint len)
|
||||
{
|
||||
const byte *name;
|
||||
byte *t, argbuf[36];
|
||||
byte argbuf[256], *t = argbuf;
|
||||
uint i;
|
||||
|
||||
/* Don't report Cease messages generated by myself */
|
||||
if (code == 6 && class == BE_BGP_TX)
|
||||
return;
|
||||
|
||||
name = bgp_error_dsc(code, subcode);
|
||||
t = argbuf;
|
||||
/* Reset shutdown message */
|
||||
if ((code == 6) && ((subcode == 2) || (subcode == 4)))
|
||||
proto_set_message(&p->p, NULL, 0);
|
||||
|
||||
if (len)
|
||||
{
|
||||
*t++ = ':';
|
||||
*t++ = ' ';
|
||||
|
||||
/* Bad peer AS - we would like to print the AS */
|
||||
if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))
|
||||
{
|
||||
/* Bad peer AS - we would like to print the AS */
|
||||
t += bsprintf(t, "%u", (len == 2) ? get_u16(data) : get_u32(data));
|
||||
t += bsprintf(t, ": %u", (len == 2) ? get_u16(data) : get_u32(data));
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* RFC 8203 - shutdown communication */
|
||||
if (((code == 6) && ((subcode == 2) || (subcode == 4))))
|
||||
if (bgp_handle_message(p, data, len, &t))
|
||||
goto done;
|
||||
|
||||
*t++ = ':';
|
||||
*t++ = ' ';
|
||||
if (len > 16)
|
||||
len = 16;
|
||||
for (i=0; i<len; i++)
|
||||
t += bsprintf(t, "%02x", data[i]);
|
||||
}
|
||||
done:
|
||||
|
||||
done:
|
||||
*t = 0;
|
||||
log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);
|
||||
const byte *dsc = bgp_error_dsc(code, subcode);
|
||||
log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, dsc, argbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2733,7 +2768,7 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
|
||||
if (err)
|
||||
{
|
||||
bgp_update_startup_delay(p);
|
||||
bgp_stop(p, 0);
|
||||
bgp_stop(p, 0, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,18 +78,66 @@ static void
|
||||
ospf_proto_finish(void)
|
||||
{
|
||||
struct ospf_config *cf = OSPF_CFG;
|
||||
|
||||
if (EMPTY_LIST(cf->area_list))
|
||||
cf_error( "No configured areas in OSPF");
|
||||
struct ospf_area_config *ac;
|
||||
struct ospf_iface_patt *ic;
|
||||
|
||||
/* Define default channel */
|
||||
if (EMPTY_LIST(this_proto->channels))
|
||||
{
|
||||
this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
|
||||
channel_config_new(NULL, this_proto->net_type, this_proto);
|
||||
}
|
||||
|
||||
/* Propagate global instance ID to interfaces */
|
||||
if (cf->instance_id_set)
|
||||
{
|
||||
WALK_LIST(ac, cf->area_list)
|
||||
WALK_LIST(ic, ac->patt_list)
|
||||
if (!ic->instance_id_set)
|
||||
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
|
||||
|
||||
WALK_LIST(ic, cf->vlink_list)
|
||||
if (!ic->instance_id_set)
|
||||
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
|
||||
}
|
||||
|
||||
if (ospf_cfg_is_v3())
|
||||
{
|
||||
uint ipv4 = (this_proto->net_type == NET_IP4);
|
||||
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
|
||||
|
||||
/* RFC 5838 - OSPFv3-AF */
|
||||
if (cf->af_ext)
|
||||
{
|
||||
/* RFC 5838 2.1 - instance IDs based on AFs */
|
||||
WALK_LIST(ac, cf->area_list)
|
||||
WALK_LIST(ic, ac->patt_list)
|
||||
{
|
||||
if (!ic->instance_id_set)
|
||||
ic->instance_id = base;
|
||||
else if (ic->instance_id >= 128)
|
||||
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
|
||||
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
|
||||
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
|
||||
}
|
||||
|
||||
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
|
||||
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
|
||||
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ipv4 || cf->af_mc)
|
||||
cf_error("Different channel type");
|
||||
}
|
||||
}
|
||||
|
||||
if (EMPTY_LIST(cf->area_list))
|
||||
cf_error("No configured areas in OSPF");
|
||||
|
||||
int areano = 0;
|
||||
int backbone = 0;
|
||||
int nssa = 0;
|
||||
struct ospf_area_config *ac;
|
||||
WALK_LIST(ac, cf->area_list)
|
||||
{
|
||||
areano++;
|
||||
@ -148,10 +196,11 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
|
||||
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
|
||||
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
|
||||
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
|
||||
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
|
||||
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838)
|
||||
|
||||
%type <ld> lsadb_args
|
||||
%type <i> ospf_variant nbma_eligible
|
||||
%type <i> ospf_variant ospf_af_mc nbma_eligible
|
||||
%type <cc> ospf_channel_start ospf_channel
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
@ -166,12 +215,14 @@ ospf_variant:
|
||||
ospf_proto_start: proto_start ospf_variant
|
||||
{
|
||||
this_proto = proto_config_new(&proto_ospf, $1);
|
||||
this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
|
||||
this_proto->net_type = $2 ? NET_IP4 : 0;
|
||||
|
||||
init_list(&OSPF_CFG->area_list);
|
||||
init_list(&OSPF_CFG->vlink_list);
|
||||
OSPF_CFG->ecmp = rt_default_ecmp;
|
||||
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
|
||||
OSPF_CFG->ospf2 = $2;
|
||||
OSPF_CFG->af_ext = !$2;
|
||||
};
|
||||
|
||||
ospf_proto:
|
||||
@ -179,16 +230,34 @@ ospf_proto:
|
||||
| ospf_proto ospf_proto_item ';'
|
||||
;
|
||||
|
||||
ospf_af_mc:
|
||||
{ $$ = 0; }
|
||||
| MULTICAST { $$ = 1; }
|
||||
;
|
||||
|
||||
/* We redefine proto_channel to add multicast flag */
|
||||
ospf_channel_start: net_type ospf_af_mc
|
||||
{
|
||||
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
|
||||
|
||||
/* Save the multicast flag */
|
||||
if (this_channel == proto_cf_main_channel(this_proto))
|
||||
OSPF_CFG->af_mc = $2;
|
||||
};
|
||||
|
||||
ospf_channel: ospf_channel_start channel_opt_list channel_end;
|
||||
|
||||
ospf_proto_item:
|
||||
proto_item
|
||||
| proto_channel
|
||||
| ospf_channel { this_proto->net_type = $1->net_type; }
|
||||
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
|
||||
| RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
|
||||
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
|
||||
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
|
||||
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
|
||||
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
|
||||
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
|
||||
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||
| ospf_area
|
||||
;
|
||||
|
||||
@ -293,7 +362,6 @@ ospf_vlink_start: VIRTUAL LINK idval
|
||||
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
|
||||
OSPF_PATT->deadc = DEADC_D;
|
||||
OSPF_PATT->type = OSPF_IT_VLINK;
|
||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
||||
init_list(&OSPF_PATT->nbma_list);
|
||||
reset_passwords();
|
||||
}
|
||||
@ -393,8 +461,8 @@ ospf_iface_start:
|
||||
OSPF_PATT->priority = PRIORITY_D;
|
||||
OSPF_PATT->deadc = DEADC_D;
|
||||
OSPF_PATT->type = OSPF_IT_UNDEF;
|
||||
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
|
||||
init_list(&OSPF_PATT->nbma_list);
|
||||
OSPF_PATT->check_link = 1;
|
||||
OSPF_PATT->ptp_netmask = 2; /* not specified */
|
||||
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
|
||||
OSPF_PATT->tx_priority = sk_priority_control;
|
||||
@ -404,7 +472,7 @@ ospf_iface_start:
|
||||
|
||||
ospf_instance_id:
|
||||
/* empty */
|
||||
| INSTANCE expr { OSPF_PATT->instance_id = $2; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
|
||||
;
|
||||
|
||||
ospf_iface_patt_list:
|
||||
@ -431,7 +499,7 @@ CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEM
|
||||
CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); })
|
||||
|
||||
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
|
||||
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol XXX]], CLI_SF_PROTOCOL)
|
||||
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]], CLI_SF_PROTOCOL)
|
||||
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
|
||||
|
||||
CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER)
|
||||
|
@ -356,7 +356,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
|
||||
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
|
||||
|
||||
if ((rcv_imms == DBDES_IMMS) &&
|
||||
if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
|
||||
(n->rid > p->router_id) &&
|
||||
(plen == ospf_dbdes_hdrlen(p)))
|
||||
{
|
||||
@ -428,7 +428,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
}
|
||||
|
||||
ospf_send_dbdes(p, n);
|
||||
tm_start(n->dbdes_timer, n->ifa->rxmtint);
|
||||
tm_start(n->dbdes_timer, n->ifa->rxmtint S);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -32,10 +32,7 @@ struct ospf_hello3_packet
|
||||
struct ospf_packet hdr;
|
||||
|
||||
u32 iface_id;
|
||||
u8 priority;
|
||||
u8 options3;
|
||||
u8 options2;
|
||||
u8 options;
|
||||
u32 options;
|
||||
u16 helloint;
|
||||
u16 deadint;
|
||||
u32 dr;
|
||||
@ -91,10 +88,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
|
||||
struct ospf_hello3_packet *ps = (void *) pkt;
|
||||
|
||||
ps->iface_id = htonl(ifa->iface_id);
|
||||
ps->priority = ifa->priority;
|
||||
ps->options3 = ifa->oa->options >> 16;
|
||||
ps->options2 = ifa->oa->options >> 8;
|
||||
ps->options = ifa->oa->options;
|
||||
ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
|
||||
ps->helloint = ntohs(ifa->helloint);
|
||||
ps->deadint = htons(ifa->deadint);
|
||||
ps->dr = htonl(ifa->drid);
|
||||
@ -190,7 +184,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
struct ospf_proto *p = ifa->oa->po;
|
||||
const char *err_dsc = NULL;
|
||||
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
|
||||
u8 rcv_options, rcv_priority;
|
||||
uint rcv_options, rcv_priority;
|
||||
uint loc_options = ifa->oa->options;
|
||||
u32 *neighbors;
|
||||
u32 neigh_count;
|
||||
uint plen, i, err_val = 0;
|
||||
@ -245,8 +240,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
rcv_deadint = ntohs(ps->deadint);
|
||||
rcv_dr = ntohl(ps->dr);
|
||||
rcv_bdr = ntohl(ps->bdr);
|
||||
rcv_options = ps->options;
|
||||
rcv_priority = ps->priority;
|
||||
rcv_options = ntohl(ps->options) & 0x00FFFFFF;
|
||||
rcv_priority = ntohl(ps->options) >> 24;
|
||||
|
||||
neighbors = ps->neighbors;
|
||||
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
|
||||
@ -259,9 +254,13 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
DROP("dead interval mismatch", rcv_deadint);
|
||||
|
||||
/* Check whether bits E, N match */
|
||||
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
|
||||
if ((rcv_options ^ loc_options) & (OPT_E | OPT_N))
|
||||
DROP("area type mismatch", rcv_options);
|
||||
|
||||
/* RFC 5838 2.4 - AF-bit check unless on IPv6 unicast */
|
||||
if ((loc_options & OPT_AF) && !(loc_options & OPT_V6) && !(rcv_options & OPT_AF))
|
||||
DROP("AF-bit mismatch", rcv_options);
|
||||
|
||||
/* Check consistency of existing neighbor entry */
|
||||
if (n)
|
||||
{
|
||||
|
@ -121,6 +121,7 @@ ospf_sk_open(struct ospf_iface *ifa)
|
||||
sk->dport = OSPF_PROTO;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->iface = ifa->iface;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->tos = ifa->cf->tx_tos;
|
||||
sk->priority = ifa->cf->tx_priority;
|
||||
@ -204,6 +205,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
|
||||
sk->type = SK_IP;
|
||||
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
|
||||
sk->dport = OSPF_PROTO;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
/* FIXME: configurable tos/priority ? */
|
||||
sk->tos = IP_PREC_INTERNET_CONTROL;
|
||||
@ -396,15 +398,15 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
|
||||
{
|
||||
ospf_iface_chstate(ifa, OSPF_IS_WAITING);
|
||||
if (ifa->wait_timer)
|
||||
tm_start(ifa->wait_timer, ifa->waitint);
|
||||
tm_start(ifa->wait_timer, ifa->waitint S);
|
||||
}
|
||||
}
|
||||
|
||||
if (ifa->hello_timer)
|
||||
tm_start(ifa->hello_timer, ifa->helloint);
|
||||
tm_start(ifa->hello_timer, ifa->helloint S);
|
||||
|
||||
if (ifa->poll_timer)
|
||||
tm_start(ifa->poll_timer, ifa->pollint);
|
||||
tm_start(ifa->poll_timer, ifa->pollint S);
|
||||
|
||||
ospf_send_hello(ifa, OHS_HELLO, NULL);
|
||||
}
|
||||
@ -494,13 +496,13 @@ ospf_iface_add(struct object_lock *lock)
|
||||
|
||||
if (! ifa->stub)
|
||||
{
|
||||
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
|
||||
ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
|
||||
|
||||
if (ifa->type == OSPF_IT_NBMA)
|
||||
ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);
|
||||
ifa->poll_timer = tm_new_init(ifa->pool, poll_timer_hook, ifa, ifa->pollint S, 0);
|
||||
|
||||
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
|
||||
ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
|
||||
ifa->wait_timer = tm_new_init(ifa->pool, wait_timer_hook, ifa, 0, 0);
|
||||
|
||||
ifa->flood_queue_size = ifa_flood_queue_size(ifa);
|
||||
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
|
||||
@ -703,7 +705,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
|
||||
|
||||
add_tail(&p->iface_list, NODE ifa);
|
||||
|
||||
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
|
||||
ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
|
||||
|
||||
ifa->flood_queue_size = ifa_flood_queue_size(ifa);
|
||||
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
|
||||
@ -715,10 +717,10 @@ ospf_iface_change_timer(timer *tm, uint val)
|
||||
if (!tm)
|
||||
return;
|
||||
|
||||
tm->recurrent = val;
|
||||
tm->recurrent = val S;
|
||||
|
||||
if (tm->expires)
|
||||
tm_start(tm, val);
|
||||
if (tm_active(tm))
|
||||
tm_start(tm, val S);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -801,8 +803,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
|
||||
ifname, ifa->waitint, new->waitint);
|
||||
|
||||
ifa->waitint = new->waitint;
|
||||
if (ifa->wait_timer && ifa->wait_timer->expires)
|
||||
tm_start(ifa->wait_timer, ifa->waitint);
|
||||
if (ifa->wait_timer && tm_active(ifa->wait_timer))
|
||||
tm_start(ifa->wait_timer, ifa->waitint S);
|
||||
}
|
||||
|
||||
/* DEAD TIMER */
|
||||
@ -1113,9 +1115,6 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||
{
|
||||
struct ospf_proto *p = (struct ospf_proto *) P;
|
||||
|
||||
if (a->prefix.type != NET_IP6)
|
||||
return;
|
||||
|
||||
if (a->flags & IA_SECONDARY)
|
||||
return;
|
||||
|
||||
@ -1126,6 +1125,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||
other addresses are used for link-LSA. */
|
||||
if (a->scope == SCOPE_LINK)
|
||||
{
|
||||
if (a->prefix.type != NET_IP6)
|
||||
return;
|
||||
|
||||
if (flags & IF_CHANGE_UP)
|
||||
{
|
||||
struct ospf_mip_walk s = { .iface = a->iface };
|
||||
@ -1143,6 +1145,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a->prefix.type != ospf_get_af(p))
|
||||
return;
|
||||
|
||||
struct ospf_iface *ifa;
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
if (ifa->iface == a->iface)
|
||||
|
@ -280,7 +280,7 @@ lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
|
||||
|
||||
|
||||
void
|
||||
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric)
|
||||
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric)
|
||||
{
|
||||
if (ospf2)
|
||||
{
|
||||
@ -292,7 +292,7 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopt
|
||||
else
|
||||
{
|
||||
struct ospf_lsa_sum3_net *ls = en->lsa_body;
|
||||
ospf_get_ipv6_prefix(ls->prefix, net, pxopts, NULL);
|
||||
ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
|
||||
*metric = ls->metric & LSA_METRIC_MASK;
|
||||
}
|
||||
}
|
||||
@ -317,7 +317,7 @@ lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u
|
||||
}
|
||||
|
||||
void
|
||||
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
|
||||
lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt)
|
||||
{
|
||||
if (ospf2)
|
||||
{
|
||||
@ -338,13 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
|
||||
else
|
||||
{
|
||||
struct ospf_lsa_ext3 *ext = en->lsa_body;
|
||||
u32 *buf = ospf_get_ipv6_prefix(ext->rest, &rt->net, &rt->pxopts, NULL);
|
||||
u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
|
||||
rt->metric = ext->metric & LSA_METRIC_MASK;
|
||||
rt->ebit = ext->metric & LSA_EXT3_EBIT;
|
||||
|
||||
rt->fbit = ext->metric & LSA_EXT3_FBIT;
|
||||
if (rt->fbit)
|
||||
buf = ospf_get_ipv6_addr(buf, &rt->fwaddr);
|
||||
buf = ospf3_get_addr(buf, af, &rt->fwaddr);
|
||||
else
|
||||
rt->fwaddr = IPA_NONE;
|
||||
|
||||
|
@ -55,9 +55,12 @@ u16 lsa_verify_checksum(const void *lsa_n, int lsa_len);
|
||||
int lsa_comp(struct ospf_lsa_header *l1, struct ospf_lsa_header *l2);
|
||||
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
|
||||
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
|
||||
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric);
|
||||
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric);
|
||||
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
|
||||
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
|
||||
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt);
|
||||
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
|
||||
|
||||
static inline btime lsa_inst_age(struct top_hash_entry *en)
|
||||
{ return current_time() - en->inst_time; }
|
||||
|
||||
#endif /* _BIRD_OSPF_LSALIB_H_ */
|
||||
|
@ -137,7 +137,7 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
|
||||
ret->lsa_body = LSA_BODY_DUMMY;
|
||||
|
||||
if (!tm_active(n->lsrt_timer))
|
||||
tm_start(n->lsrt_timer, n->ifa->rxmtint);
|
||||
tm_start(n->lsrt_timer, n->ifa->rxmtint S);
|
||||
}
|
||||
|
||||
void
|
||||
@ -572,7 +572,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
{
|
||||
/* 13. (5a) - enforce minimum time between updates for received LSAs */
|
||||
/* We also use this to ratelimit reactions to received self-originated LSAs */
|
||||
if (en && ((now - en->inst_time) < MINLSARRIVAL))
|
||||
if (en && (lsa_inst_age(en) < MINLSARRIVAL))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
|
||||
continue;
|
||||
@ -700,7 +700,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql)))
|
||||
{
|
||||
ospf_send_lsreq(p, n);
|
||||
tm_start(n->lsrq_timer, n->ifa->rxmtint);
|
||||
tm_start(n->lsrq_timer, n->ifa->rxmtint S);
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -94,11 +94,11 @@ ospf_neighbor_new(struct ospf_iface *ifa)
|
||||
init_list(&n->ackl[ACKL_DIRECT]);
|
||||
init_list(&n->ackl[ACKL_DELAY]);
|
||||
|
||||
n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0);
|
||||
n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint);
|
||||
n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint);
|
||||
n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint);
|
||||
n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2);
|
||||
n->inactim = tm_new_init(pool, inactivity_timer_hook, n, 0, 0);
|
||||
n->dbdes_timer = tm_new_init(pool, dbdes_timer_hook, n, ifa->rxmtint S, 0);
|
||||
n->lsrq_timer = tm_new_init(pool, lsrq_timer_hook, n, ifa->rxmtint S, 0);
|
||||
n->lsrt_timer = tm_new_init(pool, lsrt_timer_hook, n, ifa->rxmtint S, 0);
|
||||
n->ackd_timer = tm_new_init(pool, ackd_timer_hook, n, ifa->rxmtint S / 2, 0);
|
||||
|
||||
return (n);
|
||||
}
|
||||
@ -186,7 +186,7 @@ ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
|
||||
n->myimms = DBDES_IMMS;
|
||||
|
||||
tm_start(n->dbdes_timer, 0);
|
||||
tm_start(n->ackd_timer, ifa->rxmtint / 2);
|
||||
tm_start(n->ackd_timer, ifa->rxmtint S / 2);
|
||||
}
|
||||
|
||||
if (state > NEIGHBOR_EXSTART)
|
||||
@ -231,7 +231,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
|
||||
ospf_neigh_chstate(n, NEIGHBOR_INIT);
|
||||
|
||||
/* Restart inactivity timer */
|
||||
tm_start(n->inactim, n->ifa->deadint);
|
||||
tm_start(n->inactim, n->ifa->deadint S);
|
||||
break;
|
||||
|
||||
case INM_2WAYREC:
|
||||
@ -651,20 +651,6 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
|
||||
{
|
||||
struct ospf_iface *ifa = n->ifa;
|
||||
char *pos = "PtP ";
|
||||
char etime[6];
|
||||
int exp, sec, min;
|
||||
|
||||
exp = n->inactim->expires - now;
|
||||
sec = exp % 60;
|
||||
min = exp / 60;
|
||||
if (min > 59)
|
||||
{
|
||||
bsprintf(etime, "-Inf-");
|
||||
}
|
||||
else
|
||||
{
|
||||
bsprintf(etime, "%02u:%02u", min, sec);
|
||||
}
|
||||
|
||||
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
|
||||
{
|
||||
@ -676,6 +662,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
|
||||
pos = "Other";
|
||||
}
|
||||
|
||||
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority,
|
||||
ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip);
|
||||
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%7t\t%-10s %-1I",
|
||||
n->rid, n->priority, ospf_ns_names[n->state], pos,
|
||||
tm_remains(n->inactim), ifa->ifname, n->ip);
|
||||
}
|
||||
|
@ -92,8 +92,10 @@
|
||||
* - RFC 2328 - main OSPFv2 standard
|
||||
* - RFC 5340 - main OSPFv3 standard
|
||||
* - RFC 3101 - OSPFv2 NSSA areas
|
||||
* - RFC 6549 - OSPFv2 multi-instance extensions
|
||||
* - RFC 6987 - OSPF stub router advertisement
|
||||
* - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
|
||||
* - RFC 5838 - OSPFv3 Support of Address Families
|
||||
* - RFC 6549 - OSPFv2 Multi-Instance Extensions
|
||||
* - RFC 6987 - OSPF Stub Router Advertisement
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -115,9 +117,9 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||
struct area_net_config *anc;
|
||||
struct area_net *an;
|
||||
|
||||
fib_init(&oa->net_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
|
||||
fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
|
||||
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
||||
fib_init(&oa->enet_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6,
|
||||
fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
|
||||
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
|
||||
|
||||
WALK_LIST(anc, ac->net_list)
|
||||
@ -134,6 +136,16 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint
|
||||
ospf_opts(struct ospf_proto *p)
|
||||
{
|
||||
if (ospf_is_v2(p))
|
||||
return 0;
|
||||
|
||||
return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
|
||||
(!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
|
||||
}
|
||||
|
||||
static void
|
||||
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
||||
{
|
||||
@ -155,10 +167,7 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
|
||||
if (oa->areaid == 0)
|
||||
p->backbone = oa;
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
oa->options = ac->type;
|
||||
else
|
||||
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
||||
oa->options = ac->type | ospf_opts(p);
|
||||
|
||||
ospf_notify_rt_lsa(oa);
|
||||
}
|
||||
@ -224,22 +233,23 @@ ospf_start(struct proto *P)
|
||||
|
||||
p->router_id = proto_get_router_id(P->cf);
|
||||
p->ospf2 = c->ospf2;
|
||||
p->af_ext = c->af_ext;
|
||||
p->af_mc = c->af_mc;
|
||||
p->rfc1583 = c->rfc1583;
|
||||
p->stub_router = c->stub_router;
|
||||
p->merge_external = c->merge_external;
|
||||
p->asbr = c->asbr;
|
||||
p->ecmp = c->ecmp;
|
||||
p->tick = c->tick;
|
||||
p->disp_timer = tm_new_set(P->pool, ospf_disp, p, 0, p->tick);
|
||||
tm_start(p->disp_timer, 1);
|
||||
p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
|
||||
tm_start(p->disp_timer, 100 MS);
|
||||
p->lsab_size = 256;
|
||||
p->lsab_used = 0;
|
||||
p->lsab = mb_alloc(P->pool, p->lsab_size);
|
||||
p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
|
||||
init_list(&(p->iface_list));
|
||||
init_list(&(p->area_list));
|
||||
fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6,
|
||||
sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
|
||||
fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
|
||||
if (ospf_is_v3(p))
|
||||
idm_init(&p->idm, P->pool, 16);
|
||||
p->areano = 0;
|
||||
@ -601,11 +611,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
|
||||
struct ospf_iface *ifa;
|
||||
|
||||
oa->ac = nac;
|
||||
|
||||
if (ospf_is_v2(p))
|
||||
oa->options = nac->type;
|
||||
else
|
||||
oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
|
||||
oa->options = nac->type | ospf_opts(p);
|
||||
|
||||
if (nac->type != oac->type)
|
||||
{
|
||||
@ -659,6 +665,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
if (old->abr != new->abr)
|
||||
return 0;
|
||||
|
||||
if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
|
||||
return 0;
|
||||
|
||||
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
|
||||
return 0;
|
||||
|
||||
@ -667,8 +676,8 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
p->asbr = new->asbr;
|
||||
p->ecmp = new->ecmp;
|
||||
p->tick = new->tick;
|
||||
p->disp_timer->recurrent = p->tick;
|
||||
tm_start(p->disp_timer, 1);
|
||||
p->disp_timer->recurrent = p->tick S;
|
||||
tm_start(p->disp_timer, 100 MS);
|
||||
|
||||
/* Mark all areas and ifaces */
|
||||
WALK_LIST(oa, p->area_list)
|
||||
@ -1073,13 +1082,13 @@ show_lsa_network(struct top_hash_entry *he, int ospf2)
|
||||
}
|
||||
|
||||
static inline void
|
||||
show_lsa_sum_net(struct top_hash_entry *he, int ospf2)
|
||||
show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
|
||||
{
|
||||
net_addr net;
|
||||
u8 pxopts;
|
||||
u32 metric;
|
||||
|
||||
lsa_parse_sum_net(he, ospf2, &net, &pxopts, &metric);
|
||||
lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
|
||||
cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
|
||||
}
|
||||
|
||||
@ -1096,7 +1105,7 @@ show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
|
||||
|
||||
|
||||
static inline void
|
||||
show_lsa_external(struct top_hash_entry *he, int ospf2)
|
||||
show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
|
||||
{
|
||||
struct ospf_lsa_ext_local rt;
|
||||
char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
|
||||
@ -1105,7 +1114,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
|
||||
if (he->lsa_type == LSA_T_EXT)
|
||||
he->domain = 0; /* Unmark the LSA */
|
||||
|
||||
lsa_parse_ext(he, ospf2, &rt);
|
||||
lsa_parse_ext(he, ospf2, af, &rt);
|
||||
|
||||
if (rt.fbit)
|
||||
bsprintf(str_via, " via %I", rt.fwaddr);
|
||||
@ -1119,7 +1128,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
|
||||
}
|
||||
|
||||
static inline void
|
||||
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
|
||||
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
|
||||
{
|
||||
struct ospf_lsa_prefix *px = he->lsa_body;
|
||||
u32 *buf;
|
||||
@ -1142,7 +1151,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
|
||||
u8 pxopts;
|
||||
u16 metric;
|
||||
|
||||
buf = ospf_get_ipv6_prefix(buf, &net, &pxopts, &metric);
|
||||
buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
|
||||
|
||||
if (px->ref_type == LSA_T_RT)
|
||||
cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
|
||||
@ -1156,6 +1165,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||
{
|
||||
struct ospf_proto *p = (struct ospf_proto *) P;
|
||||
int ospf2 = ospf_is_v2(p);
|
||||
int af = ospf_get_af(p);
|
||||
uint i, ix, j1, jx;
|
||||
u32 last_area = 0xFFFFFFFF;
|
||||
|
||||
@ -1276,7 +1286,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||
|
||||
case LSA_T_SUM_NET:
|
||||
if (cnode->lsa_type == LSA_T_RT)
|
||||
show_lsa_sum_net(he, ospf2);
|
||||
show_lsa_sum_net(he, ospf2, af);
|
||||
break;
|
||||
|
||||
case LSA_T_SUM_RT:
|
||||
@ -1286,11 +1296,11 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||
|
||||
case LSA_T_EXT:
|
||||
case LSA_T_NSSA:
|
||||
show_lsa_external(he, ospf2);
|
||||
show_lsa_external(he, ospf2, af);
|
||||
break;
|
||||
|
||||
case LSA_T_PREFIX:
|
||||
show_lsa_prefix(he, cnode);
|
||||
show_lsa_prefix(he, cnode, af);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1304,7 +1314,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||
ix++;
|
||||
|
||||
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
|
||||
show_lsa_external(hex[ix++], ospf2);
|
||||
show_lsa_external(hex[ix++], ospf2, af);
|
||||
|
||||
cnode = NULL;
|
||||
}
|
||||
@ -1338,7 +1348,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
|
||||
last_rt = he->lsa.rt;
|
||||
}
|
||||
|
||||
show_lsa_external(he, ospf2);
|
||||
show_lsa_external(he, ospf2, af);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "lib/lists.h"
|
||||
#include "lib/slists.h"
|
||||
#include "lib/socket.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/resource.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
@ -58,16 +58,16 @@
|
||||
log_rl(&p->log_lsa_tbf, L_REMOTE "%s: " msg, p->p.name, args)
|
||||
|
||||
#define LOG_LSA2(msg, args...) \
|
||||
do { if (! p->log_lsa_tbf.mark) \
|
||||
do { if (! p->log_lsa_tbf.drop) \
|
||||
log(L_REMOTE "%s: " msg, p->p.name, args); } while(0)
|
||||
|
||||
|
||||
#define OSPF_PROTO 89
|
||||
|
||||
#define LSREFRESHTIME 1800 /* 30 minutes */
|
||||
#define MINLSINTERVAL 5
|
||||
#define MINLSARRIVAL 1
|
||||
#define LSINFINITY 0xffffff
|
||||
#define LSREFRESHTIME 1800 /* 30 minutes */
|
||||
#define MINLSINTERVAL (5 S_)
|
||||
#define MINLSARRIVAL (1 S_)
|
||||
#define LSINFINITY 0xffffff
|
||||
|
||||
#define OSPF_DEFAULT_TICK 1
|
||||
#define OSPF_DEFAULT_STUB_COST 1000
|
||||
@ -84,10 +84,13 @@ struct ospf_config
|
||||
struct proto_config c;
|
||||
uint tick;
|
||||
u8 ospf2;
|
||||
u8 af_ext;
|
||||
u8 af_mc;
|
||||
u8 rfc1583;
|
||||
u8 stub_router;
|
||||
u8 merge_external;
|
||||
u8 instance_id;
|
||||
u8 instance_id_set;
|
||||
u8 abr;
|
||||
u8 asbr;
|
||||
int ecmp;
|
||||
@ -168,9 +171,9 @@ struct ospf_iface_patt
|
||||
int tx_priority;
|
||||
u16 tx_length;
|
||||
u16 rx_buffer;
|
||||
|
||||
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
|
||||
u8 instance_id;
|
||||
u8 instance_id_set;
|
||||
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
|
||||
u8 strictnbma;
|
||||
u8 check_link;
|
||||
@ -211,12 +214,14 @@ struct ospf_proto
|
||||
int padj; /* Number of neighbors in Exchange or Loading state */
|
||||
struct fib rtf; /* Routing table */
|
||||
struct idm idm; /* OSPFv3 LSA ID map */
|
||||
byte ospf2; /* OSPF v2 or v3 */
|
||||
byte rfc1583; /* RFC1583 compatibility */
|
||||
byte stub_router; /* Do not forward transit traffic */
|
||||
byte merge_external; /* Should i merge external routes? */
|
||||
byte asbr; /* May i originate any ext/NSSA lsa? */
|
||||
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
||||
u8 ospf2; /* OSPF v2 or v3 */
|
||||
u8 af_ext; /* OSPFv3-AF extension */
|
||||
u8 af_mc; /* OSPFv3-AF multicast */
|
||||
u8 rfc1583; /* RFC1583 compatibility */
|
||||
u8 stub_router; /* Do not forward transit traffic */
|
||||
u8 merge_external; /* Should i merge external routes? */
|
||||
u8 asbr; /* May i originate any ext/NSSA lsa? */
|
||||
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
|
||||
struct ospf_area *backbone; /* If exists */
|
||||
event *flood_event; /* Event for flooding LS updates */
|
||||
void *lsab; /* LSA buffer used when originating router LSAs */
|
||||
@ -264,10 +269,10 @@ struct ospf_iface
|
||||
sock *sk; /* IP socket */
|
||||
list neigh_list; /* List of neighbors (struct ospf_neighbor) */
|
||||
u32 cost; /* Cost of iface */
|
||||
u32 waitint; /* number of sec before changing state from wait */
|
||||
u32 rxmtint; /* number of seconds between LSA retransmissions */
|
||||
u32 pollint; /* Poll interval */
|
||||
u32 deadint; /* after "deadint" missing hellos is router dead */
|
||||
u32 waitint; /* Number of seconds before changing state from wait */
|
||||
u32 rxmtint; /* Number of seconds between LSA retransmissions */
|
||||
u32 pollint; /* Poll interval in seconds */
|
||||
u32 deadint; /* After deadint seconds without hellos is router dead */
|
||||
u32 iface_id; /* Interface ID (iface->index or new value for vlinks) */
|
||||
u32 vid; /* ID of peer of virtual link */
|
||||
ip_addr vip; /* IP of peer of virtual link */
|
||||
@ -278,8 +283,8 @@ struct ospf_iface
|
||||
interface. LSAs contained in the update */
|
||||
u16 helloint; /* number of seconds between hello sending */
|
||||
list *passwords;
|
||||
u32 csn; /* Last used crypt seq number */
|
||||
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */
|
||||
u32 csn; /* Last used crypt seq number */
|
||||
btime csn_use; /* Last time when packet with that CSN was sent */
|
||||
ip_addr all_routers; /* Multicast (or broadcast) address for all routers */
|
||||
ip_addr des_routers; /* Multicast (or NULL) address for designated routers */
|
||||
ip_addr drip; /* Designated router IP */
|
||||
@ -449,14 +454,15 @@ struct ospf_neighbor
|
||||
|
||||
|
||||
/* Generic option flags */
|
||||
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
||||
#define OPT_E 0x02 /* Related to AS-external LSAs */
|
||||
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */
|
||||
#define OPT_N 0x08 /* Related to NSSA */
|
||||
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
||||
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */
|
||||
#define OPT_R 0x10 /* OSPFv3, originator is active router */
|
||||
#define OPT_DC 0x20 /* Related to demand circuits, not used */
|
||||
#define OPT_V6 0x0001 /* OSPFv3, LSA relevant for IPv6 routing calculation */
|
||||
#define OPT_E 0x0002 /* Related to AS-external LSAs */
|
||||
#define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
|
||||
#define OPT_N 0x0008 /* Related to NSSA */
|
||||
#define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
|
||||
#define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
|
||||
#define OPT_R 0x0010 /* OSPFv3, originator is active router */
|
||||
#define OPT_DC 0x0020 /* Related to demand circuits, not used */
|
||||
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
|
||||
|
||||
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
|
||||
#define OPT_RT_B (0x01 << 24)
|
||||
@ -718,74 +724,96 @@ lsa_net_count(struct ospf_lsa_header *lsa)
|
||||
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
|
||||
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
|
||||
|
||||
/* FIXME: these functions should be significantly redesigned w.r.t. integration,
|
||||
also should be named as ospf3_* instead of *_ipv6_* */
|
||||
|
||||
static inline int
|
||||
ospf_valid_prefix(net_addr *n)
|
||||
{
|
||||
/* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for invalid one */
|
||||
return n->pxlen <= IP6_MAX_PREFIX_LENGTH;
|
||||
/*
|
||||
* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for
|
||||
* invalid one. But OSPFv3-AF may receive IPv4 net with 32 < pxlen < 128.
|
||||
*/
|
||||
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
|
||||
return n->pxlen <= max;
|
||||
}
|
||||
|
||||
/*
|
||||
* In OSPFv3-AF (RFC 5835), IPv4 address is encoded by just placing it in the
|
||||
* first 32 bits of IPv6 address and setting remaining bits to zero. Likewise
|
||||
* for IPv4 prefix, where remaining bits do not matter. We use following
|
||||
* functions to convert between IPv4 and IPv4-in-IPv6 representations:
|
||||
*/
|
||||
|
||||
static inline ip4_addr ospf3_6to4(ip6_addr a)
|
||||
{ return _MI4(_I0(a)); }
|
||||
|
||||
static inline ip6_addr ospf3_4to6(ip4_addr a)
|
||||
{ return _MI6(_I(a), 0, 0, 0); }
|
||||
|
||||
|
||||
static inline u32 *
|
||||
ospf_get_ipv6_prefix(u32 *buf, net_addr *N, u8 *pxopts, u16 *rest)
|
||||
ospf3_get_prefix(u32 *buf, int af, net_addr *n, u8 *pxopts, u16 *rest)
|
||||
{
|
||||
net_addr_ip6 *net = (void *) N;
|
||||
u8 pxlen = (*buf >> 24);
|
||||
ip6_addr px = IP6_NONE;
|
||||
uint pxlen = (*buf >> 24);
|
||||
*pxopts = (*buf >> 16) & 0xff;
|
||||
if (rest) *rest = *buf & 0xffff;
|
||||
buf++;
|
||||
|
||||
*net = NET_ADDR_IP6(IP6_NONE, pxlen);
|
||||
|
||||
if (pxlen > 0)
|
||||
_I0(net->prefix) = *buf++;
|
||||
_I0(px) = *buf++;
|
||||
if (pxlen > 32)
|
||||
_I1(net->prefix) = *buf++;
|
||||
_I1(px) = *buf++;
|
||||
if (pxlen > 64)
|
||||
_I2(net->prefix) = *buf++;
|
||||
_I2(px) = *buf++;
|
||||
if (pxlen > 96)
|
||||
_I3(net->prefix) = *buf++;
|
||||
_I3(px) = *buf++;
|
||||
|
||||
/* Clean up remaining bits */
|
||||
if (pxlen < 128)
|
||||
net->prefix.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
|
||||
px.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
|
||||
|
||||
if (af == NET_IP4)
|
||||
net_fill_ip4(n, ospf3_6to4(px), pxlen);
|
||||
else
|
||||
net_fill_ip6(n, px, pxlen);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline u32 *
|
||||
ospf_get_ipv6_addr(u32 *buf, ip_addr *addr)
|
||||
ospf3_put_prefix(u32 *buf, net_addr *n, u8 pxopts, u16 rest)
|
||||
{
|
||||
*addr = ipa_from_ip6(*(ip6_addr *) buf);
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
static inline u32 *
|
||||
ospf_put_ipv6_prefix(u32 *buf, net_addr *N, u8 pxopts, u16 rest)
|
||||
{
|
||||
net_addr_ip6 *net = (void *) N;
|
||||
u32 pxlen = net->pxlen;
|
||||
ip6_addr px = (n->type == NET_IP4) ? ospf3_4to6(net4_prefix(n)) : net6_prefix(n);
|
||||
uint pxlen = n->pxlen;
|
||||
|
||||
*buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
|
||||
|
||||
if (pxlen > 0)
|
||||
*buf++ = _I0(net->prefix);
|
||||
*buf++ = _I0(px);
|
||||
if (pxlen > 32)
|
||||
*buf++ = _I1(net->prefix);
|
||||
*buf++ = _I1(px);
|
||||
if (pxlen > 64)
|
||||
*buf++ = _I2(net->prefix);
|
||||
*buf++ = _I2(px);
|
||||
if (pxlen > 96)
|
||||
*buf++ = _I3(net->prefix);
|
||||
*buf++ = _I3(px);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static inline u32 *
|
||||
ospf_put_ipv6_addr(u32 *buf, ip_addr addr)
|
||||
ospf3_get_addr(u32 *buf, int af, ip_addr *addr)
|
||||
{
|
||||
*(ip6_addr *) buf = ipa_to_ip6(addr);
|
||||
ip6_addr a;
|
||||
memcpy(&a, buf, 16);
|
||||
*addr = (af == NET_IP4) ? ipa_from_ip4(ospf3_6to4(a)) : ipa_from_ip6(a);
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
static inline u32 *
|
||||
ospf3_put_addr(u32 *buf, ip_addr addr)
|
||||
{
|
||||
ip6_addr a = ipa_is_ip4(addr) ? ospf3_4to6(ipa_to_ip4(addr)) : ipa_to_ip6(addr);
|
||||
memcpy(buf, &a, 16);
|
||||
return buf + 4;
|
||||
}
|
||||
|
||||
@ -838,6 +866,15 @@ static inline int ospf_is_v3(struct ospf_proto *p)
|
||||
static inline int ospf_get_version(struct ospf_proto *p)
|
||||
{ return ospf_is_v2(p) ? 2 : 3; }
|
||||
|
||||
static inline int ospf_is_ip4(struct ospf_proto *p)
|
||||
{ return p->p.net_type == NET_IP4; }
|
||||
|
||||
static inline int ospf_is_ip6(struct ospf_proto *p)
|
||||
{ return p->p.net_type == NET_IP6; }
|
||||
|
||||
static inline int ospf_get_af(struct ospf_proto *p)
|
||||
{ return p->p.net_type; }
|
||||
|
||||
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
|
||||
|
||||
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)
|
||||
|
@ -77,16 +77,16 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
|
||||
reboot when system does not have independent RTC? */
|
||||
if (!ifa->csn)
|
||||
{
|
||||
ifa->csn = (u32) now;
|
||||
ifa->csn_use = now;
|
||||
ifa->csn = (u32) (current_real_time() TO_S);
|
||||
ifa->csn_use = current_time();
|
||||
}
|
||||
|
||||
/* We must have sufficient delay between sending a packet and increasing
|
||||
CSN to prevent reordering of packets (in a network) with different CSNs */
|
||||
if ((now - ifa->csn_use) > 1)
|
||||
if ((current_time() - ifa->csn_use) > 1 S)
|
||||
ifa->csn++;
|
||||
|
||||
ifa->csn_use = now;
|
||||
ifa->csn_use = current_time();
|
||||
|
||||
uint auth_len = mac_type_length(pass->alg);
|
||||
byte *auth_tail = ((byte *) pkt + *plen);
|
||||
@ -270,9 +270,6 @@ ospf_rx_hook(sock *sk, uint len)
|
||||
if (pkt == NULL)
|
||||
DROP("bad IP header", len);
|
||||
|
||||
if (ifa->check_ttl && (sk->rcv_ttl < 255))
|
||||
DROP("wrong TTL", sk->rcv_ttl);
|
||||
|
||||
if (len < sizeof(struct ospf_packet))
|
||||
DROP("too short", len);
|
||||
|
||||
@ -379,6 +376,10 @@ found:
|
||||
if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
|
||||
return 1;
|
||||
|
||||
/* TTL check must be done after instance dispatch */
|
||||
if (ifa->check_ttl && (sk->rcv_ttl < 255))
|
||||
DROP("wrong TTL", sk->rcv_ttl);
|
||||
|
||||
if (rid == p->router_id)
|
||||
DROP1("my own router ID");
|
||||
|
||||
|
139
proto/ospf/rt.c
139
proto/ospf/rt.c
@ -10,9 +10,7 @@
|
||||
|
||||
#include "ospf.h"
|
||||
|
||||
static void add_cand(list * l, struct top_hash_entry *en,
|
||||
struct top_hash_entry *par, u32 dist,
|
||||
struct ospf_area *oa, int i);
|
||||
static void add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, int i, uint lif, uint nif);
|
||||
static void rt_sync(struct ospf_proto *p);
|
||||
|
||||
|
||||
@ -509,7 +507,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
|
||||
break;
|
||||
}
|
||||
|
||||
add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i);
|
||||
add_cand(oa, tmp, act, act->dist + rtl.metric, i, rtl.lif, rtl.nif);
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,7 +530,7 @@ spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_ent
|
||||
for (i = 0; i < cnt; i++)
|
||||
{
|
||||
tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
|
||||
add_cand(&oa->cand, tmp, act, act->dist, oa, -1);
|
||||
add_cand(oa, tmp, act, act->dist, -1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -576,20 +574,20 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
|
||||
buf = px->rest;
|
||||
for (i = 0; i < px->pxcount; i++)
|
||||
{
|
||||
net_addr_ip6 net;
|
||||
net_addr net;
|
||||
u8 pxopts;
|
||||
u16 metric;
|
||||
|
||||
buf = ospf_get_ipv6_prefix(buf, (net_addr *) &net, &pxopts, &metric);
|
||||
buf = ospf3_get_prefix(buf, ospf_get_af(p), &net, &pxopts, &metric);
|
||||
|
||||
if (pxopts & OPT_PX_NU)
|
||||
continue;
|
||||
|
||||
/* Store the first global address to use it later as a vlink endpoint */
|
||||
if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb))
|
||||
src->lb = ipa_from_ip6(net.prefix);
|
||||
if ((pxopts & OPT_PX_LA) && (net.type == NET_IP6) && ipa_zero(src->lb))
|
||||
src->lb = ipa_from_ip6(net6_prefix(&net));
|
||||
|
||||
add_network(oa, (net_addr *) &net, src->dist + metric, src, i);
|
||||
add_network(oa, &net, src->dist + metric, src, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -651,7 +649,8 @@ ospf_rt_spfa(struct ospf_area *oa)
|
||||
}
|
||||
|
||||
static int
|
||||
link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par)
|
||||
link_back(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
struct top_hash_entry *par, uint lif, uint nif)
|
||||
{
|
||||
struct ospf_proto *p = oa->po;
|
||||
struct ospf_lsa_rt_walk rtl;
|
||||
@ -689,6 +688,10 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
|
||||
tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
|
||||
if (tmp == par)
|
||||
{
|
||||
/*
|
||||
* Note that there may be multiple matching Rt-fields if router 'en'
|
||||
* have multiple interfaces to net 'par'. Perhaps we should do ECMP.
|
||||
*/
|
||||
if (ospf_is_v2(p))
|
||||
en->lb = ipa_from_u32(rtl.data);
|
||||
else
|
||||
@ -700,7 +703,13 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
|
||||
|
||||
case LSART_VLNK:
|
||||
case LSART_PTP:
|
||||
/* Not necessary the same link, see RFC 2328 [23] */
|
||||
/*
|
||||
* For OSPFv2, not necessary the same link, see RFC 2328 [23].
|
||||
* For OSPFv3, we verify that by comparing nif and lif fields.
|
||||
*/
|
||||
if (ospf_is_v3(p) && ((rtl.lif != nif) || (rtl.nif != lif)))
|
||||
break;
|
||||
|
||||
tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
|
||||
if (tmp == par)
|
||||
return 1;
|
||||
@ -761,7 +770,7 @@ ospf_rt_sum(struct ospf_area *oa)
|
||||
|
||||
if (en->lsa_type == LSA_T_SUM_NET)
|
||||
{
|
||||
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
|
||||
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
|
||||
|
||||
if (!ospf_valid_prefix(&net))
|
||||
{
|
||||
@ -858,7 +867,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
|
||||
net_addr net;
|
||||
u8 pxopts;
|
||||
|
||||
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric);
|
||||
lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
|
||||
|
||||
if (!ospf_valid_prefix(&net))
|
||||
{
|
||||
@ -1058,7 +1067,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt)
|
||||
return 0;
|
||||
|
||||
/* We do not store needed data in struct orta, we have to parse the LSA */
|
||||
lsa_parse_ext(en, ospf_is_v2(p), rt);
|
||||
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), rt);
|
||||
|
||||
if (rt->pxopts & OPT_PX_NU)
|
||||
return 0;
|
||||
@ -1320,10 +1329,10 @@ ospf_rt_abr2(struct ospf_proto *p)
|
||||
if (!translate && (oa->translate == TRANS_ON))
|
||||
{
|
||||
if (oa->translator_timer == NULL)
|
||||
oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0);
|
||||
oa->translator_timer = tm_new_init(p->p.pool, translator_timer_hook, oa, 0, 0);
|
||||
|
||||
/* Schedule the end of translation */
|
||||
tm_start(oa->translator_timer, oa->ac->transint);
|
||||
tm_start(oa->translator_timer, oa->ac->transint S);
|
||||
oa->translate = TRANS_WAIT;
|
||||
}
|
||||
}
|
||||
@ -1450,7 +1459,7 @@ ospf_ext_spf(struct ospf_proto *p)
|
||||
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
|
||||
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
|
||||
|
||||
lsa_parse_ext(en, ospf_is_v2(p), &rt);
|
||||
lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), &rt);
|
||||
|
||||
if (!ospf_valid_prefix(&rt.net))
|
||||
{
|
||||
@ -1679,13 +1688,27 @@ inherit_nexthops(struct nexthop *pn)
|
||||
return pn && (ipa_nonzero(pn->gw) || !pn->iface);
|
||||
}
|
||||
|
||||
static inline ip_addr
|
||||
link_lsa_lladdr(struct ospf_proto *p, struct top_hash_entry *en)
|
||||
{
|
||||
struct ospf_lsa_link *link_lsa = en->lsa_body;
|
||||
ip6_addr ll = link_lsa->lladdr;
|
||||
|
||||
if (ip6_zero(ll))
|
||||
return IPA_NONE;
|
||||
|
||||
return ospf_is_ip4(p) ? ipa_from_ip4(ospf3_6to4(ll)) : ipa_from_ip6(ll);
|
||||
}
|
||||
|
||||
static struct nexthop *
|
||||
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
struct top_hash_entry *par, int pos)
|
||||
struct top_hash_entry *par, int pos, uint lif, uint nif)
|
||||
{
|
||||
struct ospf_proto *p = oa->po;
|
||||
struct nexthop *pn = par->nhs;
|
||||
struct ospf_iface *ifa;
|
||||
struct top_hash_entry *link = NULL;
|
||||
struct ospf_iface *ifa = NULL;
|
||||
ip_addr nh = IPA_NONE;
|
||||
u32 rid = en->lsa.rt;
|
||||
|
||||
/* 16.1.1. The next hop calculation */
|
||||
@ -1710,6 +1733,9 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
if (!ifa)
|
||||
return NULL;
|
||||
|
||||
if (ospf_is_v3(p) && (ifa->iface_id != lif))
|
||||
log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
|
||||
|
||||
return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight);
|
||||
}
|
||||
|
||||
@ -1720,14 +1746,44 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
if (!ifa)
|
||||
return NULL;
|
||||
|
||||
if (ospf_is_v3(p) && (ifa->iface_id != lif))
|
||||
log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
|
||||
|
||||
if (ifa->type == OSPF_IT_VLINK)
|
||||
return new_nexthop(p, IPA_NONE, NULL, 0);
|
||||
|
||||
struct ospf_neighbor *m = find_neigh(ifa, rid);
|
||||
if (!m || (m->state != NEIGHBOR_FULL))
|
||||
return NULL;
|
||||
/* FIXME: On physical PtP links we may skip next-hop altogether */
|
||||
|
||||
return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight);
|
||||
if (ospf_is_v2(p) || ospf_is_ip6(p))
|
||||
{
|
||||
/*
|
||||
* In this case, next-hop is a source address from neighbor's packets.
|
||||
* That is necessary for OSPFv2 and practical for OSPFv3 (as it works even
|
||||
* if neighbor uses LinkLSASuppression), but does not work with OSPFv3-AF
|
||||
* on IPv4 topology, where src is IPv6 but next-hop should be IPv4.
|
||||
*/
|
||||
struct ospf_neighbor *m = find_neigh(ifa, rid);
|
||||
if (!m || (m->state != NEIGHBOR_FULL))
|
||||
return NULL;
|
||||
|
||||
nh = m->ip;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Next-hop is taken from lladdr field of Link-LSA, based on Neighbor
|
||||
* Iface ID (nif) field in our Router-LSA, which is just nbr->iface_id.
|
||||
*/
|
||||
link = ospf_hash_find(p->gr, ifa->iface_id, nif, rid, LSA_T_LINK);
|
||||
if (!link)
|
||||
return NULL;
|
||||
|
||||
nh = link_lsa_lladdr(p, link);
|
||||
if (ipa_zero(nh))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
|
||||
}
|
||||
|
||||
/* The third case - bcast or nbma neighbor */
|
||||
@ -1754,18 +1810,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
* Next-hop is taken from lladdr field of Link-LSA, en->lb_id
|
||||
* is computed in link_back().
|
||||
*/
|
||||
struct top_hash_entry *lhe;
|
||||
lhe = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
|
||||
|
||||
if (!lhe)
|
||||
link = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
|
||||
if (!link)
|
||||
return NULL;
|
||||
|
||||
struct ospf_lsa_link *llsa = lhe->lsa_body;
|
||||
|
||||
if (ip6_zero(llsa->lladdr))
|
||||
nh = link_lsa_lladdr(p, link);
|
||||
if (ipa_zero(nh))
|
||||
return NULL;
|
||||
|
||||
return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight);
|
||||
return new_nexthop(p, nh, pn->iface, pn->weight);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1778,8 +1831,8 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
|
||||
|
||||
/* Add LSA into list of candidates in Dijkstra's algorithm */
|
||||
static void
|
||||
add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
u32 dist, struct ospf_area *oa, int pos)
|
||||
add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
u32 dist, int pos, uint lif, uint nif)
|
||||
{
|
||||
struct ospf_proto *p = oa->po;
|
||||
node *prev, *n;
|
||||
@ -1792,9 +1845,9 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
if (en->lsa.age == LSA_MAXAGE)
|
||||
return;
|
||||
|
||||
if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT))
|
||||
if (ospf_is_v3(p) && (oa->options & OPT_V6) && (en->lsa_type == LSA_T_RT))
|
||||
{
|
||||
/* In OSPFv3, check V6 flag */
|
||||
/* In OSPFv3 IPv6 unicast, check V6 flag */
|
||||
struct ospf_lsa_rt *rt = en->lsa_body;
|
||||
if (!(rt->options & OPT_V6))
|
||||
return;
|
||||
@ -1809,10 +1862,10 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
return;
|
||||
|
||||
/* We should check whether there is a reverse link from en to par, */
|
||||
if (!link_back(oa, en, par))
|
||||
if (!link_back(oa, en, par, lif, nif))
|
||||
return;
|
||||
|
||||
struct nexthop *nhs = calc_next_hop(oa, en, par, pos);
|
||||
struct nexthop *nhs = calc_next_hop(oa, en, par, pos, lif, nif);
|
||||
if (!nhs)
|
||||
{
|
||||
log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
|
||||
@ -1869,20 +1922,20 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
|
||||
prev = NULL;
|
||||
|
||||
if (EMPTY_LIST(*l))
|
||||
if (EMPTY_LIST(oa->cand))
|
||||
{
|
||||
add_head(l, &en->cn);
|
||||
add_head(&oa->cand, &en->cn);
|
||||
}
|
||||
else
|
||||
{
|
||||
WALK_LIST(n, *l)
|
||||
WALK_LIST(n, oa->cand)
|
||||
{
|
||||
act = SKIP_BACK(struct top_hash_entry, cn, n);
|
||||
if ((act->dist > dist) ||
|
||||
((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
|
||||
{
|
||||
if (prev == NULL)
|
||||
add_head(l, &en->cn);
|
||||
add_head(&oa->cand, &en->cn);
|
||||
else
|
||||
insert_node(&en->cn, prev);
|
||||
added = 1;
|
||||
@ -1893,7 +1946,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
|
||||
|
||||
if (!added)
|
||||
{
|
||||
add_tail(l, &en->cn);
|
||||
add_tail(&oa->cand, &en->cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
|
||||
en->lsa_body = body;
|
||||
en->lsa = *lsa;
|
||||
en->init_age = en->lsa.age;
|
||||
en->inst_time = now;
|
||||
en->inst_time = current_time();
|
||||
|
||||
/*
|
||||
* We do not set en->mode. It is either default LSA_M_BASIC, or in a special
|
||||
@ -128,7 +128,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||
en->lsa.sn = lsa->sn + 1;
|
||||
en->lsa.age = 0;
|
||||
en->init_age = 0;
|
||||
en->inst_time = now;
|
||||
en->inst_time = current_time();
|
||||
lsa_generate_checksum(&en->lsa, en->lsa_body);
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||
@ -160,7 +160,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
|
||||
en->lsa = *lsa;
|
||||
en->lsa.age = LSA_MAXAGE;
|
||||
en->init_age = lsa->age;
|
||||
en->inst_time = now;
|
||||
en->inst_time = current_time();
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
|
||||
@ -196,7 +196,7 @@ static int
|
||||
ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa_body, u16 lsa_blen, u16 lsa_opts)
|
||||
{
|
||||
/* Enforce MinLSInterval */
|
||||
if ((en->init_age == 0) && en->inst_time && ((en->inst_time + MINLSINTERVAL) > now))
|
||||
if (!en->init_age && en->inst_time && (lsa_inst_age(en) < MINLSINTERVAL))
|
||||
return 0;
|
||||
|
||||
/* Handle wrapping sequence number */
|
||||
@ -237,7 +237,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
|
||||
en->lsa.sn++;
|
||||
en->lsa.age = 0;
|
||||
en->init_age = 0;
|
||||
en->inst_time = now;
|
||||
en->inst_time = current_time();
|
||||
lsa_generate_checksum(&en->lsa, en->lsa_body);
|
||||
|
||||
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
|
||||
@ -381,7 +381,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
|
||||
en->lsa.sn++;
|
||||
en->lsa.age = 0;
|
||||
en->init_age = 0;
|
||||
en->inst_time = now;
|
||||
en->inst_time = current_time();
|
||||
lsa_generate_checksum(&en->lsa, en->lsa_body);
|
||||
ospf_flood_lsa(p, en, NULL);
|
||||
}
|
||||
@ -476,14 +476,15 @@ void
|
||||
ospf_update_lsadb(struct ospf_proto *p)
|
||||
{
|
||||
struct top_hash_entry *en, *nxt;
|
||||
bird_clock_t real_age;
|
||||
btime now_ = current_time();
|
||||
int real_age;
|
||||
|
||||
WALK_SLIST_DELSAFE(en, nxt, p->lsal)
|
||||
{
|
||||
if (en->next_lsa_body)
|
||||
ospf_originate_next_lsa(p, en);
|
||||
|
||||
real_age = en->init_age + (now - en->inst_time);
|
||||
real_age = en->init_age + (now_ - en->inst_time) TO_S;
|
||||
|
||||
if (en->lsa.age == LSA_MAXAGE)
|
||||
{
|
||||
@ -1008,7 +1009,7 @@ prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
|
||||
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
|
||||
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
|
||||
sum->metric = metric;
|
||||
ospf_put_ipv6_prefix(sum->prefix, nf->fn.addr, 0, 0);
|
||||
ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1097,7 +1098,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||
ext->metric = metric & LSA_METRIC_MASK;
|
||||
u32 *buf = ext->rest;
|
||||
|
||||
buf = ospf_put_ipv6_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
|
||||
buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
|
||||
|
||||
if (ebit)
|
||||
ext->metric |= LSA_EXT3_EBIT;
|
||||
@ -1105,7 +1106,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
|
||||
if (ipa_nonzero(fwaddr))
|
||||
{
|
||||
ext->metric |= LSA_EXT3_FBIT;
|
||||
buf = ospf_put_ipv6_addr(buf, fwaddr);
|
||||
buf = ospf3_put_addr(buf, fwaddr);
|
||||
}
|
||||
|
||||
if (tag)
|
||||
@ -1222,7 +1223,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
|
||||
{
|
||||
WALK_LIST(a, ifa->iface->addrs)
|
||||
{
|
||||
if ((a->prefix.type != NET_IP6) ||
|
||||
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||
(a->flags & IA_SECONDARY) ||
|
||||
(a->flags & IA_PEER) ||
|
||||
(a->scope <= SCOPE_LINK))
|
||||
@ -1316,39 +1317,47 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
|
||||
*/
|
||||
|
||||
static inline void
|
||||
lsab_put_prefix(struct ospf_proto *p, net_addr *net, u32 cost)
|
||||
lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
|
||||
{
|
||||
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net6_pxlen(net)));
|
||||
u8 flags = (net6_pxlen(net) < IP6_MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA;
|
||||
ospf_put_ipv6_prefix(buf, net, flags, cost);
|
||||
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
|
||||
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
|
||||
u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
|
||||
ospf3_put_prefix(buf, n, flags, cost);
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||
{
|
||||
struct ospf_lsa_link *ll;
|
||||
ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
|
||||
int i = 0;
|
||||
|
||||
/* Preallocating space for header */
|
||||
ASSERT(p->lsab_used == 0);
|
||||
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
||||
ll->options = ifa->oa->options | (ifa->priority << 24);
|
||||
ll->lladdr = ipa_to_ip6(ifa->addr->ip);
|
||||
ll = NULL; /* buffer might be reallocated later */
|
||||
lsab_allocz(p, sizeof(struct ospf_lsa_link));
|
||||
|
||||
struct ifa *a;
|
||||
WALK_LIST(a, ifa->iface->addrs)
|
||||
{
|
||||
if ((a->prefix.type != NET_IP6) ||
|
||||
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||
(a->flags & IA_SECONDARY) ||
|
||||
(a->scope <= SCOPE_LINK))
|
||||
continue;
|
||||
|
||||
if (ospf_is_ip4(p) && ipa_zero(nh))
|
||||
nh = a->ip;
|
||||
|
||||
lsab_put_prefix(p, &a->prefix, 0);
|
||||
i++;
|
||||
}
|
||||
|
||||
ll = p->lsab;
|
||||
/* Filling the preallocated header */
|
||||
struct ospf_lsa_link *ll = p->lsab;
|
||||
ll->options = ifa->oa->options | (ifa->priority << 24);
|
||||
ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
|
||||
ll->pxcount = i;
|
||||
|
||||
if (ipa_zero(nh))
|
||||
log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1410,7 +1419,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
|
||||
struct ifa *a;
|
||||
WALK_LIST(a, ifa->iface->addrs)
|
||||
{
|
||||
if ((a->prefix.type != NET_IP6) ||
|
||||
if ((a->prefix.type != ospf_get_af(p)) ||
|
||||
(a->flags & IA_SECONDARY) ||
|
||||
(a->flags & IA_PEER) ||
|
||||
(a->scope <= SCOPE_LINK))
|
||||
@ -1448,7 +1457,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
|
||||
|
||||
/* If there are some configured vlinks, find some global address
|
||||
(even from another area), which will be used as a vlink endpoint. */
|
||||
if (!EMPTY_LIST(cf->vlink_list) && !host_addr)
|
||||
if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
|
||||
{
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
{
|
||||
@ -1571,7 +1580,7 @@ add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *px
|
||||
continue;
|
||||
|
||||
/* Skip link-local prefixes */
|
||||
if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
|
||||
if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
|
||||
continue;
|
||||
|
||||
add_prefix(p, pxb, offset, pxc);
|
||||
@ -1628,7 +1637,7 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
|
||||
}
|
||||
|
||||
static inline int breaks_minlsinterval(struct top_hash_entry *en)
|
||||
{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); }
|
||||
{ return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); }
|
||||
|
||||
void
|
||||
ospf_update_topology(struct ospf_proto *p)
|
||||
|
@ -26,7 +26,7 @@ struct top_hash_entry
|
||||
void *next_lsa_body; /* For postponed LSA origination */
|
||||
u16 next_lsa_blen; /* For postponed LSA origination */
|
||||
u16 next_lsa_opts; /* For postponed LSA origination */
|
||||
bird_clock_t inst_time; /* Time of installation into DB */
|
||||
btime inst_time; /* Time of installation into DB */
|
||||
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
|
||||
struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
|
||||
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
|
||||
|
@ -27,10 +27,13 @@ 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)
|
||||
LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE,
|
||||
ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME)
|
||||
|
||||
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
|
||||
|
||||
%type<i> radv_mult radv_sensitive radv_preference
|
||||
|
||||
@ -56,6 +59,7 @@ radv_proto_item:
|
||||
| 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); }
|
||||
| TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
|
||||
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
|
||||
;
|
||||
|
||||
radv_proto_opts:
|
||||
@ -76,13 +80,18 @@ radv_iface_start:
|
||||
init_list(&RADV_IFACE->rdnss_list);
|
||||
init_list(&RADV_IFACE->dnssl_list);
|
||||
|
||||
RADV_IFACE->min_ra_int = -1; /* undefined */
|
||||
RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
|
||||
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
|
||||
RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
|
||||
RADV_IFACE->prefix_linger_time = (u32) -1;
|
||||
RADV_IFACE->route_linger_time = (u32) -1;
|
||||
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
|
||||
RADV_IFACE->default_lifetime = -1;
|
||||
RADV_IFACE->default_lifetime = (u32) -1;
|
||||
RADV_IFACE->default_lifetime_sensitive = 1;
|
||||
RADV_IFACE->default_preference = RA_PREF_MEDIUM;
|
||||
RADV_IFACE->route_lifetime = (u32) -1;
|
||||
RADV_IFACE->route_lifetime_sensitive = 0;
|
||||
RADV_IFACE->route_preference = RA_PREF_MEDIUM;
|
||||
};
|
||||
|
||||
radv_iface_item:
|
||||
@ -100,7 +109,14 @@ radv_iface_item:
|
||||
if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000");
|
||||
if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
|
||||
}
|
||||
| ROUTE LIFETIME expr radv_sensitive {
|
||||
RADV_IFACE->route_lifetime = $3;
|
||||
if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4;
|
||||
}
|
||||
| DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
|
||||
| ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; }
|
||||
| PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; }
|
||||
| ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; }
|
||||
| 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); }
|
||||
@ -123,12 +139,32 @@ radv_iface_finish:
|
||||
if (ic->default_lifetime == (u32) -1)
|
||||
ic->default_lifetime = 3 * ic->max_ra_int;
|
||||
|
||||
if (ic->route_lifetime == (u32) -1)
|
||||
ic->route_lifetime = 3 * ic->max_ra_int;
|
||||
|
||||
if (ic->prefix_linger_time == (u32) -1)
|
||||
ic->prefix_linger_time = 3 * ic->max_ra_int;
|
||||
|
||||
if (ic->route_linger_time == (u32) -1)
|
||||
ic->route_linger_time = 3 * ic->max_ra_int;
|
||||
|
||||
if ((ic->min_ra_int > 3) &&
|
||||
(ic->min_ra_int > (ic->max_ra_int * 3 / 4)))
|
||||
cf_error("Min RA interval must be at most 3/4 * Max RA interval");
|
||||
|
||||
if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int))
|
||||
cf_error("Default lifetime must be either 0 or at least Max RA interval");
|
||||
|
||||
if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int))
|
||||
cf_error("Route lifetime must be either 0 or at least Max RA interval");
|
||||
|
||||
if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int))
|
||||
cf_error("Prefix linger time must be either 0 or at least Max RA interval");
|
||||
|
||||
if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int))
|
||||
cf_error("Route linger time must be either 0 or at least Max RA interval");
|
||||
|
||||
RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time);
|
||||
};
|
||||
|
||||
|
||||
@ -292,10 +328,13 @@ radv_mult:
|
||||
;
|
||||
|
||||
radv_sensitive:
|
||||
/* empty */ { $$ = -1; }
|
||||
/* empty */ { $$ = (uint) -1; }
|
||||
| SENSITIVE bool { $$ = $2; }
|
||||
;
|
||||
|
||||
CF_ADDTO(dynamic_attr, RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); })
|
||||
CF_ADDTO(dynamic_attr, RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); })
|
||||
|
||||
CF_CODE
|
||||
|
||||
CF_END
|
||||
|
@ -26,6 +26,7 @@ struct radv_ra_packet
|
||||
|
||||
#define OPT_PREFIX 3
|
||||
#define OPT_MTU 5
|
||||
#define OPT_ROUTE 24
|
||||
#define OPT_RDNSS 25
|
||||
#define OPT_DNSSL 31
|
||||
|
||||
@ -52,6 +53,15 @@ struct radv_opt_mtu
|
||||
u32 mtu;
|
||||
};
|
||||
|
||||
struct radv_opt_route {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u8 pxlen;
|
||||
u8 flags;
|
||||
u32 lifetime;
|
||||
u8 prefix[];
|
||||
};
|
||||
|
||||
struct radv_opt_rdnss
|
||||
{
|
||||
u8 type;
|
||||
@ -70,34 +80,42 @@ 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)
|
||||
static int
|
||||
radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
|
||||
char **buf, char *bufend)
|
||||
{
|
||||
struct proto *p = &ifa->ra->p;
|
||||
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||
struct radv_prefix_config *pc;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
u8 px_blocks = (net6_pxlen(rt->n.addr) + 63) / 64;
|
||||
u8 opt_len = 8 * (1 + px_blocks);
|
||||
|
||||
if (a->scope <= SCOPE_LINK)
|
||||
return NULL;
|
||||
if (*buf + opt_len > bufend)
|
||||
{
|
||||
log(L_WARN, "%s: Too many RA options on interface %s",
|
||||
p->p.name, ifa->iface->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WALK_LIST(pc, ifa->cf->pref_list)
|
||||
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix))
|
||||
return pc;
|
||||
uint preference = rt->preference_set ? rt->preference : ifa->cf->route_preference;
|
||||
uint lifetime = rt->lifetime_set ? rt->lifetime : ifa->cf->route_lifetime;
|
||||
uint valid = rt->valid && p->valid && (p->active || !ifa->cf->route_lifetime_sensitive);
|
||||
|
||||
WALK_LIST(pc, cf->pref_list)
|
||||
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix))
|
||||
return pc;
|
||||
struct radv_opt_route *opt = (void *) *buf;
|
||||
*buf += opt_len;
|
||||
opt->type = OPT_ROUTE;
|
||||
opt->length = 1 + px_blocks;
|
||||
opt->pxlen = net6_pxlen(rt->n.addr);
|
||||
opt->flags = preference;
|
||||
opt->lifetime = valid ? htonl(lifetime) : 0;
|
||||
|
||||
return &default_prefix;
|
||||
/* Copy the relevant part of the prefix */
|
||||
ip6_addr px_addr = ip6_hton(net6_prefix(rt->n.addr));
|
||||
memcpy(opt->prefix, &px_addr, 8 * px_blocks);
|
||||
|
||||
/* Keeping track of first linger timeout */
|
||||
if (!rt->valid)
|
||||
ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time S);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -206,7 +224,7 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
|
||||
else
|
||||
op->lifetime = htonl(dcf->lifetime);
|
||||
|
||||
while(NODE_VALID(dcf) &&
|
||||
while(NODE_VALID(dcf) &&
|
||||
(dcf->lifetime == dcf_base->lifetime) &&
|
||||
(dcf->lifetime_mult == dcf_base->lifetime_mult))
|
||||
{
|
||||
@ -234,12 +252,47 @@ 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);
|
||||
|
||||
/* Keeping track of first linger timeout */
|
||||
if (!px->valid)
|
||||
ifa->valid_time = MIN(ifa->valid_time, px->changed + ifa->cf->prefix_linger_time S);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
radv_prepare_ra(struct radv_iface *ifa)
|
||||
{
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
|
||||
struct radv_proto *p = ifa->ra;
|
||||
struct radv_config *cf = (struct radv_config *) (p->p.cf);
|
||||
struct radv_iface_config *ic = ifa->cf;
|
||||
btime now = current_time();
|
||||
|
||||
char *buf = ifa->sk->tbuf;
|
||||
char *bufstart = buf;
|
||||
@ -250,7 +303,7 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||
pkt->code = 0;
|
||||
pkt->checksum = 0;
|
||||
pkt->current_hop_limit = ic->current_hop_limit;
|
||||
pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ?
|
||||
pkt->router_lifetime = (p->valid && (p->active || !ic->default_lifetime_sensitive)) ?
|
||||
htons(ic->default_lifetime) : 0;
|
||||
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
|
||||
(ic->other_config ? OPT_RA_OTHER_CFG : 0) |
|
||||
@ -269,37 +322,18 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||
buf += sizeof (*om);
|
||||
}
|
||||
|
||||
struct ifa *addr;
|
||||
WALK_LIST(addr, ifa->iface->addrs)
|
||||
/* Keeping track of first linger timeout */
|
||||
ifa->valid_time = TIME_INFINITY;
|
||||
|
||||
struct radv_prefix *px;
|
||||
WALK_LIST(px, ifa->prefixes)
|
||||
{
|
||||
if (addr->prefix.type != NET_IP6)
|
||||
continue;
|
||||
/* Skip invalid prefixes that are past linger timeout but still not pruned */
|
||||
if (!px->valid && ((px->changed + ic->prefix_linger_time S) <= now))
|
||||
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", ra->p.name, ifa->iface->name);
|
||||
if (radv_prepare_prefix(ifa, px, &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 = (ra->active || !pc->valid_lifetime_sensitive) ?
|
||||
htonl(pc->valid_lifetime) : 0;
|
||||
op->preferred_lifetime = (ra->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)
|
||||
@ -316,33 +350,34 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
|
||||
goto done;
|
||||
|
||||
if (p->fib_up)
|
||||
{
|
||||
FIB_WALK(&p->routes, struct radv_route, rt)
|
||||
{
|
||||
/* Skip invalid routes that are past linger timeout but still not pruned */
|
||||
if (!rt->valid && ((rt->changed + ic->route_linger_time S) <= now))
|
||||
continue;
|
||||
|
||||
if (radv_prepare_route(ifa, rt, &buf, bufend) < 0)
|
||||
goto done;
|
||||
}
|
||||
FIB_WALK_END;
|
||||
}
|
||||
|
||||
done:
|
||||
ifa->plen = buf - bufstart;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
radv_send_ra(struct radv_iface *ifa, int shutdown)
|
||||
radv_send_ra(struct radv_iface *ifa)
|
||||
{
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
|
||||
/* We store prepared RA in tbuf */
|
||||
if (!ifa->plen)
|
||||
radv_prepare_ra(ifa);
|
||||
|
||||
if (shutdown)
|
||||
{
|
||||
/*
|
||||
* Modify router lifetime to 0, it is not restored because we suppose that
|
||||
* the iface will be removed. The preference value also has to be zeroed.
|
||||
* (RFC 4191 2.2: If router lifetime is 0, the preference value must be 0.)
|
||||
*/
|
||||
|
||||
struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf;
|
||||
pkt->router_lifetime = 0;
|
||||
pkt->flags &= ~RA_PREF_MASK;
|
||||
}
|
||||
|
||||
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
||||
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
|
||||
}
|
||||
@ -352,13 +387,13 @@ static int
|
||||
radv_rx_hook(sock *sk, uint size)
|
||||
{
|
||||
struct radv_iface *ifa = sk->data;
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
|
||||
/* We want just packets from sk->iface */
|
||||
if (sk->lifindex != sk->iface->index)
|
||||
return 1;
|
||||
|
||||
if (ipa_equal(sk->faddr, ifa->addr->ip))
|
||||
if (ipa_equal(sk->faddr, sk->saddr))
|
||||
return 1;
|
||||
|
||||
if (size < 8)
|
||||
@ -408,11 +443,12 @@ 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;
|
||||
sk->saddr = ifa->addr->ip;
|
||||
sk->vrf = ifa->ra->p.vrf;
|
||||
|
||||
sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
|
||||
sk->rx_hook = radv_rx_hook;
|
||||
|
@ -12,59 +12,206 @@
|
||||
/**
|
||||
* DOC: Router Advertisements
|
||||
*
|
||||
* The RAdv protocol is implemented in two files: |radv.c| containing
|
||||
* the interface with BIRD core and the protocol logic and |packets.c|
|
||||
* handling low level protocol stuff (RX, TX and packet formats).
|
||||
* The protocol does not export any routes.
|
||||
* The RAdv protocol is implemented in two files: |radv.c| containing the
|
||||
* interface with BIRD core and the protocol logic and |packets.c| handling low
|
||||
* level protocol stuff (RX, TX and packet formats). The protocol does not
|
||||
* export any routes.
|
||||
*
|
||||
* The RAdv is structured in the usual way - for each handled interface
|
||||
* there is a structure &radv_iface that contains a state related to
|
||||
* that interface together with its resources (a socket, a timer).
|
||||
* There is also a prepared RA stored in a TX buffer of the socket
|
||||
* associated with an iface. These iface structures are created
|
||||
* and removed according to iface events from BIRD core handled by
|
||||
* radv_if_notify() callback.
|
||||
* The RAdv is structured in the usual way - for each handled interface there is
|
||||
* a structure &radv_iface that contains a state related to that interface
|
||||
* together with its resources (a socket, a timer). There is also a prepared RA
|
||||
* stored in a TX buffer of the socket associated with an iface. These iface
|
||||
* structures are created and removed according to iface events from BIRD core
|
||||
* handled by radv_if_notify() callback.
|
||||
*
|
||||
* The main logic of RAdv consists of two functions:
|
||||
* radv_iface_notify(), which processes asynchronous events (specified
|
||||
* by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
|
||||
* computes the next timeout.
|
||||
* The main logic of RAdv consists of two functions: radv_iface_notify(), which
|
||||
* processes asynchronous events (specified by RA_EV_* codes), and radv_timer(),
|
||||
* which triggers sending RAs and computes the next timeout.
|
||||
*
|
||||
* The RAdv protocol could receive routes (through
|
||||
* radv_import_control() and radv_rt_notify()), but only the
|
||||
* configured trigger route is tracked (in &active var). When a radv
|
||||
* protocol is reconfigured, the connected routing table is examined
|
||||
* (in radv_check_active()) to have proper &active value in case of
|
||||
* the specified trigger prefix was changed.
|
||||
* The RAdv protocol could receive routes (through radv_import_control() and
|
||||
* radv_rt_notify()), but only the configured trigger route is tracked (in
|
||||
* &active var). When a radv protocol is reconfigured, the connected routing
|
||||
* table is examined (in radv_check_active()) to have proper &active value in
|
||||
* case of the specified trigger prefix was changed.
|
||||
*
|
||||
* Supported standards:
|
||||
* - RFC 4861 - main RA standard
|
||||
* - RFC 4191 - Default Router Preferences and More-Specific Routes
|
||||
* - RFC 6106 - DNS extensions (RDDNS, DNSSL)
|
||||
* - RFC 4191 (partial) - Default Router Preference
|
||||
*/
|
||||
|
||||
static void radv_prune_prefixes(struct radv_iface *ifa);
|
||||
static void radv_prune_routes(struct radv_proto *p);
|
||||
|
||||
/* Invalidate cached RA packet */
|
||||
static inline void radv_invalidate(struct radv_iface *ifa)
|
||||
{ ifa->plen = 0; }
|
||||
|
||||
static void
|
||||
radv_timer(timer *tm)
|
||||
{
|
||||
struct radv_iface *ifa = tm->data;
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
btime now = current_time();
|
||||
|
||||
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
|
||||
|
||||
radv_send_ra(ifa, 0);
|
||||
if (ifa->valid_time <= now)
|
||||
radv_invalidate(ifa);
|
||||
|
||||
if (ifa->prune_time <= now)
|
||||
radv_prune_prefixes(ifa);
|
||||
|
||||
if (p->prune_time <= now)
|
||||
radv_prune_routes(p);
|
||||
|
||||
radv_send_ra(ifa);
|
||||
|
||||
/* Update timer */
|
||||
ifa->last = now;
|
||||
unsigned after = ifa->cf->min_ra_int;
|
||||
after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1);
|
||||
btime t = ifa->cf->min_ra_int S;
|
||||
btime r = (ifa->cf->max_ra_int - ifa->cf->min_ra_int) S;
|
||||
t += random() % (r + 1);
|
||||
|
||||
if (ifa->initial)
|
||||
{
|
||||
t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL);
|
||||
ifa->initial--;
|
||||
}
|
||||
|
||||
if (ifa->initial)
|
||||
after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL);
|
||||
tm_start(ifa->timer, t);
|
||||
}
|
||||
|
||||
tm_start(ifa->timer, after);
|
||||
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_prefix *pfx, *next;
|
||||
btime now = current_time();
|
||||
|
||||
/* 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->valid = 1;
|
||||
existing->changed = now;
|
||||
existing->mark = 1;
|
||||
existing->cf = pc;
|
||||
}
|
||||
|
||||
WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
|
||||
{
|
||||
if (pfx->valid && !pfx->mark)
|
||||
{
|
||||
RADV_TRACE(D_EVENTS, "Invalidating prefix %N on %s",
|
||||
pfx->prefix, ifa->iface->name);
|
||||
|
||||
pfx->valid = 0;
|
||||
pfx->changed = now;
|
||||
pfx->cf = &dead_prefix;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
radv_prune_prefixes(struct radv_iface *ifa)
|
||||
{
|
||||
struct radv_proto *p = ifa->ra;
|
||||
btime now = current_time();
|
||||
btime next = TIME_INFINITY;
|
||||
btime expires = 0;
|
||||
|
||||
struct radv_prefix *px, *pxn;
|
||||
WALK_LIST_DELSAFE(px, pxn, ifa->prefixes)
|
||||
{
|
||||
if (!px->valid)
|
||||
{
|
||||
expires = px->changed + ifa->cf->prefix_linger_time S;
|
||||
|
||||
if (expires <= now)
|
||||
{
|
||||
RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
|
||||
px->prefix, ifa->iface->name);
|
||||
|
||||
rem_node(NODE px);
|
||||
mb_free(px);
|
||||
}
|
||||
else
|
||||
next = MIN(next, expires);
|
||||
}
|
||||
}
|
||||
|
||||
ifa->prune_time = next;
|
||||
}
|
||||
|
||||
static char* ev_name[] = { NULL, "Init", "Change", "RS" };
|
||||
@ -72,7 +219,7 @@ static char* ev_name[] = { NULL, "Init", "Change", "RS" };
|
||||
void
|
||||
radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
{
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
|
||||
if (!ifa->sk)
|
||||
return;
|
||||
@ -82,9 +229,11 @@ radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
switch (event)
|
||||
{
|
||||
case RA_EV_CHANGE:
|
||||
ifa->plen = 0;
|
||||
radv_invalidate(ifa);
|
||||
case RA_EV_INIT:
|
||||
ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
|
||||
radv_prepare_prefixes(ifa);
|
||||
radv_prune_prefixes(ifa);
|
||||
break;
|
||||
|
||||
case RA_EV_RS:
|
||||
@ -92,31 +241,25 @@ radv_iface_notify(struct radv_iface *ifa, int event)
|
||||
}
|
||||
|
||||
/* Update timer */
|
||||
unsigned delta = now - ifa->last;
|
||||
unsigned after = 0;
|
||||
|
||||
if (delta < ifa->cf->min_delay)
|
||||
after = ifa->cf->min_delay - delta;
|
||||
|
||||
tm_start(ifa->timer, after);
|
||||
btime t = ifa->last + ifa->cf->min_delay S - current_time();
|
||||
tm_start(ifa->timer, t);
|
||||
}
|
||||
|
||||
static void
|
||||
radv_iface_notify_all(struct proto_radv *ra, int event)
|
||||
radv_iface_notify_all(struct radv_proto *p, int event)
|
||||
{
|
||||
struct radv_iface *ifa;
|
||||
|
||||
WALK_LIST(ifa, ra->iface_list)
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
radv_iface_notify(ifa, event);
|
||||
}
|
||||
|
||||
|
||||
static struct radv_iface *
|
||||
radv_iface_find(struct proto_radv *ra, struct iface *what)
|
||||
radv_iface_find(struct radv_proto *p, struct iface *what)
|
||||
{
|
||||
struct radv_iface *ifa;
|
||||
|
||||
WALK_LIST(ifa, ra->iface_list)
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
if (ifa->iface == what)
|
||||
return ifa;
|
||||
|
||||
@ -127,59 +270,39 @@ static void
|
||||
radv_iface_add(struct object_lock *lock)
|
||||
{
|
||||
struct radv_iface *ifa = lock->data;
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
|
||||
if (! radv_sk_open(ifa))
|
||||
{
|
||||
log(L_ERR "%s: Socket open failed on interface %s", ra->p.name, ifa->iface->name);
|
||||
log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
|
||||
return;
|
||||
}
|
||||
|
||||
radv_iface_notify(ifa, RA_EV_INIT);
|
||||
}
|
||||
|
||||
static inline struct ifa *
|
||||
find_lladdr(struct iface *iface)
|
||||
{
|
||||
struct ifa *a;
|
||||
WALK_LIST(a, iface->addrs)
|
||||
if ((a->prefix.type == NET_IP6) && (a->scope == SCOPE_LINK))
|
||||
return a;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_config *cf)
|
||||
radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
|
||||
{
|
||||
pool *pool = ra->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->ra = ra;
|
||||
ifa->pool = pool;
|
||||
ifa->ra = p;
|
||||
ifa->cf = cf;
|
||||
ifa->iface = iface;
|
||||
ifa->addr = iface->llv6;
|
||||
init_list(&ifa->prefixes);
|
||||
ifa->prune_time = TIME_INFINITY;
|
||||
|
||||
add_tail(&ra->iface_list, NODE ifa);
|
||||
add_tail(&p->iface_list, NODE ifa);
|
||||
|
||||
ifa->addr = find_lladdr(iface);
|
||||
if (!ifa->addr)
|
||||
{
|
||||
log(L_ERR "%s: Cannot find link-locad addr on interface %s", ra->p.name, iface->name);
|
||||
return;
|
||||
}
|
||||
|
||||
timer *tm = tm_new(pool);
|
||||
tm->hook = radv_timer;
|
||||
tm->data = ifa;
|
||||
tm->randomize = 0;
|
||||
tm->recurrent = 0;
|
||||
ifa->timer = tm;
|
||||
ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
|
||||
|
||||
struct object_lock *lock = olock_new(pool);
|
||||
lock->addr = IPA_NONE;
|
||||
lock->type = OBJLOCK_IP;
|
||||
lock->port = ICMPV6_PROTO;
|
||||
lock->iface = iface;
|
||||
@ -193,39 +316,42 @@ radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_con
|
||||
static void
|
||||
radv_iface_remove(struct radv_iface *ifa)
|
||||
{
|
||||
struct proto_radv *ra = ifa->ra;
|
||||
struct radv_proto *p = ifa->ra;
|
||||
RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
|
||||
|
||||
rem_node(NODE ifa);
|
||||
|
||||
rfree(ifa->sk);
|
||||
rfree(ifa->timer);
|
||||
rfree(ifa->lock);
|
||||
|
||||
mb_free(ifa);
|
||||
rfree(ifa->pool);
|
||||
}
|
||||
|
||||
static void
|
||||
radv_if_notify(struct proto *p, unsigned flags, struct iface *iface)
|
||||
radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
struct radv_config *cf = (struct radv_config *) (P->cf);
|
||||
|
||||
if (iface->flags & IF_IGNORE)
|
||||
return;
|
||||
|
||||
if (flags & IF_CHANGE_UP)
|
||||
{
|
||||
struct radv_iface_config *ic = (struct radv_iface_config *)
|
||||
iface_patt_find(&cf->patt_list, iface, NULL);
|
||||
struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
|
||||
|
||||
/* Ignore non-multicast ifaces */
|
||||
if (!(iface->flags & IF_MULTICAST))
|
||||
return;
|
||||
|
||||
/* Ignore ifaces without link-local address */
|
||||
if (!iface->llv6)
|
||||
return;
|
||||
|
||||
if (ic)
|
||||
radv_iface_new(ra, iface, ic);
|
||||
radv_iface_new(p, iface, ic);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct radv_iface *ifa = radv_iface_find(ra, iface);
|
||||
struct radv_iface *ifa = radv_iface_find(p, iface);
|
||||
if (!ifa)
|
||||
return;
|
||||
|
||||
@ -240,9 +366,9 @@ radv_if_notify(struct proto *p, unsigned flags, struct iface *iface)
|
||||
}
|
||||
|
||||
static void
|
||||
radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
|
||||
radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
|
||||
if (a->flags & IA_SECONDARY)
|
||||
return;
|
||||
@ -250,7 +376,7 @@ radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
|
||||
if (a->scope <= SCOPE_LINK)
|
||||
return;
|
||||
|
||||
struct radv_iface *ifa = radv_iface_find(ra, a->iface);
|
||||
struct radv_iface *ifa = radv_iface_find(p, a->iface);
|
||||
|
||||
if (ifa)
|
||||
radv_iface_notify(ifa, RA_EV_CHANGE);
|
||||
@ -269,50 +395,171 @@ radv_net_match_trigger(struct radv_config *cf, net *n)
|
||||
}
|
||||
|
||||
int
|
||||
radv_import_control(struct proto *p, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
|
||||
radv_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
|
||||
{
|
||||
// struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||
// struct radv_proto *p = (struct radv_proto *) P;
|
||||
struct radv_config *cf = (struct radv_config *) (P->cf);
|
||||
|
||||
if (radv_net_match_trigger(cf, (*new)->net))
|
||||
return RIC_PROCESS;
|
||||
|
||||
return RIC_DROP;
|
||||
if (cf->propagate_routes)
|
||||
return RIC_PROCESS;
|
||||
else
|
||||
return RIC_DROP;
|
||||
}
|
||||
|
||||
static void
|
||||
radv_rt_notify(struct proto *p, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs UNUSED)
|
||||
radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
struct radv_config *cf = (struct radv_config *) (P->cf);
|
||||
struct radv_route *rt;
|
||||
eattr *ea;
|
||||
|
||||
if (radv_net_match_trigger(cf, n))
|
||||
{
|
||||
u8 old_active = ra->active;
|
||||
ra->active = !!new;
|
||||
u8 old_active = p->active;
|
||||
p->active = !!new;
|
||||
|
||||
if (ra->active == old_active)
|
||||
if (p->active == old_active)
|
||||
return;
|
||||
|
||||
if (ra->active)
|
||||
if (p->active)
|
||||
RADV_TRACE(D_EVENTS, "Triggered");
|
||||
else
|
||||
RADV_TRACE(D_EVENTS, "Suppressed");
|
||||
|
||||
radv_iface_notify_all(ra, RA_EV_CHANGE);
|
||||
radv_iface_notify_all(p, RA_EV_CHANGE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!cf->propagate_routes)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Some other route we want to send (or stop sending). Update the cache,
|
||||
* with marking a removed one as dead or creating a new one as needed.
|
||||
*
|
||||
* And yes, we exclude the trigger route on purpose.
|
||||
*/
|
||||
|
||||
if (new)
|
||||
{
|
||||
/* Update */
|
||||
|
||||
ea = ea_find(attrs, EA_RA_PREFERENCE);
|
||||
uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
|
||||
uint preference_set = !!ea;
|
||||
|
||||
ea = ea_find(attrs, EA_RA_LIFETIME);
|
||||
uint lifetime = ea ? ea->u.data : 0;
|
||||
uint lifetime_set = !!ea;
|
||||
|
||||
if ((preference != RA_PREF_LOW) &&
|
||||
(preference != RA_PREF_MEDIUM) &&
|
||||
(preference != RA_PREF_HIGH))
|
||||
{
|
||||
log(L_WARN "%s: Invalid ra_preference value %u on route %N",
|
||||
p->p.name, preference, n->n.addr);
|
||||
preference = RA_PREF_MEDIUM;
|
||||
preference_set = 1;
|
||||
lifetime = 0;
|
||||
lifetime_set = 1;
|
||||
}
|
||||
|
||||
rt = fib_get(&p->routes, n->n.addr);
|
||||
|
||||
/* Ignore update if nothing changed */
|
||||
if (rt->valid &&
|
||||
(rt->preference == preference) &&
|
||||
(rt->preference_set == preference_set) &&
|
||||
(rt->lifetime == lifetime) &&
|
||||
(rt->lifetime_set == lifetime_set))
|
||||
return;
|
||||
|
||||
if (p->routes.entries == 18)
|
||||
log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
|
||||
|
||||
rt->valid = 1;
|
||||
rt->changed = current_time();
|
||||
rt->preference = preference;
|
||||
rt->preference_set = preference_set;
|
||||
rt->lifetime = lifetime;
|
||||
rt->lifetime_set = lifetime_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Withdraw */
|
||||
rt = fib_find(&p->routes, n->n.addr);
|
||||
|
||||
if (!rt || !rt->valid)
|
||||
return;
|
||||
|
||||
/* Invalidate the route */
|
||||
rt->valid = 0;
|
||||
rt->changed = current_time();
|
||||
|
||||
/* Invalidated route will be pruned eventually */
|
||||
btime expires = rt->changed + cf->max_linger_time S;
|
||||
p->prune_time = MIN(p->prune_time, expires);
|
||||
}
|
||||
|
||||
radv_iface_notify_all(p, RA_EV_CHANGE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleans up all the dead routes that expired and schedules itself to be run
|
||||
* again if there are more routes waiting for expiration.
|
||||
*/
|
||||
static void
|
||||
radv_prune_routes(struct radv_proto *p)
|
||||
{
|
||||
struct radv_config *cf = (struct radv_config *) (p->p.cf);
|
||||
btime now = current_time();
|
||||
btime next = TIME_INFINITY;
|
||||
btime expires = 0;
|
||||
|
||||
/* Should not happen */
|
||||
if (!p->fib_up)
|
||||
return;
|
||||
|
||||
struct fib_iterator fit;
|
||||
FIB_ITERATE_INIT(&fit, &p->routes);
|
||||
|
||||
again:
|
||||
FIB_ITERATE_START(&p->routes, &fit, struct radv_route, rt)
|
||||
{
|
||||
if (!rt->valid)
|
||||
{
|
||||
expires = rt->changed + cf->max_linger_time S;
|
||||
|
||||
/* Delete expired nodes */
|
||||
if (expires <= now)
|
||||
{
|
||||
FIB_ITERATE_PUT(&fit);
|
||||
fib_delete(&p->routes, rt);
|
||||
goto again;
|
||||
}
|
||||
else
|
||||
next = MIN(next, expires);
|
||||
}
|
||||
}
|
||||
FIB_ITERATE_END;
|
||||
|
||||
p->prune_time = next;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_check_active(struct proto_radv *ra)
|
||||
radv_check_active(struct radv_proto *p)
|
||||
{
|
||||
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
|
||||
struct radv_config *cf = (struct radv_config *) (p->p.cf);
|
||||
|
||||
if (!radv_trigger_valid(cf))
|
||||
return 1;
|
||||
|
||||
struct channel *c = ra->p.main_channel;
|
||||
return rt_examine(c->table, &cf->trigger, &ra->p, c->out_filter);
|
||||
struct channel *c = p->p.main_channel;
|
||||
return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -328,26 +575,47 @@ radv_postconfig(struct proto_config *CF)
|
||||
static struct proto *
|
||||
radv_init(struct proto_config *CF)
|
||||
{
|
||||
struct proto *p = proto_new(CF);
|
||||
struct proto *P = proto_new(CF);
|
||||
|
||||
p->main_channel = proto_add_channel(p, proto_cf_main_channel(CF));
|
||||
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
||||
|
||||
p->import_control = radv_import_control;
|
||||
p->rt_notify = radv_rt_notify;
|
||||
p->if_notify = radv_if_notify;
|
||||
p->ifa_notify = radv_ifa_notify;
|
||||
P->import_control = radv_import_control;
|
||||
P->rt_notify = radv_rt_notify;
|
||||
P->if_notify = radv_if_notify;
|
||||
P->ifa_notify = radv_ifa_notify;
|
||||
|
||||
return p;
|
||||
return P;
|
||||
}
|
||||
|
||||
static void
|
||||
radv_set_fib(struct radv_proto *p, int up)
|
||||
{
|
||||
if (up == p->fib_up)
|
||||
return;
|
||||
|
||||
if (up)
|
||||
fib_init(&p->routes, p->p.pool, NET_IP6, sizeof(struct radv_route),
|
||||
OFFSETOF(struct radv_route, n), 4, NULL);
|
||||
else
|
||||
fib_free(&p->routes);
|
||||
|
||||
p->fib_up = up;
|
||||
p->prune_time = TIME_INFINITY;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_start(struct proto *p)
|
||||
radv_start(struct proto *P)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
struct radv_config *cf = (struct radv_config *) (P->cf);
|
||||
|
||||
init_list(&(ra->iface_list));
|
||||
ra->active = !radv_trigger_valid(cf);
|
||||
init_list(&(p->iface_list));
|
||||
p->valid = 1;
|
||||
p->active = !radv_trigger_valid(cf);
|
||||
|
||||
p->fib_up = 0;
|
||||
radv_set_fib(p, cf->propagate_routes);
|
||||
p->prune_time = TIME_INFINITY;
|
||||
|
||||
return PS_UP;
|
||||
}
|
||||
@ -356,46 +624,61 @@ static inline void
|
||||
radv_iface_shutdown(struct radv_iface *ifa)
|
||||
{
|
||||
if (ifa->sk)
|
||||
radv_send_ra(ifa, 1);
|
||||
{
|
||||
radv_invalidate(ifa);
|
||||
radv_send_ra(ifa);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
radv_shutdown(struct proto *p)
|
||||
radv_shutdown(struct proto *P)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
|
||||
p->valid = 0;
|
||||
|
||||
struct radv_iface *ifa;
|
||||
WALK_LIST(ifa, ra->iface_list)
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
radv_iface_shutdown(ifa);
|
||||
|
||||
return PS_DOWN;
|
||||
}
|
||||
|
||||
static int
|
||||
radv_reconfigure(struct proto *p, struct proto_config *CF)
|
||||
radv_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
// struct radv_config *old = (struct radv_config *) (p->cf);
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
struct radv_config *old = (struct radv_config *) (P->cf);
|
||||
struct radv_config *new = (struct radv_config *) CF;
|
||||
|
||||
/*
|
||||
* The question is why there is a reconfigure function for RAdv if
|
||||
* it has almost none internal state so restarting the protocol
|
||||
* would probably suffice. One small reason is that restarting the
|
||||
* protocol would lead to sending a RA with Router Lifetime 0
|
||||
* causing nodes to temporary remove their default routes.
|
||||
*/
|
||||
|
||||
if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
|
||||
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
|
||||
return 0;
|
||||
|
||||
p->cf = CF; /* radv_check_active() requires proper p->cf */
|
||||
ra->active = radv_check_active(ra);
|
||||
P->cf = CF; /* radv_check_active() requires proper P->cf */
|
||||
p->active = radv_check_active(p);
|
||||
|
||||
/* Allocate or free FIB */
|
||||
radv_set_fib(p, new->propagate_routes);
|
||||
|
||||
/* We started to accept routes so we need to refeed them */
|
||||
if (!old->propagate_routes && new->propagate_routes)
|
||||
channel_request_feeding(p->p.main_channel);
|
||||
|
||||
struct iface *iface;
|
||||
WALK_LIST(iface, iface_list)
|
||||
{
|
||||
struct radv_iface *ifa = radv_iface_find(ra, iface);
|
||||
if (!(iface->flags & IF_UP))
|
||||
continue;
|
||||
|
||||
/* Ignore non-multicast ifaces */
|
||||
if (!(iface->flags & IF_MULTICAST))
|
||||
continue;
|
||||
|
||||
/* Ignore ifaces without link-local address */
|
||||
if (!iface->llv6)
|
||||
continue;
|
||||
|
||||
struct radv_iface *ifa = radv_iface_find(p, iface);
|
||||
struct radv_iface_config *ic = (struct radv_iface_config *)
|
||||
iface_patt_find(&new->patt_list, iface, NULL);
|
||||
|
||||
@ -415,7 +698,7 @@ radv_reconfigure(struct proto *p, struct proto_config *CF)
|
||||
}
|
||||
|
||||
if (!ifa && ic)
|
||||
radv_iface_new(ra, iface, ic);
|
||||
radv_iface_new(p, iface, ic);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -435,19 +718,53 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||
}
|
||||
|
||||
static void
|
||||
radv_get_status(struct proto *p, byte *buf)
|
||||
radv_get_status(struct proto *P, byte *buf)
|
||||
{
|
||||
struct proto_radv *ra = (struct proto_radv *) p;
|
||||
struct radv_proto *p = (struct radv_proto *) P;
|
||||
|
||||
if (!ra->active)
|
||||
if (!p->active)
|
||||
strcpy(buf, "Suppressed");
|
||||
}
|
||||
|
||||
static const char *
|
||||
radv_pref_str(u32 pref)
|
||||
{
|
||||
switch (pref)
|
||||
{
|
||||
case RA_PREF_LOW:
|
||||
return "low";
|
||||
case RA_PREF_MEDIUM:
|
||||
return "medium";
|
||||
case RA_PREF_HIGH:
|
||||
return "high";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
/* The buffer has some minimal size */
|
||||
static int
|
||||
radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
|
||||
{
|
||||
switch (a->id)
|
||||
{
|
||||
case EA_RA_PREFERENCE:
|
||||
bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
|
||||
return GA_FULL;
|
||||
case EA_RA_LIFETIME:
|
||||
bsprintf(buf, "lifetime");
|
||||
return GA_NAME;
|
||||
default:
|
||||
return GA_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
struct protocol proto_radv = {
|
||||
.name = "RAdv",
|
||||
.template = "radv%d",
|
||||
.attr_class = EAP_RADV,
|
||||
.channel_mask = NB_IP6,
|
||||
.proto_size = sizeof(struct proto_radv),
|
||||
.proto_size = sizeof(struct radv_proto),
|
||||
.config_size = sizeof(struct radv_config),
|
||||
.postconfig = radv_postconfig,
|
||||
.init = radv_init,
|
||||
@ -455,5 +772,6 @@ struct protocol proto_radv = {
|
||||
.shutdown = radv_shutdown,
|
||||
.reconfigure = radv_reconfigure,
|
||||
.copy_config = radv_copy_config,
|
||||
.get_status = radv_get_status
|
||||
.get_status = radv_get_status,
|
||||
.get_attr = radv_get_attr
|
||||
};
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "lib/ip.h"
|
||||
#include "lib/lists.h"
|
||||
#include "lib/socket.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/resource.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/iface.h"
|
||||
@ -30,7 +30,7 @@
|
||||
#define ICMPV6_RA 134
|
||||
|
||||
#define MAX_INITIAL_RTR_ADVERTISEMENTS 3
|
||||
#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16
|
||||
#define MAX_INITIAL_RTR_ADVERT_INTERVAL (16 S_)
|
||||
|
||||
#define DEFAULT_MAX_RA_INT 600
|
||||
#define DEFAULT_MIN_DELAY 3
|
||||
@ -51,6 +51,8 @@ struct radv_config
|
||||
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
|
||||
|
||||
net_addr trigger; /* Prefix of a trigger route, if defined */
|
||||
u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */
|
||||
u32 max_linger_time; /* Maximum of interface route_linger_time */
|
||||
};
|
||||
|
||||
struct radv_iface_config
|
||||
@ -60,22 +62,28 @@ struct radv_iface_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) */
|
||||
|
||||
u32 min_ra_int; /* Standard options from RFC 4261 */
|
||||
u32 min_ra_int; /* Standard options from RFC 4861 */
|
||||
u32 max_ra_int;
|
||||
u32 min_delay;
|
||||
|
||||
u32 prefix_linger_time; /* How long we advertise dead prefixes with lifetime 0 */
|
||||
u32 route_linger_time; /* How long we advertise dead routes with lifetime 0 */
|
||||
|
||||
u8 rdnss_local; /* Global list is not used for RDNSS */
|
||||
u8 dnssl_local; /* Global list is not used for DNSSL */
|
||||
|
||||
u8 managed; /* Standard options from RFC 4261 */
|
||||
u8 managed; /* Standard options from RFC 4861 */
|
||||
u8 other_config;
|
||||
u32 link_mtu;
|
||||
u32 reachable_time;
|
||||
u32 retrans_timer;
|
||||
u32 current_hop_limit;
|
||||
u32 default_lifetime;
|
||||
u32 route_lifetime; /* Lifetime for the RFC 4191 routes */
|
||||
u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
|
||||
u8 route_lifetime_sensitive; /* Whether route_lifetime depends on trigger */
|
||||
u8 default_preference; /* Default Router Preference (RFC 4191) */
|
||||
u8 route_preference; /* Specific Route Preference (RFC 4191) */
|
||||
};
|
||||
|
||||
struct radv_prefix_config
|
||||
@ -84,7 +92,7 @@ struct radv_prefix_config
|
||||
net_addr_ip6 prefix;
|
||||
|
||||
u8 skip; /* Do not include this prefix to RA */
|
||||
u8 onlink; /* Standard options from RFC 4261 */
|
||||
u8 onlink; /* Standard options from RFC 4861 */
|
||||
u8 autonomous;
|
||||
u32 valid_lifetime;
|
||||
u32 preferred_lifetime;
|
||||
@ -110,29 +118,67 @@ struct radv_dnssl_config
|
||||
char *domain; /* Domain for DNS search list, in processed form */
|
||||
};
|
||||
|
||||
/*
|
||||
* One more specific route as per RFC 4191.
|
||||
*
|
||||
* Note that it does *not* contain the next hop field. The next hop is always
|
||||
* the router sending the advertisment and the more specific route only allows
|
||||
* overriding the preference of the route.
|
||||
*/
|
||||
struct radv_route
|
||||
{
|
||||
u32 lifetime; /* Lifetime from an attribute */
|
||||
u8 lifetime_set; /* Whether lifetime is defined */
|
||||
u8 preference; /* Preference of the route, RA_PREF_* */
|
||||
u8 preference_set; /* Whether preference is defined */
|
||||
u8 valid; /* Whethe route is valid or withdrawn */
|
||||
btime changed; /* Last time when the route changed */
|
||||
|
||||
struct proto_radv
|
||||
struct fib_node n;
|
||||
};
|
||||
|
||||
struct radv_proto
|
||||
{
|
||||
struct proto p;
|
||||
list iface_list; /* List of active ifaces */
|
||||
u8 valid; /* Router is valid for forwarding, used for shutdown */
|
||||
u8 active; /* Whether radv is active w.r.t. triggers */
|
||||
u8 fib_up; /* FIB table (routes) is initialized */
|
||||
struct fib routes; /* FIB table of specific routes (struct radv_route) */
|
||||
btime prune_time; /* Next time of route table pruning */
|
||||
};
|
||||
|
||||
struct radv_prefix /* One prefix we advertise */
|
||||
{
|
||||
node n;
|
||||
net_addr_ip6 prefix;
|
||||
|
||||
u8 valid; /* Is the prefix valid? If not, we advertise it
|
||||
with 0 lifetime, so clients stop using it */
|
||||
u8 mark; /* A temporary mark for processing */
|
||||
btime changed; /* Last time when the prefix changed */
|
||||
struct radv_prefix_config *cf; /* The config tied to this prefix */
|
||||
};
|
||||
|
||||
struct radv_iface
|
||||
{
|
||||
node n;
|
||||
struct proto_radv *ra;
|
||||
struct radv_proto *ra;
|
||||
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 prune_time; /* Next time of prefix list pruning */
|
||||
btime valid_time; /* Cached packet is valid until first linger timeout */
|
||||
|
||||
timer *timer;
|
||||
struct object_lock *lock;
|
||||
sock *sk;
|
||||
|
||||
bird_clock_t last; /* Time of last sending of RA */
|
||||
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 */
|
||||
@ -145,14 +191,17 @@ struct radv_iface
|
||||
#define RA_PREF_HIGH 0x08
|
||||
#define RA_PREF_MASK 0x18
|
||||
|
||||
/* Attributes */
|
||||
#define EA_RA_PREFERENCE EA_CODE(EAP_RADV, 0)
|
||||
#define EA_RA_LIFETIME EA_CODE(EAP_RADV, 1)
|
||||
|
||||
#ifdef LOCAL_DEBUG
|
||||
#define RADV_FORCE_DEBUG 1
|
||||
#else
|
||||
#define RADV_FORCE_DEBUG 0
|
||||
#endif
|
||||
#define RADV_TRACE(flags, msg, args...) do { if ((ra->p.debug & flags) || RADV_FORCE_DEBUG) \
|
||||
log(L_TRACE "%s: " msg, ra->p.name , ## args ); } while(0)
|
||||
#define RADV_TRACE(flags, msg, args...) do { if ((p->p.debug & flags) || RADV_FORCE_DEBUG) \
|
||||
log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
|
||||
|
||||
|
||||
/* radv.c */
|
||||
@ -160,7 +209,7 @@ void radv_iface_notify(struct radv_iface *ifa, int event);
|
||||
|
||||
/* packets.c */
|
||||
int radv_process_domain(struct radv_dnssl_config *cf);
|
||||
void radv_send_ra(struct radv_iface *ifa, int shutdown);
|
||||
void radv_send_ra(struct radv_iface *ifa);
|
||||
int radv_sk_open(struct radv_iface *ifa);
|
||||
|
||||
|
||||
|
@ -56,9 +56,10 @@ rip_proto_start: proto_start rip_variant
|
||||
|
||||
init_list(&RIP_CFG->patt_list);
|
||||
RIP_CFG->rip2 = $2;
|
||||
RIP_CFG->ecmp = rt_default_ecmp;
|
||||
RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
|
||||
RIP_CFG->min_timeout_time = 60;
|
||||
RIP_CFG->max_garbage_time = 60;
|
||||
RIP_CFG->min_timeout_time = 60 S_;
|
||||
RIP_CFG->max_garbage_time = 60 S_;
|
||||
};
|
||||
|
||||
rip_proto_item:
|
||||
@ -92,6 +93,7 @@ rip_iface_start:
|
||||
RIP_IFACE->split_horizon = 1;
|
||||
RIP_IFACE->poison_reverse = 1;
|
||||
RIP_IFACE->check_zero = 1;
|
||||
RIP_IFACE->check_link = 1;
|
||||
RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1;
|
||||
RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
|
||||
RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
|
||||
@ -147,9 +149,9 @@ rip_iface_item:
|
||||
| SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; }
|
||||
| POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
|
||||
| CHECK ZERO bool { RIP_IFACE->check_zero = $3; }
|
||||
| UPDATE TIME expr { RIP_IFACE->update_time = $3; if ($3<=0) cf_error("Update time must be positive"); }
|
||||
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3; if ($3<=0) cf_error("Timeout time must be positive"); }
|
||||
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3; if ($3<=0) cf_error("Garbage time must be positive"); }
|
||||
| UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
|
||||
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
|
||||
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
|
||||
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
|
||||
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
|
||||
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
|
||||
|
@ -189,7 +189,10 @@ rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
|
||||
* have the same CSN. We are using real time, but enforcing monotonicity.
|
||||
*/
|
||||
if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
|
||||
ifa->csn = (ifa->csn < (u32) now_real) ? (u32) now_real : ifa->csn + 1;
|
||||
{
|
||||
u32 now_real = (u32) (current_real_time() TO_S);
|
||||
ifa->csn = (ifa->csn < now_real) ? now_real : ifa->csn + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -434,6 +437,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
|
||||
byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
|
||||
(rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
|
||||
ip_addr last_next_hop = IPA_NONE;
|
||||
btime now_ = current_time();
|
||||
int send = 0;
|
||||
|
||||
struct rip_packet *pkt = (void *) pos;
|
||||
@ -450,7 +454,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
|
||||
|
||||
/* Stale entries that should be removed */
|
||||
if ((en->valid == RIP_ENTRY_STALE) &&
|
||||
((en->changed + (bird_clock_t) ifa->cf->garbage_time) <= now))
|
||||
((en->changed + ifa->cf->garbage_time) <= now_))
|
||||
goto next_entry;
|
||||
|
||||
/* Triggered updates */
|
||||
@ -540,7 +544,7 @@ break_loop:
|
||||
* activating the new one.
|
||||
*/
|
||||
void
|
||||
rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed)
|
||||
rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed)
|
||||
{
|
||||
DBG("RIP: Opening TX session to %I on %s\n", addr, ifa->iface->name);
|
||||
|
||||
@ -591,6 +595,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
|
||||
|
||||
byte *pos = (byte *) pkt + sizeof(struct rip_packet);
|
||||
byte *end = (byte *) pkt + plen;
|
||||
btime now_ = current_time();
|
||||
|
||||
for (; pos < end; pos += RIP_BLOCK_LENGTH)
|
||||
{
|
||||
@ -638,7 +643,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
|
||||
.next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
|
||||
.metric = rte.metric,
|
||||
.tag = rte.tag,
|
||||
.expires = now + ifa->cf->timeout_time
|
||||
.expires = now_ + ifa->cf->timeout_time
|
||||
};
|
||||
|
||||
rip_update_rte(p, &rte.net, &new);
|
||||
@ -669,8 +674,7 @@ rip_rx_hook(sock *sk, uint len)
|
||||
sk->iface->name, sk->faddr, sk->laddr);
|
||||
|
||||
/* Silently ignore my own packets */
|
||||
/* FIXME: Better local address check */
|
||||
if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
|
||||
if (ipa_equal(sk->faddr, sk->saddr))
|
||||
return 1;
|
||||
|
||||
if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr))
|
||||
@ -706,7 +710,7 @@ rip_rx_hook(sock *sk, uint len)
|
||||
if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
|
||||
DROP("invalid length", plen);
|
||||
|
||||
n->last_seen = now;
|
||||
n->last_seen = current_time();
|
||||
rip_update_bfd(p, n);
|
||||
|
||||
switch (pkt->command)
|
||||
@ -742,14 +746,8 @@ rip_open_socket(struct rip_iface *ifa)
|
||||
sk->sport = ifa->cf->port;
|
||||
sk->dport = ifa->cf->port;
|
||||
sk->iface = ifa->iface;
|
||||
|
||||
/*
|
||||
* For RIPv2, we explicitly choose a primary address, mainly to ensure that
|
||||
* RIP and BFD uses the same one. For RIPng, we left it to kernel, which
|
||||
* should choose some link-local address based on the same scope rule.
|
||||
*/
|
||||
if (rip_is_v2(p))
|
||||
sk->saddr = ifa->iface->addr->ip;
|
||||
sk->saddr = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
|
||||
sk->vrf = p->p.vrf;
|
||||
|
||||
sk->rx_hook = rip_rx_hook;
|
||||
sk->tx_hook = rip_tx_hook;
|
||||
|
@ -364,7 +364,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
|
||||
/* Activate triggered updates */
|
||||
if (en->metric != old_metric)
|
||||
{
|
||||
en->changed = now;
|
||||
en->changed = current_time();
|
||||
rip_trigger_update(p);
|
||||
}
|
||||
}
|
||||
@ -506,10 +506,10 @@ rip_iface_start(struct rip_iface *ifa)
|
||||
|
||||
TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
|
||||
|
||||
ifa->next_regular = now + (random() % ifa->cf->update_time) + 1;
|
||||
ifa->next_triggered = now; /* Available immediately */
|
||||
ifa->want_triggered = 1; /* All routes in triggered update */
|
||||
tm_start(ifa->timer, 1); /* Or 100 ms */
|
||||
ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
|
||||
ifa->next_triggered = current_time(); /* Available immediately */
|
||||
ifa->want_triggered = 1; /* All routes in triggered update */
|
||||
tm_start(ifa->timer, 100 MS);
|
||||
ifa->up = 1;
|
||||
|
||||
if (!ifa->cf->passive)
|
||||
@ -630,13 +630,19 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
|
||||
else if (ic->mode == RIP_IM_MULTICAST)
|
||||
ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
|
||||
else /* Broadcast */
|
||||
ifa->addr = iface->addr->brd;
|
||||
ifa->addr = iface->addr4->brd;
|
||||
/*
|
||||
* The above is just a workaround for BSD as it can't send broadcasts
|
||||
* to 255.255.255.255. BSD systems need the network broadcast address instead.
|
||||
*
|
||||
* TODO: move this to sysdep code
|
||||
*/
|
||||
|
||||
init_list(&ifa->neigh_list);
|
||||
|
||||
add_tail(&p->iface_list, NODE ifa);
|
||||
|
||||
ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0);
|
||||
ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
|
||||
|
||||
struct object_lock *lock = olock_new(p->p.pool);
|
||||
lock->type = OBJLOCK_UDP;
|
||||
@ -684,8 +690,8 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
|
||||
|
||||
rip_iface_update_buffers(ifa);
|
||||
|
||||
if (ifa->next_regular > (now + (bird_clock_t) new->update_time))
|
||||
ifa->next_regular = now + (random() % new->update_time) + 1;
|
||||
if (ifa->next_regular > (current_time() + new->update_time))
|
||||
ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
|
||||
|
||||
if (new->check_link != old->check_link)
|
||||
rip_iface_update_state(ifa);
|
||||
@ -706,7 +712,11 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
|
||||
|
||||
WALK_LIST(iface, iface_list)
|
||||
{
|
||||
if (! (iface->flags & IF_UP))
|
||||
if (!(iface->flags & IF_UP))
|
||||
continue;
|
||||
|
||||
/* Ignore ifaces without appropriate address */
|
||||
if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
|
||||
continue;
|
||||
|
||||
struct rip_iface *ifa = rip_find_iface(p, iface);
|
||||
@ -744,6 +754,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
|
||||
{
|
||||
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
|
||||
|
||||
/* Ignore ifaces without appropriate address */
|
||||
if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
|
||||
return;
|
||||
|
||||
if (ic)
|
||||
rip_add_iface(p, iface, ic);
|
||||
|
||||
@ -802,8 +816,9 @@ rip_timer(timer *t)
|
||||
struct rip_iface *ifa;
|
||||
struct rip_neighbor *n, *nn;
|
||||
struct fib_iterator fit;
|
||||
bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time);
|
||||
bird_clock_t expires = 0;
|
||||
btime now_ = current_time();
|
||||
btime next = now_ + MIN(cf->min_timeout_time, cf->max_garbage_time);
|
||||
btime expires = 0;
|
||||
|
||||
TRACE(D_EVENTS, "Main timer fired");
|
||||
|
||||
@ -818,7 +833,7 @@ rip_timer(timer *t)
|
||||
/* Checking received routes for timeout and for dead neighbors */
|
||||
for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
|
||||
{
|
||||
if (!rip_valid_rte(rt) || (rt->expires <= now))
|
||||
if (!rip_valid_rte(rt) || (rt->expires <= now_))
|
||||
{
|
||||
rip_remove_rte(p, rp);
|
||||
changed = 1;
|
||||
@ -848,7 +863,7 @@ rip_timer(timer *t)
|
||||
{
|
||||
expires = en->changed + cf->max_garbage_time;
|
||||
|
||||
if (expires <= now)
|
||||
if (expires <= now_)
|
||||
{
|
||||
// TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
|
||||
en->valid = 0;
|
||||
@ -876,20 +891,20 @@ rip_timer(timer *t)
|
||||
{
|
||||
expires = n->last_seen + n->ifa->cf->timeout_time;
|
||||
|
||||
if (expires <= now)
|
||||
if (expires <= now_)
|
||||
rip_remove_neighbor(p, n);
|
||||
else
|
||||
next = MIN(next, expires);
|
||||
}
|
||||
|
||||
tm_start(p->timer, MAX(next - now, 1));
|
||||
tm_start(p->timer, MAX(next - now_, 100 MS));
|
||||
}
|
||||
|
||||
static inline void
|
||||
rip_kick_timer(struct rip_proto *p)
|
||||
{
|
||||
if (p->timer->expires > (now + 1))
|
||||
tm_start(p->timer, 1); /* Or 100 ms */
|
||||
if (p->timer->expires > (current_time() + 100 MS))
|
||||
tm_start(p->timer, 100 MS);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -907,7 +922,8 @@ rip_iface_timer(timer *t)
|
||||
{
|
||||
struct rip_iface *ifa = t->data;
|
||||
struct rip_proto *p = ifa->rip;
|
||||
bird_clock_t period = ifa->cf->update_time;
|
||||
btime now_ = current_time();
|
||||
btime period = ifa->cf->update_time;
|
||||
|
||||
if (ifa->cf->passive)
|
||||
return;
|
||||
@ -916,40 +932,40 @@ rip_iface_timer(timer *t)
|
||||
|
||||
if (ifa->tx_active)
|
||||
{
|
||||
if (now < (ifa->next_regular + period))
|
||||
{ tm_start(ifa->timer, 1); return; }
|
||||
if (now_ < (ifa->next_regular + period))
|
||||
{ tm_start(ifa->timer, 100 MS); return; }
|
||||
|
||||
/* We are too late, reset is done by rip_send_table() */
|
||||
log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
|
||||
}
|
||||
|
||||
if (now >= ifa->next_regular)
|
||||
if (now_ >= ifa->next_regular)
|
||||
{
|
||||
/* Send regular update, set timer for next period (or following one if necessay) */
|
||||
TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
|
||||
rip_send_table(p, ifa, ifa->addr, 0);
|
||||
ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period));
|
||||
ifa->next_regular += period * (1 + ((now_ - ifa->next_regular) / period));
|
||||
ifa->want_triggered = 0;
|
||||
p->triggered = 0;
|
||||
}
|
||||
else if (ifa->want_triggered && (now >= ifa->next_triggered))
|
||||
else if (ifa->want_triggered && (now_ >= ifa->next_triggered))
|
||||
{
|
||||
/* Send triggered update, enforce interval between triggered updates */
|
||||
TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
|
||||
rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
|
||||
ifa->next_triggered = now + MIN(5, period / 2 + 1);
|
||||
ifa->next_triggered = now_ + MIN(5 S, period / 2);
|
||||
ifa->want_triggered = 0;
|
||||
p->triggered = 0;
|
||||
}
|
||||
|
||||
tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now));
|
||||
tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
|
||||
}
|
||||
|
||||
static inline void
|
||||
rip_iface_kick_timer(struct rip_iface *ifa)
|
||||
{
|
||||
if (ifa->timer->expires > (now + 1))
|
||||
tm_start(ifa->timer, 1); /* Or 100 ms */
|
||||
if (ifa->timer->expires > (current_time() + 100 MS))
|
||||
tm_start(ifa->timer, 100 MS);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -970,7 +986,7 @@ rip_trigger_update(struct rip_proto *p)
|
||||
continue;
|
||||
|
||||
TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
|
||||
ifa->want_triggered = now;
|
||||
ifa->want_triggered = current_time();
|
||||
rip_iface_kick_timer(ifa);
|
||||
}
|
||||
|
||||
@ -1095,7 +1111,7 @@ rip_start(struct proto *P)
|
||||
fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6,
|
||||
sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL);
|
||||
p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
|
||||
p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0);
|
||||
p->timer = tm_new_init(P->pool, rip_timer, p, 0, 0);
|
||||
|
||||
p->rip2 = cf->rip2;
|
||||
p->ecmp = cf->ecmp;
|
||||
@ -1180,7 +1196,7 @@ rip_show_interfaces(struct proto *P, char *iff)
|
||||
}
|
||||
|
||||
cli_msg(-1021, "%s:", p->p.name);
|
||||
cli_msg(-1021, "%-10s %-6s %6s %6s %6s",
|
||||
cli_msg(-1021, "%-10s %-6s %6s %6s %7s",
|
||||
"Interface", "State", "Metric", "Nbrs", "Timer");
|
||||
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
@ -1193,8 +1209,9 @@ rip_show_interfaces(struct proto *P, char *iff)
|
||||
if (n->last_seen)
|
||||
nbrs++;
|
||||
|
||||
int timer = MAX(ifa->next_regular - now, 0);
|
||||
cli_msg(-1021, "%-10s %-6s %6u %6u %6u",
|
||||
btime now_ = current_time();
|
||||
btime timer = (ifa->next_regular > now_) ? (ifa->next_regular - now_) : 0;
|
||||
cli_msg(-1021, "%-10s %-6s %6u %6u %7t",
|
||||
ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
|
||||
}
|
||||
|
||||
@ -1216,7 +1233,7 @@ rip_show_neighbors(struct proto *P, char *iff)
|
||||
}
|
||||
|
||||
cli_msg(-1022, "%s:", p->p.name);
|
||||
cli_msg(-1022, "%-25s %-10s %6s %6s %6s",
|
||||
cli_msg(-1022, "%-25s %-10s %6s %6s %7s",
|
||||
"IP address", "Interface", "Metric", "Routes", "Seen");
|
||||
|
||||
WALK_LIST(ifa, p->iface_list)
|
||||
@ -1229,8 +1246,8 @@ rip_show_neighbors(struct proto *P, char *iff)
|
||||
if (!n->last_seen)
|
||||
continue;
|
||||
|
||||
int timer = now - n->last_seen;
|
||||
cli_msg(-1022, "%-25I %-10s %6u %6u %6u",
|
||||
btime timer = current_time() - n->last_seen;
|
||||
cli_msg(-1022, "%-25I %-10s %6u %6u %7t",
|
||||
n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
|
||||
}
|
||||
}
|
||||
@ -1248,9 +1265,9 @@ rip_dump(struct proto *P)
|
||||
i = 0;
|
||||
FIB_WALK(&p->rtable, struct rip_entry, en)
|
||||
{
|
||||
debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %d s\n",
|
||||
debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
|
||||
i++, en->n.addr, en->next_hop, en->iface->name,
|
||||
en->valid, en->metric, now - en->changed);
|
||||
en->valid, en->metric, current_time() - en->changed);
|
||||
}
|
||||
FIB_WALK_END;
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "lib/resource.h"
|
||||
#include "lib/socket.h"
|
||||
#include "lib/string.h"
|
||||
#include "sysdep/unix/timer.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
|
||||
#define RIP_V1 1
|
||||
@ -38,9 +38,9 @@
|
||||
|
||||
#define RIP_DEFAULT_ECMP_LIMIT 16
|
||||
#define RIP_DEFAULT_INFINITY 16
|
||||
#define RIP_DEFAULT_UPDATE_TIME 30
|
||||
#define RIP_DEFAULT_TIMEOUT_TIME 180
|
||||
#define RIP_DEFAULT_GARBAGE_TIME 120
|
||||
#define RIP_DEFAULT_UPDATE_TIME (30 S_)
|
||||
#define RIP_DEFAULT_TIMEOUT_TIME (180 S_)
|
||||
#define RIP_DEFAULT_GARBAGE_TIME (120 S_)
|
||||
|
||||
|
||||
struct rip_config
|
||||
@ -52,8 +52,8 @@ struct rip_config
|
||||
u8 ecmp; /* Maximum number of nexthops in ECMP route, or 0 */
|
||||
u8 infinity; /* Maximum metric value, representing infinity */
|
||||
|
||||
u32 min_timeout_time; /* Minimum of interface timeout_time */
|
||||
u32 max_garbage_time; /* Maximum of interface garbage_time */
|
||||
btime min_timeout_time; /* Minimum of interface timeout_time */
|
||||
btime max_garbage_time; /* Maximum of interface garbage_time */
|
||||
};
|
||||
|
||||
struct rip_iface_config
|
||||
@ -78,9 +78,9 @@ struct rip_iface_config
|
||||
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
|
||||
int tx_tos;
|
||||
int tx_priority;
|
||||
u32 update_time; /* Periodic update interval */
|
||||
u32 timeout_time; /* Route expiration timeout */
|
||||
u32 garbage_time; /* Unreachable entry GC timeout */
|
||||
btime update_time; /* Periodic update interval */
|
||||
btime timeout_time; /* Route expiration timeout */
|
||||
btime garbage_time; /* Unreachable entry GC timeout */
|
||||
list *passwords; /* Passwords for authentication */
|
||||
};
|
||||
|
||||
@ -120,14 +120,14 @@ struct rip_iface
|
||||
list neigh_list; /* List of iface neighbors (struct rip_neighbor) */
|
||||
|
||||
/* Update scheduling */
|
||||
bird_clock_t next_regular; /* Next time when regular update should be called */
|
||||
bird_clock_t next_triggered; /* Next time when triggerd update may be called */
|
||||
bird_clock_t want_triggered; /* Nonzero if triggered update is scheduled */
|
||||
btime next_regular; /* Next time when regular update should be called */
|
||||
btime next_triggered; /* Next time when triggerd update may be called */
|
||||
btime want_triggered; /* Nonzero if triggered update is scheduled */
|
||||
|
||||
/* Active update */
|
||||
int tx_active; /* Update session is active */
|
||||
ip_addr tx_addr; /* Update session destination address */
|
||||
bird_clock_t tx_changed; /* Minimal changed time for triggered update */
|
||||
btime tx_changed; /* Minimal changed time for triggered update */
|
||||
struct fib_iterator tx_fit; /* FIB iterator in RIP routing table (p.rtable) */
|
||||
};
|
||||
|
||||
@ -137,7 +137,7 @@ struct rip_neighbor
|
||||
struct rip_iface *ifa; /* Associated interface, may be NULL if stale */
|
||||
struct neighbor *nbr; /* Associaded core neighbor, may be NULL if stale */
|
||||
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
|
||||
bird_clock_t last_seen; /* Time of last received and accepted message */
|
||||
btime last_seen; /* Time of last received and accepted message */
|
||||
u32 uc; /* Use count, number of routes linking the neighbor */
|
||||
u32 csn; /* Last received crypto sequence number */
|
||||
};
|
||||
@ -153,7 +153,7 @@ struct rip_entry
|
||||
struct iface *iface; /* Outgoing route iface (for next hop) */
|
||||
ip_addr next_hop; /* Outgoing route next hop */
|
||||
|
||||
bird_clock_t changed; /* Last time when the outgoing route metric changed */
|
||||
btime changed; /* Last time when the outgoing route metric changed */
|
||||
|
||||
struct fib_node n;
|
||||
};
|
||||
@ -167,7 +167,7 @@ struct rip_rte
|
||||
u16 metric; /* Route metric (after increase) */
|
||||
u16 tag; /* Route tag */
|
||||
|
||||
bird_clock_t expires; /* Time of route expiration */
|
||||
btime expires; /* Time of route expiration */
|
||||
};
|
||||
|
||||
|
||||
@ -211,7 +211,7 @@ void rip_show_neighbors(struct proto *P, char *iff);
|
||||
|
||||
/* packets.c */
|
||||
void rip_send_request(struct rip_proto *p, struct rip_iface *ifa);
|
||||
void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed);
|
||||
void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed);
|
||||
int rip_open_socket(struct rip_iface *ifa);
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user