0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-03 07:31:54 +00:00

Merge branch 'int-new' into show-route

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

2
.gitignore vendored
View File

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

309
.gitlab-ci.yml Normal file
View File

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

View File

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

81
NEWS
View File

@ -1,45 +1,70 @@
Version 2.0.0-pre1 (2017-04-29)
Version 2.0.2 (2018-03-22)
o Source-specific routing support for Linux kernel and Babel
o BGP: New option 'disable after cease'
o Filter: Allow silent filter execution
o Filter: Fixed stack overflow in BGP mask expressions.
o Several bugfixes
Notes:
Syntax prefix:netmask for IPv4 prefixes was dropped. Just use prefix/pxlen.
Version 2.0.1 (2018-01-16)
o Linux MPLS kernel support
o Better handling of channels inherited from templates
o Default EBGP Route Propagation Behavior without Policies (RFC 8212)
o Many bugfixes
Notes:
To satisfy requirements of RFC 8212, external BGP protocols now require
explicit configuration of import and export policies.
Version 2.0.0 (2017-12-11)
o Integrated IPv4 + IPv6 design
o Support for MPLS next hops
o 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

@ -22,13 +22,14 @@ protocol direct {
# Feed routes to kernel FIB
protocol kernel {
ipv4 { export all; };
# learn; # Learn all routes from the kernel
ipv4 { export all; import all; };
learn; # Learn all routes from the kernel
# scan time 10; # Scan kernel tables every 10 seconds
}
protocol kernel {
ipv6;
ipv6 { import all; };
learn;
}
# Static route feed
@ -52,6 +53,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);
@ -452,7 +447,7 @@ config_undo(void)
extern void cmd_reconfig_undo_notify(void);
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"
@ -50,6 +50,8 @@ CF_DECLS
struct rtable_config *r;
struct channel_config *cc;
struct f_inst *x;
struct f_dynamic_attr fda;
struct f_static_attr fsa;
struct filter *f;
struct f_tree *e;
struct f_trie *trie;
@ -61,7 +63,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;
@ -81,11 +83,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_ip6_sadr_ net_mpls_
%type <mls> label_stack_start label_stack
%type <t> text opttext
@ -98,7 +99,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, FROM)
CF_GRAMMAR
@ -138,9 +139,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 */
@ -179,10 +180,6 @@ pxlen4:
if ($2 > IP4_MAX_PREFIX_LENGTH) cf_error("Invalid prefix length %u", $2);
$$ = $2;
}
| ':' IP4 {
$$ = ip4_masklen($2);
if ($$ == 255) cf_error("Invalid netmask %I4", $2);
}
;
net_ip4_: IP4 pxlen4
@ -208,6 +205,25 @@ net_ip6_: IP6 '/' NUM
n->prefix, n->pxlen, ip6_and(n->prefix, ip6_mkmask(n->pxlen)), n->pxlen);
};
net_ip6_sadr_: IP6 '/' NUM FROM IP6 '/' NUM
{
if ($3 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $3);
if ($7 > IP6_MAX_PREFIX_LENGTH)
cf_error("Invalid prefix length %u", $7);
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr($$, $1, $3, $5, $7);
net_addr_ip6_sadr *n = (void *) $$;
if (!net_validate_ip6_sadr(n))
cf_error("Invalid SADR IPv6 prefix %I6/%d from %I6/%d, maybe you wanted %I6/%d from %I6/%d",
n->dst_prefix, n->dst_pxlen, n->src_prefix, n->src_pxlen,
ip6_and(n->dst_prefix, ip6_mkmask(n->dst_pxlen)), n->dst_pxlen,
ip6_and(n->src_prefix, ip6_mkmask(n->src_pxlen)), n->src_pxlen);
};
net_vpn4_: VPN_RD net_ip4_
{
$$ = cfg_alloc(sizeof(net_addr_vpn4));
@ -236,6 +252,12 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
cf_error("Invalid max prefix length %u", $3);
};
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_ ;
@ -245,6 +267,8 @@ net_:
| net_vpn_
| net_roa_
| net_flow_
| net_ip6_sadr_
| net_mpls_
;
@ -309,11 +333,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@:>@])],
[],
@ -175,6 +181,8 @@ else
;;
freebsd*)
sysdesc=bsd
CPPFLAGS="$CPPFLAGS -I/usr/local/include"
LDFLAGS="$LDFLAGS -L/usr/local/lib"
;;
kfreebsd*)
sysdesc=bsd
@ -239,6 +247,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 +309,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 +324,7 @@ if test "$enable_debug" = yes ; then
[
AC_DEFINE([HAVE_EXECINFO_H], [1], [Define to 1 if you have the <execinfo.h> header file.])
AC_SEARCH_LIBS([backtrace], [execinfo],
[]
[],
[AC_MSG_ERROR([Function backtrace not available.])]
)
]
@ -358,12 +368,6 @@ if test "$enable_client" = yes ; then
[$TINFO_LIBS]
)
AC_SEARCH_LIBS([add_history], [history readline],
[HISTORY_LIBS="$LIBS"; LIBS=""],
[AC_MSG_ERROR([The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client.])],
[$TINFO_LIBS]
)
AC_CHECK_LIB([readline], [rl_crlf],
[AC_DEFINE([HAVE_RL_CRLF], [1], [Define to 1 if you have rl_crlf()])],
[],
@ -377,7 +381,7 @@ if test "$enable_client" = yes ; then
)
LIBS="$BASE_LIBS"
CLIENT_LIBS="$HISTORY_LIBS $READLINE_LIBS $TINFO_LIBS"
CLIENT_LIBS="$READLINE_LIBS $TINFO_LIBS"
fi
AC_SUBST([CLIENT])
AC_SUBST([CLIENT_LIBS])
@ -396,6 +400,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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

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

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

View File

@ -1,4 +1,4 @@
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c xmalloc.c
src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(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 */
@ -165,9 +152,9 @@ void debug(const char *msg, ...); /* Printf to debug output */
#endif
#ifdef DEBUGGING
#define ASSERT(x) do { if (!(x)) bug("Assertion `%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
#define ASSERT(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
#else
#define ASSERT(x) do { } while(0)
#define ASSERT(x) do { if (!(x)) log(L_BUG "Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
#endif
/* Pseudorandom numbers */

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

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

105
lib/net.c
View File

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

107
lib/net.h
View File

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

View File

@ -126,9 +126,10 @@ static char * number(char * str, long num, int base, int size, int precision,
* or |%I6| can be used for explicit ip4_addr / ip6_addr arguments, |%N| for
* 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.
@ -140,6 +141,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];
@ -284,7 +287,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 *);
@ -371,6 +373,51 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
snprintf(ipbuf, sizeof(ipbuf), fmtbuf, va_arg(args, double));
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;
@ -412,6 +459,7 @@ int bvsnprintf(char *buf, int size, const char *fmt, va_list args)
str = number(str, num, base, field_width, precision, flags, size);
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;
}
}

378
lib/timer.c Normal file
View File

@ -0,0 +1,378 @@
/*
* BIRD -- Timers
*
* (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2013--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
/**
* DOC: Timers
*
* Timers are resources which represent a wish of a module to call a function at
* the specified time. The timer code does not guarantee exact timing, only that
* a timer function will not be called before the requested time.
*
* In BIRD, time is represented by values of the &btime type which is signed
* 64-bit integer interpreted as a relative number of microseconds since some
* fixed time point in past. The current time can be obtained by current_time()
* function with reasonable accuracy and is monotonic. There is also a current
* 'wall-clock' real time obtainable by current_real_time() reported by OS.
*
* Each timer is described by a &timer structure containing a pointer to the
* handler function (@hook), data private to this function (@data), time the
* function should be called at (@expires, 0 for inactive timers), for the other
* fields see |timer.h|.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "nest/bird.h"
#include "lib/heap.h"
#include "lib/resource.h"
#include "lib/timer.h"
struct timeloop main_timeloop;
#ifdef USE_PTHREADS
#include <pthread.h>
/* Data accessed and modified from proto/bfd/io.c */
pthread_key_t current_time_key;
static inline struct timeloop *
timeloop_current(void)
{
return pthread_getspecific(current_time_key);
}
static inline void
timeloop_init_current(void)
{
pthread_key_create(&current_time_key, NULL);
pthread_setspecific(current_time_key, &main_timeloop);
}
void wakeup_kick_current(void);
#else
/* Just use main timelooop */
static inline struct timeloop * timeloop_current(void) { return &main_timeloop; }
static inline void timeloop_init_current(void) { }
#endif
btime
current_time(void)
{
return timeloop_current()->last_time;
}
btime
current_real_time(void)
{
struct timeloop *loop = timeloop_current();
if (!loop->real_time)
times_update_real_time(loop);
return loop->real_time;
}
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
heap[a]->index = (a), heap[b]->index = (b))
static void
tm_free(resource *r)
{
timer *t = (void *) r;
tm_stop(t);
}
static void
tm_dump(resource *r)
{
timer *t = (void *) r;
debug("(code %p, data %p, ", t->hook, t->data);
if (t->randomize)
debug("rand %d, ", t->randomize);
if (t->recurrent)
debug("recur %d, ", t->recurrent);
if (t->expires)
debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
else
debug("inactive)\n");
}
static struct resclass tm_class = {
"Timer",
sizeof(timer),
tm_free,
tm_dump,
NULL,
NULL
};
timer *
tm_new(pool *p)
{
timer *t = ralloc(p, &tm_class);
t->index = -1;
return t;
}
void
tm_set(timer *t, btime when)
{
struct timeloop *loop = timeloop_current();
uint tc = timers_count(loop);
if (!t->expires)
{
t->index = ++tc;
t->expires = when;
BUFFER_PUSH(loop->timers) = t;
HEAP_INSERT(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP);
}
else if (t->expires < when)
{
t->expires = when;
HEAP_INCREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
}
else if (t->expires > when)
{
t->expires = when;
HEAP_DECREASE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
}
#ifdef CONFIG_BFD
/* Hack to notify BFD loops */
if ((loop != &main_timeloop) && (t->index == 1))
wakeup_kick_current();
#endif
}
void
tm_start(timer *t, btime after)
{
tm_set(t, current_time() + MAX(after, 0));
}
void
tm_stop(timer *t)
{
if (!t->expires)
return;
struct timeloop *loop = timeloop_current();
uint tc = timers_count(loop);
HEAP_DELETE(loop->timers.data, tc, timer *, TIMER_LESS, TIMER_SWAP, t->index);
BUFFER_POP(loop->timers);
t->index = -1;
t->expires = 0;
}
void
timers_init(struct timeloop *loop, pool *p)
{
times_init(loop);
BUFFER_INIT(loop->timers, p, 4);
BUFFER_PUSH(loop->timers) = NULL;
}
void io_log_event(void *hook, void *data);
void
timers_fire(struct timeloop *loop)
{
btime base_time;
timer *t;
times_update(loop);
base_time = loop->last_time;
while (t = timers_first(loop))
{
if (t->expires > base_time)
return;
if (t->recurrent)
{
btime when = t->expires + t->recurrent;
if (when <= loop->last_time)
when = loop->last_time + t->recurrent;
if (t->randomize)
when += random() % (t->randomize + 1);
tm_set(t, when);
}
else
tm_stop(t);
/* This is ugly hack, we want to log just timers executed from the main I/O loop */
if (loop == &main_timeloop)
io_log_event(t->hook, t->data);
t->hook(t);
}
}
void
timer_init(void)
{
timers_init(&main_timeloop, &root_pool);
timeloop_init_current();
}
/**
* tm_parse_time - parse a date and time
* @x: time string
*
* tm_parse_time() takes a textual representation of a date and time
* (yyyy-mm-dd[ hh:mm:ss[.sss]]) and converts it to the corresponding value of
* type &btime.
*/
btime
tm_parse_time(char *x)
{
struct tm tm;
int usec, n1, n2, n3, r;
r = sscanf(x, "%d-%d-%d%n %d:%d:%d%n.%d%n",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &n1,
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &n2,
&usec, &n3);
if ((r == 3) && !x[n1])
tm.tm_hour = tm.tm_min = tm.tm_sec = usec = 0;
else if ((r == 6) && !x[n2])
usec = 0;
else if ((r == 7) && !x[n3])
{
/* Convert subsecond digits to proper precision */
int digits = n3 - n2 - 1;
if ((usec < 0) || (usec > 999999) || (digits < 1) || (digits > 6))
return 0;
while (digits++ < 6)
usec *= 10;
}
else
return 0;
tm.tm_mon--;
tm.tm_year -= 1900;
s64 ts = mktime(&tm);
if ((ts == (s64) (time_t) -1) || (ts < 0) || (ts > ((s64) 1 << 40)))
return 0;
return ts S + usec;
}
/**
* tm_format_time - convert date and time to textual representation
* @x: destination buffer of size %TM_DATETIME_BUFFER_SIZE
* @fmt: specification of resulting textual representation of the time
* @t: time
*
* This function formats the given relative time value @t to a textual
* date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
*/
void
tm_format_time(char *x, struct timeformat *fmt, btime t)
{
btime dt = current_time() - t;
btime rt = current_real_time() - dt;
int v1 = !fmt->limit || (dt < fmt->limit);
tm_format_real_time(x, v1 ? fmt->fmt1 : fmt->fmt2, rt);
}
/* Replace %f in format string with usec scaled to requested precision */
static int
strfusec(char *buf, int size, const char *fmt, uint usec)
{
char *str = buf;
int parity = 0;
while (*fmt)
{
if (!size)
return 0;
if ((fmt[0] == '%') && (!parity) &&
((fmt[1] == 'f') || (fmt[1] >= '1') && (fmt[1] <= '6') && (fmt[2] == 'f')))
{
int digits = (fmt[1] == 'f') ? 6 : (fmt[1] - '0');
uint d = digits, u = usec;
/* Convert microseconds to requested precision */
while (d++ < 6)
u /= 10;
int num = bsnprintf(str, size, "%0*u", digits, u);
if (num < 0)
return 0;
fmt += (fmt[1] == 'f') ? 2 : 3;
ADVANCE(str, size, num);
}
else
{
/* Handle '%%' expression */
parity = (*fmt == '%') ? !parity : 0;
*str++ = *fmt++;
size--;
}
}
if (!size)
return 0;
*str = 0;
return str - buf;
}
void
tm_format_real_time(char *x, const char *fmt, btime t)
{
s64 t1 = t TO_S;
s64 t2 = t - t1 S;
time_t ts = t1;
struct tm tm;
if (!localtime_r(&ts, &tm))
goto err;
byte tbuf[TM_DATETIME_BUFFER_SIZE];
if (!strfusec(tbuf, TM_DATETIME_BUFFER_SIZE, fmt, t2))
goto err;
if (!strftime(x, TM_DATETIME_BUFFER_SIZE, tbuf, &tm))
goto err;
return;
err:
strcpy(x, "<error>");
}

127
lib/timer.h Normal file
View File

@ -0,0 +1,127 @@
/*
* BIRD -- Timers
*
* (c) 2013--2017 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2013--2017 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#ifndef _BIRD_TIMER_H_
#define _BIRD_TIMER_H_
#include "nest/bird.h"
#include "lib/buffer.h"
#include "lib/resource.h"
typedef struct timer
{
resource r;
void (*hook)(struct timer *);
void *data;
btime expires; /* 0=inactive */
uint randomize; /* Amount of randomization */
uint recurrent; /* Timer recurrence */
int index;
} timer;
struct timeloop
{
BUFFER_(timer *) timers;
btime last_time;
btime real_time;
};
static inline uint timers_count(struct timeloop *loop)
{ return loop->timers.used - 1; }
static inline timer *timers_first(struct timeloop *loop)
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
extern struct timeloop main_timeloop;
btime current_time(void);
btime current_real_time(void);
//#define now (current_time() TO_S)
//#define now_real (current_real_time() TO_S)
extern btime boot_time;
timer *tm_new(pool *p);
void tm_set(timer *t, btime when);
void tm_start(timer *t, btime after);
void tm_stop(timer *t);
static inline int
tm_active(timer *t)
{
return t->expires != 0;
}
static inline btime
tm_remains(timer *t)
{
btime now_ = current_time();
return (t->expires > now_) ? (t->expires - now_) : 0;
}
static inline timer *
tm_new_init(pool *p, void (*hook)(struct timer *), void *data, uint rec, uint rand)
{
timer *t = tm_new(p);
t->hook = hook;
t->data = data;
t->recurrent = rec;
t->randomize = rand;
return t;
}
static inline void
tm_set_max(timer *t, btime when)
{
if (when > t->expires)
tm_set(t, when);
}
static inline void
tm_start_max(timer *t, btime after)
{
btime rem = tm_remains(t);
tm_start(t, MAX_(rem, after));
}
/* In sysdep code */
void times_init(struct timeloop *loop);
void times_update(struct timeloop *loop);
void times_update_real_time(struct timeloop *loop);
/* For I/O loop */
void timers_init(struct timeloop *loop, pool *p);
void timers_fire(struct timeloop *loop);
void timer_init(void);
struct timeformat {
char *fmt1, *fmt2;
btime limit;
};
#define TM_ISO_SHORT_S (struct timeformat){"%T", "%F", (s64) (20*3600) S_}
#define TM_ISO_SHORT_MS (struct timeformat){"%T.%3f", "%F", (s64) (20*3600) S_}
#define TM_ISO_SHORT_US (struct timeformat){"%T.%6f", "%F", (s64) (20*3600) S_}
#define TM_ISO_LONG_S (struct timeformat){"%F %T", NULL, 0}
#define TM_ISO_LONG_MS (struct timeformat){"%F %T.%3f", NULL, 0}
#define TM_ISO_LONG_US (struct timeformat){"%F %T.%6f", NULL, 0}
#define TM_DATETIME_BUFFER_SIZE 32 /* Buffer size required by tm_format_time() */
btime tm_parse_time(char *x);
void tm_format_time(char *x, struct timeformat *fmt, btime t);
void tm_format_real_time(char *x, const char *fmt, btime t);
#endif

View File

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

View File

@ -0,0 +1,11 @@
FROM centos:6
RUN yum -y upgrade
RUN yum -y install \
autoconf \
flex \
bison \
pkgconfig \
'readline-devel' \
'pkgconfig(ncurses)' \
gcc \
make

View File

@ -0,0 +1,11 @@
FROM centos:7
RUN yum -y upgrade
RUN yum -y install \
autoconf \
flex \
bison \
pkgconfig \
'readline-devel' \
'pkgconfig(ncurses)' \
gcc \
make

View File

@ -0,0 +1,12 @@
FROM debian:wheezy-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM i386/debian:wheezy-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM debian:jessie-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM i386/debian:jessie-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM debian:stretch-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM i386/debian:stretch-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM debian:testing-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM i386/debian:testing-slim
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,10 @@
FROM fedora:25
RUN dnf -y upgrade
RUN dnf -y install \
autoconf \
flex \
bison \
pkgconfig \
'readline-devel' \
'pkgconfig(ncurses)' \
gcc

View File

@ -0,0 +1,10 @@
FROM fedora:26
RUN dnf -y upgrade
RUN dnf -y install \
autoconf \
flex \
bison \
pkgconfig \
'readline-devel' \
'pkgconfig(ncurses)' \
gcc

View File

@ -0,0 +1,11 @@
FROM opensuse:42.3
RUN zypper -n up
RUN zypper -n install \
autoconf \
flex \
bison \
pkgconfig \
readline-devel \
ncurses-devel \
gcc \
gmake

View File

@ -0,0 +1,12 @@
FROM ubuntu:14.04
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

@ -0,0 +1,12 @@
FROM ubuntu:16.04
ENV DEBIAN_FRONTEND noninteractive
RUN sed -i 's/deb.debian.org/ftp.cz.debian.org/' /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install \
autoconf \
build-essential \
flex \
bison \
ncurses-dev \
libreadline-dev

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -25,12 +25,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,18 +65,19 @@ 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(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(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)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
@ -123,24 +124,6 @@ idval:
}
;
CF_ADDTO(conf, listen)
listen: LISTEN BGP listen_opts ';' ;
listen_opts:
/* Nothing */
| listen_opts listen_opt
;
listen_opt:
ADDRESS ipa { new_config->listen_bgp_addr = $2; }
| PORT expr { new_config->listen_bgp_port = $2; }
| V6ONLY { new_config->listen_bgp_flags = 0; }
| DUAL { new_config->listen_bgp_flags = 1; }
;
CF_ADDTO(conf, gr_opts)
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
@ -151,15 +134,17 @@ gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
net_type:
IPV4 { $$ = NET_IP4; }
| IPV6 { $$ = NET_IP6; }
| IPV6 SADR { $$ = NET_IP6_SADR; }
| VPN4 { $$ = NET_VPN4; }
| VPN6 { $$ = NET_VPN6; }
| ROA4 { $$ = NET_ROA4; }
| 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)
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR)
/* Creation of routing tables */
@ -167,7 +152,7 @@ CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6)
CF_ADDTO(conf, table)
table_sorted:
{ $$ = 0; }
{ $$ = 0; }
| SORTED { $$ = 1; }
;
@ -224,12 +209,13 @@ 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); }
;
channel_start: net_type
{
$$ = this_channel = channel_config_new(NULL, $1, this_proto);
$$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
};
channel_item:
@ -295,6 +281,7 @@ limit_spec:
| OFF { $$ = (struct channel_limit){}; }
;
CF_ADDTO(conf, debug_default)
debug_default:
@ -304,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:
@ -443,9 +455,9 @@ password_item:
password_item_begin:
PASSWORD text {
if (!this_p_list) {
this_p_list = cfg_alloc(sizeof(list));
init_list(this_p_list);
password_id = 1;
this_p_list = cfg_alloc(sizeof(list));
init_list(this_p_list);
password_id = 1;
}
this_p_item = cfg_alloc(sizeof (struct password_item));
this_p_item->password = $2;
@ -462,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; }
;
@ -614,6 +626,7 @@ r_args_for:
}
| net_vpn4_
| net_vpn6_
| net_ip6_sadr_
| VPN_RD IP4 {
$$ = cfg_alloc(sizeof(net_addr_vpn4));
net_fill_vpn4($$, $2, IP4_MAX_PREFIX_LENGTH, $1);
@ -622,6 +635,10 @@ r_args_for:
$$ = cfg_alloc(sizeof(net_addr_vpn6));
net_fill_vpn6($$, $2, IP6_MAX_PREFIX_LENGTH, $1);
}
| IP6 FROM IP6 {
$$ = cfg_alloc(sizeof(net_addr_ip6_sadr));
net_fill_ip6_sadr($$, $1, IP6_MAX_PREFIX_LENGTH, $3, IP6_MAX_PREFIX_LENGTH);
}
| SYM {
if ($1->class == (SYM_CONSTANT | T_IP))
{
@ -655,6 +672,7 @@ r_args_channel:
| IPV6 { $$ = "ipv6"; }
| IPV6_MC { $$ = "ipv6-mc"; }
| IPV6_MPLS { $$ = "ipv6-mpls"; }
| IPV6_SADR { $$ = "ipv6-sadr"; }
| VPN4 { $$ = "vpn4"; }
| VPN4_MC { $$ = "vpn4-mc"; }
| VPN4_MPLS { $$ = "vpn4-mpls"; }
@ -728,12 +746,12 @@ echo_size:
}
;
CF_CLI(DISABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Disable protocol]])
{ proto_apply_cmd($2, proto_cmd_disable, 1, 0); } ;
CF_CLI(ENABLE, proto_patt, <protocol> | \"<pattern>\" | all, [[Enable protocol]])
{ proto_apply_cmd($2, proto_cmd_enable, 1, 0); } ;
CF_CLI(RESTART, proto_patt, <protocol> | \"<pattern>\" | all, [[Restart protocol]])
{ proto_apply_cmd($2, proto_cmd_restart, 1, 0); } ;
CF_CLI(DISABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Disable protocol]])
{ proto_apply_cmd($2, proto_cmd_disable, 1, (uintptr_t) $3); } ;
CF_CLI(ENABLE, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Enable protocol]])
{ proto_apply_cmd($2, proto_cmd_enable, 1, (uintptr_t) $3); } ;
CF_CLI(RESTART, proto_patt opttext, (<protocol> | \"<pattern>\" | all) [message], [[Restart protocol]])
{ proto_apply_cmd($2, proto_cmd_restart, 1, (uintptr_t) $3); } ;
CF_CLI(RELOAD, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol]])
{ proto_apply_cmd($2, proto_cmd_reload, 1, CMD_RELOAD); } ;
CF_CLI(RELOAD IN, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protocol (just imported routes)]])

View File

@ -32,11 +32,14 @@
#include "lib/resource.h"
#include "lib/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" : "");
}
/**
@ -89,7 +93,8 @@ if_dump(struct iface *i)
WALK_LIST(a, i->addrs)
{
ifa_dump(a);
ASSERT((a != i->addr) == !(a->flags & IA_PRIMARY));
ASSERT(!!(a->flags & IA_PRIMARY) ==
((a == i->addr4) || (a == i->addr6) || (a == i->llv6)));
}
}
@ -116,7 +121,7 @@ if_what_changed(struct iface *i, struct iface *j)
unsigned c;
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 +138,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 +183,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 +193,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,20 +222,14 @@ if_notify_change(unsigned c, struct iface *i)
if (c & IF_CHANGE_DOWN)
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);
WALK_LIST(p, proto_list)
if_send_notify(p, c, 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);
if (c & IF_CHANGE_UP)
neigh_if_up(i);
@ -232,24 +238,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);
}
@ -297,7 +304,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 */
@ -305,10 +311,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;
}
@ -339,13 +348,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);
}
@ -363,7 +375,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);
}
@ -460,40 +472,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
@ -525,7 +596,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);
@ -533,15 +604,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;
}
@ -564,16 +635,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;
}
@ -740,16 +819,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
@ -764,7 +844,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
@ -778,10 +864,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, "");
@ -791,16 +880,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

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

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

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

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)
{
@ -436,7 +437,7 @@ static void
channel_request_reload(struct channel *c)
{
ASSERT(c->channel_state == CS_UP);
// ASSERT(channel_reloadable(c));
ASSERT(channel_reloadable(c));
c->proto->reload_routes(c);
@ -454,11 +455,10 @@ const struct channel_class channel_basic = {
};
void *
channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto)
channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{
struct channel_config *cf = NULL;
struct rtable_config *tab = NULL;
const char *name = NULL;
if (net_type)
{
@ -469,7 +469,6 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
cf_error("Different channel type");
tab = new_config->def_tables[net_type];
name = net_label[net_type];
}
if (!cc)
@ -478,6 +477,7 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
cf = cfg_allocz(cc->config_size);
cf->name = name;
cf->channel = cc;
cf->parent = proto;
cf->table = tab;
cf->out_filter = FILTER_REJECT;
@ -490,6 +490,26 @@ channel_config_new(const struct channel_class *cc, uint net_type, struct proto_c
return cf;
}
void *
channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto)
{
struct channel_config *cf;
/* We are using name as token, so no strcmp() */
WALK_LIST(cf, proto->channels)
if (cf->name == name)
{
/* Allow to redefine channel only if inherited from template */
if (cf->parent == proto)
cf_error("Multiple %s channels", name);
cf->parent = proto;
return cf;
}
return channel_config_new(cc, name, net_type, proto);
}
struct channel_config *
channel_copy_config(struct channel_config *src, struct proto_config *proto)
{
@ -512,8 +532,9 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
if ((c->table != cf->table->table) || (cf->ra_mode && (c->ra_mode != cf->ra_mode)))
return 0;
int import_changed = !filter_same(c->in_filter, cf->in_filter);
int export_changed = !filter_same(c->out_filter, cf->out_filter);
/* Note that filter_same() requires arguments in (new, old) order */
int import_changed = !filter_same(cf->in_filter, c->in_filter);
int export_changed = !filter_same(cf->out_filter, c->out_filter);
if (c->preference != cf->preference)
import_changed = 1;
@ -672,7 +693,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 +841,8 @@ proto_reconfigure(struct proto *p, struct proto_config *oc, struct proto_config
/* If there is a too big change in core attributes, ... */
if ((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 +1000,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 +1070,7 @@ proto_rethink_goal(struct proto *p)
*
*/
static void graceful_restart_done(struct timer *t);
static void graceful_restart_done(timer *t);
/**
* graceful_restart_recovery - request initial graceful restart recovery
@ -1083,9 +1107,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 +1122,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 +1159,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 +1321,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 +1352,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 +1556,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 +1676,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 +1701,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 +1722,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 +1733,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 +1749,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 +1766,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 +1774,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 +1813,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 +1838,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 +1854,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
@ -334,7 +337,7 @@ void proto_notify_state(struct proto *p, unsigned state);
*
* HUNGRY ----> FEEDING
* ^ |
* | V
* | V
* FLUSHING <---- HAPPY
*
* States: HUNGRY Protocol either administratively down (i.e.,
@ -458,6 +461,7 @@ struct channel_config {
const char *name;
const struct channel_class *channel;
struct proto_config *parent; /* Where channel is defined (proto or template) */
struct rtable_config *table; /* Table we're attached to */
struct filter *in_filter, *out_filter; /* Attached filters */
struct channel_limit rx_limit; /* Limit for receiving routes from protocol
@ -508,7 +512,7 @@ struct channel {
u8 gr_lock; /* Graceful restart mechanism should wait for this channel */
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
bird_clock_t last_state_change; /* Time of last state transition */
btime last_state_change; /* Time of last state transition */
};
@ -582,7 +586,8 @@ static inline void channel_open(struct channel *c) { channel_set_state(c, CS_UP)
static inline void channel_close(struct channel *c) { channel_set_state(c, CS_FLUSHING); }
void channel_request_feeding(struct channel *c);
void *channel_config_new(const struct channel_class *cc, uint net_type, struct proto_config *proto);
void *channel_config_new(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
void *channel_config_get(const struct channel_class *cc, const char *name, uint net_type, struct proto_config *proto);
int channel_reconfigure(struct channel *c, struct channel_config *cf);

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;
@ -75,7 +74,7 @@ static inline struct fib_node * fib_user_to_node(struct fib *f, void *e)
void fib_init(struct fib *f, pool *p, uint addr_type, uint node_size, uint node_offset, uint hash_order, fib_init_fn init);
void *fib_find(struct fib *, const net_addr *); /* Find or return NULL if doesn't exist */
void *fib_get_chain(struct fib *f, const net_addr *a); /* Find first node in linked list from hash table */
void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */
void *fib_get(struct fib *, const net_addr *); /* Find or create new if nonexistent */
void *fib_route(struct fib *, const net_addr *); /* Longest-match routing lookup */
void fib_delete(struct fib *, void *); /* Remove fib entry */
void fib_free(struct fib *); /* Destroy the fib */
@ -105,7 +104,7 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin
type *z; \
for(;;) { \
if (!fn_) \
{ \
{ \
if (++hpos_ >= count_) \
break; \
fn_ = (fib)->hash_table[hpos_]; \
@ -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;
@ -282,7 +282,7 @@ void rt_preconfig(struct config *);
void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *);
void rt_unlock_table(rtable *);
void rt_setup(pool *, rtable *, char *, struct rtable_config *);
void rt_setup(pool *, rtable *, struct rtable_config *);
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
{ net *n = net_find(tab, addr); return (n && rte_is_valid(n->routes)) ? n : NULL; }
@ -309,6 +309,8 @@ int rt_feed_channel(struct channel *c);
void rt_feed_channel_abort(struct channel *c);
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)
@ -552,6 +555,46 @@ uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
ea_list *ea_append(ea_list *to, ea_list *what);
void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
static inline eattr *
ea_set_attr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, uintptr_t val)
{
ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
eattr *e = &a->attrs[0];
a->flags = EALF_SORTED;
a->count = 1;
a->next = *to;
*to = a;
e->id = id;
e->type = type;
e->flags = flags;
if (type & EAF_EMBEDDED)
e->u.data = (u32) val;
else
e->u.ptr = (struct adata *) val;
return e;
}
static inline void
ea_set_attr_u32(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, u32 val)
{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); }
static inline void
ea_set_attr_ptr(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, struct adata *val)
{ ea_set_attr(to, pool, id, flags, type, (uintptr_t) val); }
static inline void
ea_set_attr_data(ea_list **to, struct linpool *pool, uint id, uint flags, uint type, void *data, uint len)
{
struct adata *a = lp_alloc_adata(pool, len);
memcpy(a->data, data, len);
ea_set_attr(to, pool, id, flags, type, (uintptr_t) a);
}
#define NEXTHOP_MAX_SIZE (sizeof(struct nexthop) + sizeof(u32)*MPLS_MAX_LABEL_STACK)
static inline size_t nexthop_size(const struct nexthop *nh)
@ -620,7 +663,7 @@ extern struct protocol *attr_class_to_protocol[EAP_MAX];
* Default protocol preferences
*/
#define DEF_PREF_DIRECT 240 /* Directly connected */
#define DEF_PREF_DIRECT 240 /* Directly connected */
#define DEF_PREF_STATIC 200 /* Static route */
#define DEF_PREF_OSPF 150 /* OSPF intra-area, inter-area and type 1 external routes */
#define DEF_PREF_BABEL 130 /* Babel */

View File

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

View File

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

View File

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

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@
* BIRD -- The Babel protocol
*
* 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)
@ -80,7 +85,10 @@ enum babel_tlv_type {
enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0,
BABEL_SUBTLV_PADN = 1
BABEL_SUBTLV_PADN = 1,
/* Mandatory subtlvs */
BABEL_SUBTLV_SOURCE_PREFIX = 128,
};
enum babel_iface_type {
@ -102,8 +110,11 @@ enum babel_ae_type {
struct babel_config {
struct proto_config c;
list iface_list; /* List of iface configs (struct babel_iface_config) */
uint hold_time; /* Time to hold stale entries and unreachable routes */
list iface_list; /* Patterns configured -- keep it first; see babel_reconfigure why */
struct channel_config *ip4_channel;
struct channel_config *ip6_channel;
};
struct babel_iface_config {
@ -111,11 +122,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 +150,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 +183,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 +197,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 +219,7 @@ struct babel_source {
u64 router_id;
u16 seqno;
u16 metric;
bird_clock_t expires;
btime expires;
};
struct babel_route {
@ -212,37 +228,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 +277,7 @@ struct babel_seqno_request {
struct babel_msg_ack_req {
u8 type;
u16 nonce;
u16 interval;
uint interval;
ip_addr sender;
};
@ -264,7 +289,7 @@ struct babel_msg_ack {
struct babel_msg_hello {
u8 type;
u16 seqno;
u16 interval;
uint interval;
ip_addr sender;
};
@ -272,7 +297,7 @@ struct babel_msg_ihu {
u8 type;
u8 ae;
u16 rxcost;
u16 interval;
uint interval;
ip_addr addr;
ip_addr sender;
};
@ -280,11 +305,14 @@ struct babel_msg_ihu {
struct babel_msg_update {
u8 type;
u8 wildcard;
u16 interval;
uint interval;
u16 seqno;
u16 metric;
u64 router_id;
net_addr net;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr next_hop;
ip_addr sender;
};
@ -292,7 +320,10 @@ struct babel_msg_update {
struct babel_msg_route_request {
u8 type;
u8 full;
net_addr net;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
};
struct babel_msg_seqno_request {
@ -300,7 +331,10 @@ struct babel_msg_seqno_request {
u8 hop_count;
u16 seqno;
u64 router_id;
net_addr net;
union {
net_addr net;
net_addr_ip6_sadr net_sadr;
};
ip_addr sender;
};
@ -320,6 +354,8 @@ struct babel_msg_node {
union babel_msg msg;
};
static inline int babel_sadr_enabled(struct babel_proto *p)
{ return p->ip6_rtable.addr_type == NET_IP6_SADR; }
/* babel.c */
void babel_handle_ack_req(union babel_msg *msg, struct babel_iface *ifa);
@ -334,6 +370,7 @@ void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_show_interfaces(struct proto *P, char *iff);
void babel_show_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.
*/
@ -20,9 +22,10 @@ CF_DEFINES
CF_DECLS
CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED,
WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC, NEXT, HOP,
IPV4, IPV6)
CF_KEYWORDS(BABEL, INTERFACE, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT,
TYPE, WIRED, WIRELESS, RX, TX, BUFFER, PRIORITY, LENGTH, CHECK, LINK,
NEXT, HOP, IPV4, IPV6, BABEL_METRIC, SHOW, INTERFACES, NEIGHBORS,
ENTRIES)
CF_GRAMMAR
@ -32,6 +35,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 +60,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 +88,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 +137,9 @@ CF_CLI(SHOW BABEL NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show
CF_CLI(SHOW BABEL ENTRIES, optsym opttext, [<name>], [[Show information about Babel prefix entries]])
{ 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;
@ -103,9 +105,20 @@ struct babel_tlv_seqno_request {
u8 addr[0];
} PACKED;
struct babel_subtlv_source_prefix {
u8 type;
u8 length;
u8 plen;
u8 addr[0];
} PACKED;
#define BABEL_FLAG_DEF_PREFIX 0x80
#define BABEL_FLAG_ROUTER_ID 0x40
/* Hello flags */
#define BABEL_HF_UNICAST 0x8000
/* Update flags */
#define BABEL_UF_DEF_PREFIX 0x80
#define BABEL_UF_ROUTER_ID 0x40
struct babel_parse_state {
@ -121,6 +134,7 @@ struct babel_parse_state {
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
u8 sadr_enabled;
};
enum parse_result {
@ -162,17 +176,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
@ -231,6 +245,7 @@ static int babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *msg, stru
static int babel_read_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static int babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg, struct babel_parse_state *state);
static uint babel_write_ack(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_hello(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
@ -238,6 +253,7 @@ static uint babel_write_ihu(struct babel_tlv *hdr, union babel_msg *msg, struct
static uint babel_write_update(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_route_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static uint babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *msg, struct babel_write_state *state, uint max_len);
static int babel_write_source_prefix(struct babel_tlv *hdr, net_addr *net, uint max_len);
struct babel_tlv_data {
u8 min_length;
@ -341,6 +357,11 @@ babel_read_hello(struct babel_tlv *hdr, union babel_msg *m,
struct babel_tlv_hello *tlv = (void *) hdr;
struct babel_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 +614,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 +625,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 +650,16 @@ 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 (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
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 +772,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;
@ -759,12 +783,21 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
put_u16(&tlv->seqno, msg->seqno);
put_u16(&tlv->metric, msg->metric);
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - (len0 + len));
if (l < 0)
return 0;
len += l;
}
return len0 + len;
}
static int
babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
struct babel_parse_state *state UNUSED)
struct babel_parse_state *state)
{
struct babel_tlv_route_request *tlv = (void *) hdr;
struct babel_msg_route_request *msg = &m->route_request;
@ -801,6 +834,10 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
if (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@ -845,6 +882,15 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
put_ip6_px(tlv->addr, &msg->net);
}
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
if (l < 0)
return 0;
len += l;
}
return len;
}
@ -889,6 +935,10 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
if (state->sadr_enabled)
net_make_ip6_sadr(&msg->net);
return PARSE_SUCCESS;
case BABEL_AE_IP6_LL:
@ -932,38 +982,147 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id);
if (msg->net.type == NET_IP6_SADR)
{
int l = babel_write_source_prefix(hdr, &msg->net, max_len - len);
if (l < 0)
return 0;
len += l;
}
return len;
}
static int
babel_read_source_prefix(struct babel_tlv *hdr, union babel_msg *msg,
struct babel_parse_state *state UNUSED)
{
struct babel_subtlv_source_prefix *tlv = (void *) hdr;
net_addr_ip6_sadr *net;
/*
* We would like to skip the sub-TLV if SADR is not enabled, but we do not
* know AF of the enclosing TLV yet. We will do that later.
*/
/* Check internal consistency */
if ((tlv->length < 1) ||
(tlv->plen > IP6_MAX_PREFIX_LENGTH) ||
(tlv->length < (1 + BYTES(tlv->plen))))
return PARSE_ERROR;
/* Plen MUST NOT be 0 */
if (tlv->plen == 0)
return PARSE_ERROR;
switch(msg->type)
{
case BABEL_TLV_UPDATE:
/* Wildcard updates with source prefix MUST be silently ignored */
if (msg->update.wildcard)
return PARSE_IGNORE;
net = (void *) &msg->update.net;
break;
case BABEL_TLV_ROUTE_REQUEST:
/* Wildcard requests with source addresses MUST be silently ignored */
if (msg->route_request.full)
return PARSE_IGNORE;
net = (void *) &msg->route_request.net;
break;
case BABEL_TLV_SEQNO_REQUEST:
net = (void *) &msg->seqno_request.net;
break;
default:
return PARSE_ERROR;
}
/* If SADR is active, the net has appropriate type */
if (net->type != NET_IP6_SADR)
return PARSE_IGNORE;
/* Duplicate Source Prefix sub-TLV; SHOULD ignore whole TLV */
if (net->src_pxlen > 0)
return PARSE_IGNORE;
net_addr_ip6 src;
read_ip6_px((void *) &src, tlv->addr, tlv->plen);
net->src_prefix = src.prefix;
net->src_pxlen = src.pxlen;
return PARSE_SUCCESS;
}
static int
babel_write_source_prefix(struct babel_tlv *hdr, net_addr *n, uint max_len)
{
struct babel_subtlv_source_prefix *tlv = (void *) NEXT_TLV(hdr);
net_addr_ip6_sadr *net = (void *) n;
/* Do not use this sub-TLV for default prefix */
if (net->src_pxlen == 0)
return 0;
uint len = sizeof(*tlv) + BYTES(net->src_pxlen);
if (len > max_len)
return -1;
TLV_HDR(tlv, BABEL_SUBTLV_SOURCE_PREFIX, len);
hdr->length += len;
net_addr_ip6 src = NET_ADDR_IP6(net->src_prefix, net->src_pxlen);
tlv->plen = src.pxlen;
put_ip6_px(tlv->addr, (void *) &src);
return len;
}
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
union babel_msg *msg UNUSED,
union babel_msg *msg,
struct babel_parse_state *state)
{
struct babel_tlv *tlv;
byte *pos, *end = (byte *) hdr + TLV_LENGTH(hdr);
int res;
for (tlv = (void *) hdr + state->current_tlv_endpos;
(void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
(byte *) tlv < end;
tlv = NEXT_TLV(tlv))
{
/* Ugly special case */
if (tlv->type == BABEL_TLV_PAD1)
continue;
/* The end of the common TLV header */
pos = (byte *)tlv + sizeof(struct babel_tlv);
if ((pos > end) || (pos + tlv->length > end))
return PARSE_ERROR;
/*
* The subtlv type space is non-contiguous (due to the mandatory bit), so
* use a switch for dispatch instead of the mapping array we use for TLVs
*/
switch (tlv->type)
{
case BABEL_SUBTLV_PAD1:
case BABEL_SUBTLV_PADN:
/* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
case BABEL_SUBTLV_SOURCE_PREFIX:
res = babel_read_source_prefix(tlv, msg, state);
if (res != PARSE_SUCCESS)
return res;
break;
case BABEL_SUBTLV_PADN:
default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
if (tlv->type > 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
if (tlv->type >= 128)
return PARSE_IGNORE;
}
break;
}
}
@ -1186,6 +1345,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
.ifa = ifa,
.saddr = saddr,
.next_hop_ip6 = saddr,
.sadr_enabled = babel_sadr_enabled(p),
};
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))
@ -1294,7 +1454,7 @@ babel_rx_hook(sock *sk, uint len)
sk->iface->name, sk->faddr, sk->laddr);
/* 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 +1489,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
*/
@ -238,7 +144,7 @@ wakeup_drain(struct birdloop *loop)
}
static inline void
wakeup_do_kick(struct birdloop *loop)
wakeup_do_kick(struct birdloop *loop)
{
pipe_kick(loop->wakeup_fds[1]);
}
@ -252,6 +158,16 @@ wakeup_kick(struct birdloop *loop)
loop->wakeup_masked = 2;
}
/* For notifications from outside */
void
wakeup_kick_current(void)
{
struct birdloop *loop = birdloop_current();
if (loop && loop->poll_active)
wakeup_kick(loop);
}
/*
* Events
@ -272,7 +188,7 @@ events_init(struct birdloop *loop)
static void
events_fire(struct birdloop *loop)
{
times_update(loop);
times_update(&loop->time);
ev_run_list(&loop->event_list);
}
@ -291,154 +207,6 @@ ev2_schedule(event *e)
}
/*
* Timers
*/
#define TIMER_LESS(a,b) ((a)->expires < (b)->expires)
#define TIMER_SWAP(heap,a,b,t) (t = heap[a], heap[a] = heap[b], heap[b] = t, \
heap[a]->index = (a), heap[b]->index = (b))
static inline uint timers_count(struct birdloop *loop)
{ return loop->timers.used - 1; }
static inline timer2 *timers_first(struct birdloop *loop)
{ return (loop->timers.used > 1) ? loop->timers.data[1] : NULL; }
static void
tm2_free(resource *r)
{
timer2 *t = (timer2 *) r;
tm2_stop(t);
}
static void
tm2_dump(resource *r)
{
timer2 *t = (timer2 *) r;
debug("(code %p, data %p, ", t->hook, t->data);
if (t->randomize)
debug("rand %d, ", t->randomize);
if (t->recurrent)
debug("recur %d, ", t->recurrent);
if (t->expires)
debug("expires in %d ms)\n", (t->expires - current_time()) TO_MS);
else
debug("inactive)\n");
}
static struct resclass tm2_class = {
"Timer",
sizeof(timer2),
tm2_free,
tm2_dump,
NULL,
NULL
};
timer2 *
tm2_new(pool *p)
{
timer2 *t = ralloc(p, &tm2_class);
t->index = -1;
return t;
}
void
tm2_set(timer2 *t, btime when)
{
struct birdloop *loop = birdloop_current();
uint tc = timers_count(loop);
if (!t->expires)
{
t->index = ++tc;
t->expires = when;
BUFFER_PUSH(loop->timers) = t;
HEAP_INSERT(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP);
}
else if (t->expires < when)
{
t->expires = when;
HEAP_INCREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
}
else if (t->expires > when)
{
t->expires = when;
HEAP_DECREASE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
}
if (loop->poll_active && (t->index == 1))
wakeup_kick(loop);
}
void
tm2_start(timer2 *t, btime after)
{
tm2_set(t, current_time() + MAX(after, 0));
}
void
tm2_stop(timer2 *t)
{
if (!t->expires)
return;
struct birdloop *loop = birdloop_current();
uint tc = timers_count(loop);
HEAP_DELETE(loop->timers.data, tc, timer2 *, TIMER_LESS, TIMER_SWAP, t->index);
BUFFER_POP(loop->timers);
t->index = -1;
t->expires = 0;
}
static void
timers_init(struct birdloop *loop)
{
BUFFER_INIT(loop->timers, loop->pool, 4);
BUFFER_PUSH(loop->timers) = NULL;
}
static void
timers_fire(struct birdloop *loop)
{
btime base_time;
timer2 *t;
times_update(loop);
base_time = loop->last_time;
while (t = timers_first(loop))
{
if (t->expires > base_time)
return;
if (t->recurrent)
{
btime when = t->expires + t->recurrent;
if (when <= loop->last_time)
when = loop->last_time + t->recurrent;
if (t->randomize)
when += random() % (t->randomize + 1);
tm2_set(t, when);
}
else
tm2_stop(t);
t->hook(t);
}
}
/*
* Sockets
*/
@ -530,7 +298,7 @@ sockets_prepare(struct birdloop *loop)
struct pollfd *pfd = loop->poll_fd.data;
sock **psk = loop->poll_sk.data;
int i = 0;
uint i = 0;
node *n;
WALK_LIST(n, loop->sock_list)
@ -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;
@ -552,10 +550,12 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla
static void
bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
{
a->u.ptr = ec_set_del_nontrans(s->pool, a->u.ptr);
if (a->u.ptr->length == 0)
UNSET(a);
a->u.ptr = ec_set_sort(s->pool, a->u.ptr);
ec_set_sort_x(a->u.ptr);
}
static void
@ -701,7 +701,8 @@ bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
static inline void
bgp_decode_unknown(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to)
{
bgp_set_attr_data(to, s->pool, code, flags, data, len);
/* Cannot use bgp_set_attr_data() as it works on known attributes only */
ea_set_attr_data(to, s->pool, EA_CODE(EAP_BGP, code), flags, EAF_TYPE_OPAQUE, data, len);
}
@ -1175,6 +1176,22 @@ bgp_init_bucket_table(struct bgp_channel *c)
c->withdraw_bucket = NULL;
}
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,15 @@
* <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
* <item> <rfc id="8212"> - Default EBGP Route Propagation Behavior without Policies
* </itemize>
*/
#undef LOCAL_DEBUG
#include <stdlib.h>
#include "nest/bird.h"
#include "nest/iface.h"
#include "nest/protocol.h"
@ -110,6 +114,7 @@
#include "nest/cli.h"
#include "nest/locks.h"
#include "conf/conf.h"
#include "filter/filter.h"
#include "lib/socket.h"
#include "lib/resource.h"
#include "lib/string.h"
@ -312,20 +317,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 +387,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 +406,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 +422,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 +462,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 +604,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 +663,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,10 +682,20 @@ 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;
}
/* p->gr_ready -> at least one active channel is c->gr_ready */
ASSERT(p->gr_active_num > 0);
proto_notify_state(&p->p, PS_START);
bgp_start_timer(p->gr_timer, p->conn->local_caps->gr_time);
bgp_start_timer(p->gr_timer, p->conn->remote_caps->gr_time);
}
/**
@ -722,7 +738,7 @@ bgp_graceful_restart_timeout(timer *t)
struct bgp_proto *p = t->data;
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
@ -885,9 +901,9 @@ bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn)
conn->last_channel = 0;
conn->last_channel_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 +952,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 +1111,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 +1138,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 +1149,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 +1174,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 +1317,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 +1328,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 +1345,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 +1362,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 +1382,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 +1412,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 +1517,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 +1559,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
@ -1588,6 +1623,7 @@ bgp_postconfig(struct proto_config *CF)
{
struct bgp_config *cf = (void *) CF;
int internal = (cf->local_as == cf->remote_as);
int interior = internal || cf->confederation_member;
/* Do not check templates at all */
if (cf->c.class == SYM_TEMPLATE)
@ -1598,6 +1634,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");
@ -1640,6 +1680,20 @@ bgp_postconfig(struct proto_config *CF)
struct bgp_channel_config *cc;
WALK_LIST(cc, CF->channels)
{
/* Handle undefined import filter */
if (cc->c.in_filter == FILTER_UNDEF)
if (interior)
cc->c.in_filter = FILTER_ACCEPT;
else
cf_error("EBGP requires explicit import policy");
/* Handle undefined export filter */
if (cc->c.out_filter == FILTER_UNDEF)
if (interior)
cc->c.out_filter = FILTER_REJECT;
else
cf_error("EBGP requires explicit export policy");
/* Disable after error incompatible with restart limit action */
if ((cc->c.in_limit.action == PLA_RESTART) && cf->disable_after_error)
cc->c.in_limit.action = PLA_DISABLE;
@ -1796,7 +1850,7 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len)
if (code != 6)
{
bgp_update_startup_delay(p);
bgp_stop(p, 0);
bgp_stop(p, 0, NULL, 0);
}
}
@ -2017,17 +2071,18 @@ bgp_show_proto_info(struct proto *P)
struct bgp_conn *oc = &p->outgoing_conn;
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 +2091,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 +2113,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 */
@ -117,6 +118,7 @@ struct bgp_config {
unsigned error_delay_time_min; /* Time to wait after an error is detected */
unsigned error_delay_time_max;
unsigned disable_after_error; /* Disable the protocol when error is detected */
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
char *password; /* Password used for MD5 authentication */
int check_link; /* Use iface link state for liveness detection */
@ -210,10 +212,10 @@ struct bgp_conn {
struct bgp_caps *local_caps;
struct bgp_caps *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 +256,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 +424,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 +438,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 +493,13 @@ int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
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

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

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);
@ -2283,6 +2284,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
if (s.attr_len)
ea = bgp_decode_attrs(&s, s.attrs, s.attr_len);
else
ea = NULL;
/* Check for End-of-RIB marker */
if (!s.attr_len && !s.ip_unreach_len && !s.ip_reach_len)
@ -2678,38 +2681,72 @@ bgp_error_dsc(uint code, uint subcode)
return buff;
}
/* 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 +2770,17 @@ 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);
}
else
{
uint subcode_bit = 1 << ((subcode <= 8) ? subcode : 0);
if (p->cf->disable_after_cease & subcode_bit)
{
log(L_INFO "%s: Disabled after Cease notification", p->p.name);
p->startup_delay = 0;
p->p.disabled = 1;
}
}
}

View File

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

View File

@ -356,7 +356,7 @@ ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
LOG_PKT_WARN("MTU mismatch with nbr %R on %s (remote %d, local %d)",
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_ */

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