0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 17:51:53 +00:00

Merge branch 'int-new' into bash-completion

This commit is contained in:
Jan Maria Matejka 2017-12-13 16:46:58 +01:00
commit b7e2e8bc41
122 changed files with 5224 additions and 3410 deletions

1
.gitignore vendored
View File

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

315
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,315 @@
variables:
DEBIAN_FRONTEND: noninteractive
LC_ALL: C
GIT_STRATEGY: fetch
DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/"
IMG_BASE: registry.labs.nic.cz/labs/bird
stages:
- image
- build
.docker: &docker_build
stage: image
allow_failure: true
script:
- $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz
# Make sure we refresh the base image if it updates (eg. security updates, etc)
# If we do just the build, cache is always reused and the freshness of the
# base image is never checked. However, pull always asks and updates the
# image only if it changed therefore, the cache is used unless there's a
# change.
- $DOCKER_CMD pull `sed -ne 's/^FROM //p' "misc/docker/$IMG_NAME/Dockerfile"`
- $DOCKER_CMD build -t "bird:$IMG_NAME" "misc/docker/$IMG_NAME"
- $DOCKER_CMD tag "bird:$IMG_NAME" "$IMG_BASE:$IMG_NAME"
- $DOCKER_CMD push "$IMG_BASE:$IMG_NAME"
after_script:
- rm -f "$HOME/.docker/$CI_JOB_ID/" # cleanup the credentials
tags:
# That's Docker in Docker
- dind
docker_debian-7-amd64:
variables:
IMG_NAME: "debian-7-amd64"
<<: *docker_build
docker_debian-8-amd64:
variables:
IMG_NAME: "debian-8-amd64"
<<: *docker_build
docker_debian-9-amd64:
variables:
IMG_NAME: "debian-9-amd64"
<<: *docker_build
docker_debian-testing-amd64:
variables:
IMG_NAME: "debian-testing-amd64"
<<: *docker_build
docker_debian-7-i386:
variables:
IMG_NAME: "debian-7-i386"
<<: *docker_build
docker_debian-8-i386:
variables:
IMG_NAME: "debian-8-i386"
<<: *docker_build
docker_debian-9-i386:
variables:
IMG_NAME: "debian-9-i386"
<<: *docker_build
docker_debian-testing-i386:
variables:
IMG_NAME: "debian-testing-i386"
<<: *docker_build
docker_fedora-25-amd64:
variables:
IMG_NAME: "fedora-25-amd64"
<<: *docker_build
docker_fedora-26-amd64:
variables:
IMG_NAME: "fedora-26-amd64"
<<: *docker_build
docker_centos-6-amd64:
variables:
IMG_NAME: "centos-6-amd64"
<<: *docker_build
docker_centos-7-amd64:
variables:
IMG_NAME: "centos-7-amd64"
<<: *docker_build
docker_opensuse-42_3-amd64:
variables:
IMG_NAME: "opensuse-42.3-amd64"
<<: *docker_build
docker_ubuntu-14_04-amd64:
variables:
IMG_NAME: "ubuntu-14.04-amd64"
<<: *docker_build
docker_ubuntu-16_04-amd64:
variables:
IMG_NAME: "ubuntu-16.04-amd64"
<<: *docker_build
.debian-7-i386: &debian-7-i386_env
image: registry.labs.nic.cz/labs/bird:debian-7-i386
tags:
- docker
- linux
- amd64
.debian-8-i386: &debian-8-i386_env
image: registry.labs.nic.cz/labs/bird:debian-8-i386
tags:
- docker
- linux
- amd64
.debian-9-i386: &debian-9-i386_env
image: registry.labs.nic.cz/labs/bird:debian-9-i386
tags:
- docker
- linux
- amd64
.debian-testing-i386: &debian-testing-i386_env
image: registry.labs.nic.cz/labs/bird:debian-testing-i386
tags:
- docker
- linux
- amd64
.debian-7-amd64: &debian-7-amd64_env
image: registry.labs.nic.cz/labs/bird:debian-7-amd64
tags:
- docker
- linux
- amd64
.debian-8-amd64: &debian-8-amd64_env
image: registry.labs.nic.cz/labs/bird:debian-8-amd64
tags:
- docker
- linux
- amd64
.debian-9-amd64: &debian-9-amd64_env
image: registry.labs.nic.cz/labs/bird:debian-9-amd64
tags:
- docker
- linux
- amd64
.debian-testing-amd64: &debian-testing-amd64_env
image: registry.labs.nic.cz/labs/bird:debian-testing-amd64
tags:
- docker
- linux
- amd64
.fedora-25-amd64: &fedora-25-amd64_env
image: registry.labs.nic.cz/labs/bird:fedora-25-amd64
tags:
- docker
- linux
- amd64
.fedora-26-amd64: &fedora-26-amd64_env
image: registry.labs.nic.cz/labs/bird:fedora-26-amd64
tags:
- docker
- linux
- amd64
.centos-6-amd64: &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
variables:
CPPFLAGS: "-I/usr/local/include"
LDFLAGS: "-L/usr/local/lib"
tags:
- freebsd
- i386
#only:
#- master
#- triggers
#- tags
.freebsd-11-amd64: &freebsd-11-amd64_env
variables:
CPPFLAGS: "-I/usr/local/include"
LDFLAGS: "-L/usr/local/lib"
tags:
- freebsd
- amd64
#only:
#- master
#- triggers
#- tags
.build: &build_job
stage: build
script:
- autoreconf
- ./configure CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS"
# Detect which make is available
- MAKE=make
- which gmake 2>/dev/null >/dev/null && MAKE=gmake
- $MAKE
# Run tests if they are available
- $MAKE check
build-debian-7-amd64:
<<: *debian-7-amd64_env
<<: *build_job
build-debian-8-amd64:
<<: *debian-8-amd64_env
<<: *build_job
build-debian-9-amd64:
<<: *debian-9-amd64_env
<<: *build_job
build-debian-testing-amd64:
<<: *debian-testing-amd64_env
<<: *build_job
build-fedora-25-amd64:
<<: *fedora-25-amd64_env
<<: *build_job
build-fedora-26-amd64:
<<: *fedora-26-amd64_env
<<: *build_job
build-centos-6-amd64:
<<: *centos-6-amd64_env
<<: *build_job
build-centos-7-amd64:
<<: *centos-7-amd64_env
<<: *build_job
build-opensuse-42_3-amd64:
<<: *opensuse-42_3-amd64_env
<<: *build_job
build-ubuntu-14_04-amd64:
<<: *ubuntu-14_04-amd64_env
<<: *build_job
build-ubuntu-16_04-amd64:
<<: *ubuntu-16_04-amd64_env
<<: *build_job
build-debian-7-i386:
<<: *debian-7-i386_env
<<: *build_job
build-debian-8-i386:
<<: *debian-8-i386_env
<<: *build_job
build-debian-9-i386:
<<: *debian-9-i386_env
<<: *build_job
build-debian-testing-i386:
<<: *debian-testing-i386_env
<<: *build_job
build-freebsd-11-amd64:
<<: *freebsd-11-amd64_env
<<: *build_job
build-freebsd-11-i386:
<<: *freebsd-11-i386_env
<<: *build_job

57
NEWS
View File

@ -1,45 +1,46 @@
Version 2.0.0-pre1 (2017-04-29) Version 2.0.0 (2017-12-11)
o Integrated IPv4 + IPv6 design
o Support for MPLS next hops o 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

@ -52,6 +52,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);
@ -453,7 +448,7 @@ extern void cmd_reconfig_undo_notify(void);
extern void cmd_reconfig_msg(int r); extern void cmd_reconfig_msg(int r);
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"
@ -60,7 +60,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;
@ -80,11 +80,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_mpls_
%type <mls> label_stack_start label_stack %type <mls> label_stack_start label_stack
%type <t> text opttext %type <t> text opttext
@ -97,7 +96,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)
CF_GRAMMAR CF_GRAMMAR
@ -137,9 +136,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 */
@ -235,6 +234,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_ ;
@ -244,6 +249,7 @@ net_:
| net_vpn_ | net_vpn_
| net_roa_ | net_roa_
| net_flow_ | net_flow_
| net_mpls_
; ;
@ -308,11 +314,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@:>@])],
[], [],
@ -239,6 +245,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 +307,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 +322,7 @@ if test "$enable_debug" = yes ; then
[ [
AC_DEFINE([HAVE_EXECINFO_H], [1], [Define to 1 if you have the <execinfo.h> header file.]) AC_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.])]
) )
] ]
@ -396,6 +404,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

File diff suppressed because it is too large Load Diff

View File

@ -112,7 +112,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;
@ -421,7 +421,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
@ -763,25 +763,18 @@ 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(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; } | TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }

View File

@ -1089,7 +1089,8 @@ 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:
if (v1.type != T_INT) // Enums are also ints, so allow them in.
if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
runtime( "Setting int attribute to non-int value" ); 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;

View File

@ -147,6 +147,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 */

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

@ -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 */

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

@ -91,7 +91,7 @@ const byte *flow6_next_part(const byte *pos, const byte *end);
/* A data structure for keep a state of flow builder */ /* 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,49 @@ 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;
xfree(c);
}
}
static void static void
lp_free(resource *r) lp_free(resource *r)
{ {

View File

@ -288,3 +288,21 @@ net_in_netX(const net_addr *a, const net_addr *n)
return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n); return (net_pxlen(n) <= net_pxlen(a)) && ipa_in_netX(net_prefix(a), n);
} }
#define CHECK_NET(T,S) \
({ if (sizeof(T) != S) die("sizeof %s is %d/%d", #T, (int) sizeof(T), S); })
void
net_init(void)
{
CHECK_NET(net_addr, 24);
CHECK_NET(net_addr_ip4, 8);
CHECK_NET(net_addr_ip6, 20);
CHECK_NET(net_addr_vpn4, 16);
CHECK_NET(net_addr_vpn6, 32);
CHECK_NET(net_addr_roa4, 16);
CHECK_NET(net_addr_roa6, 28);
CHECK_NET(net_addr_flow4, 8);
CHECK_NET(net_addr_flow6, 20);
CHECK_NET(net_addr_mpls, 8);
}

View File

@ -45,7 +45,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 +76,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;
@ -152,7 +153,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 })
@ -230,11 +231,14 @@ static inline int net_type_match(const net_addr *a, u32 mask)
static inline int net_is_ip(const net_addr *a) 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)
@ -354,10 +358,10 @@ static inline int net_zero_roa6(const net_addr_roa6 *a)
{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; } { 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; }
@ -526,8 +530,21 @@ 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_net_ip4(ip4_addr a, const net_addr_ip4 *n)
{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); }
static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); }
static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); }
static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); }
int ipa_in_netX(const ip_addr A, const net_addr *N); int 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

@ -125,9 +125,10 @@ static char * number(char * str, long num, int base, int size, int precision,
* or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for * 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.
@ -139,6 +140,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];
@ -279,7 +282,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 *);
@ -360,6 +362,50 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
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;
@ -401,6 +447,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
str = number(str, num, base, field_width, precision, flags, size); 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;
}
} }

377
lib/timer.c Normal file
View File

@ -0,0 +1,377 @@
/*
* BIRD -- Timers
*
* (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2013--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Timers
*
* Timers are resources which represent a wish of a module to call a function at
* the specified time. The timer code does not guarantee exact timing, only that
* a timer function will not be called before the requested time.
*
* In BIRD, time is represented by values of the &btime type which is signed
* 64-bit integer interpreted as a relative number of microseconds since some
* fixed time point in past. The current time can be obtained by current_time()
* function with reasonable accuracy and is monotonic. There is also a current
* 'wall-clock' real time obtainable by current_real_time() reported by OS.
*
* Each timer is described by a &timer structure containing a pointer to the
* handler function (@hook), data private to this function (@data), time the
* function should be called at (@expires, 0 for inactive timers), for the other
* fields see |timer.h|.
*/
#include <stdio.h>
#include <stdlib.h>
#include "nest/bird.h"
#include "lib/heap.h"
#include "lib/resource.h"
#include "lib/timer.h"
struct timeloop main_timeloop;
#ifdef USE_PTHREADS
#include <pthread.h>
/* Data accessed and modified from proto/bfd/io.c */
pthread_key_t current_time_key;
static inline struct timeloop *
timeloop_current(void)
{
return pthread_getspecific(current_time_key);
}
static inline void
timeloop_init_current(void)
{
pthread_key_create(&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

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

@ -27,12 +27,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,14 +65,15 @@ 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)
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)
CF_KEYWORDS(REFRESH) CF_KEYWORDS(REFRESH)
@ -124,24 +125,6 @@ idval:
} }
; ;
CF_ADDTO(conf, listen)
listen: LISTEN BGP listen_opts ';' ;
listen_opts:
/* Nothing */
| listen_opts listen_opt
;
listen_opt:
ADDRESS ipa { new_config->listen_bgp_addr = $2; }
| PORT expr { new_config->listen_bgp_port = $2; }
| V6ONLY { new_config->listen_bgp_flags = 0; }
| DUAL { new_config->listen_bgp_flags = 1; }
;
CF_ADDTO(conf, gr_opts) 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; } ;
@ -158,6 +141,7 @@ net_type:
| 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)
@ -225,6 +209,7 @@ 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); }
; ;
@ -296,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:
@ -305,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:
@ -463,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; }
; ;
@ -747,12 +758,12 @@ echo_size:
} }
; ;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ; { proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ; { proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL) CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)

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" : "");
} }
/** /**
@ -116,7 +120,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 +137,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 +182,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 +192,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,10 +221,7 @@ if_notify_change(unsigned c, struct iface *i)
neigh_if_down(i); neigh_if_down(i);
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);
}
cli_notify_all_clients(); cli_notify_all_clients();
} }
@ -224,10 +232,7 @@ if_notify_change(unsigned c, struct iface *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);
}
neigh_if_up(i); neigh_if_up(i);
cli_notify_all_clients(); cli_notify_all_clients();
@ -237,24 +242,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);
} }
@ -302,7 +308,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 */
@ -310,10 +315,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;
} }
@ -344,13 +352,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);
} }
@ -368,7 +379,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);
} }
@ -465,40 +476,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
@ -530,7 +600,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);
@ -538,15 +608,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;
} }
@ -569,16 +639,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;
} }
@ -745,16 +823,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
@ -769,7 +848,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
@ -783,10 +868,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, "");
@ -796,16 +884,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

@ -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,8 +154,9 @@ 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

@ -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)
{ {
@ -672,7 +673,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 +821,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* If there is a too big change in core attributes, ... */ /* If 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 +980,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 +1050,7 @@ proto_rethink_goal(struct proto *p)
* *
*/ */
static void graceful_restart_done(struct timer *t); static void graceful_restart_done(timer *t);
/** /**
* graceful_restart_recovery - request initial graceful restart recovery * graceful_restart_recovery - request initial graceful restart recovery
@ -1083,9 +1087,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 +1102,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 +1139,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 +1301,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 +1332,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 +1536,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 +1656,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 +1681,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 +1702,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 +1713,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 +1729,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 +1746,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 +1754,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 +1793,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 +1818,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 +1834,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
@ -508,7 +511,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 */
}; };

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;
@ -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;
@ -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)

View File

@ -33,7 +33,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
struct channel *c; struct channel *c;
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;

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
@ -195,6 +213,7 @@ fib_hash(struct fib *f, const net_addr *a)
case NET_ROA6: return FIB_HASH(f, a, roa6); case NET_ROA6: return FIB_HASH(f, a, roa6);
case NET_FLOW4: return FIB_HASH(f, a, flow4); case NET_FLOW4: return FIB_HASH(f, a, flow4);
case NET_FLOW6: return FIB_HASH(f, a, flow6); case NET_FLOW6: return FIB_HASH(f, a, flow6);
case NET_MPLS: return FIB_HASH(f, a, mpls);
default: bug("invalid type"); default: bug("invalid type");
} }
} }
@ -231,6 +250,7 @@ fib_find(struct fib *f, const net_addr *a)
case NET_ROA6: return FIB_FIND(f, a, roa6); case NET_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_MPLS: return FIB_FIND(f, a, mpls);
default: bug("invalid type"); default: bug("invalid type");
} }
} }
@ -250,6 +270,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
case NET_ROA6: FIB_INSERT(f, a, e, roa6); return; case NET_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_MPLS: FIB_INSERT(f, a, e, mpls); return;
default: bug("invalid type"); default: bug("invalid type");
} }
} }

View File

@ -39,7 +39,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs); void (*get_route_info)(struct rte *, byte *buf, struct ea_list *attrs);
struct nexthop *nh; struct nexthop *nh;
tm_format_datetime(tm, &config->tf_route, e->lastmod); tm_format_time(tm, &config->tf_route, e->lastmod);
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw)) 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
@ -63,7 +63,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
if (d->last_table != d->tab) 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", ia, rta_dest_name(a->dest), cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info); a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (a->dest == RTD_UNICAST) if (a->dest == RTD_UNICAST)
@ -71,6 +71,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
{ {
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls; char 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)
{ {
@ -81,11 +82,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)

View File

@ -897,7 +897,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 +1175,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 +1203,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)
@ -1497,7 +1499,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);
@ -1609,7 +1611,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
t->rt_event = ev_new(p); t->rt_event = ev_new(p);
t->rt_event->hook = rt_event; t->rt_event->hook = rt_event;
t->rt_event->data = t; t->rt_event->data = t;
t->gc_time = now; t->gc_time = current_time();
} }
} }
@ -1708,7 +1710,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;

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)
@ -102,8 +107,8 @@ 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) */
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */ uint hold_time; /* Time to hold stale entries and unreachable routes */
}; };
struct babel_iface_config { struct babel_iface_config {
@ -111,11 +116,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 +144,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 +177,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 +191,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 +213,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 +222,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 +271,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 +283,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 +291,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,7 +299,7 @@ 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;
@ -334,6 +353,7 @@ void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_show_interfaces(struct proto *P, char *iff); void babel_show_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.
*/ */
@ -32,6 +34,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 +59,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 +87,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 +136,9 @@ CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]]) 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;
@ -104,8 +106,12 @@ struct babel_tlv_seqno_request {
} PACKED; } PACKED;
#define BABEL_FLAG_DEF_PREFIX 0x80 /* Hello flags */
#define BABEL_FLAG_ROUTER_ID 0x40 #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 {
@ -162,17 +168,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
@ -341,6 +347,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 +604,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 +615,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 +640,13 @@ 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 (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 +759,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;
@ -1294,7 +1305,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 +1340,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
*/ */
@ -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;
@ -1175,6 +1173,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,14 @@
* <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
* </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"
@ -312,20 +315,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 +385,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 +404,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 +420,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 +460,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 +602,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 +661,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,6 +680,13 @@ 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;
} }
proto_notify_state(&p->p, PS_START); proto_notify_state(&p->p, PS_START);
@ -722,7 +733,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 +896,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 +947,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 +1106,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 +1133,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 +1144,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 +1169,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 +1312,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 +1323,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 +1340,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 +1357,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 +1377,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 +1407,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 +1512,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 +1554,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
@ -1598,6 +1628,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");
@ -1796,7 +1830,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 +2051,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 +2071,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 +2093,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 */
@ -210,10 +211,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 +255,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 +423,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 +437,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 +492,13 @@ int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len); 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

@ -58,6 +58,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;
} }
; ;

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);
@ -2678,38 +2679,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 +2768,7 @@ 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);
} }
} }

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))
{
this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, this_proto->net_type, this_proto); channel_config_new(NULL, this_proto->net_type, this_proto);
}
/* Propagate global instance ID to interfaces */
if (cf->instance_id_set)
{
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
WALK_LIST(ic, cf->vlink_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
}
if (ospf_cfg_is_v3())
{
uint ipv4 = (this_proto->net_type == NET_IP4);
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
/* RFC 5838 - OSPFv3-AF */
if (cf->af_ext)
{
/* RFC 5838 2.1 - instance IDs based on AFs */
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
{
if (!ic->instance_id_set)
ic->instance_id = base;
else if (ic->instance_id >= 128)
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
}
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
}
else
{
if (ipv4 || cf->af_mc)
cf_error("Different channel type");
}
}
if (EMPTY_LIST(cf->area_list))
cf_error("No configured areas in OSPF");
int areano = 0; int 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,34 @@ 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
{
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
/* Save the multicast flag */
if (this_channel == proto_cf_main_channel(this_proto))
OSPF_CFG->af_mc = $2;
};
ospf_channel: ospf_channel_start channel_opt_list channel_end;
ospf_proto_item: 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 +362,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 +461,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 +472,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 +499,7 @@ CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEM
CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); }) CF_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]], CLI_SF_PROTOCOL) CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]], CLI_SF_PROTOCOL)
{ ospf_sh(proto_get_named($3, &proto_ospf)); }; { ospf_sh(proto_get_named($3, &proto_ospf)); };
CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER) CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER)

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_ */

View File

@ -137,7 +137,7 @@ ospf_lsa_lsrt_up(struct top_hash_entry *en, struct ospf_neighbor *n)
ret->lsa_body = LSA_BODY_DUMMY; ret->lsa_body = LSA_BODY_DUMMY;
if (!tm_active(n->lsrt_timer)) if (!tm_active(n->lsrt_timer))
tm_start(n->lsrt_timer, n->ifa->rxmtint); tm_start(n->lsrt_timer, n->ifa->rxmtint S);
} }
void void
@ -572,7 +572,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
{ {
/* 13. (5a) - enforce minimum time between updates for received LSAs */ /* 13. (5a) - enforce minimum time between updates for received LSAs */
/* We also use this to ratelimit reactions to received self-originated LSAs */ /* We also use this to ratelimit reactions to received self-originated LSAs */
if (en && ((now - en->inst_time) < MINLSARRIVAL)) if (en && (lsa_inst_age(en) < MINLSARRIVAL))
{ {
OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival"); OSPF_TRACE(D_EVENTS, "Skipping LSA received in less that MinLSArrival");
continue; continue;
@ -700,7 +700,7 @@ ospf_receive_lsupd(struct ospf_packet *pkt, struct ospf_iface *ifa,
if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql))) if (!EMPTY_SLIST(n->lsrql) && (n->lsrqi == SHEAD(n->lsrql)))
{ {
ospf_send_lsreq(p, n); ospf_send_lsreq(p, n);
tm_start(n->lsrq_timer, n->ifa->rxmtint); tm_start(n->lsrq_timer, n->ifa->rxmtint S);
} }
return; return;

View File

@ -94,11 +94,11 @@ ospf_neighbor_new(struct ospf_iface *ifa)
init_list(&n->ackl[ACKL_DIRECT]); init_list(&n->ackl[ACKL_DIRECT]);
init_list(&n->ackl[ACKL_DELAY]); init_list(&n->ackl[ACKL_DELAY]);
n->inactim = tm_new_set(pool, inactivity_timer_hook, n, 0, 0); n->inactim = tm_new_init(pool, inactivity_timer_hook, n, 0, 0);
n->dbdes_timer = tm_new_set(pool, dbdes_timer_hook, n, 0, ifa->rxmtint); n->dbdes_timer = tm_new_init(pool, dbdes_timer_hook, n, ifa->rxmtint S, 0);
n->lsrq_timer = tm_new_set(pool, lsrq_timer_hook, n, 0, ifa->rxmtint); n->lsrq_timer = tm_new_init(pool, lsrq_timer_hook, n, ifa->rxmtint S, 0);
n->lsrt_timer = tm_new_set(pool, lsrt_timer_hook, n, 0, ifa->rxmtint); n->lsrt_timer = tm_new_init(pool, lsrt_timer_hook, n, ifa->rxmtint S, 0);
n->ackd_timer = tm_new_set(pool, ackd_timer_hook, n, 0, ifa->rxmtint / 2); n->ackd_timer = tm_new_init(pool, ackd_timer_hook, n, ifa->rxmtint S / 2, 0);
return (n); return (n);
} }
@ -186,7 +186,7 @@ ospf_neigh_chstate(struct ospf_neighbor *n, u8 state)
n->myimms = DBDES_IMMS; n->myimms = DBDES_IMMS;
tm_start(n->dbdes_timer, 0); tm_start(n->dbdes_timer, 0);
tm_start(n->ackd_timer, ifa->rxmtint / 2); tm_start(n->ackd_timer, ifa->rxmtint S / 2);
} }
if (state > NEIGHBOR_EXSTART) if (state > NEIGHBOR_EXSTART)
@ -231,7 +231,7 @@ ospf_neigh_sm(struct ospf_neighbor *n, int event)
ospf_neigh_chstate(n, NEIGHBOR_INIT); ospf_neigh_chstate(n, NEIGHBOR_INIT);
/* Restart inactivity timer */ /* Restart inactivity timer */
tm_start(n->inactim, n->ifa->deadint); tm_start(n->inactim, n->ifa->deadint S);
break; break;
case INM_2WAYREC: case INM_2WAYREC:
@ -651,20 +651,6 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
{ {
struct ospf_iface *ifa = n->ifa; struct ospf_iface *ifa = n->ifa;
char *pos = "PtP "; char *pos = "PtP ";
char etime[6];
int exp, sec, min;
exp = n->inactim->expires - now;
sec = exp % 60;
min = exp / 60;
if (min > 59)
{
bsprintf(etime, "-Inf-");
}
else
{
bsprintf(etime, "%02u:%02u", min, sec);
}
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA)) if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
{ {
@ -676,6 +662,7 @@ ospf_sh_neigh_info(struct ospf_neighbor *n)
pos = "Other"; pos = "Other";
} }
cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%-5s\t%-10s %-1I", n->rid, n->priority, cli_msg(-1013, "%-1R\t%3u\t%s/%s\t%7t\t%-10s %-1I",
ospf_ns_names[n->state], pos, etime, ifa->ifname, n->ip); n->rid, n->priority, ospf_ns_names[n->state], pos,
tm_remains(n->inactim), ifa->ifname, n->ip);
} }

View File

@ -92,8 +92,10 @@
* - RFC 2328 - main OSPFv2 standard * - RFC 2328 - main OSPFv2 standard
* - RFC 5340 - main OSPFv3 standard * - RFC 5340 - main OSPFv3 standard
* - RFC 3101 - OSPFv2 NSSA areas * - RFC 3101 - OSPFv2 NSSA areas
* - RFC 6549 - OSPFv2 multi-instance extensions * - RFC 5709 - OSPFv2 HMAC-SHA Cryptographic Authentication
* - RFC 6987 - OSPF stub router advertisement * - RFC 5838 - OSPFv3 Support of Address Families
* - RFC 6549 - OSPFv2 Multi-Instance Extensions
* - RFC 6987 - OSPF Stub Router Advertisement
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -115,9 +117,9 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
struct area_net_config *anc; struct area_net_config *anc;
struct area_net *an; struct area_net *an;
fib_init(&oa->net_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6, fib_init(&oa->net_fib, p->p.pool, ospf_get_af(p),
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL); sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
fib_init(&oa->enet_fib, p->p.pool, ospf_is_v2(p) ? NET_IP4 : NET_IP6, fib_init(&oa->enet_fib, p->p.pool, ospf_get_af(p),
sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL); sizeof(struct area_net), OFFSETOF(struct area_net, fn), 0, NULL);
WALK_LIST(anc, ac->net_list) WALK_LIST(anc, ac->net_list)
@ -134,6 +136,16 @@ add_area_nets(struct ospf_area *oa, struct ospf_area_config *ac)
} }
} }
static inline uint
ospf_opts(struct ospf_proto *p)
{
if (ospf_is_v2(p))
return 0;
return ((ospf_is_ip6(p) && !p->af_mc) ? OPT_V6 : 0) |
(!p->stub_router ? OPT_R : 0) | (p->af_ext ? OPT_AF : 0);
}
static void static void
ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac) ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
{ {
@ -155,10 +167,7 @@ ospf_area_add(struct ospf_proto *p, struct ospf_area_config *ac)
if (oa->areaid == 0) if (oa->areaid == 0)
p->backbone = oa; p->backbone = oa;
if (ospf_is_v2(p)) oa->options = ac->type | ospf_opts(p);
oa->options = ac->type;
else
oa->options = ac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
ospf_notify_rt_lsa(oa); ospf_notify_rt_lsa(oa);
} }
@ -224,22 +233,23 @@ ospf_start(struct proto *P)
p->router_id = proto_get_router_id(P->cf); p->router_id = proto_get_router_id(P->cf);
p->ospf2 = c->ospf2; p->ospf2 = c->ospf2;
p->af_ext = c->af_ext;
p->af_mc = c->af_mc;
p->rfc1583 = c->rfc1583; p->rfc1583 = c->rfc1583;
p->stub_router = c->stub_router; p->stub_router = c->stub_router;
p->merge_external = c->merge_external; p->merge_external = c->merge_external;
p->asbr = c->asbr; p->asbr = c->asbr;
p->ecmp = c->ecmp; p->ecmp = c->ecmp;
p->tick = c->tick; p->tick = c->tick;
p->disp_timer = tm_new_set(P->pool, ospf_disp, p, 0, p->tick); p->disp_timer = tm_new_init(P->pool, ospf_disp, p, p->tick S, 0);
tm_start(p->disp_timer, 1); tm_start(p->disp_timer, 100 MS);
p->lsab_size = 256; p->lsab_size = 256;
p->lsab_used = 0; p->lsab_used = 0;
p->lsab = mb_alloc(P->pool, p->lsab_size); p->lsab = mb_alloc(P->pool, p->lsab_size);
p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop)); p->nhpool = lp_new(P->pool, 12*sizeof(struct nexthop));
init_list(&(p->iface_list)); init_list(&(p->iface_list));
init_list(&(p->area_list)); init_list(&(p->area_list));
fib_init(&p->rtf, P->pool, p->ospf2 ? NET_IP4 : NET_IP6, fib_init(&p->rtf, P->pool, ospf_get_af(p), sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
sizeof(ort), OFFSETOF(ort, fn), 0, NULL);
if (ospf_is_v3(p)) if (ospf_is_v3(p))
idm_init(&p->idm, P->pool, 16); idm_init(&p->idm, P->pool, 16);
p->areano = 0; p->areano = 0;
@ -601,11 +611,7 @@ ospf_area_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
struct ospf_iface *ifa; struct ospf_iface *ifa;
oa->ac = nac; oa->ac = nac;
oa->options = nac->type | ospf_opts(p);
if (ospf_is_v2(p))
oa->options = nac->type;
else
oa->options = nac->type | OPT_V6 | (p->stub_router ? 0 : OPT_R);
if (nac->type != oac->type) if (nac->type != oac->type)
{ {
@ -659,6 +665,9 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
if (old->abr != new->abr) if (old->abr != new->abr)
return 0; return 0;
if ((p->af_ext != new->af_ext) || (p->af_mc != new->af_mc))
return 0;
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
return 0; return 0;
@ -667,8 +676,8 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
p->asbr = new->asbr; p->asbr = new->asbr;
p->ecmp = new->ecmp; p->ecmp = new->ecmp;
p->tick = new->tick; p->tick = new->tick;
p->disp_timer->recurrent = p->tick; p->disp_timer->recurrent = p->tick S;
tm_start(p->disp_timer, 1); tm_start(p->disp_timer, 100 MS);
/* Mark all areas and ifaces */ /* Mark all areas and ifaces */
WALK_LIST(oa, p->area_list) WALK_LIST(oa, p->area_list)
@ -1073,13 +1082,13 @@ show_lsa_network(struct top_hash_entry *he, int ospf2)
} }
static inline void static inline void
show_lsa_sum_net(struct top_hash_entry *he, int ospf2) show_lsa_sum_net(struct top_hash_entry *he, int ospf2, int af)
{ {
net_addr net; net_addr net;
u8 pxopts; u8 pxopts;
u32 metric; u32 metric;
lsa_parse_sum_net(he, ospf2, &net, &pxopts, &metric); lsa_parse_sum_net(he, ospf2, af, &net, &pxopts, &metric);
cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric); cli_msg(-1016, "\t\txnetwork %N metric %u", &net, metric);
} }
@ -1096,7 +1105,7 @@ show_lsa_sum_rt(struct top_hash_entry *he, int ospf2)
static inline void static inline void
show_lsa_external(struct top_hash_entry *he, int ospf2) show_lsa_external(struct top_hash_entry *he, int ospf2, int af)
{ {
struct ospf_lsa_ext_local rt; struct ospf_lsa_ext_local rt;
char str_via[IPA_MAX_TEXT_LENGTH + 8] = ""; char str_via[IPA_MAX_TEXT_LENGTH + 8] = "";
@ -1105,7 +1114,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
if (he->lsa_type == LSA_T_EXT) if (he->lsa_type == LSA_T_EXT)
he->domain = 0; /* Unmark the LSA */ he->domain = 0; /* Unmark the LSA */
lsa_parse_ext(he, ospf2, &rt); lsa_parse_ext(he, ospf2, af, &rt);
if (rt.fbit) if (rt.fbit)
bsprintf(str_via, " via %I", rt.fwaddr); bsprintf(str_via, " via %I", rt.fwaddr);
@ -1119,7 +1128,7 @@ show_lsa_external(struct top_hash_entry *he, int ospf2)
} }
static inline void static inline void
show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode) show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode, int af)
{ {
struct ospf_lsa_prefix *px = he->lsa_body; struct ospf_lsa_prefix *px = he->lsa_body;
u32 *buf; u32 *buf;
@ -1142,7 +1151,7 @@ show_lsa_prefix(struct top_hash_entry *he, struct top_hash_entry *cnode)
u8 pxopts; u8 pxopts;
u16 metric; u16 metric;
buf = ospf_get_ipv6_prefix(buf, &net, &pxopts, &metric); buf = ospf3_get_prefix(buf, af, &net, &pxopts, &metric);
if (px->ref_type == LSA_T_RT) if (px->ref_type == LSA_T_RT)
cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric); cli_msg(-1016, "\t\tstubnet %N metric %u", &net, metric);
@ -1156,6 +1165,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
{ {
struct ospf_proto *p = (struct ospf_proto *) P; struct ospf_proto *p = (struct ospf_proto *) P;
int ospf2 = ospf_is_v2(p); int ospf2 = ospf_is_v2(p);
int af = ospf_get_af(p);
uint i, ix, j1, jx; uint i, ix, j1, jx;
u32 last_area = 0xFFFFFFFF; u32 last_area = 0xFFFFFFFF;
@ -1276,7 +1286,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_SUM_NET: case LSA_T_SUM_NET:
if (cnode->lsa_type == LSA_T_RT) if (cnode->lsa_type == LSA_T_RT)
show_lsa_sum_net(he, ospf2); show_lsa_sum_net(he, ospf2, af);
break; break;
case LSA_T_SUM_RT: case LSA_T_SUM_RT:
@ -1286,11 +1296,11 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
case LSA_T_EXT: case LSA_T_EXT:
case LSA_T_NSSA: case LSA_T_NSSA:
show_lsa_external(he, ospf2); show_lsa_external(he, ospf2, af);
break; break;
case LSA_T_PREFIX: case LSA_T_PREFIX:
show_lsa_prefix(he, cnode); show_lsa_prefix(he, cnode, af);
break; break;
} }
@ -1304,7 +1314,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
ix++; ix++;
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt)) while ((ix < jx) && (hex[ix]->lsa.rt == cnode->lsa.rt))
show_lsa_external(hex[ix++], ospf2); show_lsa_external(hex[ix++], ospf2, af);
cnode = NULL; cnode = NULL;
} }
@ -1338,7 +1348,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
last_rt = he->lsa.rt; last_rt = he->lsa.rt;
} }
show_lsa_external(he, ospf2); show_lsa_external(he, ospf2, af);
} }
} }

View File

@ -18,7 +18,7 @@
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/slists.h" #include "lib/slists.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/iface.h" #include "nest/iface.h"
@ -58,16 +58,16 @@
log_rl(&p->log_lsa_tbf, L_REMOTE "%s: " msg, p->p.name, args) log_rl(&p->log_lsa_tbf, L_REMOTE "%s: " msg, p->p.name, args)
#define LOG_LSA2(msg, args...) \ #define LOG_LSA2(msg, args...) \
do { if (! p->log_lsa_tbf.mark) \ do { if (! p->log_lsa_tbf.drop) \
log(L_REMOTE "%s: " msg, p->p.name, args); } while(0) log(L_REMOTE "%s: " msg, p->p.name, args); } while(0)
#define OSPF_PROTO 89 #define OSPF_PROTO 89
#define LSREFRESHTIME 1800 /* 30 minutes */ #define LSREFRESHTIME 1800 /* 30 minutes */
#define MINLSINTERVAL 5 #define MINLSINTERVAL (5 S_)
#define MINLSARRIVAL 1 #define MINLSARRIVAL (1 S_)
#define LSINFINITY 0xffffff #define LSINFINITY 0xffffff
#define OSPF_DEFAULT_TICK 1 #define OSPF_DEFAULT_TICK 1
#define OSPF_DEFAULT_STUB_COST 1000 #define OSPF_DEFAULT_STUB_COST 1000
@ -84,10 +84,13 @@ struct ospf_config
struct proto_config c; struct proto_config c;
uint tick; uint tick;
u8 ospf2; u8 ospf2;
u8 af_ext;
u8 af_mc;
u8 rfc1583; u8 rfc1583;
u8 stub_router; u8 stub_router;
u8 merge_external; u8 merge_external;
u8 instance_id; u8 instance_id;
u8 instance_id_set;
u8 abr; u8 abr;
u8 asbr; u8 asbr;
int ecmp; int ecmp;
@ -168,9 +171,9 @@ struct ospf_iface_patt
int tx_priority; int tx_priority;
u16 tx_length; u16 tx_length;
u16 rx_buffer; u16 rx_buffer;
#define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */ #define OSPF_RXBUF_MINSIZE 256 /* Minimal allowed size */
u8 instance_id; u8 instance_id;
u8 instance_id_set;
u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */ u8 autype; /* OSPF_AUTH_*, not really used in OSPFv3 */
u8 strictnbma; u8 strictnbma;
u8 check_link; u8 check_link;
@ -211,12 +214,14 @@ struct ospf_proto
int padj; /* Number of neighbors in Exchange or Loading state */ int padj; /* Number of neighbors in Exchange or Loading state */
struct fib rtf; /* Routing table */ struct fib rtf; /* Routing table */
struct idm idm; /* OSPFv3 LSA ID map */ struct idm idm; /* OSPFv3 LSA ID map */
byte ospf2; /* OSPF v2 or v3 */ u8 ospf2; /* OSPF v2 or v3 */
byte rfc1583; /* RFC1583 compatibility */ u8 af_ext; /* OSPFv3-AF extension */
byte stub_router; /* Do not forward transit traffic */ u8 af_mc; /* OSPFv3-AF multicast */
byte merge_external; /* Should i merge external routes? */ u8 rfc1583; /* RFC1583 compatibility */
byte asbr; /* May i originate any ext/NSSA lsa? */ u8 stub_router; /* Do not forward transit traffic */
byte ecmp; /* Maximal number of nexthops in ECMP route, or 0 */ u8 merge_external; /* Should i merge external routes? */
u8 asbr; /* May i originate any ext/NSSA lsa? */
u8 ecmp; /* Maximal number of nexthops in ECMP route, or 0 */
struct ospf_area *backbone; /* If exists */ struct ospf_area *backbone; /* If exists */
event *flood_event; /* Event for flooding LS updates */ event *flood_event; /* Event for flooding LS updates */
void *lsab; /* LSA buffer used when originating router LSAs */ void *lsab; /* LSA buffer used when originating router LSAs */
@ -264,10 +269,10 @@ struct ospf_iface
sock *sk; /* IP socket */ sock *sk; /* IP socket */
list neigh_list; /* List of neighbors (struct ospf_neighbor) */ list neigh_list; /* List of neighbors (struct ospf_neighbor) */
u32 cost; /* Cost of iface */ u32 cost; /* Cost of iface */
u32 waitint; /* number of sec before changing state from wait */ u32 waitint; /* Number of seconds before changing state from wait */
u32 rxmtint; /* number of seconds between LSA retransmissions */ u32 rxmtint; /* Number of seconds between LSA retransmissions */
u32 pollint; /* Poll interval */ u32 pollint; /* Poll interval in seconds */
u32 deadint; /* after "deadint" missing hellos is router dead */ u32 deadint; /* After deadint seconds without hellos is router dead */
u32 iface_id; /* Interface ID (iface->index or new value for vlinks) */ u32 iface_id; /* Interface ID (iface->index or new value for vlinks) */
u32 vid; /* ID of peer of virtual link */ u32 vid; /* ID of peer of virtual link */
ip_addr vip; /* IP of peer of virtual link */ ip_addr vip; /* IP of peer of virtual link */
@ -278,8 +283,8 @@ struct ospf_iface
interface. LSAs contained in the update */ interface. LSAs contained in the update */
u16 helloint; /* number of seconds between hello sending */ u16 helloint; /* number of seconds between hello sending */
list *passwords; list *passwords;
u32 csn; /* Last used crypt seq number */ u32 csn; /* Last used crypt seq number */
bird_clock_t csn_use; /* Last time when packet with that CSN was sent */ btime csn_use; /* Last time when packet with that CSN was sent */
ip_addr all_routers; /* Multicast (or broadcast) address for all routers */ ip_addr all_routers; /* Multicast (or broadcast) address for all routers */
ip_addr des_routers; /* Multicast (or NULL) address for designated routers */ ip_addr des_routers; /* Multicast (or NULL) address for designated routers */
ip_addr drip; /* Designated router IP */ ip_addr drip; /* Designated router IP */
@ -449,14 +454,15 @@ struct ospf_neighbor
/* Generic option flags */ /* Generic option flags */
#define OPT_V6 0x01 /* OSPFv3, LSA relevant for IPv6 routing calculation */ #define OPT_V6 0x0001 /* OSPFv3, LSA relevant for IPv6 routing calculation */
#define OPT_E 0x02 /* Related to AS-external LSAs */ #define OPT_E 0x0002 /* Related to AS-external LSAs */
#define OPT_MC 0x04 /* Related to MOSPF, not used and obsolete */ #define OPT_MC 0x0004 /* Related to MOSPF, not used and obsolete */
#define OPT_N 0x08 /* Related to NSSA */ #define OPT_N 0x0008 /* Related to NSSA */
#define OPT_P 0x08 /* OSPFv2, flags P and N share position, see NSSA RFC */ #define OPT_P 0x0008 /* OSPFv2, flags P and N share position, see NSSA RFC */
#define OPT_EA 0x10 /* OSPFv2, external attributes, not used and obsolete */ #define OPT_EA 0x0010 /* OSPFv2, external attributes, not used and obsolete */
#define OPT_R 0x10 /* OSPFv3, originator is active router */ #define OPT_R 0x0010 /* OSPFv3, originator is active router */
#define OPT_DC 0x20 /* Related to demand circuits, not used */ #define OPT_DC 0x0020 /* Related to demand circuits, not used */
#define OPT_AF 0x0100 /* OSPFv3 Address Families (RFC 5838) */
/* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */ /* Router-LSA VEB flags are are stored together with links (OSPFv2) or options (OSPFv3) */
#define OPT_RT_B (0x01 << 24) #define OPT_RT_B (0x01 << 24)
@ -718,74 +724,96 @@ lsa_net_count(struct ospf_lsa_header *lsa)
#define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4) #define IPV6_PREFIX_SPACE(x) ((((x) + 63) / 32) * 4)
#define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32) #define IPV6_PREFIX_WORDS(x) (((x) + 63) / 32)
/* FIXME: these functions should be significantly redesigned w.r.t. integration,
also should be named as ospf3_* instead of *_ipv6_* */
static inline int static inline int
ospf_valid_prefix(net_addr *n) ospf_valid_prefix(net_addr *n)
{ {
/* In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for invalid one */ /*
return n->pxlen <= IP6_MAX_PREFIX_LENGTH; * In OSPFv2, prefix is stored as netmask; ip4_masklen() returns 255 for
* invalid one. But OSPFv3-AF may receive IPv4 net with 32 < pxlen < 128.
*/
uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
return n->pxlen <= max;
} }
/*
* In OSPFv3-AF (RFC 5835), IPv4 address is encoded by just placing it in the
* first 32 bits of IPv6 address and setting remaining bits to zero. Likewise
* for IPv4 prefix, where remaining bits do not matter. We use following
* functions to convert between IPv4 and IPv4-in-IPv6 representations:
*/
static inline ip4_addr ospf3_6to4(ip6_addr a)
{ return _MI4(_I0(a)); }
static inline ip6_addr ospf3_4to6(ip4_addr a)
{ return _MI6(_I(a), 0, 0, 0); }
static inline u32 * static inline u32 *
ospf_get_ipv6_prefix(u32 *buf, net_addr *N, u8 *pxopts, u16 *rest) ospf3_get_prefix(u32 *buf, int af, net_addr *n, u8 *pxopts, u16 *rest)
{ {
net_addr_ip6 *net = (void *) N; ip6_addr px = IP6_NONE;
u8 pxlen = (*buf >> 24); uint pxlen = (*buf >> 24);
*pxopts = (*buf >> 16) & 0xff; *pxopts = (*buf >> 16) & 0xff;
if (rest) *rest = *buf & 0xffff; if (rest) *rest = *buf & 0xffff;
buf++; buf++;
*net = NET_ADDR_IP6(IP6_NONE, pxlen);
if (pxlen > 0) if (pxlen > 0)
_I0(net->prefix) = *buf++; _I0(px) = *buf++;
if (pxlen > 32) if (pxlen > 32)
_I1(net->prefix) = *buf++; _I1(px) = *buf++;
if (pxlen > 64) if (pxlen > 64)
_I2(net->prefix) = *buf++; _I2(px) = *buf++;
if (pxlen > 96) if (pxlen > 96)
_I3(net->prefix) = *buf++; _I3(px) = *buf++;
/* Clean up remaining bits */ /* Clean up remaining bits */
if (pxlen < 128) if (pxlen < 128)
net->prefix.addr[pxlen / 32] &= u32_mkmask(pxlen % 32); px.addr[pxlen / 32] &= u32_mkmask(pxlen % 32);
if (af == NET_IP4)
net_fill_ip4(n, ospf3_6to4(px), pxlen);
else
net_fill_ip6(n, px, pxlen);
return buf; return buf;
} }
static inline u32 * static inline u32 *
ospf_get_ipv6_addr(u32 *buf, ip_addr *addr) ospf3_put_prefix(u32 *buf, net_addr *n, u8 pxopts, u16 rest)
{ {
*addr = ipa_from_ip6(*(ip6_addr *) buf); ip6_addr px = (n->type == NET_IP4) ? ospf3_4to6(net4_prefix(n)) : net6_prefix(n);
return buf + 4; uint pxlen = n->pxlen;
}
static inline u32 *
ospf_put_ipv6_prefix(u32 *buf, net_addr *N, u8 pxopts, u16 rest)
{
net_addr_ip6 *net = (void *) N;
u32 pxlen = net->pxlen;
*buf++ = ((pxlen << 24) | (pxopts << 16) | rest); *buf++ = ((pxlen << 24) | (pxopts << 16) | rest);
if (pxlen > 0) if (pxlen > 0)
*buf++ = _I0(net->prefix); *buf++ = _I0(px);
if (pxlen > 32) if (pxlen > 32)
*buf++ = _I1(net->prefix); *buf++ = _I1(px);
if (pxlen > 64) if (pxlen > 64)
*buf++ = _I2(net->prefix); *buf++ = _I2(px);
if (pxlen > 96) if (pxlen > 96)
*buf++ = _I3(net->prefix); *buf++ = _I3(px);
return buf; return buf;
} }
static inline u32 * static inline u32 *
ospf_put_ipv6_addr(u32 *buf, ip_addr addr) ospf3_get_addr(u32 *buf, int af, ip_addr *addr)
{ {
*(ip6_addr *) buf = ipa_to_ip6(addr); ip6_addr a;
memcpy(&a, buf, 16);
*addr = (af == NET_IP4) ? ipa_from_ip4(ospf3_6to4(a)) : ipa_from_ip6(a);
return buf + 4;
}
static inline u32 *
ospf3_put_addr(u32 *buf, ip_addr addr)
{
ip6_addr a = ipa_is_ip4(addr) ? ospf3_4to6(ipa_to_ip4(addr)) : ipa_to_ip6(addr);
memcpy(buf, &a, 16);
return buf + 4; return buf + 4;
} }
@ -838,6 +866,15 @@ static inline int ospf_is_v3(struct ospf_proto *p)
static inline int ospf_get_version(struct ospf_proto *p) static inline int ospf_get_version(struct ospf_proto *p)
{ return ospf_is_v2(p) ? 2 : 3; } { return ospf_is_v2(p) ? 2 : 3; }
static inline int ospf_is_ip4(struct ospf_proto *p)
{ return p->p.net_type == NET_IP4; }
static inline int ospf_is_ip6(struct ospf_proto *p)
{ return p->p.net_type == NET_IP6; }
static inline int ospf_get_af(struct ospf_proto *p)
{ return p->p.net_type; }
struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid); struct ospf_area *ospf_find_area(struct ospf_proto *p, u32 aid);
static inline struct ospf_area *ospf_main_area(struct ospf_proto *p) static inline struct ospf_area *ospf_main_area(struct ospf_proto *p)

View File

@ -77,16 +77,16 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
reboot when system does not have independent RTC? */ reboot when system does not have independent RTC? */
if (!ifa->csn) if (!ifa->csn)
{ {
ifa->csn = (u32) now; ifa->csn = (u32) (current_real_time() TO_S);
ifa->csn_use = now; ifa->csn_use = current_time();
} }
/* We must have sufficient delay between sending a packet and increasing /* We must have sufficient delay between sending a packet and increasing
CSN to prevent reordering of packets (in a network) with different CSNs */ CSN to prevent reordering of packets (in a network) with different CSNs */
if ((now - ifa->csn_use) > 1) if ((current_time() - ifa->csn_use) > 1 S)
ifa->csn++; ifa->csn++;
ifa->csn_use = now; ifa->csn_use = current_time();
uint auth_len = mac_type_length(pass->alg); uint auth_len = mac_type_length(pass->alg);
byte *auth_tail = ((byte *) pkt + *plen); byte *auth_tail = ((byte *) pkt + *plen);
@ -270,9 +270,6 @@ ospf_rx_hook(sock *sk, uint len)
if (pkt == NULL) if (pkt == NULL)
DROP("bad IP header", len); DROP("bad IP header", len);
if (ifa->check_ttl && (sk->rcv_ttl < 255))
DROP("wrong TTL", sk->rcv_ttl);
if (len < sizeof(struct ospf_packet)) if (len < sizeof(struct ospf_packet))
DROP("too short", len); DROP("too short", len);
@ -379,6 +376,10 @@ found:
if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0)) if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
return 1; return 1;
/* TTL check must be done after instance dispatch */
if (ifa->check_ttl && (sk->rcv_ttl < 255))
DROP("wrong TTL", sk->rcv_ttl);
if (rid == p->router_id) if (rid == p->router_id)
DROP1("my own router ID"); DROP1("my own router ID");

View File

@ -10,9 +10,7 @@
#include "ospf.h" #include "ospf.h"
static void add_cand(list * l, struct top_hash_entry *en, static void add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par, u32 dist, int i, uint lif, uint nif);
struct top_hash_entry *par, u32 dist,
struct ospf_area *oa, int i);
static void rt_sync(struct ospf_proto *p); static void rt_sync(struct ospf_proto *p);
@ -509,7 +507,7 @@ spfa_process_rt(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_entr
break; break;
} }
add_cand(&oa->cand, tmp, act, act->dist + rtl.metric, oa, i); add_cand(oa, tmp, act, act->dist + rtl.metric, i, rtl.lif, rtl.nif);
} }
} }
@ -532,7 +530,7 @@ spfa_process_net(struct ospf_proto *p, struct ospf_area *oa, struct top_hash_ent
for (i = 0; i < cnt; i++) for (i = 0; i < cnt; i++)
{ {
tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]); tmp = ospf_hash_find_rt(p->gr, oa->areaid, ln->routers[i]);
add_cand(&oa->cand, tmp, act, act->dist, oa, -1); add_cand(oa, tmp, act, act->dist, -1, 0, 0);
} }
} }
@ -576,20 +574,20 @@ spfa_process_prefixes(struct ospf_proto *p, struct ospf_area *oa)
buf = px->rest; buf = px->rest;
for (i = 0; i < px->pxcount; i++) for (i = 0; i < px->pxcount; i++)
{ {
net_addr_ip6 net; net_addr net;
u8 pxopts; u8 pxopts;
u16 metric; u16 metric;
buf = ospf_get_ipv6_prefix(buf, (net_addr *) &net, &pxopts, &metric); buf = ospf3_get_prefix(buf, ospf_get_af(p), &net, &pxopts, &metric);
if (pxopts & OPT_PX_NU) if (pxopts & OPT_PX_NU)
continue; continue;
/* Store the first global address to use it later as a vlink endpoint */ /* Store the first global address to use it later as a vlink endpoint */
if ((pxopts & OPT_PX_LA) && ipa_zero(src->lb)) if ((pxopts & OPT_PX_LA) && (net.type == NET_IP6) && ipa_zero(src->lb))
src->lb = ipa_from_ip6(net.prefix); src->lb = ipa_from_ip6(net6_prefix(&net));
add_network(oa, (net_addr *) &net, src->dist + metric, src, i); add_network(oa, &net, src->dist + metric, src, i);
} }
} }
} }
@ -651,7 +649,8 @@ ospf_rt_spfa(struct ospf_area *oa)
} }
static int static int
link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par) link_back(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par, uint lif, uint nif)
{ {
struct ospf_proto *p = oa->po; struct ospf_proto *p = oa->po;
struct ospf_lsa_rt_walk rtl; struct ospf_lsa_rt_walk rtl;
@ -689,6 +688,10 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif); tmp = ospf_hash_find_net(p->gr, oa->areaid, rtl.id, rtl.nif);
if (tmp == par) if (tmp == par)
{ {
/*
* Note that there may be multiple matching Rt-fields if router 'en'
* have multiple interfaces to net 'par'. Perhaps we should do ECMP.
*/
if (ospf_is_v2(p)) if (ospf_is_v2(p))
en->lb = ipa_from_u32(rtl.data); en->lb = ipa_from_u32(rtl.data);
else else
@ -700,7 +703,13 @@ link_back(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry
case LSART_VLNK: case LSART_VLNK:
case LSART_PTP: case LSART_PTP:
/* Not necessary the same link, see RFC 2328 [23] */ /*
* For OSPFv2, not necessary the same link, see RFC 2328 [23].
* For OSPFv3, we verify that by comparing nif and lif fields.
*/
if (ospf_is_v3(p) && ((rtl.lif != nif) || (rtl.nif != lif)))
break;
tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id); tmp = ospf_hash_find_rt(p->gr, oa->areaid, rtl.id);
if (tmp == par) if (tmp == par)
return 1; return 1;
@ -761,7 +770,7 @@ ospf_rt_sum(struct ospf_area *oa)
if (en->lsa_type == LSA_T_SUM_NET) if (en->lsa_type == LSA_T_SUM_NET)
{ {
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric); lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
if (!ospf_valid_prefix(&net)) if (!ospf_valid_prefix(&net))
{ {
@ -858,7 +867,7 @@ ospf_rt_sum_tr(struct ospf_area *oa)
net_addr net; net_addr net;
u8 pxopts; u8 pxopts;
lsa_parse_sum_net(en, ospf_is_v2(p), &net, &pxopts, &metric); lsa_parse_sum_net(en, ospf_is_v2(p), ospf_get_af(p), &net, &pxopts, &metric);
if (!ospf_valid_prefix(&net)) if (!ospf_valid_prefix(&net))
{ {
@ -1058,7 +1067,7 @@ decide_nssa_lsa(struct ospf_proto *p, ort *nf, struct ospf_lsa_ext_local *rt)
return 0; return 0;
/* We do not store needed data in struct orta, we have to parse the LSA */ /* We do not store needed data in struct orta, we have to parse the LSA */
lsa_parse_ext(en, ospf_is_v2(p), rt); lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), rt);
if (rt->pxopts & OPT_PX_NU) if (rt->pxopts & OPT_PX_NU)
return 0; return 0;
@ -1320,10 +1329,10 @@ ospf_rt_abr2(struct ospf_proto *p)
if (!translate && (oa->translate == TRANS_ON)) if (!translate && (oa->translate == TRANS_ON))
{ {
if (oa->translator_timer == NULL) if (oa->translator_timer == NULL)
oa->translator_timer = tm_new_set(p->p.pool, translator_timer_hook, oa, 0, 0); oa->translator_timer = tm_new_init(p->p.pool, translator_timer_hook, oa, 0, 0);
/* Schedule the end of translation */ /* Schedule the end of translation */
tm_start(oa->translator_timer, oa->ac->transint); tm_start(oa->translator_timer, oa->ac->transint S);
oa->translate = TRANS_WAIT; oa->translate = TRANS_WAIT;
} }
} }
@ -1450,7 +1459,7 @@ ospf_ext_spf(struct ospf_proto *p)
DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n", DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n",
p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type); p->p.name, en->lsa.id, en->lsa.rt, en->lsa_type);
lsa_parse_ext(en, ospf_is_v2(p), &rt); lsa_parse_ext(en, ospf_is_v2(p), ospf_get_af(p), &rt);
if (!ospf_valid_prefix(&rt.net)) if (!ospf_valid_prefix(&rt.net))
{ {
@ -1679,13 +1688,27 @@ inherit_nexthops(struct nexthop *pn)
return pn && (ipa_nonzero(pn->gw) || !pn->iface); return pn && (ipa_nonzero(pn->gw) || !pn->iface);
} }
static inline ip_addr
link_lsa_lladdr(struct ospf_proto *p, struct top_hash_entry *en)
{
struct ospf_lsa_link *link_lsa = en->lsa_body;
ip6_addr ll = link_lsa->lladdr;
if (ip6_zero(ll))
return IPA_NONE;
return ospf_is_ip4(p) ? ipa_from_ip4(ospf3_6to4(ll)) : ipa_from_ip6(ll);
}
static struct nexthop * static struct nexthop *
calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en, calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
struct top_hash_entry *par, int pos) struct top_hash_entry *par, int pos, uint lif, uint nif)
{ {
struct ospf_proto *p = oa->po; struct ospf_proto *p = oa->po;
struct nexthop *pn = par->nhs; struct nexthop *pn = par->nhs;
struct ospf_iface *ifa; struct top_hash_entry *link = NULL;
struct ospf_iface *ifa = NULL;
ip_addr nh = IPA_NONE;
u32 rid = en->lsa.rt; u32 rid = en->lsa.rt;
/* 16.1.1. The next hop calculation */ /* 16.1.1. The next hop calculation */
@ -1710,6 +1733,9 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (!ifa) if (!ifa)
return NULL; return NULL;
if (ospf_is_v3(p) && (ifa->iface_id != lif))
log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight); return new_nexthop(p, IPA_NONE, ifa->iface, ifa->ecmp_weight);
} }
@ -1720,14 +1746,44 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
if (!ifa) if (!ifa)
return NULL; return NULL;
if (ospf_is_v3(p) && (ifa->iface_id != lif))
log(L_WARN "%s: Inconsistent interface ID %u/%u", p->p.name, ifa->iface_id, lif);
if (ifa->type == OSPF_IT_VLINK) if (ifa->type == OSPF_IT_VLINK)
return new_nexthop(p, IPA_NONE, NULL, 0); return new_nexthop(p, IPA_NONE, NULL, 0);
struct ospf_neighbor *m = find_neigh(ifa, rid); /* FIXME: On physical PtP links we may skip next-hop altogether */
if (!m || (m->state != NEIGHBOR_FULL))
return NULL;
return new_nexthop(p, m->ip, ifa->iface, ifa->ecmp_weight); if (ospf_is_v2(p) || ospf_is_ip6(p))
{
/*
* In this case, next-hop is a source address from neighbor's packets.
* That is necessary for OSPFv2 and practical for OSPFv3 (as it works even
* if neighbor uses LinkLSASuppression), but does not work with OSPFv3-AF
* on IPv4 topology, where src is IPv6 but next-hop should be IPv4.
*/
struct ospf_neighbor *m = find_neigh(ifa, rid);
if (!m || (m->state != NEIGHBOR_FULL))
return NULL;
nh = m->ip;
}
else
{
/*
* Next-hop is taken from lladdr field of Link-LSA, based on Neighbor
* Iface ID (nif) field in our Router-LSA, which is just nbr->iface_id.
*/
link = ospf_hash_find(p->gr, ifa->iface_id, nif, rid, LSA_T_LINK);
if (!link)
return NULL;
nh = link_lsa_lladdr(p, link);
if (ipa_zero(nh))
return NULL;
}
return new_nexthop(p, nh, ifa->iface, ifa->ecmp_weight);
} }
/* The third case - bcast or nbma neighbor */ /* The third case - bcast or nbma neighbor */
@ -1754,18 +1810,15 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
* Next-hop is taken from lladdr field of Link-LSA, en->lb_id * Next-hop is taken from lladdr field of Link-LSA, en->lb_id
* is computed in link_back(). * is computed in link_back().
*/ */
struct top_hash_entry *lhe; link = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK);
lhe = ospf_hash_find(p->gr, pn->iface->index, en->lb_id, rid, LSA_T_LINK); if (!link)
if (!lhe)
return NULL; return NULL;
struct ospf_lsa_link *llsa = lhe->lsa_body; nh = link_lsa_lladdr(p, link);
if (ipa_zero(nh))
if (ip6_zero(llsa->lladdr))
return NULL; return NULL;
return new_nexthop(p, ipa_from_ip6(llsa->lladdr), pn->iface, pn->weight); return new_nexthop(p, nh, pn->iface, pn->weight);
} }
} }
@ -1778,8 +1831,8 @@ calc_next_hop(struct ospf_area *oa, struct top_hash_entry *en,
/* Add LSA into list of candidates in Dijkstra's algorithm */ /* Add LSA into list of candidates in Dijkstra's algorithm */
static void static void
add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par, add_cand(struct ospf_area *oa, struct top_hash_entry *en, struct top_hash_entry *par,
u32 dist, struct ospf_area *oa, int pos) u32 dist, int pos, uint lif, uint nif)
{ {
struct ospf_proto *p = oa->po; struct ospf_proto *p = oa->po;
node *prev, *n; node *prev, *n;
@ -1792,9 +1845,9 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
return; return;
if (ospf_is_v3(p) && (en->lsa_type == LSA_T_RT)) if (ospf_is_v3(p) && (oa->options & OPT_V6) && (en->lsa_type == LSA_T_RT))
{ {
/* In OSPFv3, check V6 flag */ /* In OSPFv3 IPv6 unicast, check V6 flag */
struct ospf_lsa_rt *rt = en->lsa_body; struct ospf_lsa_rt *rt = en->lsa_body;
if (!(rt->options & OPT_V6)) if (!(rt->options & OPT_V6))
return; return;
@ -1809,10 +1862,10 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
return; return;
/* We should check whether there is a reverse link from en to par, */ /* We should check whether there is a reverse link from en to par, */
if (!link_back(oa, en, par)) if (!link_back(oa, en, par, lif, nif))
return; return;
struct nexthop *nhs = calc_next_hop(oa, en, par, pos); struct nexthop *nhs = calc_next_hop(oa, en, par, pos, lif, nif);
if (!nhs) if (!nhs)
{ {
log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)", log(L_WARN "%s: Cannot find next hop for LSA (Type: %04x, Id: %R, Rt: %R)",
@ -1869,20 +1922,20 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
prev = NULL; prev = NULL;
if (EMPTY_LIST(*l)) if (EMPTY_LIST(oa->cand))
{ {
add_head(l, &en->cn); add_head(&oa->cand, &en->cn);
} }
else else
{ {
WALK_LIST(n, *l) WALK_LIST(n, oa->cand)
{ {
act = SKIP_BACK(struct top_hash_entry, cn, n); act = SKIP_BACK(struct top_hash_entry, cn, n);
if ((act->dist > dist) || if ((act->dist > dist) ||
((act->dist == dist) && (act->lsa_type == LSA_T_RT))) ((act->dist == dist) && (act->lsa_type == LSA_T_RT)))
{ {
if (prev == NULL) if (prev == NULL)
add_head(l, &en->cn); add_head(&oa->cand, &en->cn);
else else
insert_node(&en->cn, prev); insert_node(&en->cn, prev);
added = 1; added = 1;
@ -1893,7 +1946,7 @@ add_cand(list * l, struct top_hash_entry *en, struct top_hash_entry *par,
if (!added) if (!added)
{ {
add_tail(l, &en->cn); add_tail(&oa->cand, &en->cn);
} }
} }
} }

View File

@ -70,7 +70,7 @@ ospf_install_lsa(struct ospf_proto *p, struct ospf_lsa_header *lsa, u32 type, u3
en->lsa_body = body; en->lsa_body = body;
en->lsa = *lsa; en->lsa = *lsa;
en->init_age = en->lsa.age; en->init_age = en->lsa.age;
en->inst_time = now; en->inst_time = current_time();
/* /*
* We do not set en->mode. It is either default LSA_M_BASIC, or in a special * We do not set en->mode. It is either default LSA_M_BASIC, or in a special
@ -128,7 +128,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
en->lsa.sn = lsa->sn + 1; en->lsa.sn = lsa->sn + 1;
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", OSPF_TRACE(D_EVENTS, "Advancing LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@ -160,7 +160,7 @@ ospf_advance_lsa(struct ospf_proto *p, struct top_hash_entry *en, struct ospf_ls
en->lsa = *lsa; en->lsa = *lsa;
en->lsa.age = LSA_MAXAGE; en->lsa.age = LSA_MAXAGE;
en->init_age = lsa->age; en->init_age = lsa->age;
en->inst_time = now; en->inst_time = current_time();
OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", OSPF_TRACE(D_EVENTS, "Resetting LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn); en->lsa_type, en->lsa.id, en->lsa.rt, en->lsa.sn);
@ -196,7 +196,7 @@ static int
ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa_body, u16 lsa_blen, u16 lsa_opts) ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa_body, u16 lsa_blen, u16 lsa_opts)
{ {
/* Enforce MinLSInterval */ /* Enforce MinLSInterval */
if ((en->init_age == 0) && en->inst_time && ((en->inst_time + MINLSINTERVAL) > now)) if (!en->init_age && en->inst_time && (lsa_inst_age(en) < MINLSINTERVAL))
return 0; return 0;
/* Handle wrapping sequence number */ /* Handle wrapping sequence number */
@ -237,7 +237,7 @@ ospf_do_originate_lsa(struct ospf_proto *p, struct top_hash_entry *en, void *lsa
en->lsa.sn++; en->lsa.sn++;
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x", OSPF_TRACE(D_EVENTS, "Originating LSA: Type: %04x, Id: %R, Rt: %R, Seq: %08x",
@ -381,7 +381,7 @@ ospf_refresh_lsa(struct ospf_proto *p, struct top_hash_entry *en)
en->lsa.sn++; en->lsa.sn++;
en->lsa.age = 0; en->lsa.age = 0;
en->init_age = 0; en->init_age = 0;
en->inst_time = now; en->inst_time = current_time();
lsa_generate_checksum(&en->lsa, en->lsa_body); lsa_generate_checksum(&en->lsa, en->lsa_body);
ospf_flood_lsa(p, en, NULL); ospf_flood_lsa(p, en, NULL);
} }
@ -476,14 +476,15 @@ void
ospf_update_lsadb(struct ospf_proto *p) ospf_update_lsadb(struct ospf_proto *p)
{ {
struct top_hash_entry *en, *nxt; struct top_hash_entry *en, *nxt;
bird_clock_t real_age; btime now_ = current_time();
int real_age;
WALK_SLIST_DELSAFE(en, nxt, p->lsal) WALK_SLIST_DELSAFE(en, nxt, p->lsal)
{ {
if (en->next_lsa_body) if (en->next_lsa_body)
ospf_originate_next_lsa(p, en); ospf_originate_next_lsa(p, en);
real_age = en->init_age + (now - en->inst_time); real_age = en->init_age + (now_ - en->inst_time) TO_S;
if (en->lsa.age == LSA_MAXAGE) if (en->lsa.age == LSA_MAXAGE)
{ {
@ -1008,7 +1009,7 @@ prepare_sum3_net_lsa_body(struct ospf_proto *p, ort *nf, u32 metric)
sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) + sum = lsab_allocz(p, sizeof(struct ospf_lsa_sum3_net) +
IPV6_PREFIX_SPACE(nf->fn.addr->pxlen)); IPV6_PREFIX_SPACE(nf->fn.addr->pxlen));
sum->metric = metric; sum->metric = metric;
ospf_put_ipv6_prefix(sum->prefix, nf->fn.addr, 0, 0); ospf3_put_prefix(sum->prefix, nf->fn.addr, 0, 0);
} }
static inline void static inline void
@ -1097,7 +1098,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
ext->metric = metric & LSA_METRIC_MASK; ext->metric = metric & LSA_METRIC_MASK;
u32 *buf = ext->rest; u32 *buf = ext->rest;
buf = ospf_put_ipv6_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0); buf = ospf3_put_prefix(buf, nf->fn.addr, pbit ? OPT_PX_P : 0, 0);
if (ebit) if (ebit)
ext->metric |= LSA_EXT3_EBIT; ext->metric |= LSA_EXT3_EBIT;
@ -1105,7 +1106,7 @@ prepare_ext3_lsa_body(struct ospf_proto *p, ort *nf,
if (ipa_nonzero(fwaddr)) if (ipa_nonzero(fwaddr))
{ {
ext->metric |= LSA_EXT3_FBIT; ext->metric |= LSA_EXT3_FBIT;
buf = ospf_put_ipv6_addr(buf, fwaddr); buf = ospf3_put_addr(buf, fwaddr);
} }
if (tag) if (tag)
@ -1222,7 +1223,7 @@ find_surrogate_fwaddr(struct ospf_proto *p, struct ospf_area *oa)
{ {
WALK_LIST(a, ifa->iface->addrs) WALK_LIST(a, ifa->iface->addrs)
{ {
if ((a->prefix.type != NET_IP6) || if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) || (a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) || (a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK)) (a->scope <= SCOPE_LINK))
@ -1316,39 +1317,47 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
*/ */
static inline void static inline void
lsab_put_prefix(struct ospf_proto *p, net_addr *net, u32 cost) lsab_put_prefix(struct ospf_proto *p, net_addr *n, u32 cost)
{ {
void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net6_pxlen(net))); void *buf = lsab_alloc(p, IPV6_PREFIX_SPACE(net_pxlen(n)));
u8 flags = (net6_pxlen(net) < IP6_MAX_PREFIX_LENGTH) ? 0 : OPT_PX_LA; uint max = (n->type == NET_IP4) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
ospf_put_ipv6_prefix(buf, net, flags, cost); u8 flags = (net_pxlen(n) < max) ? 0 : OPT_PX_LA;
ospf3_put_prefix(buf, n, flags, cost);
} }
static void static void
prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa) prepare_link_lsa_body(struct ospf_proto *p, struct ospf_iface *ifa)
{ {
struct ospf_lsa_link *ll; ip_addr nh = ospf_is_ip4(p) ? IPA_NONE : ifa->addr->ip;
int i = 0; int i = 0;
/* Preallocating space for header */
ASSERT(p->lsab_used == 0); ASSERT(p->lsab_used == 0);
ll = lsab_allocz(p, sizeof(struct ospf_lsa_link)); lsab_allocz(p, sizeof(struct ospf_lsa_link));
ll->options = ifa->oa->options | (ifa->priority << 24);
ll->lladdr = ipa_to_ip6(ifa->addr->ip);
ll = NULL; /* buffer might be reallocated later */
struct ifa *a; struct ifa *a;
WALK_LIST(a, ifa->iface->addrs) WALK_LIST(a, ifa->iface->addrs)
{ {
if ((a->prefix.type != NET_IP6) || if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) || (a->flags & IA_SECONDARY) ||
(a->scope <= SCOPE_LINK)) (a->scope <= SCOPE_LINK))
continue; continue;
if (ospf_is_ip4(p) && ipa_zero(nh))
nh = a->ip;
lsab_put_prefix(p, &a->prefix, 0); lsab_put_prefix(p, &a->prefix, 0);
i++; i++;
} }
ll = p->lsab; /* Filling the preallocated header */
struct ospf_lsa_link *ll = p->lsab;
ll->options = ifa->oa->options | (ifa->priority << 24);
ll->lladdr = ospf_is_ip4(p) ? ospf3_4to6(ipa_to_ip4(nh)) : ipa_to_ip6(nh);
ll->pxcount = i; ll->pxcount = i;
if (ipa_zero(nh))
log(L_ERR "%s: Cannot find next hop address for %s", p->p.name, ifa->ifname);
} }
static void static void
@ -1410,7 +1419,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
struct ifa *a; struct ifa *a;
WALK_LIST(a, ifa->iface->addrs) WALK_LIST(a, ifa->iface->addrs)
{ {
if ((a->prefix.type != NET_IP6) || if ((a->prefix.type != ospf_get_af(p)) ||
(a->flags & IA_SECONDARY) || (a->flags & IA_SECONDARY) ||
(a->flags & IA_PEER) || (a->flags & IA_PEER) ||
(a->scope <= SCOPE_LINK)) (a->scope <= SCOPE_LINK))
@ -1448,7 +1457,7 @@ prepare_prefix_rt_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
/* If there are some configured vlinks, find some global address /* If there are some configured vlinks, find some global address
(even from another area), which will be used as a vlink endpoint. */ (even from another area), which will be used as a vlink endpoint. */
if (!EMPTY_LIST(cf->vlink_list) && !host_addr) if (!EMPTY_LIST(cf->vlink_list) && !host_addr && ospf_is_ip6(p))
{ {
WALK_LIST(ifa, p->iface_list) WALK_LIST(ifa, p->iface_list)
{ {
@ -1571,7 +1580,7 @@ add_link_lsa(struct ospf_proto *p, struct ospf_lsa_link *ll, int offset, int *px
continue; continue;
/* Skip link-local prefixes */ /* Skip link-local prefixes */
if ((pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000)) if (ospf_is_ip6(p) && (pxlen >= 10) && ((pxb[1] & 0xffc00000) == 0xfe800000))
continue; continue;
add_prefix(p, pxb, offset, pxc); add_prefix(p, pxb, offset, pxc);
@ -1628,7 +1637,7 @@ ospf_originate_prefix_net_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
} }
static inline int breaks_minlsinterval(struct top_hash_entry *en) static inline int breaks_minlsinterval(struct top_hash_entry *en)
{ return en && (en->lsa.age < LSA_MAXAGE) && ((en->inst_time + MINLSINTERVAL) > now); } { return en && (en->lsa.age < LSA_MAXAGE) && (lsa_inst_age(en) < MINLSINTERVAL); }
void void
ospf_update_topology(struct ospf_proto *p) ospf_update_topology(struct ospf_proto *p)

View File

@ -26,7 +26,7 @@ struct top_hash_entry
void *next_lsa_body; /* For postponed LSA origination */ void *next_lsa_body; /* For postponed LSA origination */
u16 next_lsa_blen; /* For postponed LSA origination */ u16 next_lsa_blen; /* For postponed LSA origination */
u16 next_lsa_opts; /* For postponed LSA origination */ u16 next_lsa_opts; /* For postponed LSA origination */
bird_clock_t inst_time; /* Time of installation into DB */ btime inst_time; /* Time of installation into DB */
struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */ struct ort *nf; /* Reference fibnode for sum and ext LSAs, NULL for otherwise */
struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */ struct nexthop *nhs; /* Computed nexthops - valid only in ospf_rt_spf() */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */ ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */

View File

@ -27,10 +27,13 @@ static u8 radv_mult_val; /* Used by radv_mult for second return value */
CF_DECLS CF_DECLS
CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, RETRANS,
TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH) LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE,
ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME)
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
%type<i> radv_mult radv_sensitive radv_preference %type<i> radv_mult radv_sensitive radv_preference
@ -56,6 +59,7 @@ radv_proto_item:
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
| TRIGGER net_ip6 { RADV_CFG->trigger = $2; } | TRIGGER net_ip6 { RADV_CFG->trigger = $2; }
| PROPAGATE ROUTES bool { RADV_CFG->propagate_routes = $3; }
; ;
radv_proto_opts: radv_proto_opts:
@ -76,13 +80,18 @@ radv_iface_start:
init_list(&RADV_IFACE->rdnss_list); init_list(&RADV_IFACE->rdnss_list);
init_list(&RADV_IFACE->dnssl_list); init_list(&RADV_IFACE->dnssl_list);
RADV_IFACE->min_ra_int = -1; /* undefined */ RADV_IFACE->min_ra_int = (u32) -1; /* undefined */
RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT; RADV_IFACE->max_ra_int = DEFAULT_MAX_RA_INT;
RADV_IFACE->min_delay = DEFAULT_MIN_DELAY; RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
RADV_IFACE->prefix_linger_time = (u32) -1;
RADV_IFACE->route_linger_time = (u32) -1;
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT; RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
RADV_IFACE->default_lifetime = -1; RADV_IFACE->default_lifetime = (u32) -1;
RADV_IFACE->default_lifetime_sensitive = 1; RADV_IFACE->default_lifetime_sensitive = 1;
RADV_IFACE->default_preference = RA_PREF_MEDIUM; RADV_IFACE->default_preference = RA_PREF_MEDIUM;
RADV_IFACE->route_lifetime = (u32) -1;
RADV_IFACE->route_lifetime_sensitive = 0;
RADV_IFACE->route_preference = RA_PREF_MEDIUM;
}; };
radv_iface_item: radv_iface_item:
@ -100,7 +109,14 @@ radv_iface_item:
if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000"); if ($3 > 9000) cf_error("Default lifetime must be in range 0-9000");
if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4; if ($4 != (uint) -1) RADV_IFACE->default_lifetime_sensitive = $4;
} }
| ROUTE LIFETIME expr radv_sensitive {
RADV_IFACE->route_lifetime = $3;
if ($4 != (uint) -1) RADV_IFACE->route_lifetime_sensitive = $4;
}
| DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; } | DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
| ROUTE PREFERENCE radv_preference { RADV_IFACE->route_preference = $3; }
| PREFIX LINGER TIME expr { RADV_IFACE->prefix_linger_time = $4; }
| ROUTE LINGER TIME expr { RADV_IFACE->route_linger_time = $4; }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
@ -123,12 +139,32 @@ radv_iface_finish:
if (ic->default_lifetime == (u32) -1) if (ic->default_lifetime == (u32) -1)
ic->default_lifetime = 3 * ic->max_ra_int; ic->default_lifetime = 3 * ic->max_ra_int;
if (ic->route_lifetime == (u32) -1)
ic->route_lifetime = 3 * ic->max_ra_int;
if (ic->prefix_linger_time == (u32) -1)
ic->prefix_linger_time = 3 * ic->max_ra_int;
if (ic->route_linger_time == (u32) -1)
ic->route_linger_time = 3 * ic->max_ra_int;
if ((ic->min_ra_int > 3) && if ((ic->min_ra_int > 3) &&
(ic->min_ra_int > (ic->max_ra_int * 3 / 4))) (ic->min_ra_int > (ic->max_ra_int * 3 / 4)))
cf_error("Min RA interval must be at most 3/4 * Max RA interval"); cf_error("Min RA interval must be at most 3/4 * Max RA interval");
if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int)) if ((ic->default_lifetime > 0) && (ic->default_lifetime < ic->max_ra_int))
cf_error("Default lifetime must be either 0 or at least Max RA interval"); cf_error("Default lifetime must be either 0 or at least Max RA interval");
if ((ic->route_lifetime > 0) && (ic->route_lifetime < ic->max_ra_int))
cf_error("Route lifetime must be either 0 or at least Max RA interval");
if ((ic->prefix_linger_time > 0) && (ic->prefix_linger_time < ic->max_ra_int))
cf_error("Prefix linger time must be either 0 or at least Max RA interval");
if ((ic->route_linger_time > 0) && (ic->route_linger_time < ic->max_ra_int))
cf_error("Route linger time must be either 0 or at least Max RA interval");
RADV_CFG->max_linger_time = MAX_(RADV_CFG->max_linger_time, ic->route_linger_time);
}; };
@ -292,10 +328,13 @@ radv_mult:
; ;
radv_sensitive: radv_sensitive:
/* empty */ { $$ = -1; } /* empty */ { $$ = (uint) -1; }
| SENSITIVE bool { $$ = $2; } | SENSITIVE bool { $$ = $2; }
; ;
CF_ADDTO(dynamic_attr, RA_PREFERENCE { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_ENUM_RA_PREFERENCE, EA_RA_PREFERENCE); })
CF_ADDTO(dynamic_attr, RA_LIFETIME { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RA_LIFETIME); })
CF_CODE CF_CODE
CF_END CF_END

View File

@ -26,6 +26,7 @@ struct radv_ra_packet
#define OPT_PREFIX 3 #define OPT_PREFIX 3
#define OPT_MTU 5 #define OPT_MTU 5
#define OPT_ROUTE 24
#define OPT_RDNSS 25 #define OPT_RDNSS 25
#define OPT_DNSSL 31 #define OPT_DNSSL 31
@ -52,6 +53,15 @@ struct radv_opt_mtu
u32 mtu; u32 mtu;
}; };
struct radv_opt_route {
u8 type;
u8 length;
u8 pxlen;
u8 flags;
u32 lifetime;
u8 prefix[];
};
struct radv_opt_rdnss struct radv_opt_rdnss
{ {
u8 type; u8 type;
@ -70,34 +80,42 @@ struct radv_opt_dnssl
char domain[]; char domain[];
}; };
static int
static struct radv_prefix_config default_prefix = { radv_prepare_route(struct radv_iface *ifa, struct radv_route *rt,
.onlink = 1, char **buf, char *bufend)
.autonomous = 1,
.valid_lifetime = DEFAULT_VALID_LIFETIME,
.preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
};
static struct radv_prefix_config *
radv_prefix_match(struct radv_iface *ifa, struct ifa *a)
{ {
struct proto *p = &ifa->ra->p; struct radv_proto *p = ifa->ra;
struct radv_config *cf = (struct radv_config *) (p->cf); u8 px_blocks = (net6_pxlen(rt->n.addr) + 63) / 64;
struct radv_prefix_config *pc; u8 opt_len = 8 * (1 + px_blocks);
if (a->scope <= SCOPE_LINK) if (*buf + opt_len > bufend)
return NULL; {
log(L_WARN, "%s: Too many RA options on interface %s",
p->p.name, ifa->iface->name);
return -1;
}
WALK_LIST(pc, ifa->cf->pref_list) uint preference = rt->preference_set ? rt->preference : ifa->cf->route_preference;
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix)) uint lifetime = rt->lifetime_set ? rt->lifetime : ifa->cf->route_lifetime;
return pc; uint valid = rt->valid && p->valid && (p->active || !ifa->cf->route_lifetime_sensitive);
WALK_LIST(pc, cf->pref_list) struct radv_opt_route *opt = (void *) *buf;
if (net_in_netX(&a->prefix, (net_addr *) &pc->prefix)) *buf += opt_len;
return pc; opt->type = OPT_ROUTE;
opt->length = 1 + px_blocks;
opt->pxlen = net6_pxlen(rt->n.addr);
opt->flags = preference;
opt->lifetime = valid ? htonl(lifetime) : 0;
return &default_prefix; /* Copy the relevant part of the prefix */
ip6_addr px_addr = ip6_hton(net6_prefix(rt->n.addr));
memcpy(opt->prefix, &px_addr, 8 * px_blocks);
/* Keeping track of first linger timeout */
if (!rt->valid)
ifa->valid_time = MIN(ifa->valid_time, rt->changed + ifa->cf->route_linger_time S);
return 0;
} }
static int static int
@ -206,7 +224,7 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
else else
op->lifetime = htonl(dcf->lifetime); op->lifetime = htonl(dcf->lifetime);
while(NODE_VALID(dcf) && while(NODE_VALID(dcf) &&
(dcf->lifetime == dcf_base->lifetime) && (dcf->lifetime == dcf_base->lifetime) &&
(dcf->lifetime_mult == dcf_base->lifetime_mult)) (dcf->lifetime_mult == dcf_base->lifetime_mult))
{ {
@ -234,12 +252,47 @@ radv_prepare_dnssl(struct radv_iface *ifa, list *dnssl_list, char **buf, char *b
return -1; return -1;
} }
static int
radv_prepare_prefix(struct radv_iface *ifa, struct radv_prefix *px,
char **buf, char *bufend)
{
struct radv_prefix_config *pc = px->cf;
if (*buf + sizeof(struct radv_opt_prefix) > bufend)
{
log(L_WARN "%s: Too many prefixes on interface %s",
ifa->ra->p.name, ifa->iface->name);
return -1;
}
struct radv_opt_prefix *op = (void *) *buf;
op->type = OPT_PREFIX;
op->length = 4;
op->pxlen = px->prefix.pxlen;
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
op->valid_lifetime = (ifa->ra->active || !pc->valid_lifetime_sensitive) ?
htonl(pc->valid_lifetime) : 0;
op->preferred_lifetime = (ifa->ra->active || !pc->preferred_lifetime_sensitive) ?
htonl(pc->preferred_lifetime) : 0;
op->reserved = 0;
op->prefix = ip6_hton(px->prefix.prefix);
*buf += sizeof(*op);
/* Keeping track of first linger timeout */
if (!px->valid)
ifa->valid_time = MIN(ifa->valid_time, px->changed + ifa->cf->prefix_linger_time S);
return 0;
}
static void static void
radv_prepare_ra(struct radv_iface *ifa) radv_prepare_ra(struct radv_iface *ifa)
{ {
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
struct radv_config *cf = (struct radv_config *) (ra->p.cf); struct radv_config *cf = (struct radv_config *) (p->p.cf);
struct radv_iface_config *ic = ifa->cf; struct radv_iface_config *ic = ifa->cf;
btime now = current_time();
char *buf = ifa->sk->tbuf; char *buf = ifa->sk->tbuf;
char *bufstart = buf; char *bufstart = buf;
@ -250,7 +303,7 @@ radv_prepare_ra(struct radv_iface *ifa)
pkt->code = 0; pkt->code = 0;
pkt->checksum = 0; pkt->checksum = 0;
pkt->current_hop_limit = ic->current_hop_limit; pkt->current_hop_limit = ic->current_hop_limit;
pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ? pkt->router_lifetime = (p->valid && (p->active || !ic->default_lifetime_sensitive)) ?
htons(ic->default_lifetime) : 0; htons(ic->default_lifetime) : 0;
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) | pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
(ic->other_config ? OPT_RA_OTHER_CFG : 0) | (ic->other_config ? OPT_RA_OTHER_CFG : 0) |
@ -269,37 +322,18 @@ radv_prepare_ra(struct radv_iface *ifa)
buf += sizeof (*om); buf += sizeof (*om);
} }
struct ifa *addr; /* Keeping track of first linger timeout */
WALK_LIST(addr, ifa->iface->addrs) ifa->valid_time = TIME_INFINITY;
struct radv_prefix *px;
WALK_LIST(px, ifa->prefixes)
{ {
if (addr->prefix.type != NET_IP6) /* Skip invalid prefixes that are past linger timeout but still not pruned */
continue; if (!px->valid && ((px->changed + ic->prefix_linger_time S) <= now))
continue;
struct radv_prefix_config *pc; if (radv_prepare_prefix(ifa, px, &buf, bufend) < 0)
pc = radv_prefix_match(ifa, addr);
if (!pc || pc->skip)
continue;
if (buf + sizeof(struct radv_opt_prefix) > bufend)
{
log(L_WARN "%s: Too many prefixes on interface %s", ra->p.name, ifa->iface->name);
goto done; goto done;
}
struct radv_opt_prefix *op = (void *) buf;
op->type = OPT_PREFIX;
op->length = 4;
op->pxlen = net6_pxlen(&addr->prefix);
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
op->valid_lifetime = (ra->active || !pc->valid_lifetime_sensitive) ?
htonl(pc->valid_lifetime) : 0;
op->preferred_lifetime = (ra->active || !pc->preferred_lifetime_sensitive) ?
htonl(pc->preferred_lifetime) : 0;
op->reserved = 0;
op->prefix = ip6_hton(net6_prefix(&addr->prefix));
buf += sizeof(*op);
} }
if (! ic->rdnss_local) if (! ic->rdnss_local)
@ -316,33 +350,34 @@ radv_prepare_ra(struct radv_iface *ifa)
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0) if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
goto done; goto done;
if (p->fib_up)
{
FIB_WALK(&p->routes, struct radv_route, rt)
{
/* Skip invalid routes that are past linger timeout but still not pruned */
if (!rt->valid && ((rt->changed + ic->route_linger_time S) <= now))
continue;
if (radv_prepare_route(ifa, rt, &buf, bufend) < 0)
goto done;
}
FIB_WALK_END;
}
done: done:
ifa->plen = buf - bufstart; ifa->plen = buf - bufstart;
} }
void void
radv_send_ra(struct radv_iface *ifa, int shutdown) radv_send_ra(struct radv_iface *ifa)
{ {
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
/* We store prepared RA in tbuf */ /* We store prepared RA in tbuf */
if (!ifa->plen) if (!ifa->plen)
radv_prepare_ra(ifa); radv_prepare_ra(ifa);
if (shutdown)
{
/*
* Modify router lifetime to 0, it is not restored because we suppose that
* the iface will be removed. The preference value also has to be zeroed.
* (RFC 4191 2.2: If router lifetime is 0, the preference value must be 0.)
*/
struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf;
pkt->router_lifetime = 0;
pkt->flags &= ~RA_PREF_MASK;
}
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
} }
@ -352,13 +387,13 @@ static int
radv_rx_hook(sock *sk, uint size) radv_rx_hook(sock *sk, uint size)
{ {
struct radv_iface *ifa = sk->data; struct radv_iface *ifa = sk->data;
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
/* We want just packets from sk->iface */ /* We want just packets from sk->iface */
if (sk->lifindex != sk->iface->index) if (sk->lifindex != sk->iface->index)
return 1; return 1;
if (ipa_equal(sk->faddr, ifa->addr->ip)) if (ipa_equal(sk->faddr, sk->saddr))
return 1; return 1;
if (size < 8) if (size < 8)
@ -408,11 +443,12 @@ radv_err_hook(sock *sk, int err)
int int
radv_sk_open(struct radv_iface *ifa) radv_sk_open(struct radv_iface *ifa)
{ {
sock *sk = sk_new(ifa->ra->p.pool); sock *sk = sk_new(ifa->pool);
sk->type = SK_IP; sk->type = SK_IP;
sk->subtype = SK_IPV6; sk->subtype = SK_IPV6;
sk->dport = ICMPV6_PROTO; sk->dport = ICMPV6_PROTO;
sk->saddr = ifa->addr->ip; sk->saddr = ifa->addr->ip;
sk->vrf = ifa->ra->p.vrf;
sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */ sk->ttl = 255; /* Mandatory for Neighbor Discovery packets */
sk->rx_hook = radv_rx_hook; sk->rx_hook = radv_rx_hook;

View File

@ -12,59 +12,206 @@
/** /**
* DOC: Router Advertisements * DOC: Router Advertisements
* *
* The RAdv protocol is implemented in two files: |radv.c| containing * The RAdv protocol is implemented in two files: |radv.c| containing the
* the interface with BIRD core and the protocol logic and |packets.c| * interface with BIRD core and the protocol logic and |packets.c| handling low
* handling low level protocol stuff (RX, TX and packet formats). * level protocol stuff (RX, TX and packet formats). The protocol does not
* The protocol does not export any routes. * export any routes.
* *
* The RAdv is structured in the usual way - for each handled interface * The RAdv is structured in the usual way - for each handled interface there is
* there is a structure &radv_iface that contains a state related to * a structure &radv_iface that contains a state related to that interface
* that interface together with its resources (a socket, a timer). * together with its resources (a socket, a timer). There is also a prepared RA
* There is also a prepared RA stored in a TX buffer of the socket * stored in a TX buffer of the socket associated with an iface. These iface
* associated with an iface. These iface structures are created * structures are created and removed according to iface events from BIRD core
* and removed according to iface events from BIRD core handled by * handled by radv_if_notify() callback.
* radv_if_notify() callback.
* *
* The main logic of RAdv consists of two functions: * The main logic of RAdv consists of two functions: radv_iface_notify(), which
* radv_iface_notify(), which processes asynchronous events (specified * processes asynchronous events (specified by RA_EV_* codes), and radv_timer(),
* by RA_EV_* codes), and radv_timer(), which triggers sending RAs and * which triggers sending RAs and computes the next timeout.
* computes the next timeout.
* *
* The RAdv protocol could receive routes (through * The RAdv protocol could receive routes (through radv_import_control() and
* radv_import_control() and radv_rt_notify()), but only the * radv_rt_notify()), but only the configured trigger route is tracked (in
* configured trigger route is tracked (in &active var). When a radv * &active var). When a radv protocol is reconfigured, the connected routing
* protocol is reconfigured, the connected routing table is examined * table is examined (in radv_check_active()) to have proper &active value in
* (in radv_check_active()) to have proper &active value in case of * case of the specified trigger prefix was changed.
* the specified trigger prefix was changed.
* *
* Supported standards: * Supported standards:
* - RFC 4861 - main RA standard * - RFC 4861 - main RA standard
* - RFC 4191 - Default Router Preferences and More-Specific Routes
* - RFC 6106 - DNS extensions (RDDNS, DNSSL) * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
* - RFC 4191 (partial) - Default Router Preference
*/ */
static void radv_prune_prefixes(struct radv_iface *ifa);
static void radv_prune_routes(struct radv_proto *p);
/* Invalidate cached RA packet */
static inline void radv_invalidate(struct radv_iface *ifa)
{ ifa->plen = 0; }
static void static void
radv_timer(timer *tm) radv_timer(timer *tm)
{ {
struct radv_iface *ifa = tm->data; struct radv_iface *ifa = tm->data;
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
btime now = current_time();
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name); RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
radv_send_ra(ifa, 0); if (ifa->valid_time <= now)
radv_invalidate(ifa);
if (ifa->prune_time <= now)
radv_prune_prefixes(ifa);
if (p->prune_time <= now)
radv_prune_routes(p);
radv_send_ra(ifa);
/* Update timer */ /* Update timer */
ifa->last = now; ifa->last = now;
unsigned after = ifa->cf->min_ra_int; btime t = ifa->cf->min_ra_int S;
after += random() % (ifa->cf->max_ra_int - ifa->cf->min_ra_int + 1); btime r = (ifa->cf->max_ra_int - ifa->cf->min_ra_int) S;
t += random() % (r + 1);
if (ifa->initial) if (ifa->initial)
{
t = MIN(t, MAX_INITIAL_RTR_ADVERT_INTERVAL);
ifa->initial--; ifa->initial--;
}
if (ifa->initial) tm_start(ifa->timer, t);
after = MIN(after, MAX_INITIAL_RTR_ADVERT_INTERVAL); }
tm_start(ifa->timer, after); static struct radv_prefix_config default_prefix = {
.onlink = 1,
.autonomous = 1,
.valid_lifetime = DEFAULT_VALID_LIFETIME,
.preferred_lifetime = DEFAULT_PREFERRED_LIFETIME
};
static struct radv_prefix_config dead_prefix = {
};
/* Find a corresponding config for the given prefix */
static struct radv_prefix_config *
radv_prefix_match(struct radv_iface *ifa, net_addr_ip6 *px)
{
struct radv_proto *p = ifa->ra;
struct radv_config *cf = (struct radv_config *) (p->p.cf);
struct radv_prefix_config *pc;
WALK_LIST(pc, ifa->cf->pref_list)
if (net_in_net_ip6(px, &pc->prefix))
return pc;
WALK_LIST(pc, cf->pref_list)
if (net_in_net_ip6(px, &pc->prefix))
return pc;
return &default_prefix;
}
/*
* Go through the list of prefixes, compare them with configs and decide if we
* want them or not.
*/
static void
radv_prepare_prefixes(struct radv_iface *ifa)
{
struct radv_proto *p = ifa->ra;
struct radv_prefix *pfx, *next;
btime now = current_time();
/* First mark all the prefixes as unused */
WALK_LIST(pfx, ifa->prefixes)
pfx->mark = 0;
/* Find all the prefixes we want to use and make sure they are in the list. */
struct ifa *addr;
WALK_LIST(addr, ifa->iface->addrs)
{
if ((addr->prefix.type != NET_IP6) ||
(addr->scope <= SCOPE_LINK))
continue;
net_addr_ip6 *prefix = (void *) &addr->prefix;
struct radv_prefix_config *pc = radv_prefix_match(ifa, prefix);
if (!pc || pc->skip)
continue;
/* Do we have it already? */
struct radv_prefix *existing = NULL;
WALK_LIST(pfx, ifa->prefixes)
if (net_equal_ip6(&pfx->prefix, prefix))
{
existing = pfx;
break;
}
if (!existing)
{
RADV_TRACE(D_EVENTS, "Adding new prefix %N on %s",
prefix, ifa->iface->name);
existing = mb_allocz(ifa->pool, sizeof *existing);
net_copy_ip6(&existing->prefix, prefix);
add_tail(&ifa->prefixes, NODE existing);
}
/*
* Update the information (it may have changed, or even bring a prefix back
* to life).
*/
existing->valid = 1;
existing->changed = now;
existing->mark = 1;
existing->cf = pc;
}
WALK_LIST_DELSAFE(pfx, next, ifa->prefixes)
{
if (pfx->valid && !pfx->mark)
{
RADV_TRACE(D_EVENTS, "Invalidating prefix %N on %s",
pfx->prefix, ifa->iface->name);
pfx->valid = 0;
pfx->changed = now;
pfx->cf = &dead_prefix;
}
}
}
static void
radv_prune_prefixes(struct radv_iface *ifa)
{
struct radv_proto *p = ifa->ra;
btime now = current_time();
btime next = TIME_INFINITY;
btime expires = 0;
struct radv_prefix *px, *pxn;
WALK_LIST_DELSAFE(px, pxn, ifa->prefixes)
{
if (!px->valid)
{
expires = px->changed + ifa->cf->prefix_linger_time S;
if (expires <= now)
{
RADV_TRACE(D_EVENTS, "Removing prefix %N on %s",
px->prefix, ifa->iface->name);
rem_node(NODE px);
mb_free(px);
}
else
next = MIN(next, expires);
}
}
ifa->prune_time = next;
} }
static char* ev_name[] = { NULL, "Init", "Change", "RS" }; static char* ev_name[] = { NULL, "Init", "Change", "RS" };
@ -72,7 +219,7 @@ static char* ev_name[] = { NULL, "Init", "Change", "RS" };
void void
radv_iface_notify(struct radv_iface *ifa, int event) radv_iface_notify(struct radv_iface *ifa, int event)
{ {
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
if (!ifa->sk) if (!ifa->sk)
return; return;
@ -82,9 +229,11 @@ radv_iface_notify(struct radv_iface *ifa, int event)
switch (event) switch (event)
{ {
case RA_EV_CHANGE: case RA_EV_CHANGE:
ifa->plen = 0; radv_invalidate(ifa);
case RA_EV_INIT: case RA_EV_INIT:
ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS; ifa->initial = MAX_INITIAL_RTR_ADVERTISEMENTS;
radv_prepare_prefixes(ifa);
radv_prune_prefixes(ifa);
break; break;
case RA_EV_RS: case RA_EV_RS:
@ -92,31 +241,25 @@ radv_iface_notify(struct radv_iface *ifa, int event)
} }
/* Update timer */ /* Update timer */
unsigned delta = now - ifa->last; btime t = ifa->last + ifa->cf->min_delay S - current_time();
unsigned after = 0; tm_start(ifa->timer, t);
if (delta < ifa->cf->min_delay)
after = ifa->cf->min_delay - delta;
tm_start(ifa->timer, after);
} }
static void static void
radv_iface_notify_all(struct proto_radv *ra, int event) radv_iface_notify_all(struct radv_proto *p, int event)
{ {
struct radv_iface *ifa; struct radv_iface *ifa;
WALK_LIST(ifa, ra->iface_list) WALK_LIST(ifa, p->iface_list)
radv_iface_notify(ifa, event); radv_iface_notify(ifa, event);
} }
static struct radv_iface * static struct radv_iface *
radv_iface_find(struct proto_radv *ra, struct iface *what) radv_iface_find(struct radv_proto *p, struct iface *what)
{ {
struct radv_iface *ifa; struct radv_iface *ifa;
WALK_LIST(ifa, ra->iface_list) WALK_LIST(ifa, p->iface_list)
if (ifa->iface == what) if (ifa->iface == what)
return ifa; return ifa;
@ -127,59 +270,39 @@ static void
radv_iface_add(struct object_lock *lock) radv_iface_add(struct object_lock *lock)
{ {
struct radv_iface *ifa = lock->data; struct radv_iface *ifa = lock->data;
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
if (! radv_sk_open(ifa)) if (! radv_sk_open(ifa))
{ {
log(L_ERR "%s: Socket open failed on interface %s", ra->p.name, ifa->iface->name); log(L_ERR "%s: Socket open failed on interface %s", p->p.name, ifa->iface->name);
return; return;
} }
radv_iface_notify(ifa, RA_EV_INIT); radv_iface_notify(ifa, RA_EV_INIT);
} }
static inline struct ifa *
find_lladdr(struct iface *iface)
{
struct ifa *a;
WALK_LIST(a, iface->addrs)
if ((a->prefix.type == NET_IP6) && (a->scope == SCOPE_LINK))
return a;
return NULL;
}
static void static void
radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_config *cf) radv_iface_new(struct radv_proto *p, struct iface *iface, struct radv_iface_config *cf)
{ {
pool *pool = ra->p.pool;
struct radv_iface *ifa; struct radv_iface *ifa;
RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name); RADV_TRACE(D_EVENTS, "Adding interface %s", iface->name);
pool *pool = rp_new(p->p.pool, iface->name);
ifa = mb_allocz(pool, sizeof(struct radv_iface)); ifa = mb_allocz(pool, sizeof(struct radv_iface));
ifa->ra = ra; ifa->pool = pool;
ifa->ra = p;
ifa->cf = cf; ifa->cf = cf;
ifa->iface = iface; ifa->iface = iface;
ifa->addr = iface->llv6;
init_list(&ifa->prefixes);
ifa->prune_time = TIME_INFINITY;
add_tail(&ra->iface_list, NODE ifa); add_tail(&p->iface_list, NODE ifa);
ifa->addr = find_lladdr(iface); ifa->timer = tm_new_init(pool, radv_timer, ifa, 0, 0);
if (!ifa->addr)
{
log(L_ERR "%s: Cannot find link-locad addr on interface %s", ra->p.name, iface->name);
return;
}
timer *tm = tm_new(pool);
tm->hook = radv_timer;
tm->data = ifa;
tm->randomize = 0;
tm->recurrent = 0;
ifa->timer = tm;
struct object_lock *lock = olock_new(pool); struct object_lock *lock = olock_new(pool);
lock->addr = IPA_NONE;
lock->type = OBJLOCK_IP; lock->type = OBJLOCK_IP;
lock->port = ICMPV6_PROTO; lock->port = ICMPV6_PROTO;
lock->iface = iface; lock->iface = iface;
@ -193,39 +316,42 @@ radv_iface_new(struct proto_radv *ra, struct iface *iface, struct radv_iface_con
static void static void
radv_iface_remove(struct radv_iface *ifa) radv_iface_remove(struct radv_iface *ifa)
{ {
struct proto_radv *ra = ifa->ra; struct radv_proto *p = ifa->ra;
RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name); RADV_TRACE(D_EVENTS, "Removing interface %s", ifa->iface->name);
rem_node(NODE ifa); rem_node(NODE ifa);
rfree(ifa->sk); rfree(ifa->pool);
rfree(ifa->timer);
rfree(ifa->lock);
mb_free(ifa);
} }
static void static void
radv_if_notify(struct proto *p, unsigned flags, struct iface *iface) radv_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_config *cf = (struct radv_config *) (P->cf);
if (iface->flags & IF_IGNORE) if (iface->flags & IF_IGNORE)
return; return;
if (flags & IF_CHANGE_UP) if (flags & IF_CHANGE_UP)
{ {
struct radv_iface_config *ic = (struct radv_iface_config *) struct radv_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
iface_patt_find(&cf->patt_list, iface, NULL);
/* Ignore non-multicast ifaces */
if (!(iface->flags & IF_MULTICAST))
return;
/* Ignore ifaces without link-local address */
if (!iface->llv6)
return;
if (ic) if (ic)
radv_iface_new(ra, iface, ic); radv_iface_new(p, iface, ic);
return; return;
} }
struct radv_iface *ifa = radv_iface_find(ra, iface); struct radv_iface *ifa = radv_iface_find(p, iface);
if (!ifa) if (!ifa)
return; return;
@ -240,9 +366,9 @@ radv_if_notify(struct proto *p, unsigned flags, struct iface *iface)
} }
static void static void
radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a) radv_ifa_notify(struct proto *P, unsigned flags UNUSED, struct ifa *a)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
if (a->flags & IA_SECONDARY) if (a->flags & IA_SECONDARY)
return; return;
@ -250,7 +376,7 @@ radv_ifa_notify(struct proto *p, unsigned flags UNUSED, struct ifa *a)
if (a->scope <= SCOPE_LINK) if (a->scope <= SCOPE_LINK)
return; return;
struct radv_iface *ifa = radv_iface_find(ra, a->iface); struct radv_iface *ifa = radv_iface_find(p, a->iface);
if (ifa) if (ifa)
radv_iface_notify(ifa, RA_EV_CHANGE); radv_iface_notify(ifa, RA_EV_CHANGE);
@ -269,50 +395,171 @@ radv_net_match_trigger(struct radv_config *cf, net *n)
} }
int int
radv_import_control(struct proto *p, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED) radv_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
{ {
// struct proto_radv *ra = (struct proto_radv *) p; // struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_config *cf = (struct radv_config *) (P->cf);
if (radv_net_match_trigger(cf, (*new)->net)) if (radv_net_match_trigger(cf, (*new)->net))
return RIC_PROCESS; return RIC_PROCESS;
return RIC_DROP; if (cf->propagate_routes)
return RIC_PROCESS;
else
return RIC_DROP;
} }
static void static void
radv_rt_notify(struct proto *p, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs UNUSED) radv_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_config *cf = (struct radv_config *) (P->cf);
struct radv_route *rt;
eattr *ea;
if (radv_net_match_trigger(cf, n)) if (radv_net_match_trigger(cf, n))
{ {
u8 old_active = ra->active; u8 old_active = p->active;
ra->active = !!new; p->active = !!new;
if (ra->active == old_active) if (p->active == old_active)
return; return;
if (ra->active) if (p->active)
RADV_TRACE(D_EVENTS, "Triggered"); RADV_TRACE(D_EVENTS, "Triggered");
else else
RADV_TRACE(D_EVENTS, "Suppressed"); RADV_TRACE(D_EVENTS, "Suppressed");
radv_iface_notify_all(ra, RA_EV_CHANGE); radv_iface_notify_all(p, RA_EV_CHANGE);
return;
} }
if (!cf->propagate_routes)
return;
/*
* Some other route we want to send (or stop sending). Update the cache,
* with marking a removed one as dead or creating a new one as needed.
*
* And yes, we exclude the trigger route on purpose.
*/
if (new)
{
/* Update */
ea = ea_find(attrs, EA_RA_PREFERENCE);
uint preference = ea ? ea->u.data : RA_PREF_MEDIUM;
uint preference_set = !!ea;
ea = ea_find(attrs, EA_RA_LIFETIME);
uint lifetime = ea ? ea->u.data : 0;
uint lifetime_set = !!ea;
if ((preference != RA_PREF_LOW) &&
(preference != RA_PREF_MEDIUM) &&
(preference != RA_PREF_HIGH))
{
log(L_WARN "%s: Invalid ra_preference value %u on route %N",
p->p.name, preference, n->n.addr);
preference = RA_PREF_MEDIUM;
preference_set = 1;
lifetime = 0;
lifetime_set = 1;
}
rt = fib_get(&p->routes, n->n.addr);
/* Ignore update if nothing changed */
if (rt->valid &&
(rt->preference == preference) &&
(rt->preference_set == preference_set) &&
(rt->lifetime == lifetime) &&
(rt->lifetime_set == lifetime_set))
return;
if (p->routes.entries == 18)
log(L_WARN "%s: More than 17 routes exported to RAdv", p->p.name);
rt->valid = 1;
rt->changed = current_time();
rt->preference = preference;
rt->preference_set = preference_set;
rt->lifetime = lifetime;
rt->lifetime_set = lifetime_set;
}
else
{
/* Withdraw */
rt = fib_find(&p->routes, n->n.addr);
if (!rt || !rt->valid)
return;
/* Invalidate the route */
rt->valid = 0;
rt->changed = current_time();
/* Invalidated route will be pruned eventually */
btime expires = rt->changed + cf->max_linger_time S;
p->prune_time = MIN(p->prune_time, expires);
}
radv_iface_notify_all(p, RA_EV_CHANGE);
}
/*
* Cleans up all the dead routes that expired and schedules itself to be run
* again if there are more routes waiting for expiration.
*/
static void
radv_prune_routes(struct radv_proto *p)
{
struct radv_config *cf = (struct radv_config *) (p->p.cf);
btime now = current_time();
btime next = TIME_INFINITY;
btime expires = 0;
/* Should not happen */
if (!p->fib_up)
return;
struct fib_iterator fit;
FIB_ITERATE_INIT(&fit, &p->routes);
again:
FIB_ITERATE_START(&p->routes, &fit, struct radv_route, rt)
{
if (!rt->valid)
{
expires = rt->changed + cf->max_linger_time S;
/* Delete expired nodes */
if (expires <= now)
{
FIB_ITERATE_PUT(&fit);
fib_delete(&p->routes, rt);
goto again;
}
else
next = MIN(next, expires);
}
}
FIB_ITERATE_END;
p->prune_time = next;
} }
static int static int
radv_check_active(struct proto_radv *ra) radv_check_active(struct radv_proto *p)
{ {
struct radv_config *cf = (struct radv_config *) (ra->p.cf); struct radv_config *cf = (struct radv_config *) (p->p.cf);
if (!radv_trigger_valid(cf)) if (!radv_trigger_valid(cf))
return 1; return 1;
struct channel *c = ra->p.main_channel; struct channel *c = p->p.main_channel;
return rt_examine(c->table, &cf->trigger, &ra->p, c->out_filter); return rt_examine(c->table, &cf->trigger, &p->p, c->out_filter);
} }
static void static void
@ -328,26 +575,47 @@ radv_postconfig(struct proto_config *CF)
static struct proto * static struct proto *
radv_init(struct proto_config *CF) radv_init(struct proto_config *CF)
{ {
struct proto *p = proto_new(CF); struct proto *P = proto_new(CF);
p->main_channel = proto_add_channel(p, proto_cf_main_channel(CF)); P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
p->import_control = radv_import_control; P->import_control = radv_import_control;
p->rt_notify = radv_rt_notify; P->rt_notify = radv_rt_notify;
p->if_notify = radv_if_notify; P->if_notify = radv_if_notify;
p->ifa_notify = radv_ifa_notify; P->ifa_notify = radv_ifa_notify;
return p; return P;
}
static void
radv_set_fib(struct radv_proto *p, int up)
{
if (up == p->fib_up)
return;
if (up)
fib_init(&p->routes, p->p.pool, NET_IP6, sizeof(struct radv_route),
OFFSETOF(struct radv_route, n), 4, NULL);
else
fib_free(&p->routes);
p->fib_up = up;
p->prune_time = TIME_INFINITY;
} }
static int static int
radv_start(struct proto *p) radv_start(struct proto *P)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (p->cf); struct radv_config *cf = (struct radv_config *) (P->cf);
init_list(&(ra->iface_list)); init_list(&(p->iface_list));
ra->active = !radv_trigger_valid(cf); p->valid = 1;
p->active = !radv_trigger_valid(cf);
p->fib_up = 0;
radv_set_fib(p, cf->propagate_routes);
p->prune_time = TIME_INFINITY;
return PS_UP; return PS_UP;
} }
@ -356,46 +624,61 @@ static inline void
radv_iface_shutdown(struct radv_iface *ifa) radv_iface_shutdown(struct radv_iface *ifa)
{ {
if (ifa->sk) if (ifa->sk)
radv_send_ra(ifa, 1); {
radv_invalidate(ifa);
radv_send_ra(ifa);
}
} }
static int static int
radv_shutdown(struct proto *p) radv_shutdown(struct proto *P)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
p->valid = 0;
struct radv_iface *ifa; struct radv_iface *ifa;
WALK_LIST(ifa, ra->iface_list) WALK_LIST(ifa, p->iface_list)
radv_iface_shutdown(ifa); radv_iface_shutdown(ifa);
return PS_DOWN; return PS_DOWN;
} }
static int static int
radv_reconfigure(struct proto *p, struct proto_config *CF) radv_reconfigure(struct proto *P, struct proto_config *CF)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
// struct radv_config *old = (struct radv_config *) (p->cf); struct radv_config *old = (struct radv_config *) (P->cf);
struct radv_config *new = (struct radv_config *) CF; struct radv_config *new = (struct radv_config *) CF;
/* if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF)))
* The question is why there is a reconfigure function for RAdv if
* it has almost none internal state so restarting the protocol
* would probably suffice. One small reason is that restarting the
* protocol would lead to sending a RA with Router Lifetime 0
* causing nodes to temporary remove their default routes.
*/
if (!proto_configure_channel(p, &p->main_channel, proto_cf_main_channel(CF)))
return 0; return 0;
p->cf = CF; /* radv_check_active() requires proper p->cf */ P->cf = CF; /* radv_check_active() requires proper P->cf */
ra->active = radv_check_active(ra); p->active = radv_check_active(p);
/* Allocate or free FIB */
radv_set_fib(p, new->propagate_routes);
/* We started to accept routes so we need to refeed them */
if (!old->propagate_routes && new->propagate_routes)
channel_request_feeding(p->p.main_channel);
struct iface *iface; struct iface *iface;
WALK_LIST(iface, iface_list) WALK_LIST(iface, iface_list)
{ {
struct radv_iface *ifa = radv_iface_find(ra, iface); if (!(iface->flags & IF_UP))
continue;
/* Ignore non-multicast ifaces */
if (!(iface->flags & IF_MULTICAST))
continue;
/* Ignore ifaces without link-local address */
if (!iface->llv6)
continue;
struct radv_iface *ifa = radv_iface_find(p, iface);
struct radv_iface_config *ic = (struct radv_iface_config *) struct radv_iface_config *ic = (struct radv_iface_config *)
iface_patt_find(&new->patt_list, iface, NULL); iface_patt_find(&new->patt_list, iface, NULL);
@ -415,7 +698,7 @@ radv_reconfigure(struct proto *p, struct proto_config *CF)
} }
if (!ifa && ic) if (!ifa && ic)
radv_iface_new(ra, iface, ic); radv_iface_new(p, iface, ic);
} }
return 1; return 1;
@ -435,19 +718,53 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src)
} }
static void static void
radv_get_status(struct proto *p, byte *buf) radv_get_status(struct proto *P, byte *buf)
{ {
struct proto_radv *ra = (struct proto_radv *) p; struct radv_proto *p = (struct radv_proto *) P;
if (!ra->active) if (!p->active)
strcpy(buf, "Suppressed"); strcpy(buf, "Suppressed");
} }
static const char *
radv_pref_str(u32 pref)
{
switch (pref)
{
case RA_PREF_LOW:
return "low";
case RA_PREF_MEDIUM:
return "medium";
case RA_PREF_HIGH:
return "high";
default:
return "??";
}
}
/* The buffer has some minimal size */
static int
radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
case EA_RA_PREFERENCE:
bsprintf(buf, "preference: %s", radv_pref_str(a->u.data));
return GA_FULL;
case EA_RA_LIFETIME:
bsprintf(buf, "lifetime");
return GA_NAME;
default:
return GA_UNKNOWN;
}
}
struct protocol proto_radv = { struct protocol proto_radv = {
.name = "RAdv", .name = "RAdv",
.template = "radv%d", .template = "radv%d",
.attr_class = EAP_RADV,
.channel_mask = NB_IP6, .channel_mask = NB_IP6,
.proto_size = sizeof(struct proto_radv), .proto_size = sizeof(struct radv_proto),
.config_size = sizeof(struct radv_config), .config_size = sizeof(struct radv_config),
.postconfig = radv_postconfig, .postconfig = radv_postconfig,
.init = radv_init, .init = radv_init,
@ -455,5 +772,6 @@ struct protocol proto_radv = {
.shutdown = radv_shutdown, .shutdown = radv_shutdown,
.reconfigure = radv_reconfigure, .reconfigure = radv_reconfigure,
.copy_config = radv_copy_config, .copy_config = radv_copy_config,
.get_status = radv_get_status .get_status = radv_get_status,
.get_attr = radv_get_attr
}; };

View File

@ -13,7 +13,7 @@
#include "lib/ip.h" #include "lib/ip.h"
#include "lib/lists.h" #include "lib/lists.h"
#include "lib/socket.h" #include "lib/socket.h"
#include "sysdep/unix/timer.h" #include "lib/timer.h"
#include "lib/resource.h" #include "lib/resource.h"
#include "nest/protocol.h" #include "nest/protocol.h"
#include "nest/iface.h" #include "nest/iface.h"
@ -30,7 +30,7 @@
#define ICMPV6_RA 134 #define ICMPV6_RA 134
#define MAX_INITIAL_RTR_ADVERTISEMENTS 3 #define MAX_INITIAL_RTR_ADVERTISEMENTS 3
#define MAX_INITIAL_RTR_ADVERT_INTERVAL 16 #define MAX_INITIAL_RTR_ADVERT_INTERVAL (16 S_)
#define DEFAULT_MAX_RA_INT 600 #define DEFAULT_MAX_RA_INT 600
#define DEFAULT_MIN_DELAY 3 #define DEFAULT_MIN_DELAY 3
@ -51,6 +51,8 @@ struct radv_config
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */ list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
net_addr trigger; /* Prefix of a trigger route, if defined */ net_addr trigger; /* Prefix of a trigger route, if defined */
u8 propagate_routes; /* Do we propagate more specific routes (RFC 4191)? */
u32 max_linger_time; /* Maximum of interface route_linger_time */
}; };
struct radv_iface_config struct radv_iface_config
@ -60,22 +62,28 @@ struct radv_iface_config
list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */ list rdnss_list; /* Local list of RDNSS configs (struct radv_rdnss_config) */
list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */ list dnssl_list; /* Local list of DNSSL configs (struct radv_dnssl_config) */
u32 min_ra_int; /* Standard options from RFC 4261 */ u32 min_ra_int; /* Standard options from RFC 4861 */
u32 max_ra_int; u32 max_ra_int;
u32 min_delay; u32 min_delay;
u32 prefix_linger_time; /* How long we advertise dead prefixes with lifetime 0 */
u32 route_linger_time; /* How long we advertise dead routes with lifetime 0 */
u8 rdnss_local; /* Global list is not used for RDNSS */ u8 rdnss_local; /* Global list is not used for RDNSS */
u8 dnssl_local; /* Global list is not used for DNSSL */ u8 dnssl_local; /* Global list is not used for DNSSL */
u8 managed; /* Standard options from RFC 4261 */ u8 managed; /* Standard options from RFC 4861 */
u8 other_config; u8 other_config;
u32 link_mtu; u32 link_mtu;
u32 reachable_time; u32 reachable_time;
u32 retrans_timer; u32 retrans_timer;
u32 current_hop_limit; u32 current_hop_limit;
u32 default_lifetime; u32 default_lifetime;
u32 route_lifetime; /* Lifetime for the RFC 4191 routes */
u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */ u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
u8 route_lifetime_sensitive; /* Whether route_lifetime depends on trigger */
u8 default_preference; /* Default Router Preference (RFC 4191) */ u8 default_preference; /* Default Router Preference (RFC 4191) */
u8 route_preference; /* Specific Route Preference (RFC 4191) */
}; };
struct radv_prefix_config struct radv_prefix_config
@ -84,7 +92,7 @@ struct radv_prefix_config
net_addr_ip6 prefix; net_addr_ip6 prefix;
u8 skip; /* Do not include this prefix to RA */ u8 skip; /* Do not include this prefix to RA */
u8 onlink; /* Standard options from RFC 4261 */ u8 onlink; /* Standard options from RFC 4861 */
u8 autonomous; u8 autonomous;
u32 valid_lifetime; u32 valid_lifetime;
u32 preferred_lifetime; u32 preferred_lifetime;
@ -110,29 +118,67 @@ struct radv_dnssl_config
char *domain; /* Domain for DNS search list, in processed form */ char *domain; /* Domain for DNS search list, in processed form */
}; };
/*
* One more specific route as per RFC 4191.
*
* Note that it does *not* contain the next hop field. The next hop is always
* the router sending the advertisment and the more specific route only allows
* overriding the preference of the route.
*/
struct radv_route
{
u32 lifetime; /* Lifetime from an attribute */
u8 lifetime_set; /* Whether lifetime is defined */
u8 preference; /* Preference of the route, RA_PREF_* */
u8 preference_set; /* Whether preference is defined */
u8 valid; /* Whethe route is valid or withdrawn */
btime changed; /* Last time when the route changed */
struct proto_radv struct fib_node n;
};
struct radv_proto
{ {
struct proto p; struct proto p;
list iface_list; /* List of active ifaces */ list iface_list; /* List of active ifaces */
u8 valid; /* Router is valid for forwarding, used for shutdown */
u8 active; /* Whether radv is active w.r.t. triggers */ u8 active; /* Whether radv is active w.r.t. triggers */
u8 fib_up; /* FIB table (routes) is initialized */
struct fib routes; /* FIB table of specific routes (struct radv_route) */
btime prune_time; /* Next time of route table pruning */
};
struct radv_prefix /* One prefix we advertise */
{
node n;
net_addr_ip6 prefix;
u8 valid; /* Is the prefix valid? If not, we advertise it
with 0 lifetime, so clients stop using it */
u8 mark; /* A temporary mark for processing */
btime changed; /* Last time when the prefix changed */
struct radv_prefix_config *cf; /* The config tied to this prefix */
}; };
struct radv_iface struct radv_iface
{ {
node n; node n;
struct proto_radv *ra; struct radv_proto *ra;
struct radv_iface_config *cf; /* Related config, must be updated in reconfigure */ struct radv_iface_config *cf; /* Related config, must be updated in reconfigure */
struct iface *iface; struct iface *iface;
struct ifa *addr; /* Link-local address of iface */ struct ifa *addr; /* Link-local address of iface */
struct pool *pool; /* A pool for interface-specific things */
list prefixes; /* The prefixes we advertise (struct radv_prefix) */
btime prune_time; /* Next time of prefix list pruning */
btime valid_time; /* Cached packet is valid until first linger timeout */
timer *timer; timer *timer;
struct object_lock *lock; struct object_lock *lock;
sock *sk; sock *sk;
bird_clock_t last; /* Time of last sending of RA */ btime last; /* Time of last sending of RA */
u16 plen; /* Length of prepared RA in tbuf, or 0 if not valid */ u16 plen; /* Length of prepared RA in tbuf, or 0 if not valid */
byte initial; /* List of active ifaces */ byte initial; /* How many RAs are still to be sent as initial */
}; };
#define RA_EV_INIT 1 /* Switch to initial mode */ #define RA_EV_INIT 1 /* Switch to initial mode */
@ -145,14 +191,17 @@ struct radv_iface
#define RA_PREF_HIGH 0x08 #define RA_PREF_HIGH 0x08
#define RA_PREF_MASK 0x18 #define RA_PREF_MASK 0x18
/* Attributes */
#define EA_RA_PREFERENCE EA_CODE(EAP_RADV, 0)
#define EA_RA_LIFETIME EA_CODE(EAP_RADV, 1)
#ifdef LOCAL_DEBUG #ifdef LOCAL_DEBUG
#define RADV_FORCE_DEBUG 1 #define RADV_FORCE_DEBUG 1
#else #else
#define RADV_FORCE_DEBUG 0 #define RADV_FORCE_DEBUG 0
#endif #endif
#define RADV_TRACE(flags, msg, args...) do { if ((ra->p.debug & flags) || RADV_FORCE_DEBUG) \ #define RADV_TRACE(flags, msg, args...) do { if ((p->p.debug & flags) || RADV_FORCE_DEBUG) \
log(L_TRACE "%s: " msg, ra->p.name , ## args ); } while(0) log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
/* radv.c */ /* radv.c */
@ -160,7 +209,7 @@ void radv_iface_notify(struct radv_iface *ifa, int event);
/* packets.c */ /* packets.c */
int radv_process_domain(struct radv_dnssl_config *cf); int radv_process_domain(struct radv_dnssl_config *cf);
void radv_send_ra(struct radv_iface *ifa, int shutdown); void radv_send_ra(struct radv_iface *ifa);
int radv_sk_open(struct radv_iface *ifa); int radv_sk_open(struct radv_iface *ifa);

View File

@ -56,9 +56,10 @@ rip_proto_start: proto_start rip_variant
init_list(&RIP_CFG->patt_list); init_list(&RIP_CFG->patt_list);
RIP_CFG->rip2 = $2; RIP_CFG->rip2 = $2;
RIP_CFG->ecmp = rt_default_ecmp;
RIP_CFG->infinity = RIP_DEFAULT_INFINITY; RIP_CFG->infinity = RIP_DEFAULT_INFINITY;
RIP_CFG->min_timeout_time = 60; RIP_CFG->min_timeout_time = 60 S_;
RIP_CFG->max_garbage_time = 60; RIP_CFG->max_garbage_time = 60 S_;
}; };
rip_proto_item: rip_proto_item:
@ -92,6 +93,7 @@ rip_iface_start:
RIP_IFACE->split_horizon = 1; RIP_IFACE->split_horizon = 1;
RIP_IFACE->poison_reverse = 1; RIP_IFACE->poison_reverse = 1;
RIP_IFACE->check_zero = 1; RIP_IFACE->check_zero = 1;
RIP_IFACE->check_link = 1;
RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1; RIP_IFACE->ttl_security = rip_cfg_is_v2() ? 0 : 1;
RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0; RIP_IFACE->rx_buffer = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0; RIP_IFACE->tx_length = rip_cfg_is_v2() ? RIP_MAX_PKT_LENGTH : 0;
@ -147,9 +149,9 @@ rip_iface_item:
| SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; } | SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; }
| POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; } | POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
| CHECK ZERO bool { RIP_IFACE->check_zero = $3; } | CHECK ZERO bool { RIP_IFACE->check_zero = $3; }
| UPDATE TIME expr { RIP_IFACE->update_time = $3; if ($3<=0) cf_error("Update time must be positive"); } | UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3; if ($3<=0) cf_error("Timeout time must be positive"); } | TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3; if ($3<=0) cf_error("Garbage time must be positive"); } | GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); } | ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); } | RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); } | TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }

View File

@ -189,7 +189,10 @@ rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
* have the same CSN. We are using real time, but enforcing monotonicity. * have the same CSN. We are using real time, but enforcing monotonicity.
*/ */
if (ifa->cf->auth_type == RIP_AUTH_CRYPTO) if (ifa->cf->auth_type == RIP_AUTH_CRYPTO)
ifa->csn = (ifa->csn < (u32) now_real) ? (u32) now_real : ifa->csn + 1; {
u32 now_real = (u32) (current_real_time() TO_S);
ifa->csn = (ifa->csn < now_real) ? now_real : ifa->csn + 1;
}
} }
static void static void
@ -434,6 +437,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
byte *max = rip_tx_buffer(ifa) + ifa->tx_plen - byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
(rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH); (rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
ip_addr last_next_hop = IPA_NONE; ip_addr last_next_hop = IPA_NONE;
btime now_ = current_time();
int send = 0; int send = 0;
struct rip_packet *pkt = (void *) pos; struct rip_packet *pkt = (void *) pos;
@ -450,7 +454,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
/* Stale entries that should be removed */ /* Stale entries that should be removed */
if ((en->valid == RIP_ENTRY_STALE) && if ((en->valid == RIP_ENTRY_STALE) &&
((en->changed + (bird_clock_t) ifa->cf->garbage_time) <= now)) ((en->changed + ifa->cf->garbage_time) <= now_))
goto next_entry; goto next_entry;
/* Triggered updates */ /* Triggered updates */
@ -540,7 +544,7 @@ break_loop:
* activating the new one. * activating the new one.
*/ */
void void
rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed) rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed)
{ {
DBG("RIP: Opening TX session to %I on %s\n", addr, ifa->iface->name); DBG("RIP: Opening TX session to %I on %s\n", addr, ifa->iface->name);
@ -591,6 +595,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
byte *pos = (byte *) pkt + sizeof(struct rip_packet); byte *pos = (byte *) pkt + sizeof(struct rip_packet);
byte *end = (byte *) pkt + plen; byte *end = (byte *) pkt + plen;
btime now_ = current_time();
for (; pos < end; pos += RIP_BLOCK_LENGTH) for (; pos < end; pos += RIP_BLOCK_LENGTH)
{ {
@ -638,7 +643,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
.next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr, .next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
.metric = rte.metric, .metric = rte.metric,
.tag = rte.tag, .tag = rte.tag,
.expires = now + ifa->cf->timeout_time .expires = now_ + ifa->cf->timeout_time
}; };
rip_update_rte(p, &rte.net, &new); rip_update_rte(p, &rte.net, &new);
@ -669,8 +674,7 @@ rip_rx_hook(sock *sk, uint len)
sk->iface->name, sk->faddr, sk->laddr); sk->iface->name, sk->faddr, sk->laddr);
/* Silently ignore my own packets */ /* Silently ignore my own packets */
/* FIXME: Better local address check */ if (ipa_equal(sk->faddr, sk->saddr))
if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
return 1; return 1;
if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr)) if (rip_is_ng(p) && !ipa_is_link_local(sk->faddr))
@ -706,7 +710,7 @@ rip_rx_hook(sock *sk, uint len)
if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH) if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
DROP("invalid length", plen); DROP("invalid length", plen);
n->last_seen = now; n->last_seen = current_time();
rip_update_bfd(p, n); rip_update_bfd(p, n);
switch (pkt->command) switch (pkt->command)
@ -742,14 +746,8 @@ rip_open_socket(struct rip_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 = rip_is_v2(p) ? ifa->iface->addr4->ip : ifa->iface->llv6->ip;
/* sk->vrf = p->p.vrf;
* For RIPv2, we explicitly choose a primary address, mainly to ensure that
* RIP and BFD uses the same one. For RIPng, we left it to kernel, which
* should choose some link-local address based on the same scope rule.
*/
if (rip_is_v2(p))
sk->saddr = ifa->iface->addr->ip;
sk->rx_hook = rip_rx_hook; sk->rx_hook = rip_rx_hook;
sk->tx_hook = rip_tx_hook; sk->tx_hook = rip_tx_hook;

View File

@ -364,7 +364,7 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
/* Activate triggered updates */ /* Activate triggered updates */
if (en->metric != old_metric) if (en->metric != old_metric)
{ {
en->changed = now; en->changed = current_time();
rip_trigger_update(p); rip_trigger_update(p);
} }
} }
@ -506,10 +506,10 @@ rip_iface_start(struct rip_iface *ifa)
TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name); TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
ifa->next_regular = now + (random() % ifa->cf->update_time) + 1; ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
ifa->next_triggered = now; /* Available immediately */ ifa->next_triggered = current_time(); /* Available immediately */
ifa->want_triggered = 1; /* All routes in triggered update */ ifa->want_triggered = 1; /* All routes in triggered update */
tm_start(ifa->timer, 1); /* Or 100 ms */ tm_start(ifa->timer, 100 MS);
ifa->up = 1; ifa->up = 1;
if (!ifa->cf->passive) if (!ifa->cf->passive)
@ -630,13 +630,19 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
else if (ic->mode == RIP_IM_MULTICAST) else if (ic->mode == RIP_IM_MULTICAST)
ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS; ifa->addr = rip_is_v2(p) ? IP4_RIP_ROUTERS : IP6_RIP_ROUTERS;
else /* Broadcast */ else /* Broadcast */
ifa->addr = iface->addr->brd; ifa->addr = iface->addr4->brd;
/*
* The above is just a workaround for BSD as it can't send broadcasts
* to 255.255.255.255. BSD systems need the network broadcast address instead.
*
* TODO: move this to sysdep code
*/
init_list(&ifa->neigh_list); init_list(&ifa->neigh_list);
add_tail(&p->iface_list, NODE ifa); add_tail(&p->iface_list, NODE ifa);
ifa->timer = tm_new_set(p->p.pool, rip_iface_timer, ifa, 0, 0); ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
struct object_lock *lock = olock_new(p->p.pool); struct object_lock *lock = olock_new(p->p.pool);
lock->type = OBJLOCK_UDP; lock->type = OBJLOCK_UDP;
@ -684,8 +690,8 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
rip_iface_update_buffers(ifa); rip_iface_update_buffers(ifa);
if (ifa->next_regular > (now + (bird_clock_t) new->update_time)) if (ifa->next_regular > (current_time() + new->update_time))
ifa->next_regular = now + (random() % new->update_time) + 1; ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
if (new->check_link != old->check_link) if (new->check_link != old->check_link)
rip_iface_update_state(ifa); rip_iface_update_state(ifa);
@ -706,7 +712,11 @@ rip_reconfigure_ifaces(struct rip_proto *p, struct rip_config *cf)
WALK_LIST(iface, iface_list) WALK_LIST(iface, iface_list)
{ {
if (! (iface->flags & IF_UP)) if (!(iface->flags & IF_UP))
continue;
/* Ignore ifaces without appropriate address */
if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
continue; continue;
struct rip_iface *ifa = rip_find_iface(p, iface); struct rip_iface *ifa = rip_find_iface(p, iface);
@ -744,6 +754,10 @@ rip_if_notify(struct proto *P, unsigned flags, struct iface *iface)
{ {
struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL); struct rip_iface_config *ic = (void *) iface_patt_find(&cf->patt_list, iface, NULL);
/* Ignore ifaces without appropriate address */
if (rip_is_v2(p) ? !iface->addr4 : !iface->llv6)
return;
if (ic) if (ic)
rip_add_iface(p, iface, ic); rip_add_iface(p, iface, ic);
@ -802,8 +816,9 @@ rip_timer(timer *t)
struct rip_iface *ifa; struct rip_iface *ifa;
struct rip_neighbor *n, *nn; struct rip_neighbor *n, *nn;
struct fib_iterator fit; struct fib_iterator fit;
bird_clock_t next = now + MIN(cf->min_timeout_time, cf->max_garbage_time); btime now_ = current_time();
bird_clock_t expires = 0; btime next = now_ + MIN(cf->min_timeout_time, cf->max_garbage_time);
btime expires = 0;
TRACE(D_EVENTS, "Main timer fired"); TRACE(D_EVENTS, "Main timer fired");
@ -818,7 +833,7 @@ rip_timer(timer *t)
/* Checking received routes for timeout and for dead neighbors */ /* Checking received routes for timeout and for dead neighbors */
for (rp = &en->routes; rt = *rp; /* rp = &rt->next */) for (rp = &en->routes; rt = *rp; /* rp = &rt->next */)
{ {
if (!rip_valid_rte(rt) || (rt->expires <= now)) if (!rip_valid_rte(rt) || (rt->expires <= now_))
{ {
rip_remove_rte(p, rp); rip_remove_rte(p, rp);
changed = 1; changed = 1;
@ -848,7 +863,7 @@ rip_timer(timer *t)
{ {
expires = en->changed + cf->max_garbage_time; expires = en->changed + cf->max_garbage_time;
if (expires <= now) if (expires <= now_)
{ {
// TRACE(D_EVENTS, "entry is too old: %N", en->n.addr); // TRACE(D_EVENTS, "entry is too old: %N", en->n.addr);
en->valid = 0; en->valid = 0;
@ -876,20 +891,20 @@ rip_timer(timer *t)
{ {
expires = n->last_seen + n->ifa->cf->timeout_time; expires = n->last_seen + n->ifa->cf->timeout_time;
if (expires <= now) if (expires <= now_)
rip_remove_neighbor(p, n); rip_remove_neighbor(p, n);
else else
next = MIN(next, expires); next = MIN(next, expires);
} }
tm_start(p->timer, MAX(next - now, 1)); tm_start(p->timer, MAX(next - now_, 100 MS));
} }
static inline void static inline void
rip_kick_timer(struct rip_proto *p) rip_kick_timer(struct rip_proto *p)
{ {
if (p->timer->expires > (now + 1)) if (p->timer->expires > (current_time() + 100 MS))
tm_start(p->timer, 1); /* Or 100 ms */ tm_start(p->timer, 100 MS);
} }
/** /**
@ -907,7 +922,8 @@ rip_iface_timer(timer *t)
{ {
struct rip_iface *ifa = t->data; struct rip_iface *ifa = t->data;
struct rip_proto *p = ifa->rip; struct rip_proto *p = ifa->rip;
bird_clock_t period = ifa->cf->update_time; btime now_ = current_time();
btime period = ifa->cf->update_time;
if (ifa->cf->passive) if (ifa->cf->passive)
return; return;
@ -916,40 +932,40 @@ rip_iface_timer(timer *t)
if (ifa->tx_active) if (ifa->tx_active)
{ {
if (now < (ifa->next_regular + period)) if (now_ < (ifa->next_regular + period))
{ tm_start(ifa->timer, 1); return; } { tm_start(ifa->timer, 100 MS); return; }
/* We are too late, reset is done by rip_send_table() */ /* We are too late, reset is done by rip_send_table() */
log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name); log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
} }
if (now >= ifa->next_regular) if (now_ >= ifa->next_regular)
{ {
/* Send regular update, set timer for next period (or following one if necessay) */ /* Send regular update, set timer for next period (or following one if necessay) */
TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name); TRACE(D_EVENTS, "Sending regular updates for %s", ifa->iface->name);
rip_send_table(p, ifa, ifa->addr, 0); rip_send_table(p, ifa, ifa->addr, 0);
ifa->next_regular += period * (1 + ((now - ifa->next_regular) / period)); ifa->next_regular += period * (1 + ((now_ - ifa->next_regular) / period));
ifa->want_triggered = 0; ifa->want_triggered = 0;
p->triggered = 0; p->triggered = 0;
} }
else if (ifa->want_triggered && (now >= ifa->next_triggered)) else if (ifa->want_triggered && (now_ >= ifa->next_triggered))
{ {
/* Send triggered update, enforce interval between triggered updates */ /* Send triggered update, enforce interval between triggered updates */
TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name); TRACE(D_EVENTS, "Sending triggered updates for %s", ifa->iface->name);
rip_send_table(p, ifa, ifa->addr, ifa->want_triggered); rip_send_table(p, ifa, ifa->addr, ifa->want_triggered);
ifa->next_triggered = now + MIN(5, period / 2 + 1); ifa->next_triggered = now_ + MIN(5 S, period / 2);
ifa->want_triggered = 0; ifa->want_triggered = 0;
p->triggered = 0; p->triggered = 0;
} }
tm_start(ifa->timer, ifa->want_triggered ? 1 : (ifa->next_regular - now)); tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
} }
static inline void static inline void
rip_iface_kick_timer(struct rip_iface *ifa) rip_iface_kick_timer(struct rip_iface *ifa)
{ {
if (ifa->timer->expires > (now + 1)) if (ifa->timer->expires > (current_time() + 100 MS))
tm_start(ifa->timer, 1); /* Or 100 ms */ tm_start(ifa->timer, 100 MS);
} }
static void static void
@ -970,7 +986,7 @@ rip_trigger_update(struct rip_proto *p)
continue; continue;
TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name); TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
ifa->want_triggered = now; ifa->want_triggered = current_time();
rip_iface_kick_timer(ifa); rip_iface_kick_timer(ifa);
} }
@ -1095,7 +1111,7 @@ rip_start(struct proto *P)
fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6, fib_init(&p->rtable, P->pool, cf->rip2 ? NET_IP4 : NET_IP6,
sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL); sizeof(struct rip_entry), OFFSETOF(struct rip_entry, n), 0, NULL);
p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte)); p->rte_slab = sl_new(P->pool, sizeof(struct rip_rte));
p->timer = tm_new_set(P->pool, rip_timer, p, 0, 0); p->timer = tm_new_init(P->pool, rip_timer, p, 0, 0);
p->rip2 = cf->rip2; p->rip2 = cf->rip2;
p->ecmp = cf->ecmp; p->ecmp = cf->ecmp;
@ -1180,7 +1196,7 @@ rip_show_interfaces(struct proto *P, char *iff)
} }
cli_msg(-1021, "%s:", p->p.name); cli_msg(-1021, "%s:", p->p.name);
cli_msg(-1021, "%-10s %-6s %6s %6s %6s", cli_msg(-1021, "%-10s %-6s %6s %6s %7s",
"Interface", "State", "Metric", "Nbrs", "Timer"); "Interface", "State", "Metric", "Nbrs", "Timer");
WALK_LIST(ifa, p->iface_list) WALK_LIST(ifa, p->iface_list)
@ -1193,8 +1209,9 @@ rip_show_interfaces(struct proto *P, char *iff)
if (n->last_seen) if (n->last_seen)
nbrs++; nbrs++;
int timer = MAX(ifa->next_regular - now, 0); btime now_ = current_time();
cli_msg(-1021, "%-10s %-6s %6u %6u %6u", btime timer = (ifa->next_regular > now_) ? (ifa->next_regular - now_) : 0;
cli_msg(-1021, "%-10s %-6s %6u %6u %7t",
ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer); ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
} }
@ -1216,7 +1233,7 @@ rip_show_neighbors(struct proto *P, char *iff)
} }
cli_msg(-1022, "%s:", p->p.name); cli_msg(-1022, "%s:", p->p.name);
cli_msg(-1022, "%-25s %-10s %6s %6s %6s", cli_msg(-1022, "%-25s %-10s %6s %6s %7s",
"IP address", "Interface", "Metric", "Routes", "Seen"); "IP address", "Interface", "Metric", "Routes", "Seen");
WALK_LIST(ifa, p->iface_list) WALK_LIST(ifa, p->iface_list)
@ -1229,8 +1246,8 @@ rip_show_neighbors(struct proto *P, char *iff)
if (!n->last_seen) if (!n->last_seen)
continue; continue;
int timer = now - n->last_seen; btime timer = current_time() - n->last_seen;
cli_msg(-1022, "%-25I %-10s %6u %6u %6u", cli_msg(-1022, "%-25I %-10s %6u %6u %7t",
n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer); n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
} }
} }
@ -1248,9 +1265,9 @@ rip_dump(struct proto *P)
i = 0; i = 0;
FIB_WALK(&p->rtable, struct rip_entry, en) FIB_WALK(&p->rtable, struct rip_entry, en)
{ {
debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %d s\n", debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
i++, en->n.addr, en->next_hop, en->iface->name, i++, en->n.addr, en->next_hop, en->iface->name,
en->valid, en->metric, now - en->changed); en->valid, en->metric, current_time() - en->changed);
} }
FIB_WALK_END; FIB_WALK_END;

View File

@ -24,7 +24,7 @@
#include "lib/resource.h" #include "lib/resource.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 RIP_V1 1 #define RIP_V1 1
@ -38,9 +38,9 @@
#define RIP_DEFAULT_ECMP_LIMIT 16 #define RIP_DEFAULT_ECMP_LIMIT 16
#define RIP_DEFAULT_INFINITY 16 #define RIP_DEFAULT_INFINITY 16
#define RIP_DEFAULT_UPDATE_TIME 30 #define RIP_DEFAULT_UPDATE_TIME (30 S_)
#define RIP_DEFAULT_TIMEOUT_TIME 180 #define RIP_DEFAULT_TIMEOUT_TIME (180 S_)
#define RIP_DEFAULT_GARBAGE_TIME 120 #define RIP_DEFAULT_GARBAGE_TIME (120 S_)
struct rip_config struct rip_config
@ -52,8 +52,8 @@ struct rip_config
u8 ecmp; /* Maximum number of nexthops in ECMP route, or 0 */ u8 ecmp; /* Maximum number of nexthops in ECMP route, or 0 */
u8 infinity; /* Maximum metric value, representing infinity */ u8 infinity; /* Maximum metric value, representing infinity */
u32 min_timeout_time; /* Minimum of interface timeout_time */ btime min_timeout_time; /* Minimum of interface timeout_time */
u32 max_garbage_time; /* Maximum of interface garbage_time */ btime max_garbage_time; /* Maximum of interface garbage_time */
}; };
struct rip_iface_config struct rip_iface_config
@ -78,9 +78,9 @@ struct rip_iface_config
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */ u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos; int tx_tos;
int tx_priority; int tx_priority;
u32 update_time; /* Periodic update interval */ btime update_time; /* Periodic update interval */
u32 timeout_time; /* Route expiration timeout */ btime timeout_time; /* Route expiration timeout */
u32 garbage_time; /* Unreachable entry GC timeout */ btime garbage_time; /* Unreachable entry GC timeout */
list *passwords; /* Passwords for authentication */ list *passwords; /* Passwords for authentication */
}; };
@ -120,14 +120,14 @@ struct rip_iface
list neigh_list; /* List of iface neighbors (struct rip_neighbor) */ list neigh_list; /* List of iface neighbors (struct rip_neighbor) */
/* Update scheduling */ /* Update scheduling */
bird_clock_t next_regular; /* Next time when regular update should be called */ btime next_regular; /* Next time when regular update should be called */
bird_clock_t next_triggered; /* Next time when triggerd update may be called */ btime next_triggered; /* Next time when triggerd update may be called */
bird_clock_t want_triggered; /* Nonzero if triggered update is scheduled */ btime want_triggered; /* Nonzero if triggered update is scheduled */
/* Active update */ /* Active update */
int tx_active; /* Update session is active */ int tx_active; /* Update session is active */
ip_addr tx_addr; /* Update session destination address */ ip_addr tx_addr; /* Update session destination address */
bird_clock_t tx_changed; /* Minimal changed time for triggered update */ btime tx_changed; /* Minimal changed time for triggered update */
struct fib_iterator tx_fit; /* FIB iterator in RIP routing table (p.rtable) */ struct fib_iterator tx_fit; /* FIB iterator in RIP routing table (p.rtable) */
}; };
@ -137,7 +137,7 @@ struct rip_neighbor
struct rip_iface *ifa; /* Associated interface, may be NULL if stale */ struct rip_iface *ifa; /* Associated interface, may be NULL if stale */
struct neighbor *nbr; /* Associaded core neighbor, may be NULL if stale */ struct neighbor *nbr; /* Associaded core neighbor, may be NULL if stale */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */
bird_clock_t last_seen; /* Time of last received and accepted message */ btime last_seen; /* Time of last received and accepted message */
u32 uc; /* Use count, number of routes linking the neighbor */ u32 uc; /* Use count, number of routes linking the neighbor */
u32 csn; /* Last received crypto sequence number */ u32 csn; /* Last received crypto sequence number */
}; };
@ -153,7 +153,7 @@ struct rip_entry
struct iface *iface; /* Outgoing route iface (for next hop) */ struct iface *iface; /* Outgoing route iface (for next hop) */
ip_addr next_hop; /* Outgoing route next hop */ ip_addr next_hop; /* Outgoing route next hop */
bird_clock_t changed; /* Last time when the outgoing route metric changed */ btime changed; /* Last time when the outgoing route metric changed */
struct fib_node n; struct fib_node n;
}; };
@ -167,7 +167,7 @@ struct rip_rte
u16 metric; /* Route metric (after increase) */ u16 metric; /* Route metric (after increase) */
u16 tag; /* Route tag */ u16 tag; /* Route tag */
bird_clock_t expires; /* Time of route expiration */ btime expires; /* Time of route expiration */
}; };
@ -211,7 +211,7 @@ void rip_show_neighbors(struct proto *P, char *iff);
/* packets.c */ /* packets.c */
void rip_send_request(struct rip_proto *p, struct rip_iface *ifa); void rip_send_request(struct rip_proto *p, struct rip_iface *ifa);
void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, bird_clock_t changed); void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed);
int rip_open_socket(struct rip_iface *ifa); int rip_open_socket(struct rip_iface *ifa);

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