0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-05 08:31:53 +00:00

Merge branch 'int-new' into show-route

Updated static flowspec action definition to the new filter syntax.
This commit is contained in:
Jan Maria Matejka 2018-04-04 10:42:54 +02:00
commit 92bccd4ccd
144 changed files with 6807 additions and 4237 deletions

2
.gitignore vendored
View File

@ -11,3 +11,5 @@
/config.status /config.status
/configure /configure
/sysdep/autoconf.h.in /sysdep/autoconf.h.in
/sysdep/autoconf.h.in~
/cscope.*

309
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,309 @@
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: &centos-6-amd64_env
image: registry.labs.nic.cz/labs/bird:centos-6-amd64
tags:
- docker
- linux
- amd64
.centos-7-amd64: &centos-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
tags:
- freebsd
- i386
#only:
#- master
#- triggers
#- tags
.freebsd-11-amd64: &freebsd-11-amd64_env
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

View File

@ -21,6 +21,11 @@ INSTALL=@INSTALL@
INSTALL_PROGRAM=@INSTALL_PROGRAM@ INSTALL_PROGRAM=@INSTALL_PROGRAM@
INSTALL_DATA=@INSTALL_DATA@ INSTALL_DATA=@INSTALL_DATA@
git-label:=$(strip $(shell git describe --always --dirty=-x 2>/dev/null))
ifneq ($(git-label),)
CFLAGS += -DGIT_LABEL="$(git-label)"
endif
client=$(addprefix $(exedir)/,@CLIENT@) client=$(addprefix $(exedir)/,@CLIENT@)
daemon=$(exedir)/bird daemon=$(exedir)/bird
protocols=@protocols@ protocols=@protocols@
@ -53,7 +58,7 @@ endif
docgoals := docs userdocs progdocs docgoals := docs userdocs progdocs
testgoals := check test tests tests_run testgoals := check test tests tests_run
cleangoals := clean distclean testsclean cleangoals := clean distclean testsclean
.PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags .PHONY: all daemon cli $(docgoals) $(testgoals) $(cleangoals) tags cscope
all: daemon cli all: daemon cli
daemon: $(daemon) daemon: $(daemon)
@ -157,6 +162,9 @@ endif
tags: tags:
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]` cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
cscope:
cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b
# Install # Install
install: all install: all

81
NEWS
View File

@ -1,45 +1,70 @@
Version 2.0.0-pre1 (2017-04-29) Version 2.0.2 (2018-03-22)
o Source-specific routing support for Linux kernel and Babel
o BGP: New option 'disable after cease'
o Filter: Allow silent filter execution
o Filter: Fixed stack overflow in BGP mask expressions.
o Several bugfixes
Notes:
Syntax prefix:netmask for IPv4 prefixes was dropped. Just use prefix/pxlen.
Version 2.0.1 (2018-01-16)
o Linux MPLS kernel support
o Better handling of channels inherited from templates
o Default EBGP Route Propagation Behavior without Policies (RFC 8212)
o Many bugfixes
Notes:
To satisfy requirements of RFC 8212, external BGP protocols now require
explicit configuration of import and export policies.
Version 2.0.0 (2017-12-11)
o Integrated IPv4 + IPv6 design
o Support for MPLS next hops 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 with MPLS labels (RFC 3107)
o BGP MPLS/VPN support (RFC 4364) o BGP MPLS/VPN support (RFC 4364)
o BGP 6PE - IPv6 NLRI over IPv4 MPLS (RFC 4798) o BGP 6PE - IPv6 NLRI over IPv4 MPLS (RFC 4798)
o BGP IPv4 NLRI with an IPv6 Next Hop (RFC 5549) o BGP IPv4 NLRI with an IPv6 Next Hop (RFC 5549)
o BGP Confederations (RFC 5065) 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 exchanging LOCAL_PREF with eBGP peers
o BGP: Allow to specify interface for regular sessions o BGP: Allow to specify interface for regular sessions
o Babel support restored o OSPF: Support of address families in OSPFv3
o Static: Minor overhaul o OSPF: Enable ECMP and Link detection by default
o Netlink: Default kernel metric changed to 32 o RAdv: Support for more specific routes (RFC 4191)
o Flowspec: Limit tcp mask length to 12 bits o RAdv: Proper handling of prefix retraction
o Update of show route command o RIP: Enable ECMP and Link detection by default
o Redesign of RPKI handling
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 New RPKI-Router protocol 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 New build system
o Unit tests o Unit tests
o ...
Notes: Notes:
Protocols and tables are now connected using explicit channels, most related Tables are now defined with appropriate net type keyword. Protocols and tables
protocol options (table, import, export, ...) are now channel options. See are now connected by explicit channels, most related protocol options (table,
doc/bird.conf.example2 for configuration examples. 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) Version 1.6.3 (2016-12-21)

4
README
View File

@ -6,7 +6,7 @@
(c) 1998--2008 Martin Mares <mj@ucw.cz> (c) 1998--2008 Martin Mares <mj@ucw.cz>
(c) 1998--2000 Pavel Machek <pavel@ucw.cz> (c) 1998--2000 Pavel Machek <pavel@ucw.cz>
(c) 1998--2008 Ondrej Filip <feela@network.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 What do we support
================== ==================
o Both IPv4 and IPv6 (use --enable-ipv6 when configuring) o Both IPv4 and IPv6
o Multiple routing tables o Multiple routing tables
o Border Gateway Protocol (BGPv4) o Border Gateway Protocol (BGPv4)
o Routing Information Protocol (RIPv2, RIPng) o Routing Information Protocol (RIPv2, RIPng)

45
TODO
View File

@ -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
View File

@ -31,6 +31,41 @@ AC_DEFUN([BIRD_CHECK_PTHREADS],
CFLAGS="$bird_tmp_cflags" 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], AC_DEFUN([BIRD_CHECK_GCC_OPTION],
[ [
bird_tmp_cflags="$CFLAGS" bird_tmp_cflags="$CFLAGS"

View File

@ -22,13 +22,14 @@ protocol direct {
# Feed routes to kernel FIB # Feed routes to kernel FIB
protocol kernel { protocol kernel {
ipv4 { export all; }; ipv4 { export all; import all; };
# learn; # Learn all routes from the kernel learn; # Learn all routes from the kernel
# scan time 10; # Scan kernel tables every 10 seconds # scan time 10; # Scan kernel tables every 10 seconds
} }
protocol kernel { protocol kernel {
ipv6; ipv6 { import all; };
learn;
} }
# Static route feed # Static route feed
@ -52,6 +53,6 @@ protocol rip {
ipv4; ipv4;
} }
protocol ripng { protocol rip ng {
ipv6; ipv6;
} }

View File

@ -25,9 +25,10 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#include <sys/select.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/un.h>
#include "nest/bird.h" #include "nest/bird.h"
#include "lib/resource.h" #include "lib/resource.h"

View File

@ -52,7 +52,7 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/string.h" #include "lib/string.h"
#include "lib/event.h" #include "lib/event.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h" #include "filter/filter.h"
@ -102,9 +102,9 @@ config_alloc(const char *name)
c->pool = p; c->pool = p;
c->mem = l; c->mem = l;
c->file_name = ndup; c->file_name = ndup;
c->load_time = now; c->load_time = current_time();
c->tf_route = c->tf_proto = (struct timeformat){"%T", "%F", 20*3600}; c->tf_route = c->tf_proto = TM_ISO_SHORT_MS;
c->tf_base = c->tf_log = (struct timeformat){"%F %T", NULL, 0}; c->tf_base = c->tf_log = TM_ISO_LONG_MS;
c->gr_wait = DEFAULT_GR_WAIT; c->gr_wait = DEFAULT_GR_WAIT;
return c; return c;
@ -219,11 +219,6 @@ global_commit(struct config *new, struct config *old)
if (!old) if (!old)
return 0; 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) if (!new->router_id)
{ {
new->router_id = old->router_id; new->router_id = old->router_id;
@ -307,7 +302,7 @@ config_done(void *unused UNUSED)
* config_commit - commit a configuration * config_commit - commit a configuration
* @c: new configuration * @c: new configuration
* @type: type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD) * @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 * When a configuration is parsed and prepared for use, the
* config_commit() function starts the process of reconfiguration. * config_commit() function starts the process of reconfiguration.
@ -331,7 +326,7 @@ config_done(void *unused UNUSED)
* are accepted. * are accepted.
*/ */
int int
config_commit(struct config *c, int type, int timeout) config_commit(struct config *c, int type, uint timeout)
{ {
if (shutting_down) if (shutting_down)
{ {
@ -340,8 +335,8 @@ config_commit(struct config *c, int type, int timeout)
} }
undo_available = 1; undo_available = 1;
if (timeout > 0) if (timeout)
tm_start(config_timer, timeout); tm_start(config_timer, timeout S);
else else
tm_stop(config_timer); tm_stop(config_timer);
@ -452,7 +447,7 @@ config_undo(void)
extern void cmd_reconfig_undo_notify(void); extern void cmd_reconfig_undo_notify(void);
static void static void
config_timeout(struct timer *t UNUSED) config_timeout(timer *t UNUSED)
{ {
log(L_INFO "Config timeout expired, starting undo"); log(L_INFO "Config timeout expired, starting undo");
cmd_reconfig_undo_notify(); cmd_reconfig_undo_notify();

View File

@ -13,7 +13,7 @@
#include "lib/ip.h" #include "lib/ip.h"
#include "lib/hash.h" #include "lib/hash.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
/* Configuration structure */ /* Configuration structure */
@ -32,16 +32,13 @@ struct config {
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */ struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
u32 router_id; /* Our Router ID */ 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_debug; /* Default protocol debug mask */
unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */ unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */
struct timeformat tf_route; /* Time format for 'show route' */ struct timeformat tf_route; /* Time format for 'show route' */
struct timeformat tf_proto; /* Time format for 'show protocol' */ struct timeformat tf_proto; /* Time format for 'show protocol' */
struct timeformat tf_log; /* Time format for the logfile */ struct timeformat tf_log; /* Time format for the logfile */
struct timeformat tf_base; /* Time format for other purposes */ 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 cli_debug; /* Tracing of CLI connections and commands */
int latency_debug; /* I/O loop tracks duration of each event */ 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 */ struct config *fallback; /* Link to regular config for CLI parsing */
int obstacle_count; /* Number of items blocking freeing of this config */ int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */ 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. */ /* 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 config_parse(struct config *);
int cli_parse(struct config *); int cli_parse(struct config *);
void config_free(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_confirm(void);
int config_undo(void); int config_undo(void);
void config_init(void); void config_init(void);

View File

@ -14,7 +14,7 @@ CF_HDR
#include "conf/conf.h" #include "conf/conf.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
#include "lib/string.h" #include "lib/string.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/iface.h" #include "nest/iface.h"
@ -50,6 +50,8 @@ CF_DECLS
struct rtable_config *r; struct rtable_config *r;
struct channel_config *cc; struct channel_config *cc;
struct f_inst *x; struct f_inst *x;
struct f_dynamic_attr fda;
struct f_static_attr fsa;
struct filter *f; struct filter *f;
struct f_tree *e; struct f_tree *e;
struct f_trie *trie; struct f_trie *trie;
@ -61,7 +63,7 @@ CF_DECLS
struct lsadb_show_data *ld; struct lsadb_show_data *ld;
struct iface *iface; struct iface *iface;
void *g; void *g;
bird_clock_t time; btime time;
struct f_prefix px; struct f_prefix px;
struct proto_spec ps; struct proto_spec ps;
struct channel_limit cl; struct channel_limit cl;
@ -81,11 +83,10 @@ CF_DECLS
%type <iface> ipa_scope %type <iface> ipa_scope
%type <i> expr bool pxlen4 %type <i> expr bool pxlen4
%type <i32> expr_us %type <time> expr_us time
%type <time> datetime
%type <a> ipa %type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_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_ip6_sadr_ net_mpls_
%type <mls> label_stack_start label_stack %type <mls> label_stack_start label_stack
%type <t> text opttext %type <t> text opttext
@ -98,7 +99,7 @@ CF_DECLS
%left '!' %left '!'
%nonassoc '.' %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, FROM)
CF_GRAMMAR CF_GRAMMAR
@ -138,9 +139,9 @@ expr:
expr_us: expr_us:
expr S { $$ = (u32) $1 * 1000000; } expr S { $$ = $1 S_; }
| expr MS { $$ = (u32) $1 * 1000; } | expr MS { $$ = $1 MS_; }
| expr US { $$ = (u32) $1 * 1; } | expr US { $$ = $1 US_; }
; ;
/* Switches */ /* Switches */
@ -179,10 +180,6 @@ pxlen4:
if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2); if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
$$ = $2; $$ = $2;
} }
| ':' IP4 {
$$ = ip4_masklen($2);
if ($$ == 255) cf_error("Invalid netmask %I4", $2);
}
; ;
net_ip4_: IP4 pxlen4 net_ip4_: IP4 pxlen4
@ -208,6 +205,25 @@ net_ip6_: IP6 '/' NUM
n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen); n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
}; };
net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
{
if ($3 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $3);
if ($7 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $7);
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr($$, $1, $3, $5, $7);
net_addr_ip6_sadr *n = (void *) $$;
if (!net_validate_ip6_sadr(n))
cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
};
net_vpn4_: VPN_RD net_ip4_ net_vpn4_: VPN_RD net_ip4_
{ {
$$ = cfg_alloc(sizeof(net_addr_vpn4)); $$ = cfg_alloc(sizeof(net_addr_vpn4));
@ -236,6 +252,12 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
cf_error("Invalid max prefix length %u", $3); 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_ip_: net_ip4_ | net_ip6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ; net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ; net_roa_: net_roa4_ | net_roa6_ ;
@ -245,6 +267,8 @@ net_:
| net_vpn_ | net_vpn_
| net_roa_ | net_roa_
| net_flow_ | net_flow_
| net_ip6_sadr_
| net_mpls_
; ;
@ -309,11 +333,11 @@ label_stack:
} }
; ;
datetime: time:
TEXT { TEXT {
$$ = tm_parse_datetime($1); $$ = tm_parse_time($1);
if (!$$) if (!$$)
cf_error("Invalid date and time"); cf_error("Invalid date/time");
} }
; ;

View File

@ -11,16 +11,6 @@ CF_HDR
#define PARSER 1 #define PARSER 1
#include "nest/bird.h" #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" #include "lib/flowspec.h"

View File

@ -36,6 +36,12 @@ AC_ARG_ENABLE([libssh],
[enable_libssh=try] [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], AC_ARG_WITH([protocols],
[AS_HELP_STRING([--with-protocols=LIST], [include specified routing protocols @<:@all@:>@])], [AS_HELP_STRING([--with-protocols=LIST], [include specified routing protocols @<:@all@:>@])],
[], [],
@ -175,6 +181,8 @@ else
;; ;;
freebsd*) freebsd*)
sysdesc=bsd sysdesc=bsd
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
;; ;;
kfreebsd*) kfreebsd*)
sysdesc=bsd sysdesc=bsd
@ -239,6 +247,20 @@ if test "$enable_libssh" != no ; then
fi fi
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="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static"
all_protocols=`echo $all_protocols | sed 's/ /,/g'` all_protocols=`echo $all_protocols | sed 's/ /,/g'`
@ -287,18 +309,6 @@ esac
AC_CHECK_HEADERS_ONCE([alloca.h syslog.h]) AC_CHECK_HEADERS_ONCE([alloca.h syslog.h])
AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/socket.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_C_BIGENDIAN(
[AC_DEFINE([CPU_BIG_ENDIAN], [1], [Define to 1 if cpu is big endian])], [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])], [AC_DEFINE([CPU_LITTLE_ENDIAN], [1], [Define to 1 if cpu is little endian])],
@ -314,7 +324,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_DEFINE([HAVE_EXECINFO_H], [1], [Define to 1 if you have the <execinfo.h> header file.])
AC_SEARCH_LIBS([backtrace], [execinfo], AC_SEARCH_LIBS([backtrace], [execinfo],
[] [],
[AC_MSG_ERROR([Function backtrace not available.])] [AC_MSG_ERROR([Function backtrace not available.])]
) )
] ]
@ -358,12 +368,6 @@ if test "$enable_client" = yes ; then
[$TINFO_LIBS] [$TINFO_LIBS]
) )
AC_SEARCH_LIBS([add_history], [history readline],
[HISTORY_LIBS="$LIBS"; LIBS=""],
[AC_MSG_ERROR([The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client.])],
[$TINFO_LIBS]
)
AC_CHECK_LIB([readline], [rl_crlf], AC_CHECK_LIB([readline], [rl_crlf],
[AC_DEFINE([HAVE_RL_CRLF], [1], [Define to 1 if you have rl_crlf()])], [AC_DEFINE([HAVE_RL_CRLF], [1], [Define to 1 if you have rl_crlf()])],
[], [],
@ -377,7 +381,7 @@ if test "$enable_client" = yes ; then
) )
LIBS="$BASE_LIBS" LIBS="$BASE_LIBS"
CLIENT_LIBS="$HISTORY_LIBS $READLINE_LIBS $TINFO_LIBS" CLIENT_LIBS="$READLINE_LIBS $TINFO_LIBS"
fi fi
AC_SUBST([CLIENT]) AC_SUBST([CLIENT])
AC_SUBST([CLIENT_LIBS]) AC_SUBST([CLIENT_LIBS])
@ -396,6 +400,7 @@ AC_MSG_RESULT([ System configuration: $sysdesc])
AC_MSG_RESULT([ Debugging: $enable_debug]) AC_MSG_RESULT([ Debugging: $enable_debug])
AC_MSG_RESULT([ POSIX threads: $enable_pthreads]) AC_MSG_RESULT([ POSIX threads: $enable_pthreads])
AC_MSG_RESULT([ Routing protocols: $protocols]) AC_MSG_RESULT([ Routing protocols: $protocols])
AC_MSG_RESULT([ Kernel MPLS support: $enable_mpls_kernel])
AC_MSG_RESULT([ Client: $enable_client]) AC_MSG_RESULT([ Client: $enable_client])
rm -f $objdir/.*-stamp rm -f $objdir/.*-stamp

View File

@ -1,222 +1,204 @@
/* # This is a basic configuration file, which contains boilerplate options and
* This is an example configuration file # some basic examples. It allows the BIRD daemon to start but will not cause
* (for version 1.x.x, obsolete) # anything else to happen.
*/ #
# Please refer to the BIRD User's Guide documentation, which is also available
# Yes, even shell-like comments work... # online at http://bird.network.cz/ in HTML format, for more information on
# configuring BIRD and adding routing protocols.
# Configure logging # Configure logging
#log syslog { debug, trace, info, remote, warning, error, auth, fatal, bug }; log syslog all;
#log stderr all; # log "/var/log/bird.log" { debug, trace, info, remote, warning, error, auth, fatal, bug };
#log "tmp" all;
# Override router ID # Set router ID. It is a unique identification of your router, usually one of
#router id 198.51.100.1; # IPv4 addresses of the router. It is recommended to configure it explicitly.
# router id 198.51.100.1;
# You can define your own symbols... # Turn on global debugging of all protocols (all messages or just selected classes)
#define xyzzy = (120+10); # debug protocols all;
#define '1a-a1' = (30+40); # debug protocols { events, states };
# Define a route filter...
#filter test_filter {
# if net ~ 10.0.0.0/16 then accept;
# else reject;
#}
#filter sink { reject; }
#filter okay { accept; }
#include "filters.conf";
# Define another routing table
#table testable;
# Turn on global debugging of all protocols
#debug protocols all;
# Turn on internal watchdog # Turn on internal watchdog
#watchdog warning 5 s; # watchdog warning 5 s;
#watchdog timeout 30 s; # watchdog timeout 30 s;
# The direct protocol automatically generates device routes to # You can define your own constants
# all network interfaces. Can exist in as many instances as you wish # define my_asn = 65000;
# if you want to populate multiple routing tables with device routes. # define my_addr = 198.51.100.1;
#protocol direct {
# interface "-eth*", "*"; # Restrict network interfaces it works with
#}
# This pseudo-protocol performs synchronization between BIRD's routing # Tables master4 and master6 are defined by default
# tables and the kernel. If your kernel supports multiple routing tables # ipv4 table master4;
# (as Linux 2.2.x does), you can run multiple instances of the kernel # ipv6 table master6;
# protocol and synchronize different kernel tables with different BIRD tables.
protocol kernel {
# learn; # Learn all alien routes from the kernel
persist; # Don't remove routes on bird shutdown
scan time 20; # Scan kernel routing table every 20 seconds
# import none; # Default is import all
export all; # Default is export none
# kernel table 5; # Kernel table to synchronize with (default: main)
}
# This pseudo-protocol watches all interface up/down events. # Define more tables, e.g. for policy routing or as MRIB
# ipv4 table mrib4;
# ipv6 table mrib6;
# The Device protocol is not a real routing protocol. It does not generate any
# routes and it only serves as a module for getting information about network
# interfaces from the kernel. It is necessary in almost any configuration.
protocol device { protocol device {
scan time 10; # Scan interfaces every 10 seconds
} }
# Static routes (again, there can be multiple instances, so that you # The direct protocol is not a real routing protocol. It automatically generates
# can disable/enable various groups of static routes on the fly). # direct routes to all network interfaces. Can exist in as many instances as you
# wish if you want to populate multiple routing tables with direct routes.
protocol direct {
disabled; # Disable by default
ipv4; # Connect to default IPv4 table
ipv6; # ... and to default IPv6 table
}
# The Kernel protocol is not a real routing protocol. Instead of communicating
# with other routers in the network, it performs synchronization of BIRD
# routing tables with the OS kernel. One instance per table.
protocol kernel {
ipv4 { # Connect protocol to IPv4 table by channel
# table master4; # Default IPv4 table is master4
# import all; # Import to table, default is import all
export all; # Export to protocol. default is export none
};
# learn; # Learn alien routes from the kernel
# kernel table 10; # Kernel table to synchronize with (default: main)
}
# Another instance for IPv6, skipping default options
protocol kernel {
ipv6 { export all; };
}
# Static routes (Again, there can be multiple instances, for different address
# families and to disable/enable various groups of static routes on the fly).
protocol static { protocol static {
# disabled; # Disable by default ipv4; # Again, IPv4 channel with default options
# table testable; # Connect to a non-default table
# preference 1000; # Default preference of routes # route 0.0.0.0/0 via 198.51.100.10;
# debug { states, routes, filters, interfaces, events, packets }; # route 192.0.2.0/24 blackhole;
# debug all;
# route 0.0.0.0/0 via 198.51.100.13;
# route 198.51.100.0/25 unreachable;
# route 10.0.0.0/8 unreachable; # route 10.0.0.0/8 unreachable;
# route 10.1.1.0:255.255.255.0 via 198.51.100.3; # route 10.2.0.0/24 via "eth0";
# route 10.1.2.0:255.255.255.0 via 198.51.100.3; # # Static routes can be defined with optional attributes
# route 10.1.3.0:255.255.255.0 via 198.51.100.4; # route 10.1.1.0/24 via 198.51.100.3 { rip_metric = 3; };
# route 10.2.0.0/24 via "arc0"; # route 10.1.2.0/24 via 198.51.100.3 { ospf_metric1 = 100; };
# route 10.1.3.0/24 via 198.51.100.4 { ospf_metric2 = 100; };
} }
# Pipe protocol connects two routing tables... Beware of loops. # Pipe protocol connects two routing tables. Beware of loops.
#protocol pipe { # protocol pipe {
# peer table testable; # table master4; # No ipv4/ipv6 channel definition like in other protocols
# Define what routes do we export to this protocol / import from it. # peer table mrib4;
# import all; # default is all # import all; # Direction peer table -> table
# export all; # default is none # export all; # Direction table -> peer table
# import none; # If you wish to disable imports # }
# import filter test_filter; # Use named filter
# import where source = RTS_DEVICE; # Use explicit filter
#}
# RIP aka Rest In Pieces... # RIP example, both RIP and RIPng are supported
#protocol rip MyRIP { # You can also use an explicit name # protocol rip {
# preference xyzzy; # ipv4 {
# debug all; # # Export direct, static routes and ones from RIP itself
# port 1520; # import all;
# period 7; # export where source ~ [ RTS_DEVICE, RTS_STATIC, RTS_RIP ];
# infinity 16;
# garbage time 60;
# interface "*" { mode broadcast; };
# honor neighbor; # To whom do we agree to send the routing table
# honor always;
# honor never;
# passwords {
# password "nazdar";
# }; # };
# authentication none; # interface "eth*" {
# import filter { print "importing"; accept; }; # update time 10; # Default period is 30
# export filter { print "exporting"; accept; }; # timeout time 60; # Default timeout is 180
#} # authentication cryptographic; # No authentication by default
# password "hello" { algorithm hmac sha256; }; # Default is MD5
# };
# }
#protocol ospf MyOSPF { # OSPF example, both OSPFv2 and OSPFv3 are supported
# tick 2; # protocol ospf v3 {
# rfc1583compat yes; # ipv6 {
# area 0.0.0.0 { # import all;
# stub no; # export where source = RTS_STATIC;
# };
# area 0 {
# interface "eth*" { # interface "eth*" {
# hello 9; # type broadcast; # Detected by default
# retransmit 6; # cost 10; # Interface metric
# cost 10; # hello 5; # Default hello perid 10 is too long
# transmit delay 5;
# dead count 5;
# wait 50;
# type broadcast;
# authentication simple;
# password "pass";
# }; # };
# interface "arc0" { # interface "tun*" {
# rx buffer large; # type ptp; # PtP mode, avoids DR selection
# type nonbroadcast; # cost 100; # Interface metric
# poll 14; # hello 5; # Default hello perid 10 is too long
# dead 75;
# neighbors {
# 10.1.1.2 eligible;
# 10.1.1.4;
# };
# strict nonbroadcast yes;
# }; # };
# interface "xxx0" { # interface "dummy0" {
# passwords { # stub; # Stub interface, just propagate it
# password "abc" {
# id 1;
# generate to "22-04-2003 11:00:06";
# accept to "17-01-2004 12:01:05";
# };
# password "def" {
# id 2;
# generate from "22-04-2003 11:00:07";
# accept from "17-01-2003 12:01:05";
# };
# };
# authentication cryptographic;
# }; # };
# }; # };
# area 20 {
# stub 1;
# interface "ppp1" {
# hello 8;
# authentication none;
# };
# interface "fr*";
# virtual link 192.168.0.1 {
# password "sdsdffsdfg";
# authentication cryptographic;
# };
# };
#} #}
# Define simple filter as an example for BGP import filter
# See https://gitlab.labs.nic.cz/labs/bird/wikis/BGP_filtering for more examples
# filter rt_import
# {
# if bgp_path.first != 64496 then accept;
# if bgp_path.len > 64 then accept;
# if bgp_next_hop != from then accept;
# reject;
# }
#protocol bgp { # BGP example, explicit name 'uplink1' is used instead of default 'bgp1'
# disabled; # protocol bgp uplink1 {
# description "My BGP uplink"; # description "My BGP uplink";
# local as 65000; # local 198.51.100.1 as 65000;
# neighbor 198.51.100.130 as 64496; # neighbor 198.51.100.10 as 64496;
# multihop; # hold time 90; # Default is 240
# hold time 240;
# startup hold time 240;
# connect retry time 120;
# keepalive time 80; # defaults to hold time / 3
# start delay time 5; # How long do we wait before initial connect
# error wait time 60, 300;# Minimum and maximum time we wait after an error (when consecutive
# # errors occur, we increase the delay exponentially ...
# error forget time 300; # ... until this timeout expires)
# disable after error; # Disable the protocol automatically when an error occurs
# next hop self; # Disable next hop processing and always advertise our local address as nexthop
# path metric 1; # Prefer routes with shorter paths (like Cisco does)
# default bgp_med 0; # MED value we use for comparison when none is defined
# default bgp_local_pref 0; # The same for local preference
# source address 198.51.100.14; # What local address we use for the TCP connection
# password "secret"; # Password used for MD5 authentication # password "secret"; # Password used for MD5 authentication
# rr client; # I am a route reflector and the neighor is my client #
# rr cluster id 1.0.0.1; # Use this value for cluster id instead of my router id # ipv4 { # regular IPv4 unicast (1/1)
# export where source=RTS_STATIC; # import filter rt_import;
# export filter { # export where source ~ [ RTS_STATIC, RTS_BGP ];
# if source = RTS_STATIC then { # };
# bgp_community = -empty-; bgp_community = add(bgp_community,(65000,5678)); #
# bgp_origin = 0; # ipv6 { # regular IPv6 unicast (2/1)
# bgp_community = -empty-; bgp_community.add((65000,5678)); # import filter rt_import;
# if (65000,64501) ~ bgp_community then # export filter { # The same as 'where' expression above
# bgp_community.add((0, 1)); # if source ~ [ RTS_STATIC, RTS_BGP ]
# if bgp_path ~ [= 65000 =] then # then accept;
# bgp_path.prepend(65000); # else reject;
# accept; # };
# } # };
# reject; #
# ipv4 multicast { # IPv4 multicast topology (1/2)
# table mrib4; # explicit IPv4 table
# import filter rt_import;
# export all;
# };
#
# ipv6 multicast { # IPv6 multicast topology (2/2)
# table mrib6; # explicit IPv6 table
# import filter rt_import;
# export all;
# }; # };
#} #}
#
# Template usage example # Template example. Using templates to define IBGP route reflector clients.
#template bgp rr_client { # template bgp rr_clients {
# disabled; # local 10.0.0.1 as 65000;
# local as 65000; # neighbor as 65000;
# multihop;
# rr client; # rr client;
# rr cluster id 1.0.0.1; # rr cluster id 1.0.0.1;
#}
# #
#protocol bgp rr_abcd from rr_client { # ipv4 {
# neighbor 10.1.4.7 as 65000; # import all;
#} # export where source = RTS_BGP;
# };
#
# ipv6 {
# import all;
# export where source = RTS_BGP;
# };
# }
#
# protocol bgp client1 from rr_clients {
# neighbor 10.0.1.1;
# }
#
# protocol bgp client2 from rr_clients {
# neighbor 10.0.2.1;
# }
#
# protocol bgp client3 from rr_clients {
# neighbor 10.0.3.1;
# }

View File

@ -28,20 +28,15 @@ flow6 table flowtab6;
protocol device { protocol device {
scan time 10;
} }
protocol kernel kernel4 { protocol kernel kernel4 {
scan time 20;
ipv4 { ipv4 {
export all; export all;
}; };
} }
protocol kernel kernel6 { protocol kernel kernel6 {
scan time 20;
ipv6 { ipv6 {
export all; export all;
}; };
@ -169,8 +164,6 @@ protocol pipe {
} }
protocol ospf v2 ospf4 { protocol ospf v2 ospf4 {
# ecmp;
ipv4 { ipv4 {
import all; import all;
# export where source = RTS_STATIC; # export where source = RTS_STATIC;
@ -186,8 +179,6 @@ protocol ospf v2 ospf4 {
protocol ospf v3 ospf6 { protocol ospf v3 ospf6 {
# ecmp;
ipv6 { ipv6 {
import all; import all;
# export where source = RTS_STATIC; # export where source = RTS_STATIC;
@ -251,7 +242,7 @@ protocol bgp {
}; };
# IPv6 with MPLS labels (2/4) # IPv6 with MPLS labels (2/4)
ipv6 multicast { ipv6 mpls {
# explicit IPv6 table # explicit IPv6 table
table mtab6; table mtab6;
import all; import all;

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,6 @@ CF_HDR
CF_DEFINES CF_DEFINES
#define P(a,b) ((a << 8) | b)
static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; } static inline u32 pair(u32 a, u32 b) { return (a << 16) | b; }
static inline u32 pair_a(u32 p) { return p >> 16; } static inline u32 pair_a(u32 p) { return p >> 16; }
static inline u32 pair_b(u32 p) { return p & 0xFFFF; } static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
@ -112,7 +110,7 @@ f_new_ec_item(u32 kind, u32 ipv4_used, u32 key, u32 vf, u32 vt)
{ {
u64 fm, to; u64 fm, to;
if (ipv4_used || (key >= 0x10000)) { if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
check_u16(vf); check_u16(vf);
if (vt == EC_ALL) if (vt == EC_ALL)
vt = 0xFFFF; vt = 0xFFFF;
@ -157,12 +155,11 @@ f_new_lc_item(u32 f1, u32 t1, u32 f2, u32 t2, u32 f3, u32 t3)
} }
static inline struct f_inst * static inline struct f_inst *
f_generate_empty(struct f_inst *dyn) f_generate_empty(struct f_dynamic_attr dyn)
{ {
struct f_inst *e = f_new_inst(); struct f_inst *e = f_new_inst(FI_EMPTY);
e->code = 'E';
switch (dyn->aux & EAF_TYPE_MASK) { switch (dyn.type & EAF_TYPE_MASK) {
case EAF_TYPE_AS_PATH: case EAF_TYPE_AS_PATH:
e->aux = T_PATH; e->aux = T_PATH;
break; break;
@ -179,9 +176,9 @@ f_generate_empty(struct f_inst *dyn)
cf_error("Can't empty that attribute"); cf_error("Can't empty that attribute");
} }
dyn->code = P('e','S'); struct f_inst *s = f_new_inst_da(FI_EA_SET, dyn);
dyn->a1.p = e; s->a1.p = e;
return dyn; return s;
} }
@ -190,21 +187,19 @@ f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
{ {
struct f_inst *rv; struct f_inst *rv;
if ((t1->code == 'c') && (t2->code == 'c')) { if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT)) if ((t1->aux != T_INT) || (t2->aux != T_INT))
cf_error( "Can't operate with value of non-integer type in pair constructor"); cf_error( "Can't operate with value of non-integer type in pair constructor");
check_u16(t1->a2.i); check_u16(t1->a2.i);
check_u16(t2->a2.i); check_u16(t2->a2.i);
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT);
rv->code = 'c';
rv->aux = T_PAIR; rv->aux = T_PAIR;
rv->a2.i = pair(t1->a2.i, t2->a2.i); rv->a2.i = pair(t1->a2.i, t2->a2.i);
} }
else { else {
rv = f_new_inst(); rv = f_new_inst(FI_PAIR_CONSTRUCT);
rv->code = P('m', 'p');
rv->a1.p = t1; rv->a1.p = t1;
rv->a2.p = t2; rv->a2.p = t2;
} }
@ -219,7 +214,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
int c1 = 0, c2 = 0, ipv4_used = 0; int c1 = 0, c2 = 0, ipv4_used = 0;
u32 key = 0, val2 = 0; u32 key = 0, val2 = 0;
if (tk->code == 'c') { if (tk->fi_code == FI_CONSTANT) {
c1 = 1; c1 = 1;
if (tk->aux == T_INT) { if (tk->aux == T_INT) {
@ -233,7 +228,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
} }
/* IP->Quad implicit conversion */ /* IP->Quad implicit conversion */
else if (tk->code == 'C') { else if (tk->fi_code == FI_CONSTANT_INDIRECT) {
c1 = 1; c1 = 1;
struct f_val *val = tk->a1.p; struct f_val *val = tk->a1.p;
@ -250,7 +245,7 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor"); cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
} }
if (tv->code == 'c') { if (tv->fi_code == FI_CONSTANT) {
if (tv->aux != T_INT) if (tv->aux != T_INT)
cf_error("Can't operate with value of non-integer type in EC constructor"); cf_error("Can't operate with value of non-integer type in EC constructor");
c2 = 1; c2 = 1;
@ -276,15 +271,13 @@ f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
} }
NEW_F_VAL; NEW_F_VAL;
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->code = 'C';
rv->a1.p = val; rv->a1.p = val;
val->type = T_EC; val->type = T_EC;
val->val.ec = ec; val->val.ec = ec;
} }
else { else {
rv = f_new_inst(); rv = f_new_inst(FI_EC_CONSTRUCT);
rv->code = P('m','c');
rv->aux = kind; rv->aux = kind;
rv->a1.p = tk; rv->a1.p = tk;
rv->a2.p = tv; rv->a2.p = tv;
@ -298,12 +291,11 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{ {
struct f_inst *rv; struct f_inst *rv;
if ((t1->code == 'c') && (t2->code == 'c') && (t3->code == 'c')) { if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT)) if ((t1->aux != T_INT) || (t2->aux != T_INT) || (t3->aux != T_INT))
cf_error( "LC - Can't operate with value of non-integer type in tuple constructor"); cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
rv = f_new_inst(); rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->code = 'C';
NEW_F_VAL; NEW_F_VAL;
rv->a1.p = val; rv->a1.p = val;
@ -314,7 +306,7 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
{ {
rv = cfg_allocz(sizeof(struct f_inst3)); rv = cfg_allocz(sizeof(struct f_inst3));
rv->lineno = ifs->lino; rv->lineno = ifs->lino;
rv->code = P('m','l'); rv->fi_code = FI_LC_CONSTRUCT;
rv->a1.p = t1; rv->a1.p = t1;
rv->a2.p = t2; rv->a2.p = t2;
INST3(rv).p = t3; INST3(rv).p = t3;
@ -323,6 +315,27 @@ f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
return rv; return rv;
} }
static inline struct f_inst *
f_generate_path_mask(struct f_path_mask *t)
{
for (struct f_path_mask *tt = t; tt; tt = tt->next) {
if (tt->kind == PM_ASN_EXPR) {
struct f_inst *mrv = f_new_inst(FI_PATHMASK_CONSTRUCT);
mrv->a1.p = t;
return mrv;
}
}
NEW_F_VAL;
val->type = T_PATH_MASK;
val->val.path_mask = t;
struct f_inst *rv = f_new_inst(FI_CONSTANT_INDIRECT);
rv->a1.p = val;
return rv;
}
/* /*
* Remove all new lines and doubled whitespaces * Remove all new lines and doubled whitespaces
* and convert all tabulators to spaces * and convert all tabulators to spaces
@ -372,8 +385,7 @@ static struct f_inst *
assert_done(struct f_inst *expr, const char *start, const char *end) assert_done(struct f_inst *expr, const char *start, const char *end)
{ {
struct f_inst *i; struct f_inst *i;
i = f_new_inst(); i = f_new_inst(FI_ASSERT);
i->code = P('a','s');
i->a1.p = expr; i->a1.p = expr;
if (end >= start) if (end >= start)
@ -412,7 +424,9 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%nonassoc THEN %nonassoc THEN
%nonassoc ELSE %nonassoc ELSE
%type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn dynamic_attr static_attr function_call symbol bgp_path_expr %type <x> term block cmds cmds_int cmd function_body constant constructor print_one print_list var_list var_listn function_call symbol bgp_path_expr
%type <fda> dynamic_attr
%type <fsa> static_attr
%type <f> filter filter_body where_filter %type <f> filter filter_body where_filter
%type <i> type break_command ec_kind %type <i> type break_command ec_kind
%type <i32> cnum %type <i32> cnum
@ -421,7 +435,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom switch_atom fipa %type <v> set_atom switch_atom fipa
%type <px> fprefix %type <px> fprefix
%type <s> decls declsn one_decl function_params %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 %type <t> get_cf_position
CF_GRAMMAR CF_GRAMMAR
@ -543,16 +557,13 @@ where_filter:
/* Construct 'IF term THEN ACCEPT; REJECT;' */ /* Construct 'IF term THEN ACCEPT; REJECT;' */
struct filter *f = cfg_alloc(sizeof(struct filter)); struct filter *f = cfg_alloc(sizeof(struct filter));
struct f_inst *i, *acc, *rej; struct f_inst *i, *acc, *rej;
acc = f_new_inst(); /* ACCEPT */ acc = f_new_inst(FI_PRINT_AND_DIE); /* ACCEPT */
acc->code = P('p',',');
acc->a1.p = NULL; acc->a1.p = NULL;
acc->a2.i = F_ACCEPT; acc->a2.i = F_ACCEPT;
rej = f_new_inst(); /* REJECT */ rej = f_new_inst(FI_PRINT_AND_DIE); /* REJECT */
rej->code = P('p',',');
rej->a1.p = NULL; rej->a1.p = NULL;
rej->a2.i = F_REJECT; rej->a2.i = F_REJECT;
i = f_new_inst(); /* IF */ i = f_new_inst(FI_CONDITION); /* IF */
i->code = '?';
i->a1.p = $2; i->a1.p = $2;
i->a2.p = acc; i->a2.p = acc;
i->next = rej; i->next = rej;
@ -571,8 +582,7 @@ function_body:
decls '{' cmds '}' { decls '{' cmds '}' {
if ($1) { if ($1) {
/* Prepend instruction to clear local variables */ /* Prepend instruction to clear local variables */
$$ = f_new_inst(); $$ = f_new_inst(FI_CLEAR_LOCAL_VARS);
$$->code = P('c','v');
$$->a1.p = $1; $$->a1.p = $1;
$$->next = $3; $$->next = $3;
} else } else
@ -755,7 +765,7 @@ switch_body: /* EMPTY */ { $$ = NULL; }
} }
; ;
/* CONST '(' expr ')' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $3; } */ /* CONST '(' expr ')' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $3; } */
bgp_path_expr: bgp_path_expr:
symbol { $$ = $1; } symbol { $$ = $1; }
@ -763,43 +773,36 @@ bgp_path_expr:
; ;
bgp_path: bgp_path:
PO bgp_path_tail1 PC { $$ = $2; } PO bgp_path_tail PC { $$ = $2; }
| '/' bgp_path_tail2 '/' { $$ = $2; }
; ;
bgp_path_tail1: bgp_path_tail:
NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; } NUM bgp_path_tail { $$ = 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; } | 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_tail1 { $$ = 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_ASTERISK; }
| '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; } | '?' bgp_path_tail { $$ = 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_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
| { $$ = NULL; } | { $$ = 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: constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; } NUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } | TRUE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 1; }
| FALSE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 0; } | FALSE { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_BOOL; $$->a2.i = 0; }
| TEXT { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_STRING; $$->a2.p = $1; } | TEXT { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_STRING; $$->a2.p = $1; }
| fipa { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; $$->a1.p = val; *val = $1; } | fipa { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); $$->a1.p = val; *val = $1; }
| VPN_RD { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_RD; val->val.ec = $1; $$->a1.p = val; } | VPN_RD { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_RD; val->val.ec = $1; $$->a1.p = val; }
| net_ { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_NET; val->val.net = $1; $$->a1.p = val; } | net_ { NEW_F_VAL; $$ = f_new_inst(FI_CONSTANT_INDIRECT); val->type = T_NET; val->val.net = $1; $$->a1.p = val; }
| '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); } | '[' set_items ']' { DBG( "We've got a set here..." ); $$ = f_new_inst(FI_CONSTANT); $$->aux = T_SET; $$->a2.p = build_tree($2); DBG( "ook\n" ); }
| '[' fprefix_set ']' { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_PREFIX_SET; $$->a2.p = $2; } | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT); $$->aux = T_PREFIX_SET; $$->a2.p = $2; }
| ENUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; } | ENUM { $$ = f_new_inst(FI_CONSTANT); $$->aux = $1 >> 16; $$->a2.i = $1 & 0xffff; }
| bgp_path { NEW_F_VAL; $$ = f_new_inst(); $$->code = 'C'; val->type = T_PATH_MASK; val->val.path_mask = $1; $$->a1.p = val; }
; ;
constructor: constructor:
'(' term ',' term ')' { $$ = f_generate_dpair($2, $4); } '(' term ',' term ')' { $$ = f_generate_dpair($2, $4); }
| '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); } | '(' ec_kind ',' term ',' term ')' { $$ = f_generate_ec($2, $4, $6); }
| '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); } | '(' term ',' term ',' term ')' { $$ = f_generate_lc($2, $4, $6); }
| bgp_path { $$ = f_generate_path_mask($1); }
; ;
@ -808,7 +811,7 @@ constructor:
* For such cases, we force the dynamic_attr list to contain * For such cases, we force the dynamic_attr list to contain
* at least an invalid token, so it is syntantically correct. * at least an invalid token, so it is syntantically correct.
*/ */
CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = NULL; }) CF_ADDTO(dynamic_attr, INVALID_TOKEN { $$ = (struct f_dynamic_attr) {}; })
rtadot: /* EMPTY, we are not permitted RTA. prefix */ rtadot: /* EMPTY, we are not permitted RTA. prefix */
; ;
@ -820,8 +823,7 @@ function_call:
if ($1->class != SYM_FUNCTION) if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really."); cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name); DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(); $$ = f_new_inst(FI_CALL);
$$->code = P('c','a');
$$->a1.p = inst; $$->a1.p = inst;
$$->a2.p = $1->def; $$->a2.p = $1->def;
sym = $1->aux2; sym = $1->aux2;
@ -838,11 +840,9 @@ function_call:
symbol: symbol:
SYM { SYM {
$$ = f_new_inst();
switch ($1->class & 0xff00) { switch ($1->class & 0xff00) {
case SYM_CONSTANT: $$->code = 'C'; break; case SYM_CONSTANT: $$ = f_new_inst(FI_CONSTANT_INDIRECT); break;
case SYM_VARIABLE: $$->code = 'V'; break; case SYM_VARIABLE: $$ = f_new_inst(FI_VARIABLE); break;
default: cf_error("%s: variable expected.", $1->name); default: cf_error("%s: variable expected.", $1->name);
} }
@ -851,57 +851,57 @@ symbol:
} }
static_attr: static_attr:
FROM { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_FROM; $$->a1.i = 1; } FROM { $$ = f_new_static_attr(T_IP, SA_FROM, 1); }
| GW { $$ = f_new_inst(); $$->aux = T_IP; $$->a2.i = SA_GW; $$->a1.i = 1; } | GW { $$ = f_new_static_attr(T_IP, SA_GW, 1); }
| NET { $$ = f_new_inst(); $$->aux = T_NET; $$->a2.i = SA_NET; } | NET { $$ = f_new_static_attr(T_NET, SA_NET, 0); }
| PROTO { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_PROTO; } | PROTO { $$ = f_new_static_attr(T_STRING, SA_PROTO, 0); }
| SOURCE { $$ = f_new_inst(); $$->aux = T_ENUM_RTS; $$->a2.i = SA_SOURCE; } | SOURCE { $$ = f_new_static_attr(T_ENUM_RTS, SA_SOURCE, 0); }
| SCOPE { $$ = f_new_inst(); $$->aux = T_ENUM_SCOPE; $$->a2.i = SA_SCOPE; $$->a1.i = 1; } | SCOPE { $$ = f_new_static_attr(T_ENUM_SCOPE, SA_SCOPE, 1); }
| DEST { $$ = f_new_inst(); $$->aux = T_ENUM_RTD; $$->a2.i = SA_DEST; $$->a1.i = 1; } | DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 1); }
| IFNAME { $$ = f_new_inst(); $$->aux = T_STRING; $$->a2.i = SA_IFNAME; } | IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_inst(); $$->aux = T_INT; $$->a2.i = SA_IFINDEX; } | IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 0); }
; ;
term: term:
'(' term ')' { $$ = $2; } '(' term ')' { $$ = $2; }
| term '+' term { $$ = f_new_inst(); $$->code = '+'; $$->a1.p = $1; $$->a2.p = $3; } | term '+' term { $$ = f_new_inst(FI_ADD); $$->a1.p = $1; $$->a2.p = $3; }
| term '-' term { $$ = f_new_inst(); $$->code = '-'; $$->a1.p = $1; $$->a2.p = $3; } | term '-' term { $$ = f_new_inst(FI_SUBTRACT); $$->a1.p = $1; $$->a2.p = $3; }
| term '*' term { $$ = f_new_inst(); $$->code = '*'; $$->a1.p = $1; $$->a2.p = $3; } | term '*' term { $$ = f_new_inst(FI_MULTIPLY); $$->a1.p = $1; $$->a2.p = $3; }
| term '/' term { $$ = f_new_inst(); $$->code = '/'; $$->a1.p = $1; $$->a2.p = $3; } | term '/' term { $$ = f_new_inst(FI_DIVIDE); $$->a1.p = $1; $$->a2.p = $3; }
| term AND term { $$ = f_new_inst(); $$->code = '&'; $$->a1.p = $1; $$->a2.p = $3; } | term AND term { $$ = f_new_inst(FI_AND); $$->a1.p = $1; $$->a2.p = $3; }
| term OR term { $$ = f_new_inst(); $$->code = '|'; $$->a1.p = $1; $$->a2.p = $3; } | term OR term { $$ = f_new_inst(FI_OR); $$->a1.p = $1; $$->a2.p = $3; }
| term '=' term { $$ = f_new_inst(); $$->code = P('=','='); $$->a1.p = $1; $$->a2.p = $3; } | term '=' term { $$ = f_new_inst(FI_EQ); $$->a1.p = $1; $$->a2.p = $3; }
| term NEQ term { $$ = f_new_inst(); $$->code = P('!','='); $$->a1.p = $1; $$->a2.p = $3; } | term NEQ term { $$ = f_new_inst(FI_NEQ); $$->a1.p = $1; $$->a2.p = $3; }
| term '<' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $1; $$->a2.p = $3; } | term '<' term { $$ = f_new_inst(FI_LT); $$->a1.p = $1; $$->a2.p = $3; }
| term LEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $1; $$->a2.p = $3; } | term LEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $1; $$->a2.p = $3; }
| term '>' term { $$ = f_new_inst(); $$->code = '<'; $$->a1.p = $3; $$->a2.p = $1; } | term '>' term { $$ = f_new_inst(FI_LT); $$->a1.p = $3; $$->a2.p = $1; }
| term GEQ term { $$ = f_new_inst(); $$->code = P('<','='); $$->a1.p = $3; $$->a2.p = $1; } | term GEQ term { $$ = f_new_inst(FI_LTE); $$->a1.p = $3; $$->a2.p = $1; }
| term '~' term { $$ = f_new_inst(); $$->code = '~'; $$->a1.p = $1; $$->a2.p = $3; } | term '~' term { $$ = f_new_inst(FI_MATCH); $$->a1.p = $1; $$->a2.p = $3; }
| term NMA term { $$ = f_new_inst(); $$->code = P('!','~'); $$->a1.p = $1; $$->a2.p = $3; } | term NMA term { $$ = f_new_inst(FI_NOT_MATCH);$$->a1.p = $1; $$->a2.p = $3; }
| '!' term { $$ = f_new_inst(); $$->code = '!'; $$->a1.p = $2; } | '!' term { $$ = f_new_inst(FI_NOT); $$->a1.p = $2; }
| DEFINED '(' term ')' { $$ = f_new_inst(); $$->code = P('d','e'); $$->a1.p = $3; } | DEFINED '(' term ')' { $$ = f_new_inst(FI_DEFINED); $$->a1.p = $3; }
| symbol { $$ = $1; } | symbol { $$ = $1; }
| constant { $$ = $1; } | constant { $$ = $1; }
| constructor { $$ = $1; } | constructor { $$ = $1; }
| PREFERENCE { $$ = f_new_inst(); $$->code = 'P'; } | PREFERENCE { $$ = f_new_inst(FI_PREF_GET); }
| rtadot static_attr { $$ = $2; $$->code = 'a'; } | rtadot static_attr { $$ = f_new_inst_sa(FI_RTA_GET, $2); }
| rtadot dynamic_attr { $$ = $2; $$->code = P('e','a'); } | rtadot dynamic_attr { $$ = f_new_inst_da(FI_EA_GET, $2); }
| term '.' IS_V4 { $$ = f_new_inst(); $$->code = P('I','i'); $$->a1.p = $1; } | term '.' IS_V4 { $$ = f_new_inst(FI_IS_V4); $$->a1.p = $1; }
| term '.' TYPE { $$ = f_new_inst(); $$->code = 'T'; $$->a1.p = $1; } | term '.' TYPE { $$ = f_new_inst(FI_TYPE); $$->a1.p = $1; }
| term '.' IP { $$ = f_new_inst(); $$->code = P('c','p'); $$->a1.p = $1; $$->aux = T_IP; } | term '.' IP { $$ = f_new_inst(FI_IP); $$->a1.p = $1; $$->aux = T_IP; }
| term '.' RD { $$ = f_new_inst(); $$->code = P('R','D'); $$->a1.p = $1; $$->aux = T_RD; } | term '.' RD { $$ = f_new_inst(FI_ROUTE_DISTINGUISHER); $$->a1.p = $1; $$->aux = T_RD; }
| term '.' LEN { $$ = f_new_inst(); $$->code = 'L'; $$->a1.p = $1; } | term '.' LEN { $$ = f_new_inst(FI_LENGTH); $$->a1.p = $1; }
| term '.' MAXLEN { $$ = f_new_inst(); $$->code = P('R','m'); $$->a1.p = $1; } | term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN); $$->a1.p = $1; }
| term '.' ASN { $$ = f_new_inst(); $$->code = P('R','a'); $$->a1.p = $1; } | term '.' ASN { $$ = f_new_inst(FI_ROA_ASN); $$->a1.p = $1; }
| term '.' MASK '(' term ')' { $$ = f_new_inst(); $$->code = P('i','M'); $$->a1.p = $1; $$->a2.p = $5; } | term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK); $$->a1.p = $1; $$->a2.p = $5; }
| term '.' FIRST { $$ = f_new_inst(); $$->code = P('a','f'); $$->a1.p = $1; } | term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST); $$->a1.p = $1; }
| term '.' LAST { $$ = f_new_inst(); $$->code = P('a','l'); $$->a1.p = $1; } | term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST); $$->a1.p = $1; }
| term '.' LAST_NONAGGREGATED { $$ = f_new_inst(); $$->code = P('a','L'); $$->a1.p = $1; } | term '.' LAST_NONAGGREGATED { $$ = f_new_inst(FI_AS_PATH_LAST_NAG); $$->a1.p = $1; }
/* Communities */ /* Communities */
/* This causes one shift/reduce conflict /* This causes one shift/reduce conflict
@ -911,19 +911,19 @@ term:
| rtadot dynamic_attr '.' RESET{ } | rtadot dynamic_attr '.' RESET{ }
*/ */
| '+' EMPTY '+' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_PATH; } | '+' EMPTY '+' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_PATH; }
| '-' EMPTY '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_CLIST; } | '-' EMPTY '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_CLIST; }
| '-' '-' EMPTY '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_ECLIST; } | '-' '-' EMPTY '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_ECLIST; }
| '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(); $$->code = 'E'; $$->aux = T_LCLIST; } | '-' '-' '-' EMPTY '-' '-' '-' { $$ = f_new_inst(FI_EMPTY); $$->aux = T_LCLIST; }
| PREPEND '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('A','p'); $$->a1.p = $3; $$->a2.p = $5; } | PREPEND '(' term ',' term ')' { $$ = f_new_inst(FI_PATH_PREPEND); $$->a1.p = $3; $$->a2.p = $5; }
| ADD '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; } | ADD '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'a'; }
| DELETE '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; } | DELETE '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'd'; }
| FILTER '(' term ',' term ')' { $$ = f_new_inst(); $$->code = P('C','a'); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; } | FILTER '(' term ',' term ')' { $$ = f_new_inst(FI_CLIST_ADD_DEL); $$->a1.p = $3; $$->a2.p = $5; $$->aux = 'f'; }
| ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); } | ROA_CHECK '(' rtable ')' { $$ = f_generate_roa_check($3, NULL, NULL); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); } | ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_generate_roa_check($3, $5, $7); }
| FORMAT '(' term ')' { $$ = f_new_inst(); $$->code = P('f','m'); $$->a1.p = $3; } | FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT); $$->a1.p = $3; }
/* | term '.' LEN { $$->code = P('P','l'); } */ /* | term '.' LEN { $$->code = P('P','l'); } */
@ -934,8 +934,7 @@ term:
if ($1->class != SYM_FUNCTION) if ($1->class != SYM_FUNCTION)
cf_error("You can't call something which is not a function. Really."); cf_error("You can't call something which is not a function. Really.");
DBG("You are calling function %s\n", $1->name); DBG("You are calling function %s\n", $1->name);
$$ = f_new_inst(); $$ = f_new_inst(FI_CALL);
$$->code = P('c','a');
$$->a1.p = inst; $$->a1.p = inst;
$$->a2.p = $1->def; $$->a2.p = $1->def;
sym = $1->aux2; sym = $1->aux2;
@ -960,7 +959,7 @@ break_command:
; ;
print_one: print_one:
term { $$ = f_new_inst(); $$->code = 'p'; $$->a1.p = $1; $$->a2.p = NULL; } term { $$ = f_new_inst(FI_PRINT); $$->a1.p = $1; $$->a2.p = NULL; }
; ;
print_list: /* EMPTY */ { $$ = NULL; } print_list: /* EMPTY */ { $$ = NULL; }
@ -974,15 +973,13 @@ print_list: /* EMPTY */ { $$ = NULL; }
; ;
var_listn: term { var_listn: term {
$$ = f_new_inst(); $$ = f_new_inst(FI_SET);
$$->code = 's';
$$->a1.p = NULL; $$->a1.p = NULL;
$$->a2.p = $1; $$->a2.p = $1;
$$->next = NULL; $$->next = NULL;
} }
| term ',' var_listn { | term ',' var_listn {
$$ = f_new_inst(); $$ = f_new_inst(FI_SET);
$$->code = 's';
$$->a1.p = NULL; $$->a1.p = NULL;
$$->a2.p = $1; $$->a2.p = $1;
$$->next = $3; $$->next = $3;
@ -995,73 +992,63 @@ var_list: /* EMPTY */ { $$ = NULL; }
cmd: cmd:
IF term THEN block { IF term THEN block {
$$ = f_new_inst(); $$ = f_new_inst(FI_CONDITION);
$$->code = '?';
$$->a1.p = $2; $$->a1.p = $2;
$$->a2.p = $4; $$->a2.p = $4;
} }
| IF term THEN block ELSE block { | IF term THEN block ELSE block {
struct f_inst *i = f_new_inst(); struct f_inst *i = f_new_inst(FI_CONDITION);
i->code = '?';
i->a1.p = $2; i->a1.p = $2;
i->a2.p = $4; i->a2.p = $4;
$$ = f_new_inst(); $$ = f_new_inst(FI_CONDITION);
$$->code = '?';
$$->a1.p = i; $$->a1.p = i;
$$->a2.p = $6; $$->a2.p = $6;
} }
| SYM '=' term ';' { | SYM '=' term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll set value\n" ); DBG( "Ook, we'll set value\n" );
if (($1->class & ~T_MASK) != SYM_VARIABLE) if (($1->class & ~T_MASK) != SYM_VARIABLE)
cf_error( "You may set only variables." ); cf_error( "You may set only variables." );
$$->code = 's'; $$ = f_new_inst(FI_SET);
$$->a1.p = $1; $$->a1.p = $1;
$$->a2.p = $3; $$->a2.p = $3;
} }
| RETURN term ';' { | RETURN term ';' {
$$ = f_new_inst();
DBG( "Ook, we'll return the value\n" ); DBG( "Ook, we'll return the value\n" );
$$->code = 'r'; $$ = f_new_inst(FI_RETURN);
$$->a1.p = $2; $$->a1.p = $2;
} }
| rtadot dynamic_attr '=' term ';' { | rtadot dynamic_attr '=' term ';' {
$$ = $2; $$ = f_new_inst_da(FI_EA_SET, $2);
$$->code = P('e','S');
$$->a1.p = $4; $$->a1.p = $4;
} }
| rtadot static_attr '=' term ';' { | rtadot static_attr '=' term ';' {
$$ = $2; $$ = f_new_inst_sa(FI_RTA_SET, $2);
if (!$$->a1.i) if (!$$->a1.i)
cf_error( "This static attribute is read-only."); cf_error( "This static attribute is read-only.");
$$->code = P('a','S');
$$->a1.p = $4; $$->a1.p = $4;
} }
| PREFERENCE '=' term ';' { | PREFERENCE '=' term ';' {
$$ = f_new_inst(); $$ = f_new_inst(FI_PREF_SET);
$$->code = P('P','S');
$$->a1.p = $3; $$->a1.p = $3;
} }
| UNSET '(' rtadot dynamic_attr ')' ';' { | UNSET '(' rtadot dynamic_attr ')' ';' {
$$ = $4; $$ = f_new_inst_da(FI_EA_SET, $4);
$$->aux = EAF_TYPE_UNDEF | EAF_TEMP; $$->aux = EAF_TYPE_UNDEF | EAF_TEMP;
$$->code = P('e','S');
$$->a1.p = NULL; $$->a1.p = NULL;
} }
| break_command print_list ';' { $$ = f_new_inst(); $$->code = P('p',','); $$->a1.p = $2; $$->a2.i = $1; } | break_command print_list ';' { $$ = f_new_inst(FI_PRINT_AND_DIE); $$->a1.p = $2; $$->a2.i = $1; }
| function_call ';' { $$ = $1; } | function_call ';' { $$ = $1; }
| CASE term '{' switch_body '}' { | CASE term '{' switch_body '}' {
$$ = f_new_inst(); $$ = f_new_inst(FI_SWITCH);
$$->code = P('S','W');
$$->a1.p = $2; $$->a1.p = $2;
$$->a2.p = build_tree( $4 ); $$->a2.p = build_tree( $4 );
} }
| rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); } | rtadot dynamic_attr '.' EMPTY ';' { $$ = f_generate_empty($2); }
| rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( P('A','p'), 'x', $2, $6 ); } | rtadot dynamic_attr '.' PREPEND '(' term ')' ';' { $$ = f_generate_complex( FI_PATH_PREPEND, 'x', $2, $6 ); }
| rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'a', $2, $6 ); } | rtadot dynamic_attr '.' ADD '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'a', $2, $6 ); }
| rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'd', $2, $6 ); } | rtadot dynamic_attr '.' DELETE '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'd', $2, $6 ); }
| rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( P('C','a'), 'f', $2, $6 ); } | rtadot dynamic_attr '.' FILTER '(' term ')' ';' { $$ = f_generate_complex( FI_CLIST_ADD_DEL, 'f', $2, $6 ); }
| BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); } | BT_ASSERT '(' get_cf_position term get_cf_position ')' ';' { $$ = assert_done($4, $3 + 1, $5 - 1); }
; ;

View File

@ -2,6 +2,7 @@
* Filters: utility functions * Filters: utility functions
* *
* Copyright 1998 Pavel Machek <pavel@ucw.cz> * Copyright 1998 Pavel Machek <pavel@ucw.cz>
* 2017 Jan Maria Matejka <mq@ucw.cz>
* *
* Can be freely distributed and used under the terms of the GNU GPL. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -13,43 +14,48 @@
#define P(a,b) ((a<<8) | b) #define P(a,b) ((a<<8) | b)
struct f_inst * struct f_inst *
f_new_inst(void) f_new_inst(enum f_instruction_code fi_code)
{ {
struct f_inst * ret; struct f_inst * ret;
ret = cfg_alloc(sizeof(struct f_inst)); ret = cfg_allocz(sizeof(struct f_inst));
ret->code = ret->aux = 0; ret->fi_code = fi_code;
ret->arg1 = ret->arg2 = ret->next = NULL;
ret->lineno = ifs->lino; ret->lineno = ifs->lino;
return ret; return ret;
} }
struct f_inst * struct f_inst *
f_new_dynamic_attr(int type, int f_type UNUSED, int code) f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da)
{ {
/* FIXME: Remove the f_type parameter? */ struct f_inst *ret = f_new_inst(fi_code);
struct f_inst *f = f_new_inst(); ret->aux = (da.f_type << 8) | da.type;
f->aux = type; ret->a2.i = da.ea_code;
f->a2.i = code; return ret;
return f; }
struct f_inst *
f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa)
{
struct f_inst *ret = f_new_inst(fi_code);
ret->aux = sa.f_type;
ret->a2.i = sa.sa_code;
ret->a1.i = sa.readonly;
return ret;
} }
/* /*
* Generate set_dynamic( operation( get_dynamic(), argument ) ) * Generate set_dynamic( operation( get_dynamic(), argument ) )
*/ */
struct f_inst * struct f_inst *
f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument) f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument)
{ {
struct f_inst *set_dyn = f_new_inst(), struct f_inst *set_dyn = f_new_inst_da(FI_EA_SET, da),
*oper = f_new_inst(), *oper = f_new_inst(operation),
*get_dyn = dyn; *get_dyn = f_new_inst_da(FI_EA_GET, da);
*set_dyn = *get_dyn;
get_dyn->code = P('e','a');
oper->code = operation;
oper->aux = operation_aux; oper->aux = operation_aux;
oper->a1.p = get_dyn; oper->a1.p = get_dyn;
oper->a2.p = argument; oper->a2.p = argument;
set_dyn->code = P('e','S');
set_dyn->a1.p = oper; set_dyn->a1.p = oper;
return set_dyn; return set_dyn;
} }
@ -58,7 +64,7 @@ struct f_inst *
f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn) f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn)
{ {
struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check)); struct f_inst_roa_check *ret = cfg_allocz(sizeof(struct f_inst_roa_check));
ret->i.code = P('R','C'); ret->i.fi_code = FI_ROA_CHECK;
ret->i.lineno = ifs->lino; ret->i.lineno = ifs->lino;
ret->i.arg1 = prefix; ret->i.arg1 = prefix;
ret->i.arg2 = asn; ret->i.arg2 = asn;

View File

@ -48,12 +48,21 @@
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h" #include "filter/filter.h"
#define P(a,b) ((a<<8) | b)
#define CMP_ERROR 999 #define CMP_ERROR 999
void (*bt_assert_hook)(int result, struct f_inst *assert); void (*bt_assert_hook)(int result, struct f_inst *assert);
static struct adata undef_adata; /* adata of length 0 used for undefined */
/* Special undef value for paths and clists */
static inline int
undef_value(struct f_val v)
{
return ((v.type == T_PATH) || (v.type == T_CLIST) ||
(v.type == T_ECLIST) || (v.type == T_LCLIST)) &&
(v.val.ad == &undef_adata);
}
static struct adata * static struct adata *
adata_empty(struct linpool *pool, int l) adata_empty(struct linpool *pool, int l)
{ {
@ -88,8 +97,7 @@ pm_format(struct f_path_mask *p, buffer *buf)
break; break;
case PM_ASN_EXPR: case PM_ASN_EXPR:
buffer_print(buf, "%u ", f_eval_asn((struct f_inst *) p->val)); ASSERT(0);
break;
} }
p = p->next; p = p->next;
@ -451,7 +459,6 @@ val_in_range(struct f_val v1, struct f_val v2)
if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST)) if (((v1.type == T_PAIR) || (v1.type == T_QUAD)) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, v1.val.i); return int_set_contains(v2.val.ad, v1.val.i);
/* IP->Quad implicit conversion */ /* IP->Quad implicit conversion */
if (val_is_ip4(v1) && (v2.type == T_CLIST)) if (val_is_ip4(v1) && (v2.type == T_CLIST))
return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip)); return int_set_contains(v2.val.ad, ipa_to_u32(v1.val.ip));
@ -576,7 +583,8 @@ val_format_str(struct f_val v) {
static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS; static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
#define runtime(fmt, ...) do { \ #define runtime(fmt, ...) do { \
log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \ if (!(f_flags & FF_SILENT)) \
log_rl(&rl_runtime_err, L_ERR "filters, line %d: " fmt, what->lineno, ##__VA_ARGS__); \
res.type = T_RETURN; \ res.type = T_RETURN; \
res.val.i = F_ERROR; \ res.val.i = F_ERROR; \
return res; \ return res; \
@ -620,22 +628,16 @@ static struct f_val
interpret(struct f_inst *what) interpret(struct f_inst *what)
{ {
struct symbol *sym; struct symbol *sym;
struct f_val v1, v2, res, *vp; struct f_val v1, v2, res = { .type = T_VOID }, *vp;
unsigned u1, u2; unsigned u1, u2;
int i; int i;
u32 as; u32 as;
for ( ; what; what = what->next) {
res.type = T_VOID; res.type = T_VOID;
if (!what) switch(what->fi_code) {
return res;
switch(what->code) {
case ',':
TWOARGS;
break;
/* Binary operators */ /* Binary operators */
case '+': case FI_ADD:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -643,7 +645,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '-': case FI_SUBTRACT:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -651,7 +653,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '*': case FI_MULTIPLY:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -659,7 +661,7 @@ interpret(struct f_inst *what)
default: runtime( "Usage of unknown type" ); default: runtime( "Usage of unknown type" );
} }
break; break;
case '/': case FI_DIVIDE:
TWOARGS_C; TWOARGS_C;
switch (res.type = v1.type) { switch (res.type = v1.type) {
case T_VOID: runtime( "Can't operate with values of type void" ); case T_VOID: runtime( "Can't operate with values of type void" );
@ -669,12 +671,12 @@ interpret(struct f_inst *what)
} }
break; break;
case '&': case FI_AND:
case '|': case FI_OR:
ARG(v1, a1.p); ARG(v1, a1.p);
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "Can't do boolean operation on non-booleans" ); runtime( "Can't do boolean operation on non-booleans" );
if (v1.val.i == (what->code == '|')) { if (v1.val.i == (what->fi_code == FI_OR)) {
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = v1.val.i; res.val.i = v1.val.i;
break; break;
@ -687,7 +689,7 @@ interpret(struct f_inst *what)
res.val.i = v2.val.i; res.val.i = v2.val.i;
break; break;
case P('m','p'): case FI_PAIR_CONSTRUCT:
TWOARGS; TWOARGS;
if ((v1.type != T_INT) || (v2.type != T_INT)) if ((v1.type != T_INT) || (v2.type != T_INT))
runtime( "Can't operate with value of non-integer type in pair constructor" ); runtime( "Can't operate with value of non-integer type in pair constructor" );
@ -699,7 +701,7 @@ interpret(struct f_inst *what)
res.type = T_PAIR; res.type = T_PAIR;
break; break;
case P('m','c'): case FI_EC_CONSTRUCT:
{ {
TWOARGS; TWOARGS;
@ -745,7 +747,7 @@ interpret(struct f_inst *what)
break; break;
} }
case P('m','l'): case FI_LC_CONSTRUCT:
{ {
TWOARGS; TWOARGS;
@ -763,6 +765,32 @@ interpret(struct f_inst *what)
break; break;
} }
case FI_PATHMASK_CONSTRUCT:
{
struct f_path_mask *tt = what->a1.p, *vbegin, **vv = &vbegin;
while (tt) {
*vv = lp_alloc(f_pool, sizeof(struct f_path_mask));
if (tt->kind == PM_ASN_EXPR) {
struct f_val res = interpret((struct f_inst *) tt->val);
(*vv)->kind = PM_ASN;
if (res.type != T_INT) {
runtime( "Error resolving path mask template: value not an integer" );
return (struct f_val) { .type = T_VOID };
}
(*vv)->val = res.val.i;
} else {
**vv = *tt;
}
tt = tt->next;
vv = &((*vv)->next);
}
res = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = vbegin };
break;
}
/* Relational operators */ /* Relational operators */
#define COMPARE(x) \ #define COMPARE(x) \
@ -781,12 +809,12 @@ interpret(struct f_inst *what)
res.val.i = (x); \ res.val.i = (x); \
break; break;
case P('!','='): SAME(!i); case FI_NEQ: SAME(!i);
case P('=','='): SAME(i); case FI_EQ: SAME(i);
case '<': COMPARE(i==-1); case FI_LT: COMPARE(i==-1);
case P('<','='): COMPARE(i!=1); case FI_LTE: COMPARE(i!=1);
case '!': case FI_NOT:
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "Not applied to non-boolean" ); runtime( "Not applied to non-boolean" );
@ -794,7 +822,7 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i; res.val.i = !res.val.i;
break; break;
case '~': case FI_MATCH:
TWOARGS; TWOARGS;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
@ -803,7 +831,7 @@ interpret(struct f_inst *what)
res.val.i = !!res.val.i; res.val.i = !!res.val.i;
break; break;
case P('!','~'): case FI_NOT_MATCH:
TWOARGS; TWOARGS;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = val_in_range(v1, v2); res.val.i = val_in_range(v1, v2);
@ -812,12 +840,12 @@ interpret(struct f_inst *what)
res.val.i = !res.val.i; res.val.i = !res.val.i;
break; break;
case P('d','e'): case FI_DEFINED:
ONEARG; ONEARG;
res.type = T_BOOL; res.type = T_BOOL;
res.val.i = (v1.type != T_VOID); res.val.i = (v1.type != T_VOID) && !undef_value(v1);
break; break;
case 'T': case FI_TYPE:
ONEARG; ONEARG;
switch (v1.type) switch (v1.type)
{ {
@ -829,7 +857,7 @@ interpret(struct f_inst *what)
runtime( "Can't determine type of this item" ); runtime( "Can't determine type of this item" );
} }
break; break;
case P('I','i'): case FI_IS_V4:
ONEARG; ONEARG;
if (v1.type != T_IP) if (v1.type != T_IP)
runtime( "IP version check needs an IP address" ); runtime( "IP version check needs an IP address" );
@ -838,7 +866,7 @@ interpret(struct f_inst *what)
break; break;
/* Set to indirect value, a1 = variable, a2 = value */ /* Set to indirect value, a1 = variable, a2 = value */
case 's': case FI_SET:
ARG(v2, a2.p); ARG(v2, a2.p);
sym = what->a1.p; sym = what->a1.p;
vp = sym->def; vp = sym->def;
@ -857,7 +885,7 @@ interpret(struct f_inst *what)
break; break;
/* some constants have value in a2, some in *a1.p, strange. */ /* some constants have value in a2, some in *a1.p, strange. */
case 'c': /* integer (or simple type) constant, string, set, or prefix_set */ case FI_CONSTANT: /* integer (or simple type) constant, string, set, or prefix_set */
res.type = what->aux; res.type = what->aux;
if (res.type == T_PREFIX_SET) if (res.type == T_PREFIX_SET)
@ -869,15 +897,15 @@ interpret(struct f_inst *what)
else else
res.val.i = what->a2.i; res.val.i = what->a2.i;
break; break;
case 'V': case FI_VARIABLE:
case 'C': case FI_CONSTANT_INDIRECT:
res = * ((struct f_val *) what->a1.p); res = * ((struct f_val *) what->a1.p);
break; break;
case 'p': case FI_PRINT:
ONEARG; ONEARG;
val_format(v1, &f_buf); val_format(v1, &f_buf);
break; break;
case '?': /* ? has really strange error value, so we can implement if ... else nicely :-) */ case FI_CONDITION: /* ? has really strange error value, so we can implement if ... else nicely :-) */
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
runtime( "If requires boolean expression" ); runtime( "If requires boolean expression" );
@ -887,12 +915,13 @@ interpret(struct f_inst *what)
} else res.val.i = 1; } else res.val.i = 1;
res.type = T_BOOL; res.type = T_BOOL;
break; break;
case '0': case FI_NOP:
debug( "No operation\n" ); debug( "No operation\n" );
break; break;
case P('p',','): case FI_PRINT_AND_DIE:
ONEARG; ONEARG;
if (what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) if ((what->a2.i == F_NOP || (what->a2.i != F_NONL && what->a1.p)) &&
!(f_flags & FF_SILENT))
log_commit(*L_INFO, &f_buf); log_commit(*L_INFO, &f_buf);
switch (what->a2.i) { switch (what->a2.i) {
@ -912,7 +941,7 @@ interpret(struct f_inst *what)
bug( "unknown return type: Can't happen"); bug( "unknown return type: Can't happen");
} }
break; break;
case 'a': /* rta access */ case FI_RTA_GET: /* rta access */
{ {
ACCESS_RTE; ACCESS_RTE;
struct rta *rta = (*f_rte)->attrs; struct rta *rta = (*f_rte)->attrs;
@ -935,7 +964,7 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('a','S'): case FI_RTA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
if (what->aux != v1.type) if (what->aux != v1.type)
@ -987,11 +1016,12 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('e','a'): /* Access to extended attributes */ case FI_EA_GET: /* Access to extended attributes */
ACCESS_RTE; ACCESS_RTE;
{ {
eattr *e = NULL; eattr *e = NULL;
u16 code = what->a2.i; u16 code = what->a2.i;
int f_type = what->aux >> 8;
if (!(f_flags & FF_FORCE_TMPATTR)) if (!(f_flags & FF_FORCE_TMPATTR))
e = ea_find((*f_rte)->attrs->eattrs, code); e = ea_find((*f_rte)->attrs->eattrs, code);
@ -1001,24 +1031,31 @@ interpret(struct f_inst *what)
e = ea_find((*f_rte)->attrs->eattrs, code); e = ea_find((*f_rte)->attrs->eattrs, code);
if (!e) { if (!e) {
/* A special case: undefined int_set looks like empty int_set */ /* A special case: undefined as_path looks like empty as_path */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_AS_PATH) {
res.type = T_PATH;
res.val.ad = &undef_adata;
break;
}
/* The same special case for int_set */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) { if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_INT_SET) {
res.type = T_CLIST; res.type = T_CLIST;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = &undef_adata;
break; break;
} }
/* The same special case for ec_set */ /* The same special case for ec_set */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) { if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_EC_SET) {
res.type = T_ECLIST; res.type = T_ECLIST;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = &undef_adata;
break; break;
} }
/* The same special case for lc_set */ /* The same special case for lc_set */
if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) { if ((what->aux & EAF_TYPE_MASK) == EAF_TYPE_LC_SET) {
res.type = T_LCLIST; res.type = T_LCLIST;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = &undef_adata;
break; break;
} }
@ -1029,7 +1066,7 @@ interpret(struct f_inst *what)
switch (what->aux & EAF_TYPE_MASK) { switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT: case EAF_TYPE_INT:
res.type = T_INT; res.type = f_type;
res.val.i = e->u.data; res.val.i = e->u.data;
break; break;
case EAF_TYPE_ROUTER_ID: case EAF_TYPE_ROUTER_ID:
@ -1073,23 +1110,24 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case P('e','S'): case FI_EA_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
{ {
struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr)); struct ea_list *l = lp_alloc(f_pool, sizeof(struct ea_list) + sizeof(eattr));
u16 code = what->a2.i; u16 code = what->a2.i;
int f_type = what->aux >> 8;
l->next = NULL; l->next = NULL;
l->flags = EALF_SORTED; l->flags = EALF_SORTED;
l->count = 1; l->count = 1;
l->attrs[0].id = code; l->attrs[0].id = code;
l->attrs[0].flags = 0; l->attrs[0].flags = 0;
l->attrs[0].type = what->aux | EAF_ORIGINATED | EAF_FRESH; l->attrs[0].type = (what->aux & 0xff) | EAF_ORIGINATED | EAF_FRESH;
switch (what->aux & EAF_TYPE_MASK) { switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT: case EAF_TYPE_INT:
if (v1.type != T_INT) if (v1.type != f_type)
runtime( "Setting int attribute to non-int value" ); runtime( "Setting int attribute to non-int value" );
l->attrs[0].u.data = v1.val.i; l->attrs[0].u.data = v1.val.i;
break; break;
@ -1176,12 +1214,12 @@ interpret(struct f_inst *what)
} }
} }
break; break;
case 'P': case FI_PREF_GET:
ACCESS_RTE; ACCESS_RTE;
res.type = T_INT; res.type = T_INT;
res.val.i = (*f_rte)->pref; res.val.i = (*f_rte)->pref;
break; break;
case P('P','S'): case FI_PREF_SET:
ACCESS_RTE; ACCESS_RTE;
ONEARG; ONEARG;
if (v1.type != T_INT) if (v1.type != T_INT)
@ -1191,7 +1229,7 @@ interpret(struct f_inst *what)
f_rte_cow(); f_rte_cow();
(*f_rte)->pref = v1.val.i; (*f_rte)->pref = v1.val.i;
break; break;
case 'L': /* Get length of */ case FI_LENGTH: /* Get length of */
ONEARG; ONEARG;
res.type = T_INT; res.type = T_INT;
switch(v1.type) { switch(v1.type) {
@ -1203,7 +1241,7 @@ interpret(struct f_inst *what)
default: runtime( "Prefix, path, clist or eclist expected" ); default: runtime( "Prefix, path, clist or eclist expected" );
} }
break; break;
case P('R','m'): /* Get ROA max prefix length */ case FI_ROA_MAXLEN: /* Get ROA max prefix length */
ONEARG; ONEARG;
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (v1.type != T_NET || !net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
@ -1213,7 +1251,7 @@ interpret(struct f_inst *what)
((net_addr_roa4 *) v1.val.net)->max_pxlen : ((net_addr_roa4 *) v1.val.net)->max_pxlen :
((net_addr_roa6 *) v1.val.net)->max_pxlen; ((net_addr_roa6 *) v1.val.net)->max_pxlen;
break; break;
case P('R','a'): /* Get ROA ASN */ case FI_ROA_ASN: /* Get ROA ASN */
ONEARG; ONEARG;
if (v1.type != T_NET || !net_is_roa(v1.val.net)) if (v1.type != T_NET || !net_is_roa(v1.val.net))
runtime( "ROA expected" ); runtime( "ROA expected" );
@ -1223,14 +1261,14 @@ interpret(struct f_inst *what)
((net_addr_roa4 *) v1.val.net)->asn : ((net_addr_roa4 *) v1.val.net)->asn :
((net_addr_roa6 *) v1.val.net)->asn; ((net_addr_roa6 *) v1.val.net)->asn;
break; break;
case P('c','p'): /* Convert prefix to ... */ case FI_IP: /* Convert prefix to ... */
ONEARG; ONEARG;
if (v1.type != T_NET) if (v1.type != T_NET)
runtime( "Prefix expected" ); runtime( "Prefix expected" );
res.type = T_IP; res.type = T_IP;
res.val.ip = net_prefix(v1.val.net); res.val.ip = net_prefix(v1.val.net);
break; break;
case P('R','D'): case FI_ROUTE_DISTINGUISHER:
ONEARG; ONEARG;
if (v1.type != T_NET) if (v1.type != T_NET)
runtime( "Prefix expected" ); runtime( "Prefix expected" );
@ -1239,7 +1277,7 @@ interpret(struct f_inst *what)
res.type = T_RD; res.type = T_RD;
res.val.ec = net_rd(v1.val.net); res.val.ec = net_rd(v1.val.net);
break; break;
case P('a','f'): /* Get first ASN from AS PATH */ case FI_AS_PATH_FIRST: /* Get first ASN from AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1249,7 +1287,7 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as; res.val.i = as;
break; break;
case P('a','l'): /* Get last ASN from AS PATH */ case FI_AS_PATH_LAST: /* Get last ASN from AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1259,7 +1297,7 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as; res.val.i = as;
break; break;
case P('a','L'): /* Get last ASN from non-aggregated part of AS PATH */ case FI_AS_PATH_LAST_NAG: /* Get last ASN from non-aggregated part of AS PATH */
ONEARG; ONEARG;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime( "AS path expected" ); runtime( "AS path expected" );
@ -1267,23 +1305,23 @@ interpret(struct f_inst *what)
res.type = T_INT; res.type = T_INT;
res.val.i = as_path_get_last_nonaggregated(v1.val.ad); res.val.i = as_path_get_last_nonaggregated(v1.val.ad);
break; break;
case 'r': case FI_RETURN:
ONEARG; ONEARG;
res = v1; res = v1;
res.type |= T_RETURN; res.type |= T_RETURN;
return res; return res;
case P('c','a'): /* CALL: this is special: if T_RETURN and returning some value, mask it out */ case FI_CALL: /* CALL: this is special: if T_RETURN and returning some value, mask it out */
ONEARG; ONEARG;
res = interpret(what->a2.p); res = interpret(what->a2.p);
if (res.type == T_RETURN) if (res.type == T_RETURN)
return res; return res;
res.type &= ~T_RETURN; res.type &= ~T_RETURN;
break; break;
case P('c','v'): /* Clear local variables */ case FI_CLEAR_LOCAL_VARS: /* Clear local variables */
for (sym = what->a1.p; sym != NULL; sym = sym->aux2) for (sym = what->a1.p; sym != NULL; sym = sym->aux2)
((struct f_val *) sym->def)->type = T_VOID; ((struct f_val *) sym->def)->type = T_VOID;
break; break;
case P('S','W'): case FI_SWITCH:
ONEARG; ONEARG;
{ {
struct f_tree *t = find_tree(what->a2.p, v1); struct f_tree *t = find_tree(what->a2.p, v1);
@ -1302,7 +1340,7 @@ interpret(struct f_inst *what)
return res; return res;
} }
break; break;
case P('i','M'): /* IP.MASK(val) */ case FI_IP_MASK: /* IP.MASK(val) */
TWOARGS; TWOARGS;
if (v2.type != T_INT) if (v2.type != T_INT)
runtime( "Integer expected"); runtime( "Integer expected");
@ -1315,11 +1353,11 @@ interpret(struct f_inst *what)
ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i))); ipa_from_ip6(ip6_and(ipa_to_ip6(v1.val.ip), ip6_mkmask(v2.val.i)));
break; break;
case 'E': /* Create empty attribute */ case FI_EMPTY: /* Create empty attribute */
res.type = what->aux; res.type = what->aux;
res.val.ad = adata_empty(f_pool, 0); res.val.ad = adata_empty(f_pool, 0);
break; break;
case P('A','p'): /* Path prepend */ case FI_PATH_PREPEND: /* Path prepend */
TWOARGS; TWOARGS;
if (v1.type != T_PATH) if (v1.type != T_PATH)
runtime("Can't prepend to non-path"); runtime("Can't prepend to non-path");
@ -1330,7 +1368,7 @@ interpret(struct f_inst *what)
res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i); res.val.ad = as_path_prepend(f_pool, v1.val.ad, v2.val.i);
break; break;
case P('C','a'): /* (Extended) Community list add or delete */ case FI_CLIST_ADD_DEL: /* (Extended) Community list add or delete */
TWOARGS; TWOARGS;
if (v1.type == T_PATH) if (v1.type == T_PATH)
{ {
@ -1496,8 +1534,7 @@ interpret(struct f_inst *what)
break; break;
case FI_ROA_CHECK: /* ROA Check */
case P('R','C'): /* ROA Check */
if (what->arg1) if (what->arg1)
{ {
TWOARGS; TWOARGS;
@ -1537,14 +1574,14 @@ interpret(struct f_inst *what)
break; break;
case P('f','m'): /* Format */ case FI_FORMAT: /* Format */
ONEARG; ONEARG;
res.type = T_STRING; res.type = T_STRING;
res.val.s = val_format_str(v1); res.val.s = val_format_str(v1);
break; break;
case P('a','s'): /* Birdtest Assert */ case FI_ASSERT: /* Birdtest Assert */
ONEARG; ONEARG;
if (v1.type != T_BOOL) if (v1.type != T_BOOL)
@ -1557,10 +1594,8 @@ interpret(struct f_inst *what)
break; break;
default: default:
bug( "Unknown instruction %d (%c)", what->code, what->code & 0xff); bug( "Unknown instruction %d (%c)", what->fi_code, what->fi_code & 0xff);
} }}
if (what->next)
return interpret(what->next);
return res; return res;
} }
@ -1587,40 +1622,40 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 1; return 1;
if (f1->aux != f2->aux) if (f1->aux != f2->aux)
return 0; return 0;
if (f1->code != f2->code) if (f1->fi_code != f2->fi_code)
return 0; return 0;
if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */ if (f1 == f2) /* It looks strange, but it is possible with call rewriting trickery */
return 1; return 1;
switch(f1->code) { switch(f1->fi_code) {
case ',': /* fall through */ case FI_ADD: /* fall through */
case '+': case FI_SUBTRACT:
case '-': case FI_MULTIPLY:
case '*': case FI_DIVIDE:
case '/': case FI_OR:
case '|': case FI_AND:
case '&': case FI_PAIR_CONSTRUCT:
case P('m','p'): case FI_EC_CONSTRUCT:
case P('m','c'): case FI_NEQ:
case P('!','='): case FI_EQ:
case P('=','='): case FI_LT:
case '<': case FI_LTE: TWOARGS; break;
case P('<','='): TWOARGS; break;
case '!': ONEARG; break; case FI_PATHMASK_CONSTRUCT: if (!pm_same(f1->a1.p, f2->a1.p)) return 0; break;
case P('!', '~'):
case '~': TWOARGS; break;
case P('d','e'): ONEARG; break;
case 'T': ONEARG; break;
case P('n','T'): break;
case P('m','l'): case FI_NOT: ONEARG; break;
case FI_NOT_MATCH:
case FI_MATCH: TWOARGS; break;
case FI_DEFINED: ONEARG; break;
case FI_TYPE: ONEARG; break;
case FI_LC_CONSTRUCT:
TWOARGS; TWOARGS;
if (!i_same(INST3(f1).p, INST3(f2).p)) if (!i_same(INST3(f1).p, INST3(f2).p))
return 0; return 0;
break; break;
case 's': case FI_SET:
ARG(v2, a2.p); ARG(v2, a2.p);
{ {
struct symbol *s1, *s2; struct symbol *s1, *s2;
@ -1633,7 +1668,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
} }
break; break;
case 'c': case FI_CONSTANT:
switch (f1->aux) { switch (f1->aux) {
case T_PREFIX_SET: case T_PREFIX_SET:
@ -1656,44 +1691,44 @@ i_same(struct f_inst *f1, struct f_inst *f2)
} }
break; break;
case 'C': case FI_CONSTANT_INDIRECT:
if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p)) if (!val_same(* (struct f_val *) f1->a1.p, * (struct f_val *) f2->a1.p))
return 0; return 0;
break; break;
case 'V': case FI_VARIABLE:
if (strcmp((char *) f1->a2.p, (char *) f2->a2.p)) if (strcmp((char *) f1->a2.p, (char *) f2->a2.p))
return 0; return 0;
break; break;
case 'p': case 'L': ONEARG; break; case FI_PRINT: case FI_LENGTH: ONEARG; break;
case '?': TWOARGS; break; case FI_CONDITION: TWOARGS; break;
case '0': case 'E': break; case FI_NOP: case FI_EMPTY: break;
case P('p',','): ONEARG; A2_SAME; break; case FI_PRINT_AND_DIE: ONEARG; A2_SAME; break;
case 'P': case FI_PREF_GET:
case 'a': A2_SAME; break; case FI_RTA_GET: A2_SAME; break;
case P('e','a'): A2_SAME; break; case FI_EA_GET: A2_SAME; break;
case P('P','S'): case FI_PREF_SET:
case P('a','S'): case FI_RTA_SET:
case P('e','S'): ONEARG; A2_SAME; break; case FI_EA_SET: ONEARG; A2_SAME; break;
case 'r': ONEARG; break; case FI_RETURN: ONEARG; break;
case P('c','p'): ONEARG; break; case FI_IP: ONEARG; break;
case P('R','D'): ONEARG; break; case FI_ROUTE_DISTINGUISHER: ONEARG; break;
case P('c','a'): /* Call rewriting trickery to avoid exponential behaviour */ case FI_CALL: /* Call rewriting trickery to avoid exponential behaviour */
ONEARG; ONEARG;
if (!i_same(f1->a2.p, f2->a2.p)) if (!i_same(f1->a2.p, f2->a2.p))
return 0; return 0;
f2->a2.p = f1->a2.p; f2->a2.p = f1->a2.p;
break; break;
case P('c','v'): break; /* internal instruction */ case FI_CLEAR_LOCAL_VARS: break; /* internal instruction */
case P('S','W'): ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break; case FI_SWITCH: ONEARG; if (!same_tree(f1->a2.p, f2->a2.p)) return 0; break;
case P('i','M'): TWOARGS; break; case FI_IP_MASK: TWOARGS; break;
case P('A','p'): TWOARGS; break; case FI_PATH_PREPEND: TWOARGS; break;
case P('C','a'): TWOARGS; break; case FI_CLIST_ADD_DEL: TWOARGS; break;
case P('a','f'): case FI_AS_PATH_FIRST:
case P('a','l'): case FI_AS_PATH_LAST:
case P('a','L'): ONEARG; break; case FI_AS_PATH_LAST_NAG: ONEARG; break;
case P('R','C'): case FI_ROA_CHECK:
TWOARGS; TWOARGS;
/* Does not really make sense - ROA check results may change anyway */ /* Does not really make sense - ROA check results may change anyway */
if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name, if (strcmp(((struct f_inst_roa_check *) f1)->rtc->name,
@ -1701,7 +1736,7 @@ i_same(struct f_inst *f1, struct f_inst *f2)
return 0; return 0;
break; break;
default: default:
bug( "Unknown instruction %d in same (%c)", f1->code, f1->code & 0xff); bug( "Unknown instruction %d in same (%c)", f1->fi_code, f1->fi_code & 0xff);
} }
return i_same(f1->next, f2->next); return i_same(f1->next, f2->next);
} }
@ -1774,7 +1809,8 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
if (res.type != T_RETURN) { if (res.type != T_RETURN) {
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); if (!(f_flags & FF_SILENT))
log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
return F_ERROR; return F_ERROR;
} }
DBG( "done (%u)\n", res.val.i ); DBG( "done (%u)\n", res.val.i );
@ -1830,14 +1866,6 @@ f_eval_int(struct f_inst *expr)
return res.val.i; return res.val.i;
} }
u32
f_eval_asn(struct f_inst *expr)
{
/* Called as a part of another interpret call, therefore no log_reset() */
struct f_val res = interpret(expr);
return (res.type == T_INT) ? res.val.i : 0;
}
/** /**
* filter_same - compare two filters * filter_same - compare two filters
* @new: first filter to be compared * @new: first filter to be compared

View File

@ -14,9 +14,74 @@
#include "nest/route.h" #include "nest/route.h"
#include "nest/attrs.h" #include "nest/attrs.h"
/* Filter instruction types */
#define FI__TWOCHAR(a,b) ((a<<8) | b)
#define FI__LIST \
F(FI_ADD, 0, '+') \
F(FI_SUBTRACT, 0, '-') \
F(FI_MULTIPLY, 0, '*') \
F(FI_DIVIDE, 0, '/') \
F(FI_AND, 0, '&') \
F(FI_OR, 0, '|') \
F(FI_PAIR_CONSTRUCT, 'm', 'p') \
F(FI_EC_CONSTRUCT, 'm', 'c') \
F(FI_LC_CONSTRUCT, 'm', 'l') \
F(FI_PATHMASK_CONSTRUCT, 'm', 'P') \
F(FI_NEQ, '!', '=') \
F(FI_EQ, '=', '=') \
F(FI_LT, 0, '<') \
F(FI_LTE, '<', '=') \
F(FI_NOT, 0, '!') \
F(FI_MATCH, 0, '~') \
F(FI_NOT_MATCH, '!', '~') \
F(FI_DEFINED, 'd', 'e') \
F(FI_TYPE, 0, 'T') \
F(FI_IS_V4, 'I', 'i') \
F(FI_SET, 0, 's') \
F(FI_CONSTANT, 0, 'c') \
F(FI_VARIABLE, 0, 'V') \
F(FI_CONSTANT_INDIRECT, 0, 'C') \
F(FI_PRINT, 0, 'p') \
F(FI_CONDITION, 0, '?') \
F(FI_NOP, 0, '0') \
F(FI_PRINT_AND_DIE, 'p', ',') \
F(FI_RTA_GET, 0, 'a') \
F(FI_RTA_SET, 'a', 'S') \
F(FI_EA_GET, 'e', 'a') \
F(FI_EA_SET, 'e', 'S') \
F(FI_PREF_GET, 0, 'P') \
F(FI_PREF_SET, 'P', 'S') \
F(FI_LENGTH, 0, 'L') \
F(FI_ROA_MAXLEN, 'R', 'M') \
F(FI_ROA_ASN, 'R', 'A') \
F(FI_IP, 'c', 'p') \
F(FI_ROUTE_DISTINGUISHER, 'R', 'D') \
F(FI_AS_PATH_FIRST, 'a', 'f') \
F(FI_AS_PATH_LAST, 'a', 'l') \
F(FI_AS_PATH_LAST_NAG, 'a', 'L') \
F(FI_RETURN, 0, 'r') \
F(FI_CALL, 'c', 'a') \
F(FI_CLEAR_LOCAL_VARS, 'c', 'V') \
F(FI_SWITCH, 'S', 'W') \
F(FI_IP_MASK, 'i', 'M') \
F(FI_EMPTY, 0, 'E') \
F(FI_PATH_PREPEND, 'A', 'p') \
F(FI_CLIST_ADD_DEL, 'C', 'a') \
F(FI_ROA_CHECK, 'R', 'C') \
F(FI_FORMAT, 0, 'F') \
F(FI_ASSERT, 'a', 's')
enum f_instruction_code {
#define F(c,a,b) \
c = FI__TWOCHAR(a,b),
FI__LIST
#undef F
} PACKED;
struct f_inst { /* Instruction */ struct f_inst { /* Instruction */
struct f_inst *next; /* Structure is 16 bytes, anyway */ struct f_inst *next; /* Structure is 16 bytes, anyway */
u16 code; /* Instruction code, see the interpret() function and P() macro */ enum f_instruction_code fi_code;
u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */ u16 aux; /* Extension to instruction code, T_*, EA_*, EAF_* */
union { union {
uint i; uint i;
@ -70,15 +135,32 @@ struct f_val {
} val; } val;
}; };
struct f_dynamic_attr {
int type;
int f_type;
int ea_code;
};
struct f_static_attr {
int f_type;
int sa_code;
int readonly;
};
struct filter { struct filter {
char *name; char *name;
struct f_inst *root; struct f_inst *root;
}; };
struct f_inst *f_new_inst(void); struct f_inst *f_new_inst(enum f_instruction_code fi_code);
struct f_inst *f_new_dynamic_attr(int type, int f_type, int code); /* Type as core knows it, type as filters know it, and code of dynamic attribute */ struct f_inst *f_new_inst_da(enum f_instruction_code fi_code, struct f_dynamic_attr da);
struct f_inst *f_new_inst_sa(enum f_instruction_code fi_code, struct f_static_attr sa);
static inline struct f_dynamic_attr f_new_dynamic_attr(int type, int f_type, int code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
static inline struct f_static_attr f_new_static_attr(int f_type, int code, int readonly)
{ return (struct f_static_attr) { .f_type = f_type, .sa_code = code, .readonly = readonly }; }
struct f_tree *f_new_tree(void); struct f_tree *f_new_tree(void);
struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_inst *dyn, struct f_inst *argument); struct f_inst *f_generate_complex(int operation, int operation_aux, struct f_dynamic_attr da, struct f_inst *argument);
struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn); struct f_inst *f_generate_roa_check(struct rtable_config *table, struct f_inst *prefix, struct f_inst *asn);
@ -100,7 +182,6 @@ int f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, s
struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool); struct f_val f_eval_rte(struct f_inst *expr, struct rte **rte, struct linpool *tmp_pool);
struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool); struct f_val f_eval(struct f_inst *expr, struct linpool *tmp_pool);
uint f_eval_int(struct f_inst *expr); uint f_eval_int(struct f_inst *expr);
u32 f_eval_asn(struct f_inst *expr);
char *filter_name(struct filter *filter); char *filter_name(struct filter *filter);
int filter_same(struct filter *new, struct filter *old); int filter_same(struct filter *new, struct filter *old);
@ -122,6 +203,7 @@ void val_format(struct f_val v, buffer *buf);
#define FILTER_ACCEPT NULL #define FILTER_ACCEPT NULL
#define FILTER_REJECT ((void *) 1) #define FILTER_REJECT ((void *) 1)
#define FILTER_UNDEF ((void *) 2) /* Used in BGP */
/* Type numbers must be in 0..0xff range */ /* Type numbers must be in 0..0xff range */
#define T_MASK 0xff #define T_MASK 0xff
@ -147,6 +229,7 @@ void val_format(struct f_val v, buffer *buf);
#define T_ENUM_RTD 0x34 #define T_ENUM_RTD 0x34
#define T_ENUM_ROA 0x35 #define T_ENUM_ROA 0x35
#define T_ENUM_NETTYPE 0x36 #define T_ENUM_NETTYPE 0x36
#define T_ENUM_RA_PREFERENCE 0x37
/* new enums go here */ /* new enums go here */
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */ #define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */
@ -206,6 +289,7 @@ struct f_trie
#define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val)); #define NEW_F_VAL struct f_val * val; val = cfg_alloc(sizeof(struct f_val));
#define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */ #define FF_FORCE_TMPATTR 1 /* Force all attributes to be temporary */
#define FF_SILENT 2 /* Silent filter execution */
/* Bird Tests */ /* Bird Tests */
struct f_bt_test_suite { struct f_bt_test_suite {

View File

@ -589,14 +589,11 @@ function mkpath(int a; int b)
function t_path() function t_path()
bgpmask pm1; bgpmask pm1;
bgpmask pm2;
bgppath p2; bgppath p2;
{ {
pm1 = / 4 3 2 1 /; pm1 = [= 4 3 2 1 =];
pm2 = [= 4 3 2 1 =];
bt_assert(pm1 = pm2); bt_assert(format(pm1) = "[= 4 3 2 1 =]");
bt_assert(format(pm2) = "[= 4 3 2 1 =]");
bt_assert(+empty+ = +empty+); bt_assert(+empty+ = +empty+);
bt_assert(10 !~ +empty+); bt_assert(10 !~ +empty+);
@ -609,17 +606,14 @@ bgppath p2;
bt_assert(format(p2) = "(path 4 3 2 1)"); bt_assert(format(p2) = "(path 4 3 2 1)");
bt_assert(p2.len = 4); bt_assert(p2.len = 4);
bt_assert(p2 ~ pm1); bt_assert(p2 ~ pm1);
bt_assert(p2 ~ pm2);
bt_assert(3 ~ p2); bt_assert(3 ~ p2);
bt_assert(p2 ~ [2, 10..20]); bt_assert(p2 ~ [2, 10..20]);
bt_assert(p2 ~ [4, 10..20]); bt_assert(p2 ~ [4, 10..20]);
p2 = prepend(p2, 5); p2 = prepend(p2, 5);
bt_assert(p2 !~ pm1); bt_assert(p2 !~ pm1);
bt_assert(p2 !~ pm2);
bt_assert(10 !~ p2); bt_assert(10 !~ p2);
bt_assert(p2 !~ [8, ten..(2*ten)]); bt_assert(p2 !~ [8, ten..(2*ten)]);
bt_assert(p2 ~ / ? 4 3 2 1 /);
bt_assert(p2 ~ [= * 4 3 * 1 =]); bt_assert(p2 ~ [= * 4 3 * 1 =]);
bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]); bt_assert(p2 ~ [= (3+2) (2*2) 3 2 1 =]);
bt_assert(p2 ~ mkpath(5, 4)); bt_assert(p2 ~ mkpath(5, 4));

View File

@ -55,29 +55,28 @@ protocol static {
rip_metric = rip_metric + 5; rip_metric = rip_metric + 5;
print rip_metric; print rip_metric;
# bgp_community = -empty-;
# TODO: uncomment this part after finishing BGP integration version print "hi";
# bgp_community = add(bgp_community, (1,2));
# bgp_community = -empty-; print "hello";
# print "hi"; bgp_community = add(bgp_community, (2,3));
# bgp_community = add(bgp_community, (1,2)); bgp_community.add((4,5));
# print "hello"; print "community = ", bgp_community;
# bgp_community = add(bgp_community, (2,3)); bgp_community.delete((2,3));
# bgp_community.add((4,5)); print "community = ", bgp_community;
# print "community = ", bgp_community; bgp_community.empty;
# bgp_community.delete((2,3)); print "community = ", bgp_community;
# print "community = ", bgp_community; print "done";
# bgp_community.empty;
# print "community = ", bgp_community; accept;
# print "done";
}; };
}; };
route 0.0.0.0/0 via 195.113.31.113; route 0.0.0.0/0 via 195.113.31.113;
route 62.168.0.0/25 reject; route 62.168.0.0/25 reject;
route 1.2.3.4/32 via 195.113.31.124; route 1.2.3.4/32 via 195.113.31.124;
route 10.0.0.0/8 reject; route 10.0.0.0/8 reject;
route 10.1.1.0:255.255.255.0 via 62.168.0.3; route 10.1.1.0/24 via 62.168.0.3;
route 10.1.2.0:255.255.255.0 via 62.168.0.3; route 10.1.2.0/24 via 62.168.0.3;
route 10.1.3.0:255.255.255.0 via 62.168.0.4; route 10.1.3.0/24 via 62.168.0.4;
route 10.2.0.0/24 via "arc0"; route 10.2.0.0/24 via "arc0";
} }

View File

@ -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) obj := $(src-o-files)
$(all-daemon) $(all-daemon)

View File

@ -9,7 +9,6 @@
#ifndef _BIRD_BIRDLIB_H_ #ifndef _BIRD_BIRDLIB_H_
#define _BIRD_BIRDLIB_H_ #define _BIRD_BIRDLIB_H_
#include "sysdep/unix/timer.h"
#include "lib/alloca.h" #include "lib/alloca.h"
/* Ugly structure offset handling macros */ /* Ugly structure offset handling macros */
@ -70,10 +69,11 @@ static inline int u64_cmp(u64 i1, u64 i2)
/* Microsecond time */ /* Microsecond time */
typedef s64 btime; typedef s64 btime;
//typedef s64 bird_clock_t;
#define S_ *1000000 #define S_ * (btime) 1000000
#define MS_ *1000 #define MS_ * (btime) 1000
#define US_ *1 #define US_ * (btime) 1
#define TO_S /1000000 #define TO_S /1000000
#define TO_MS /1000 #define TO_MS /1000
#define TO_US /1 #define TO_US /1
@ -82,39 +82,26 @@ typedef s64 btime;
#define S S_ #define S S_
#define MS MS_ #define MS MS_
#define US US_ #define US US_
#define NS /1000
#endif #endif
#define TIME_INFINITY ((s64) 0x7fffffffffffffff)
/* Rate limiting */ /* Rate limiting */
struct tbf { struct tbf {
bird_clock_t timestamp; /* Last update */ btime timestamp; /* Last update */
u16 count; /* Available tokens */ u64 count; /* Available micro-tokens */
u16 burst; /* Max number of tokens */ u16 burst; /* Max number of tokens */
u16 rate; /* Rate of replenishment */ u16 rate; /* Rate of replenishment (tokens / sec) */
u16 mark; /* Whether last op was limited */ u32 drop; /* Number of failed request since last successful */
}; };
/* Default TBF values for rate limiting log messages */ /* Default TBF values for rate limiting log messages */
#define TBF_DEFAULT_LOG_LIMITS { .rate = 1, .burst = 5 } #define TBF_DEFAULT_LOG_LIMITS { .rate = 1, .burst = 5 }
void tbf_update(struct tbf *f); int tbf_limit(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;
}
/* Logging and dying */ /* Logging and dying */
@ -165,9 +152,9 @@ void debug(const char *msg, ...); /* Printf to debug output */
#endif #endif
#ifdef DEBUGGING #ifdef DEBUGGING
#define ASSERT(x) do { if (!(x)) bug("Assertion `%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0) #define ASSERT(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
#else #else
#define ASSERT(x) do { } while(0) #define ASSERT(x) do { if (!(x)) log(L_BUG "Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
#endif #endif
/* Pseudorandom numbers */ /* Pseudorandom numbers */

View File

@ -13,10 +13,14 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "sysdep/config.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_TYPE(v) typeof(* (v).data)
#define BUFFER_SIZE(v) ((v).size * sizeof(* (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) \ #define BUFFER_INIT(v,pool,isize) \
({ \ ({ \
(v).used = 0; \ (v).used = 0; \

View File

@ -55,6 +55,7 @@ t_ev_run_list(void)
resource_init(); resource_init();
olock_init(); olock_init();
timer_init();
io_init(); io_init();
rt_init(); rt_init();
if_init(); if_init();

View File

@ -118,7 +118,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end);
/* A data structure for keep a state of flow builder */ /* A data structure for keep a state of flow builder */
struct flow_builder { struct flow_builder {
BUFFER(byte) data; BUFFER_(byte) data;
enum flow_type this_type; enum flow_type this_type;
enum flow_type last_type; enum flow_type last_type;
u16 last_op_offset; /* Position of last operator in data.data */ u16 last_op_offset; /* Position of last operator in data.data */

View File

@ -70,8 +70,8 @@ t_first_part(void)
net_addr_flow4 *f; net_addr_flow4 *f;
NET_ADDR_FLOW4_(f, ip4_build(10,0,0,1), 24, ((byte[]) { 0x00, 0x00, 0xab })); NET_ADDR_FLOW4_(f, ip4_build(10,0,0,1), 24, ((byte[]) { 0x00, 0x00, 0xab }));
const byte const *under240 = &f->data[1]; const byte *under240 = &f->data[1];
const byte const *above240 = &f->data[2]; const byte *above240 = &f->data[2];
/* Case 0x00 0x00 */ /* Case 0x00 0x00 */
bt_assert(flow4_first_part(f) == NULL); bt_assert(flow4_first_part(f) == NULL);

View File

@ -11,7 +11,7 @@
* *
* Linear memory pools are collections of memory blocks which * Linear memory pools are collections of memory blocks which
* support very fast allocation of new blocks, but are able to free only * 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, * Example: Each configuration is described by a complex system of structures,
* linked lists and function trees which are all allocated from a single linear * 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 { struct linpool {
resource r; resource r;
byte *ptr, *end; 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 */ struct lp_chunk *first_large; /* Large chunks */
uint chunk_size, threshold, total, total_large; uint chunk_size, threshold, total, total_large;
}; };
@ -69,7 +69,6 @@ linpool
*lp_new(pool *p, uint blk) *lp_new(pool *p, uint blk)
{ {
linpool *m = ralloc(p, &lp_class); linpool *m = ralloc(p, &lp_class);
m->plast = &m->first;
m->chunk_size = blk; m->chunk_size = blk;
m->threshold = 3*blk/4; m->threshold = 3*blk/4;
return m; return m;
@ -114,22 +113,25 @@ lp_alloc(linpool *m, uint size)
} }
else else
{ {
if (m->current) if (m->current && m->current->next)
{ {
/* Still have free chunks from previous incarnation (before lp_flush()) */ /* Still have free chunks from previous incarnation (before lp_flush()) */
c = m->current; c = m->current->next;
m->current = c->next;
} }
else else
{ {
/* Need to allocate a new chunk */ /* Need to allocate a new chunk */
c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size); c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
m->total += m->chunk_size; m->total += m->chunk_size;
*m->plast = c;
m->plast = &c->next;
c->next = NULL; c->next = NULL;
c->size = m->chunk_size; 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->ptr = c->data + size;
m->end = c->data + m->chunk_size; m->end = c->data + m->chunk_size;
} }
@ -190,9 +192,11 @@ lp_flush(linpool *m)
{ {
struct lp_chunk *c; struct lp_chunk *c;
/* Relink all normal chunks to free list and free all large chunks */ /* Move ptr to the first chunk and free all large chunks */
m->ptr = m->end = NULL; m->current = c = m->first;
m->current = m->first; m->ptr = c ? c->data : NULL;
m->end = c ? c->data + m->chunk_size : NULL;
while (c = m->first_large) while (c = m->first_large)
{ {
m->first_large = c->next; m->first_large = c->next;
@ -201,6 +205,50 @@ lp_flush(linpool *m)
m->total_large = 0; 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;
m->total_large -= c->size;
xfree(c);
}
}
static void static void
lp_free(resource *r) lp_free(resource *r)
{ {

105
lib/net.c
View File

@ -6,50 +6,54 @@
const char * const net_label[] = { const char * const net_label[] = {
[NET_IP4] = "ipv4", [NET_IP4] = "ipv4",
[NET_IP6] = "ipv6", [NET_IP6] = "ipv6",
[NET_VPN4] = "vpn4", [NET_VPN4] = "vpn4",
[NET_VPN6] = "vpn6", [NET_VPN6] = "vpn6",
[NET_ROA4] = "roa4", [NET_ROA4] = "roa4",
[NET_ROA6] = "roa6", [NET_ROA6] = "roa6",
[NET_FLOW4] = "flow4", [NET_FLOW4] = "flow4",
[NET_FLOW6] = "flow6", [NET_FLOW6] = "flow6",
[NET_IP6_SADR]= "ipv6-sadr",
[NET_MPLS] = "mpls", [NET_MPLS] = "mpls",
}; };
const u16 net_addr_length[] = { const u16 net_addr_length[] = {
[NET_IP4] = sizeof(net_addr_ip4), [NET_IP4] = sizeof(net_addr_ip4),
[NET_IP6] = sizeof(net_addr_ip6), [NET_IP6] = sizeof(net_addr_ip6),
[NET_VPN4] = sizeof(net_addr_vpn4), [NET_VPN4] = sizeof(net_addr_vpn4),
[NET_VPN6] = sizeof(net_addr_vpn6), [NET_VPN6] = sizeof(net_addr_vpn6),
[NET_ROA4] = sizeof(net_addr_roa4), [NET_ROA4] = sizeof(net_addr_roa4),
[NET_ROA6] = sizeof(net_addr_roa6), [NET_ROA6] = sizeof(net_addr_roa6),
[NET_FLOW4] = 0, [NET_FLOW4] = 0,
[NET_FLOW6] = 0, [NET_FLOW6] = 0,
[NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
[NET_MPLS] = sizeof(net_addr_mpls), [NET_MPLS] = sizeof(net_addr_mpls),
}; };
const u8 net_max_prefix_length[] = { const u8 net_max_prefix_length[] = {
[NET_IP4] = IP4_MAX_PREFIX_LENGTH, [NET_IP4] = IP4_MAX_PREFIX_LENGTH,
[NET_IP6] = IP6_MAX_PREFIX_LENGTH, [NET_IP6] = IP6_MAX_PREFIX_LENGTH,
[NET_VPN4] = IP4_MAX_PREFIX_LENGTH, [NET_VPN4] = IP4_MAX_PREFIX_LENGTH,
[NET_VPN6] = IP6_MAX_PREFIX_LENGTH, [NET_VPN6] = IP6_MAX_PREFIX_LENGTH,
[NET_ROA4] = IP4_MAX_PREFIX_LENGTH, [NET_ROA4] = IP4_MAX_PREFIX_LENGTH,
[NET_ROA6] = IP6_MAX_PREFIX_LENGTH, [NET_ROA6] = IP6_MAX_PREFIX_LENGTH,
[NET_FLOW4] = IP4_MAX_PREFIX_LENGTH, [NET_FLOW4] = IP4_MAX_PREFIX_LENGTH,
[NET_FLOW6] = IP6_MAX_PREFIX_LENGTH, [NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
[NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
[NET_MPLS] = 0, [NET_MPLS] = 0,
}; };
const u16 net_max_text_length[] = { const u16 net_max_text_length[] = {
[NET_IP4] = 18, /* "255.255.255.255/32" */ [NET_IP4] = 18, /* "255.255.255.255/32" */
[NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ [NET_IP6] = 43, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
[NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */ [NET_VPN4] = 40, /* "4294967296:4294967296 255.255.255.255/32" */
[NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */ [NET_VPN6] = 65, /* "4294967296:4294967296 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
[NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */ [NET_ROA4] = 34, /* "255.255.255.255/32-32 AS4294967295" */
[NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */ [NET_ROA6] = 60, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128-128 AS4294967295" */
[NET_FLOW4] = 0, /* "flow4 { ... }" */ [NET_FLOW4] = 0, /* "flow4 { ... }" */
[NET_FLOW6] = 0, /* "flow6 { ... }" */ [NET_FLOW6] = 0, /* "flow6 { ... }" */
[NET_IP6_SADR]= 92, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
[NET_MPLS] = 7, /* "1048575" */ [NET_MPLS] = 7, /* "1048575" */
}; };
@ -102,6 +106,8 @@ net_format(const net_addr *N, char *buf, int buflen)
return flow4_net_format(buf, buflen, &n->flow4, " "); return flow4_net_format(buf, buflen, &n->flow4, " ");
case NET_FLOW6: case NET_FLOW6:
return flow6_net_format(buf, buflen, &n->flow6, " "); return flow6_net_format(buf, buflen, &n->flow6, " ");
case NET_IP6_SADR:
return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen);
case NET_MPLS: case NET_MPLS:
return bsnprintf(buf, buflen, "%u", n->mpls.label); return bsnprintf(buf, buflen, "%u", n->mpls.label);
} }
@ -124,6 +130,7 @@ net_pxmask(const net_addr *a)
case NET_VPN6: case NET_VPN6:
case NET_ROA6: case NET_ROA6:
case NET_FLOW6: case NET_FLOW6:
case NET_IP6_SADR:
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a))); return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
case NET_MPLS: case NET_MPLS:
@ -156,6 +163,8 @@ net_compare(const net_addr *a, const net_addr *b)
return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b); return net_compare_flow4((const net_addr_flow4 *) a, (const net_addr_flow4 *) b);
case NET_FLOW6: case NET_FLOW6:
return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b); return net_compare_flow6((const net_addr_flow6 *) a, (const net_addr_flow6 *) b);
case NET_IP6_SADR:
return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b);
case NET_MPLS: case NET_MPLS:
return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b); return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
} }
@ -177,6 +186,7 @@ net_hash(const net_addr *n)
case NET_ROA6: return NET_HASH(n, roa6); case NET_ROA6: return NET_HASH(n, roa6);
case NET_FLOW4: return NET_HASH(n, flow4); case NET_FLOW4: return NET_HASH(n, flow4);
case NET_FLOW6: return NET_HASH(n, flow6); case NET_FLOW6: return NET_HASH(n, flow6);
case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
case NET_MPLS: return NET_HASH(n, mpls); case NET_MPLS: return NET_HASH(n, mpls);
default: bug("invalid type"); default: bug("invalid type");
} }
@ -198,6 +208,7 @@ net_validate(const net_addr *n)
case NET_ROA6: return NET_VALIDATE(n, roa6); case NET_ROA6: return NET_VALIDATE(n, roa6);
case NET_FLOW4: return NET_VALIDATE(n, flow4); case NET_FLOW4: return NET_VALIDATE(n, flow4);
case NET_FLOW6: return NET_VALIDATE(n, flow6); case NET_FLOW6: return NET_VALIDATE(n, flow6);
case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
case NET_MPLS: return NET_VALIDATE(n, mpls); case NET_MPLS: return NET_VALIDATE(n, mpls);
default: return 0; default: return 0;
} }
@ -222,6 +233,9 @@ net_normalize(net_addr *N)
case NET_FLOW6: case NET_FLOW6:
return net_normalize_ip6(&n->ip6); return net_normalize_ip6(&n->ip6);
case NET_IP6_SADR:
return net_normalize_ip6_sadr(&n->ip6_sadr);
case NET_MPLS: case NET_MPLS:
return; return;
} }
@ -246,6 +260,9 @@ net_classify(const net_addr *N)
case NET_FLOW6: case NET_FLOW6:
return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix); return ip6_zero(n->ip6.prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6.prefix);
case NET_IP6_SADR:
return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix);
case NET_MPLS: case NET_MPLS:
return IADDR_HOST | SCOPE_UNIVERSE; return IADDR_HOST | SCOPE_UNIVERSE;
} }
@ -274,6 +291,11 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)), return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
ip6_mkmask(net6_pxlen(n)))); ip6_mkmask(net6_pxlen(n))));
case NET_IP6_SADR:
if (ipa_is_ip4(a)) return 0;
return ip6_zero(ip6_and(ip6_xor(ipa_to_ip6(a), net6_prefix(n)),
ip6_mkmask(net6_pxlen(n))));
case NET_MPLS: case NET_MPLS:
default: default:
return 0; return 0;
@ -288,3 +310,22 @@ 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); 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_ip6_sadr, 40);
CHECK_NET(net_addr_mpls, 8);
}

107
lib/net.h
View File

@ -21,8 +21,9 @@
#define NET_ROA6 6 #define NET_ROA6 6
#define NET_FLOW4 7 #define NET_FLOW4 7
#define NET_FLOW6 8 #define NET_FLOW6 8
#define NET_MPLS 9 #define NET_IP6_SADR 9
#define NET_MAX 10 #define NET_MPLS 10
#define NET_MAX 11
#define NB_IP4 (1 << NET_IP4) #define NB_IP4 (1 << NET_IP4)
#define NB_IP6 (1 << NET_IP6) #define NB_IP6 (1 << NET_IP6)
@ -32,12 +33,13 @@
#define NB_ROA6 (1 << NET_ROA6) #define NB_ROA6 (1 << NET_ROA6)
#define NB_FLOW4 (1 << NET_FLOW4) #define NB_FLOW4 (1 << NET_FLOW4)
#define NB_FLOW6 (1 << NET_FLOW6) #define NB_FLOW6 (1 << NET_FLOW6)
#define NB_IP6_SADR (1 << NET_IP6_SADR)
#define NB_MPLS (1 << NET_MPLS) #define NB_MPLS (1 << NET_MPLS)
#define NB_IP (NB_IP4 | NB_IP6) #define NB_IP (NB_IP4 | NB_IP6)
#define NB_VPN (NB_VPN4 | NB_VPN6) #define NB_VPN (NB_VPN4 | NB_VPN6)
#define NB_FLOW (NB_FLOW4 | NB_FLOW6) #define NB_FLOW (NB_FLOW4 | NB_FLOW6)
#define NB_DEST (NB_IP | NB_VPN | NB_MPLS) #define NB_DEST (NB_IP | NB_IP6_SADR | NB_VPN | NB_MPLS)
#define NB_ANY 0xffffffff #define NB_ANY 0xffffffff
@ -45,7 +47,7 @@ typedef struct net_addr {
u8 type; u8 type;
u8 pxlen; u8 pxlen;
u16 length; u16 length;
u8 data[16]; u8 data[20];
u64 align[0]; u64 align[0];
} net_addr; } net_addr;
@ -76,6 +78,7 @@ typedef struct net_addr_vpn6 {
u8 pxlen; u8 pxlen;
u16 length; u16 length;
ip6_addr prefix; ip6_addr prefix;
u32 padding;
u64 rd; u64 rd;
} net_addr_vpn6; } net_addr_vpn6;
@ -120,6 +123,15 @@ typedef struct net_addr_mpls {
u32 label; u32 label;
} net_addr_mpls; } net_addr_mpls;
typedef struct net_addr_ip6_sadr {
u8 type;
u8 dst_pxlen;
u16 length;
ip6_addr dst_prefix;
s32 src_pxlen; /* s32 to avoid padding */
ip6_addr src_prefix;
} net_addr_ip6_sadr;
typedef union net_addr_union { typedef union net_addr_union {
net_addr n; net_addr n;
net_addr_ip4 ip4; net_addr_ip4 ip4;
@ -130,6 +142,7 @@ typedef union net_addr_union {
net_addr_roa6 roa6; net_addr_roa6 roa6;
net_addr_flow4 flow4; net_addr_flow4 flow4;
net_addr_flow6 flow6; net_addr_flow6 flow6;
net_addr_ip6_sadr ip6_sadr;
net_addr_mpls mpls; net_addr_mpls mpls;
} net_addr_union; } net_addr_union;
@ -152,7 +165,7 @@ extern const u16 net_max_text_length[];
((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd }) ((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd })
#define NET_ADDR_VPN6(prefix,pxlen,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) \ #define NET_ADDR_ROA4(prefix,pxlen,max_pxlen,asn) \
((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn }) ((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn })
@ -166,6 +179,9 @@ extern const u16 net_max_text_length[];
#define NET_ADDR_FLOW6(prefix,pxlen,dlen) \ #define NET_ADDR_FLOW6(prefix,pxlen,dlen) \
((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix }) ((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix })
#define NET_ADDR_IP6_SADR(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \
((net_addr_ip6_sadr) { NET_IP6_SADR, dst_pxlen, sizeof(net_addr_ip6_sadr), dst_prefix, src_pxlen, src_prefix })
#define NET_ADDR_MPLS(label) \ #define NET_ADDR_MPLS(label) \
((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label }) ((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
@ -188,6 +204,9 @@ static inline void net_fill_roa4(net_addr *a, ip4_addr prefix, uint pxlen, uint
static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn) static inline void net_fill_roa6(net_addr *a, ip6_addr prefix, uint pxlen, uint max_pxlen, u32 asn)
{ *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); } { *(net_addr_roa6 *)a = NET_ADDR_ROA6(prefix, pxlen, max_pxlen, asn); }
static inline void net_fill_ip6_sadr(net_addr *a, ip6_addr dst_prefix, uint dst_pxlen, ip6_addr src_prefix, uint src_pxlen)
{ *(net_addr_ip6_sadr *)a = NET_ADDR_IP6_SADR(dst_prefix, dst_pxlen, src_prefix, src_pxlen); }
static inline void net_fill_mpls(net_addr *a, u32 label) static inline void net_fill_mpls(net_addr *a, u32 label)
{ *(net_addr_mpls *)a = NET_ADDR_MPLS(label); } { *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
@ -221,6 +240,16 @@ static inline void net_fill_flow6(net_addr *a, ip6_addr prefix, uint pxlen, byte
memcpy(f->data, data, dlen); memcpy(f->data, data, dlen);
} }
/* Make NET_IP6_SADR from NET_IP6, assuming there is enough space */
static inline void net_make_ip6_sadr(net_addr *a)
{
net_addr_ip6_sadr *n = (void *) a;
n->type = NET_IP6_SADR;
n->length = sizeof(net_addr_ip6_sadr);
n->src_pxlen = 0;
n->src_prefix = IP6_NONE;
}
static inline int net_val_match(u8 type, u32 mask) static inline int net_val_match(u8 type, u32 mask)
{ return !!((1 << type) & mask); } { return !!((1 << type) & mask); }
@ -230,11 +259,14 @@ static inline int net_type_match(const net_addr *a, u32 mask)
static inline int net_is_ip(const net_addr *a) static inline int net_is_ip(const net_addr *a)
{ return (a->type == NET_IP4) || (a->type == NET_IP6); } { 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) static inline int net_is_roa(const net_addr *a)
{ return (a->type == NET_ROA4) || (a->type == NET_ROA6); } { return (a->type == NET_ROA4) || (a->type == NET_ROA6); }
static inline int net_is_vpn(const net_addr *a) static inline int net_is_flow(const net_addr *a)
{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); } { return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); }
static inline ip4_addr net4_prefix(const net_addr *a) static inline ip4_addr net4_prefix(const net_addr *a)
@ -257,6 +289,7 @@ static inline ip_addr net_prefix(const net_addr *a)
case NET_VPN6: case NET_VPN6:
case NET_ROA6: case NET_ROA6:
case NET_FLOW6: case NET_FLOW6:
case NET_IP6_SADR:
return ipa_from_ip6(net6_prefix(a)); return ipa_from_ip6(net6_prefix(a));
case NET_MPLS: case NET_MPLS:
@ -324,6 +357,9 @@ static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4
static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
{ return net_equal((const net_addr *) a, (const net_addr *) b); } { return net_equal((const net_addr *) a, (const net_addr *) b); }
static inline int net_equal_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return !memcmp(a, b, sizeof(net_addr_ip6_sadr)); }
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b) static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return !memcmp(a, b, sizeof(net_addr_mpls)); } { return !memcmp(a, b, sizeof(net_addr_mpls)); }
@ -334,6 +370,12 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r
static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } { return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
static inline int net_equal_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return ip6_equal(a->dst_prefix, b->dst_prefix) && (a->dst_pxlen == b->dst_pxlen); }
static inline int net_equal_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return ip6_equal(a->src_prefix, b->src_prefix) && (a->src_pxlen == b->src_pxlen); }
static inline int net_zero_ip4(const net_addr_ip4 *a) static inline int net_zero_ip4(const net_addr_ip4 *a)
{ return !a->pxlen && ip4_zero(a->prefix); } { return !a->pxlen && ip4_zero(a->prefix); }
@ -354,10 +396,10 @@ static inline int net_zero_roa6(const net_addr_roa6 *a)
{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; } { return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
static inline int net_zero_flow4(const net_addr_flow4 *a) 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) 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) static inline int net_zero_mpls(const net_addr_mpls *a)
{ return !a->label; } { return !a->label; }
@ -387,6 +429,13 @@ static inline int net_compare_flow4(const net_addr_flow4 *a, const net_addr_flow
static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) static inline int net_compare_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
{ return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow6)); } { return ip6_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen) ?: uint_cmp(a->length, b->length) ?: memcmp(a->data, b->data, a->length - sizeof(net_addr_flow6)); }
static inline int net_compare_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{
return
ip6_compare(a->dst_prefix, b->dst_prefix) ?: uint_cmp(a->dst_pxlen, b->dst_pxlen) ?:
ip6_compare(a->src_prefix, b->src_prefix) ?: uint_cmp(a->src_pxlen, b->src_pxlen);
}
static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b) static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return uint_cmp(a->label, b->label); } { return uint_cmp(a->label, b->label); }
@ -420,6 +469,9 @@ static inline void net_copy_flow4(net_addr_flow4 *dst, const net_addr_flow4 *src
static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src) static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src)
{ memcpy(dst, src, src->length); } { memcpy(dst, src, src->length); }
static inline void net_copy_ip6_sadr(net_addr_ip6_sadr *dst, const net_addr_ip6_sadr *src)
{ memcpy(dst, src, sizeof(net_addr_ip6_sadr)); }
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src) static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
{ memcpy(dst, src, sizeof(net_addr_mpls)); } { memcpy(dst, src, sizeof(net_addr_mpls)); }
@ -452,6 +504,9 @@ static inline u32 net_hash_flow4(const net_addr_flow4 *n)
static inline u32 net_hash_flow6(const net_addr_flow6 *n) static inline u32 net_hash_flow6(const net_addr_flow6 *n)
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); } { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
static inline u32 net_hash_ip6_sadr(const net_addr_ip6_sadr *n)
{ return net_hash_ip6((net_addr_ip6 *) n); }
static inline u32 net_hash_mpls(const net_addr_mpls *n) static inline u32 net_hash_mpls(const net_addr_mpls *n)
{ return n->label; } { return n->label; }
@ -504,6 +559,9 @@ static inline int net_validate_flow6(const net_addr_flow6 *n)
static inline int net_validate_mpls(const net_addr_mpls *n) static inline int net_validate_mpls(const net_addr_mpls *n)
{ return n->label < (1 << 20); } { return n->label < (1 << 20); }
static inline int net_validate_ip6_sadr(const net_addr_ip6_sadr *n)
{ return net_validate_px6(n->dst_prefix, n->dst_pxlen) && net_validate_px6(n->src_prefix, n->src_pxlen); }
int net_validate(const net_addr *N); int net_validate(const net_addr *N);
@ -519,6 +577,12 @@ static inline void net_normalize_vpn4(net_addr_vpn4 *n)
static inline void net_normalize_vpn6(net_addr_vpn6 *n) static inline void net_normalize_vpn6(net_addr_vpn6 *n)
{ net_normalize_ip6((net_addr_ip6 *) n); } { net_normalize_ip6((net_addr_ip6 *) n); }
static inline void net_normalize_ip6_sadr(net_addr_ip6_sadr *n)
{
n->dst_prefix = ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen));
n->src_prefix = ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen));
}
void net_normalize(net_addr *N); void net_normalize(net_addr *N);
@ -526,8 +590,33 @@ int net_classify(const net_addr *N);
int net_format(const net_addr *N, char *buf, int buflen); int net_format(const net_addr *N, char *buf, int buflen);
int rd_format(const u64 rd, char *buf, int buflen); int rd_format(const u64 rd, char *buf, int buflen);
static inline int ipa_in_px4(ip4_addr a, ip4_addr prefix, uint pxlen)
{ return ip4_zero(ip4_and(ip4_xor(a, prefix), ip4_mkmask(pxlen))); }
static inline int ipa_in_px6(ip6_addr a, ip6_addr prefix, uint pxlen)
{ return ip6_zero(ip6_and(ip6_xor(a, prefix), ip6_mkmask(pxlen))); }
static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
{ return ipa_in_px4(a, n->prefix, n->pxlen); }
static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
{ return ipa_in_px6(a, n->prefix, 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_px4(a->prefix, b->prefix, b->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_px6(a->prefix, b->prefix, b->pxlen); }
static inline int net_in_net_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return (a->dst_pxlen >= b->dst_pxlen) && ipa_in_px6(a->dst_prefix, b->dst_prefix, b->dst_pxlen); }
static inline int net_in_net_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return (a->src_pxlen >= b->src_pxlen) && ipa_in_px6(a->src_prefix, b->src_prefix, b->src_pxlen); }
int ipa_in_netX(const ip_addr A, const net_addr *N); int ipa_in_netX(const ip_addr A, const net_addr *N);
int net_in_netX(const net_addr *A, const net_addr *N); int net_in_netX(const net_addr *A, const net_addr *N);
void net_init(void);
#endif #endif

View File

@ -126,9 +126,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 * 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 * 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 IPv4 address), |%lR| for 64bit Router / Network ID (u64
* value printed as eight :-separated octets) and |%m| resp. |%M| for error * value printed as eight :-separated octets), |%t| for time values (btime) with
* messages (uses strerror() to translate @errno code to message text). On the * specified subsecond precision, and |%m| resp. |%M| for error messages (uses
* other hand, it doesn't support floating point numbers. * 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 * Result: number of characters of the output string or -1 if
* the buffer space was insufficient. * the buffer space was insufficient.
@ -140,6 +141,8 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
int i, base; int i, base;
u32 x; u32 x;
u64 X; u64 X;
btime t;
s64 t1, t2;
char *str, *start; char *str, *start;
const char *s; const char *s;
char ipbuf[NET_MAX_TEXT_LENGTH+1]; char ipbuf[NET_MAX_TEXT_LENGTH+1];
@ -284,7 +287,6 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
return -1; return -1;
continue; continue;
case 'n': case 'n':
if (qualifier == 'l') { if (qualifier == 'l') {
long * ip = va_arg(args, long *); long * ip = va_arg(args, long *);
@ -371,6 +373,51 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
snprintf(ipbuf, sizeof(ipbuf), fmtbuf, va_arg(args, double)); snprintf(ipbuf, sizeof(ipbuf), fmtbuf, va_arg(args, double));
s = ipbuf; s = ipbuf;
goto str; 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" */ /* integer number formats - set up the flags and "break" */
case 'o': case 'o':
base = 8; base = 8;
@ -412,6 +459,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
str = number(str, num, base, field_width, precision, flags, size); str = number(str, num, base, field_width, precision, flags, size);
if (!str) if (!str)
return -1; return -1;
done: ;
} }
if (!size) if (!size)
return -1; return -1;

View File

@ -56,6 +56,15 @@ t_simple(void)
BSPRINTF(2, "-1", buf, "%d", -1); BSPRINTF(2, "-1", buf, "%d", -1);
BSPRINTF(11, "-2147483648", buf, "%d", -2147483648); 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; return 1;
} }

View File

@ -59,11 +59,18 @@ void mb_free(void *);
typedef struct linpool linpool; typedef struct linpool linpool;
typedef struct lp_state {
void *current, *large;
byte *ptr;
} lp_state;
linpool *lp_new(pool *, unsigned blk); linpool *lp_new(pool *, unsigned blk);
void *lp_alloc(linpool *, unsigned size); /* Aligned */ void *lp_alloc(linpool *, unsigned size); /* Aligned */
void *lp_allocu(linpool *, unsigned size); /* Unaligned */ void *lp_allocu(linpool *, unsigned size); /* Unaligned */
void *lp_allocz(linpool *, unsigned size); /* With clear */ void *lp_allocz(linpool *, unsigned size); /* With clear */
void lp_flush(linpool *); /* Free everything, but leave linpool */ 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; extern const int lp_chunk_size;
#define LP_GAS 1024 #define LP_GAS 1024

View File

@ -50,6 +50,7 @@ typedef struct birdsock {
int ttl; /* Time To Live, -1 = default */ int ttl; /* Time To Live, -1 = default */
u32 flags; u32 flags;
struct iface *iface; /* Interface; specify this for broad/multicast sockets */ 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 */ byte *rbuf, *rpos; /* NULL=allocate automatically */
uint fast_rx; /* RX has higher priority in event loop */ uint fast_rx; /* RX has higher priority in event loop */

View File

@ -8,22 +8,30 @@
*/ */
#include "nest/bird.h" #include "nest/bird.h"
#include "lib/timer.h"
void int
tbf_update(struct tbf *f) tbf_limit(struct tbf *f)
{ {
bird_clock_t delta = now - f->timestamp; btime delta = current_time() - f->timestamp;
if (delta == 0) if (delta > 0)
return;
f->timestamp = now;
if ((0 < delta) && (delta < f->burst))
{ {
u32 next = f->count + delta * f->rate; u64 next = f->count + delta * f->rate;
f->count = MIN(next, f->burst); u64 burst = (u64) f->burst << 20;
f->count = MIN(next, burst);
f->timestamp += delta;
}
if (f->count < 1000000)
{
f->drop++;
return 1;
} }
else else
f->count = f->burst; {
f->count -= 1000000;
f->drop = 0;
return 0;
}
} }

378
lib/timer.c Normal file
View File

@ -0,0 +1,378 @@
/*
* 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 <time.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(&current_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
View 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

View File

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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@ -805,12 +805,11 @@ as_path_match(const struct adata *path, struct f_path_mask *mask)
val2 = val = mask->val; val2 = val = mask->val;
goto step; goto step;
case PM_ASN_EXPR: case PM_ASN_EXPR:
val2 = val = f_eval_asn((struct f_inst *) mask->val); ASSERT(0);
goto step;
case PM_ASN_RANGE: case PM_ASN_RANGE:
val = mask->val; val = mask->val;
val2 = mask->val2; val2 = mask->val2;
goto step; goto step;
case PM_QUESTION: case PM_QUESTION:
step: step:
nh = nl = -1; nh = nl = -1;

View File

@ -43,14 +43,14 @@ t_as_path_match(void)
bt_debug("Prepending ASN: %10u \n", val); bt_debug("Prepending ASN: %10u \n", val);
if (i == 0) if (i == 0)
first_prepended = val; first_prepended = val;
if (i == AS_PATH_LENGTH-1) if (i == AS_PATH_LENGTH-1)
last_prepended = val; last_prepended = val;
mask[i].kind = PM_ASN; mask[i].kind = PM_ASN;
mask[i].val = val; mask[i].val = val;
if (i) if (i)
mask[i].next = &mask[i-1]; mask[i].next = &mask[i-1];
} }
bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path"); bt_assert_msg(as_path_match(as_path, &mask[AS_PATH_LENGTH-1]), "Mask should match with AS path");

View File

@ -536,6 +536,13 @@ ec_set_sort(struct linpool *pool, struct adata *src)
return dst; return dst;
} }
void
ec_set_sort_x(struct adata *set)
{
/* Sort in place */
qsort(set->data, set->length / 8, 8, ec_set_cmp);
}
static int static int
lc_set_cmp(const void *X, const void *Y) lc_set_cmp(const void *X, const void *Y)

View File

@ -197,4 +197,6 @@ struct adata *int_set_sort(struct linpool *pool, struct adata *src);
struct adata *ec_set_sort(struct linpool *pool, struct adata *src); struct adata *ec_set_sort(struct linpool *pool, struct adata *src);
struct adata *lc_set_sort(struct linpool *pool, struct adata *src); struct adata *lc_set_sort(struct linpool *pool, struct adata *src);
void ec_set_sort_x(struct adata *set); /* Sort in place */
#endif #endif

View File

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

View File

@ -60,7 +60,7 @@
* the new one. When the consumer processes everything in the buffer * the new one. When the consumer processes everything in the buffer
* queue, it calls cli_written(), tha frees all buffers (except the * queue, it calls cli_written(), tha frees all buffers (except the
* first one) and schedules cli.event . * first one) and schedules cli.event .
* *
*/ */
#include "nest/bird.h" #include "nest/bird.h"

View File

@ -25,12 +25,12 @@ cmd_show_status(void)
byte tim[TM_DATETIME_BUFFER_SIZE]; byte tim[TM_DATETIME_BUFFER_SIZE];
cli_msg(-1000, "BIRD " BIRD_VERSION); 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, "Router ID is %R", config->router_id);
cli_msg(-1011, "Current server time is %s", tim); 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); 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); cli_msg(-1011, "Last reconfiguration on %s", tim);
graceful_restart_show_status(); graceful_restart_show_status();

View File

@ -65,18 +65,19 @@ proto_postconfig(void)
CF_DECLS CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT) 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(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512) CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE) 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(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(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
/* For r_args_channel */ /* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC) CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL) RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
@ -123,24 +124,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) CF_ADDTO(conf, gr_opts)
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ; gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
@ -151,15 +134,17 @@ gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
net_type: net_type:
IPV4 { $$ = NET_IP4; } IPV4 { $$ = NET_IP4; }
| IPV6 { $$ = NET_IP6; } | IPV6 { $$ = NET_IP6; }
| IPV6 SADR { $$ = NET_IP6_SADR; }
| VPN4 { $$ = NET_VPN4; } | VPN4 { $$ = NET_VPN4; }
| VPN6 { $$ = NET_VPN6; } | VPN6 { $$ = NET_VPN6; }
| ROA4 { $$ = NET_ROA4; } | ROA4 { $$ = NET_ROA4; }
| ROA6 { $$ = NET_ROA6; } | ROA6 { $$ = NET_ROA6; }
| FLOW4{ $$ = NET_FLOW4; } | FLOW4{ $$ = NET_FLOW4; }
| FLOW6{ $$ = NET_FLOW6; } | FLOW6{ $$ = NET_FLOW6; }
| MPLS { $$ = NET_MPLS; }
; ;
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6) CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR)
/* Creation of routing tables */ /* Creation of routing tables */
@ -167,7 +152,7 @@ CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
CF_ADDTO(conf, table) CF_ADDTO(conf, table)
table_sorted: table_sorted:
{ $$ = 0; } { $$ = 0; }
| SORTED { $$ = 1; } | SORTED { $$ = 1; }
; ;
@ -224,12 +209,13 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; } | MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| ROUTER ID idval { this_proto->router_id = $3; } | ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; } | DESCRIPTION text { this_proto->dsc = $2; }
| VRF text { this_proto->vrf = if_get_by_name($2); }
; ;
channel_start: net_type channel_start: net_type
{ {
$$ = this_channel = channel_config_new(NULL, $1, this_proto); $$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
}; };
channel_item: channel_item:
@ -295,6 +281,7 @@ limit_spec:
| OFF { $$ = (struct channel_limit){}; } | OFF { $$ = (struct channel_limit){}; }
; ;
CF_ADDTO(conf, debug_default) CF_ADDTO(conf, debug_default)
debug_default: debug_default:
@ -304,6 +291,31 @@ debug_default:
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */ /* 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 */ /* Interface patterns */
iface_patt_node_init: iface_patt_node_init:
@ -443,9 +455,9 @@ password_item:
password_item_begin: password_item_begin:
PASSWORD text { PASSWORD text {
if (!this_p_list) { if (!this_p_list) {
this_p_list = cfg_alloc(sizeof(list)); this_p_list = cfg_alloc(sizeof(list));
init_list(this_p_list); init_list(this_p_list);
password_id = 1; password_id = 1;
} }
this_p_item = cfg_alloc(sizeof (struct password_item)); this_p_item = cfg_alloc(sizeof (struct password_item));
this_p_item->password = $2; this_p_item->password = $2;
@ -462,12 +474,12 @@ password_item_begin:
password_item_params: password_item_params:
/* empty */ { } /* empty */ { }
| GENERATE FROM datetime ';' password_item_params { this_p_item->genfrom = $3; } | GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
| GENERATE TO datetime ';' password_item_params { this_p_item->gento = $3; } | GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
| ACCEPT FROM datetime ';' password_item_params { this_p_item->accfrom = $3; } | ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
| ACCEPT TO datetime ';' password_item_params { this_p_item->accto = $3; } | ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
| FROM datetime ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; } | FROM time ';' 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; } | 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."); } | 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; } | ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
; ;
@ -614,6 +626,7 @@ r_args_for:
} }
| net_vpn4_ | net_vpn4_
| net_vpn6_ | net_vpn6_
| net_ip6_sadr_
| VPN_RD IP4 { | VPN_RD IP4 {
$$ = cfg_alloc(sizeof(net_addr_vpn4)); $$ = cfg_alloc(sizeof(net_addr_vpn4));
net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1); net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1);
@ -622,6 +635,10 @@ r_args_for:
$$ = cfg_alloc(sizeof(net_addr_vpn6)); $$ = cfg_alloc(sizeof(net_addr_vpn6));
net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1); net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1);
} }
| IP6 FROM IP6 {
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
}
| SYM { | SYM {
if ($1->class == (SYM_CONSTANT | T_IP)) if ($1->class == (SYM_CONSTANT | T_IP))
{ {
@ -655,6 +672,7 @@ r_args_channel:
| IPV6 { $$ = "ipv6"; } | IPV6 { $$ = "ipv6"; }
| IPV6_MC { $$ = "ipv6-mc"; } | IPV6_MC { $$ = "ipv6-mc"; }
| IPV6_MPLS { $$ = "ipv6-mpls"; } | IPV6_MPLS { $$ = "ipv6-mpls"; }
| IPV6_SADR { $$ = "ipv6-sadr"; }
| VPN4 { $$ = "vpn4"; } | VPN4 { $$ = "vpn4"; }
| VPN4_MC { $$ = "vpn4-mc"; } | VPN4_MC { $$ = "vpn4-mc"; }
| VPN4_MPLS { $$ = "vpn4-mpls"; } | VPN4_MPLS { $$ = "vpn4-mpls"; }
@ -728,12 +746,12 @@ echo_size:
} }
; ;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]]) CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]])
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]]) CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]])
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]]) CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]])
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]]) CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ; { proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]]) CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])

View File

@ -32,11 +32,14 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/string.h" #include "lib/string.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "sysdep/unix/krt.h"
static pool *if_pool; static pool *if_pool;
list iface_list; list iface_list;
static void if_recalc_preferred(struct iface *i);
/** /**
* ifa_dump - dump interface address * ifa_dump - dump interface address
* @a: interface address descriptor * @a: interface address descriptor
@ -46,10 +49,11 @@ list iface_list;
void void
ifa_dump(struct ifa *a) 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, debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
(a->flags & IF_UP) ? "" : " DOWN", (a->flags & IA_PRIMARY) ? " PRIMARY" : "",
(a->flags & IA_PRIMARY) ? "" : " SEC", (a->flags & IA_SECONDARY) ? " SEC" : "",
(a->flags & IA_PEER) ? "PEER" : ""); (a->flags & IA_HOST) ? " HOST" : "",
(a->flags & IA_PEER) ? " PEER" : "");
} }
/** /**
@ -89,7 +93,8 @@ if_dump(struct iface *i)
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
{ {
ifa_dump(a); ifa_dump(a);
ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY)); ASSERT(!!(a->flags & IA_PRIMARY) ==
((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
} }
} }
@ -116,7 +121,7 @@ if_what_changed(struct iface *i, struct iface *j)
unsigned c; 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)) 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; return IF_CHANGE_TOO_MUCH;
c = 0; c = 0;
if ((i->flags ^ j->flags) & IF_UP) if ((i->flags ^ j->flags) & IF_UP)
@ -133,17 +138,21 @@ if_copy(struct iface *to, struct iface *from)
{ {
to->flags = from->flags | (to->flags & IF_TMP_DOWN); to->flags = from->flags | (to->flags & IF_TMP_DOWN);
to->mtu = from->mtu; to->mtu = from->mtu;
to->master_index = from->master_index;
to->master = from->master;
} }
static inline void static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a) 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) if (p->debug & D_IFACES)
log(L_TRACE "%s < %s address %N on interface %s %s", log(L_TRACE "%s < address %N on interface %s %s",
p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary", p->name, &a->prefix, a->iface->name,
&a->prefix, a->iface->name, (c & IF_CHANGE_UP) ? "added" : "removed"); (c & IF_CHANGE_UP) ? "added" : "removed");
p->ifa_notify(p, c, a); p->ifa_notify(p, c, a);
} }
} }
@ -174,7 +183,9 @@ ifa_notify_change(unsigned c, struct ifa *a)
static inline void static inline void
if_send_notify(struct proto *p, unsigned c, struct iface *i) 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) if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name, log(L_TRACE "%s < interface %s %s", p->name, i->name,
@ -182,6 +193,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
(c & IF_CHANGE_DOWN) ? "goes down" : (c & IF_CHANGE_DOWN) ? "goes down" :
(c & IF_CHANGE_MTU) ? "changes MTU" : (c & IF_CHANGE_MTU) ? "changes MTU" :
(c & IF_CHANGE_LINK) ? "changes link" : (c & IF_CHANGE_LINK) ? "changes link" :
(c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
(c & IF_CHANGE_CREATE) ? "created" : (c & IF_CHANGE_CREATE) ? "created" :
"sends unknown event"); "sends unknown event");
p->if_notify(p, c, i); p->if_notify(p, c, i);
@ -210,20 +222,14 @@ if_notify_change(unsigned c, struct iface *i)
if (c & IF_CHANGE_DOWN) if (c & IF_CHANGE_DOWN)
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
{ ifa_notify_change_(IF_CHANGE_DOWN, a);
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
ifa_notify_change_(IF_CHANGE_DOWN, a);
}
WALK_LIST(p, proto_list) WALK_LIST(p, proto_list)
if_send_notify(p, c, i); if_send_notify(p, c, i);
if (c & IF_CHANGE_UP) if (c & IF_CHANGE_UP)
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
{ ifa_notify_change_(IF_CHANGE_UP, a);
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
ifa_notify_change_(IF_CHANGE_UP, a);
}
if (c & IF_CHANGE_UP) if (c & IF_CHANGE_UP)
neigh_if_up(i); neigh_if_up(i);
@ -232,24 +238,25 @@ if_notify_change(unsigned c, struct iface *i)
neigh_if_link(i); neigh_if_link(i);
} }
static unsigned static uint
if_recalc_flags(struct iface *i, unsigned flags) if_recalc_flags(struct iface *i UNUSED, uint flags)
{ {
if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) || if ((flags & IF_ADMIN_UP) &&
!(flags & IF_ADMIN_UP) || !(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
!i->addr) !(i->master_index && !i->master))
flags &= ~IF_UP;
else
flags |= IF_UP; flags |= IF_UP;
else
flags &= ~IF_UP;
return flags; return flags;
} }
static void 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); i->flags = if_recalc_flags(i, flags);
if ((i->flags ^ of) & IF_UP) if ((i->flags ^ of) & IF_UP)
if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i); if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
} }
@ -297,7 +304,6 @@ if_update(struct iface *new)
WALK_LIST(i, iface_list) WALK_LIST(i, iface_list)
if (!strcmp(new->name, i->name)) if (!strcmp(new->name, i->name))
{ {
new->addr = i->addr;
new->flags = if_recalc_flags(new, new->flags); new->flags = if_recalc_flags(new, new->flags);
c = if_what_changed(i, new); c = if_what_changed(i, new);
if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */ if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */
@ -305,10 +311,13 @@ if_update(struct iface *new)
DBG("Interface %s changed too much -- forcing down/up transition\n", i->name); DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
if_change_flags(i, i->flags | IF_TMP_DOWN); if_change_flags(i, i->flags | IF_TMP_DOWN);
rem_node(&i->n); 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(&new->addrs, &i->addrs, sizeof(i->addrs));
memcpy(i, new, sizeof(*i)); 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; goto newif;
} }
@ -339,13 +348,16 @@ if_start_update(void)
{ {
i->flags &= ~IF_UPDATED; i->flags &= ~IF_UPDATED;
WALK_LIST(a, i->addrs) WALK_LIST(a, i->addrs)
a->flags &= ~IF_UPDATED; a->flags &= ~IA_UPDATED;
} }
} }
void void
if_end_partial_update(struct iface *i) if_end_partial_update(struct iface *i)
{ {
if (i->flags & IF_NEEDS_RECALC)
if_recalc_preferred(i);
if (i->flags & IF_TMP_DOWN) if (i->flags & IF_TMP_DOWN)
if_change_flags(i, i->flags & ~IF_TMP_DOWN); if_change_flags(i, i->flags & ~IF_TMP_DOWN);
} }
@ -363,7 +375,7 @@ if_end_update(void)
else else
{ {
WALK_LIST_DELSAFE(a, b, i->addrs) WALK_LIST_DELSAFE(a, b, i->addrs)
if (!(a->flags & IF_UPDATED)) if (!(a->flags & IA_UPDATED))
ifa_delete(a); ifa_delete(a);
if_end_partial_update(i); if_end_partial_update(i);
} }
@ -460,40 +472,99 @@ if_get_by_name(char *name)
return i; return i;
} }
struct ifa *kif_choose_primary(struct iface *i); static inline void
if_set_preferred(struct ifa **pos, struct ifa *new)
static int
ifa_recalc_primary(struct iface *i)
{ {
struct ifa *a = kif_choose_primary(i); if (*pos)
(*pos)->flags &= ~IA_PRIMARY;
if (new)
new->flags |= IA_PRIMARY;
if (a == i->addr) *pos = new;
return 0; }
if (i->addr) static void
i->addr->flags &= ~IA_PRIMARY; 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; /* Secondary address is never selected */
rem_node(&a->n); if (a->flags & IA_SECONDARY)
add_head(&i->addrs, &a->n); 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; if (a4 != i->addr4)
return 1; {
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 void
ifa_recalc_all_primary_addresses(void) if_recalc_all_preferred_addresses(void)
{ {
struct iface *i; struct iface *i;
WALK_LIST(i, iface_list) WALK_LIST(i, iface_list)
{ {
if (ifa_recalc_primary(i)) if_recalc_preferred(i);
if_change_flags(i, i->flags | IF_TMP_DOWN);
} if (i->flags & IF_TMP_DOWN)
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
}
} }
static inline int static inline int
@ -525,7 +596,7 @@ ifa_update(struct ifa *a)
b->scope == a->scope && b->scope == a->scope &&
!((b->flags ^ a->flags) & IA_PEER)) !((b->flags ^ a->flags) & IA_PEER))
{ {
b->flags |= IF_UPDATED; b->flags |= IA_UPDATED;
return b; return b;
} }
ifa_delete(b); ifa_delete(b);
@ -533,15 +604,15 @@ ifa_update(struct ifa *a)
} }
if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd)) 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)); b = mb_alloc(if_pool, sizeof(struct ifa));
memcpy(b, a, sizeof(struct ifa)); memcpy(b, a, sizeof(struct ifa));
add_tail(&i->addrs, &b->n); add_tail(&i->addrs, &b->n);
b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS); b->flags |= IA_UPDATED;
if (ifa_recalc_primary(i))
if_change_flags(i, i->flags | IF_TMP_DOWN); i->flags |= IF_NEEDS_RECALC;
if (b->flags & IF_UP) if (i->flags & IF_UP)
ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b); ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
return b; return b;
} }
@ -564,16 +635,24 @@ ifa_delete(struct ifa *a)
if (ifa_same(b, a)) if (ifa_same(b, a))
{ {
rem_node(&b->n); 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 (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); mb_free(b);
return; return;
} }
@ -740,16 +819,17 @@ iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct ifac
static void static void
if_show_addr(struct ifa *a) 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)) if (ipa_nonzero(a->opposite))
bsprintf(opp, ", opposite %I", a->opposite); bsprintf(opp, "opposite %I, ", a->opposite);
else else
opp[0] = 0; opp[0] = 0;
cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
a->ip, a->prefix.pxlen, cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
(a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected", a->ip, a->prefix.pxlen, flg, opp, ip_scope_text(a->scope));
opp, ip_scope_text(a->scope));
} }
void void
@ -764,7 +844,13 @@ if_show(void)
if (i->flags & IF_SHUTDOWN) if (i->flags & IF_SHUTDOWN)
continue; 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)) if (!(i->flags & IF_MULTIACCESS))
type = "PtP"; type = "PtP";
else else
@ -778,10 +864,13 @@ if_show(void)
(i->flags & IF_LOOPBACK) ? " Loopback" : "", (i->flags & IF_LOOPBACK) ? " Loopback" : "",
(i->flags & IF_IGNORE) ? " Ignored" : "", (i->flags & IF_IGNORE) ? " Ignored" : "",
i->mtu); i->mtu);
if (i->addr)
if_show_addr(i->addr);
WALK_LIST(a, i->addrs) 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); if_show_addr(a);
} }
cli_msg(0, ""); cli_msg(0, "");
@ -791,16 +880,25 @@ void
if_show_summary(void) if_show_summary(void)
{ {
struct iface *i; 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) WALK_LIST(i, iface_list)
{ {
if (i->addr) byte a4[IPA_MAX_TEXT_LENGTH + 17];
bsprintf(addr, "%I/%d", i->addr->ip, i->addr->prefix.pxlen); byte a6[IPA_MAX_TEXT_LENGTH + 17];
if (i->addr4)
bsprintf(a4, "%I/%d", i->addr4->ip, i->addr4->prefix.pxlen);
else else
addr[0] = 0; a4[0] = 0;
cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
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, ""); cli_msg(0, "");
} }

View File

@ -34,12 +34,17 @@ struct iface {
unsigned flags; unsigned flags;
unsigned mtu; unsigned mtu;
unsigned index; /* OS-dependent interface index */ 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 */ 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 */ 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_MULTIACCESS 2
#define IF_BROADCAST 4 #define IF_BROADCAST 4
#define IF_MULTICAST 8 #define IF_MULTICAST 8
@ -70,7 +75,10 @@ struct iface {
#define IF_JUST_CREATED 0x10000000 /* Send creation event as soon as possible */ #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_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 */ /* Interface change events */
@ -79,8 +87,14 @@ struct iface {
#define IF_CHANGE_MTU 4 #define IF_CHANGE_MTU 4
#define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */ #define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */
#define IF_CHANGE_LINK 0x10 #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_TOO_MUCH 0x40000000 /* Used internally */
#define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
void if_init(void); void if_init(void);
void if_dump(struct iface *); void if_dump(struct iface *);
void if_dump_all(void); 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_index(unsigned);
struct iface *if_find_by_name(char *); struct iface *if_find_by_name(char *);
struct iface *if_get_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 */ /* The Neighbor Cache */

View File

@ -45,6 +45,7 @@ olock_same(struct object_lock *x, struct object_lock *y)
return return
x->type == y->type && x->type == y->type &&
x->iface == y->iface && x->iface == y->iface &&
x->vrf == y->vrf &&
x->port == y->port && x->port == y->port &&
x->inst == y->inst && x->inst == y->inst &&
ipa_equal(x->addr, y->addr); ipa_equal(x->addr, y->addr);

View File

@ -30,6 +30,7 @@ struct object_lock {
uint port; /* ... port number */ uint port; /* ... port number */
uint inst; /* ... instance ID */ uint inst; /* ... instance ID */
struct iface *iface; /* ... interface */ struct iface *iface; /* ... interface */
struct iface *vrf; /* ... or VRF (if iface is unknown) */
void (*hook)(struct object_lock *); /* Called when the lock succeeds */ void (*hook)(struct object_lock *); /* Called when the lock succeeds */
void *data; /* User data */ void *data; /* User data */
/* ... internal to lock manager, don't touch ... */ /* ... internal to lock manager, don't touch ... */

View File

@ -28,4 +28,3 @@
void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len); void mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len);
#endif #endif

View File

@ -30,7 +30,8 @@
* when the protocol has explicitly requested it via the %NEF_STICKY * when the protocol has explicitly requested it via the %NEF_STICKY
* flag because it wishes to be notified when the node will again become * 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 * 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 * When a neighbor event occurs (a neighbor gets disconnected or a sticky
* inactive neighbor becomes connected), the protocol hook neigh_notify() * inactive neighbor becomes connected), the protocol hook neigh_notify()
@ -153,7 +154,8 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
} }
else else
WALK_LIST(i, iface_list) 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; ifa = i;
break; break;

View File

@ -10,6 +10,7 @@
#include "nest/bird.h" #include "nest/bird.h"
#include "nest/password.h" #include "nest/password.h"
#include "lib/string.h" #include "lib/string.h"
#include "lib/timer.h"
#include "lib/mac.h" #include "lib/mac.h"
struct password_item *last_password_item = NULL; 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 *pi;
struct password_item *pf = NULL; struct password_item *pf = NULL;
btime now_ = current_real_time();
if (l) if (l)
{ {
WALK_LIST(pi, *l) WALK_LIST(pi, *l)
{ {
if ((pi->genfrom < now_real) && (pi->gento > now_real)) if ((pi->genfrom < now_) && (pi->gento > now_))
{ {
if (first_fit) if (first_fit)
return pi; return pi;
@ -41,12 +43,13 @@ struct password_item *
password_find_by_id(list *l, uint id) password_find_by_id(list *l, uint id)
{ {
struct password_item *pi; struct password_item *pi;
btime now_ = current_real_time();
if (!l) if (!l)
return NULL; return NULL;
WALK_LIST(pi, *l) 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 pi;
return NULL; return NULL;
@ -56,12 +59,13 @@ struct password_item *
password_find_by_value(list *l, char *pass, uint size) password_find_by_value(list *l, char *pass, uint size)
{ {
struct password_item *pi; struct password_item *pi;
btime now_ = current_real_time();
if (!l) if (!l)
return NULL; return NULL;
WALK_LIST(pi, *l) 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 pi;
return NULL; return NULL;

View File

@ -10,15 +10,13 @@
#ifndef PASSWORD_H #ifndef PASSWORD_H
#define PASSWORD_H #define PASSWORD_H
#include "sysdep/unix/timer.h"
struct password_item { struct password_item {
node n; node n;
char *password; /* Key data, null terminated */ char *password; /* Key data, null terminated */
uint length; /* Key length, without null */ uint length; /* Key length, without null */
uint id; /* Key ID */ uint id; /* Key ID */
uint alg; /* MAC algorithm */ uint alg; /* MAC algorithm */
bird_clock_t accfrom, accto, genfrom, gento; btime accfrom, accto, genfrom, gento;
}; };
extern struct password_item *last_password_item; extern struct password_item *last_password_item;

View File

@ -281,7 +281,7 @@ int import_control(struct proto *p, rte **e, ea_list **attrs, struct linpool *po
/** /**
* rte_recalculate - prepare routes for comparison * rte_recalculate - prepare routes for comparison
* @table: a routing table * @table: a routing table
* @net: a network entry * @net: a network entry
* @new: new route for the network * @new: new route for the network
* @old: old route for the network * @old: old route for the network

View File

@ -13,6 +13,7 @@
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/event.h" #include "lib/event.h"
#include "lib/timer.h"
#include "lib/string.h" #include "lib/string.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "nest/route.h" #include "nest/route.h"
@ -43,7 +44,7 @@ static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" };
extern struct protocol proto_unix_iface; 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 void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p); static char *proto_state_name(struct proto *p);
static void channel_verify_limits(struct channel *c); 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->channel_state = CS_DOWN;
c->export_state = ES_DOWN; c->export_state = ES_DOWN;
c->last_state_change = now; c->last_state_change = current_time();
c->reloadable = 1; c->reloadable = 1;
CALL(c->channel->init, c, cf); CALL(c->channel->init, c, cf);
@ -341,7 +342,7 @@ channel_set_state(struct channel *c, uint state)
return; return;
c->channel_state = state; c->channel_state = state;
c->last_state_change = now; c->last_state_change = current_time();
switch (state) switch (state)
{ {
@ -436,7 +437,7 @@ static void
channel_request_reload(struct channel *c) channel_request_reload(struct channel *c)
{ {
ASSERT(c->channel_state == CS_UP); ASSERT(c->channel_state == CS_UP);
// ASSERT(channel_reloadable(c)); ASSERT(channel_reloadable(c));
c->proto->reload_routes(c); c->proto->reload_routes(c);
@ -454,11 +455,10 @@ const struct channel_class channel_basic = {
}; };
void * void *
channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto) channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{ {
struct channel_config *cf = NULL; struct channel_config *cf = NULL;
struct rtable_config *tab = NULL; struct rtable_config *tab = NULL;
const char *name = NULL;
if (net_type) if (net_type)
{ {
@ -469,7 +469,6 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
cf_error("Different channel type"); cf_error("Different channel type");
tab = new_config->def_tables[net_type]; tab = new_config->def_tables[net_type];
name = net_label[net_type];
} }
if (!cc) if (!cc)
@ -478,6 +477,7 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
cf = cfg_allocz(cc->config_size); cf = cfg_allocz(cc->config_size);
cf->name = name; cf->name = name;
cf->channel = cc; cf->channel = cc;
cf->parent = proto;
cf->table = tab; cf->table = tab;
cf->out_filter = FILTER_REJECT; cf->out_filter = FILTER_REJECT;
@ -490,6 +490,26 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
return cf; return cf;
} }
void *
channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{
struct channel_config *cf;
/* We are using name as token, so no strcmp() */
WALK_LIST(cf, proto->channels)
if (cf->name == name)
{
/* Allow to redefine channel only if inherited from template */
if (cf->parent == proto)
cf_error("Multiple %s channels", name);
cf->parent = proto;
return cf;
}
return channel_config_new(cc, name, net_type, proto);
}
struct channel_config * struct channel_config *
channel_copy_config(struct channel_config *src, struct proto_config *proto) channel_copy_config(struct channel_config *src, struct proto_config *proto)
{ {
@ -512,8 +532,9 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode))) if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)))
return 0; return 0;
int import_changed = !filter_same(c->in_filter, cf->in_filter); /* Note that filter_same() requires arguments in (new, old) order */
int export_changed = !filter_same(c->out_filter, cf->out_filter); int import_changed = !filter_same(cf->in_filter, c->in_filter);
int export_changed = !filter_same(cf->out_filter, c->out_filter);
if (c->preference != cf->preference) if (c->preference != cf->preference)
import_changed = 1; import_changed = 1;
@ -672,7 +693,8 @@ proto_init(struct proto_config *c, node *n)
struct proto *p = pr->init(c); struct proto *p = pr->init(c);
p->proto_state = PS_DOWN; 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); insert_node(&p->n, n);
p->event = ev_new(proto_pool); p->event = ev_new(proto_pool);
@ -819,7 +841,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* If there is a too big change in core attributes, ... */ /* If there is a too big change in core attributes, ... */
if ((nc->protocol != oc->protocol) || if ((nc->protocol != oc->protocol) ||
(nc->net_type != oc->net_type) || (nc->net_type != oc->net_type) ||
(nc->disabled != p->disabled)) (nc->disabled != p->disabled) ||
(nc->vrf != oc->vrf))
return 0; return 0;
p->name = nc->name; p->name = nc->name;
@ -977,6 +1000,7 @@ proto_rethink_goal(struct proto *p)
proto_remove_channels(p); proto_remove_channels(p);
rem_node(&p->n); rem_node(&p->n);
rfree(p->event); rfree(p->event);
mb_free(p->message);
mb_free(p); mb_free(p);
if (!nc) if (!nc)
return; return;
@ -1046,7 +1070,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 * graceful_restart_recovery - request initial graceful restart recovery
@ -1083,9 +1107,8 @@ graceful_restart_init(void)
} }
graceful_restart_state = GRS_ACTIVE; graceful_restart_state = GRS_ACTIVE;
gr_wait_timer = tm_new(proto_pool); gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0);
gr_wait_timer->hook = graceful_restart_done; tm_start(gr_wait_timer, config->gr_wait S);
tm_start(gr_wait_timer, config->gr_wait);
} }
/** /**
@ -1099,7 +1122,7 @@ graceful_restart_init(void)
* restart wait timer fires (but there are still some locks). * restart wait timer fires (but there are still some locks).
*/ */
static void static void
graceful_restart_done(struct timer *t UNUSED) graceful_restart_done(timer *t UNUSED)
{ {
log(L_INFO "Graceful restart done"); log(L_INFO "Graceful restart done");
graceful_restart_state = GRS_DONE; graceful_restart_state = GRS_DONE;
@ -1136,7 +1159,7 @@ graceful_restart_show_status(void)
cli_msg(-24, "Graceful restart recovery in progress"); cli_msg(-24, "Graceful restart recovery in progress");
cli_msg(-24, " Waiting for %d channels to recover", graceful_restart_locks); 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 +1321,7 @@ protos_build(void)
int proto_restart; int proto_restart;
static void static void
proto_shutdown_loop(struct timer *t UNUSED) proto_shutdown_loop(timer *t UNUSED)
{ {
struct proto *p, *p_next; struct proto *p, *p_next;
@ -1329,7 +1352,40 @@ proto_schedule_down(struct proto *p, byte restart, byte code)
p->down_sched = restart ? PDS_RESTART : PDS_DISABLE; p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
p->down_code = code; 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 +1556,7 @@ proto_notify_state(struct proto *p, uint state)
return; return;
p->proto_state = state; p->proto_state = state;
p->last_state_change = now; p->last_state_change = current_time();
switch (state) switch (state)
{ {
@ -1620,19 +1676,20 @@ channel_show_info(struct channel *c)
} }
void 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]; byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
/* First protocol - show header */ /* First protocol - show header */
if (!cnt) 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; buf[0] = 0;
if (p->proto->get_status) if (p->proto->get_status)
p->proto->get_status(p, buf); p->proto->get_status(p, buf);
tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change); tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s", cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
p->name, p->name,
p->proto->name, p->proto->name,
p->main_channel ? p->main_channel->table->name : "---", p->main_channel ? p->main_channel->table->name : "---",
@ -1644,8 +1701,12 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
{ {
if (p->cf->dsc) if (p->cf->dsc)
cli_msg(-1006, " Description: %s", 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) if (p->cf->router_id)
cli_msg(-1006, " Router ID: %R", 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) if (p->proto->show_proto_info)
p->proto->show_proto_info(p); p->proto->show_proto_info(p);
@ -1661,7 +1722,7 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
} }
void 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) if (p->disabled)
{ {
@ -1672,12 +1733,13 @@ proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Disabling protocol %s", p->name); log(L_INFO "Disabling protocol %s", p->name);
p->disabled = 1; p->disabled = 1;
p->down_code = PDC_CMD_DISABLE; p->down_code = PDC_CMD_DISABLE;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p); proto_rethink_goal(p);
cli_msg(-9, "%s: disabled", p->name); cli_msg(-9, "%s: disabled", p->name);
} }
void 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) if (!p->disabled)
{ {
@ -1687,12 +1749,13 @@ proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Enabling protocol %s", p->name); log(L_INFO "Enabling protocol %s", p->name);
p->disabled = 0; p->disabled = 0;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p); proto_rethink_goal(p);
cli_msg(-11, "%s: enabled", p->name); cli_msg(-11, "%s: enabled", p->name);
} }
void 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) if (p->disabled)
{ {
@ -1703,6 +1766,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Restarting protocol %s", p->name); log(L_INFO "Restarting protocol %s", p->name);
p->disabled = 1; p->disabled = 1;
p->down_code = PDC_CMD_RESTART; p->down_code = PDC_CMD_RESTART;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p); proto_rethink_goal(p);
p->disabled = 0; p->disabled = 0;
proto_rethink_goal(p); proto_rethink_goal(p);
@ -1710,7 +1774,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
} }
void 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; struct channel *c;
@ -1749,19 +1813,19 @@ proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
} }
void 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; p->debug = mask;
} }
void 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; p->mrtdump = mask;
} }
static void 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) if (s->class != SYM_PROTO)
{ {
@ -1774,7 +1838,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int)
} }
static void 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; struct proto *p;
int cnt = 0; int cnt = 0;
@ -1790,8 +1854,8 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint a
} }
void void
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int), proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int),
int restricted, uint arg) int restricted, uintptr_t arg)
{ {
if (restricted && cli_access_restricted()) if (restricted && cli_access_restricted())
return; return;

View File

@ -12,7 +12,6 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/event.h" #include "lib/event.h"
#include "sysdep/unix/timer.h"
#include "nest/route.h" #include "nest/route.h"
#include "conf/conf.h" #include "conf/conf.h"
@ -101,6 +100,7 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */ u32 router_id; /* Protocol specific router ID */
list channels; /* List of channel configs (struct channel_config) */ 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 */ /* 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) */ list channels; /* List of channels to rtables (struct channel) */
struct channel *main_channel; /* Primary channel */ struct channel *main_channel; /* Primary channel */
struct rte_src *main_source; /* Primary route source */ 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) */ char *name; /* Name of this instance (== cf->name) */
u32 debug; /* Debugging flags */ u32 debug; /* Debugging flags */
@ -159,8 +160,9 @@ struct proto {
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */ byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
byte down_code; /* Reason for shutdown (PDC_* codes) */ byte down_code; /* Reason for shutdown (PDC_* codes) */
u32 hash_key; /* Random key used for hashing of neighbors */ 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 *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: * General protocol hooks:
@ -237,6 +239,7 @@ struct proto_spec {
void *proto_new(struct proto_config *); void *proto_new(struct proto_config *);
void *proto_config_new(struct protocol *, int class); void *proto_config_new(struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src); 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_recovery(void);
void graceful_restart_init(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_limit(struct channel_limit *l, const char *dsc);
void channel_show_info(struct channel *c); void channel_show_info(struct channel *c);
void proto_cmd_show(struct proto *, uint, int); void proto_cmd_show(struct proto *, uintptr_t, int);
void proto_cmd_disable(struct proto *, uint, int); void proto_cmd_disable(struct proto *, uintptr_t, int);
void proto_cmd_enable(struct proto *, uint, int); void proto_cmd_enable(struct proto *, uintptr_t, int);
void proto_cmd_restart(struct proto *, uint, int); void proto_cmd_restart(struct proto *, uintptr_t, int);
void proto_cmd_reload(struct proto *, uint, int); void proto_cmd_reload(struct proto *, uintptr_t, int);
void proto_cmd_debug(struct proto *, uint, int); void proto_cmd_debug(struct proto *, uintptr_t, int);
void proto_cmd_mrtdump(struct proto *, uint, 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 *); struct proto *proto_get_named(struct symbol *, struct protocol *);
#define CMD_RELOAD 0 #define CMD_RELOAD 0
@ -334,7 +337,7 @@ void proto_notify_state(struct proto *p, unsigned state);
* *
* HUNGRY ----> FEEDING * HUNGRY ----> FEEDING
* ^ | * ^ |
* | V * | V
* FLUSHING <---- HAPPY * FLUSHING <---- HAPPY
* *
* States: HUNGRY Protocol either administratively down (i.e., * States: HUNGRY Protocol either administratively down (i.e.,
@ -458,6 +461,7 @@ struct channel_config {
const char *name; const char *name;
const struct channel_class *channel; const struct channel_class *channel;
struct proto_config *parent; /* Where channel is defined (proto or template) */
struct rtable_config *table; /* Table we're attached to */ struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */ struct filter *in_filter, *out_filter; /* Attached filters */
struct channel_limit rx_limit; /* Limit for receiving routes from protocol struct channel_limit rx_limit; /* Limit for receiving routes from protocol
@ -508,7 +512,7 @@ struct channel {
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */ u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */ 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 */
}; };
@ -582,7 +586,8 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); } static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
void channel_request_feeding(struct channel *c); void channel_request_feeding(struct channel *c);
void *channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto); void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf); int channel_reconfigure(struct channel *c, struct channel_config *cf);

View File

@ -11,7 +11,6 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "sysdep/unix/timer.h"
#include "lib/net.h" #include "lib/net.h"
struct ea_list; struct ea_list;
@ -75,7 +74,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e)
void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init); void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init);
void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */ void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */
void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */ void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */
void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */ void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */
void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */ void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */
void fib_delete(struct fib *, void *); /* Remove fib entry */ void fib_delete(struct fib *, void *); /* Remove fib entry */
void fib_free(struct fib *); /* Destroy the fib */ void fib_free(struct fib *); /* Destroy the fib */
@ -105,7 +104,7 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin
type *z; \ type *z; \
for(;;) { \ for(;;) { \
if (!fn_) \ if (!fn_) \
{ \ { \
if (++hpos_ >= count_) \ if (++hpos_ >= count_) \
break; \ break; \
fn_ = (fib)->hash_table[hpos_]; \ fn_ = (fib)->hash_table[hpos_]; \
@ -159,8 +158,8 @@ typedef struct rtable {
* obstacle from this routing table. * obstacle from this routing table.
*/ */
struct event *rt_event; /* Routing table event */ struct event *rt_event; /* Routing table event */
btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since 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 prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */ byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */ byte nhu_state; /* Next Hop Update state */
@ -213,7 +212,7 @@ typedef struct rte {
byte flags; /* Flags (REF_...) */ byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */ byte pflags; /* Protocol-specific flags */
word pref; /* Route preference */ word pref; /* Route preference */
bird_clock_t lastmod; /* Last modified */ btime lastmod; /* Last modified */
union { /* Protocol-dependent data (metrics etc.) */ union { /* Protocol-dependent data (metrics etc.) */
#ifdef CONFIG_RIP #ifdef CONFIG_RIP
struct { struct {
@ -236,6 +235,7 @@ typedef struct rte {
#endif #endif
#ifdef CONFIG_BABEL #ifdef CONFIG_BABEL
struct { struct {
u16 seqno; /* Babel seqno */
u16 metric; /* Babel metric */ u16 metric; /* Babel metric */
u64 router_id; /* Babel router id */ u64 router_id; /* Babel router id */
} babel; } babel;
@ -282,7 +282,7 @@ void rt_preconfig(struct config *);
void rt_commit(struct config *new, struct config *old); void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *); void rt_lock_table(rtable *);
void rt_unlock_table(rtable *); void rt_unlock_table(rtable *);
void rt_setup(pool *, rtable *, char *, struct rtable_config *); void rt_setup(pool *, rtable *, struct rtable_config *);
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); } static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find_valid(rtable *tab, const net_addr *addr) static inline net *net_find_valid(rtable *tab, const net_addr *addr)
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; } { net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
@ -309,6 +309,8 @@ int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c); void rt_feed_channel_abort(struct channel *c);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type); 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 { struct rt_show_data_rtable {
node n; node n;
@ -470,7 +472,8 @@ typedef struct eattr {
#define EAP_OSPF 3 /* OSPF */ #define EAP_OSPF 3 /* OSPF */
#define EAP_KRT 4 /* Kernel route attributes */ #define EAP_KRT 4 /* Kernel route attributes */
#define EAP_BABEL 5 /* Babel 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_CODE(proto,id) (((proto) << 8) | (id))
#define EA_PROTO(ea) ((ea) >> 8) #define EA_PROTO(ea) ((ea) >> 8)
@ -552,6 +555,46 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
ea_list *ea_append(ea_list *to, ea_list *what); ea_list *ea_append(ea_list *to, ea_list *what);
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max); void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
static inline eattr *
ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, uintptr_t val)
{
ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
eattr *e = &a->attrs[0];
a->flags = EALF_SORTED;
a->count = 1;
a->next = *to;
*to = a;
e->id = id;
e->type = type;
e->flags = flags;
if (type & EAF_EMBEDDED)
e->u.data = (u32) val;
else
e->u.ptr = (struct adata *) val;
return e;
}
static inline void
ea_set_attr_u32(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, u32 val)
{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); }
static inline void
ea_set_attr_ptr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, struct adata *val)
{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); }
static inline void
ea_set_attr_data(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, void *data, uint len)
{
struct adata *a = lp_alloc_adata(pool, len);
memcpy(a->data, data, len);
ea_set_attr(to, pool, id, flags, type, (uintptr_t) a);
}
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK) #define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
static inline size_t nexthop_size(const struct nexthop *nh) static inline size_t nexthop_size(const struct nexthop *nh)
@ -620,7 +663,7 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX];
* Default protocol preferences * Default protocol preferences
*/ */
#define DEF_PREF_DIRECT 240 /* Directly connected */ #define DEF_PREF_DIRECT 240 /* Directly connected */
#define DEF_PREF_STATIC 200 /* Static route */ #define DEF_PREF_STATIC 200 /* Static route */
#define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */ #define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */
#define DEF_PREF_BABEL 130 /* Babel */ #define DEF_PREF_BABEL 130 /* Babel */

View File

@ -1204,7 +1204,7 @@ rta_dump(rta *a)
static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE", static char *rts[] = { "RTS_DUMMY", "RTS_STATIC", "RTS_INHERIT", "RTS_DEVICE",
"RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP", "RTS_STAT_DEV", "RTS_REDIR", "RTS_RIP",
"RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1", "RTS_OSPF", "RTS_OSPF_IA", "RTS_OSPF_EXT1",
"RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" }; "RTS_OSPF_EXT2", "RTS_BGP", "RTS_PIPE", "RTS_BABEL" };
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" }; static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
debug("p=%s uc=%d %s %s%s h=%04x", debug("p=%s uc=%d %s %s%s h=%04x",

View File

@ -31,9 +31,10 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
struct rt_dev_proto *p = (void *) P; struct rt_dev_proto *p = (void *) P;
struct rt_dev_config *cf = (void *) P->cf; struct rt_dev_config *cf = (void *) P->cf;
struct channel *c; struct channel *c;
net_addr *net = &ad->prefix;
if (!EMPTY_LIST(cf->iface_list) && 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 "*" */ /* Empty list is automatically treated as "*" */
return; return;
@ -53,13 +54,20 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
if (!c) if (!c)
return; return;
/* For IPv6 SADR, replace regular prefix with SADR prefix */
if (c->net_type == NET_IP6_SADR)
{
net = alloca(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr(net, net6_prefix(&ad->prefix), net6_pxlen(&ad->prefix), IP6_NONE, 0);
}
if (flags & IF_CHANGE_DOWN) if (flags & IF_CHANGE_DOWN)
{ {
DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip); DBG("dev_if_notify: %s:%I going down\n", ad->iface->name, ad->ip);
/* Use iface ID as local source ID */ /* Use iface ID as local source ID */
struct rte_src *src = rt_get_source(P, ad->iface->index); struct rte_src *src = rt_get_source(P, ad->iface->index);
rte_update2(c, &ad->prefix, NULL, src); rte_update2(c, net, NULL, src);
} }
else if (flags & IF_CHANGE_UP) else if (flags & IF_CHANGE_UP)
{ {
@ -85,7 +93,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
a = rta_lookup(&a0); a = rta_lookup(&a0);
e = rte_get_temp(a); e = rte_get_temp(a);
e->pflags = 0; e->pflags = 0;
rte_update2(c, &ad->prefix, e, src); rte_update2(c, net, e, src);
} }
} }
@ -107,16 +115,32 @@ dev_if_notify(struct proto *p, uint c, struct iface *iface)
} }
} }
static void
dev_postconfig(struct proto_config *CF)
{
struct rt_dev_config *cf = (void *) CF;
struct channel_config *ip4, *ip6, *ip6_sadr;
ip4 = proto_cf_find_channel(CF, NET_IP4);
ip6 = proto_cf_find_channel(CF, NET_IP6);
ip6_sadr = proto_cf_find_channel(CF, NET_IP6_SADR);
if (ip6 && ip6_sadr)
cf_error("Both ipv6 and ipv6-sadr channels");
cf->ip4_channel = ip4;
cf->ip6_channel = ip6 ?: ip6_sadr;
}
static struct proto * static struct proto *
dev_init(struct proto_config *CF) dev_init(struct proto_config *CF)
{ {
struct proto *P = proto_new(CF); struct proto *P = proto_new(CF);
struct rt_dev_proto *p = (void *) P; struct rt_dev_proto *p = (void *) P;
// struct rt_dev_config *cf = (void *) CF; struct rt_dev_config *cf = (void *) CF;
proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)); proto_configure_channel(P, &p->ip4_channel, cf->ip4_channel);
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)); proto_configure_channel(P, &p->ip6_channel, cf->ip6_channel);
P->if_notify = dev_if_notify; P->if_notify = dev_if_notify;
P->ifa_notify = dev_ifa_notify; P->ifa_notify = dev_ifa_notify;
@ -136,8 +160,8 @@ dev_reconfigure(struct proto *P, struct proto_config *CF)
return 0; return 0;
return return
proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) && proto_configure_channel(P, &p->ip4_channel, n->ip4_channel) &&
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)); proto_configure_channel(P, &p->ip6_channel, n->ip6_channel);
return 1; return 1;
} }
@ -159,13 +183,14 @@ dev_copy_config(struct proto_config *dest, struct proto_config *src)
} }
struct protocol proto_device = { struct protocol proto_device = {
.name = "Direct", .name = "Direct",
.template = "direct%d", .template = "direct%d",
.preference = DEF_PREF_DIRECT, .preference = DEF_PREF_DIRECT,
.channel_mask = NB_IP, .channel_mask = NB_IP | NB_IP6_SADR,
.proto_size = sizeof(struct rt_dev_proto), .proto_size = sizeof(struct rt_dev_proto),
.config_size = sizeof(struct rt_dev_config), .config_size = sizeof(struct rt_dev_config),
.init = dev_init, .postconfig = dev_postconfig,
.reconfigure = dev_reconfigure, .init = dev_init,
.copy_config = dev_copy_config .reconfigure = dev_reconfigure,
.copy_config = dev_copy_config
}; };

View File

@ -13,6 +13,9 @@ struct rt_dev_config {
struct proto_config c; struct proto_config c;
list iface_list; /* list of struct iface_patt */ list iface_list; /* list of struct iface_patt */
int check_link; int check_link;
struct channel_config *ip4_channel;
struct channel_config *ip6_channel;
}; };
struct rt_dev_proto { struct rt_dev_proto {

View File

@ -32,6 +32,24 @@
* Basic FIB operations are performed by functions defined by this module, * Basic FIB operations are performed by functions defined by this module,
* enumerating of FIB contents is accomplished by using the FIB_WALK() macro * enumerating of FIB contents is accomplished by using the FIB_WALK() macro
* or FIB_ITERATE_START() if you want to do it asynchronously. * 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 #undef LOCAL_DEBUG
@ -74,8 +92,7 @@ fib_ht_free(struct fib_node **h)
} }
static u32 static inline u32 fib_hash(struct fib *f, const net_addr *a);
fib_hash(struct fib *f, const net_addr *a);
/** /**
* fib_init - initialize a new FIB * fib_init - initialize a new FIB
@ -180,23 +197,11 @@ fib_rehash(struct fib *f, int step)
}) })
static u32 static inline u32
fib_hash(struct fib *f, const net_addr *a) fib_hash(struct fib *f, const net_addr *a)
{ {
ASSERT(f->addr_type == a->type); /* Same as FIB_HASH() */
return net_hash(a) >> f->hash_shift;
switch (f->addr_type)
{
case NET_IP4: return FIB_HASH(f, a, ip4);
case NET_IP6: return FIB_HASH(f, a, ip6);
case NET_VPN4: return FIB_HASH(f, a, vpn4);
case NET_VPN6: return FIB_HASH(f, a, vpn6);
case NET_ROA4: return FIB_HASH(f, a, roa4);
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);
default: bug("invalid type");
}
} }
void * void *
@ -231,6 +236,8 @@ fib_find(struct fib *f, const net_addr *a)
case NET_ROA6: return FIB_FIND(f, a, roa6); case NET_ROA6: return FIB_FIND(f, a, roa6);
case NET_FLOW4: return FIB_FIND(f, a, flow4); case NET_FLOW4: return FIB_FIND(f, a, flow4);
case NET_FLOW6: return FIB_FIND(f, a, flow6); case NET_FLOW6: return FIB_FIND(f, a, flow6);
case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
case NET_MPLS: return FIB_FIND(f, a, mpls);
default: bug("invalid type"); default: bug("invalid type");
} }
} }
@ -250,6 +257,8 @@ 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_ROA6: FIB_INSERT(f, a, e, roa6); return;
case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return; case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return; case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); return;
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
default: bug("invalid type"); default: bug("invalid type");
} }
} }
@ -547,22 +556,17 @@ found:
void void
fib_check(struct fib *f) fib_check(struct fib *f)
{ {
#if 0 uint i, ec, nulls;
uint i, ec, lo, nulls;
ec = 0; ec = 0;
for(i=0; i<f->hash_size; i++) for(i=0; i<f->hash_size; i++)
{ {
struct fib_node *n; struct fib_node *n;
lo = 0;
for(n=f->hash_table[i]; n; n=n->next) for(n=f->hash_table[i]; n; n=n->next)
{ {
struct fib_iterator *j, *j0; struct fib_iterator *j, *j0;
uint h0 = ipa_hash(n->prefix); uint h0 = fib_hash(f, n->addr);
if (h0 < lo) if (h0 != i)
bug("fib_check: discord in hash chains");
lo = h0;
if ((h0 >> f->hash_shift) != i)
bug("fib_check: mishashed %x->%x (order %d)", h0, i, f->hash_order); bug("fib_check: mishashed %x->%x (order %d)", h0, i, f->hash_order);
j0 = (struct fib_iterator *) n; j0 = (struct fib_iterator *) n;
nulls = 0; nulls = 0;
@ -583,7 +587,6 @@ fib_check(struct fib *f)
} }
if (ec != f->entries) if (ec != f->entries)
bug("fib_check: invalid entry count (%d != %d)", ec, f->entries); bug("fib_check: invalid entry count (%d != %d)", ec, f->entries);
#endif
return; return;
} }
@ -602,7 +605,7 @@ fib_histogram(struct fib *f)
for (e = f->hash_table[i]; e != NULL; e = e->next) for (e = f->hash_table[i]; e != NULL; e = e->next)
j++; j++;
if (j > 0) if (j > 0)
log(L_WARN "Histogram line %d: %d", i, j); log(L_WARN "Histogram line %d: %d", i, j);
} }
log(L_WARN "Histogram dump end"); log(L_WARN "Histogram dump end");

View File

@ -89,7 +89,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
break; break;
} }
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)) if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
bsprintf(from, " from %I", a->from); bsprintf(from, " from %I", a->from);
else else
@ -113,7 +113,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) if (d->last_table != d->tab)
rt_show_table(c, d); rt_show_table(c, d);
cli_printf(c, -1007, "%-18s%s %s [%s %s%s]%s%s", ia, ai, rta_dest_name(a->dest), cli_printf(c, -1007, "%-20s%s %s [%s %s%s]%s%s", ia, ai, rta_dest_name(a->dest),
a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (a->dest == RTD_UNICAST) if (a->dest == RTD_UNICAST)
@ -121,9 +121,10 @@ 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 mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : ""; char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
char weight[16] = "";
if (nh->labels) if (nh->labels)
{ {
lsp += bsprintf(lsp, " mpls %d", nh->label[0]); lsp += bsprintf(lsp, " mpls %d", nh->label[0]);
for (int i=1;i<nh->labels; i++) for (int i=1;i<nh->labels; i++)
lsp += bsprintf(lsp, "/%d", nh->label[i]); lsp += bsprintf(lsp, "/%d", nh->label[i]);
@ -131,11 +132,14 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
*lsp = '\0'; *lsp = '\0';
if (a->nh.next) if (a->nh.next)
cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d", bsprintf(weight, " weight %d", nh->weight + 1);
nh->gw, mpls, nh->iface->name, onlink, 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 else
cli_printf(c, -1007, "\tvia %I%s on %s%s", cli_printf(c, -1007, "\tdev %s%s%s",
nh->gw, mpls, nh->iface->name, onlink); nh->iface->name, mpls, onlink, weight);
} }
if (d->verbose) if (d->verbose)
@ -189,7 +193,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d, const uint addr_type)
/* Special case for merged export */ /* Special case for merged export */
if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED)) if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
{ {
rte *rt_free; rte *rt_free;
e = rt_export_merged(ec, n, &rt_free, &tmpa, c->show_pool, 1); e = rt_export_merged(ec, n, &rt_free, &tmpa, c->show_pool, 1);
pass = 1; pass = 1;
@ -216,7 +220,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d, const uint addr_type)
* command may change the export filter and do not update routes. * command may change the export filter and do not update routes.
*/ */
int do_export = (ic > 0) || int do_export = (ic > 0) ||
(f_run(ec->out_filter, &e, &tmpa, c->show_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); (f_run(ec->out_filter, &e, &tmpa, c->show_pool,
FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT);
if (do_export != (d->export_mode == RSEM_EXPORT)) if (do_export != (d->export_mode == RSEM_EXPORT))
goto skip; goto skip;
@ -479,4 +484,3 @@ rt_show(struct rt_show_data *d)
cli_msg(8001, "Network not found"); cli_msg(8001, "Network not found");
} }
} }

View File

@ -85,6 +85,45 @@ net_route_ip6(rtable *t, net_addr_ip6 *n)
return r; return r;
} }
static inline void *
net_route_ip6_sadr(rtable *t, net_addr_ip6_sadr *n)
{
struct fib_node *fn;
while (1)
{
net *best = NULL;
int best_pxlen = 0;
/* We need to do dst first matching. Since sadr addresses are hashed on dst
prefix only, find the hash table chain and go through it to find the
match with the smallest matching src prefix. */
for (fn = fib_get_chain(&t->fib, (net_addr *) n); fn; fn = fn->next)
{
net_addr_ip6_sadr *a = (void *) fn->addr;
if (net_equal_dst_ip6_sadr(n, a) &&
net_in_net_src_ip6_sadr(n, a) &&
(a->src_pxlen >= best_pxlen))
{
best = fib_node_to_user(&t->fib, fn);
best_pxlen = a->src_pxlen;
}
}
if (best)
return best;
if (!n->dst_pxlen)
break;
n->dst_pxlen--;
ip6_clrbit(&n->dst_prefix, n->dst_pxlen);
}
return NULL;
}
void * void *
net_route(rtable *tab, const net_addr *n) net_route(rtable *tab, const net_addr *n)
{ {
@ -105,6 +144,9 @@ net_route(rtable *tab, const net_addr *n)
case NET_ROA6: case NET_ROA6:
return net_route_ip6(tab, (net_addr_ip6 *) n0); return net_route_ip6(tab, (net_addr_ip6 *) n0);
case NET_IP6_SADR:
return net_route_ip6_sadr(tab, (net_addr_ip6_sadr *) n0);
default: default:
return NULL; return NULL;
} }
@ -387,7 +429,8 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, ea_list **tmpa, linpo
} }
v = filter && ((filter == FILTER_REJECT) || v = filter && ((filter == FILTER_REJECT) ||
(f_run(filter, &rt, tmpa, pool, FF_FORCE_TMPATTR) > F_ACCEPT)); (f_run(filter, &rt, tmpa, pool,
FF_FORCE_TMPATTR | (silent ? FF_SILENT : 0)) > F_ACCEPT));
if (v) if (v)
{ {
if (silent) if (silent)
@ -613,9 +656,9 @@ rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_chang
old_meet = 1; old_meet = 1;
} }
/* /*
* Second, handle the feed case. That means we do not care for * Second, handle the feed case. That means we do not care for
* old_best. It is NULL for feed, and the new_best for refeed. * old_best. It is NULL for feed, and the new_best for refeed.
* For refeed, there is a hack similar to one in rt_notify_basic() * For refeed, there is a hack similar to one in rt_notify_basic()
* to ensure withdraws in case of changed filters * to ensure withdraws in case of changed filters
*/ */
@ -824,7 +867,7 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
* @new_best: the new best route for the same network * @new_best: the new best route for the same network
* @old_best: the previous best route for the same network * @old_best: the previous best route for the same network
* @before_old: The previous route before @old for the same network. * @before_old: The previous route before @old for the same network.
* If @before_old is NULL @old was the first. * If @before_old is NULL @old was the first.
* *
* This function gets a routing table update and announces it * This function gets a routing table update and announces it
* to all protocols that acccepts given type of route announcement * to all protocols that acccepts given type of route announcement
@ -897,7 +940,9 @@ rte_validate(rte *e)
return 0; 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)) if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{ {
log(L_WARN "Ignoring bogus route %N received via %s", log(L_WARN "Ignoring bogus route %N received via %s",
@ -1173,7 +1218,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
} }
if (new) if (new)
new->lastmod = now; new->lastmod = current_time();
/* Log the route change */ /* Log the route change */
if (p->debug & D_ROUTES) if (p->debug & D_ROUTES)
@ -1201,7 +1246,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
if (!net->routes && if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) && (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); rt_schedule_prune(table);
if (old_ok && p->rte_remove) if (old_ok && p->rte_remove)
@ -1384,7 +1429,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
/* Independent call to rte_announce(), used from next hop /* Independent call to rte_announce(), used from next hop
recalculation, outside of rte_update(). new must be non-NULL */ recalculation, outside of rte_update(). new must be non-NULL */
static inline void static inline void
rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old, rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
rte *new_best, rte *old_best) rte *new_best, rte *old_best)
{ {
@ -1417,7 +1462,8 @@ rt_examine(rtable *t, net_addr *a, struct proto *p, struct filter *filter)
ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool); ea_list *tmpa = rte_make_tmp_attrs(rt, rte_update_pool);
int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0; int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
if (v == RIC_PROCESS) if (v == RIC_PROCESS)
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT); v = (f_run(filter, &rt, &tmpa, rte_update_pool,
FF_FORCE_TMPATTR | FF_SILENT) <= F_ACCEPT);
/* Discard temporary rte */ /* Discard temporary rte */
if (rt != n->routes) if (rt != n->routes)
@ -1497,7 +1543,7 @@ rte_dump(rte *e)
{ {
net *n = e->net; net *n = e->net;
debug("%-1N ", n->n.addr); 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); rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs) if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e); e->attrs->src->proto->proto->dump_attrs(e);
@ -1595,22 +1641,19 @@ rt_event(void *ptr)
} }
void void
rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf) rt_setup(pool *p, rtable *t, struct rtable_config *cf)
{ {
bzero(t, sizeof(*t)); bzero(t, sizeof(*t));
t->name = name; t->name = cf->name;
t->config = cf; t->config = cf;
t->addr_type = cf ? cf->addr_type : NET_IP4; t->addr_type = cf->addr_type;
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL); fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
init_list(&t->channels); init_list(&t->channels);
if (cf) t->rt_event = ev_new(p);
{ t->rt_event->hook = rt_event;
t->rt_event = ev_new(p); t->rt_event->data = t;
t->rt_event->hook = rt_event; t->gc_time = current_time();
t->rt_event->data = t;
t->gc_time = now;
}
} }
/** /**
@ -1708,7 +1751,7 @@ again:
#endif #endif
tab->gc_counter = 0; tab->gc_counter = 0;
tab->gc_time = now; tab->gc_time = current_time();
/* state change 2->0, 3->1 */ /* state change 2->0, 3->1 */
tab->prune_state &= 1; tab->prune_state &= 1;
@ -2033,6 +2076,13 @@ rt_unlock_table(rtable *r)
} }
} }
static struct rtable_config *
rt_find_table_config(struct config *cf, char *name)
{
struct symbol *sym = cf_find_symbol(cf, name);
return (sym && (sym->class == SYM_TABLE)) ? sym->def : NULL;
}
/** /**
* rt_commit - commit new routing table configuration * rt_commit - commit new routing table configuration
* @new: new configuration * @new: new configuration
@ -2058,11 +2108,10 @@ rt_commit(struct config *new, struct config *old)
rtable *ot = o->table; rtable *ot = o->table;
if (!ot->deleted) if (!ot->deleted)
{ {
struct symbol *sym = cf_find_symbol(new, o->name); r = rt_find_table_config(new, o->name);
if (sym && sym->class == SYM_TABLE && !new->shutdown) if (r && (r->addr_type == o->addr_type) && !new->shutdown)
{ {
DBG("\t%s: same\n", o->name); DBG("\t%s: same\n", o->name);
r = sym->def;
r->table = ot; r->table = ot;
ot->name = r->name; ot->name = r->name;
ot->config = r; ot->config = r;
@ -2086,7 +2135,7 @@ rt_commit(struct config *new, struct config *old)
{ {
rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable)); rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
DBG("\t%s: created\n", r->name); DBG("\t%s: created\n", r->name);
rt_setup(rt_table_pool, t, r->name, r); rt_setup(rt_table_pool, t, r);
add_tail(&routing_tables, &t->n); add_tail(&routing_tables, &t->n);
r->table = t; r->table = t;
} }
@ -2356,7 +2405,7 @@ if_local_addr(ip_addr a, struct iface *i)
return 0; return 0;
} }
static u32 static u32
rt_get_igp_metric(rte *rt) rt_get_igp_metric(rte *rt)
{ {
eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC); eattr *ea = ea_find(rt->attrs->eattrs, EA_GEN_IGP_METRIC);
@ -2388,12 +2437,13 @@ static int
rt_update_hostentry(rtable *tab, struct hostentry *he) rt_update_hostentry(rtable *tab, struct hostentry *he)
{ {
rta *old_src = he->src; rta *old_src = he->src;
int direct = 0;
int pxlen = 0; int pxlen = 0;
/* Reset the hostentry */ /* Reset the hostentry */
he->src = NULL; he->src = NULL;
he->nexthop_linkable = 0;
he->dest = RTD_UNREACHABLE; he->dest = RTD_UNREACHABLE;
he->nexthop_linkable = 0;
he->igp_metric = 0; he->igp_metric = 0;
net_addr he_addr; net_addr he_addr;
@ -2413,9 +2463,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
goto done; goto done;
} }
he->dest = a->dest; if (a->dest == RTD_UNICAST)
he->nexthop_linkable = 1;
if (he->dest == RTD_UNICAST)
{ {
for (struct nexthop *nh = &(a->nh); nh; nh = nh->next) for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
if (ipa_zero(nh->gw)) if (ipa_zero(nh->gw))
@ -2428,12 +2476,13 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
goto done; goto done;
} }
he->nexthop_linkable = 0; direct++;
break;
} }
} }
he->src = rta_clone(a); he->src = rta_clone(a);
he->dest = a->dest;
he->nexthop_linkable = !direct;
he->igp_metric = rt_get_igp_metric(e); he->igp_metric = rt_get_igp_metric(e);
} }

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@
* BIRD -- The Babel protocol * BIRD -- The Babel protocol
* *
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen * 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. * Can be freely distributed and used under the terms of the GNU GPL.
* *
@ -21,7 +23,7 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "lib/string.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_METRIC EA_CODE(EAP_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1) #define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1)
@ -32,25 +34,28 @@
#define BABEL_INFINITY 0xFFFF #define BABEL_INFINITY 0xFFFF
#define BABEL_HELLO_INTERVAL_WIRED 4 /* Default hello intervals in seconds */ #define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
#define BABEL_HELLO_INTERVAL_WIRELESS 4 #define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
#define BABEL_HELLO_LIMIT 12
#define BABEL_UPDATE_INTERVAL_FACTOR 4 #define BABEL_UPDATE_INTERVAL_FACTOR 4
#define BABEL_IHU_INTERVAL_FACTOR 3 #define BABEL_IHU_INTERVAL_FACTOR 3
#define BABEL_IHU_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */ #define BABEL_HOLD_TIME_FACTOR 4 /* How long we keep unreachable route relative to update interval */
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */ #define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((X)*7/2) /* 3.5 */ #define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
#define BABEL_ROUTE_REFRESH_INTERVAL 2 /* Seconds before route expiry to send route request */ #define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_HOLD_TIME 10 /* Expiry time for our own routes */ #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_WIRED 96
#define BABEL_RXCOST_WIRELESS 256 #define BABEL_RXCOST_WIRELESS 256
#define BABEL_INITIAL_HOP_COUNT 255 #define BABEL_INITIAL_HOP_COUNT 255
#define BABEL_MAX_SEND_INTERVAL 5 #define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
#define BABEL_TIME_UNITS 100 /* On-wire times are counted in centiseconds */
#define BABEL_SEQNO_REQUEST_EXPIRY 60
#define BABEL_GARBAGE_INTERVAL 300
/* Max interval that will not overflow when carried as 16-bit centiseconds */ /* 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_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD) #define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
@ -80,7 +85,10 @@ enum babel_tlv_type {
enum babel_subtlv_type { enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0, BABEL_SUBTLV_PAD1 = 0,
BABEL_SUBTLV_PADN = 1 BABEL_SUBTLV_PADN = 1,
/* Mandatory subtlvs */
BABEL_SUBTLV_SOURCE_PREFIX = 128,
}; };
enum babel_iface_type { enum babel_iface_type {
@ -102,8 +110,11 @@ enum babel_ae_type {
struct babel_config { struct babel_config {
struct proto_config c; struct proto_config c;
list iface_list; /* List of iface configs (struct babel_iface_config) */
uint hold_time; /* Time to hold stale entries and unreachable routes */
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */ struct channel_config *ip4_channel;
struct channel_config *ip6_channel;
}; };
struct babel_iface_config { struct babel_iface_config {
@ -111,11 +122,12 @@ struct babel_iface_config {
u16 rxcost; u16 rxcost;
u8 type; u8 type;
u8 limit; /* Minimum number of Hellos to keep link up */
u8 check_link; u8 check_link;
uint port; uint port;
u16 hello_interval; uint hello_interval; /* Hello interval, in us */
u16 ihu_interval; uint ihu_interval; /* IHU interval, in us */
u16 update_interval; uint update_interval; /* Update interval, in us */
u16 rx_buffer; /* RX buffer size, 0 for MTU */ u16 rx_buffer; /* RX buffer size, 0 for MTU */
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */ u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
@ -138,14 +150,13 @@ struct babel_proto {
list interfaces; /* Interfaces we really know about (struct babel_iface) */ list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id; u64 router_id;
u16 update_seqno; /* To be increased on request */ u16 update_seqno; /* To be increased on request */
u8 update_seqno_inc; /* Request for update_seqno increase */
u8 triggered; /* For triggering global updates */ u8 triggered; /* For triggering global updates */
slab *route_slab; slab *route_slab;
slab *source_slab; slab *source_slab;
slab *msg_slab; slab *msg_slab;
slab *seqno_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 */ struct tbf log_pkt_tbf; /* TBF for packet messages */
}; };
@ -172,10 +183,10 @@ struct babel_iface {
u16 hello_seqno; /* To be increased on each hello */ u16 hello_seqno; /* To be increased on each hello */
bird_clock_t next_hello; btime next_hello;
bird_clock_t next_regular; btime next_regular;
bird_clock_t next_triggered; btime next_triggered;
bird_clock_t want_triggered; btime want_triggered;
timer *timer; timer *timer;
event *send_event; event *send_event;
@ -186,13 +197,18 @@ struct babel_neighbor {
struct babel_iface *ifa; struct babel_iface *ifa;
ip_addr addr; 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; u8 hello_cnt;
u16 hello_map; u16 hello_map;
u16 next_hello_seqno; u16 next_hello_seqno;
uint last_hello_int;
/* expiry timers */ /* expiry timers */
bird_clock_t hello_expiry; btime hello_expiry;
bird_clock_t ihu_expiry; btime ihu_expiry;
list routes; /* Routes this neighbour has sent us (struct babel_route) */ list routes; /* Routes this neighbour has sent us (struct babel_route) */
}; };
@ -203,7 +219,7 @@ struct babel_source {
u64 router_id; u64 router_id;
u16 seqno; u16 seqno;
u16 metric; u16 metric;
bird_clock_t expires; btime expires;
}; };
struct babel_route { struct babel_route {
@ -212,37 +228,46 @@ struct babel_route {
struct babel_entry *e; struct babel_entry *e;
struct babel_neighbor *neigh; struct babel_neighbor *neigh;
u8 feasible;
u16 seqno; u16 seqno;
u16 advert_metric;
u16 metric; u16 metric;
u16 advert_metric;
u64 router_id; u64 router_id;
ip_addr next_hop; ip_addr next_hop;
bird_clock_t refresh_time; btime refresh_time;
bird_clock_t expires; btime expires;
u16 expiry_interval; };
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_entry {
struct babel_proto *proto; struct babel_route *selected;
struct babel_route *selected_in;
struct babel_route *selected_out;
bird_clock_t updated;
list sources; /* Source entries for this prefix (struct babel_source). */
list routes; /* Routes for this prefix (struct babel_route) */ 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; struct fib_node n;
}; };
/* Stores forwarded seqno requests for duplicate suppression. */ #define BABEL_ENTRY_DUMMY 0 /* No outgoing route */
struct babel_seqno_request { #define BABEL_ENTRY_VALID 1 /* Valid outgoing route */
node n; #define BABEL_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */
net_addr net;
u64 router_id;
u16 seqno;
bird_clock_t updated;
};
/* /*
@ -252,7 +277,7 @@ struct babel_seqno_request {
struct babel_msg_ack_req { struct babel_msg_ack_req {
u8 type; u8 type;
u16 nonce; u16 nonce;
u16 interval; uint interval;
ip_addr sender; ip_addr sender;
}; };
@ -264,7 +289,7 @@ struct babel_msg_ack {
struct babel_msg_hello { struct babel_msg_hello {
u8 type; u8 type;
u16 seqno; u16 seqno;
u16 interval; uint interval;
ip_addr sender; ip_addr sender;
}; };
@ -272,7 +297,7 @@ struct babel_msg_ihu {
u8 type; u8 type;
u8 ae; u8 ae;
u16 rxcost; u16 rxcost;
u16 interval; uint interval;
ip_addr addr; ip_addr addr;
ip_addr sender; ip_addr sender;
}; };
@ -280,11 +305,14 @@ struct babel_msg_ihu {
struct babel_msg_update { struct babel_msg_update {
u8 type; u8 type;
u8 wildcard; u8 wildcard;
u16 interval; uint interval;
u16 seqno; u16 seqno;
u16 metric; u16 metric;
u64 router_id; u64 router_id;
net_addr net; union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr next_hop; ip_addr next_hop;
ip_addr sender; ip_addr sender;
}; };
@ -292,7 +320,10 @@ struct babel_msg_update {
struct babel_msg_route_request { struct babel_msg_route_request {
u8 type; u8 type;
u8 full; u8 full;
net_addr net; union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
}; };
struct babel_msg_seqno_request { struct babel_msg_seqno_request {
@ -300,7 +331,10 @@ struct babel_msg_seqno_request {
u8 hop_count; u8 hop_count;
u16 seqno; u16 seqno;
u64 router_id; u64 router_id;
net_addr net; union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr sender; ip_addr sender;
}; };
@ -320,6 +354,8 @@ struct babel_msg_node {
union babel_msg msg; union babel_msg msg;
}; };
static inline int babel_sadr_enabled(struct babel_proto *p)
{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }
/* babel.c */ /* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa); void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
@ -334,6 +370,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_interfaces(struct proto *P, char *iff);
void babel_show_neighbors(struct proto *P, char *iff); void babel_show_neighbors(struct proto *P, char *iff);
void babel_show_entries(struct proto *P); void babel_show_entries(struct proto *P);
void babel_show_routes(struct proto *P);
/* packets.c */ /* packets.c */
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa); void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);

View File

@ -2,6 +2,8 @@
* BIRD -- Babel Configuration * BIRD -- Babel Configuration
* *
* Copyright (c) 2015-2016 Toke Hoiland-Jorgensen * 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. * Can be freely distributed and used under the terms of the GNU GPL.
*/ */
@ -20,9 +22,10 @@ CF_DEFINES
CF_DECLS CF_DECLS
CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED, CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC, NEXT, HOP, TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
IPV4, IPV6) NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
ENTRIES)
CF_GRAMMAR CF_GRAMMAR
@ -32,6 +35,7 @@ babel_proto_start: proto_start BABEL
{ {
this_proto = proto_config_new(&proto_babel, $1); this_proto = proto_config_new(&proto_babel, $1);
init_list(&BABEL_CFG->iface_list); init_list(&BABEL_CFG->iface_list);
BABEL_CFG->hold_time = 1 S_;
}; };
babel_proto_item: babel_proto_item:
@ -56,6 +60,7 @@ babel_iface_start:
init_list(&this_ipatt->ipn_list); init_list(&this_ipatt->ipn_list);
BABEL_IFACE->port = BABEL_PORT; BABEL_IFACE->port = BABEL_PORT;
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL; BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
BABEL_IFACE->tx_priority = sk_priority_control; BABEL_IFACE->tx_priority = sk_priority_control;
BABEL_IFACE->check_link = 1; BABEL_IFACE->check_link = 1;
@ -83,16 +88,19 @@ babel_iface_finish:
if (!BABEL_IFACE->update_interval) if (!BABEL_IFACE->update_interval)
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_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_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: babel_iface_item:
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); } | 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"); } | 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"); } | LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
| UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid update interval"); }
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; } | TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; } | 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"); } | 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 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; } | TX tos { BABEL_IFACE->tx_tos = $2; }
@ -129,6 +137,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]]) CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
{ babel_show_entries(proto_get_named($4, &proto_babel)); }; { 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_CODE
CF_END CF_END

View File

@ -2,6 +2,8 @@
* BIRD -- The Babel protocol * BIRD -- The Babel protocol
* *
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen * 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. * 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 { struct babel_tlv_hello {
u8 type; u8 type;
u8 length; u8 length;
u16 reserved; u16 flags;
u16 seqno; u16 seqno;
u16 interval; u16 interval;
} PACKED; } PACKED;
@ -103,9 +105,20 @@ struct babel_tlv_seqno_request {
u8 addr[0]; u8 addr[0];
} PACKED; } PACKED;
struct babel_subtlv_source_prefix {
u8 type;
u8 length;
u8 plen;
u8 addr[0];
} 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 { struct babel_parse_state {
@ -121,6 +134,7 @@ struct babel_parse_state {
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */ u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */ u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */ u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
u8 sadr_enabled;
}; };
enum parse_result { enum parse_result {
@ -162,17 +176,17 @@ bytes_equal(u8 *b1, u8 *b2, uint maxlen)
return i; return i;
} }
static inline u16 static inline uint
get_time16(const void *p) get_time16(const void *p)
{ {
u16 v = get_u16(p) / BABEL_TIME_UNITS; uint v = get_u16(p) * BABEL_TIME_UNITS;
return MAX(1, v); return MAX(BABEL_MIN_INTERVAL, v);
} }
static inline void 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 static inline void
@ -231,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru
static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state); static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
@ -238,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct
static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len); static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
struct babel_tlv_data { struct babel_tlv_data {
u8 min_length; u8 min_length;
@ -341,6 +357,11 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
struct babel_tlv_hello *tlv = (void *) hdr; struct babel_tlv_hello *tlv = (void *) hdr;
struct babel_msg_hello *msg = &m->hello; 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->type = BABEL_TLV_HELLO;
msg->seqno = get_u16(&tlv->seqno); msg->seqno = get_u16(&tlv->seqno);
msg->interval = get_time16(&tlv->interval); msg->interval = get_time16(&tlv->interval);
@ -593,8 +614,8 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
if (tlv->omitted && !state->def_ip4_prefix_seen) if (tlv->omitted && !state->def_ip4_prefix_seen)
return PARSE_ERROR; return PARSE_ERROR;
/* Need next hop for v4 routes */ /* Update must have next hop, unless it is retraction */
if (ipa_zero(state->next_hop_ip4)) if (ipa_zero(state->next_hop_ip4) && (msg->metric != BABEL_INFINITY))
return PARSE_ERROR; return PARSE_ERROR;
/* Merge saved prefix and received prefix parts */ /* Merge saved prefix and received prefix parts */
@ -604,7 +625,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
ip4_addr prefix4 = get_ip4(buf); ip4_addr prefix4 = get_ip4(buf);
net_fill_ip4(&msg->net, prefix4, tlv->plen); 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); put_ip4(state->def_ip4_prefix, prefix4);
state->def_ip4_prefix_seen = 1; state->def_ip4_prefix_seen = 1;
@ -629,13 +650,16 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
ip6_addr prefix6 = get_ip6(buf); ip6_addr prefix6 = get_ip6(buf);
net_fill_ip6(&msg->net, prefix6, tlv->plen); net_fill_ip6(&msg->net, prefix6, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX) if (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{ {
put_ip6(state->def_ip6_prefix, prefix6); put_ip6(state->def_ip6_prefix, prefix6);
state->def_ip6_prefix_seen = 1; 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 = ((u64) _I2(prefix6)) << 32 | _I3(prefix6);
state->router_id_seen = 1; state->router_id_seen = 1;
@ -748,7 +772,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
else else
{ {
put_ip6_px(tlv->addr, &msg->net); 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)); put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen; state->def_ip6_pxlen = tlv->plen;
@ -759,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_u16(&tlv->seqno, msg->seqno); put_u16(&tlv->seqno, msg->seqno);
put_u16(&tlv->metric, msg->metric); put_u16(&tlv->metric, msg->metric);
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len));
if (l < 0)
return 0;
len += l;
}
return len0 + len; return len0 + len;
} }
static int static int
babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m, babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_parse_state *state UNUSED) struct babel_parse_state *state)
{ {
struct babel_tlv_route_request *tlv = (void *) hdr; struct babel_tlv_route_request *tlv = (void *) hdr;
struct babel_msg_route_request *msg = &m->route_request; struct babel_msg_route_request *msg = &m->route_request;
@ -801,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen); read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen);
if (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
return PARSE_SUCCESS; return PARSE_SUCCESS;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
@ -845,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
put_ip6_px(tlv->addr, &msg->net); put_ip6_px(tlv->addr, &msg->net);
} }
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
if (l < 0)
return 0;
len += l;
}
return len; return len;
} }
@ -889,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen); read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen); state->current_tlv_endpos += BYTES(tlv->plen);
if (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
return PARSE_SUCCESS; return PARSE_SUCCESS;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
@ -932,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->hop_count = msg->hop_count; tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id); put_u64(&tlv->router_id, msg->router_id);
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
if (l < 0)
return 0;
len += l;
}
return len; return len;
} }
static int
babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg,
struct babel_parse_state *state UNUSED)
{
struct babel_subtlv_source_prefix *tlv = (void *) hdr;
net_addr_ip6_sadr *net;
/*
* We would like to skip the sub-TLV if SADR is not enabled, but we do not
* know AF of the enclosing TLV yet. We will do that later.
*/
/* Check internal consistency */
if ((tlv->length < 1) ||
(tlv->plen > IP6_MAX_PREFIX_LENGTH) ||
(tlv->length < (1 + BYTES(tlv->plen))))
return PARSE_ERROR;
/* Plen MUST NOT be 0 */
if (tlv->plen == 0)
return PARSE_ERROR;
switch(msg->type)
{
case BABEL_TLV_UPDATE:
/* Wildcard updates with source prefix MUST be silently ignored */
if (msg->update.wildcard)
return PARSE_IGNORE;
net = (void *) &msg->update.net;
break;
case BABEL_TLV_ROUTE_REQUEST:
/* Wildcard requests with source addresses MUST be silently ignored */
if (msg->route_request.full)
return PARSE_IGNORE;
net = (void *) &msg->route_request.net;
break;
case BABEL_TLV_SEQNO_REQUEST:
net = (void *) &msg->seqno_request.net;
break;
default:
return PARSE_ERROR;
}
/* If SADR is active, the net has appropriate type */
if (net->type != NET_IP6_SADR)
return PARSE_IGNORE;
/* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */
if (net->src_pxlen > 0)
return PARSE_IGNORE;
net_addr_ip6 src;
read_ip6_px((void *) &src, tlv->addr, tlv->plen);
net->src_prefix = src.prefix;
net->src_pxlen = src.pxlen;
return PARSE_SUCCESS;
}
static int
babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
{
struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr);
net_addr_ip6_sadr *net = (void *) n;
/* Do not use this sub-TLV for default prefix */
if (net->src_pxlen == 0)
return 0;
uint len = sizeof(*tlv) + BYTES(net->src_pxlen);
if (len > max_len)
return -1;
TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len);
hdr->length += len;
net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen);
tlv->plen = src.pxlen;
put_ip6_px(tlv->addr, (void *) &src);
return len;
}
static inline int static inline int
babel_read_subtlvs(struct babel_tlv *hdr, babel_read_subtlvs(struct babel_tlv *hdr,
union babel_msg *msg UNUSED, union babel_msg *msg,
struct babel_parse_state *state) struct babel_parse_state *state)
{ {
struct babel_tlv *tlv; struct babel_tlv *tlv;
byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
int res;
for (tlv = (void *) hdr + state->current_tlv_endpos; for (tlv = (void *) hdr + state->current_tlv_endpos;
(void *) tlv < (void *) hdr + TLV_LENGTH(hdr); (byte *) tlv < end;
tlv = NEXT_TLV(tlv)) tlv = NEXT_TLV(tlv))
{ {
/* Ugly special case */
if (tlv->type == BABEL_TLV_PAD1)
continue;
/* The end of the common TLV header */
pos = (byte *)tlv + sizeof(struct babel_tlv);
if ((pos > end) || (pos + tlv->length > end))
return PARSE_ERROR;
/* /*
* The subtlv type space is non-contiguous (due to the mandatory bit), so * The subtlv type space is non-contiguous (due to the mandatory bit), so
* use a switch for dispatch instead of the mapping array we use for TLVs * use a switch for dispatch instead of the mapping array we use for TLVs
*/ */
switch (tlv->type) switch (tlv->type)
{ {
case BABEL_SUBTLV_PAD1: case BABEL_SUBTLV_SOURCE_PREFIX:
case BABEL_SUBTLV_PADN: res = babel_read_source_prefix(tlv, msg, state);
/* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */ if (res != PARSE_SUCCESS)
return res;
break; break;
case BABEL_SUBTLV_PADN:
default: default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */ /* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
if (tlv->type > 128) if (tlv->type >= 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
return PARSE_IGNORE; return PARSE_IGNORE;
}
break; break;
} }
} }
@ -1186,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
.ifa = ifa, .ifa = ifa,
.saddr = saddr, .saddr = saddr,
.next_hop_ip6 = saddr, .next_hop_ip6 = saddr,
.sadr_enabled = babel_sadr_enabled(p),
}; };
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION)) if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
@ -1294,7 +1454,7 @@ babel_rx_hook(sock *sk, uint len)
sk->iface->name, sk->faddr, sk->laddr); sk->iface->name, sk->faddr, sk->laddr);
/* Silently ignore my own packets */ /* Silently ignore my own packets */
if (ipa_equal(ifa->iface->addr->ip, sk->faddr)) if (ipa_equal(sk->faddr, sk->saddr))
return 1; return 1;
if (!ipa_is_link_local(sk->faddr)) if (!ipa_is_link_local(sk->faddr))
@ -1329,6 +1489,8 @@ babel_open_socket(struct babel_iface *ifa)
sk->sport = ifa->cf->port; sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port; sk->dport = ifa->cf->port;
sk->iface = ifa->iface; sk->iface = ifa->iface;
sk->saddr = ifa->addr;
sk->vrf = p->p.vrf;
sk->rx_hook = babel_rx_hook; sk->rx_hook = babel_rx_hook;
sk->tx_hook = babel_tx_hook; sk->tx_hook = babel_tx_hook;

View File

@ -64,16 +64,15 @@
* ready, the protocol just creates a BFD request like any other protocol. * 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|, * The protocol uses a new generic event loop (structure &birdloop) from |io.c|,
* which supports sockets, timers and events like the main loop. Timers * which supports sockets, timers and events like the main loop. A birdloop is
* (structure &timer2) are new microsecond based timers, while sockets and * associated with a thread (field @thread) in which event hooks are executed.
* events are the same. A birdloop is associated with a thread (field @thread) * Most functions for setting event sources (like sk_start() or tm_start()) must
* in which event hooks are executed. Most functions for setting event sources * be called from the context of that thread. Birdloop allows to temporarily
* (like sk_start() or tm2_start()) must be called from the context of that * acquire the context of that thread for the main thread by calling
* thread. Birdloop allows to temporarily acquire the context of that thread for * birdloop_enter() and then birdloop_leave(), which also ensures mutual
* the main thread by calling birdloop_enter() and then birdloop_leave(), which * exclusion with all event hooks. Note that resources associated with a
* also ensures mutual exclusion with all event hooks. Note that resources * birdloop (like timers) should be attached to the independent resource pool,
* associated with a birdloop (like timers) should be attached to the * detached from the main resource tree.
* independent resource pool, detached from the main resource tree.
* *
* There are two kinds of interaction between the BFD core (running in the BFD * 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 * 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); bfd_lock_sessions(p);
s->loc_state = state; s->loc_state = state;
s->loc_diag = diag; s->loc_diag = diag;
s->last_state_change = current_time();
notify = !NODE_VALID(&s->n); notify = !NODE_VALID(&s->n);
if (notify) if (notify)
@ -176,7 +176,7 @@ bfd_session_update_tx_interval(struct bfd_session *s)
return; return;
/* Set timer relative to last tx_timer event */ /* 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 static void
@ -190,7 +190,7 @@ bfd_session_update_detection_time(struct bfd_session *s, int kick)
if (!s->last_rx) if (!s->last_rx)
return; return;
tm2_set(s->hold_timer, s->last_rx + timeout); tm_set(s->hold_timer, s->last_rx + timeout);
} }
static void static void
@ -211,16 +211,16 @@ bfd_session_control_tx_timer(struct bfd_session *s, int reset)
goto stop; goto stop;
/* So TX timer should run */ /* So TX timer should run */
if (reset || !tm2_active(s->tx_timer)) if (reset || !tm_active(s->tx_timer))
{ {
s->last_tx = 0; s->last_tx = 0;
tm2_start(s->tx_timer, 0); tm_start(s->tx_timer, 0);
} }
return; return;
stop: stop:
tm2_stop(s->tx_timer); tm_stop(s->tx_timer);
s->last_tx = 0; s->last_tx = 0;
} }
@ -379,7 +379,7 @@ bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr)
} }
static void static void
bfd_tx_timer_hook(timer2 *t) bfd_tx_timer_hook(timer *t)
{ {
struct bfd_session *s = t->data; struct bfd_session *s = t->data;
@ -388,7 +388,7 @@ bfd_tx_timer_hook(timer2 *t)
} }
static void static void
bfd_hold_timer_hook(timer2 *t) bfd_hold_timer_hook(timer *t)
{ {
bfd_session_timeout(t->data); 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->passive = ifa->cf->passive;
s->tx_csn = random_u32(); s->tx_csn = random_u32();
s->tx_timer = tm2_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0); s->tx_timer = tm_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->hold_timer = tm_new_init(p->tpool, bfd_hold_timer_hook, s, 0, 0);
bfd_session_update_tx_interval(s); bfd_session_update_tx_interval(s);
bfd_session_control_tx_timer(s, 1); bfd_session_control_tx_timer(s, 1);
init_list(&s->request_list); 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); 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; diag = s->loc_diag;
bfd_unlock_sessions(p); bfd_unlock_sessions(p);
/* FIXME: convert to btime and move to bfd_session_update_state() */
s->last_state_change = now;
s->notify_running = 1; s->notify_running = 1;
WALK_LIST_DELSAFE(n, nn, s->request_list) WALK_LIST_DELSAFE(n, nn, s->request_list)
bfd_request_notify(SKIP_BACK(struct bfd_request, n, n), state, diag); 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]; byte tbuf[TM_DATETIME_BUFFER_SIZE];
struct bfd_proto *p = (struct bfd_proto *) P; struct bfd_proto *p = (struct bfd_proto *) P;
uint state, diag UNUSED; uint state, diag UNUSED;
u32 tx_int, timeout; btime tx_int, timeout;
const char *ifname; const char *ifname;
if (p->p.proto_state != PS_UP) if (p->p.proto_state != PS_UP)
@ -1101,15 +1098,14 @@ bfd_show_sessions(struct proto *P)
state = s->loc_state; state = s->loc_state;
diag = s->loc_diag; diag = s->loc_diag;
ifname = (s->ifa && s->ifa->iface) ? s->ifa->iface->name : "---"; 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; tx_int = s->last_tx ? MAX(s->des_min_tx_int, s->rem_min_rx_int) : 0;
timeout = (MAX(s->req_min_rx_int, s->rem_min_tx_int) TO_MS) * s->rem_detect_mult; timeout = (btime) MAX(s->req_min_rx_int, s->rem_min_tx_int) * s->rem_detect_mult;
state = (state < 4) ? state : 0; 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", cli_msg(-1020, "%-25I %-10s %-10s %-10s %7t %7t",
s->addr, ifname, bfd_state_names[state], tbuf, s->addr, ifname, bfd_state_names[state], tbuf, tx_int, timeout);
tx_int / 1000, tx_int % 1000, timeout / 1000, timeout % 1000);
} }
HASH_WALK_END; HASH_WALK_END;

View File

@ -140,11 +140,11 @@ struct bfd_session
btime last_tx; /* Time of last sent periodic control packet */ btime last_tx; /* Time of last sent periodic control packet */
btime last_rx; /* Time of last received valid control packet */ btime last_rx; /* Time of last received valid control packet */
timer2 *tx_timer; /* Periodic control packet timer */ timer *tx_timer; /* Periodic control packet timer */
timer2 *hold_timer; /* Timer for session down detection time */ timer *hold_timer; /* Timer for session down detection time */
list request_list; /* List of client requests (struct bfd_request) */ 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 notify_running; /* 1 if notify hooks are running */
u8 rx_csn_known; /* Received crypto sequence number is known */ u8 rx_csn_known; /* Received crypto sequence number is known */

View File

@ -18,10 +18,10 @@
#include "proto/bfd/io.h" #include "proto/bfd/io.h"
#include "lib/buffer.h" #include "lib/buffer.h"
#include "lib/heap.h"
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/event.h" #include "lib/event.h"
#include "lib/timer.h"
#include "lib/socket.h" #include "lib/socket.h"
@ -31,16 +31,12 @@ struct birdloop
pthread_t thread; pthread_t thread;
pthread_mutex_t mutex; pthread_mutex_t mutex;
btime last_time;
btime real_time;
u8 use_monotonic_clock;
u8 stop_called; u8 stop_called;
u8 poll_active; u8 poll_active;
u8 wakeup_masked; u8 wakeup_masked;
int wakeup_fds[2]; int wakeup_fds[2];
BUFFER(timer2 *) timers; struct timeloop time;
list event_list; list event_list;
list sock_list; list sock_list;
uint sock_num; uint sock_num;
@ -57,6 +53,7 @@ struct birdloop
*/ */
static pthread_key_t current_loop_key; static pthread_key_t current_loop_key;
extern pthread_key_t current_time_key;
static inline struct birdloop * static inline struct birdloop *
birdloop_current(void) birdloop_current(void)
@ -68,6 +65,7 @@ static inline void
birdloop_set_current(struct birdloop *loop) birdloop_set_current(struct birdloop *loop)
{ {
pthread_setspecific(current_loop_key, loop); pthread_setspecific(current_loop_key, loop);
pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
} }
static inline void 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 * Wakeup code for birdloop
*/ */
@ -238,7 +144,7 @@ wakeup_drain(struct birdloop *loop)
} }
static inline void static inline void
wakeup_do_kick(struct birdloop *loop) wakeup_do_kick(struct birdloop *loop)
{ {
pipe_kick(loop->wakeup_fds[1]); pipe_kick(loop->wakeup_fds[1]);
} }
@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
loop->wakeup_masked = 2; 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 * Events
@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
static void static void
events_fire(struct birdloop *loop) events_fire(struct birdloop *loop)
{ {
times_update(loop); times_update(&loop->time);
ev_run_list(&loop->event_list); 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 * Sockets
*/ */
@ -530,7 +298,7 @@ sockets_prepare(struct birdloop *loop)
struct pollfd *pfd = loop->poll_fd.data; struct pollfd *pfd = loop->poll_fd.data;
sock **psk = loop->poll_sk.data; sock **psk = loop->poll_sk.data;
int i = 0; uint i = 0;
node *n; node *n;
WALK_LIST(n, loop->sock_list) WALK_LIST(n, loop->sock_list)
@ -586,7 +354,7 @@ sockets_fire(struct birdloop *loop)
sock **psk = loop->poll_sk.data; sock **psk = loop->poll_sk.data;
int poll_num = loop->poll_fd.used - 1; int poll_num = loop->poll_fd.used - 1;
times_update(loop); times_update(&loop->time);
/* Last fd is internal wakeup fd */ /* Last fd is internal wakeup fd */
if (pfd[poll_num].revents & POLLIN) if (pfd[poll_num].revents & POLLIN)
@ -634,11 +402,10 @@ birdloop_new(void)
loop->pool = p; loop->pool = p;
pthread_mutex_init(&loop->mutex, NULL); pthread_mutex_init(&loop->mutex, NULL);
times_init(loop);
wakeup_init(loop); wakeup_init(loop);
events_init(loop); events_init(loop);
timers_init(loop); timers_init(&loop->time, p);
sockets_init(loop); sockets_init(loop);
return loop; return loop;
@ -710,7 +477,7 @@ static void *
birdloop_main(void *arg) birdloop_main(void *arg)
{ {
struct birdloop *loop = arg; struct birdloop *loop = arg;
timer2 *t; timer *t;
int rv, timeout; int rv, timeout;
birdloop_set_current(loop); birdloop_set_current(loop);
@ -719,13 +486,13 @@ birdloop_main(void *arg)
while (1) while (1)
{ {
events_fire(loop); events_fire(loop);
timers_fire(loop); timers_fire(&loop->time);
times_update(loop); times_update(&loop->time);
if (events_waiting(loop)) if (events_waiting(loop))
timeout = 0; timeout = 0;
else if (t = timers_first(loop)) else if (t = timers_first(&loop->time))
timeout = (tm2_remains(t) TO_MS) + 1; timeout = (tm_remains(t) TO_MS) + 1;
else else
timeout = -1; timeout = -1;
@ -756,7 +523,7 @@ birdloop_main(void *arg)
if (rv) if (rv)
sockets_fire(loop); sockets_fire(loop);
timers_fire(loop); timers_fire(&loop->time);
} }
loop->stop_called = 0; loop->stop_called = 0;

View File

@ -11,80 +11,15 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/event.h" #include "lib/event.h"
#include "lib/timer.h"
#include "lib/socket.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); 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_start(sock *s);
void sk_stop(sock *s); void sk_stop(sock *s);
struct birdloop *birdloop_new(void); struct birdloop *birdloop_new(void);
void birdloop_start(struct birdloop *loop); void birdloop_start(struct birdloop *loop);
void birdloop_stop(struct birdloop *loop); void birdloop_stop(struct birdloop *loop);

View File

@ -64,8 +64,6 @@
* format - Optional hook that converts eattr to textual representation. * format - Optional hook that converts eattr to textual representation.
*/ */
// XXXX review pool usage : c->c.proto->pool
struct bgp_attr_desc { struct bgp_attr_desc {
const char *name; const char *name;
@ -552,10 +550,12 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla
static void static void
bgp_export_ext_community(struct bgp_export_state *s, eattr *a) bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
{ {
a->u.ptr = ec_set_del_nontrans(s->pool, a->u.ptr);
if (a->u.ptr->length == 0) if (a->u.ptr->length == 0)
UNSET(a); UNSET(a);
a->u.ptr = ec_set_sort(s->pool, a->u.ptr); ec_set_sort_x(a->u.ptr);
} }
static void static void
@ -701,7 +701,8 @@ bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
static inline void static inline void
bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to) bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
{ {
bgp_set_attr_data(to, s->pool, code, flags, data, len); /* Cannot use bgp_set_attr_data() as it works on known attributes only */
ea_set_attr_data(to, s->pool, EA_CODE(EAP_BGP, code), flags, EAF_TYPE_OPAQUE, data, len);
} }
@ -1175,6 +1176,22 @@ bgp_init_bucket_table(struct bgp_channel *c)
c->withdraw_bucket = NULL; 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 * static struct bgp_bucket *
bgp_get_bucket(struct bgp_channel *c, ea_list *new) bgp_get_bucket(struct bgp_channel *c, ea_list *new)
{ {

View File

@ -98,11 +98,15 @@
* <item> <rfc id="7911"> - Advertisement of Multiple Paths in BGP * <item> <rfc id="7911"> - Advertisement of Multiple Paths in BGP
* <item> <rfc id="7947"> - Internet Exchange BGP Route Server * <item> <rfc id="7947"> - Internet Exchange BGP Route Server
* <item> <rfc id="8092"> - BGP Large Communities Attribute * <item> <rfc id="8092"> - BGP Large Communities Attribute
* <item> <rfc id="8203"> - BGP Administrative Shutdown Communication
* <item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
* </itemize> * </itemize>
*/ */
#undef LOCAL_DEBUG #undef LOCAL_DEBUG
#include <stdlib.h>
#include "nest/bird.h" #include "nest/bird.h"
#include "nest/iface.h" #include "nest/iface.h"
#include "nest/protocol.h" #include "nest/protocol.h"
@ -110,6 +114,7 @@
#include "nest/cli.h" #include "nest/cli.h"
#include "nest/locks.h" #include "nest/locks.h"
#include "conf/conf.h" #include "conf/conf.h"
#include "filter/filter.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "lib/string.h" #include "lib/string.h"
@ -312,20 +317,21 @@ err1:
/** /**
* bgp_start_timer - start a BGP timer * bgp_start_timer - start a BGP timer
* @t: 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 * 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 * randomization suggested by the BGP standard. Please use it for all BGP
* timers. * timers.
*/ */
void void
bgp_start_timer(timer *t, int value) bgp_start_timer(timer *t, uint value)
{ {
if (value) if (value)
{ {
/* The randomization procedure is specified in RFC 1771: 9.2.3.3 */ /* The randomization procedure is specified in RFC 4271 section 10 */
t->randomize = value / 4; btime time = value S;
tm_start(t, value - t->randomize); btime randomize = random() % ((time / 4) + 1);
tm_start(t, time - randomize);
} }
else else
tm_stop(t); tm_stop(t);
@ -381,10 +387,10 @@ bgp_update_startup_delay(struct bgp_proto *p)
DBG("BGP: Updating startup delay\n"); 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->startup_delay = 0;
p->last_proto_error = now; p->last_proto_error = current_time();
if (cf->disable_after_error) if (cf->disable_after_error)
{ {
@ -400,7 +406,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
} }
static void 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) switch (conn->state)
{ {
@ -416,7 +422,7 @@ bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
case BS_OPENSENT: case BS_OPENSENT:
case BS_OPENCONFIRM: case BS_OPENCONFIRM:
case BS_ESTABLISHED: case BS_ESTABLISHED:
bgp_error(conn, 6, subcode, NULL, 0); bgp_error(conn, 6, subcode, data, len);
return; return;
default: default:
@ -456,11 +462,11 @@ bgp_decision(void *vp)
} }
void 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); proto_notify_state(&p->p, PS_STOP);
bgp_graceful_close_conn(&p->outgoing_conn, subcode); bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
bgp_graceful_close_conn(&p->incoming_conn, subcode); bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
ev_schedule(p->event); ev_schedule(p->event);
} }
@ -598,12 +604,8 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
BGP_TRACE(D_EVENTS, "BGP session closed"); BGP_TRACE(D_EVENTS, "BGP session closed");
p->conn = NULL; 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) if (p->p.proto_state == PS_UP)
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
} }
void void
@ -661,6 +663,10 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
struct bgp_channel *c; struct bgp_channel *c;
WALK_LIST(c, p->p.channels) 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_ready)
{ {
if (c->gr_active) if (c->gr_active)
@ -676,10 +682,20 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
rt_refresh_begin(c->c.table, &c->c); rt_refresh_begin(c->c.table, &c->c);
rt_refresh_end(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;
} }
/* p->gr_ready -> at least one active channel is c->gr_ready */
ASSERT(p->gr_active_num > 0);
proto_notify_state(&p->p, PS_START); proto_notify_state(&p->p, PS_START);
bgp_start_timer(p->gr_timer, p->conn->local_caps->gr_time); bgp_start_timer(p->gr_timer, p->conn->remote_caps->gr_time);
} }
/** /**
@ -722,7 +738,7 @@ bgp_graceful_restart_timeout(timer *t)
struct bgp_proto *p = t->data; struct bgp_proto *p = t->data;
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout"); BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
} }
@ -885,9 +901,9 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
conn->last_channel = 0; conn->last_channel = 0;
conn->last_channel_count = 0; conn->last_channel_count = 0;
conn->connect_timer = tm_new_set(p->p.pool, bgp_connect_timeout, conn, 0, 0); conn->connect_timer = tm_new_init(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->hold_timer = tm_new_init(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->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 = ev_new(p->p.pool);
conn->tx_ev->hook = bgp_kick_tx; conn->tx_ev->hook = bgp_kick_tx;
@ -936,6 +952,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
s->daddr = p->cf->remote_ip; s->daddr = p->cf->remote_ip;
s->dport = p->cf->remote_port; s->dport = p->cf->remote_port;
s->iface = p->neigh ? p->neigh->iface : NULL; s->iface = p->neigh ? p->neigh->iface : NULL;
s->vrf = p->p.vrf;
s->ttl = p->cf->ttl_security ? 255 : hops; 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->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; s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
@ -1094,19 +1111,8 @@ bgp_start_neighbor(struct bgp_proto *p)
if (ipa_is_link_local(p->source_addr)) if (ipa_is_link_local(p->source_addr))
p->link_addr = p->source_addr; p->link_addr = p->source_addr;
else else if (p->neigh->iface->llv6)
{ p->link_addr = p->neigh->iface->llv6->ip;
/* 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);
}
bgp_initiate(p); bgp_initiate(p);
} }
@ -1132,7 +1138,7 @@ bgp_neigh_notify(neighbor *n)
BGP_TRACE(D_EVENTS, "Neighbor lost"); BGP_TRACE(D_EVENTS, "Neighbor lost");
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST); bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST);
/* Perhaps also run bgp_update_startup_delay(p)? */ /* 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)) else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP))
@ -1143,7 +1149,7 @@ bgp_neigh_notify(neighbor *n)
bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN); bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN);
if (ps == PS_UP) if (ps == PS_UP)
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
} }
} }
else else
@ -1168,7 +1174,7 @@ bgp_bfd_notify(struct bfd_request *req)
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN); bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
if (ps == PS_UP) if (ps == PS_UP)
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
} }
} }
@ -1311,13 +1317,8 @@ bgp_start(struct proto *P)
p->event->hook = bgp_decision; p->event->hook = bgp_decision;
p->event->data = p; p->event->data = p;
p->startup_timer = tm_new(p->p.pool); p->startup_timer = tm_new_init(p->p.pool, bgp_startup_timeout, p, 0, 0);
p->startup_timer->hook = bgp_startup_timeout; p->gr_timer = tm_new_init(p->p.pool, bgp_graceful_restart_timeout, p, 0, 0);
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->local_id = proto_get_router_id(P->cf); p->local_id = proto_get_router_id(P->cf);
if (p->rr_client) if (p->rr_client)
@ -1327,7 +1328,7 @@ bgp_start(struct proto *P)
p->source_addr = p->cf->local_ip; p->source_addr = p->cf->local_ip;
p->link_addr = IPA_NONE; p->link_addr = IPA_NONE;
/* XXXX */ /* Lock all channels when in GR recovery mode */
if (p->p.gr_recovery && p->cf->gr_mode) if (p->p.gr_recovery && p->cf->gr_mode)
{ {
struct bgp_channel *c; struct bgp_channel *c;
@ -1344,6 +1345,7 @@ bgp_start(struct proto *P)
lock->addr = p->cf->remote_ip; lock->addr = p->cf->remote_ip;
lock->port = p->cf->remote_port; lock->port = p->cf->remote_port;
lock->iface = p->cf->iface; lock->iface = p->cf->iface;
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
lock->type = OBJLOCK_TCP; lock->type = OBJLOCK_TCP;
lock->hook = bgp_start_locked; lock->hook = bgp_start_locked;
lock->data = p; lock->data = p;
@ -1360,6 +1362,10 @@ bgp_shutdown(struct proto *P)
struct bgp_proto *p = (struct bgp_proto *) P; struct bgp_proto *p = (struct bgp_proto *) P;
uint subcode = 0; uint subcode = 0;
char *message = NULL;
byte *data = NULL;
uint len = 0;
BGP_TRACE(D_EVENTS, "Shutdown requested"); BGP_TRACE(D_EVENTS, "Shutdown requested");
switch (P->down_code) switch (P->down_code)
@ -1376,10 +1382,12 @@ bgp_shutdown(struct proto *P)
case PDC_CMD_DISABLE: case PDC_CMD_DISABLE:
case PDC_CMD_SHUTDOWN: case PDC_CMD_SHUTDOWN:
subcode = 2; // Errcode 6, 2 - administrative shutdown subcode = 2; // Errcode 6, 2 - administrative shutdown
message = P->message;
break; break;
case PDC_CMD_RESTART: case PDC_CMD_RESTART:
subcode = 4; // Errcode 6, 4 - administrative reset subcode = 4; // Errcode 6, 4 - administrative reset
message = P->message;
break; break;
case PDC_RX_LIMIT_HIT: case PDC_RX_LIMIT_HIT:
@ -1404,8 +1412,22 @@ bgp_shutdown(struct proto *P)
bgp_store_error(p, NULL, BE_MAN_DOWN, 0); bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 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: done:
bgp_stop(p, subcode); bgp_stop(p, subcode, data, len);
return p->p.proto_state; return p->p.proto_state;
} }
@ -1495,6 +1517,20 @@ bgp_channel_start(struct channel *C)
c->next_hop_addr = src; 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 */ /* Exit if no feasible next hop address is found */
if (ipa_zero(c->next_hop_addr)) if (ipa_zero(c->next_hop_addr))
{ {
@ -1523,10 +1559,9 @@ bgp_channel_shutdown(struct channel *C)
{ {
struct bgp_channel *c = (void *) C; struct bgp_channel *c = (void *) C;
/* XXXX: cleanup bucket and prefix tables */
c->next_hop_addr = IPA_NONE; c->next_hop_addr = IPA_NONE;
c->link_addr = IPA_NONE; c->link_addr = IPA_NONE;
c->packets_to_send = 0;
} }
static void static void
@ -1588,6 +1623,7 @@ bgp_postconfig(struct proto_config *CF)
{ {
struct bgp_config *cf = (void *) CF; struct bgp_config *cf = (void *) CF;
int internal = (cf->local_as == cf->remote_as); int internal = (cf->local_as == cf->remote_as);
int interior = internal || cf->confederation_member;
/* Do not check templates at all */ /* Do not check templates at all */
if (cf->c.class == SYM_TEMPLATE) if (cf->c.class == SYM_TEMPLATE)
@ -1598,6 +1634,10 @@ bgp_postconfig(struct proto_config *CF)
if (cf->multihop < 0) if (cf->multihop < 0)
cf->multihop = internal ? 64 : 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) if (!cf->local_as)
cf_error("Local AS number must be set"); cf_error("Local AS number must be set");
@ -1640,6 +1680,20 @@ bgp_postconfig(struct proto_config *CF)
struct bgp_channel_config *cc; struct bgp_channel_config *cc;
WALK_LIST(cc, CF->channels) WALK_LIST(cc, CF->channels)
{ {
/* Handle undefined import filter */
if (cc->c.in_filter == FILTER_UNDEF)
if (interior)
cc->c.in_filter = FILTER_ACCEPT;
else
cf_error("EBGP requires explicit import policy");
/* Handle undefined export filter */
if (cc->c.out_filter == FILTER_UNDEF)
if (interior)
cc->c.out_filter = FILTER_REJECT;
else
cf_error("EBGP requires explicit export policy");
/* Disable after error incompatible with restart limit action */ /* Disable after error incompatible with restart limit action */
if ((cc->c.in_limit.action == PLA_RESTART) && cf->disable_after_error) if ((cc->c.in_limit.action == PLA_RESTART) && cf->disable_after_error)
cc->c.in_limit.action = PLA_DISABLE; cc->c.in_limit.action = PLA_DISABLE;
@ -1796,7 +1850,7 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len)
if (code != 6) if (code != 6)
{ {
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
} }
} }
@ -2017,17 +2071,18 @@ bgp_show_proto_info(struct proto *P)
struct bgp_conn *oc = &p->outgoing_conn; struct bgp_conn *oc = &p->outgoing_conn;
if ((p->start_state < BSS_CONNECT) && if ((p->start_state < BSS_CONNECT) &&
(p->startup_timer->expires)) (tm_active(p->startup_timer)))
cli_msg(-1006, " Error wait: %d/%d", cli_msg(-1006, " Error wait: %t/%u",
p->startup_timer->expires - now, p->startup_delay); tm_remains(p->startup_timer), p->startup_delay);
if ((oc->state == BS_ACTIVE) && if ((oc->state == BS_ACTIVE) &&
(oc->connect_timer->expires)) (tm_active(oc->connect_timer)))
cli_msg(-1006, " Connect delay: %d/%d", cli_msg(-1006, " Connect delay: %t/%u",
oc->connect_timer->expires - now, p->cf->connect_delay_time); tm_remains(oc->connect_timer), p->cf->connect_delay_time);
if (p->gr_active_num && p->gr_timer->expires) if (p->gr_active_num && tm_active(p->gr_timer))
cli_msg(-1006, " Restart timer: %d/-", p->gr_timer->expires - now); cli_msg(-1006, " Restart timer: %t/-",
tm_remains(p->gr_timer));
} }
else if (P->proto_state == PS_UP) else if (P->proto_state == PS_UP)
{ {
@ -2036,21 +2091,16 @@ bgp_show_proto_info(struct proto *P)
bgp_show_capabilities(p, p->conn->local_caps); bgp_show_capabilities(p, p->conn->local_caps);
cli_msg(-1006, " Neighbor capabilities"); cli_msg(-1006, " Neighbor capabilities");
bgp_show_capabilities(p, p->conn->remote_caps); bgp_show_capabilities(p, p->conn->remote_caps);
/* XXXX cli_msg(-1006, " Session: %s%s%s%s%s",
cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s", p->is_internal ? "internal" : "external",
p->is_internal ? "internal" : "external", p->cf->multihop ? " multihop" : "",
p->cf->multihop ? " multihop" : "", p->rr_client ? " route-reflector" : "",
p->rr_client ? " route-reflector" : "", p->rs_client ? " route-server" : "",
p->rs_client ? " route-server" : "", p->as4_session ? " AS4" : "");
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, " Source address: %I", p->source_addr); 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); 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); tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
} }
@ -2063,12 +2113,19 @@ bgp_show_proto_info(struct proto *P)
} }
{ {
/* XXXX ?? */
struct bgp_channel *c; struct bgp_channel *c;
WALK_LIST(c, p->p.channels) WALK_LIST(c, p->p.channels)
{ {
channel_show_info(&c->c); 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) if (c->igp_table_ip4)
cli_msg(-1006, " IGP IPv4 table: %s", c->igp_table_ip4->name); cli_msg(-1006, " IGP IPv4 table: %s", c->igp_table_ip4->name);

View File

@ -108,6 +108,7 @@ struct bgp_config {
int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */ int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */
int gr_mode; /* Graceful restart mode (BGP_GR_*) */ int gr_mode; /* Graceful restart mode (BGP_GR_*) */
int setkey; /* Set MD5 password to system SA/SP database */ int setkey; /* Set MD5 password to system SA/SP database */
/* Times below are in seconds */
unsigned gr_time; /* Graceful restart timeout */ unsigned gr_time; /* Graceful restart timeout */
unsigned connect_delay_time; /* Minimum delay between connect attempts */ unsigned connect_delay_time; /* Minimum delay between connect attempts */
unsigned connect_retry_time; /* Timeout for connect attempts */ unsigned connect_retry_time; /* Timeout for connect attempts */
@ -117,6 +118,7 @@ struct bgp_config {
unsigned error_delay_time_min; /* Time to wait after an error is detected */ unsigned error_delay_time_min; /* Time to wait after an error is detected */
unsigned error_delay_time_max; unsigned error_delay_time_max;
unsigned disable_after_error; /* Disable the protocol when error is detected */ unsigned disable_after_error; /* Disable the protocol when error is detected */
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
char *password; /* Password used for MD5 authentication */ char *password; /* Password used for MD5 authentication */
int check_link; /* Use iface link state for liveness detection */ int check_link; /* Use iface link state for liveness detection */
@ -210,10 +212,10 @@ struct bgp_conn {
struct bgp_caps *local_caps; struct bgp_caps *local_caps;
struct bgp_caps *remote_caps; struct bgp_caps *remote_caps;
struct timer *connect_timer; timer *connect_timer;
struct timer *hold_timer; timer *hold_timer;
struct timer *keepalive_timer; timer *keepalive_timer;
struct event *tx_ev; event *tx_ev;
u32 packets_to_send; /* Bitmap of packet types to be sent */ u32 packets_to_send; /* Bitmap of packet types to be sent */
u32 channels_to_send; /* Bitmap of channels with packets to be sent */ u32 channels_to_send; /* Bitmap of channels with packets to be sent */
u8 last_channel; /* Channel used last time for TX */ u8 last_channel; /* Channel used last time for TX */
@ -254,11 +256,11 @@ struct bgp_proto {
struct bfd_request *bfd_req; /* BFD request, if BFD is used */ 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 source_addr; /* Local address used as an advertised next hop */
ip_addr link_addr; /* Link-local version of source_addr */ ip_addr link_addr; /* Link-local version of source_addr */
struct event *event; /* Event for respawning and shutting process */ event *event; /* Event for respawning and shutting process */
struct timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */ 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 */ timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
unsigned startup_delay; /* Time to delay protocol startup by due to errors */ uint startup_delay; /* Delay (in seconds) of protocol startup due to previous errors */
bird_clock_t last_proto_error; /* Time of last error that leads to protocol stop */ btime last_proto_error; /* Time of last error that leads to protocol stop */
u8 last_error_class; /* Error class of last error */ u8 last_error_class; /* Error class of last error */
u32 last_error_code; /* Error code of last error. BGP protocol errors u32 last_error_code; /* Error code of last error. BGP protocol errors
are encoded as (bgp_err_code << 16 | bgp_err_subcode) */ are encoded as (bgp_err_code << 16 | bgp_err_subcode) */
@ -422,7 +424,7 @@ extern struct linpool *bgp_linpool;
extern struct linpool *bgp_linpool2; 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_check_config(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len); void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c); void bgp_close_conn(struct bgp_conn *c);
@ -436,7 +438,7 @@ void bgp_graceful_restart_done(struct bgp_channel *c);
void bgp_refresh_begin(struct bgp_channel *c); void bgp_refresh_begin(struct bgp_channel *c);
void bgp_refresh_end(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_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_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id); struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
@ -491,11 +493,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); 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_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_free_bucket(struct bgp_channel *c, struct bgp_bucket *b);
void bgp_defer_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_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b);
void bgp_init_prefix_table(struct bgp_channel *c); 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); void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
int bgp_rte_better(struct rte *, struct rte *); int bgp_rte_better(struct rte *, struct rte *);

View File

@ -32,6 +32,12 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
%type <i32> bgp_afi %type <i32> bgp_afi
CF_KEYWORDS(CEASE, PREFIX, LIMIT, HIT, ADMINISTRATIVE, SHUTDOWN, RESET, PEER,
CONFIGURATION, CHANGE, DECONFIGURED, CONNECTION, REJECTED, COLLISION,
OUT, OF, RESOURCES)
%type<i> bgp_cease_mask bgp_cease_list bgp_cease_flag
CF_GRAMMAR CF_GRAMMAR
CF_ADDTO(proto, bgp_proto '}' ) CF_ADDTO(proto, bgp_proto '}' )
@ -58,6 +64,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->gr_mode = BGP_GR_AWARE; BGP_CFG->gr_mode = BGP_GR_AWARE;
BGP_CFG->gr_time = 120; BGP_CFG->gr_time = 120;
BGP_CFG->setkey = 1; BGP_CFG->setkey = 1;
BGP_CFG->check_link = -1;
} }
; ;
@ -73,6 +80,29 @@ bgp_nbr_opts:
| bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; } | bgp_nbr_opts AS expr { BGP_CFG->remote_as = $3; }
; ;
bgp_cease_mask:
/* true -> all except connection collision */
bool { $$ = $1 ? ~(1 << 7) : 0; }
| '{' bgp_cease_list '}' { $$ = $2; }
;
bgp_cease_list:
bgp_cease_flag
| bgp_cease_list ',' bgp_cease_flag { $$ = $1 | $3; }
;
bgp_cease_flag:
CEASE { $$ = 1 << 0; }
| PREFIX LIMIT HIT { $$ = 1 << 1; }
| ADMINISTRATIVE SHUTDOWN { $$ = 1 << 2; }
| PEER DECONFIGURED { $$ = 1 << 3; }
| ADMINISTRATIVE RESET { $$ = 1 << 4; }
| CONNECTION REJECTED { $$ = 1 << 5; }
| CONFIGURATION CHANGE { $$ = 1 << 6; }
| CONNECTION COLLISION { $$ = 1 << 7; }
| OUT OF RESOURCES { $$ = 1 << 8; }
;
bgp_proto: bgp_proto:
bgp_proto_start proto_name '{' bgp_proto_start proto_name '{'
| bgp_proto proto_item ';' | bgp_proto proto_item ';'
@ -116,6 +146,7 @@ bgp_proto:
| bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; } | bgp_proto ERROR FORGET TIME expr ';' { BGP_CFG->error_amnesia_time = $5; }
| bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; } | bgp_proto ERROR WAIT TIME expr ',' expr ';' { BGP_CFG->error_delay_time_min = $5; BGP_CFG->error_delay_time_max = $7; }
| bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; } | bgp_proto DISABLE AFTER ERROR bool ';' { BGP_CFG->disable_after_error = $5; }
| bgp_proto DISABLE AFTER CEASE bgp_cease_mask ';' { BGP_CFG->disable_after_cease = $5; }
| bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; } | bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; } | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; } | bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
@ -157,12 +188,18 @@ bgp_channel_start: bgp_afi
if (!desc) if (!desc)
cf_error("Unknown AFI/SAFI"); cf_error("Unknown AFI/SAFI");
this_channel = channel_config_new(&channel_bgp, desc->net, this_proto); this_channel = channel_config_get(&channel_bgp, desc->name, desc->net, this_proto);
BGP_CC->c.name = desc->name;
BGP_CC->c.ra_mode = RA_UNDEF; /* New channel */
BGP_CC->afi = $1; if (!BGP_CC->desc)
BGP_CC->desc = desc; {
BGP_CC->gr_able = 0xff; /* undefined */ BGP_CC->c.in_filter = FILTER_UNDEF;
BGP_CC->c.out_filter = FILTER_UNDEF;
BGP_CC->c.ra_mode = RA_UNDEF;
BGP_CC->afi = $1;
BGP_CC->desc = desc;
BGP_CC->gr_able = 0xff; /* undefined */
}
}; };
bgp_channel_item: bgp_channel_item:

View File

@ -1483,7 +1483,8 @@ bgp_encode_nlri_vpn6(struct bgp_write_state *s, struct bgp_bucket *buck, byte *b
ADVANCE(pos, size, 1); ADVANCE(pos, size, 1);
/* Encode MPLS labels */ /* 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 */ /* Encode route distinguisher */
put_u64(pos, net->rd); 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]; uint pxlen = data[1];
// FIXME: Use some generic function // FIXME: Use some generic function
memcpy(&px, data, BYTES(pxlen)); memcpy(&px, data+2, BYTES(pxlen));
px = ip4_and(px, ip4_mkmask(pxlen)); px = ip4_and(ip4_ntoh(px), ip4_mkmask(pxlen));
/* Prepare the flow */ /* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen); 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]; uint pxlen = data[1];
// FIXME: Use some generic function // FIXME: Use some generic function
memcpy(&px, data, BYTES(pxlen)); memcpy(&px, data+2, BYTES(pxlen));
px = ip6_and(px, ip6_mkmask(pxlen)); px = ip6_and(ip6_ntoh(px), ip6_mkmask(pxlen));
/* Prepare the flow */ /* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen); net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
@ -2283,6 +2284,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
if (s.attr_len) if (s.attr_len)
ea = bgp_decode_attrs(&s, s.attrs, s.attr_len); ea = bgp_decode_attrs(&s, s.attrs, s.attr_len);
else
ea = NULL;
/* Check for End-of-RIB marker */ /* Check for End-of-RIB marker */
if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len) if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
@ -2678,38 +2681,72 @@ bgp_error_dsc(uint code, uint subcode)
return buff; 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 void
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, uint code, uint subcode, byte *data, uint len) bgp_log_error(struct bgp_proto *p, u8 class, char *msg, uint code, uint subcode, byte *data, uint len)
{ {
const byte *name; byte argbuf[256], *t = argbuf;
byte *t, argbuf[36];
uint i; uint i;
/* Don't report Cease messages generated by myself */ /* Don't report Cease messages generated by myself */
if (code == 6 && class == BE_BGP_TX) if (code == 6 && class == BE_BGP_TX)
return; return;
name = bgp_error_dsc(code, subcode); /* Reset shutdown message */
t = argbuf; if ((code == 6) && ((subcode == 2) || (subcode == 4)))
proto_set_message(&p->p, NULL, 0);
if (len) if (len)
{ {
*t++ = ':'; /* Bad peer AS - we would like to print the AS */
*t++ = ' ';
if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4))) 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; 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) if (len > 16)
len = 16; len = 16;
for (i=0; i<len; i++) for (i=0; i<len; i++)
t += bsprintf(t, "%02x", data[i]); t += bsprintf(t, "%02x", data[i]);
} }
done:
done:
*t = 0; *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 static void
@ -2733,7 +2770,17 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
if (err) if (err)
{ {
bgp_update_startup_delay(p); bgp_update_startup_delay(p);
bgp_stop(p, 0); bgp_stop(p, 0, NULL, 0);
}
else
{
uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0);
if (p->cf->disable_after_cease & subcode_bit)
{
log(L_INFO "%s: Disabled after Cease notification", p->p.name);
p->startup_delay = 0;
p->p.disabled = 1;
}
} }
} }

View File

@ -78,18 +78,66 @@ static void
ospf_proto_finish(void) ospf_proto_finish(void)
{ {
struct ospf_config *cf = OSPF_CFG; struct ospf_config *cf = OSPF_CFG;
struct ospf_area_config *ac;
if (EMPTY_LIST(cf->area_list)) struct ospf_iface_patt *ic;
cf_error( "No configured areas in OSPF");
/* Define default channel */ /* Define default channel */
if (EMPTY_LIST(this_proto->channels)) if (EMPTY_LIST(this_proto->channels))
channel_config_new(NULL, this_proto->net_type, this_proto); {
uint net_type = this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, net_label[net_type], 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 areano = 0;
int backbone = 0; int backbone = 0;
int nssa = 0; int nssa = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list) WALK_LIST(ac, cf->area_list)
{ {
areano++; 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(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY) 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(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 <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 CF_GRAMMAR
@ -166,12 +215,14 @@ ospf_variant:
ospf_proto_start: proto_start ospf_variant ospf_proto_start: proto_start ospf_variant
{ {
this_proto = proto_config_new(&proto_ospf, $1); 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->area_list);
init_list(&OSPF_CFG->vlink_list); init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->ecmp = rt_default_ecmp;
OSPF_CFG->tick = OSPF_DEFAULT_TICK; OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2; OSPF_CFG->ospf2 = $2;
OSPF_CFG->af_ext = !$2;
}; };
ospf_proto: ospf_proto:
@ -179,16 +230,35 @@ ospf_proto:
| ospf_proto ospf_proto_item ';' | 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
{
/* TODO: change name for multicast channels */
$$ = this_channel = channel_config_get(NULL, net_label[$1], $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: ospf_proto_item:
proto_item proto_item
| proto_channel | ospf_channel { this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; } | 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; } | STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; } | ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; } | ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; } | 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"); } | 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 | ospf_area
; ;
@ -293,7 +363,6 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->inftransdelay = INFTRANSDELAY_D; OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->deadc = DEADC_D; OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_VLINK; OSPF_PATT->type = OSPF_IT_VLINK;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list); init_list(&OSPF_PATT->nbma_list);
reset_passwords(); reset_passwords();
} }
@ -393,8 +462,8 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D; OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->deadc = DEADC_D; OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_UNDEF; OSPF_PATT->type = OSPF_IT_UNDEF;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list); init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->check_link = 1;
OSPF_PATT->ptp_netmask = 2; /* not specified */ OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL; OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
OSPF_PATT->tx_priority = sk_priority_control; OSPF_PATT->tx_priority = sk_priority_control;
@ -404,7 +473,7 @@ ospf_iface_start:
ospf_instance_id: ospf_instance_id:
/* empty */ /* 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: ospf_iface_patt_list:
@ -431,7 +500,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_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_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol XXX]]) CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]])
{ ospf_sh(proto_get_named($3, &proto_ospf)); }; { ospf_sh(proto_get_named($3, &proto_ospf)); };
CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]]) CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])

View File

@ -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)", LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu); 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) && (n->rid > p->router_id) &&
(plen == ospf_dbdes_hdrlen(p))) (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); ospf_send_dbdes(p, n);
tm_start(n->dbdes_timer, n->ifa->rxmtint); tm_start(n->dbdes_timer, n->ifa->rxmtint S);
} }
else else
{ {

View File

@ -32,10 +32,7 @@ struct ospf_hello3_packet
struct ospf_packet hdr; struct ospf_packet hdr;
u32 iface_id; u32 iface_id;
u8 priority; u32 options;
u8 options3;
u8 options2;
u8 options;
u16 helloint; u16 helloint;
u16 deadint; u16 deadint;
u32 dr; 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; struct ospf_hello3_packet *ps = (void *) pkt;
ps->iface_id = htonl(ifa->iface_id); ps->iface_id = htonl(ifa->iface_id);
ps->priority = ifa->priority; ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
ps->options3 = ifa->oa->options >> 16;
ps->options2 = ifa->oa->options >> 8;
ps->options = ifa->oa->options;
ps->helloint = ntohs(ifa->helloint); ps->helloint = ntohs(ifa->helloint);
ps->deadint = htons(ifa->deadint); ps->deadint = htons(ifa->deadint);
ps->dr = htonl(ifa->drid); 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; struct ospf_proto *p = ifa->oa->po;
const char *err_dsc = NULL; const char *err_dsc = NULL;
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr; 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 *neighbors;
u32 neigh_count; u32 neigh_count;
uint plen, i, err_val = 0; 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_deadint = ntohs(ps->deadint);
rcv_dr = ntohl(ps->dr); rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr); rcv_bdr = ntohl(ps->bdr);
rcv_options = ps->options; rcv_options = ntohl(ps->options) & 0x00FFFFFF;
rcv_priority = ps->priority; rcv_priority = ntohl(ps->options) >> 24;
neighbors = ps->neighbors; neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32); 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); DROP("dead interval mismatch", rcv_deadint);
/* Check whether bits E, N match */ /* 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); 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 */ /* Check consistency of existing neighbor entry */
if (n) if (n)
{ {

View File

@ -121,6 +121,7 @@ ospf_sk_open(struct ospf_iface *ifa)
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
sk->saddr = ifa->addr->ip; sk->saddr = ifa->addr->ip;
sk->iface = ifa->iface; sk->iface = ifa->iface;
sk->vrf = p->p.vrf;
sk->tos = ifa->cf->tx_tos; sk->tos = ifa->cf->tx_tos;
sk->priority = ifa->cf->tx_priority; sk->priority = ifa->cf->tx_priority;
@ -204,6 +205,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
sk->type = SK_IP; sk->type = SK_IP;
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6; sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
sk->dport = OSPF_PROTO; sk->dport = OSPF_PROTO;
sk->vrf = p->p.vrf;
/* FIXME: configurable tos/priority ? */ /* FIXME: configurable tos/priority ? */
sk->tos = IP_PREC_INTERNET_CONTROL; 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); ospf_iface_chstate(ifa, OSPF_IS_WAITING);
if (ifa->wait_timer) if (ifa->wait_timer)
tm_start(ifa->wait_timer, ifa->waitint); tm_start(ifa->wait_timer, ifa->waitint S);
} }
} }
if (ifa->hello_timer) if (ifa->hello_timer)
tm_start(ifa->hello_timer, ifa->helloint); tm_start(ifa->hello_timer, ifa->helloint S);
if (ifa->poll_timer) 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); ospf_send_hello(ifa, OHS_HELLO, NULL);
} }
@ -494,13 +496,13 @@ ospf_iface_add(struct object_lock *lock)
if (! ifa->stub) 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) 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)) 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_size = ifa_flood_queue_size(ifa);
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *)); 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); 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_size = ifa_flood_queue_size(ifa);
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *)); 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) if (!tm)
return; return;
tm->recurrent = val; tm->recurrent = val S;
if (tm->expires) if (tm_active(tm))
tm_start(tm, val); tm_start(tm, val S);
} }
static inline void static inline void
@ -801,8 +803,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifname, ifa->waitint, new->waitint); ifname, ifa->waitint, new->waitint);
ifa->waitint = new->waitint; ifa->waitint = new->waitint;
if (ifa->wait_timer && ifa->wait_timer->expires) if (ifa->wait_timer && tm_active(ifa->wait_timer))
tm_start(ifa->wait_timer, ifa->waitint); tm_start(ifa->wait_timer, ifa->waitint S);
} }
/* DEAD TIMER */ /* 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; struct ospf_proto *p = (struct ospf_proto *) P;
if (a->prefix.type != NET_IP6)
return;
if (a->flags & IA_SECONDARY) if (a->flags & IA_SECONDARY)
return; return;
@ -1126,6 +1125,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
other addresses are used for link-LSA. */ other addresses are used for link-LSA. */
if (a->scope == SCOPE_LINK) if (a->scope == SCOPE_LINK)
{ {
if (a->prefix.type != NET_IP6)
return;
if (flags & IF_CHANGE_UP) if (flags & IF_CHANGE_UP)
{ {
struct ospf_mip_walk s = { .iface = a->iface }; struct ospf_mip_walk s = { .iface = a->iface };
@ -1143,6 +1145,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
} }
else else
{ {
if (a->prefix.type != ospf_get_af(p))
return;
struct ospf_iface *ifa; struct ospf_iface *ifa;
WALK_LIST(ifa, p->iface_list) WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface) if (ifa->iface == a->iface)

View File

@ -280,7 +280,7 @@ lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
void 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) if (ospf2)
{ {
@ -292,7 +292,7 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopt
else else
{ {
struct ospf_lsa_sum3_net *ls = en->lsa_body; 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; *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 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) if (ospf2)
{ {
@ -338,13 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
else else
{ {
struct ospf_lsa_ext3 *ext = en->lsa_body; 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->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT3_EBIT; rt->ebit = ext->metric & LSA_EXT3_EBIT;
rt->fbit = ext->metric & LSA_EXT3_FBIT; rt->fbit = ext->metric & LSA_EXT3_FBIT;
if (rt->fbit) if (rt->fbit)
buf = ospf_get_ipv6_addr(buf, &rt->fwaddr); buf = ospf3_get_addr(buf, af, &rt->fwaddr);
else else
rt->fwaddr = IPA_NONE; rt->fwaddr = IPA_NONE;

View File

@ -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); 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); 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); 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_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); 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_ */ #endif /* _BIRD_OSPF_LSALIB_H_ */

Some files were not shown because too many files have changed in this diff Show More