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
/configure
/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 VPNv4 and VPNv6 network types
o Support for VPNv4 and VPNv6 networks
o Microsecond timers infrastructure
o Basic VRF support
o Babel: Support for dual-stack IPv4/IPv6
o Babel: Many improvements and bugfixes
o Major BGP protocol redesign
o Full support for Multiprotocol BGP
o BGP multicast support (SAFI 2)
o BGP flowspec support (RFC 5575)
o BGP with MPLS labels (RFC 3107)
o BGP MPLS/VPN support (RFC 4364)
o BGP 6PE - IPv6 NLRI over IPv4 MPLS (RFC 4798)
o BGP IPv4 NLRI with an IPv6 Next Hop (RFC 5549)
o BGP Confederations (RFC 5065)
o BGP: Simplify igp table options
o BGP Shutdown communication (RFC 8203)
o BGP: Allow exchanging LOCAL_PREF with eBGP peers
o BGP: Allow to specify interface for regular sessions
o Babel support restored
o Static: Minor overhaul
o Netlink: Default kernel metric changed to 32
o Flowspec: Limit tcp mask length to 12 bits
o Update of show route command
Notes:
Definitions of OSPFv2, OSPFv3 and RIP NG protocols now use keywords
'ospf v2', 'ospf v3' and 'rip ng' instead of 'ospf2', 'ospf3' and 'ripng'.
Flows and ROAs no longer use phony next hops, so there is no need to use
'drop' or 'unreachable' in their static route definitions.
See doc/bird.conf.example2 for configuration examples.
Version 2.0.0-pre0 (2016-12-07)
o Integrated IPv4 + IPv6 design
o Major BGP protocol redesign
o BGP multicast support (SAFI 2)
o BGP flowspec support (RFC 5575)
o OSPF: Support of address families in OSPFv3
o OSPF: Enable ECMP and Link detection by default
o RAdv: Support for more specific routes (RFC 4191)
o RAdv: Proper handling of prefix retraction
o RIP: Enable ECMP and Link detection by default
o Redesign of RPKI handling
o New RPKI-Router protocol
o Static: Minor overhaul
o Static: Support for all new route types
o Kenrel: Default Linux kernel metric changed to 32
o Kernel: Fix IPv6 ECMP handling with Linux 4.11+
o Update of show route command
o BIRD client persistent history
o New build system
o Unit tests
o ...
Notes:
Protocols and tables are now connected using explicit channels, most related
protocol options (table, import, export, ...) are now channel options. See
doc/bird.conf.example2 for configuration examples.
Tables are now defined with appropriate net type keyword. Protocols and tables
are now connected by explicit channels, most related protocol options (table,
import, export, ...) are now channel options. See doc/bird.conf.example2 for
configuration examples. Some options were removed/replaced.
Version 1.6.3 (2016-12-21)

4
README
View File

@ -6,7 +6,7 @@
(c) 1998--2008 Martin Mares <mj@ucw.cz>
(c) 1998--2000 Pavel Machek <pavel@ucw.cz>
(c) 1998--2008 Ondrej Filip <feela@network.cz>
(c) 2009--2016 CZ.NIC z.s.p.o.
(c) 2009--2017 CZ.NIC z.s.p.o.
================================================================================
@ -19,7 +19,7 @@ Public License.
What do we support
==================
o Both IPv4 and IPv6 (use --enable-ipv6 when configuring)
o Both IPv4 and IPv6
o Multiple routing tables
o Border Gateway Protocol (BGPv4)
o Routing Information Protocol (RIPv2, RIPng)

45
TODO
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"
])
AC_DEFUN([BIRD_CHECK_MPLS_KERNEL],
[
AC_CACHE_CHECK(
[for Linux MPLS headers],
[bird_cv_mpls_kernel],
[
AC_COMPILE_IFELSE(
[
AC_LANG_PROGRAM(
[
#include <linux/lwtunnel.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
void t(int arg);
],
[
t(AF_MPLS);
t(RTA_VIA);
t(RTA_NEWDST);
t(RTA_ENCAP_TYPE);
t(RTA_ENCAP);
struct rtvia rtvia;
t(LWTUNNEL_ENCAP_MPLS);
]
)
],
[bird_cv_mpls_kernel=yes],
[bird_cv_mpls_kernel=no]
)
]
)
])
AC_DEFUN([BIRD_CHECK_GCC_OPTION],
[
bird_tmp_cflags="$CFLAGS"

View File

@ -52,6 +52,6 @@ protocol rip {
ipv4;
}
protocol ripng {
protocol rip ng {
ipv6;
}

View File

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

View File

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

View File

@ -13,7 +13,7 @@
#include "lib/ip.h"
#include "lib/hash.h"
#include "lib/resource.h"
#include "sysdep/unix/timer.h"
#include "lib/timer.h"
/* Configuration structure */
@ -32,16 +32,13 @@ struct config {
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
u32 router_id; /* Our Router ID */
ip_addr listen_bgp_addr; /* Listening BGP socket should use this address */
unsigned listen_bgp_port; /* Listening BGP socket should use this port (0 is default) */
u32 listen_bgp_flags; /* Listening BGP socket should use these flags */
unsigned proto_default_debug; /* Default protocol debug mask */
unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */
struct timeformat tf_route; /* Time format for 'show route' */
struct timeformat tf_proto; /* Time format for 'show protocol' */
struct timeformat tf_log; /* Time format for the logfile */
struct timeformat tf_base; /* Time format for other purposes */
u32 gr_wait; /* Graceful restart wait timeout */
u32 gr_wait; /* Graceful restart wait timeout (sec) */
int cli_debug; /* Tracing of CLI connections and commands */
int latency_debug; /* I/O loop tracks duration of each event */
@ -57,7 +54,7 @@ struct config {
struct config *fallback; /* Link to regular config for CLI parsing */
int obstacle_count; /* Number of items blocking freeing of this config */
int shutdown; /* This is a pseudo-config for daemon shutdown */
bird_clock_t load_time; /* When we've got this configuration */
btime load_time; /* When we've got this configuration */
};
/* Please don't use these variables in protocols. Use proto_config->global instead. */
@ -68,7 +65,7 @@ struct config *config_alloc(const char *name);
int config_parse(struct config *);
int cli_parse(struct config *);
void config_free(struct config *);
int config_commit(struct config *, int type, int timeout);
int config_commit(struct config *, int type, uint timeout);
int config_confirm(void);
int config_undo(void);
void config_init(void);

View File

@ -14,7 +14,7 @@ CF_HDR
#include "conf/conf.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "sysdep/unix/timer.h"
#include "lib/timer.h"
#include "lib/string.h"
#include "nest/protocol.h"
#include "nest/iface.h"
@ -60,7 +60,7 @@ CF_DECLS
struct lsadb_show_data *ld;
struct iface *iface;
void *g;
bird_clock_t time;
btime time;
struct f_prefix px;
struct proto_spec ps;
struct channel_limit cl;
@ -80,11 +80,10 @@ CF_DECLS
%type <iface> ipa_scope
%type <i> expr bool pxlen4
%type <i32> expr_us
%type <time> datetime
%type <time> expr_us time
%type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_mpls_
%type <mls> label_stack_start label_stack
%type <t> text opttext
@ -97,7 +96,7 @@ CF_DECLS
%left '!'
%nonassoc '.'
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN)
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS)
CF_GRAMMAR
@ -137,9 +136,9 @@ expr:
expr_us:
expr S { $$ = (u32) $1 * 1000000; }
| expr MS { $$ = (u32) $1 * 1000; }
| expr US { $$ = (u32) $1 * 1; }
expr S { $$ = $1 S_; }
| expr MS { $$ = $1 MS_; }
| expr US { $$ = $1 US_; }
;
/* Switches */
@ -235,6 +234,12 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
cf_error("Invalid max prefix length %u", $3);
};
net_mpls_: MPLS NUM
{
$$ = cfg_alloc(sizeof(net_addr_roa6));
net_fill_mpls($$, $2);
}
net_ip_: net_ip4_ | net_ip6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
@ -244,6 +249,7 @@ net_:
| net_vpn_
| net_roa_
| net_flow_
| net_mpls_
;
@ -308,11 +314,11 @@ label_stack:
}
;
datetime:
time:
TEXT {
$$ = tm_parse_datetime($1);
$$ = tm_parse_time($1);
if (!$$)
cf_error("Invalid date and time");
cf_error("Invalid date/time");
}
;

View File

@ -11,16 +11,6 @@ CF_HDR
#define PARSER 1
#include "nest/bird.h"
#include "conf/conf.h"
#include "lib/resource.h"
#include "lib/socket.h"
#include "sysdep/unix/timer.h"
#include "lib/string.h"
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/cli.h"
#include "filter/filter.h"
#include "lib/flowspec.h"

View File

@ -36,6 +36,12 @@ AC_ARG_ENABLE([libssh],
[enable_libssh=try]
)
AC_ARG_ENABLE([mpls-kernel],
[AS_HELP_STRING([--enable-mpls-kernel], [enable MPLS support in kernel protocol @<:@try@:>@])],
[],
[enable_mpls_kernel=try]
)
AC_ARG_WITH([protocols],
[AS_HELP_STRING([--with-protocols=LIST], [include specified routing protocols @<:@all@:>@])],
[],
@ -239,6 +245,20 @@ if test "$enable_libssh" != no ; then
fi
fi
if test "$enable_mpls_kernel" != no ; then
BIRD_CHECK_MPLS_KERNEL
if test "$bird_cv_mpls_kernel" = yes ; then
AC_DEFINE([HAVE_MPLS_KERNEL], [1], [Define to 1 if kernel is MPLS capable])
elif test "$enable_mpls_kernel" = yes ; then
AC_MSG_ERROR([Kernel MPLS support not found.])
fi
if test "$enable_mpls_kernel" = try ; then
enable_mpls_kernel="$bird_cv_mpls_kernel"
fi
fi
all_protocols="$proto_bfd babel bgp ospf pipe radv rip $proto_rpki static"
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
@ -287,18 +307,6 @@ esac
AC_CHECK_HEADERS_ONCE([alloca.h syslog.h])
AC_CHECK_MEMBERS([struct sockaddr.sa_len], [], [], [#include <sys/socket.h>])
AC_CHECK_HEADERS([linux/lwtunnel.h],
[AC_DEFINE([HAVE_LWTUNNEL], [1], [Define to 1 if you have the <linux/lwtunnel.h> header file.])],
[],
[] dnl Force new AC_CHECK_HEADER semantics
)
AC_CHECK_MEMBERS([struct rtvia.rtvia_family],
[AC_DEFINE([HAVE_STRUCT_RTVIA], [1], [Define to 1 if you have rtvia structure.])],
[],
[#include <linux/rtnetlink.h>]
)
AC_C_BIGENDIAN(
[AC_DEFINE([CPU_BIG_ENDIAN], [1], [Define to 1 if cpu is big endian])],
[AC_DEFINE([CPU_LITTLE_ENDIAN], [1], [Define to 1 if cpu is little endian])],
@ -314,7 +322,7 @@ if test "$enable_debug" = yes ; then
[
AC_DEFINE([HAVE_EXECINFO_H], [1], [Define to 1 if you have the <execinfo.h> header file.])
AC_SEARCH_LIBS([backtrace], [execinfo],
[]
[],
[AC_MSG_ERROR([Function backtrace not available.])]
)
]
@ -396,6 +404,7 @@ AC_MSG_RESULT([ System configuration: $sysdesc])
AC_MSG_RESULT([ Debugging: $enable_debug])
AC_MSG_RESULT([ POSIX threads: $enable_pthreads])
AC_MSG_RESULT([ Routing protocols: $protocols])
AC_MSG_RESULT([ Kernel MPLS support: $enable_mpls_kernel])
AC_MSG_RESULT([ Client: $enable_client])
rm -f $objdir/.*-stamp

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;
if (ipv4_used || (key >= 0x10000)) {
if ((kind != EC_GENERIC) && (ipv4_used || (key >= 0x10000))) {
check_u16(vf);
if (vt == EC_ALL)
vt = 0xFFFF;
@ -421,7 +421,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
%type <v> set_atom switch_atom fipa
%type <px> fprefix
%type <s> decls declsn one_decl function_params
%type <h> bgp_path bgp_path_tail1 bgp_path_tail2
%type <h> bgp_path bgp_path_tail
%type <t> get_cf_position
CF_GRAMMAR
@ -763,25 +763,18 @@ bgp_path_expr:
;
bgp_path:
PO bgp_path_tail1 PC { $$ = $2; }
| '/' bgp_path_tail2 '/' { $$ = $2; }
PO bgp_path_tail PC { $$ = $2; }
;
bgp_path_tail1:
NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
| NUM DDOT NUM bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
| '*' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
| '?' bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
| bgp_path_expr bgp_path_tail1 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
bgp_path_tail:
NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
| NUM DDOT NUM bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $4; $$->kind = PM_ASN_RANGE; $$->val = $1; $$->val2 = $3; }
| '*' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
| '?' bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_QUESTION; }
| bgp_path_expr bgp_path_tail { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN_EXPR; $$->val = (uintptr_t) $1; }
| { $$ = NULL; }
;
bgp_path_tail2:
NUM bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASN; $$->val = $1; }
| '?' bgp_path_tail2 { $$ = cfg_allocz(sizeof(struct f_path_mask)); $$->next = $2; $$->kind = PM_ASTERISK; }
| { $$ = NULL; }
;
constant:
NUM { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_INT; $$->a2.i = $1; }
| TRUE { $$ = f_new_inst(); $$->code = 'c'; $$->aux = T_BOOL; $$->a2.i = 1; }

View File

@ -1089,7 +1089,8 @@ interpret(struct f_inst *what)
switch (what->aux & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
if (v1.type != T_INT)
// Enums are also ints, so allow them in.
if (v1.type != T_INT && (v1.type < T_ENUM_LO || v1.type > T_ENUM_HI))
runtime( "Setting int attribute to non-int value" );
l->attrs[0].u.data = v1.val.i;
break;

View File

@ -147,6 +147,7 @@ void val_format(struct f_val v, buffer *buf);
#define T_ENUM_RTD 0x34
#define T_ENUM_ROA 0x35
#define T_ENUM_NETTYPE 0x36
#define T_ENUM_RA_PREFERENCE 0x37
/* new enums go here */
#define T_ENUM_EMPTY 0x3f /* Special hack for atomic_aggr */

View File

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

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)
$(all-daemon)

View File

@ -9,7 +9,6 @@
#ifndef _BIRD_BIRDLIB_H_
#define _BIRD_BIRDLIB_H_
#include "sysdep/unix/timer.h"
#include "lib/alloca.h"
/* Ugly structure offset handling macros */
@ -70,10 +69,11 @@ static inline int u64_cmp(u64 i1, u64 i2)
/* Microsecond time */
typedef s64 btime;
//typedef s64 bird_clock_t;
#define S_ *1000000
#define MS_ *1000
#define US_ *1
#define S_ * (btime) 1000000
#define MS_ * (btime) 1000
#define US_ * (btime) 1
#define TO_S /1000000
#define TO_MS /1000
#define TO_US /1
@ -82,39 +82,26 @@ typedef s64 btime;
#define S S_
#define MS MS_
#define US US_
#define NS /1000
#endif
#define TIME_INFINITY ((s64) 0x7fffffffffffffff)
/* Rate limiting */
struct tbf {
bird_clock_t timestamp; /* Last update */
u16 count; /* Available tokens */
btime timestamp; /* Last update */
u64 count; /* Available micro-tokens */
u16 burst; /* Max number of tokens */
u16 rate; /* Rate of replenishment */
u16 mark; /* Whether last op was limited */
u16 rate; /* Rate of replenishment (tokens / sec) */
u32 drop; /* Number of failed request since last successful */
};
/* Default TBF values for rate limiting log messages */
#define TBF_DEFAULT_LOG_LIMITS { .rate = 1, .burst = 5 }
void tbf_update(struct tbf *f);
static inline int
tbf_limit(struct tbf *f)
{
tbf_update(f);
if (!f->count)
{
f->mark = 1;
return 1;
}
f->count--;
f->mark = 0;
return 0;
}
int tbf_limit(struct tbf *f);
/* Logging and dying */

View File

@ -13,10 +13,14 @@
#include "lib/resource.h"
#include "sysdep/config.h"
#define BUFFER(type) struct { type *data; uint used, size; }
#define BUFFER_(type) struct { type *data; uint used, size; }
#define BUFFER_TYPE(v) typeof(* (v).data)
#define BUFFER_SIZE(v) ((v).size * sizeof(* (v).data))
#ifndef PARSER
#define BUFFER(type) BUFFER_(type)
#endif
#define BUFFER_INIT(v,pool,isize) \
({ \
(v).used = 0; \

View File

@ -55,6 +55,7 @@ t_ev_run_list(void)
resource_init();
olock_init();
timer_init();
io_init();
rt_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 */
struct flow_builder {
BUFFER(byte) data;
BUFFER_(byte) data;
enum flow_type this_type;
enum flow_type last_type;
u16 last_op_offset; /* Position of last operator in data.data */

View File

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

View File

@ -11,7 +11,7 @@
*
* Linear memory pools are collections of memory blocks which
* support very fast allocation of new blocks, but are able to free only
* the whole collection at once.
* the whole collection at once (or in stack order).
*
* Example: Each configuration is described by a complex system of structures,
* linked lists and function trees which are all allocated from a single linear
@ -37,7 +37,7 @@ const int lp_chunk_size = sizeof(struct lp_chunk);
struct linpool {
resource r;
byte *ptr, *end;
struct lp_chunk *first, *current, **plast; /* Normal (reusable) chunks */
struct lp_chunk *first, *current; /* Normal (reusable) chunks */
struct lp_chunk *first_large; /* Large chunks */
uint chunk_size, threshold, total, total_large;
};
@ -69,7 +69,6 @@ linpool
*lp_new(pool *p, uint blk)
{
linpool *m = ralloc(p, &lp_class);
m->plast = &m->first;
m->chunk_size = blk;
m->threshold = 3*blk/4;
return m;
@ -114,22 +113,25 @@ lp_alloc(linpool *m, uint size)
}
else
{
if (m->current)
if (m->current && m->current->next)
{
/* Still have free chunks from previous incarnation (before lp_flush()) */
c = m->current;
m->current = c->next;
c = m->current->next;
}
else
{
/* Need to allocate a new chunk */
c = xmalloc(sizeof(struct lp_chunk) + m->chunk_size);
m->total += m->chunk_size;
*m->plast = c;
m->plast = &c->next;
c->next = NULL;
c->size = m->chunk_size;
if (m->current)
m->current->next = c;
else
m->first = c;
}
m->current = c;
m->ptr = c->data + size;
m->end = c->data + m->chunk_size;
}
@ -190,9 +192,11 @@ lp_flush(linpool *m)
{
struct lp_chunk *c;
/* Relink all normal chunks to free list and free all large chunks */
m->ptr = m->end = NULL;
m->current = m->first;
/* Move ptr to the first chunk and free all large chunks */
m->current = c = m->first;
m->ptr = c ? c->data : NULL;
m->end = c ? c->data + m->chunk_size : NULL;
while (c = m->first_large)
{
m->first_large = c->next;
@ -201,6 +205,49 @@ lp_flush(linpool *m)
m->total_large = 0;
}
/**
* lp_save - save the state of a linear memory pool
* @m: linear memory pool
* @p: state buffer
*
* This function saves the state of a linear memory pool. Saved state can be
* used later to restore the pool (to free memory allocated since).
*/
void
lp_save(linpool *m, lp_state *p)
{
p->current = m->current;
p->large = m->first_large;
p->ptr = m->ptr;
}
/**
* lp_restore - restore the state of a linear memory pool
* @m: linear memory pool
* @p: saved state
*
* This function restores the state of a linear memory pool, freeing all memory
* allocated since the state was saved. Note that the function cannot un-free
* the memory, therefore the function also invalidates other states that were
* saved between (on the same pool).
*/
void
lp_restore(linpool *m, lp_state *p)
{
struct lp_chunk *c;
/* Move ptr to the saved pos and free all newer large chunks */
m->current = c = p->current;
m->ptr = p->ptr;
m->end = c ? c->data + m->chunk_size : NULL;
while ((c = m->first_large) && (c != p->large))
{
m->first_large = c->next;
xfree(c);
}
}
static void
lp_free(resource *r)
{

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);
}
#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 pxlen;
u16 length;
u8 data[16];
u8 data[20];
u64 align[0];
} net_addr;
@ -76,6 +76,7 @@ typedef struct net_addr_vpn6 {
u8 pxlen;
u16 length;
ip6_addr prefix;
u32 padding;
u64 rd;
} net_addr_vpn6;
@ -152,7 +153,7 @@ extern const u16 net_max_text_length[];
((net_addr_vpn4) { NET_VPN4, pxlen, sizeof(net_addr_vpn4), prefix, rd })
#define NET_ADDR_VPN6(prefix,pxlen,rd) \
((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, rd })
((net_addr_vpn6) { NET_VPN6, pxlen, sizeof(net_addr_vpn6), prefix, 0, rd })
#define NET_ADDR_ROA4(prefix,pxlen,max_pxlen,asn) \
((net_addr_roa4) { NET_ROA4, pxlen, sizeof(net_addr_roa4), prefix, max_pxlen, asn })
@ -230,11 +231,14 @@ static inline int net_type_match(const net_addr *a, u32 mask)
static inline int net_is_ip(const net_addr *a)
{ return (a->type == NET_IP4) || (a->type == NET_IP6); }
static inline int net_is_vpn(const net_addr *a)
{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
static inline int net_is_roa(const net_addr *a)
{ return (a->type == NET_ROA4) || (a->type == NET_ROA6); }
static inline int net_is_vpn(const net_addr *a)
{ return (a->type == NET_VPN4) || (a->type == NET_VPN6); }
static inline int net_is_flow(const net_addr *a)
{ return (a->type == NET_FLOW4) || (a->type == NET_FLOW6); }
static inline ip4_addr net4_prefix(const net_addr *a)
@ -354,10 +358,10 @@ static inline int net_zero_roa6(const net_addr_roa6 *a)
{ return !a->pxlen && ip6_zero(a->prefix) && !a->max_pxlen && !a->asn; }
static inline int net_zero_flow4(const net_addr_flow4 *a)
{ return !a->pxlen && ip4_zero(a->prefix) && !a->data; }
{ return !a->pxlen && ip4_zero(a->prefix) && (a->length == sizeof(net_addr_flow4)); }
static inline int net_zero_flow6(const net_addr_flow6 *a)
{ return !a->pxlen && ip6_zero(a->prefix) && !a->data; }
{ return !a->pxlen && ip6_zero(a->prefix) && (a->length == sizeof(net_addr_flow6)); }
static inline int net_zero_mpls(const net_addr_mpls *a)
{ return !a->label; }
@ -526,8 +530,21 @@ int net_classify(const net_addr *N);
int net_format(const net_addr *N, char *buf, int buflen);
int rd_format(const u64 rd, char *buf, int buflen);
static inline int ipa_in_net_ip4(ip4_addr a, const net_addr_ip4 *n)
{ return ip4_zero(ip4_and(ip4_xor(a, n->prefix), ip4_mkmask(n->pxlen))); }
static inline int net_in_net_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip4(a->prefix, b); }
static inline int ipa_in_net_ip6(ip6_addr a, const net_addr_ip6 *n)
{ return ip6_zero(ip6_and(ip6_xor(a, n->prefix), ip6_mkmask(n->pxlen))); }
static inline int net_in_net_ip6(const net_addr_ip6 *a, const net_addr_ip6 *b)
{ return (a->pxlen >= b->pxlen) && ipa_in_net_ip6(a->prefix, b); }
int ipa_in_netX(const ip_addr A, const net_addr *N);
int net_in_netX(const net_addr *A, const net_addr *N);
void net_init(void);
#endif

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
* generic network addresses (net_addr *), |%R| for Router / Network ID (u32
* value printed as IPv4 address), |%lR| for 64bit Router / Network ID (u64
* value printed as eight :-separated octets) and |%m| resp. |%M| for error
* messages (uses strerror() to translate @errno code to message text). On the
* other hand, it doesn't support floating point numbers.
* value printed as eight :-separated octets), |%t| for time values (btime) with
* specified subsecond precision, and |%m| resp. |%M| for error messages (uses
* strerror() to translate @errno code to message text). On the other hand, it
* doesn't support floating point numbers.
*
* Result: number of characters of the output string or -1 if
* the buffer space was insufficient.
@ -139,6 +140,8 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
int i, base;
u32 x;
u64 X;
btime t;
s64 t1, t2;
char *str, *start;
const char *s;
char ipbuf[NET_MAX_TEXT_LENGTH+1];
@ -279,7 +282,6 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
return -1;
continue;
case 'n':
if (qualifier == 'l') {
long * ip = va_arg(args, long *);
@ -360,6 +362,50 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
s = ipbuf;
goto str;
case 't':
t = va_arg(args, btime);
t1 = t TO_S;
t2 = t - t1 S;
if (precision < 0)
precision = 3;
if (precision > 6)
precision = 6;
/* Compute field_width for second part */
if ((precision > 0) && (field_width > 0))
field_width -= (1 + precision);
if (field_width < 0)
field_width = 0;
/* Print seconds */
flags |= SIGN;
str = number(str, t1, 10, field_width, 0, flags, size);
if (!str)
return -1;
if (precision > 0)
{
size -= (str-start);
start = str;
if ((1 + precision) > size)
return -1;
/* Convert microseconds to requested precision */
for (i = precision; i < 6; i++)
t2 /= 10;
/* Print sub-seconds */
*str++ = '.';
str = number(str, t2, 10, precision, 0, ZEROPAD, size - 1);
if (!str)
return -1;
}
goto done;
/* integer number formats - set up the flags and "break" */
case 'o':
base = 8;
@ -401,6 +447,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
str = number(str, num, base, field_width, precision, flags, size);
if (!str)
return -1;
done: ;
}
if (!size)
return -1;

View File

@ -56,6 +56,15 @@ t_simple(void)
BSPRINTF(2, "-1", buf, "%d", -1);
BSPRINTF(11, "-2147483648", buf, "%d", -2147483648);
BSPRINTF(7, "123.456", buf, "%t", (btime) 123456789);
BSPRINTF(7, "123.456", buf, "%2t", (btime) 123456789);
BSPRINTF(8, " 123.456", buf, "%8t", (btime) 123456789);
BSPRINTF(4, " 123", buf, "%4.0t", (btime) 123456789);
BSPRINTF(8, "123.4567", buf, "%8.4t", (btime) 123456789);
BSPRINTF(9, "0123.4567", buf, "%09.4t", (btime) 123456789);
BSPRINTF(12, " 123.456789", buf, "%12.10t", (btime) 123456789);
BSPRINTF(8, " 123.004", buf, "%8t", (btime) 123004 MS);
return 1;
}

View File

@ -59,11 +59,18 @@ void mb_free(void *);
typedef struct linpool linpool;
typedef struct lp_state {
void *current, *large;
byte *ptr;
} lp_state;
linpool *lp_new(pool *, unsigned blk);
void *lp_alloc(linpool *, unsigned size); /* Aligned */
void *lp_allocu(linpool *, unsigned size); /* Unaligned */
void *lp_allocz(linpool *, unsigned size); /* With clear */
void lp_flush(linpool *); /* Free everything, but leave linpool */
void lp_save(linpool *m, lp_state *p); /* Save state */
void lp_restore(linpool *m, lp_state *p); /* Restore state */
extern const int lp_chunk_size;
#define LP_GAS 1024

View File

@ -50,6 +50,7 @@ typedef struct birdsock {
int ttl; /* Time To Live, -1 = default */
u32 flags;
struct iface *iface; /* Interface; specify this for broad/multicast sockets */
struct iface *vrf; /* Related VRF instance, NULL if global */
byte *rbuf, *rpos; /* NULL=allocate automatically */
uint fast_rx; /* RX has higher priority in event loop */

View File

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

377
lib/timer.c Normal file
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];
cli_msg(-1000, "BIRD " BIRD_VERSION);
tm_format_datetime(tim, &config->tf_base, now);
tm_format_time(tim, &config->tf_base, current_time());
cli_msg(-1011, "Router ID is %R", config->router_id);
cli_msg(-1011, "Current server time is %s", tim);
tm_format_datetime(tim, &config->tf_base, boot_time);
tm_format_time(tim, &config->tf_base, boot_time);
cli_msg(-1011, "Last reboot on %s", tim);
tm_format_datetime(tim, &config->tf_base, config->load_time);
tm_format_time(tim, &config->tf_base, config->load_time);
cli_msg(-1011, "Last reconfiguration on %s", tim);
graceful_restart_show_status();

View File

@ -65,14 +65,15 @@ proto_postconfig(void)
CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(REFRESH)
@ -124,24 +125,6 @@ idval:
}
;
CF_ADDTO(conf, listen)
listen: LISTEN BGP listen_opts ';' ;
listen_opts:
/* Nothing */
| listen_opts listen_opt
;
listen_opt:
ADDRESS ipa { new_config->listen_bgp_addr = $2; }
| PORT expr { new_config->listen_bgp_port = $2; }
| V6ONLY { new_config->listen_bgp_flags = 0; }
| DUAL { new_config->listen_bgp_flags = 1; }
;
CF_ADDTO(conf, gr_opts)
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
@ -158,6 +141,7 @@ net_type:
| ROA6 { $$ = NET_ROA6; }
| FLOW4{ $$ = NET_FLOW4; }
| FLOW6{ $$ = NET_FLOW6; }
| MPLS { $$ = NET_MPLS; }
;
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
@ -225,6 +209,7 @@ proto_item:
| MRTDUMP mrtdump_mask { this_proto->mrtdump = $2; }
| ROUTER ID idval { this_proto->router_id = $3; }
| DESCRIPTION text { this_proto->dsc = $2; }
| VRF text { this_proto->vrf = if_get_by_name($2); }
;
@ -296,6 +281,7 @@ limit_spec:
| OFF { $$ = (struct channel_limit){}; }
;
CF_ADDTO(conf, debug_default)
debug_default:
@ -305,6 +291,31 @@ debug_default:
/* MRTDUMP PROTOCOLS is in systep/unix/config.Y */
CF_ADDTO(conf, timeformat_base)
timeformat_which:
ROUTE { $$ = &new_config->tf_route; }
| PROTOCOL { $$ = &new_config->tf_proto; }
| BASE { $$ = &new_config->tf_base; }
| LOG { $$ = &new_config->tf_log; }
;
timeformat_spec:
timeformat_which TEXT { *$1 = (struct timeformat){$2, NULL, 0}; }
| timeformat_which TEXT expr TEXT { *$1 = (struct timeformat){$2, $4, (s64) $3 S_}; }
| timeformat_which ISO SHORT { *$1 = TM_ISO_SHORT_S; }
| timeformat_which ISO SHORT MS { *$1 = TM_ISO_SHORT_MS; }
| timeformat_which ISO SHORT US { *$1 = TM_ISO_SHORT_US; }
| timeformat_which ISO LONG { *$1 = TM_ISO_LONG_S; }
| timeformat_which ISO LONG MS { *$1 = TM_ISO_LONG_MS; }
| timeformat_which ISO LONG US { *$1 = TM_ISO_LONG_US; }
;
timeformat_base:
TIMEFORMAT timeformat_spec ';'
;
/* Interface patterns */
iface_patt_node_init:
@ -463,12 +474,12 @@ password_item_begin:
password_item_params:
/* empty */ { }
| GENERATE FROM datetime ';' password_item_params { this_p_item->genfrom = $3; }
| GENERATE TO datetime ';' password_item_params { this_p_item->gento = $3; }
| ACCEPT FROM datetime ';' password_item_params { this_p_item->accfrom = $3; }
| ACCEPT TO datetime ';' password_item_params { this_p_item->accto = $3; }
| FROM datetime ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
| TO datetime ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
| GENERATE FROM time ';' password_item_params { this_p_item->genfrom = $3; }
| GENERATE TO time ';' password_item_params { this_p_item->gento = $3; }
| ACCEPT FROM time ';' password_item_params { this_p_item->accfrom = $3; }
| ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
| FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
| TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
| ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
| ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
;
@ -747,12 +758,12 @@ echo_size:
}
;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]], CLI_SF_PROTOCOL | CLI_SF_KW_ALL)

View File

@ -32,11 +32,14 @@
#include "lib/resource.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "sysdep/unix/krt.h"
static pool *if_pool;
list iface_list;
static void if_recalc_preferred(struct iface *i);
/**
* ifa_dump - dump interface address
* @a: interface address descriptor
@ -46,10 +49,11 @@ list iface_list;
void
ifa_dump(struct ifa *a)
{
debug("\t%I, net %N bc %I -> %I%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
(a->flags & IF_UP) ? "" : " DOWN",
(a->flags & IA_PRIMARY) ? "" : " SEC",
(a->flags & IA_PEER) ? "PEER" : "");
debug("\t%I, net %N bc %I -> %I%s%s%s%s\n", a->ip, &a->prefix, a->brd, a->opposite,
(a->flags & IA_PRIMARY) ? " PRIMARY" : "",
(a->flags & IA_SECONDARY) ? " SEC" : "",
(a->flags & IA_HOST) ? " HOST" : "",
(a->flags & IA_PEER) ? " PEER" : "");
}
/**
@ -116,7 +120,7 @@ if_what_changed(struct iface *i, struct iface *j)
unsigned c;
if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
|| i->index != j->index)
|| (i->index != j->index) || (i->master != j->master))
return IF_CHANGE_TOO_MUCH;
c = 0;
if ((i->flags ^ j->flags) & IF_UP)
@ -133,17 +137,21 @@ if_copy(struct iface *to, struct iface *from)
{
to->flags = from->flags | (to->flags & IF_TMP_DOWN);
to->mtu = from->mtu;
to->master_index = from->master_index;
to->master = from->master;
}
static inline void
ifa_send_notify(struct proto *p, unsigned c, struct ifa *a)
{
if (p->ifa_notify && (p->proto_state != PS_DOWN))
if (p->ifa_notify &&
(p->proto_state != PS_DOWN) &&
(!p->vrf || p->vrf == a->iface->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s < %s address %N on interface %s %s",
p->name, (a->flags & IA_PRIMARY) ? "primary" : "secondary",
&a->prefix, a->iface->name, (c & IF_CHANGE_UP) ? "added" : "removed");
log(L_TRACE "%s < address %N on interface %s %s",
p->name, &a->prefix, a->iface->name,
(c & IF_CHANGE_UP) ? "added" : "removed");
p->ifa_notify(p, c, a);
}
}
@ -174,7 +182,9 @@ ifa_notify_change(unsigned c, struct ifa *a)
static inline void
if_send_notify(struct proto *p, unsigned c, struct iface *i)
{
if (p->if_notify && (p->proto_state != PS_DOWN))
if (p->if_notify &&
(p->proto_state != PS_DOWN) &&
(!p->vrf || p->vrf == i->master))
{
if (p->debug & D_IFACES)
log(L_TRACE "%s < interface %s %s", p->name, i->name,
@ -182,6 +192,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
(c & IF_CHANGE_DOWN) ? "goes down" :
(c & IF_CHANGE_MTU) ? "changes MTU" :
(c & IF_CHANGE_LINK) ? "changes link" :
(c & IF_CHANGE_PREFERRED) ? "changes preferred address" :
(c & IF_CHANGE_CREATE) ? "created" :
"sends unknown event");
p->if_notify(p, c, i);
@ -210,10 +221,7 @@ if_notify_change(unsigned c, struct iface *i)
neigh_if_down(i);
WALK_LIST(a, i->addrs)
{
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
ifa_notify_change_(IF_CHANGE_DOWN, a);
}
ifa_notify_change_(IF_CHANGE_DOWN, a);
cli_notify_all_clients();
}
@ -224,10 +232,7 @@ if_notify_change(unsigned c, struct iface *i)
if (c & IF_CHANGE_UP)
{
WALK_LIST(a, i->addrs)
{
a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
ifa_notify_change_(IF_CHANGE_UP, a);
}
ifa_notify_change_(IF_CHANGE_UP, a);
neigh_if_up(i);
cli_notify_all_clients();
@ -237,24 +242,25 @@ if_notify_change(unsigned c, struct iface *i)
neigh_if_link(i);
}
static unsigned
if_recalc_flags(struct iface *i, unsigned flags)
static uint
if_recalc_flags(struct iface *i UNUSED, uint flags)
{
if ((flags & (IF_SHUTDOWN | IF_TMP_DOWN)) ||
!(flags & IF_ADMIN_UP) ||
!i->addr)
flags &= ~IF_UP;
else
if ((flags & IF_ADMIN_UP) &&
!(flags & (IF_SHUTDOWN | IF_TMP_DOWN)) &&
!(i->master_index && !i->master))
flags |= IF_UP;
else
flags &= ~IF_UP;
return flags;
}
static void
if_change_flags(struct iface *i, unsigned flags)
if_change_flags(struct iface *i, uint flags)
{
unsigned of = i->flags;
uint of = i->flags;
i->flags = if_recalc_flags(i, flags);
if ((i->flags ^ of) & IF_UP)
if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i);
}
@ -302,7 +308,6 @@ if_update(struct iface *new)
WALK_LIST(i, iface_list)
if (!strcmp(new->name, i->name))
{
new->addr = i->addr;
new->flags = if_recalc_flags(new, new->flags);
c = if_what_changed(i, new);
if (c & IF_CHANGE_TOO_MUCH) /* Changed a lot, convert it to down/up */
@ -310,10 +315,13 @@ if_update(struct iface *new)
DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
if_change_flags(i, i->flags | IF_TMP_DOWN);
rem_node(&i->n);
new->addr = i->addr;
new->addr4 = i->addr4;
new->addr6 = i->addr6;
new->llv6 = i->llv6;
new->sysdep = i->sysdep;
memcpy(&new->addrs, &i->addrs, sizeof(i->addrs));
memcpy(i, new, sizeof(*i));
i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
i->flags &= ~IF_UP; /* IF_TMP_DOWN will be added later */
goto newif;
}
@ -344,13 +352,16 @@ if_start_update(void)
{
i->flags &= ~IF_UPDATED;
WALK_LIST(a, i->addrs)
a->flags &= ~IF_UPDATED;
a->flags &= ~IA_UPDATED;
}
}
void
if_end_partial_update(struct iface *i)
{
if (i->flags & IF_NEEDS_RECALC)
if_recalc_preferred(i);
if (i->flags & IF_TMP_DOWN)
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
}
@ -368,7 +379,7 @@ if_end_update(void)
else
{
WALK_LIST_DELSAFE(a, b, i->addrs)
if (!(a->flags & IF_UPDATED))
if (!(a->flags & IA_UPDATED))
ifa_delete(a);
if_end_partial_update(i);
}
@ -465,40 +476,99 @@ if_get_by_name(char *name)
return i;
}
struct ifa *kif_choose_primary(struct iface *i);
static int
ifa_recalc_primary(struct iface *i)
static inline void
if_set_preferred(struct ifa **pos, struct ifa *new)
{
struct ifa *a = kif_choose_primary(i);
if (*pos)
(*pos)->flags &= ~IA_PRIMARY;
if (new)
new->flags |= IA_PRIMARY;
if (a == i->addr)
return 0;
*pos = new;
}
if (i->addr)
i->addr->flags &= ~IA_PRIMARY;
static void
if_recalc_preferred(struct iface *i)
{
/*
* Preferred address selection priority:
* 1) Address configured in Device protocol
* 2) Sysdep IPv4 address (BSD)
* 3) Old preferred address
* 4) First address in list
*/
if (a)
struct kif_iface_config *ic = kif_get_iface_config(i);
struct ifa *a4 = i->addr4, *a6 = i->addr6, *ll = i->llv6;
ip_addr pref_v4 = ic->pref_v4;
uint change = 0;
if (kif_update_sysdep_addr(i))
change |= IF_CHANGE_SYSDEP;
/* BSD sysdep address */
if (ipa_zero(pref_v4) && ip4_nonzero(i->sysdep))
pref_v4 = ipa_from_ip4(i->sysdep);
struct ifa *a;
WALK_LIST(a, i->addrs)
{
a->flags |= IA_PRIMARY;
rem_node(&a->n);
add_head(&i->addrs, &a->n);
/* Secondary address is never selected */
if (a->flags & IA_SECONDARY)
continue;
if (ipa_is_ip4(a->ip)) {
if (!a4 || ipa_equal(a->ip, pref_v4))
a4 = a;
} else if (!ipa_is_link_local(a->ip)) {
if (!a6 || ipa_equal(a->ip, ic->pref_v6))
a6 = a;
} else {
if (!ll || ipa_equal(a->ip, ic->pref_ll))
ll = a;
}
}
i->addr = a;
return 1;
if (a4 != i->addr4)
{
if_set_preferred(&i->addr4, a4);
change |= IF_CHANGE_ADDR4;
}
if (a6 != i->addr6)
{
if_set_preferred(&i->addr6, a6);
change |= IF_CHANGE_ADDR6;
}
if (ll != i->llv6)
{
if_set_preferred(&i->llv6, ll);
change |= IF_CHANGE_LLV6;
}
i->flags &= ~IF_NEEDS_RECALC;
/*
* FIXME: There should be proper notification instead of iface restart:
* if_notify_change(change, i)
*/
if (change)
if_change_flags(i, i->flags | IF_TMP_DOWN);
}
void
ifa_recalc_all_primary_addresses(void)
if_recalc_all_preferred_addresses(void)
{
struct iface *i;
WALK_LIST(i, iface_list)
{
if (ifa_recalc_primary(i))
if_change_flags(i, i->flags | IF_TMP_DOWN);
}
{
if_recalc_preferred(i);
if (i->flags & IF_TMP_DOWN)
if_change_flags(i, i->flags & ~IF_TMP_DOWN);
}
}
static inline int
@ -530,7 +600,7 @@ ifa_update(struct ifa *a)
b->scope == a->scope &&
!((b->flags ^ a->flags) & IA_PEER))
{
b->flags |= IF_UPDATED;
b->flags |= IA_UPDATED;
return b;
}
ifa_delete(b);
@ -538,15 +608,15 @@ ifa_update(struct ifa *a)
}
if ((a->prefix.type == NET_IP4) && (i->flags & IF_BROADCAST) && ipa_zero(a->brd))
log(L_ERR "Missing broadcast address for interface %s", i->name);
log(L_WARN "Missing broadcast address for interface %s", i->name);
b = mb_alloc(if_pool, sizeof(struct ifa));
memcpy(b, a, sizeof(struct ifa));
add_tail(&i->addrs, &b->n);
b->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
if (ifa_recalc_primary(i))
if_change_flags(i, i->flags | IF_TMP_DOWN);
if (b->flags & IF_UP)
b->flags |= IA_UPDATED;
i->flags |= IF_NEEDS_RECALC;
if (i->flags & IF_UP)
ifa_notify_change(IF_CHANGE_CREATE | IF_CHANGE_UP, b);
return b;
}
@ -569,16 +639,24 @@ ifa_delete(struct ifa *a)
if (ifa_same(b, a))
{
rem_node(&b->n);
if (b->flags & IF_UP)
{
b->flags &= ~IF_UP;
ifa_notify_change(IF_CHANGE_DOWN, b);
}
if (b->flags & IA_PRIMARY)
{
if_change_flags(i, i->flags | IF_TMP_DOWN);
ifa_recalc_primary(i);
/*
* We unlink deleted preferred address and mark for recalculation.
* FIXME: This could break if we make iface scan non-atomic, as
* protocols still could use the freed address until they get
* if_notify from preferred route recalculation.
*/
if (b == i->addr4) i->addr4 = NULL;
if (b == i->addr6) i->addr6 = NULL;
if (b == i->llv6) i->llv6 = NULL;
i->flags |= IF_NEEDS_RECALC;
}
if (i->flags & IF_UP)
ifa_notify_change(IF_CHANGE_DOWN, b);
mb_free(b);
return;
}
@ -745,16 +823,17 @@ iface_patts_equal(list *a, list *b, int (*comp)(struct iface_patt *, struct ifac
static void
if_show_addr(struct ifa *a)
{
byte opp[IPA_MAX_TEXT_LENGTH + 16];
byte *flg, opp[IPA_MAX_TEXT_LENGTH + 16];
flg = (a->flags & IA_PRIMARY) ? "Preferred, " : (a->flags & IA_SECONDARY) ? "Secondary, " : "";
if (ipa_nonzero(a->opposite))
bsprintf(opp, ", opposite %I", a->opposite);
bsprintf(opp, "opposite %I, ", a->opposite);
else
opp[0] = 0;
cli_msg(-1003, "\t%I/%d (%s%s, scope %s)",
a->ip, a->prefix.pxlen,
(a->flags & IA_PRIMARY) ? "Primary" : (a->flags & IA_SECONDARY) ? "Secondary" : "Unselected",
opp, ip_scope_text(a->scope));
cli_msg(-1003, "\t%I/%d (%s%sscope %s)",
a->ip, a->prefix.pxlen, flg, opp, ip_scope_text(a->scope));
}
void
@ -769,7 +848,13 @@ if_show(void)
if (i->flags & IF_SHUTDOWN)
continue;
cli_msg(-1001, "%s %s (index=%d)", i->name, (i->flags & IF_UP) ? "up" : "DOWN", i->index);
char mbuf[16 + sizeof(i->name)] = {};
if (i->master)
bsprintf(mbuf, " master=%s", i->master->name);
else if (i->master_index)
bsprintf(mbuf, " master=#%u", i->master_index);
cli_msg(-1001, "%s %s (index=%d%s)", i->name, (i->flags & IF_UP) ? "up" : "down", i->index, mbuf);
if (!(i->flags & IF_MULTIACCESS))
type = "PtP";
else
@ -783,10 +868,13 @@ if_show(void)
(i->flags & IF_LOOPBACK) ? " Loopback" : "",
(i->flags & IF_IGNORE) ? " Ignored" : "",
i->mtu);
if (i->addr)
if_show_addr(i->addr);
WALK_LIST(a, i->addrs)
if (a != i->addr)
if (a->prefix.type == NET_IP4)
if_show_addr(a);
WALK_LIST(a, i->addrs)
if (a->prefix.type == NET_IP6)
if_show_addr(a);
}
cli_msg(0, "");
@ -796,16 +884,25 @@ void
if_show_summary(void)
{
struct iface *i;
byte addr[IPA_MAX_TEXT_LENGTH + 16];
cli_msg(-2005, "interface state address");
cli_msg(-2005, "%-10s %-6s %-18s %s", "Interface", "State", "IPv4 address", "IPv6 address");
WALK_LIST(i, iface_list)
{
if (i->addr)
bsprintf(addr, "%I/%d", i->addr->ip, i->addr->prefix.pxlen);
byte a4[IPA_MAX_TEXT_LENGTH + 17];
byte a6[IPA_MAX_TEXT_LENGTH + 17];
if (i->addr4)
bsprintf(a4, "%I/%d", i->addr4->ip, i->addr4->prefix.pxlen);
else
addr[0] = 0;
cli_msg(-1005, "%-9s %-5s %s", i->name, (i->flags & IF_UP) ? "up" : "DOWN", addr);
a4[0] = 0;
if (i->addr6)
bsprintf(a6, "%I/%d", i->addr6->ip, i->addr6->prefix.pxlen);
else
a6[0] = 0;
cli_msg(-1005, "%-10s %-6s %-18s %s",
i->name, (i->flags & IF_UP) ? "up" : "down", a4, a6);
}
cli_msg(0, "");
}

View File

@ -34,12 +34,17 @@ struct iface {
unsigned flags;
unsigned mtu;
unsigned index; /* OS-dependent interface index */
unsigned master_index; /* Interface index of master iface */
struct iface *master; /* Master iface (e.g. for VRF) */
list addrs; /* Addresses assigned to this interface */
struct ifa *addr; /* Primary address */
struct ifa *addr4; /* Primary address for IPv4 */
struct ifa *addr6; /* Primary address for IPv6 */
struct ifa *llv6; /* Primary link-local address for IPv6 */
ip4_addr sysdep; /* Arbitrary IPv4 address for internal sysdep use */
list neighbors; /* All neighbors on this interface */
};
#define IF_UP 1 /* IF_ADMIN_UP and IP address known */
#define IF_UP 1 /* Currently just IF_ADMIN_UP */
#define IF_MULTIACCESS 2
#define IF_BROADCAST 4
#define IF_MULTICAST 8
@ -70,7 +75,10 @@ struct iface {
#define IF_JUST_CREATED 0x10000000 /* Send creation event as soon as possible */
#define IF_TMP_DOWN 0x20000000 /* Temporary shutdown due to interface reconfiguration */
#define IF_UPDATED 0x40000000 /* Touched in last scan */
#define IF_UPDATED 0x40000000 /* Iface touched in last scan */
#define IF_NEEDS_RECALC 0x80000000 /* Preferred address recalculation is needed */
#define IA_UPDATED IF_UPDATED /* Address touched in last scan */
/* Interface change events */
@ -79,8 +87,14 @@ struct iface {
#define IF_CHANGE_MTU 4
#define IF_CHANGE_CREATE 8 /* Seen this interface for the first time */
#define IF_CHANGE_LINK 0x10
#define IF_CHANGE_ADDR4 0x100 /* Change of iface->addr4 */
#define IF_CHANGE_ADDR6 0x200 /* ... */
#define IF_CHANGE_LLV6 0x400
#define IF_CHANGE_SYSDEP 0x800
#define IF_CHANGE_TOO_MUCH 0x40000000 /* Used internally */
#define IF_CHANGE_PREFERRED (IF_CHANGE_ADDR4 | IF_CHANGE_ADDR6 | IF_CHANGE_LLV6)
void if_init(void);
void if_dump(struct iface *);
void if_dump_all(void);
@ -99,7 +113,7 @@ void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned);
struct iface *if_find_by_name(char *);
struct iface *if_get_by_name(char *);
void ifa_recalc_all_primary_addresses(void);
void if_recalc_all_preferred_addresses(void);
/* The Neighbor Cache */

View File

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

View File

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

View File

@ -30,7 +30,8 @@
* when the protocol has explicitly requested it via the %NEF_STICKY
* flag because it wishes to be notified when the node will again become
* a neighbor. Such entries are enqueued in a special list which is walked
* whenever an interface changes its state to up.
* whenever an interface changes its state to up. Neighbor entry VRF
* association is implied by respective protocol.
*
* When a neighbor event occurs (a neighbor gets disconnected or a sticky
* inactive neighbor becomes connected), the protocol hook neigh_notify()
@ -153,8 +154,9 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
}
else
WALK_LIST(i, iface_list)
if ((scope = if_connected(a, i, &addr)) >= 0)
{
if ((!p->vrf || p->vrf == i->master) &&
((scope = if_connected(a, i, &addr)) >= 0))
{
ifa = i;
break;
}

View File

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

View File

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

View File

@ -13,6 +13,7 @@
#include "lib/resource.h"
#include "lib/lists.h"
#include "lib/event.h"
#include "lib/timer.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "nest/route.h"
@ -43,7 +44,7 @@ static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" };
extern struct protocol proto_unix_iface;
static void proto_shutdown_loop(struct timer *);
static void proto_shutdown_loop(timer *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
static void channel_verify_limits(struct channel *c);
@ -162,7 +163,7 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->channel_state = CS_DOWN;
c->export_state = ES_DOWN;
c->last_state_change = now;
c->last_state_change = current_time();
c->reloadable = 1;
CALL(c->channel->init, c, cf);
@ -341,7 +342,7 @@ channel_set_state(struct channel *c, uint state)
return;
c->channel_state = state;
c->last_state_change = now;
c->last_state_change = current_time();
switch (state)
{
@ -672,7 +673,8 @@ proto_init(struct proto_config *c, node *n)
struct proto *p = pr->init(c);
p->proto_state = PS_DOWN;
p->last_state_change = now;
p->last_state_change = current_time();
p->vrf = c->vrf;
insert_node(&p->n, n);
p->event = ev_new(proto_pool);
@ -819,7 +821,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* If there is a too big change in core attributes, ... */
if ((nc->protocol != oc->protocol) ||
(nc->net_type != oc->net_type) ||
(nc->disabled != p->disabled))
(nc->disabled != p->disabled) ||
(nc->vrf != oc->vrf))
return 0;
p->name = nc->name;
@ -977,6 +980,7 @@ proto_rethink_goal(struct proto *p)
proto_remove_channels(p);
rem_node(&p->n);
rfree(p->event);
mb_free(p->message);
mb_free(p);
if (!nc)
return;
@ -1046,7 +1050,7 @@ proto_rethink_goal(struct proto *p)
*
*/
static void graceful_restart_done(struct timer *t);
static void graceful_restart_done(timer *t);
/**
* graceful_restart_recovery - request initial graceful restart recovery
@ -1083,9 +1087,8 @@ graceful_restart_init(void)
}
graceful_restart_state = GRS_ACTIVE;
gr_wait_timer = tm_new(proto_pool);
gr_wait_timer->hook = graceful_restart_done;
tm_start(gr_wait_timer, config->gr_wait);
gr_wait_timer = tm_new_init(proto_pool, graceful_restart_done, NULL, 0, 0);
tm_start(gr_wait_timer, config->gr_wait S);
}
/**
@ -1099,7 +1102,7 @@ graceful_restart_init(void)
* restart wait timer fires (but there are still some locks).
*/
static void
graceful_restart_done(struct timer *t UNUSED)
graceful_restart_done(timer *t UNUSED)
{
log(L_INFO "Graceful restart done");
graceful_restart_state = GRS_DONE;
@ -1136,7 +1139,7 @@ graceful_restart_show_status(void)
cli_msg(-24, "Graceful restart recovery in progress");
cli_msg(-24, " Waiting for %d channels to recover", graceful_restart_locks);
cli_msg(-24, " Wait timer is %d/%d", tm_remains(gr_wait_timer), config->gr_wait);
cli_msg(-24, " Wait timer is %t/%u", tm_remains(gr_wait_timer), config->gr_wait);
}
/**
@ -1298,7 +1301,7 @@ protos_build(void)
int proto_restart;
static void
proto_shutdown_loop(struct timer *t UNUSED)
proto_shutdown_loop(timer *t UNUSED)
{
struct proto *p, *p_next;
@ -1329,7 +1332,40 @@ proto_schedule_down(struct proto *p, byte restart, byte code)
p->down_sched = restart ? PDS_RESTART : PDS_DISABLE;
p->down_code = code;
tm_start_max(proto_shutdown_timer, restart ? 2 : 0);
tm_start_max(proto_shutdown_timer, restart ? 250 MS : 0);
}
/**
* proto_set_message - set administrative message to protocol
* @p: protocol
* @msg: message
* @len: message length (-1 for NULL-terminated string)
*
* The function sets administrative message (string) related to protocol state
* change. It is called by the nest code for manual enable/disable/restart
* commands all routes to the protocol, and by protocol-specific code when the
* protocol state change is initiated by the protocol. Using NULL message clears
* the last message. The message string may be either NULL-terminated or with an
* explicit length.
*/
void
proto_set_message(struct proto *p, char *msg, int len)
{
mb_free(p->message);
p->message = NULL;
if (!msg || !len)
return;
if (len < 0)
len = strlen(msg);
if (!len)
return;
p->message = mb_alloc(proto_pool, len + 1);
memcpy(p->message, msg, len);
p->message[len] = 0;
}
@ -1500,7 +1536,7 @@ proto_notify_state(struct proto *p, uint state)
return;
p->proto_state = state;
p->last_state_change = now;
p->last_state_change = current_time();
switch (state)
{
@ -1620,19 +1656,20 @@ channel_show_info(struct channel *c)
}
void
proto_cmd_show(struct proto *p, uint verbose, int cnt)
proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
{
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
/* First protocol - show header */
if (!cnt)
cli_msg(-2002, "name proto table state since info");
cli_msg(-2002, "%-10s %-10s %-10s %-6s %-12s %s",
"Name", "Proto", "Table", "State", "Since", "Info");
buf[0] = 0;
if (p->proto->get_status)
p->proto->get_status(p, buf);
tm_format_datetime(tbuf, &config->tf_proto, p->last_state_change);
cli_msg(-1002, "%-8s %-8s %-8s %-5s %-10s %s",
tm_format_time(tbuf, &config->tf_proto, p->last_state_change);
cli_msg(-1002, "%-10s %-10s %-10s %-6s %-12s %s",
p->name,
p->proto->name,
p->main_channel ? p->main_channel->table->name : "---",
@ -1644,8 +1681,12 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
{
if (p->cf->dsc)
cli_msg(-1006, " Description: %s", p->cf->dsc);
if (p->message)
cli_msg(-1006, " Message: %s", p->message);
if (p->cf->router_id)
cli_msg(-1006, " Router ID: %R", p->cf->router_id);
if (p->vrf)
cli_msg(-1006, " VRF: %s", p->vrf->name);
if (p->proto->show_proto_info)
p->proto->show_proto_info(p);
@ -1661,7 +1702,7 @@ proto_cmd_show(struct proto *p, uint verbose, int cnt)
}
void
proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
proto_cmd_disable(struct proto *p, uintptr_t arg, int cnt UNUSED)
{
if (p->disabled)
{
@ -1672,12 +1713,13 @@ proto_cmd_disable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Disabling protocol %s", p->name);
p->disabled = 1;
p->down_code = PDC_CMD_DISABLE;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p);
cli_msg(-9, "%s: disabled", p->name);
}
void
proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
proto_cmd_enable(struct proto *p, uintptr_t arg, int cnt UNUSED)
{
if (!p->disabled)
{
@ -1687,12 +1729,13 @@ proto_cmd_enable(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Enabling protocol %s", p->name);
p->disabled = 0;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p);
cli_msg(-11, "%s: enabled", p->name);
}
void
proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
proto_cmd_restart(struct proto *p, uintptr_t arg, int cnt UNUSED)
{
if (p->disabled)
{
@ -1703,6 +1746,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
log(L_INFO "Restarting protocol %s", p->name);
p->disabled = 1;
p->down_code = PDC_CMD_RESTART;
proto_set_message(p, (char *) arg, -1);
proto_rethink_goal(p);
p->disabled = 0;
proto_rethink_goal(p);
@ -1710,7 +1754,7 @@ proto_cmd_restart(struct proto *p, uint arg UNUSED, int cnt UNUSED)
}
void
proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
{
struct channel *c;
@ -1749,19 +1793,19 @@ proto_cmd_reload(struct proto *p, uint dir, int cnt UNUSED)
}
void
proto_cmd_debug(struct proto *p, uint mask, int cnt UNUSED)
proto_cmd_debug(struct proto *p, uintptr_t mask, int cnt UNUSED)
{
p->debug = mask;
}
void
proto_cmd_mrtdump(struct proto *p, uint mask, int cnt UNUSED)
proto_cmd_mrtdump(struct proto *p, uintptr_t mask, int cnt UNUSED)
{
p->mrtdump = mask;
}
static void
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int), uint arg)
proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
{
if (s->class != SYM_PROTO)
{
@ -1774,7 +1818,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uint, int)
}
static void
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint arg)
proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
{
struct proto *p;
int cnt = 0;
@ -1790,8 +1834,8 @@ proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uint, int), uint a
}
void
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int),
int restricted, uint arg)
proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int),
int restricted, uintptr_t arg)
{
if (restricted && cli_access_restricted())
return;

View File

@ -12,7 +12,6 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
#include "sysdep/unix/timer.h"
#include "nest/route.h"
#include "conf/conf.h"
@ -101,6 +100,7 @@ struct proto_config {
u32 router_id; /* Protocol specific router ID */
list channels; /* List of channel configs (struct channel_config) */
struct iface *vrf; /* Related VRF instance, NULL if global */
/* Check proto_reconfigure() and proto_copy_config() after changing struct proto_config */
@ -143,6 +143,7 @@ struct proto {
list channels; /* List of channels to rtables (struct channel) */
struct channel *main_channel; /* Primary channel */
struct rte_src *main_source; /* Primary route source */
struct iface *vrf; /* Related VRF instance, NULL if global */
char *name; /* Name of this instance (== cf->name) */
u32 debug; /* Debugging flags */
@ -159,8 +160,9 @@ struct proto {
byte down_sched; /* Shutdown is scheduled for later (PDS_*) */
byte down_code; /* Reason for shutdown (PDC_* codes) */
u32 hash_key; /* Random key used for hashing of neighbors */
bird_clock_t last_state_change; /* Time of last state transition */
btime last_state_change; /* Time of last state transition */
char *last_state_name_announced; /* Last state name we've announced to the user */
char *message; /* State-change message, allocated from proto_pool */
/*
* General protocol hooks:
@ -237,6 +239,7 @@ struct proto_spec {
void *proto_new(struct proto_config *);
void *proto_config_new(struct protocol *, int class);
void proto_copy_config(struct proto_config *dest, struct proto_config *src);
void proto_set_message(struct proto *p, char *msg, int len);
void graceful_restart_recovery(void);
void graceful_restart_init(void);
@ -249,15 +252,15 @@ void channel_graceful_restart_unlock(struct channel *c);
void channel_show_limit(struct channel_limit *l, const char *dsc);
void channel_show_info(struct channel *c);
void proto_cmd_show(struct proto *, uint, int);
void proto_cmd_disable(struct proto *, uint, int);
void proto_cmd_enable(struct proto *, uint, int);
void proto_cmd_restart(struct proto *, uint, int);
void proto_cmd_reload(struct proto *, uint, int);
void proto_cmd_debug(struct proto *, uint, int);
void proto_cmd_mrtdump(struct proto *, uint, int);
void proto_cmd_show(struct proto *, uintptr_t, int);
void proto_cmd_disable(struct proto *, uintptr_t, int);
void proto_cmd_enable(struct proto *, uintptr_t, int);
void proto_cmd_restart(struct proto *, uintptr_t, int);
void proto_cmd_reload(struct proto *, uintptr_t, int);
void proto_cmd_debug(struct proto *, uintptr_t, int);
void proto_cmd_mrtdump(struct proto *, uintptr_t, int);
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uint, int), int restricted, uint arg);
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg);
struct proto *proto_get_named(struct symbol *, struct protocol *);
#define CMD_RELOAD 0
@ -508,7 +511,7 @@ struct channel {
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
bird_clock_t last_state_change; /* Time of last state transition */
btime last_state_change; /* Time of last state transition */
};

View File

@ -11,7 +11,6 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "sysdep/unix/timer.h"
#include "lib/net.h"
struct ea_list;
@ -159,8 +158,8 @@ typedef struct rtable {
* obstacle from this routing table.
*/
struct event *rt_event; /* Routing table event */
btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since last GC */
bird_clock_t gc_time; /* Time of last GC */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
byte hcu_scheduled; /* Hostcache update is scheduled */
byte nhu_state; /* Next Hop Update state */
@ -213,7 +212,7 @@ typedef struct rte {
byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */
word pref; /* Route preference */
bird_clock_t lastmod; /* Last modified */
btime lastmod; /* Last modified */
union { /* Protocol-dependent data (metrics etc.) */
#ifdef CONFIG_RIP
struct {
@ -236,6 +235,7 @@ typedef struct rte {
#endif
#ifdef CONFIG_BABEL
struct {
u16 seqno; /* Babel seqno */
u16 metric; /* Babel metric */
u64 router_id; /* Babel router id */
} babel;
@ -309,6 +309,8 @@ int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
struct rtable_config *rt_new_table(struct symbol *s, uint addr_type);
/* Default limit for ECMP next hops, defined in sysdep code */
extern const int rt_default_ecmp;
struct rt_show_data_rtable {
node n;
@ -470,7 +472,8 @@ typedef struct eattr {
#define EAP_OSPF 3 /* OSPF */
#define EAP_KRT 4 /* Kernel route attributes */
#define EAP_BABEL 5 /* Babel attributes */
#define EAP_MAX 6
#define EAP_RADV 6 /* Router advertisment attributes */
#define EAP_MAX 7
#define EA_CODE(proto,id) (((proto) << 8) | (id))
#define EA_PROTO(ea) ((ea) >> 8)

View File

@ -33,7 +33,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
struct channel *c;
if (!EMPTY_LIST(cf->iface_list) &&
!iface_patt_find(&cf->iface_list, ad->iface, ad->iface->addr))
!iface_patt_find(&cf->iface_list, ad->iface, ad))
/* Empty list is automatically treated as "*" */
return;

View File

@ -32,6 +32,24 @@
* Basic FIB operations are performed by functions defined by this module,
* enumerating of FIB contents is accomplished by using the FIB_WALK() macro
* or FIB_ITERATE_START() if you want to do it asynchronously.
*
* For simple iteration just place the body of the loop between FIB_WALK() and
* FIB_WALK_END(). You can't modify the FIB during the iteration (you can modify
* data in the node, but not add or remove nodes).
*
* If you need more freedom, you can use the FIB_ITERATE_*() group of macros.
* First, you initialize an iterator with FIB_ITERATE_INIT(). Then you can put
* the loop body in between FIB_ITERATE_START() and FIB_ITERATE_END(). In
* addition, the iteration can be suspended by calling FIB_ITERATE_PUT().
* This'll link the iterator inside the FIB. While suspended, you may modify the
* FIB, exit the current function, etc. To resume the iteration, enter the loop
* again. You can use FIB_ITERATE_UNLINK() to unlink the iterator (while
* iteration is suspended) in cases like premature end of FIB iteration.
*
* Note that the iterator must not be destroyed when the iteration is suspended,
* the FIB would then contain a pointer to invalid memory. Therefore, after each
* FIB_ITERATE_INIT() or FIB_ITERATE_PUT() there must be either
* FIB_ITERATE_START() or FIB_ITERATE_UNLINK() before the iterator is destroyed.
*/
#undef LOCAL_DEBUG
@ -195,6 +213,7 @@ fib_hash(struct fib *f, const net_addr *a)
case NET_ROA6: return FIB_HASH(f, a, roa6);
case NET_FLOW4: return FIB_HASH(f, a, flow4);
case NET_FLOW6: return FIB_HASH(f, a, flow6);
case NET_MPLS: return FIB_HASH(f, a, mpls);
default: bug("invalid type");
}
}
@ -231,6 +250,7 @@ fib_find(struct fib *f, const net_addr *a)
case NET_ROA6: return FIB_FIND(f, a, roa6);
case NET_FLOW4: return FIB_FIND(f, a, flow4);
case NET_FLOW6: return FIB_FIND(f, a, flow6);
case NET_MPLS: return FIB_FIND(f, a, mpls);
default: bug("invalid type");
}
}
@ -250,6 +270,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
case NET_ROA6: FIB_INSERT(f, a, e, roa6); return;
case NET_FLOW4: FIB_INSERT(f, a, e, flow4); return;
case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
default: bug("invalid type");
}
}

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);
struct nexthop *nh;
tm_format_datetime(tm, &config->tf_route, e->lastmod);
tm_format_time(tm, &config->tf_route, e->lastmod);
if (ipa_nonzero(a->from) && !ipa_equal(a->from, a->nh.gw))
bsprintf(from, " from %I", a->from);
else
@ -63,7 +63,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
if (d->last_table != d->tab)
rt_show_table(c, d);
cli_printf(c, -1007, "%-18s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
a->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
if (a->dest == RTD_UNICAST)
@ -71,6 +71,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
{
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
char weight[16] = "";
if (nh->labels)
{
@ -81,11 +82,14 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
*lsp = '\0';
if (a->nh.next)
cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d",
nh->gw, mpls, nh->iface->name, onlink, nh->weight + 1);
bsprintf(weight, " weight %d", nh->weight + 1);
if (ipa_nonzero(nh->gw))
cli_printf(c, -1007, "\tvia %I on %s%s%s%s",
nh->gw, nh->iface->name, mpls, onlink, weight);
else
cli_printf(c, -1007, "\tvia %I%s on %s%s",
nh->gw, mpls, nh->iface->name, onlink);
cli_printf(c, -1007, "\tdev %s%s%s",
nh->iface->name, mpls, onlink, weight);
}
if (d->verbose)

View File

@ -897,7 +897,9 @@ rte_validate(rte *e)
return 0;
}
c = net_classify(n->n.addr);
/* FIXME: better handling different nettypes */
c = !net_is_flow(n->n.addr) ?
net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{
log(L_WARN "Ignoring bogus route %N received via %s",
@ -1173,7 +1175,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
}
if (new)
new->lastmod = now;
new->lastmod = current_time();
/* Log the route change */
if (p->debug & D_ROUTES)
@ -1201,7 +1203,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) &&
(table->gc_time + table->config->gc_min_time <= now))
(table->gc_time + table->config->gc_min_time <= current_time()))
rt_schedule_prune(table);
if (old_ok && p->rte_remove)
@ -1497,7 +1499,7 @@ rte_dump(rte *e)
{
net *n = e->net;
debug("%-1N ", n->n.addr);
debug("KF=%02x PF=%02x pref=%d lm=%d ", n->n.flags, e->pflags, e->pref, now-e->lastmod);
debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e);
@ -1609,7 +1611,7 @@ rt_setup(pool *p, rtable *t, char *name, struct rtable_config *cf)
t->rt_event = ev_new(p);
t->rt_event->hook = rt_event;
t->rt_event->data = t;
t->gc_time = now;
t->gc_time = current_time();
}
}
@ -1708,7 +1710,7 @@ again:
#endif
tab->gc_counter = 0;
tab->gc_time = now;
tab->gc_time = current_time();
/* state change 2->0, 3->1 */
tab->prune_state &= 1;

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@
* BIRD -- The Babel protocol
*
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2016--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
@ -21,7 +23,7 @@
#include "lib/lists.h"
#include "lib/socket.h"
#include "lib/string.h"
#include "sysdep/unix/timer.h"
#include "lib/timer.h"
#define EA_BABEL_METRIC EA_CODE(EAP_BABEL, 0)
#define EA_BABEL_ROUTER_ID EA_CODE(EAP_BABEL, 1)
@ -32,25 +34,28 @@
#define BABEL_INFINITY 0xFFFF
#define BABEL_HELLO_INTERVAL_WIRED 4 /* Default hello intervals in seconds */
#define BABEL_HELLO_INTERVAL_WIRELESS 4
#define BABEL_HELLO_INTERVAL_WIRED (4 S_) /* Default hello intervals in seconds */
#define BABEL_HELLO_INTERVAL_WIRELESS (4 S_)
#define BABEL_HELLO_LIMIT 12
#define BABEL_UPDATE_INTERVAL_FACTOR 4
#define BABEL_IHU_INTERVAL_FACTOR 3
#define BABEL_IHU_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((X)*3/2) /* 1.5 */
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((X)*7/2) /* 3.5 */
#define BABEL_ROUTE_REFRESH_INTERVAL 2 /* Seconds before route expiry to send route request */
#define BABEL_HOLD_TIME 10 /* Expiry time for our own routes */
#define BABEL_HOLD_TIME_FACTOR 4 /* How long we keep unreachable route relative to update interval */
#define BABEL_IHU_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_HELLO_EXPIRY_FACTOR(X) ((btime)(X)*3/2) /* 1.5 */
#define BABEL_ROUTE_EXPIRY_FACTOR(X) ((btime)(X)*7/2) /* 3.5 */
#define BABEL_ROUTE_REFRESH_FACTOR(X) ((btime)(X)*5/2) /* 2.5 */
#define BABEL_SEQNO_REQUEST_RETRY 4
#define BABEL_SEQNO_REQUEST_EXPIRY (2 S_)
#define BABEL_GARBAGE_INTERVAL (300 S_)
#define BABEL_RXCOST_WIRED 96
#define BABEL_RXCOST_WIRELESS 256
#define BABEL_INITIAL_HOP_COUNT 255
#define BABEL_MAX_SEND_INTERVAL 5
#define BABEL_TIME_UNITS 100 /* On-wire times are counted in centiseconds */
#define BABEL_SEQNO_REQUEST_EXPIRY 60
#define BABEL_GARBAGE_INTERVAL 300
#define BABEL_MAX_SEND_INTERVAL 5 /* Unused ? */
/* Max interval that will not overflow when carried as 16-bit centiseconds */
#define BABEL_MAX_INTERVAL (0xFFFF/BABEL_TIME_UNITS)
#define BABEL_TIME_UNITS 10000 /* On-wire times are counted in centiseconds */
#define BABEL_MIN_INTERVAL (0x0001 * BABEL_TIME_UNITS)
#define BABEL_MAX_INTERVAL (0xFFFF * BABEL_TIME_UNITS)
#define BABEL_OVERHEAD (IP6_HEADER_LENGTH+UDP_HEADER_LENGTH)
#define BABEL_MIN_MTU (512 + BABEL_OVERHEAD)
@ -102,8 +107,8 @@ enum babel_ae_type {
struct babel_config {
struct proto_config c;
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */
list iface_list; /* List of iface configs (struct babel_iface_config) */
uint hold_time; /* Time to hold stale entries and unreachable routes */
};
struct babel_iface_config {
@ -111,11 +116,12 @@ struct babel_iface_config {
u16 rxcost;
u8 type;
u8 limit; /* Minimum number of Hellos to keep link up */
u8 check_link;
uint port;
u16 hello_interval;
u16 ihu_interval;
u16 update_interval;
uint hello_interval; /* Hello interval, in us */
uint ihu_interval; /* IHU interval, in us */
uint update_interval; /* Update interval, in us */
u16 rx_buffer; /* RX buffer size, 0 for MTU */
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
@ -138,14 +144,13 @@ struct babel_proto {
list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id;
u16 update_seqno; /* To be increased on request */
u8 update_seqno_inc; /* Request for update_seqno increase */
u8 triggered; /* For triggering global updates */
slab *route_slab;
slab *source_slab;
slab *msg_slab;
slab *seqno_slab;
list seqno_cache; /* Seqno requests in the cache (struct babel_seqno_request) */
struct tbf log_pkt_tbf; /* TBF for packet messages */
};
@ -172,10 +177,10 @@ struct babel_iface {
u16 hello_seqno; /* To be increased on each hello */
bird_clock_t next_hello;
bird_clock_t next_regular;
bird_clock_t next_triggered;
bird_clock_t want_triggered;
btime next_hello;
btime next_regular;
btime next_triggered;
btime want_triggered;
timer *timer;
event *send_event;
@ -186,13 +191,18 @@ struct babel_neighbor {
struct babel_iface *ifa;
ip_addr addr;
u16 txcost;
uint uc; /* Reference counter for seqno requests */
u16 rxcost; /* Sent in last IHU */
u16 txcost; /* Received in last IHU */
u16 cost; /* Computed neighbor cost */
s8 ihu_cnt; /* IHU countdown, 0 to send it */
u8 hello_cnt;
u16 hello_map;
u16 next_hello_seqno;
uint last_hello_int;
/* expiry timers */
bird_clock_t hello_expiry;
bird_clock_t ihu_expiry;
btime hello_expiry;
btime ihu_expiry;
list routes; /* Routes this neighbour has sent us (struct babel_route) */
};
@ -203,7 +213,7 @@ struct babel_source {
u64 router_id;
u16 seqno;
u16 metric;
bird_clock_t expires;
btime expires;
};
struct babel_route {
@ -212,37 +222,46 @@ struct babel_route {
struct babel_entry *e;
struct babel_neighbor *neigh;
u8 feasible;
u16 seqno;
u16 advert_metric;
u16 metric;
u16 advert_metric;
u64 router_id;
ip_addr next_hop;
bird_clock_t refresh_time;
bird_clock_t expires;
u16 expiry_interval;
btime refresh_time;
btime expires;
};
struct babel_seqno_request {
node n;
u64 router_id;
u16 seqno;
u8 hop_count;
u8 count;
btime expires;
struct babel_neighbor *nbr;
};
struct babel_entry {
struct babel_proto *proto;
struct babel_route *selected_in;
struct babel_route *selected_out;
struct babel_route *selected;
bird_clock_t updated;
list sources; /* Source entries for this prefix (struct babel_source). */
list routes; /* Routes for this prefix (struct babel_route) */
list sources; /* Source entries for this prefix (struct babel_source). */
list requests;
u8 valid; /* Entry validity state (BABEL_ENTRY_*) */
u8 unreachable; /* Unreachable route is announced */
u16 seqno; /* Outgoing seqno */
u16 metric; /* Outgoing metric */
u64 router_id; /* Outgoing router ID */
btime updated; /* Last change of outgoing rte, for triggered updates */
struct fib_node n;
};
/* Stores forwarded seqno requests for duplicate suppression. */
struct babel_seqno_request {
node n;
net_addr net;
u64 router_id;
u16 seqno;
bird_clock_t updated;
};
#define BABEL_ENTRY_DUMMY 0 /* No outgoing route */
#define BABEL_ENTRY_VALID 1 /* Valid outgoing route */
#define BABEL_ENTRY_STALE 2 /* Stale outgoing route, waiting for GC */
/*
@ -252,7 +271,7 @@ struct babel_seqno_request {
struct babel_msg_ack_req {
u8 type;
u16 nonce;
u16 interval;
uint interval;
ip_addr sender;
};
@ -264,7 +283,7 @@ struct babel_msg_ack {
struct babel_msg_hello {
u8 type;
u16 seqno;
u16 interval;
uint interval;
ip_addr sender;
};
@ -272,7 +291,7 @@ struct babel_msg_ihu {
u8 type;
u8 ae;
u16 rxcost;
u16 interval;
uint interval;
ip_addr addr;
ip_addr sender;
};
@ -280,7 +299,7 @@ struct babel_msg_ihu {
struct babel_msg_update {
u8 type;
u8 wildcard;
u16 interval;
uint interval;
u16 seqno;
u16 metric;
u64 router_id;
@ -334,6 +353,7 @@ void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_show_interfaces(struct proto *P, char *iff);
void babel_show_neighbors(struct proto *P, char *iff);
void babel_show_entries(struct proto *P);
void babel_show_routes(struct proto *P);
/* packets.c */
void babel_enqueue(union babel_msg *msg, struct babel_iface *ifa);

View File

@ -2,6 +2,8 @@
* BIRD -- Babel Configuration
*
* Copyright (c) 2015-2016 Toke Hoiland-Jorgensen
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2016--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
@ -32,6 +34,7 @@ babel_proto_start: proto_start BABEL
{
this_proto = proto_config_new(&proto_babel, $1);
init_list(&BABEL_CFG->iface_list);
BABEL_CFG->hold_time = 1 S_;
};
babel_proto_item:
@ -56,6 +59,7 @@ babel_iface_start:
init_list(&this_ipatt->ipn_list);
BABEL_IFACE->port = BABEL_PORT;
BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED;
BABEL_IFACE->limit = BABEL_HELLO_LIMIT;
BABEL_IFACE->tx_tos = IP_PREC_INTERNET_CONTROL;
BABEL_IFACE->tx_priority = sk_priority_control;
BABEL_IFACE->check_link = 1;
@ -83,16 +87,19 @@ babel_iface_finish:
if (!BABEL_IFACE->update_interval)
BABEL_IFACE->update_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_UPDATE_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
BABEL_IFACE->ihu_interval = MIN_(BABEL_IFACE->hello_interval*BABEL_IHU_INTERVAL_FACTOR, BABEL_MAX_INTERVAL);
BABEL_CFG->hold_time = MAX_(BABEL_CFG->hold_time, BABEL_IFACE->update_interval*BABEL_HOLD_TIME_FACTOR);
};
babel_iface_item:
| PORT expr { BABEL_IFACE->port = $2; if (($2<1) || ($2>65535)) cf_error("Invalid port number"); }
| RXCOST expr { BABEL_IFACE->rxcost = $2; if (($2<1) || ($2>65535)) cf_error("Invalid rxcost"); }
| HELLO INTERVAL expr { BABEL_IFACE->hello_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid hello interval"); }
| UPDATE INTERVAL expr { BABEL_IFACE->update_interval = $3; if (($3<1) || ($3>BABEL_MAX_INTERVAL)) cf_error("Invalid update interval"); }
| LIMIT expr { BABEL_IFACE->limit = $2; if (($2<1) || ($2>16)) cf_error("Limit must be in range 1-16"); }
| TYPE WIRED { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRED; }
| TYPE WIRELESS { BABEL_IFACE->type = BABEL_IFACE_TYPE_WIRELESS; }
| HELLO INTERVAL expr_us { BABEL_IFACE->hello_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Hello interval must be in range 10 ms - 655 s"); }
| UPDATE INTERVAL expr_us { BABEL_IFACE->update_interval = $3; if (($3<BABEL_MIN_INTERVAL) || ($3>BABEL_MAX_INTERVAL)) cf_error("Update interval must be in range 10 ms - 655 s"); }
| RX BUFFER expr { BABEL_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX buffer must be in range 256-65535"); }
| TX LENGTH expr { BABEL_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
| TX tos { BABEL_IFACE->tx_tos = $2; }
@ -129,6 +136,9 @@ CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
{ babel_show_entries(proto_get_named($4, &proto_babel)); };
CF_CLI(SHOW BABEL ROUTES, optsym opttext, [<name>], [[Show information about Babel route entries]])
{ babel_show_routes(proto_get_named($4, &proto_babel)); };
CF_CODE
CF_END

View File

@ -2,6 +2,8 @@
* BIRD -- The Babel protocol
*
* Copyright (c) 2015--2016 Toke Hoiland-Jorgensen
* (c) 2016--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2016--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*
@ -40,7 +42,7 @@ struct babel_tlv_ack {
struct babel_tlv_hello {
u8 type;
u8 length;
u16 reserved;
u16 flags;
u16 seqno;
u16 interval;
} PACKED;
@ -104,8 +106,12 @@ struct babel_tlv_seqno_request {
} PACKED;
#define BABEL_FLAG_DEF_PREFIX 0x80
#define BABEL_FLAG_ROUTER_ID 0x40
/* Hello flags */
#define BABEL_HF_UNICAST 0x8000
/* Update flags */
#define BABEL_UF_DEF_PREFIX 0x80
#define BABEL_UF_ROUTER_ID 0x40
struct babel_parse_state {
@ -162,17 +168,17 @@ bytes_equal(u8 *b1, u8 *b2, uint maxlen)
return i;
}
static inline u16
static inline uint
get_time16(const void *p)
{
u16 v = get_u16(p) / BABEL_TIME_UNITS;
return MAX(1, v);
uint v = get_u16(p) * BABEL_TIME_UNITS;
return MAX(BABEL_MIN_INTERVAL, v);
}
static inline void
put_time16(void *p, u16 v)
put_time16(void *p, uint v)
{
put_u16(p, v * BABEL_TIME_UNITS);
put_u16(p, v / BABEL_TIME_UNITS);
}
static inline void
@ -341,6 +347,11 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
struct babel_tlv_hello *tlv = (void *) hdr;
struct babel_msg_hello *msg = &m->hello;
/* We currently don't support unicast Hello */
u16 flags = get_u16(&tlv->flags);
if (flags & BABEL_HF_UNICAST)
return PARSE_IGNORE;
msg->type = BABEL_TLV_HELLO;
msg->seqno = get_u16(&tlv->seqno);
msg->interval = get_time16(&tlv->interval);
@ -593,8 +604,8 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
if (tlv->omitted && !state->def_ip4_prefix_seen)
return PARSE_ERROR;
/* Need next hop for v4 routes */
if (ipa_zero(state->next_hop_ip4))
/* Update must have next hop, unless it is retraction */
if (ipa_zero(state->next_hop_ip4) && (msg->metric != BABEL_INFINITY))
return PARSE_ERROR;
/* Merge saved prefix and received prefix parts */
@ -604,7 +615,7 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
ip4_addr prefix4 = get_ip4(buf);
net_fill_ip4(&msg->net, prefix4, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
put_ip4(state->def_ip4_prefix, prefix4);
state->def_ip4_prefix_seen = 1;
@ -629,13 +640,13 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
ip6_addr prefix6 = get_ip6(buf);
net_fill_ip6(&msg->net, prefix6, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
if (tlv->flags & BABEL_UF_DEF_PREFIX)
{
put_ip6(state->def_ip6_prefix, prefix6);
state->def_ip6_prefix_seen = 1;
}
if (tlv->flags & BABEL_FLAG_ROUTER_ID)
if (tlv->flags & BABEL_UF_ROUTER_ID)
{
state->router_id = ((u64) _I2(prefix6)) << 32 | _I3(prefix6);
state->router_id_seen = 1;
@ -748,7 +759,7 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
else
{
put_ip6_px(tlv->addr, &msg->net);
tlv->flags |= BABEL_FLAG_DEF_PREFIX;
tlv->flags |= BABEL_UF_DEF_PREFIX;
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen;
@ -1294,7 +1305,7 @@ babel_rx_hook(sock *sk, uint len)
sk->iface->name, sk->faddr, sk->laddr);
/* Silently ignore my own packets */
if (ipa_equal(ifa->iface->addr->ip, sk->faddr))
if (ipa_equal(sk->faddr, sk->saddr))
return 1;
if (!ipa_is_link_local(sk->faddr))
@ -1329,6 +1340,8 @@ babel_open_socket(struct babel_iface *ifa)
sk->sport = ifa->cf->port;
sk->dport = ifa->cf->port;
sk->iface = ifa->iface;
sk->saddr = ifa->addr;
sk->vrf = p->p.vrf;
sk->rx_hook = babel_rx_hook;
sk->tx_hook = babel_tx_hook;

View File

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

View File

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

View File

@ -18,10 +18,10 @@
#include "proto/bfd/io.h"
#include "lib/buffer.h"
#include "lib/heap.h"
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
#include "lib/timer.h"
#include "lib/socket.h"
@ -31,16 +31,12 @@ struct birdloop
pthread_t thread;
pthread_mutex_t mutex;
btime last_time;
btime real_time;
u8 use_monotonic_clock;
u8 stop_called;
u8 poll_active;
u8 wakeup_masked;
int wakeup_fds[2];
BUFFER(timer2 *) timers;
struct timeloop time;
list event_list;
list sock_list;
uint sock_num;
@ -57,6 +53,7 @@ struct birdloop
*/
static pthread_key_t current_loop_key;
extern pthread_key_t current_time_key;
static inline struct birdloop *
birdloop_current(void)
@ -68,6 +65,7 @@ static inline void
birdloop_set_current(struct birdloop *loop)
{
pthread_setspecific(current_loop_key, loop);
pthread_setspecific(current_time_key, loop ? &loop->time : &main_timeloop);
}
static inline void
@ -77,98 +75,6 @@ birdloop_init_current(void)
}
/*
* Time clock
*/
static void times_update_alt(struct birdloop *loop);
static void
times_init(struct birdloop *loop)
{
struct timespec ts;
int rv;
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rv < 0)
{
log(L_WARN "Monotonic clock is missing");
loop->use_monotonic_clock = 0;
loop->last_time = 0;
loop->real_time = 0;
times_update_alt(loop);
return;
}
if ((ts.tv_sec < 0) || (((s64) ts.tv_sec) > ((s64) 1 << 40)))
log(L_WARN "Monotonic clock is crazy");
loop->use_monotonic_clock = 1;
loop->last_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
loop->real_time = 0;
}
static void
times_update_pri(struct birdloop *loop)
{
struct timespec ts;
int rv;
rv = clock_gettime(CLOCK_MONOTONIC, &ts);
if (rv < 0)
die("clock_gettime: %m");
btime new_time = ((s64) ts.tv_sec S) + (ts.tv_nsec / 1000);
if (new_time < loop->last_time)
log(L_ERR "Monotonic clock is broken");
loop->last_time = new_time;
loop->real_time = 0;
}
static void
times_update_alt(struct birdloop *loop)
{
struct timeval tv;
int rv;
rv = gettimeofday(&tv, NULL);
if (rv < 0)
die("gettimeofday: %m");
btime new_time = ((s64) tv.tv_sec S) + tv.tv_usec;
btime delta = new_time - loop->real_time;
if ((delta < 0) || (delta > (60 S)))
{
if (loop->real_time)
log(L_WARN "Time jump, delta %d us", (int) delta);
delta = 100 MS;
}
loop->last_time += delta;
loop->real_time = new_time;
}
static void
times_update(struct birdloop *loop)
{
if (loop->use_monotonic_clock)
times_update_pri(loop);
else
times_update_alt(loop);
}
btime
current_time(void)
{
return birdloop_current()->last_time;
}
/*
* Wakeup code for birdloop
*/
@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
loop->wakeup_masked = 2;
}
/* For notifications from outside */
void
wakeup_kick_current(void)
{
struct birdloop *loop = birdloop_current();
if (loop && loop->poll_active)
wakeup_kick(loop);
}
/*
* Events
@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
static void
events_fire(struct birdloop *loop)
{
times_update(loop);
times_update(&loop->time);
ev_run_list(&loop->event_list);
}
@ -291,154 +207,6 @@ ev2_schedule(event *e)
}
/*
* Timers
*/
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
heap[a]->index = (a), heap[b]->index = (b))
static inline uint timers_count(struct birdloop *loop)
{ return loop->timers.used - 1; }
static inline timer2 *timers_first(struct birdloop *loop)
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
static void
tm2_free(resource *r)
{
timer2 *t = (timer2 *) r;
tm2_stop(t);
}
static void
tm2_dump(resource *r)
{
timer2 *t = (timer2 *) r;
debug("(code %p, data %p, ", t->hook, t->data);
if (t->randomize)
debug("rand %d, ", t->randomize);
if (t->recurrent)
debug("recur %d, ", t->recurrent);
if (t->expires)
debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
else
debug("inactive)\n");
}
static struct resclass tm2_class = {
"Timer",
sizeof(timer2),
tm2_free,
tm2_dump,
NULL,
NULL
};
timer2 *
tm2_new(pool *p)
{
timer2 *t = ralloc(p, &tm2_class);
t->index = -1;
return t;
}
void
tm2_set(timer2 *t, btime when)
{
struct birdloop *loop = birdloop_current();
uint tc = timers_count(loop);
if (!t->expires)
{
t->index = ++tc;
t->expires = when;
BUFFER_PUSH(loop->timers) = t;
HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP);
}
else if (t->expires < when)
{
t->expires = when;
HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
}
else if (t->expires > when)
{
t->expires = when;
HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
}
if (loop->poll_active && (t->index == 1))
wakeup_kick(loop);
}
void
tm2_start(timer2 *t, btime after)
{
tm2_set(t, current_time() + MAX(after, 0));
}
void
tm2_stop(timer2 *t)
{
if (!t->expires)
return;
struct birdloop *loop = birdloop_current();
uint tc = timers_count(loop);
HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
BUFFER_POP(loop->timers);
t->index = -1;
t->expires = 0;
}
static void
timers_init(struct birdloop *loop)
{
BUFFER_INIT(loop->timers, loop->pool, 4);
BUFFER_PUSH(loop->timers) = NULL;
}
static void
timers_fire(struct birdloop *loop)
{
btime base_time;
timer2 *t;
times_update(loop);
base_time = loop->last_time;
while (t = timers_first(loop))
{
if (t->expires > base_time)
return;
if (t->recurrent)
{
btime when = t->expires + t->recurrent;
if (when <= loop->last_time)
when = loop->last_time + t->recurrent;
if (t->randomize)
when += random() % (t->randomize + 1);
tm2_set(t, when);
}
else
tm2_stop(t);
t->hook(t);
}
}
/*
* Sockets
*/
@ -586,7 +354,7 @@ sockets_fire(struct birdloop *loop)
sock **psk = loop->poll_sk.data;
int poll_num = loop->poll_fd.used - 1;
times_update(loop);
times_update(&loop->time);
/* Last fd is internal wakeup fd */
if (pfd[poll_num].revents & POLLIN)
@ -634,11 +402,10 @@ birdloop_new(void)
loop->pool = p;
pthread_mutex_init(&loop->mutex, NULL);
times_init(loop);
wakeup_init(loop);
events_init(loop);
timers_init(loop);
timers_init(&loop->time, p);
sockets_init(loop);
return loop;
@ -710,7 +477,7 @@ static void *
birdloop_main(void *arg)
{
struct birdloop *loop = arg;
timer2 *t;
timer *t;
int rv, timeout;
birdloop_set_current(loop);
@ -719,13 +486,13 @@ birdloop_main(void *arg)
while (1)
{
events_fire(loop);
timers_fire(loop);
timers_fire(&loop->time);
times_update(loop);
times_update(&loop->time);
if (events_waiting(loop))
timeout = 0;
else if (t = timers_first(loop))
timeout = (tm2_remains(t) TO_MS) + 1;
else if (t = timers_first(&loop->time))
timeout = (tm_remains(t) TO_MS) + 1;
else
timeout = -1;
@ -756,7 +523,7 @@ birdloop_main(void *arg)
if (rv)
sockets_fire(loop);
timers_fire(loop);
timers_fire(&loop->time);
}
loop->stop_called = 0;

View File

@ -11,80 +11,15 @@
#include "lib/lists.h"
#include "lib/resource.h"
#include "lib/event.h"
#include "lib/timer.h"
#include "lib/socket.h"
// #include "sysdep/unix/timer.h"
typedef struct timer2
{
resource r;
void (*hook)(struct timer2 *);
void *data;
btime expires; /* 0=inactive */
uint randomize; /* Amount of randomization */
uint recurrent; /* Timer recurrence */
int index;
} timer2;
btime current_time(void);
void ev2_schedule(event *e);
timer2 *tm2_new(pool *p);
void tm2_set(timer2 *t, btime when);
void tm2_start(timer2 *t, btime after);
void tm2_stop(timer2 *t);
static inline int
tm2_active(timer2 *t)
{
return t->expires != 0;
}
static inline btime
tm2_remains(timer2 *t)
{
btime now = current_time();
return (t->expires > now) ? (t->expires - now) : 0;
}
static inline timer2 *
tm2_new_init(pool *p, void (*hook)(struct timer2 *), void *data, uint rec, uint rand)
{
timer2 *t = tm2_new(p);
t->hook = hook;
t->data = data;
t->recurrent = rec;
t->randomize = rand;
return t;
}
static inline void
tm2_set_max(timer2 *t, btime when)
{
if (when > t->expires)
tm2_set(t, when);
}
/*
static inline void
tm2_start_max(timer2 *t, btime after)
{
btime rem = tm2_remains(t);
tm2_start(t, MAX_(rem, after));
}
*/
void sk_start(sock *s);
void sk_stop(sock *s);
struct birdloop *birdloop_new(void);
void birdloop_start(struct birdloop *loop);
void birdloop_stop(struct birdloop *loop);

View File

@ -64,8 +64,6 @@
* format - Optional hook that converts eattr to textual representation.
*/
// XXXX review pool usage : c->c.proto->pool
struct bgp_attr_desc {
const char *name;
@ -1175,6 +1173,22 @@ bgp_init_bucket_table(struct bgp_channel *c)
c->withdraw_bucket = NULL;
}
void
bgp_free_bucket_table(struct bgp_channel *c)
{
HASH_FREE(c->bucket_hash);
struct bgp_bucket *b;
WALK_LIST_FIRST(b, c->bucket_queue)
{
rem_node(&b->send_node);
mb_free(b);
}
mb_free(c->withdraw_bucket);
c->withdraw_bucket = NULL;
}
static struct bgp_bucket *
bgp_get_bucket(struct bgp_channel *c, ea_list *new)
{

View File

@ -98,11 +98,14 @@
* <item> <rfc id="7911"> - Advertisement of Multiple Paths in BGP
* <item> <rfc id="7947"> - Internet Exchange BGP Route Server
* <item> <rfc id="8092"> - BGP Large Communities Attribute
* <item> <rfc id="8203"> - BGP Administrative Shutdown Communication
* </itemize>
*/
#undef LOCAL_DEBUG
#include <stdlib.h>
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
@ -312,20 +315,21 @@ err1:
/**
* bgp_start_timer - start a BGP timer
* @t: timer
* @value: time to fire (0 to disable the timer)
* @value: time (in seconds) to fire (0 to disable the timer)
*
* This functions calls tm_start() on @t with time @value and the amount of
* randomization suggested by the BGP standard. Please use it for all BGP
* timers.
*/
void
bgp_start_timer(timer *t, int value)
bgp_start_timer(timer *t, uint value)
{
if (value)
{
/* The randomization procedure is specified in RFC 1771: 9.2.3.3 */
t->randomize = value / 4;
tm_start(t, value - t->randomize);
/* The randomization procedure is specified in RFC 4271 section 10 */
btime time = value S;
btime randomize = random() % ((time / 4) + 1);
tm_start(t, time - randomize);
}
else
tm_stop(t);
@ -381,10 +385,10 @@ bgp_update_startup_delay(struct bgp_proto *p)
DBG("BGP: Updating startup delay\n");
if (p->last_proto_error && ((now - p->last_proto_error) >= (int) cf->error_amnesia_time))
if (p->last_proto_error && ((current_time() - p->last_proto_error) >= cf->error_amnesia_time S))
p->startup_delay = 0;
p->last_proto_error = now;
p->last_proto_error = current_time();
if (cf->disable_after_error)
{
@ -400,7 +404,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
}
static void
bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint len)
{
switch (conn->state)
{
@ -416,7 +420,7 @@ bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
case BS_OPENSENT:
case BS_OPENCONFIRM:
case BS_ESTABLISHED:
bgp_error(conn, 6, subcode, NULL, 0);
bgp_error(conn, 6, subcode, data, len);
return;
default:
@ -456,11 +460,11 @@ bgp_decision(void *vp)
}
void
bgp_stop(struct bgp_proto *p, uint subcode)
bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
{
proto_notify_state(&p->p, PS_STOP);
bgp_graceful_close_conn(&p->outgoing_conn, subcode);
bgp_graceful_close_conn(&p->incoming_conn, subcode);
bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
ev_schedule(p->event);
}
@ -598,12 +602,8 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
BGP_TRACE(D_EVENTS, "BGP session closed");
p->conn = NULL;
// XXXX free these tables to avoid memory leak during graceful restart
// bgp_free_prefix_table(p);
// bgp_free_bucket_table(p);
if (p->p.proto_state == PS_UP)
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
void
@ -661,6 +661,10 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
struct bgp_channel *c;
WALK_LIST(c, p->p.channels)
{
/* FIXME: perhaps check for channel state instead of disabled flag? */
if (c->c.disabled)
continue;
if (c->gr_ready)
{
if (c->gr_active)
@ -676,6 +680,13 @@ bgp_handle_graceful_restart(struct bgp_proto *p)
rt_refresh_begin(c->c.table, &c->c);
rt_refresh_end(c->c.table, &c->c);
}
/* Reset bucket and prefix tables */
bgp_free_bucket_table(c);
bgp_free_prefix_table(c);
bgp_init_bucket_table(c);
bgp_init_prefix_table(c);
c->packets_to_send = 0;
}
proto_notify_state(&p->p, PS_START);
@ -722,7 +733,7 @@ bgp_graceful_restart_timeout(timer *t)
struct bgp_proto *p = t->data;
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
@ -885,9 +896,9 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
conn->last_channel = 0;
conn->last_channel_count = 0;
conn->connect_timer = tm_new_set(p->p.pool, bgp_connect_timeout, conn, 0, 0);
conn->hold_timer = tm_new_set(p->p.pool, bgp_hold_timeout, conn, 0, 0);
conn->keepalive_timer = tm_new_set(p->p.pool, bgp_keepalive_timeout, conn, 0, 0);
conn->connect_timer = tm_new_init(p->p.pool, bgp_connect_timeout, conn, 0, 0);
conn->hold_timer = tm_new_init(p->p.pool, bgp_hold_timeout, conn, 0, 0);
conn->keepalive_timer = tm_new_init(p->p.pool, bgp_keepalive_timeout, conn, 0, 0);
conn->tx_ev = ev_new(p->p.pool);
conn->tx_ev->hook = bgp_kick_tx;
@ -936,6 +947,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
s->daddr = p->cf->remote_ip;
s->dport = p->cf->remote_port;
s->iface = p->neigh ? p->neigh->iface : NULL;
s->vrf = p->p.vrf;
s->ttl = p->cf->ttl_security ? 255 : hops;
s->rbsize = p->cf->enable_extended_messages ? BGP_RX_BUFFER_EXT_SIZE : BGP_RX_BUFFER_SIZE;
s->tbsize = p->cf->enable_extended_messages ? BGP_TX_BUFFER_EXT_SIZE : BGP_TX_BUFFER_SIZE;
@ -1094,19 +1106,8 @@ bgp_start_neighbor(struct bgp_proto *p)
if (ipa_is_link_local(p->source_addr))
p->link_addr = p->source_addr;
else
{
/* Find some link-local address for given iface */
struct ifa *a;
WALK_LIST(a, p->neigh->iface->addrs)
if (a->scope == SCOPE_LINK)
{
p->link_addr = a->ip;
break;
}
DBG("%s: Selected link-local address %I\n", p->p.name, p->link_addr);
}
else if (p->neigh->iface->llv6)
p->link_addr = p->neigh->iface->llv6->ip;
bgp_initiate(p);
}
@ -1132,7 +1133,7 @@ bgp_neigh_notify(neighbor *n)
BGP_TRACE(D_EVENTS, "Neighbor lost");
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST);
/* Perhaps also run bgp_update_startup_delay(p)? */
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}
else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP))
@ -1143,7 +1144,7 @@ bgp_neigh_notify(neighbor *n)
bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN);
if (ps == PS_UP)
bgp_update_startup_delay(p);
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}
else
@ -1168,7 +1169,7 @@ bgp_bfd_notify(struct bfd_request *req)
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
if (ps == PS_UP)
bgp_update_startup_delay(p);
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}
@ -1311,13 +1312,8 @@ bgp_start(struct proto *P)
p->event->hook = bgp_decision;
p->event->data = p;
p->startup_timer = tm_new(p->p.pool);
p->startup_timer->hook = bgp_startup_timeout;
p->startup_timer->data = p;
p->gr_timer = tm_new(p->p.pool);
p->gr_timer->hook = bgp_graceful_restart_timeout;
p->gr_timer->data = p;
p->startup_timer = tm_new_init(p->p.pool, bgp_startup_timeout, p, 0, 0);
p->gr_timer = tm_new_init(p->p.pool, bgp_graceful_restart_timeout, p, 0, 0);
p->local_id = proto_get_router_id(P->cf);
if (p->rr_client)
@ -1327,7 +1323,7 @@ bgp_start(struct proto *P)
p->source_addr = p->cf->local_ip;
p->link_addr = IPA_NONE;
/* XXXX */
/* Lock all channels when in GR recovery mode */
if (p->p.gr_recovery && p->cf->gr_mode)
{
struct bgp_channel *c;
@ -1344,6 +1340,7 @@ bgp_start(struct proto *P)
lock->addr = p->cf->remote_ip;
lock->port = p->cf->remote_port;
lock->iface = p->cf->iface;
lock->vrf = p->cf->iface ? NULL : p->p.vrf;
lock->type = OBJLOCK_TCP;
lock->hook = bgp_start_locked;
lock->data = p;
@ -1360,6 +1357,10 @@ bgp_shutdown(struct proto *P)
struct bgp_proto *p = (struct bgp_proto *) P;
uint subcode = 0;
char *message = NULL;
byte *data = NULL;
uint len = 0;
BGP_TRACE(D_EVENTS, "Shutdown requested");
switch (P->down_code)
@ -1376,10 +1377,12 @@ bgp_shutdown(struct proto *P)
case PDC_CMD_DISABLE:
case PDC_CMD_SHUTDOWN:
subcode = 2; // Errcode 6, 2 - administrative shutdown
message = P->message;
break;
case PDC_CMD_RESTART:
subcode = 4; // Errcode 6, 4 - administrative reset
message = P->message;
break;
case PDC_RX_LIMIT_HIT:
@ -1404,8 +1407,22 @@ bgp_shutdown(struct proto *P)
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 0;
/* RFC 8203 - shutdown communication */
if (message)
{
uint msg_len = strlen(message);
msg_len = MIN(msg_len, 128);
/* Buffer will be freed automatically by protocol shutdown */
data = mb_alloc(p->p.pool, msg_len + 1);
len = msg_len + 1;
data[0] = msg_len;
memcpy(data+1, message, msg_len);
}
done:
bgp_stop(p, subcode);
bgp_stop(p, subcode, data, len);
return p->p.proto_state;
}
@ -1495,6 +1512,20 @@ bgp_channel_start(struct channel *C)
c->next_hop_addr = src;
}
/* Use preferred addresses associated with interface / source address */
if (ipa_zero(c->next_hop_addr))
{
/* We know the iface for single-hop, we make lookup for multihop */
struct neighbor *nbr = p->neigh ?: neigh_find2(&p->p, &src, NULL, 0);
struct iface *iface = nbr ? nbr->iface : NULL;
if (bgp_channel_is_ipv4(c) && iface && iface->addr4)
c->next_hop_addr = iface->addr4->ip;
if (bgp_channel_is_ipv6(c) && iface && iface->addr6)
c->next_hop_addr = iface->addr6->ip;
}
/* Exit if no feasible next hop address is found */
if (ipa_zero(c->next_hop_addr))
{
@ -1523,10 +1554,9 @@ bgp_channel_shutdown(struct channel *C)
{
struct bgp_channel *c = (void *) C;
/* XXXX: cleanup bucket and prefix tables */
c->next_hop_addr = IPA_NONE;
c->link_addr = IPA_NONE;
c->packets_to_send = 0;
}
static void
@ -1598,6 +1628,10 @@ bgp_postconfig(struct proto_config *CF)
if (cf->multihop < 0)
cf->multihop = internal ? 64 : 0;
/* Link check for single-hop BGP by default */
if (cf->check_link < 0)
cf->check_link = !cf->multihop;
if (!cf->local_as)
cf_error("Local AS number must be set");
@ -1796,7 +1830,7 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len)
if (code != 6)
{
bgp_update_startup_delay(p);
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}
@ -2017,17 +2051,18 @@ bgp_show_proto_info(struct proto *P)
struct bgp_conn *oc = &p->outgoing_conn;
if ((p->start_state < BSS_CONNECT) &&
(p->startup_timer->expires))
cli_msg(-1006, " Error wait: %d/%d",
p->startup_timer->expires - now, p->startup_delay);
(tm_active(p->startup_timer)))
cli_msg(-1006, " Error wait: %t/%u",
tm_remains(p->startup_timer), p->startup_delay);
if ((oc->state == BS_ACTIVE) &&
(oc->connect_timer->expires))
cli_msg(-1006, " Connect delay: %d/%d",
oc->connect_timer->expires - now, p->cf->connect_delay_time);
(tm_active(oc->connect_timer)))
cli_msg(-1006, " Connect delay: %t/%u",
tm_remains(oc->connect_timer), p->cf->connect_delay_time);
if (p->gr_active_num && p->gr_timer->expires)
cli_msg(-1006, " Restart timer: %d/-", p->gr_timer->expires - now);
if (p->gr_active_num && tm_active(p->gr_timer))
cli_msg(-1006, " Restart timer: %t/-",
tm_remains(p->gr_timer));
}
else if (P->proto_state == PS_UP)
{
@ -2036,21 +2071,16 @@ bgp_show_proto_info(struct proto *P)
bgp_show_capabilities(p, p->conn->local_caps);
cli_msg(-1006, " Neighbor capabilities");
bgp_show_capabilities(p, p->conn->remote_caps);
/* XXXX
cli_msg(-1006, " Session: %s%s%s%s%s%s%s%s",
p->is_internal ? "internal" : "external",
p->cf->multihop ? " multihop" : "",
p->rr_client ? " route-reflector" : "",
p->rs_client ? " route-server" : "",
p->as4_session ? " AS4" : "",
p->add_path_rx ? " add-path-rx" : "",
p->add_path_tx ? " add-path-tx" : "",
p->ext_messages ? " ext-messages" : "");
*/
cli_msg(-1006, " Session: %s%s%s%s%s",
p->is_internal ? "internal" : "external",
p->cf->multihop ? " multihop" : "",
p->rr_client ? " route-reflector" : "",
p->rs_client ? " route-server" : "",
p->as4_session ? " AS4" : "");
cli_msg(-1006, " Source address: %I", p->source_addr);
cli_msg(-1006, " Hold timer: %d/%d",
cli_msg(-1006, " Hold timer: %t/%u",
tm_remains(p->conn->hold_timer), p->conn->hold_time);
cli_msg(-1006, " Keepalive timer: %d/%d",
cli_msg(-1006, " Keepalive timer: %t/%u",
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
}
@ -2063,12 +2093,19 @@ bgp_show_proto_info(struct proto *P)
}
{
/* XXXX ?? */
struct bgp_channel *c;
WALK_LIST(c, p->p.channels)
{
channel_show_info(&c->c);
if (c->c.channel_state == CS_UP)
{
if (ipa_zero(c->link_addr))
cli_msg(-1006, " BGP Next hop: %I", c->next_hop_addr);
else
cli_msg(-1006, " BGP Next hop: %I %I", c->next_hop_addr, c->link_addr);
}
if (c->igp_table_ip4)
cli_msg(-1006, " IGP IPv4 table: %s", c->igp_table_ip4->name);

View File

@ -108,6 +108,7 @@ struct bgp_config {
int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
int setkey; /* Set MD5 password to system SA/SP database */
/* Times below are in seconds */
unsigned gr_time; /* Graceful restart timeout */
unsigned connect_delay_time; /* Minimum delay between connect attempts */
unsigned connect_retry_time; /* Timeout for connect attempts */
@ -210,10 +211,10 @@ struct bgp_conn {
struct bgp_caps *local_caps;
struct bgp_caps *remote_caps;
struct timer *connect_timer;
struct timer *hold_timer;
struct timer *keepalive_timer;
struct event *tx_ev;
timer *connect_timer;
timer *hold_timer;
timer *keepalive_timer;
event *tx_ev;
u32 packets_to_send; /* Bitmap of packet types to be sent */
u32 channels_to_send; /* Bitmap of channels with packets to be sent */
u8 last_channel; /* Channel used last time for TX */
@ -254,11 +255,11 @@ struct bgp_proto {
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
ip_addr source_addr; /* Local address used as an advertised next hop */
ip_addr link_addr; /* Link-local version of source_addr */
struct event *event; /* Event for respawning and shutting process */
struct timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
struct timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
unsigned startup_delay; /* Time to delay protocol startup by due to errors */
bird_clock_t last_proto_error; /* Time of last error that leads to protocol stop */
event *event; /* Event for respawning and shutting process */
timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
timer *gr_timer; /* Timer waiting for reestablishment after graceful restart */
uint startup_delay; /* Delay (in seconds) of protocol startup due to previous errors */
btime last_proto_error; /* Time of last error that leads to protocol stop */
u8 last_error_class; /* Error class of last error */
u32 last_error_code; /* Error code of last error. BGP protocol errors
are encoded as (bgp_err_code << 16 | bgp_err_subcode) */
@ -422,7 +423,7 @@ extern struct linpool *bgp_linpool;
extern struct linpool *bgp_linpool2;
void bgp_start_timer(struct timer *t, int value);
void bgp_start_timer(timer *t, uint value);
void bgp_check_config(struct bgp_config *c);
void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len);
void bgp_close_conn(struct bgp_conn *c);
@ -436,7 +437,7 @@ void bgp_graceful_restart_done(struct bgp_channel *c);
void bgp_refresh_begin(struct bgp_channel *c);
void bgp_refresh_end(struct bgp_channel *c);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
void bgp_stop(struct bgp_proto *p, unsigned subcode);
void bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len);
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
@ -491,11 +492,13 @@ int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
void bgp_init_bucket_table(struct bgp_channel *c);
void bgp_free_bucket_table(struct bgp_channel *c);
void bgp_free_bucket(struct bgp_channel *c, struct bgp_bucket *b);
void bgp_defer_bucket(struct bgp_channel *c, struct bgp_bucket *b);
void bgp_withdraw_bucket(struct bgp_channel *c, struct bgp_bucket *b);
void bgp_init_prefix_table(struct bgp_channel *c);
void bgp_free_prefix_table(struct bgp_channel *c);
void bgp_free_prefix(struct bgp_channel *c, struct bgp_prefix *bp);
int bgp_rte_better(struct rte *, struct rte *);

View File

@ -58,6 +58,7 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->gr_mode = BGP_GR_AWARE;
BGP_CFG->gr_time = 120;
BGP_CFG->setkey = 1;
BGP_CFG->check_link = -1;
}
;

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);
/* Encode MPLS labels */
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
if (s->mpls)
bgp_encode_mpls_labels(s, s->mpls_labels, &pos, &size, pos - 1);
/* Encode route distinguisher */
put_u64(pos, net->rd);
@ -1636,8 +1637,8 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
uint pxlen = data[1];
// FIXME: Use some generic function
memcpy(&px, data, BYTES(pxlen));
px = ip4_and(px, ip4_mkmask(pxlen));
memcpy(&px, data+2, BYTES(pxlen));
px = ip4_and(ip4_ntoh(px), ip4_mkmask(pxlen));
/* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen);
@ -1728,8 +1729,8 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
uint pxlen = data[1];
// FIXME: Use some generic function
memcpy(&px, data, BYTES(pxlen));
px = ip6_and(px, ip6_mkmask(pxlen));
memcpy(&px, data+2, BYTES(pxlen));
px = ip6_and(ip6_ntoh(px), ip6_mkmask(pxlen));
/* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
@ -2678,38 +2679,72 @@ bgp_error_dsc(uint code, uint subcode)
return buff;
}
/* RFC 8203 - shutdown communication message */
static int
bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
{
byte *msg = data + 1;
uint msg_len = data[0];
uint i;
/* Handle zero length message */
if (msg_len == 0)
return 1;
/* Handle proper message */
if ((msg_len > 128) && (msg_len + 1 > len))
return 0;
/* Some elementary cleanup */
for (i = 0; i < msg_len; i++)
if (msg[i] < ' ')
msg[i] = ' ';
proto_set_message(&p->p, msg, msg_len);
*bp += bsprintf(*bp, ": \"%s\"", p->p.message);
return 1;
}
void
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, uint code, uint subcode, byte *data, uint len)
{
const byte *name;
byte *t, argbuf[36];
byte argbuf[256], *t = argbuf;
uint i;
/* Don't report Cease messages generated by myself */
if (code == 6 && class == BE_BGP_TX)
return;
name = bgp_error_dsc(code, subcode);
t = argbuf;
/* Reset shutdown message */
if ((code == 6) && ((subcode == 2) || (subcode == 4)))
proto_set_message(&p->p, NULL, 0);
if (len)
{
*t++ = ':';
*t++ = ' ';
/* Bad peer AS - we would like to print the AS */
if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))
{
/* Bad peer AS - we would like to print the AS */
t += bsprintf(t, "%u", (len == 2) ? get_u16(data) : get_u32(data));
t += bsprintf(t, ": %u", (len == 2) ? get_u16(data) : get_u32(data));
goto done;
}
/* RFC 8203 - shutdown communication */
if (((code == 6) && ((subcode == 2) || (subcode == 4))))
if (bgp_handle_message(p, data, len, &t))
goto done;
*t++ = ':';
*t++ = ' ';
if (len > 16)
len = 16;
for (i=0; i<len; i++)
t += bsprintf(t, "%02x", data[i]);
}
done:
done:
*t = 0;
log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);
const byte *dsc = bgp_error_dsc(code, subcode);
log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, dsc, argbuf);
}
static void
@ -2733,7 +2768,7 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
if (err)
{
bgp_update_startup_delay(p);
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}

View File

@ -78,18 +78,66 @@ static void
ospf_proto_finish(void)
{
struct ospf_config *cf = OSPF_CFG;
if (EMPTY_LIST(cf->area_list))
cf_error( "No configured areas in OSPF");
struct ospf_area_config *ac;
struct ospf_iface_patt *ic;
/* Define default channel */
if (EMPTY_LIST(this_proto->channels))
{
this_proto->net_type = ospf_cfg_is_v2() ? NET_IP4 : NET_IP6;
channel_config_new(NULL, this_proto->net_type, this_proto);
}
/* Propagate global instance ID to interfaces */
if (cf->instance_id_set)
{
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
WALK_LIST(ic, cf->vlink_list)
if (!ic->instance_id_set)
{ ic->instance_id = cf->instance_id; ic->instance_id_set = 1; }
}
if (ospf_cfg_is_v3())
{
uint ipv4 = (this_proto->net_type == NET_IP4);
uint base = (ipv4 ? 64 : 0) + (cf->af_mc ? 32 : 0);
/* RFC 5838 - OSPFv3-AF */
if (cf->af_ext)
{
/* RFC 5838 2.1 - instance IDs based on AFs */
WALK_LIST(ac, cf->area_list)
WALK_LIST(ic, ac->patt_list)
{
if (!ic->instance_id_set)
ic->instance_id = base;
else if (ic->instance_id >= 128)
log(L_WARN "Instance ID %d from unassigned/private range", ic->instance_id);
else if ((ic->instance_id < base) || (ic->instance_id >= (base + 32)))
cf_error("Instance ID %d invalid for given channel type", ic->instance_id);
}
/* RFC 5838 2.8 - vlinks limited to IPv6 unicast */
if ((ipv4 || cf->af_mc) && !EMPTY_LIST(cf->vlink_list))
cf_error("Vlinks not supported in AFs other than IPv6 unicast");
}
else
{
if (ipv4 || cf->af_mc)
cf_error("Different channel type");
}
}
if (EMPTY_LIST(cf->area_list))
cf_error("No configured areas in OSPF");
int areano = 0;
int backbone = 0;
int nssa = 0;
struct ospf_area_config *ac;
WALK_LIST(ac, cf->area_list)
{
areano++;
@ -148,10 +196,11 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION)
CF_KEYWORDS(SECONDARY, MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838)
%type <ld> lsadb_args
%type <i> ospf_variant nbma_eligible
%type <i> ospf_variant ospf_af_mc nbma_eligible
%type <cc> ospf_channel_start ospf_channel
CF_GRAMMAR
@ -166,12 +215,14 @@ ospf_variant:
ospf_proto_start: proto_start ospf_variant
{
this_proto = proto_config_new(&proto_ospf, $1);
this_proto->net_type = $2 ? NET_IP4 : NET_IP6;
this_proto->net_type = $2 ? NET_IP4 : 0;
init_list(&OSPF_CFG->area_list);
init_list(&OSPF_CFG->vlink_list);
OSPF_CFG->ecmp = rt_default_ecmp;
OSPF_CFG->tick = OSPF_DEFAULT_TICK;
OSPF_CFG->ospf2 = $2;
OSPF_CFG->af_ext = !$2;
};
ospf_proto:
@ -179,16 +230,34 @@ ospf_proto:
| ospf_proto ospf_proto_item ';'
;
ospf_af_mc:
{ $$ = 0; }
| MULTICAST { $$ = 1; }
;
/* We redefine proto_channel to add multicast flag */
ospf_channel_start: net_type ospf_af_mc
{
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
/* Save the multicast flag */
if (this_channel == proto_cf_main_channel(this_proto))
OSPF_CFG->af_mc = $2;
};
ospf_channel: ospf_channel_start channel_opt_list channel_end;
ospf_proto_item:
proto_item
| proto_channel
| ospf_channel { this_proto->net_type = $1->net_type; }
| RFC1583COMPAT bool { OSPF_CFG->rfc1583 = $2; }
| RFC5838 bool { OSPF_CFG->af_ext = $2; if (!ospf_cfg_is_v3()) cf_error("RFC5838 option requires OSPFv3"); }
| STUB ROUTER bool { OSPF_CFG->stub_router = $3; }
| ECMP bool { OSPF_CFG->ecmp = $2 ? OSPF_DEFAULT_ECMP_LIMIT : 0; }
| ECMP bool LIMIT expr { OSPF_CFG->ecmp = $2 ? $4 : 0; }
| MERGE EXTERNAL bool { OSPF_CFG->merge_external = $3; }
| TICK expr { OSPF_CFG->tick = $2; if($2 <= 0) cf_error("Tick must be greater than zero"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| INSTANCE ID expr { OSPF_CFG->instance_id = $3; OSPF_CFG->instance_id_set = 1; if ($3 > 255) cf_error("Instance ID must be in range 0-255"); }
| ospf_area
;
@ -293,7 +362,6 @@ ospf_vlink_start: VIRTUAL LINK idval
OSPF_PATT->inftransdelay = INFTRANSDELAY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_VLINK;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
reset_passwords();
}
@ -393,8 +461,8 @@ ospf_iface_start:
OSPF_PATT->priority = PRIORITY_D;
OSPF_PATT->deadc = DEADC_D;
OSPF_PATT->type = OSPF_IT_UNDEF;
OSPF_PATT->instance_id = OSPF_CFG->instance_id;
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->check_link = 1;
OSPF_PATT->ptp_netmask = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
OSPF_PATT->tx_priority = sk_priority_control;
@ -404,7 +472,7 @@ ospf_iface_start:
ospf_instance_id:
/* empty */
| INSTANCE expr { OSPF_PATT->instance_id = $2; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
| INSTANCE expr { OSPF_PATT->instance_id = $2; OSPF_PATT->instance_id_set = 1; if ($2 > 255) cf_error("Instance ID must be in range 0-255"); }
;
ospf_iface_patt_list:
@ -431,7 +499,7 @@ CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEM
CF_ADDTO(dynamic_attr, OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID | EAF_TEMP, T_QUAD, EA_OSPF_ROUTER_ID); })
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol XXX]], CLI_SF_PROTOCOL)
CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]], CLI_SF_PROTOCOL)
{ ospf_sh(proto_get_named($3, &proto_ospf)); };
CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]], CLI_SF_PROTOCOL | CLI_SF_INTERFACE | CLI_SF_PARAMETER)

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)",
n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
if ((rcv_imms == DBDES_IMMS) &&
if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
(n->rid > p->router_id) &&
(plen == ospf_dbdes_hdrlen(p)))
{
@ -428,7 +428,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
}
ospf_send_dbdes(p, n);
tm_start(n->dbdes_timer, n->ifa->rxmtint);
tm_start(n->dbdes_timer, n->ifa->rxmtint S);
}
else
{

View File

@ -32,10 +32,7 @@ struct ospf_hello3_packet
struct ospf_packet hdr;
u32 iface_id;
u8 priority;
u8 options3;
u8 options2;
u8 options;
u32 options;
u16 helloint;
u16 deadint;
u32 dr;
@ -91,10 +88,7 @@ ospf_send_hello(struct ospf_iface *ifa, int kind, struct ospf_neighbor *dirn)
struct ospf_hello3_packet *ps = (void *) pkt;
ps->iface_id = htonl(ifa->iface_id);
ps->priority = ifa->priority;
ps->options3 = ifa->oa->options >> 16;
ps->options2 = ifa->oa->options >> 8;
ps->options = ifa->oa->options;
ps->options = ntohl(ifa->oa->options | (ifa->priority << 24));
ps->helloint = ntohs(ifa->helloint);
ps->deadint = htons(ifa->deadint);
ps->dr = htonl(ifa->drid);
@ -190,7 +184,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
struct ospf_proto *p = ifa->oa->po;
const char *err_dsc = NULL;
u32 rcv_iface_id, rcv_helloint, rcv_deadint, rcv_dr, rcv_bdr;
u8 rcv_options, rcv_priority;
uint rcv_options, rcv_priority;
uint loc_options = ifa->oa->options;
u32 *neighbors;
u32 neigh_count;
uint plen, i, err_val = 0;
@ -245,8 +240,8 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
rcv_deadint = ntohs(ps->deadint);
rcv_dr = ntohl(ps->dr);
rcv_bdr = ntohl(ps->bdr);
rcv_options = ps->options;
rcv_priority = ps->priority;
rcv_options = ntohl(ps->options) & 0x00FFFFFF;
rcv_priority = ntohl(ps->options) >> 24;
neighbors = ps->neighbors;
neigh_count = (plen - sizeof(struct ospf_hello3_packet)) / sizeof(u32);
@ -259,9 +254,13 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
DROP("dead interval mismatch", rcv_deadint);
/* Check whether bits E, N match */
if ((rcv_options ^ ifa->oa->options) & (OPT_E | OPT_N))
if ((rcv_options ^ loc_options) & (OPT_E | OPT_N))
DROP("area type mismatch", rcv_options);
/* RFC 5838 2.4 - AF-bit check unless on IPv6 unicast */
if ((loc_options & OPT_AF) && !(loc_options & OPT_V6) && !(rcv_options & OPT_AF))
DROP("AF-bit mismatch", rcv_options);
/* Check consistency of existing neighbor entry */
if (n)
{

View File

@ -121,6 +121,7 @@ ospf_sk_open(struct ospf_iface *ifa)
sk->dport = OSPF_PROTO;
sk->saddr = ifa->addr->ip;
sk->iface = ifa->iface;
sk->vrf = p->p.vrf;
sk->tos = ifa->cf->tx_tos;
sk->priority = ifa->cf->tx_priority;
@ -204,6 +205,7 @@ ospf_open_vlink_sk(struct ospf_proto *p)
sk->type = SK_IP;
sk->subtype = ospf_is_v2(p) ? SK_IPV4 : SK_IPV6;
sk->dport = OSPF_PROTO;
sk->vrf = p->p.vrf;
/* FIXME: configurable tos/priority ? */
sk->tos = IP_PREC_INTERNET_CONTROL;
@ -396,15 +398,15 @@ ospf_iface_sm(struct ospf_iface *ifa, int event)
{
ospf_iface_chstate(ifa, OSPF_IS_WAITING);
if (ifa->wait_timer)
tm_start(ifa->wait_timer, ifa->waitint);
tm_start(ifa->wait_timer, ifa->waitint S);
}
}
if (ifa->hello_timer)
tm_start(ifa->hello_timer, ifa->helloint);
tm_start(ifa->hello_timer, ifa->helloint S);
if (ifa->poll_timer)
tm_start(ifa->poll_timer, ifa->pollint);
tm_start(ifa->poll_timer, ifa->pollint S);
ospf_send_hello(ifa, OHS_HELLO, NULL);
}
@ -494,13 +496,13 @@ ospf_iface_add(struct object_lock *lock)
if (! ifa->stub)
{
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
if (ifa->type == OSPF_IT_NBMA)
ifa->poll_timer = tm_new_set(ifa->pool, poll_timer_hook, ifa, 0, ifa->pollint);
ifa->poll_timer = tm_new_init(ifa->pool, poll_timer_hook, ifa, ifa->pollint S, 0);
if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA))
ifa->wait_timer = tm_new_set(ifa->pool, wait_timer_hook, ifa, 0, 0);
ifa->wait_timer = tm_new_init(ifa->pool, wait_timer_hook, ifa, 0, 0);
ifa->flood_queue_size = ifa_flood_queue_size(ifa);
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
@ -703,7 +705,7 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
add_tail(&p->iface_list, NODE ifa);
ifa->hello_timer = tm_new_set(ifa->pool, hello_timer_hook, ifa, 0, ifa->helloint);
ifa->hello_timer = tm_new_init(ifa->pool, hello_timer_hook, ifa, ifa->helloint S, 0);
ifa->flood_queue_size = ifa_flood_queue_size(ifa);
ifa->flood_queue = mb_allocz(ifa->pool, ifa->flood_queue_size * sizeof(void *));
@ -715,10 +717,10 @@ ospf_iface_change_timer(timer *tm, uint val)
if (!tm)
return;
tm->recurrent = val;
tm->recurrent = val S;
if (tm->expires)
tm_start(tm, val);
if (tm_active(tm))
tm_start(tm, val S);
}
static inline void
@ -801,8 +803,8 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ifname, ifa->waitint, new->waitint);
ifa->waitint = new->waitint;
if (ifa->wait_timer && ifa->wait_timer->expires)
tm_start(ifa->wait_timer, ifa->waitint);
if (ifa->wait_timer && tm_active(ifa->wait_timer))
tm_start(ifa->wait_timer, ifa->waitint S);
}
/* DEAD TIMER */
@ -1113,9 +1115,6 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
{
struct ospf_proto *p = (struct ospf_proto *) P;
if (a->prefix.type != NET_IP6)
return;
if (a->flags & IA_SECONDARY)
return;
@ -1126,6 +1125,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
other addresses are used for link-LSA. */
if (a->scope == SCOPE_LINK)
{
if (a->prefix.type != NET_IP6)
return;
if (flags & IF_CHANGE_UP)
{
struct ospf_mip_walk s = { .iface = a->iface };
@ -1143,6 +1145,9 @@ ospf_ifa_notify3(struct proto *P, uint flags, struct ifa *a)
}
else
{
if (a->prefix.type != ospf_get_af(p))
return;
struct ospf_iface *ifa;
WALK_LIST(ifa, p->iface_list)
if (ifa->iface == a->iface)

View File

@ -280,7 +280,7 @@ lsa_walk_rt(struct ospf_lsa_rt_walk *rt)
void
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric)
lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric)
{
if (ospf2)
{
@ -292,7 +292,7 @@ lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopt
else
{
struct ospf_lsa_sum3_net *ls = en->lsa_body;
ospf_get_ipv6_prefix(ls->prefix, net, pxopts, NULL);
ospf3_get_prefix(ls->prefix, af, net, pxopts, NULL);
*metric = ls->metric & LSA_METRIC_MASK;
}
}
@ -317,7 +317,7 @@ lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u
}
void
lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt)
lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt)
{
if (ospf2)
{
@ -338,13 +338,13 @@ lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *r
else
{
struct ospf_lsa_ext3 *ext = en->lsa_body;
u32 *buf = ospf_get_ipv6_prefix(ext->rest, &rt->net, &rt->pxopts, NULL);
u32 *buf = ospf3_get_prefix(ext->rest, af, &rt->net, &rt->pxopts, NULL);
rt->metric = ext->metric & LSA_METRIC_MASK;
rt->ebit = ext->metric & LSA_EXT3_EBIT;
rt->fbit = ext->metric & LSA_EXT3_FBIT;
if (rt->fbit)
buf = ospf_get_ipv6_addr(buf, &rt->fwaddr);
buf = ospf3_get_addr(buf, af, &rt->fwaddr);
else
rt->fwaddr = IPA_NONE;

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);
void lsa_walk_rt_init(struct ospf_proto *po, struct top_hash_entry *act, struct ospf_lsa_rt_walk *rt);
int lsa_walk_rt(struct ospf_lsa_rt_walk *rt);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, net_addr *net, u8 *pxopts, u32 *metric);
void lsa_parse_sum_net(struct top_hash_entry *en, int ospf2, int af, net_addr *net, u8 *pxopts, u32 *metric);
void lsa_parse_sum_rt(struct top_hash_entry *en, int ospf2, u32 *drid, u32 *metric, u32 *options);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, struct ospf_lsa_ext_local *rt);
void lsa_parse_ext(struct top_hash_entry *en, int ospf2, int af, struct ospf_lsa_ext_local *rt);
int lsa_validate(struct ospf_lsa_header *lsa, u32 lsa_type, int ospf2, void *body);
static inline btime lsa_inst_age(struct top_hash_entry *en)
{ return current_time() - en->inst_time; }
#endif /* _BIRD_OSPF_LSALIB_H_ */

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

View File

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

View File

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

View File

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

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

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