Compare commits
32 Commits
burble-2.0
...
burble.dn4
Author | SHA1 | Date | |
---|---|---|---|
256e198fee | |||
18853a82c6 | |||
e6133456c1 | |||
b86d3f9a2e | |||
910f9127f0 | |||
ce7a2736e9 | |||
397c52070a | |||
|
4aecc5f8cd | ||
|
3155bb34be | ||
|
82f19ba95e | ||
|
f1ffe6a231 | ||
|
5a6e8380f8 | ||
|
454ae30445 | ||
|
0a3db4c680 | ||
|
2f98153490 | ||
|
ae9ae864d3 | ||
|
94abefc00b | ||
|
0d1a11cca3 | ||
|
6489a2450e | ||
|
7be3af7fa6 | ||
|
9cf3d53311 | ||
|
211fe69c98 | ||
|
d3782c72b9 | ||
|
77ce849ecf | ||
|
714238716e | ||
|
00b85905b9 | ||
|
d06a875b04 | ||
|
5d414309ec | ||
|
df83f62697 | ||
|
a40ddf5c61 | ||
|
d774f6d721 | ||
|
910adaa08b |
57
.drone.yml
Normal file
57
.drone.yml
Normal file
@ -0,0 +1,57 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: deploy
|
||||
|
||||
steps:
|
||||
|
||||
- name: build alpine
|
||||
image: c8n.io/simonburblecom/bird-build:alpine
|
||||
commands:
|
||||
- /build.sh
|
||||
|
||||
- name: build ubuntu
|
||||
image: c8n.io/simonburblecom/bird-build:ubuntu
|
||||
commands:
|
||||
- /build.sh
|
||||
|
||||
- name: upload
|
||||
image: plugins/s3
|
||||
settings:
|
||||
bucket: artifacts
|
||||
access_key:
|
||||
from_secret: MINIO_ACCESS_KEY
|
||||
secret_key:
|
||||
from_secret: MINIO_SECRET_KEY
|
||||
endpoint: https://minio.burble.dn42
|
||||
region: uk-lon3
|
||||
path_style: true
|
||||
source: artifacts/**/*
|
||||
strip_prefix: artifacts/
|
||||
target: /bird/${DRONE_BRANCH}
|
||||
|
||||
|
||||
image_pull_secrets:
|
||||
- CONFIG_JSON
|
||||
|
||||
---
|
||||
kind: secret
|
||||
name: CONFIG_JSON
|
||||
get:
|
||||
path: burble.dn42/kv/data/drone/docker
|
||||
name: configjson
|
||||
|
||||
---
|
||||
kind: secret
|
||||
name: MINIO_ACCESS_KEY
|
||||
get:
|
||||
path: burble.dn42/kv/data/drone/minio
|
||||
name: ACCESS_KEY
|
||||
|
||||
---
|
||||
kind: secret
|
||||
name: MINIO_SECRET_KEY
|
||||
get:
|
||||
path: burble.dn42/kv/data/drone/minio
|
||||
name: SECRET_KEY
|
||||
|
@ -388,3 +388,28 @@ test-bgp-int:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-bgp-int
|
||||
|
||||
test-bgp-merged:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-bgp-merged
|
||||
|
||||
test-ebgp-loop:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-ebgp-loop
|
||||
|
||||
test-ebgp-star:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-ebgp-star
|
||||
|
||||
test-ibgp-loop:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-ibgp-loop
|
||||
|
||||
test-ibgp-star:
|
||||
<<: *test-base
|
||||
variables:
|
||||
TEST_NAME: cf-ibgp-flat
|
||||
|
@ -194,10 +194,10 @@ static-scan:
|
||||
$(Q)scan-build $(STATIC_SCAN_FLAGS) $(MAKE) -$(MAKEFLAGS)
|
||||
|
||||
tags:
|
||||
cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
|
||||
cd $(srcdir) ; etags -lc `find $(dirs) -name '*.[chY]'`
|
||||
|
||||
cscope:
|
||||
cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b
|
||||
cd $(srcdir) ; find $(dirs) -name '*.[chY]' > cscope.files ; cscope -b
|
||||
|
||||
# Install
|
||||
|
||||
|
41
NEWS
41
NEWS
@ -1,3 +1,44 @@
|
||||
Version 2.0.8 (2021-03-18)
|
||||
o Automatic channel reloads based on RPKI changes
|
||||
o Multiple static routes with the same network
|
||||
o Use bitmaps to keep track of exported routes
|
||||
o Per-channel debug flags
|
||||
o CLI commands show info from multiple protocols
|
||||
o Linux: IPv4 routes with IPv6 nexthops
|
||||
o Filter: Optimized redesign of prefix sets
|
||||
o Filter: Improved type checking of user filters
|
||||
o Filter: New src/dst accessors for Flowspec and SADR
|
||||
o Filter: New 'weight' route attribute
|
||||
o Filter: BGP path mask loop operator
|
||||
o Filter: Remove quitbird command
|
||||
o RIP: Demand circuit support (RFC 2091)
|
||||
o BGP: New 'allow as sets' and 'enforce first as' options
|
||||
o BGP: Support for BGP hostname capability
|
||||
o BGP: Support for MD5SIG with dynamic BGP
|
||||
o BFD: Optional separation of IPv4 / IPv6 BFD instances
|
||||
o BFD: Per-peer session options
|
||||
o RPKI: Allow build without libSSH
|
||||
o RPKI: New 'ignore max length' option
|
||||
o OSPF: Redesign of handling of unnumbered PtPs
|
||||
o OSPF: Allow key id 0 in authentication
|
||||
o Babel: Use onlink flag for routes with unreachable next hop
|
||||
o Many bugfixes
|
||||
|
||||
Notes:
|
||||
|
||||
Automatic channel reloads based on RPKI changes are enabled by default,
|
||||
but require import table enabled when used in BGP import filter.
|
||||
|
||||
BIRD now uses bitmaps to keep track of exported routes instead of
|
||||
re-evaluation of export filters. That should improve speed and accuracy in
|
||||
route export handling during reconfiguration, but takes some more memory.
|
||||
|
||||
Per-channel debug logging and some CLI commands (like 'show ospf neighbors')
|
||||
defaulting to all protocol instances lead to some minor changes in log and
|
||||
CLI output. Caution is recommended when logs or CLI output are monitored by
|
||||
scripts.
|
||||
|
||||
|
||||
Version 2.0.7 (2019-10-11)
|
||||
o BGP: Accumulated IGP metric (RFC 7311)
|
||||
o Important filter reconfiguration bugfix
|
||||
|
52
build.sh
52
build.sh
@ -1,52 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
##########################################################################
|
||||
|
||||
date=$(date +%y%m%d)
|
||||
version='2.0.7'
|
||||
|
||||
git tag -a "burble-${version}-${date}" -m "burble.dn42 build ${version}/${date}"
|
||||
git push --tags
|
||||
|
||||
# configure
|
||||
|
||||
if [ ! -f configure ]
|
||||
then
|
||||
autoreconf
|
||||
fi
|
||||
|
||||
./configure \
|
||||
--prefix=/usr \
|
||||
--sysconfdir=/etc/bird \
|
||||
--localstatedir=/var
|
||||
|
||||
# make
|
||||
|
||||
make -j4
|
||||
|
||||
# create debian package
|
||||
|
||||
echo "bird-$version for burble.dn42" > description-pak
|
||||
sudo checkinstall \
|
||||
--default \
|
||||
--type='debian' --install=no \
|
||||
--pkgname='bird' \
|
||||
--pkgversion="$version" \
|
||||
--pkgrelease="burble-$date" \
|
||||
--maintainer="simon@burble.com" \
|
||||
--provides='bird' \
|
||||
--strip \
|
||||
--backup=no
|
||||
# reset perms
|
||||
sudo chown simon.simon *.deb
|
||||
|
||||
# upload
|
||||
|
||||
pkg="bird_${version}-burble-${date}_amd64.deb"
|
||||
dstdir='minio/artifacts/bird'
|
||||
dst="${dstdir}/${date}/${pkg}"
|
||||
|
||||
mc cp "$pkg" "$dst"
|
||||
mc cp "$dst" "${dstdir}/current/bird_${version}-burble_amd64.deb"
|
||||
|
||||
##########################################################################
|
||||
# end of file
|
@ -55,6 +55,7 @@
|
||||
#include "lib/timer.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
#include "sysdep/unix/unix.h"
|
||||
|
||||
|
||||
static jmp_buf conf_jmpbuf;
|
||||
@ -217,6 +218,14 @@ config_del_obstacle(struct config *c)
|
||||
static int
|
||||
global_commit(struct config *new, struct config *old)
|
||||
{
|
||||
if (!new->hostname)
|
||||
{
|
||||
new->hostname = get_hostname(new->mem);
|
||||
|
||||
if (!new->hostname)
|
||||
log(L_WARN "Cannot determine hostname");
|
||||
}
|
||||
|
||||
if (!old)
|
||||
return 0;
|
||||
|
||||
|
@ -40,6 +40,7 @@ struct config {
|
||||
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 (sec) */
|
||||
const char *hostname; /* Hostname */
|
||||
|
||||
int cli_debug; /* Tracing of CLI connections and commands */
|
||||
int latency_debug; /* I/O loop tracks duration of each event */
|
||||
|
@ -504,8 +504,14 @@ include "tablename.conf";;
|
||||
command-line option.
|
||||
|
||||
<tag><label id="opt-debug-protocols">debug protocols all|off|{ states|routes|filters|interfaces|events|packets [, <m/.../] }</tag>
|
||||
Set global defaults of protocol debugging options. See <cf/debug/ in the
|
||||
following section. Default: off.
|
||||
Set global defaults of protocol debugging options.
|
||||
See <ref id="proto-debug" name="debug"> in the following section.
|
||||
Default: off.
|
||||
|
||||
<tag><label id="opt-debug-channels">debug channels all|off|{ states|routes|filters|events [, <m/.../] }</tag>
|
||||
Set global defaults of channel debugging options.
|
||||
See <ref id="channel-debug" name="debug"> in the channel section.
|
||||
Default: off.
|
||||
|
||||
<tag><label id="opt-debug-commands">debug commands <m/number/</tag>
|
||||
Control logging of client connections (0 for no logging, 1 for logging
|
||||
@ -585,6 +591,9 @@ include "tablename.conf";;
|
||||
See <ref id="proto-iface" name="interface"> section for detailed
|
||||
description of interface patterns with extended clauses.
|
||||
|
||||
<tag><label id="opt-hostname">hostname "<m/name/"</tag>
|
||||
Set hostname. Default: node name as returned by `uname -n'.
|
||||
|
||||
<tag><label id="opt-graceful-restart">graceful restart wait <m/number/</tag>
|
||||
During graceful restart recovery, BIRD waits for convergence of routing
|
||||
protocols. This option allows to specify a timeout for the recovery to
|
||||
@ -654,12 +663,14 @@ agreement").
|
||||
Set protocol debugging options. If asked, each protocol is capable of
|
||||
writing trace messages about its work to the log (with category
|
||||
<cf/trace/). You can either request printing of <cf/all/ trace messages
|
||||
or only of the types selected: <cf/states/ for protocol state changes
|
||||
or only of the selected types: <cf/states/ for protocol state changes
|
||||
(protocol going up, down, starting, stopping etc.), <cf/routes/ for
|
||||
routes exchanged with the routing table, <cf/filters/ for details on
|
||||
route filtering, <cf/interfaces/ for interface change events sent to the
|
||||
protocol, <cf/events/ for events internal to the protocol and <cf/packets/
|
||||
for packets sent and received by the protocol. Default: off.
|
||||
route filtering, <cf/interfaces/ for interface change events sent to
|
||||
the protocol, <cf/events/ for events internal to the protocol and
|
||||
<cf/packets/ for packets sent and received by the protocol. Classes
|
||||
<cf/routes/ and <cf/filters/ can be also set per-channel using
|
||||
<ref id="channel-debug" name="channel debugging option">) Default: off.
|
||||
|
||||
<tag><label id="proto-mrtdump">mrtdump all|off|{ states|messages [, <m/.../] }</tag>
|
||||
Set protocol MRTdump flags. MRTdump is a standard binary format for
|
||||
@ -828,6 +839,16 @@ templates. Multiple definitions of the same channel are forbidden, but channels
|
||||
inherited from templates can be updated by new definitions.
|
||||
|
||||
<descrip>
|
||||
<tag><label id="channel-debug">debug all|off|{ states|routes|filters [, <m/.../] }</tag>
|
||||
Set channel debugging options. Like in <ref id="proto-debug"
|
||||
name="protocol debugging">, channels are capable of writing trace
|
||||
messages about its work to the log (with category <cf/trace/). You can
|
||||
either request printing of <cf/all/ trace messages or only of the
|
||||
selected types: <cf/states/ for channel state changes (channel going up,
|
||||
down, feeding, reloading etc.), <cf/routes/ for routes propagated
|
||||
through the channel, <cf/filters/ for details on route filtering,
|
||||
remaining debug flags are not used in channel debug. Default: off.
|
||||
|
||||
<tag><label id="proto-table">table <m/name/</tag>
|
||||
Specify a table to which the channel is connected. Default: the first
|
||||
table of given nettype.
|
||||
@ -854,6 +875,19 @@ inherited from templates can be updated by new definitions.
|
||||
possible to show them using <cf/show route filtered/. Note that this
|
||||
option does not work for the pipe protocol. Default: off.
|
||||
|
||||
<tag><label id="proto-rpki-reload">rpki reload <m/switch/</tag>
|
||||
Import or export filters may depend on route RPKI status (using
|
||||
<cf/roa_check()/ operator). In contrast to to other filter operators,
|
||||
this status for the same route may change as the content of ROA tables
|
||||
changes. When this option is active, BIRD activates automatic reload of
|
||||
affected channels whenever ROA tables are updated (after a short settle
|
||||
time). When disabled, route reloads have to be requested manually. The
|
||||
option is ignored if <cf/roa_check()/ is not used in channel filters.
|
||||
Note that for BGP channels, automatic reload requires
|
||||
<ref id="bgp-import-table" name="import table"> or
|
||||
<ref id="bgp-export-table" name="export table"> (for respective
|
||||
direction). Default: on.
|
||||
|
||||
<tag><label id="proto-import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
|
||||
Specify an import route limit (a maximum number of routes imported from
|
||||
the protocol) and optionally the action to be taken when the limit is
|
||||
@ -2536,6 +2570,9 @@ using the following configuration parameters:
|
||||
This option is relevant to IPv4 mode with enabled capability
|
||||
advertisement only. Default: on.
|
||||
|
||||
<tag><label id="bgp-advertise-hostname">advertise hostname <m/switch/</tag>
|
||||
Advertise hostname capability along with the hostname. Default: off.
|
||||
|
||||
<tag><label id="bgp-disable-after-error">disable after error <m/switch/</tag>
|
||||
When an error is encountered (either locally or by the other side),
|
||||
disable the instance automatically and wait for an administrator to fix
|
||||
@ -4737,21 +4774,21 @@ protocol rip {
|
||||
<sect1>Introduction
|
||||
|
||||
<p>The Resource Public Key Infrastructure (RPKI) is mechanism for origin
|
||||
validation of BGP routes (RFC 6480). BIRD supports only so-called RPKI-based
|
||||
origin validation. There is implemented RPKI to Router (RPKI-RTR) protocol (RFC
|
||||
6810). It uses some of the RPKI data to allow a router to verify that the
|
||||
autonomous system announcing an IP address prefix is in fact authorized to do
|
||||
so. This is not crypto checked so can be violated. But it should prevent the
|
||||
vast majority of accidental hijackings on the Internet today, e.g. the famous
|
||||
Pakastani accidental announcement of YouTube's address space.
|
||||
validation of BGP routes (<rfc id="6480">). BIRD supports only so-called
|
||||
RPKI-based origin validation. There is implemented RPKI to Router (RPKI-RTR)
|
||||
protocol (<rfc id="6810">). It uses some of the RPKI data to allow a router to
|
||||
verify that the autonomous system announcing an IP address prefix is in fact
|
||||
authorized to do so. This is not crypto checked so can be violated. But it
|
||||
should prevent the vast majority of accidental hijackings on the Internet today,
|
||||
e.g. the famous Pakistani accidental announcement of YouTube's address space.
|
||||
|
||||
<p>The RPKI-RTR protocol receives and maintains a set of ROAs from a cache
|
||||
server (also called validator). You can validate routes (RFC 6483) using
|
||||
function <cf/roa_check()/ in filter and set it as import filter at the BGP
|
||||
protocol. BIRD should re-validate all of affected routes after RPKI update by
|
||||
RFC 6811, but we don't support it yet! You can use a BIRD's client command
|
||||
<cf>reload in <m/bgp_protocol_name/</cf> for manual call of revalidation of all
|
||||
routes.
|
||||
server (also called validator). You can validate routes (<rfc id="6483">,
|
||||
<rfc id="6811">) using function <cf/roa_check()/ in filter and set it as import
|
||||
filter at the BGP protocol. BIRD offers crude automatic re-validating of
|
||||
affected routes after RPKI update, see option <ref id="proto-rpki-reload"
|
||||
name="rpki reload">. Or you can use a BIRD client command <cf>reload in
|
||||
<m/bgp_protocol_name/</cf> for manual call of revalidation of all routes.
|
||||
|
||||
<sect1>Supported transports
|
||||
<p>
|
||||
|
@ -175,6 +175,7 @@ struct f_tree *build_tree(struct f_tree *);
|
||||
const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
|
||||
int same_tree(const struct f_tree *t0, const struct f_tree *t2);
|
||||
void tree_format(const struct f_tree *t, buffer *buf);
|
||||
void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data);
|
||||
|
||||
struct f_trie *f_new_trie(linpool *lp, uint data_size);
|
||||
void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
|
||||
|
@ -40,6 +40,7 @@ m4_divert(-1)m4_dnl
|
||||
# 106 comparator body
|
||||
# 107 struct f_line_item content
|
||||
# 108 interpreter body
|
||||
# 109 iterator body
|
||||
#
|
||||
# Here are macros to allow you to _divert to the right directions.
|
||||
m4_define(FID_STRUCT_IN, `m4_divert(101)')
|
||||
@ -50,6 +51,7 @@ m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
|
||||
m4_define(FID_SAME_BODY, `m4_divert(106)')
|
||||
m4_define(FID_LINE_IN, `m4_divert(107)')
|
||||
m4_define(FID_INTERPRET_BODY, `m4_divert(108)')
|
||||
m4_define(FID_ITERATE_BODY, `m4_divert(109)')
|
||||
|
||||
# Sometimes you want slightly different code versions in different
|
||||
# outputs.
|
||||
@ -211,6 +213,8 @@ FID_LINEARIZE_BODY()m4_dnl
|
||||
item->fl$1 = f_linearize(whati->f$1);
|
||||
FID_SAME_BODY()m4_dnl
|
||||
if (!f_same(f1->fl$1, f2->fl$1)) return 0;
|
||||
FID_ITERATE_BODY()m4_dnl
|
||||
if (whati->fl$1) BUFFER_PUSH(fit->lines) = whati->fl$1;
|
||||
FID_INTERPRET_EXEC()m4_dnl
|
||||
do { if (whati->fl$1) {
|
||||
LINEX_(whati->fl$1);
|
||||
@ -265,6 +269,7 @@ m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access
|
||||
# 7 dump line item callers
|
||||
# 8 linearize
|
||||
# 9 same (filter comparator)
|
||||
# 10 iterate
|
||||
# 1 union in struct f_inst
|
||||
# 3 constructors + interpreter
|
||||
#
|
||||
@ -285,6 +290,7 @@ m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
|
||||
m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)')
|
||||
m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)')
|
||||
m4_define(FID_SAME, `FID_ZONE(9, Comparison)')
|
||||
m4_define(FID_ITERATE, `FID_ZONE(10, Iteration)')
|
||||
|
||||
# This macro does all the code wrapping. See inline comments.
|
||||
m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
|
||||
@ -372,6 +378,13 @@ m4_undivert(106)m4_dnl
|
||||
#undef f2
|
||||
break;
|
||||
|
||||
FID_ITERATE()m4_dnl The iterator
|
||||
case INST_NAME():
|
||||
#define whati (&(what->i_]]INST_NAME()[[))
|
||||
m4_undivert(109)m4_dnl
|
||||
#undef whati
|
||||
break;
|
||||
|
||||
m4_divert(-1)FID_FLUSH(101,200)m4_dnl And finally this flushes all the unused diversions
|
||||
]])')
|
||||
|
||||
@ -582,6 +595,27 @@ FID_WR_PUT(9)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Part of FI_SWITCH filter iterator */
|
||||
static void
|
||||
f_add_tree_lines(const struct f_tree *t, void *fit_)
|
||||
{
|
||||
struct filter_iterator * fit = fit_;
|
||||
|
||||
if (t->data)
|
||||
BUFFER_PUSH(fit->lines) = t->data;
|
||||
}
|
||||
|
||||
/* Filter line iterator */
|
||||
void
|
||||
f_add_lines(const struct f_line_item *what, struct filter_iterator *fit)
|
||||
{
|
||||
switch(what->fi_code) {
|
||||
FID_WR_PUT(10)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 6
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
@ -172,6 +172,22 @@
|
||||
* m4_dnl use macros f1 and f2.
|
||||
* m4_dnl For writing directly here, use FID_SAME_BODY.
|
||||
*
|
||||
* m4_dnl f_add_lines(...)
|
||||
* m4_dnl {
|
||||
* m4_dnl switch (what_->fi_code) {
|
||||
* m4_dnl case FI_EXAMPLE:
|
||||
* m4_dnl (109) [[ put it here ]]
|
||||
* m4_dnl break;
|
||||
* m4_dnl }
|
||||
* m4_dnl }
|
||||
* m4_dnl This code adds new filter lines reachable from the instruction
|
||||
* m4_dnl to the filter iterator line buffer. This is for instructions
|
||||
* m4_dnl that changes conrol flow, like FI_CONDITION or FI_CALL, most
|
||||
* m4_dnl instructions do not need to update it. It is used in generic
|
||||
* m4_dnl filter iteration code (FILTER_ITERATE*). For accessing your
|
||||
* m4_dnl custom instruction data, use macros f1 and f2. For writing
|
||||
* m4_dnl directly here, use FID_ITERATE_BODY.
|
||||
*
|
||||
* m4_dnl interpret(...)
|
||||
* m4_dnl {
|
||||
* m4_dnl switch (what->fi_code) {
|
||||
@ -543,7 +559,8 @@
|
||||
case SA_GW:
|
||||
{
|
||||
ip_addr ip = v1.val.ip;
|
||||
neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
|
||||
struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
|
||||
neighbor *n = neigh_find(rta->src->proto, ip, ifa, 0);
|
||||
if (!n || (n->scope == SCOPE_HOST))
|
||||
runtime( "Invalid gw address" );
|
||||
|
||||
@ -948,6 +965,10 @@
|
||||
FID_SAME_BODY()
|
||||
if (!(f1->sym->flags & SYM_FLAG_SAME))
|
||||
return 0;
|
||||
|
||||
FID_ITERATE_BODY()
|
||||
BUFFER_PUSH(fit->lines) = whati->sym->function;
|
||||
|
||||
FID_INTERPRET_BODY()
|
||||
|
||||
/* Push the body on stack */
|
||||
@ -977,6 +998,10 @@
|
||||
|
||||
FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
|
||||
|
||||
FID_ITERATE_BODY()
|
||||
tree_walk(whati->tree, f_add_tree_lines, fit);
|
||||
|
||||
FID_INTERPRET_BODY()
|
||||
const struct f_tree *t = find_tree(tree, &v1);
|
||||
if (!t) {
|
||||
v1.type = T_VOID;
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
#include "filter/data.h"
|
||||
#include "lib/buffer.h"
|
||||
#include "lib/flowspec.h"
|
||||
|
||||
/* Flags for instructions */
|
||||
@ -50,6 +51,41 @@ static inline struct f_line *f_linearize(const struct f_inst *root)
|
||||
|
||||
void f_dump_line(const struct f_line *, uint indent);
|
||||
|
||||
|
||||
/* Recursive iteration over filter instructions */
|
||||
|
||||
struct filter_iterator {
|
||||
BUFFER_(const struct f_line *) lines;
|
||||
};
|
||||
|
||||
void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
|
||||
|
||||
#define FILTER_ITERATE_INIT(fit, filter, pool) \
|
||||
({ \
|
||||
BUFFER_INIT((fit)->lines, (pool), 32); \
|
||||
BUFFER_PUSH((fit)->lines) = (filter)->root; \
|
||||
})
|
||||
|
||||
#define FILTER_ITERATE(fit, fi) ({ \
|
||||
const struct f_line *fl_; \
|
||||
while (!BUFFER_EMPTY((fit)->lines)) \
|
||||
{ \
|
||||
BUFFER_POP((fit)->lines); \
|
||||
fl_ = (fit)->lines.data[(fit)->lines.used]; \
|
||||
for (uint i_ = 0; i_ < fl_->len; i_++) \
|
||||
{ \
|
||||
const struct f_line_item *fi = &fl_->items[i_]; \
|
||||
f_add_lines(fi, (fit));
|
||||
|
||||
#define FILTER_ITERATE_END } } })
|
||||
|
||||
#define FILTER_ITERATE_CLEANUP(fit) \
|
||||
({ \
|
||||
mb_free((fit)->lines.data); \
|
||||
memset((fit), 0, sizeof(struct filter_iterator)); \
|
||||
})
|
||||
|
||||
|
||||
struct filter *f_new_where(struct f_inst *);
|
||||
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint 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 */
|
||||
|
@ -170,3 +170,14 @@ tree_format(const struct f_tree *t, buffer *buf)
|
||||
|
||||
buffer_puts(buf, "]");
|
||||
}
|
||||
|
||||
void
|
||||
tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data)
|
||||
{
|
||||
if (!t)
|
||||
return;
|
||||
|
||||
tree_walk(t->left, hook, data);
|
||||
hook(t, data);
|
||||
tree_walk(t->right, hook, data);
|
||||
}
|
||||
|
@ -50,6 +50,8 @@
|
||||
|
||||
#define BUFFER_FLUSH(v) ({ (v).used = 0; })
|
||||
|
||||
#define BUFFER_EMPTY(v) ({ (v).used == 0; })
|
||||
|
||||
#define BUFFER_WALK(v,n) \
|
||||
for (BUFFER_TYPE(v) *_n = (v).data, n; _n < ((v).data + (v).used) && (n = *_n, 1); _n++)
|
||||
|
||||
|
56
lib/event.c
56
lib/event.c
@ -23,6 +23,7 @@
|
||||
#include "lib/event.h"
|
||||
|
||||
event_list global_event_list;
|
||||
event_list global_work_list;
|
||||
|
||||
inline void
|
||||
ev_postpone(event *e)
|
||||
@ -114,6 +115,22 @@ ev_schedule(event *e)
|
||||
ev_enqueue(&global_event_list, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* ev_schedule_work - schedule a work-event.
|
||||
* @e: an event
|
||||
*
|
||||
* This function schedules an event by enqueueing it to a system-wide work-event
|
||||
* list which is run by the platform dependent code whenever appropriate. This
|
||||
* is designated for work-events instead of regular events. They are executed
|
||||
* less often in order to not clog I/O loop.
|
||||
*/
|
||||
void
|
||||
ev_schedule_work(event *e)
|
||||
{
|
||||
if (!ev_active(e))
|
||||
add_tail(&global_work_list, &e->n);
|
||||
}
|
||||
|
||||
void io_log_event(void *hook, void *data);
|
||||
|
||||
/**
|
||||
@ -136,10 +153,47 @@ ev_run_list(event_list *l)
|
||||
event *e = SKIP_BACK(event, n, n);
|
||||
|
||||
/* This is ugly hack, we want to log just events executed from the main I/O loop */
|
||||
if (l == &global_event_list)
|
||||
if ((l == &global_event_list) || (l == &global_work_list))
|
||||
io_log_event(e->hook, e->data);
|
||||
|
||||
ev_run(e);
|
||||
}
|
||||
|
||||
return !EMPTY_LIST(*l);
|
||||
}
|
||||
|
||||
int
|
||||
ev_run_list_limited(event_list *l, uint limit)
|
||||
{
|
||||
node *n;
|
||||
list tmp_list;
|
||||
|
||||
init_list(&tmp_list);
|
||||
add_tail_list(&tmp_list, l);
|
||||
init_list(l);
|
||||
|
||||
WALK_LIST_FIRST(n, tmp_list)
|
||||
{
|
||||
event *e = SKIP_BACK(event, n, n);
|
||||
|
||||
if (!limit)
|
||||
break;
|
||||
|
||||
/* This is ugly hack, we want to log just events executed from the main I/O loop */
|
||||
if ((l == &global_event_list) || (l == &global_work_list))
|
||||
io_log_event(e->hook, e->data);
|
||||
|
||||
ev_run(e);
|
||||
limit--;
|
||||
}
|
||||
|
||||
if (!EMPTY_LIST(tmp_list))
|
||||
{
|
||||
/* Attach new items after the unprocessed old items */
|
||||
add_tail_list(&tmp_list, l);
|
||||
init_list(l);
|
||||
add_tail_list(l, &tmp_list);
|
||||
}
|
||||
|
||||
return !EMPTY_LIST(*l);
|
||||
}
|
||||
|
@ -21,14 +21,17 @@ typedef struct event {
|
||||
typedef list event_list;
|
||||
|
||||
extern event_list global_event_list;
|
||||
extern event_list global_work_list;
|
||||
|
||||
event *ev_new(pool *);
|
||||
void ev_run(event *);
|
||||
#define ev_init_list(el) init_list(el)
|
||||
void ev_enqueue(event_list *, event *);
|
||||
void ev_schedule(event *);
|
||||
void ev_schedule_work(event *);
|
||||
void ev_postpone(event *);
|
||||
int ev_run_list(event_list *);
|
||||
int ev_run_list_limited(event_list *, uint);
|
||||
|
||||
static inline int
|
||||
ev_active(event *e)
|
||||
|
@ -1,6 +1,6 @@
|
||||
Summary: BIRD Internet Routing Daemon
|
||||
Name: bird
|
||||
Version: 2.0.7
|
||||
Version: 2.0.8
|
||||
Release: 1
|
||||
Copyright: GPL
|
||||
Group: Networking/Daemons
|
||||
|
@ -27,6 +27,7 @@ cmd_show_status(void)
|
||||
cli_msg(-1000, "BIRD " BIRD_VERSION);
|
||||
tm_format_time(tim, &config->tf_base, current_time());
|
||||
cli_msg(-1011, "Router ID is %R", config->router_id);
|
||||
cli_msg(-1011, "Hostname is %s", config->hostname);
|
||||
cli_msg(-1011, "Current server time is %s", tim);
|
||||
tm_format_time(tim, &config->tf_base, boot_time);
|
||||
cli_msg(-1011, "Last reboot on %s", tim);
|
||||
|
@ -87,10 +87,10 @@ proto_postconfig(void)
|
||||
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||
CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
||||
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, 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(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
|
||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
|
||||
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
|
||||
CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
|
||||
@ -151,6 +151,10 @@ idval:
|
||||
}
|
||||
;
|
||||
|
||||
conf: hostname_override ;
|
||||
|
||||
hostname_override: HOSTNAME text ';' { new_config->hostname = $2; } ;
|
||||
|
||||
conf: gr_opts ;
|
||||
|
||||
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
|
||||
@ -261,6 +265,7 @@ channel_item_:
|
||||
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
|
||||
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
|
||||
| IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
|
||||
| RPKI RELOAD bool { this_channel->rpki_reload = $3; }
|
||||
;
|
||||
|
||||
/* To avoid grammar collision in Pipe protocol */
|
||||
|
243
nest/proto.c
243
nest/proto.c
@ -20,6 +20,7 @@
|
||||
#include "nest/iface.h"
|
||||
#include "nest/cli.h"
|
||||
#include "filter/filter.h"
|
||||
#include "filter/f-inst.h"
|
||||
|
||||
pool *proto_pool;
|
||||
list proto_list;
|
||||
@ -47,6 +48,7 @@ static char *e_states[] = { "DOWN", "FEEDING", "READY" };
|
||||
|
||||
extern struct protocol proto_unix_iface;
|
||||
|
||||
static void channel_request_reload(struct channel *c);
|
||||
static void proto_shutdown_loop(timer *);
|
||||
static void proto_rethink_goal(struct proto *p);
|
||||
static char *proto_state_name(struct proto *p);
|
||||
@ -60,6 +62,9 @@ static inline int proto_is_done(struct proto *p)
|
||||
static inline int channel_is_active(struct channel *c)
|
||||
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
|
||||
|
||||
static inline int channel_reloadable(struct channel *c)
|
||||
{ return c->proto->reload_routes && c->reloadable; }
|
||||
|
||||
static inline void
|
||||
channel_log_state_change(struct channel *c)
|
||||
{
|
||||
@ -173,12 +178,15 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
|
||||
c->debug = cf->debug;
|
||||
c->merge_limit = cf->merge_limit;
|
||||
c->in_keep_filtered = cf->in_keep_filtered;
|
||||
c->rpki_reload = cf->rpki_reload;
|
||||
|
||||
c->channel_state = CS_DOWN;
|
||||
c->export_state = ES_DOWN;
|
||||
c->last_state_change = current_time();
|
||||
c->reloadable = 1;
|
||||
|
||||
init_list(&c->roa_subscriptions);
|
||||
|
||||
CALL(c->channel->init, c, cf);
|
||||
|
||||
add_tail(&p->channels, &c->n);
|
||||
@ -244,7 +252,7 @@ channel_schedule_feed(struct channel *c, int initial)
|
||||
c->export_state = ES_FEEDING;
|
||||
c->refeeding = !initial;
|
||||
|
||||
ev_schedule(c->feed_event);
|
||||
ev_schedule_work(c->feed_event);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -255,14 +263,19 @@ channel_feed_loop(void *ptr)
|
||||
if (c->export_state != ES_FEEDING)
|
||||
return;
|
||||
|
||||
/* Start feeding */
|
||||
if (!c->feed_active)
|
||||
{
|
||||
if (c->proto->feed_begin)
|
||||
c->proto->feed_begin(c, !c->refeeding);
|
||||
|
||||
c->refeed_pending = 0;
|
||||
}
|
||||
|
||||
// DBG("Feeding protocol %s continued\n", p->name);
|
||||
if (!rt_feed_channel(c))
|
||||
{
|
||||
ev_schedule(c->feed_event);
|
||||
ev_schedule_work(c->feed_event);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -278,7 +291,7 @@ channel_feed_loop(void *ptr)
|
||||
|
||||
/* Continue in feed - it will process routing table again from beginning */
|
||||
c->refeed_count = 0;
|
||||
ev_schedule(c->feed_event);
|
||||
ev_schedule_work(c->feed_event);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -288,9 +301,149 @@ channel_feed_loop(void *ptr)
|
||||
|
||||
if (c->proto->feed_end)
|
||||
c->proto->feed_end(c);
|
||||
|
||||
/* Restart feeding */
|
||||
if (c->refeed_pending)
|
||||
channel_request_feeding(c);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
channel_roa_in_changed(struct rt_subscription *s)
|
||||
{
|
||||
struct channel *c = s->data;
|
||||
int active = c->reload_event && ev_active(c->reload_event);
|
||||
|
||||
CD(c, "Reload triggered by RPKI change%s", active ? " - already active" : "");
|
||||
|
||||
if (!active)
|
||||
channel_request_reload(c);
|
||||
else
|
||||
c->reload_pending = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_out_changed(struct rt_subscription *s)
|
||||
{
|
||||
struct channel *c = s->data;
|
||||
int active = (c->export_state == ES_FEEDING);
|
||||
|
||||
CD(c, "Feeding triggered by RPKI change%s", active ? " - already active" : "");
|
||||
|
||||
if (!active)
|
||||
channel_request_feeding(c);
|
||||
else
|
||||
c->refeed_pending = 1;
|
||||
}
|
||||
|
||||
/* Temporary code, subscriptions should be changed to resources */
|
||||
struct roa_subscription {
|
||||
struct rt_subscription s;
|
||||
node roa_node;
|
||||
};
|
||||
|
||||
static int
|
||||
channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
|
||||
{
|
||||
void (*hook)(struct rt_subscription *) =
|
||||
dir ? channel_roa_in_changed : channel_roa_out_changed;
|
||||
|
||||
struct roa_subscription *s;
|
||||
node *n;
|
||||
|
||||
WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
|
||||
if ((s->s.tab == tab) && (s->s.hook == hook))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
|
||||
{
|
||||
if (channel_roa_is_subscribed(c, tab, dir))
|
||||
return;
|
||||
|
||||
struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
|
||||
|
||||
s->s.hook = dir ? channel_roa_in_changed : channel_roa_out_changed;
|
||||
s->s.data = c;
|
||||
rt_subscribe(tab, &s->s);
|
||||
|
||||
add_tail(&c->roa_subscriptions, &s->roa_node);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_unsubscribe(struct roa_subscription *s)
|
||||
{
|
||||
rt_unsubscribe(&s->s);
|
||||
rem_node(&s->roa_node);
|
||||
mb_free(s);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_subscribe_filter(struct channel *c, int dir)
|
||||
{
|
||||
const struct filter *f = dir ? c->in_filter : c->out_filter;
|
||||
struct rtable *tab;
|
||||
int valid = 1, found = 0;
|
||||
|
||||
if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT))
|
||||
return;
|
||||
|
||||
/* No automatic reload for non-reloadable channels */
|
||||
if (dir && !channel_reloadable(c))
|
||||
valid = 0;
|
||||
|
||||
#ifdef CONFIG_BGP
|
||||
/* No automatic reload for BGP channels without in_table / out_table */
|
||||
if (c->channel == &channel_bgp)
|
||||
valid = dir ? !!c->in_table : !!c->out_table;
|
||||
#endif
|
||||
|
||||
struct filter_iterator fit;
|
||||
FILTER_ITERATE_INIT(&fit, f, c->proto->pool);
|
||||
|
||||
FILTER_ITERATE(&fit, fi)
|
||||
{
|
||||
switch (fi->fi_code)
|
||||
{
|
||||
case FI_ROA_CHECK_IMPLICIT:
|
||||
tab = fi->i_FI_ROA_CHECK_IMPLICIT.rtc->table;
|
||||
if (valid) channel_roa_subscribe(c, tab, dir);
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
case FI_ROA_CHECK_EXPLICIT:
|
||||
tab = fi->i_FI_ROA_CHECK_EXPLICIT.rtc->table;
|
||||
if (valid) channel_roa_subscribe(c, tab, dir);
|
||||
found = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
FILTER_ITERATE_END;
|
||||
|
||||
FILTER_ITERATE_CLEANUP(&fit);
|
||||
|
||||
if (!valid && found)
|
||||
log(L_WARN "%s.%s: Automatic RPKI reload not active for %s",
|
||||
c->proto->name, c->name ?: "?", dir ? "import" : "export");
|
||||
}
|
||||
|
||||
static void
|
||||
channel_roa_unsubscribe_all(struct channel *c)
|
||||
{
|
||||
struct roa_subscription *s;
|
||||
node *n, *x;
|
||||
|
||||
WALK_LIST2_DELSAFE(s, n, x, c->roa_subscriptions, roa_node)
|
||||
channel_roa_unsubscribe(s);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_start_export(struct channel *c)
|
||||
{
|
||||
@ -320,7 +473,7 @@ channel_schedule_reload(struct channel *c)
|
||||
ASSERT(c->channel_state == CS_UP);
|
||||
|
||||
rt_reload_channel_abort(c);
|
||||
ev_schedule(c->reload_event);
|
||||
ev_schedule_work(c->reload_event);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -328,11 +481,19 @@ channel_reload_loop(void *ptr)
|
||||
{
|
||||
struct channel *c = ptr;
|
||||
|
||||
/* Start reload */
|
||||
if (!c->reload_active)
|
||||
c->reload_pending = 0;
|
||||
|
||||
if (!rt_reload_channel(c))
|
||||
{
|
||||
ev_schedule(c->reload_event);
|
||||
ev_schedule_work(c->reload_event);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Restart reload */
|
||||
if (c->reload_pending)
|
||||
channel_request_reload(c);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -398,6 +559,17 @@ channel_do_start(struct channel *c)
|
||||
CALL(c->channel->start, c);
|
||||
}
|
||||
|
||||
static void
|
||||
channel_do_up(struct channel *c)
|
||||
{
|
||||
/* Register RPKI/ROA subscriptions */
|
||||
if (c->rpki_reload)
|
||||
{
|
||||
channel_roa_subscribe_filter(c, 1);
|
||||
channel_roa_subscribe_filter(c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
channel_do_flush(struct channel *c)
|
||||
{
|
||||
@ -414,6 +586,8 @@ channel_do_flush(struct channel *c)
|
||||
c->in_table = NULL;
|
||||
c->reload_event = NULL;
|
||||
c->out_table = NULL;
|
||||
|
||||
channel_roa_unsubscribe_all(c);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -483,6 +657,7 @@ channel_set_state(struct channel *c, uint state)
|
||||
if (!c->gr_wait && c->proto->rt_notify)
|
||||
channel_start_export(c);
|
||||
|
||||
channel_do_up(c);
|
||||
break;
|
||||
|
||||
case CS_FLUSHING:
|
||||
@ -551,12 +726,6 @@ channel_request_feeding(struct channel *c)
|
||||
channel_log_state_change(c);
|
||||
}
|
||||
|
||||
static inline int
|
||||
channel_reloadable(struct channel *c)
|
||||
{
|
||||
return c->proto->reload_routes && c->reloadable;
|
||||
}
|
||||
|
||||
static void
|
||||
channel_request_reload(struct channel *c)
|
||||
{
|
||||
@ -611,6 +780,7 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
|
||||
cf->ra_mode = RA_OPTIMAL;
|
||||
cf->preference = proto->protocol->preference;
|
||||
cf->debug = new_config->channel_default_debug;
|
||||
cf->rpki_reload = 1;
|
||||
|
||||
add_tail(&proto->channels, &cf->n);
|
||||
|
||||
@ -663,6 +833,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||
/* 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);
|
||||
int rpki_reload_changed = (cf->rpki_reload != c->rpki_reload);
|
||||
|
||||
if (c->preference != cf->preference)
|
||||
import_changed = 1;
|
||||
@ -682,6 +853,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||
c->preference = cf->preference;
|
||||
c->debug = cf->debug;
|
||||
c->in_keep_filtered = cf->in_keep_filtered;
|
||||
c->rpki_reload = cf->rpki_reload;
|
||||
|
||||
channel_verify_limits(c);
|
||||
|
||||
@ -693,6 +865,18 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||
if (c->channel_state != CS_UP)
|
||||
goto done;
|
||||
|
||||
/* Update RPKI/ROA subscriptions */
|
||||
if (import_changed || export_changed || rpki_reload_changed)
|
||||
{
|
||||
channel_roa_unsubscribe_all(c);
|
||||
|
||||
if (c->rpki_reload)
|
||||
{
|
||||
channel_roa_subscribe_filter(c, 1);
|
||||
channel_roa_subscribe_filter(c, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (reconfigure_type == RECONFIG_SOFT)
|
||||
{
|
||||
if (import_changed)
|
||||
@ -2028,10 +2212,17 @@ proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
|
||||
cli_msg(-15, "%s: reloading", p->name);
|
||||
}
|
||||
|
||||
extern void pipe_update_debug(struct proto *P);
|
||||
|
||||
void
|
||||
proto_cmd_debug(struct proto *p, uintptr_t mask, int cnt UNUSED)
|
||||
{
|
||||
p->debug = mask;
|
||||
|
||||
#ifdef CONFIG_PIPE
|
||||
if (p->proto == &proto_pipe)
|
||||
pipe_update_debug(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -2156,33 +2347,3 @@ proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *ol
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* jrb0001 fix to reload protocols on RPKI change
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
reload_all(void)
|
||||
{
|
||||
log(L_INFO "Reloading all protocols.");
|
||||
struct proto *p;
|
||||
WALK_LIST(p, proto_list)
|
||||
{
|
||||
if (!p->disabled && p->proto_state == PS_UP)
|
||||
{
|
||||
log(L_INFO "Reloading protocol %s.", p->name);
|
||||
struct channel *c;
|
||||
WALK_LIST(c, p->channels)
|
||||
{
|
||||
if (channel_reloadable(c) && c->channel_state == CS_UP)
|
||||
{
|
||||
channel_request_reload(c);
|
||||
channel_request_feeding(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,6 +500,7 @@ struct channel_config {
|
||||
u32 debug; /* Debugging flags (D_*) */
|
||||
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
|
||||
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
|
||||
u8 rpki_reload; /* RPKI changes trigger channel reload */
|
||||
};
|
||||
|
||||
struct channel {
|
||||
@ -549,7 +550,13 @@ struct channel {
|
||||
struct rte *reload_next_rte; /* Route iterator in in_table used during reloading */
|
||||
u8 reload_active; /* Iterator reload_fit is linked */
|
||||
|
||||
u8 reload_pending; /* Reloading and another reload is scheduled */
|
||||
u8 refeed_pending; /* Refeeding and another refeed is scheduled */
|
||||
u8 rpki_reload; /* RPKI changes trigger channel reload */
|
||||
|
||||
struct rtable *out_table; /* Internal table for exported routes */
|
||||
|
||||
list roa_subscriptions; /* List of active ROA table subscriptions based on filters roa_check() */
|
||||
};
|
||||
|
||||
|
||||
@ -630,7 +637,6 @@ void *channel_config_new(const struct channel_class *cc, const char *name, uint
|
||||
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);
|
||||
|
||||
void reload_all(void);
|
||||
|
||||
/* Moved from route.h to avoid dependency conflicts */
|
||||
static inline void rte_update(struct proto *p, const net_addr *n, rte *new) { rte_update2(p->main_channel, n, new, p->main_source); }
|
||||
|
17
nest/route.h
17
nest/route.h
@ -19,6 +19,7 @@ struct protocol;
|
||||
struct proto;
|
||||
struct rte_src;
|
||||
struct symbol;
|
||||
struct timer;
|
||||
struct filter;
|
||||
struct cli;
|
||||
|
||||
@ -147,6 +148,8 @@ struct rtable_config {
|
||||
int gc_max_ops; /* Maximum number of operations before GC is run */
|
||||
int gc_min_time; /* Minimum time between two consecutive GC runs */
|
||||
byte sorted; /* Routes of network are sorted according to rte_better() */
|
||||
btime min_settle_time; /* Minimum settle time for notifications */
|
||||
btime max_settle_time; /* Maximum settle time for notifications */
|
||||
};
|
||||
|
||||
typedef struct rtable {
|
||||
@ -166,6 +169,8 @@ typedef struct rtable {
|
||||
* obstacle from this routing table.
|
||||
*/
|
||||
struct event *rt_event; /* Routing table event */
|
||||
btime last_rt_change; /* Last time when route changed */
|
||||
btime base_settle_time; /* Start time of rtable settling interval */
|
||||
btime gc_time; /* Time of last GC */
|
||||
int gc_counter; /* Number of operations since last GC */
|
||||
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
|
||||
@ -173,8 +178,18 @@ typedef struct rtable {
|
||||
byte nhu_state; /* Next Hop Update state */
|
||||
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
|
||||
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
|
||||
|
||||
list subscribers; /* Subscribers for notifications */
|
||||
struct timer *settle_timer; /* Settle time for notifications */
|
||||
} rtable;
|
||||
|
||||
struct rt_subscription {
|
||||
node n;
|
||||
rtable *tab;
|
||||
void (*hook)(struct rt_subscription *b);
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define NHU_CLEAN 0
|
||||
#define NHU_SCHEDULED 1
|
||||
#define NHU_RUNNING 2
|
||||
@ -294,6 +309,8 @@ 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_subscribe(rtable *tab, struct rt_subscription *s);
|
||||
void rt_unsubscribe(struct rt_subscription *s);
|
||||
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)
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include "nest/iface.h"
|
||||
#include "lib/resource.h"
|
||||
#include "lib/event.h"
|
||||
#include "lib/timer.h"
|
||||
#include "lib/string.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
@ -60,6 +61,7 @@ static void rt_notify_hostcache(rtable *tab, net *net);
|
||||
static void rt_update_hostcache(rtable *tab);
|
||||
static void rt_next_hop_update(rtable *tab);
|
||||
static inline void rt_prune_table(rtable *tab);
|
||||
static inline void rt_schedule_notify(rtable *tab);
|
||||
|
||||
|
||||
/* Like fib_route(), but skips empty net entries */
|
||||
@ -968,6 +970,8 @@ rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
|
||||
rt_notify_hostcache(tab, net);
|
||||
}
|
||||
|
||||
rt_schedule_notify(tab);
|
||||
|
||||
struct channel *c; node *n;
|
||||
WALK_LIST2(c, n, tab->channels, table_node)
|
||||
{
|
||||
@ -1211,6 +1215,9 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
|
||||
else
|
||||
stats->imp_withdraws_ignored++;
|
||||
|
||||
if (old_ok || new_ok)
|
||||
table->last_rt_change = current_time();
|
||||
|
||||
skip_stats1:
|
||||
|
||||
if (new)
|
||||
@ -1792,6 +1799,78 @@ rt_event(void *ptr)
|
||||
rt_unlock_table(tab);
|
||||
}
|
||||
|
||||
|
||||
static inline btime
|
||||
rt_settled_time(rtable *tab)
|
||||
{
|
||||
ASSUME(tab->base_settle_time != 0);
|
||||
|
||||
return MIN(tab->last_rt_change + tab->config->min_settle_time,
|
||||
tab->base_settle_time + tab->config->max_settle_time);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_settle_timer(timer *t)
|
||||
{
|
||||
rtable *tab = t->data;
|
||||
|
||||
if (!tab->base_settle_time)
|
||||
return;
|
||||
|
||||
btime settled_time = rt_settled_time(tab);
|
||||
if (current_time() < settled_time)
|
||||
{
|
||||
tm_set(tab->settle_timer, settled_time);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Settled */
|
||||
tab->base_settle_time = 0;
|
||||
|
||||
struct rt_subscription *s;
|
||||
WALK_LIST(s, tab->subscribers)
|
||||
s->hook(s);
|
||||
}
|
||||
|
||||
static void
|
||||
rt_kick_settle_timer(rtable *tab)
|
||||
{
|
||||
tab->base_settle_time = current_time();
|
||||
|
||||
if (!tab->settle_timer)
|
||||
tab->settle_timer = tm_new_init(rt_table_pool, rt_settle_timer, tab, 0, 0);
|
||||
|
||||
if (!tm_active(tab->settle_timer))
|
||||
tm_set(tab->settle_timer, rt_settled_time(tab));
|
||||
}
|
||||
|
||||
static inline void
|
||||
rt_schedule_notify(rtable *tab)
|
||||
{
|
||||
if (EMPTY_LIST(tab->subscribers))
|
||||
return;
|
||||
|
||||
if (tab->base_settle_time)
|
||||
return;
|
||||
|
||||
rt_kick_settle_timer(tab);
|
||||
}
|
||||
|
||||
void
|
||||
rt_subscribe(rtable *tab, struct rt_subscription *s)
|
||||
{
|
||||
s->tab = tab;
|
||||
rt_lock_table(tab);
|
||||
add_tail(&tab->subscribers, &s->n);
|
||||
}
|
||||
|
||||
void
|
||||
rt_unsubscribe(struct rt_subscription *s)
|
||||
{
|
||||
rem_node(&s->n);
|
||||
rt_unlock_table(s->tab);
|
||||
}
|
||||
|
||||
void
|
||||
rt_setup(pool *p, rtable *t, struct rtable_config *cf)
|
||||
{
|
||||
@ -1806,7 +1885,9 @@ rt_setup(pool *p, rtable *t, struct rtable_config *cf)
|
||||
hmap_set(&t->id_map, 0);
|
||||
|
||||
t->rt_event = ev_new_init(p, rt_event, t);
|
||||
t->gc_time = current_time();
|
||||
t->last_rt_change = t->gc_time = current_time();
|
||||
|
||||
init_list(&t->subscribers);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2204,6 +2285,8 @@ rt_new_table(struct symbol *s, uint addr_type)
|
||||
c->addr_type = addr_type;
|
||||
c->gc_max_ops = 1000;
|
||||
c->gc_min_time = 5;
|
||||
c->min_settle_time = 1 S;
|
||||
c->max_settle_time = 20 S;
|
||||
|
||||
add_tail(&new_config->tables, &c->n);
|
||||
|
||||
@ -2250,6 +2333,7 @@ rt_unlock_table(rtable *r)
|
||||
fib_free(&r->fib);
|
||||
hmap_free(&r->id_map);
|
||||
rfree(r->rt_event);
|
||||
rfree(r->settle_timer);
|
||||
mb_free(r);
|
||||
config_del_obstacle(conf);
|
||||
}
|
||||
|
@ -27,13 +27,13 @@
|
||||
* related to the session and two timers (TX timer for periodic packets and hold
|
||||
* timer for session timeout). These sessions are allocated from @session_slab
|
||||
* and are accessible by two hash tables, @session_hash_id (by session ID) and
|
||||
* @session_hash_ip (by IP addresses of neighbors). Slab and both hashes are in
|
||||
* the main protocol structure &bfd_proto. The protocol logic related to BFD
|
||||
* sessions is implemented in internal functions bfd_session_*(), which are
|
||||
* expected to be called from the context of BFD thread, and external functions
|
||||
* bfd_add_session(), bfd_remove_session() and bfd_reconfigure_session(), which
|
||||
* form an interface to the BFD core for the rest and are expected to be called
|
||||
* from the context of main thread.
|
||||
* @session_hash_ip (by IP addresses of neighbors and associated interfaces).
|
||||
* Slab and both hashes are in the main protocol structure &bfd_proto. The
|
||||
* protocol logic related to BFD sessions is implemented in internal functions
|
||||
* bfd_session_*(), which are expected to be called from the context of BFD
|
||||
* thread, and external functions bfd_add_session(), bfd_remove_session() and
|
||||
* bfd_reconfigure_session(), which form an interface to the BFD core for the
|
||||
* rest and are expected to be called from the context of main thread.
|
||||
*
|
||||
* Each BFD session has an associated BFD interface, represented by structure
|
||||
* &bfd_iface. A BFD interface contains a socket used for TX (the one for RX is
|
||||
@ -108,10 +108,10 @@
|
||||
#define HASH_ID_EQ(a,b) a == b
|
||||
#define HASH_ID_FN(k) k
|
||||
|
||||
#define HASH_IP_KEY(n) n->addr
|
||||
#define HASH_IP_KEY(n) n->addr, n->ifindex
|
||||
#define HASH_IP_NEXT(n) n->next_ip
|
||||
#define HASH_IP_EQ(a,b) ipa_equal(a,b)
|
||||
#define HASH_IP_FN(k) ipa_hash(k)
|
||||
#define HASH_IP_EQ(a1,n1,a2,n2) ipa_equal(a1, a2) && n1 == n2
|
||||
#define HASH_IP_FN(a,n) ipa_hash(a) ^ u32_hash(n)
|
||||
|
||||
static list bfd_proto_list;
|
||||
static list bfd_wait_list;
|
||||
@ -385,9 +385,9 @@ bfd_find_session_by_id(struct bfd_proto *p, u32 id)
|
||||
}
|
||||
|
||||
struct bfd_session *
|
||||
bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr)
|
||||
bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex)
|
||||
{
|
||||
return HASH_FIND(p->session_hash_ip, HASH_IP, addr);
|
||||
return HASH_FIND(p->session_hash_ip, HASH_IP, addr, ifindex);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -426,6 +426,7 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
|
||||
struct bfd_session *s = sl_allocz(p->session_slab);
|
||||
s->addr = addr;
|
||||
s->ifa = ifa;
|
||||
s->ifindex = iface ? iface->index : 0;
|
||||
s->loc_id = bfd_get_free_id(p);
|
||||
|
||||
HASH_INSERT(p->session_hash_id, HASH_ID, s);
|
||||
@ -658,7 +659,8 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
|
||||
if (req->iface ? !cf->accept_direct : !cf->accept_multihop)
|
||||
return 0;
|
||||
|
||||
struct bfd_session *s = bfd_find_session_by_addr(p, req->addr);
|
||||
uint ifindex = req->iface ? req->iface->index : 0;
|
||||
struct bfd_session *s = bfd_find_session_by_addr(p, req->addr, ifindex);
|
||||
u8 state, diag;
|
||||
|
||||
if (!s)
|
||||
|
@ -153,6 +153,7 @@ struct bfd_session
|
||||
u8 detect_mult; /* Announced detect_mult, local option */
|
||||
u8 rem_detect_mult; /* Last received detect_mult */
|
||||
|
||||
uint ifindex; /* Iface index, for hashing in bfd.session_hash_ip */
|
||||
btime last_tx; /* Time of last sent periodic control packet */
|
||||
btime last_rx; /* Time of last received valid control packet */
|
||||
|
||||
@ -213,7 +214,7 @@ static inline void bfd_unlock_sessions(struct bfd_proto *p) { pthread_spin_unloc
|
||||
|
||||
/* bfd.c */
|
||||
struct bfd_session * bfd_find_session_by_id(struct bfd_proto *p, u32 id);
|
||||
struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr);
|
||||
struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex);
|
||||
void bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old_rx_int);
|
||||
void bfd_show_sessions(struct proto *P);
|
||||
|
||||
|
@ -366,7 +366,8 @@ bfd_rx_hook(sock *sk, uint len)
|
||||
if (ps > BFD_STATE_DOWN)
|
||||
DROP("invalid init state", ps);
|
||||
|
||||
s = bfd_find_session_by_addr(p, sk->faddr);
|
||||
uint ifindex = (sk->sport == BFD_CONTROL_PORT) ? sk->lifindex : 0;
|
||||
s = bfd_find_session_by_addr(p, sk->faddr, ifindex);
|
||||
|
||||
/* FIXME: better session matching and message */
|
||||
if (!s)
|
||||
|
@ -118,7 +118,7 @@ bgp_set_attr(ea_list **attrs, struct linpool *pool, uint code, uint flags, uintp
|
||||
static inline int
|
||||
bgp_put_attr_hdr3(byte *buf, uint code, uint flags, uint len)
|
||||
{
|
||||
*buf++ = flags;
|
||||
*buf++ = flags & ~BAF_EXT_LEN;
|
||||
*buf++ = code;
|
||||
*buf++ = len;
|
||||
return 3;
|
||||
@ -683,6 +683,37 @@ bgp_format_cluster_list(const eattr *a, byte *buf, uint size)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
bgp_encode_mp_reach_mrt(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
|
||||
{
|
||||
/*
|
||||
* Limited version of MP_REACH_NLRI used for MRT table dumps (IPv6 only):
|
||||
*
|
||||
* 3 B MP_REACH_NLRI header
|
||||
* 1 B MP_REACH_NLRI data - Length of Next Hop Network Address
|
||||
* var MP_REACH_NLRI data - Network Address of Next Hop
|
||||
*/
|
||||
|
||||
ip_addr *nh = (void *) a->u.ptr->data;
|
||||
uint len = a->u.ptr->length;
|
||||
|
||||
ASSERT((len == 16) || (len == 32));
|
||||
|
||||
if (size < (3+1+len))
|
||||
return -1;
|
||||
|
||||
bgp_put_attr_hdr3(buf, BA_MP_REACH_NLRI, BAF_OPTIONAL, 1+len);
|
||||
buf[3] = len;
|
||||
buf += 4;
|
||||
|
||||
put_ip6(buf, ipa_to_ip6(nh[0]));
|
||||
|
||||
if (len == 32)
|
||||
put_ip6(buf+16, ipa_to_ip6(nh[1]));
|
||||
|
||||
return 3+1+len;
|
||||
}
|
||||
|
||||
static inline u32
|
||||
get_af3(byte *buf)
|
||||
{
|
||||
|
@ -103,6 +103,7 @@
|
||||
* RFC 8654 - Extended Message Support for BGP
|
||||
* draft-ietf-idr-ext-opt-param-07
|
||||
* draft-uttaro-idr-bgp-persistence-04
|
||||
* draft-walton-bgp-hostname-capability-02
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
@ -2415,6 +2416,9 @@ bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
|
||||
bgp_show_afis(-1006, " AF supported:", afl1, afn1);
|
||||
bgp_show_afis(-1006, " AF preserved:", afl2, afn2);
|
||||
}
|
||||
|
||||
if (caps->hostname)
|
||||
cli_msg(-1006, " Hostname: %s", caps->hostname);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2473,6 +2477,7 @@ bgp_show_proto_info(struct proto *P)
|
||||
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
|
||||
}
|
||||
|
||||
#if 0
|
||||
struct bgp_stats *s = &p->stats;
|
||||
cli_msg(-1006, " FSM established transitions: %u",
|
||||
s->fsm_established_transitions);
|
||||
@ -2482,6 +2487,7 @@ bgp_show_proto_info(struct proto *P)
|
||||
s->tx_messages, s->tx_updates, s->tx_bytes);
|
||||
cli_msg(-1006, " Last rcvd update elapsed time: %t s",
|
||||
p->last_rx_update ? (current_time() - p->last_rx_update) : 0);
|
||||
#endif
|
||||
|
||||
if ((p->last_error_class != BE_NONE) &&
|
||||
(p->last_error_class != BE_MAN_DOWN))
|
||||
|
@ -98,6 +98,7 @@ struct bgp_config {
|
||||
int enable_refresh; /* Enable local support for route refresh [RFC 2918] */
|
||||
int enable_as4; /* Enable local support for 4B AS numbers [RFC 6793] */
|
||||
int enable_extended_messages; /* Enable local support for extended messages [draft] */
|
||||
int enable_hostname; /* Enable local support for hostname [draft] */
|
||||
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
|
||||
int rr_client; /* Whether neighbor is RR client of me */
|
||||
int rs_client; /* Whether neighbor is RS client of me */
|
||||
@ -228,6 +229,8 @@ struct bgp_caps {
|
||||
u8 any_ext_next_hop; /* Bitwise OR of per-AF ext_next_hop */
|
||||
u8 any_add_path; /* Bitwise OR of per-AF add_path */
|
||||
|
||||
const char *hostname; /* Hostname, RFC draft */
|
||||
|
||||
u16 af_count; /* Number of af_data items */
|
||||
u16 length; /* Length of capabilities in OPEN msg */
|
||||
|
||||
@ -559,6 +562,7 @@ static inline void
|
||||
bgp_unset_attr(ea_list **to, struct linpool *pool, uint code)
|
||||
{ eattr *e = bgp_set_attr(to, pool, code, 0, 0); e->type = EAF_TYPE_UNDEF; }
|
||||
|
||||
int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
|
||||
|
||||
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
|
||||
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
|
||||
|
@ -62,6 +62,7 @@ bgp_proto_start: proto_start BGP {
|
||||
BGP_CFG->error_delay_time_max = 300;
|
||||
BGP_CFG->enable_refresh = 1;
|
||||
BGP_CFG->enable_as4 = 1;
|
||||
BGP_CFG->enable_hostname = 0;
|
||||
BGP_CFG->capabilities = 2;
|
||||
BGP_CFG->interpret_communities = 1;
|
||||
BGP_CFG->allow_as_sets = 1;
|
||||
@ -173,6 +174,7 @@ bgp_proto:
|
||||
| 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; }
|
||||
| bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
|
||||
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
|
||||
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
|
||||
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
|
||||
|
@ -252,6 +252,14 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
|
||||
if (p->cf->llgr_mode)
|
||||
caps->llgr_aware = 1;
|
||||
|
||||
if (p->cf->enable_hostname && config->hostname)
|
||||
{
|
||||
size_t length = strlen(config->hostname);
|
||||
char *hostname = mb_allocz(p->p.pool, length+1);
|
||||
memcpy(hostname, config->hostname, length+1);
|
||||
caps->hostname = hostname;
|
||||
}
|
||||
|
||||
/* Allocate and fill per-AF fields */
|
||||
WALK_LIST(c, p->p.channels)
|
||||
{
|
||||
@ -412,6 +420,24 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
|
||||
data[-1] = buf - data;
|
||||
}
|
||||
|
||||
if (caps->hostname)
|
||||
{
|
||||
*buf++ = 73; /* Capability 73: Hostname */
|
||||
*buf++ = 0; /* Capability data length */
|
||||
data = buf;
|
||||
|
||||
/* Hostname */
|
||||
size_t length = strlen(caps->hostname);
|
||||
*buf++ = length;
|
||||
memcpy(buf, caps->hostname, length);
|
||||
buf += length;
|
||||
|
||||
/* Domain, not implemented */
|
||||
*buf++ = 0;
|
||||
|
||||
data[-1] = buf - data;
|
||||
}
|
||||
|
||||
caps->length = buf - buf_head;
|
||||
|
||||
return buf;
|
||||
@ -573,6 +599,21 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
|
||||
}
|
||||
break;
|
||||
|
||||
case 73: /* Hostname, RFC draft */
|
||||
if ((cl < 2) || (cl < 2 + pos[2]))
|
||||
goto err;
|
||||
|
||||
int length = pos[2];
|
||||
char *hostname = mb_allocz(p->p.pool, length+1);
|
||||
memcpy(hostname, pos + 3, length);
|
||||
hostname[length] = 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (hostname[i] < ' ')
|
||||
hostname[i] = ' ';
|
||||
|
||||
caps->hostname = hostname;
|
||||
|
||||
/* We can safely ignore all other capabilities */
|
||||
}
|
||||
|
||||
|
@ -244,7 +244,6 @@ mrt_next_table(struct mrt_table_dump_state *s)
|
||||
|
||||
s->table = tab;
|
||||
s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
|
||||
s->bws->mp_reach = !s->ipv4;
|
||||
|
||||
if (s->table)
|
||||
rt_lock_table(s->table);
|
||||
@ -417,6 +416,51 @@ mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n)
|
||||
mrt_put_u16(b, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BGP
|
||||
static void
|
||||
mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
|
||||
{
|
||||
struct ea_list *eattrs = r->attrs->eattrs;
|
||||
buffer *b = &s->buf;
|
||||
|
||||
if (!eattrs)
|
||||
return;
|
||||
|
||||
/* Attribute list must be normalized for bgp_encode_attrs() */
|
||||
if (!rta_is_cached(r->attrs))
|
||||
ea_normalize(eattrs);
|
||||
|
||||
mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
|
||||
byte *pos = b->pos;
|
||||
|
||||
s->bws->mp_reach = !s->ipv4;
|
||||
s->bws->mp_next_hop = NULL;
|
||||
|
||||
/* Encode BGP attributes */
|
||||
int len = bgp_encode_attrs(s->bws, eattrs, pos, b->end);
|
||||
if (len < 0)
|
||||
goto fail;
|
||||
pos += len;
|
||||
|
||||
/* Encode IPv6 next hop separately as fake MP_REACH_NLRI attribute */
|
||||
if (s->bws->mp_next_hop)
|
||||
{
|
||||
len = bgp_encode_mp_reach_mrt(s->bws, s->bws->mp_next_hop, pos, b->end - pos);
|
||||
if (len < 0)
|
||||
goto fail;
|
||||
pos += len;
|
||||
}
|
||||
|
||||
/* Update attribute length and advance buffer pos */
|
||||
put_u16(b->pos - 2, pos - b->pos);
|
||||
b->pos = pos;
|
||||
return;
|
||||
|
||||
fail:
|
||||
mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
|
||||
{
|
||||
@ -447,25 +491,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
|
||||
mrt_put_u16(b, 0);
|
||||
|
||||
#ifdef CONFIG_BGP
|
||||
if (r->attrs->eattrs)
|
||||
{
|
||||
struct ea_list *eattrs = r->attrs->eattrs;
|
||||
|
||||
if (!rta_is_cached(r->attrs))
|
||||
ea_normalize(eattrs);
|
||||
|
||||
mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
|
||||
int alen = bgp_encode_attrs(s->bws, eattrs, b->pos, b->end);
|
||||
|
||||
if (alen < 0)
|
||||
{
|
||||
mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
|
||||
alen = 0;
|
||||
}
|
||||
|
||||
put_u16(b->pos - 2, alen);
|
||||
b->pos += alen;
|
||||
}
|
||||
mrt_rib_table_entry_bgp_attrs(s, r);
|
||||
#endif
|
||||
|
||||
s->entry_count++;
|
||||
|
@ -294,6 +294,14 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
n->ip = faddr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Update RFC 7166 authentication trailer flag */
|
||||
if (ospf_is_v3(p) && ((rcv_options ^ n->options) & OPT_AT))
|
||||
{
|
||||
OSPF_TRACE(D_EVENTS, "Neighbor %R on %s %s authentication",
|
||||
n->rid, ifa->ifname, (rcv_options & OPT_AT) ? "enabled" : "disabled");
|
||||
n->options = (n->options & ~OPT_AT) | (rcv_options & OPT_AT);
|
||||
}
|
||||
}
|
||||
|
||||
if (!n)
|
||||
@ -326,6 +334,9 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
|
||||
n->priority = rcv_priority;
|
||||
n->iface_id = rcv_iface_id;
|
||||
|
||||
if (ospf_is_v3(p))
|
||||
n->options = rcv_options & OPT_AT;
|
||||
|
||||
if (n->ifa->cf->bfd)
|
||||
ospf_neigh_update_bfd(n, n->ifa->bfd);
|
||||
}
|
||||
|
@ -141,6 +141,8 @@ pipe_postconfig(struct proto_config *CF)
|
||||
|
||||
if (cc->in_keep_filtered)
|
||||
cf_error("Pipe protocol prohibits keeping filtered routes");
|
||||
|
||||
cc->debug = cf->c.debug;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -154,7 +156,9 @@ pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
|
||||
.table = cc->table,
|
||||
.out_filter = cc->out_filter,
|
||||
.in_limit = cc->in_limit,
|
||||
.ra_mode = RA_ANY
|
||||
.ra_mode = RA_ANY,
|
||||
.debug = cc->debug,
|
||||
.rpki_reload = cc->rpki_reload,
|
||||
};
|
||||
|
||||
struct channel_config sec_cf = {
|
||||
@ -163,7 +167,9 @@ pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
|
||||
.table = cf->peer,
|
||||
.out_filter = cc->in_filter,
|
||||
.in_limit = cc->out_limit,
|
||||
.ra_mode = RA_ANY
|
||||
.ra_mode = RA_ANY,
|
||||
.debug = cc->debug,
|
||||
.rpki_reload = cc->rpki_reload,
|
||||
};
|
||||
|
||||
return
|
||||
@ -276,6 +282,14 @@ pipe_show_proto_info(struct proto *P)
|
||||
pipe_show_stats(p);
|
||||
}
|
||||
|
||||
void
|
||||
pipe_update_debug(struct proto *P)
|
||||
{
|
||||
struct pipe_proto *p = (void *) P;
|
||||
|
||||
p->pri->debug = p->sec->debug = p->p.debug;
|
||||
}
|
||||
|
||||
|
||||
struct protocol proto_pipe = {
|
||||
.name = "Pipe",
|
||||
|
@ -33,11 +33,11 @@ rip_check_auth(void)
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(RIP, NG, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
|
||||
GARBAGE, PORT, ADDRESS, MODE, BROADCAST, MULTICAST, PASSIVE,
|
||||
VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO, TIME, BFD,
|
||||
AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5, TTL, SECURITY,
|
||||
RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, DEMAND, CIRCUIT,
|
||||
RIP_METRIC, RIP_TAG)
|
||||
GARBAGE, RETRANSMIT, PORT, ADDRESS, MODE, BROADCAST, MULTICAST,
|
||||
PASSIVE, VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO,
|
||||
TIME, BFD, AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5,
|
||||
TTL, SECURITY, RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK,
|
||||
DEMAND, CIRCUIT, RIP_METRIC, RIP_TAG)
|
||||
|
||||
%type <i> rip_variant rip_auth
|
||||
|
||||
|
@ -827,8 +827,6 @@ rpki_handle_end_of_data_pdu(struct rpki_cache *cache, const struct pdu_end_of_da
|
||||
cache->last_update = current_time();
|
||||
cache->serial_num = pdu->serial_num;
|
||||
rpki_cache_change_state(cache, RPKI_CS_ESTABLISHED);
|
||||
|
||||
reload_all();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,12 +19,13 @@
|
||||
/**
|
||||
* rpki_hostname_autoresolv - auto-resolve an IP address from a hostname
|
||||
* @host: domain name of host, e.g. "rpki-validator.realmv6.org"
|
||||
* @err_msg: error message returned in case of errors
|
||||
*
|
||||
* This function resolves an IP address from a hostname.
|
||||
* Returns &ip_addr structure with IP address or |IPA_NONE|.
|
||||
*/
|
||||
static ip_addr
|
||||
rpki_hostname_autoresolv(const char *host)
|
||||
rpki_hostname_autoresolv(const char *host, const char **err_msg)
|
||||
{
|
||||
struct addrinfo *res;
|
||||
struct addrinfo hints = {
|
||||
@ -33,13 +34,15 @@ rpki_hostname_autoresolv(const char *host)
|
||||
.ai_flags = AI_ADDRCONFIG,
|
||||
};
|
||||
|
||||
*err_msg = NULL;
|
||||
|
||||
if (!host)
|
||||
return IPA_NONE;
|
||||
|
||||
int err_code = getaddrinfo(host, NULL, &hints, &res);
|
||||
if (err_code != 0)
|
||||
{
|
||||
log(L_DEBUG "getaddrinfo failed: %s", gai_strerror(err_code));
|
||||
*err_msg = gai_strerror(err_code);
|
||||
return IPA_NONE;
|
||||
}
|
||||
|
||||
@ -83,12 +86,15 @@ rpki_tr_open(struct rpki_tr_sock *tr)
|
||||
sk->tbsize = RPKI_TX_BUFFER_SIZE;
|
||||
sk->tos = IP_PREC_INTERNET_CONTROL;
|
||||
|
||||
if (ipa_zero2(sk->daddr) && sk->host)
|
||||
if (ipa_zero(sk->daddr) && sk->host)
|
||||
{
|
||||
sk->daddr = rpki_hostname_autoresolv(sk->host);
|
||||
const char *err_msg;
|
||||
|
||||
sk->daddr = rpki_hostname_autoresolv(sk->host, &err_msg);
|
||||
if (ipa_zero(sk->daddr))
|
||||
{
|
||||
CACHE_TRACE(D_EVENTS, cache, "Cannot resolve the hostname '%s'", sk->host);
|
||||
log(L_ERR "%s: Cannot resolve hostname '%s': %s",
|
||||
cache->p->p.name, sk->host, err_msg);
|
||||
return RPKI_TR_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -148,15 +148,48 @@ static_mark_rte(struct static_proto *p, struct static_route *r)
|
||||
ev_schedule(p->event);
|
||||
}
|
||||
|
||||
static void
|
||||
static_mark_all(struct static_proto *p)
|
||||
{
|
||||
struct static_config *cf = (void *) p->p.cf;
|
||||
struct static_route *r;
|
||||
|
||||
/* We want to reload all routes, mark them as dirty */
|
||||
|
||||
WALK_LIST(r, cf->routes)
|
||||
if (r->state == SRS_CLEAN)
|
||||
r->state = SRS_DIRTY;
|
||||
|
||||
p->marked_all = 1;
|
||||
BUFFER_FLUSH(p->marked);
|
||||
|
||||
if (!ev_active(p->event))
|
||||
ev_schedule(p->event);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
static_announce_marked(void *P)
|
||||
{
|
||||
struct static_proto *p = P;
|
||||
struct static_config *cf = (void *) p->p.cf;
|
||||
struct static_route *r;
|
||||
|
||||
BUFFER_WALK(p->marked, r)
|
||||
static_announce_rte(P, r);
|
||||
if (p->marked_all)
|
||||
{
|
||||
WALK_LIST(r, cf->routes)
|
||||
if (r->state == SRS_DIRTY)
|
||||
static_announce_rte(p, r);
|
||||
|
||||
BUFFER_FLUSH(p->marked);
|
||||
p->marked_all = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
BUFFER_WALK(p->marked, r)
|
||||
static_announce_rte(p, r);
|
||||
|
||||
BUFFER_FLUSH(p->marked);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -367,6 +400,16 @@ static_bfd_notify(struct bfd_request *req)
|
||||
static_mark_rte(p, r->mp_head);
|
||||
}
|
||||
|
||||
static void
|
||||
static_reload_routes(struct channel *C)
|
||||
{
|
||||
struct static_proto *p = (void *) C->proto;
|
||||
|
||||
TRACE(D_EVENTS, "Scheduling route reload");
|
||||
|
||||
static_mark_all(p);
|
||||
}
|
||||
|
||||
static int
|
||||
static_rte_better(rte *new, rte *old)
|
||||
{
|
||||
@ -421,6 +464,7 @@ static_init(struct proto_config *CF)
|
||||
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
|
||||
|
||||
P->neigh_notify = static_neigh_notify;
|
||||
P->reload_routes = static_reload_routes;
|
||||
P->rte_better = static_rte_better;
|
||||
P->rte_mergable = static_rte_mergable;
|
||||
|
||||
@ -633,6 +677,10 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
xfree(orbuf);
|
||||
xfree(nrbuf);
|
||||
|
||||
/* All dirty routes were announced anyways */
|
||||
BUFFER_FLUSH(p->marked);
|
||||
p->marked_all = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ struct static_proto {
|
||||
|
||||
struct event *event; /* Event for announcing updated routes */
|
||||
BUFFER_(struct static_route *) marked; /* Routes marked for reannouncement */
|
||||
int marked_all; /* All routes are marked */
|
||||
rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
|
||||
rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
|
||||
};
|
||||
|
@ -13,7 +13,7 @@
|
||||
#ifdef GIT_LABEL
|
||||
#define BIRD_VERSION XSTR1(GIT_LABEL)
|
||||
#else
|
||||
#define BIRD_VERSION "2.0.7"
|
||||
#define BIRD_VERSION "2.0.8"
|
||||
#endif
|
||||
|
||||
/* Include parameters determined by configure script */
|
||||
|
@ -790,6 +790,9 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
|
||||
if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
|
||||
return NULL;
|
||||
|
||||
if (nh->rtnh_flags & RTNH_F_DEAD)
|
||||
goto next;
|
||||
|
||||
*last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE);
|
||||
last = &(rv->next);
|
||||
|
||||
@ -865,7 +868,7 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
next:
|
||||
len -= NLMSG_ALIGN(nh->rtnh_len);
|
||||
nh = RTNH_NEXT(nh);
|
||||
}
|
||||
@ -1776,6 +1779,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i->rtm_flags & RTNH_F_DEAD)
|
||||
return;
|
||||
|
||||
ra->nh.iface = if_find_by_index(oif);
|
||||
if (!ra->nh.iface)
|
||||
{
|
||||
|
@ -2161,6 +2161,7 @@ io_init(void)
|
||||
{
|
||||
init_list(&sock_list);
|
||||
init_list(&global_event_list);
|
||||
init_list(&global_work_list);
|
||||
krt_io_init();
|
||||
// XXX init_times();
|
||||
// XXX update_times();
|
||||
@ -2172,6 +2173,7 @@ io_init(void)
|
||||
|
||||
static int short_loops = 0;
|
||||
#define SHORT_LOOP_MAX 10
|
||||
#define WORK_EVENTS_MAX 10
|
||||
|
||||
void
|
||||
io_loop(void)
|
||||
@ -2189,6 +2191,7 @@ io_loop(void)
|
||||
{
|
||||
times_update(&main_timeloop);
|
||||
events = ev_run_list(&global_event_list);
|
||||
events = ev_run_list_limited(&global_work_list, WORK_EVENTS_MAX) || events;
|
||||
timers_fire(&main_timeloop);
|
||||
io_close_event();
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include "nest/bird.h"
|
||||
@ -88,6 +89,21 @@ drop_gid(gid_t gid)
|
||||
die("setgroups: %m");
|
||||
}
|
||||
|
||||
/*
|
||||
* Hostname
|
||||
*/
|
||||
|
||||
char *
|
||||
get_hostname(linpool *lp)
|
||||
{
|
||||
struct utsname uts = {};
|
||||
|
||||
if (uname(&uts) < 0)
|
||||
return NULL;
|
||||
|
||||
return lp_strdup(lp, uts.nodename);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reading the Configuration
|
||||
*/
|
||||
|
@ -24,6 +24,7 @@ extern int parse_and_exit;
|
||||
void async_config(void);
|
||||
void async_dump(void);
|
||||
void async_shutdown(void);
|
||||
char *get_hostname(linpool *lp);
|
||||
void cmd_check_config(const char *name);
|
||||
void cmd_reconfig(const char *name, int type, uint timeout);
|
||||
void cmd_reconfig_confirm(void);
|
||||
|
@ -516,6 +516,7 @@ char *bird_name;
|
||||
void async_config(void) {}
|
||||
void async_dump(void) {}
|
||||
void async_shutdown(void) {}
|
||||
char *get_hostname(linpool *lp UNUSED) { return NULL; }
|
||||
void cmd_check_config(char *name UNUSED) {}
|
||||
void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
|
||||
void cmd_reconfig_confirm(void) {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user