Compare commits

...

32 Commits

Author SHA1 Message Date
256e198fee
add drone pipeline
Some checks reported errors
continuous-integration/drone/push Build is passing
continuous-integration/drone Build encountered an error
2021-12-30 13:19:02 +00:00
18853a82c6
Reset Extendend Length flag when encoding BGP attributes 2021-03-27 14:29:55 +00:00
e6133456c1
Bump version in build script 2021-03-22 09:09:19 +00:00
b86d3f9a2e
Revert "Add patch from JRB0001 to reload protocols on RPKI change"
This reverts commit 3155bb34bed49c909f00e5d3aadc9a74c2e6ef5c.
2021-03-22 09:05:39 +00:00
910f9127f0
Add additional error information on NETLINK failures 2021-03-22 09:03:24 +00:00
ce7a2736e9
add tag to build 2021-03-22 09:03:24 +00:00
397c52070a
Add build script 2021-03-22 09:03:24 +00:00
Simon Marsh
4aecc5f8cd
Add patch from JRB0001 to provide more verbose error logging on bad next hop. 2021-03-22 09:03:23 +00:00
Simon Marsh
3155bb34be
Add patch from JRB0001 to reload protocols on RPKI change 2021-03-22 09:03:23 +00:00
Ondrej Zajicek (work)
82f19ba95e NEWS and version update 2021-03-18 20:18:38 +01:00
Ondrej Zajicek (work)
f1ffe6a231 Add new BGP tests 2021-03-18 15:54:44 +01:00
Ondrej Zajicek (work)
5a6e8380f8 BGP: Do not show statistics
BGP statistics code was preliminary and i wanted to replace it by
separate 'show X stats' command. The patch hides the preliminary
output in 'show protocols all' so it is not part of the released
version.
2021-03-18 15:44:04 +01:00
Ondrej Zajicek (work)
454ae30445 RPKI: Improve error handling of DNS resolver 2021-03-17 17:24:00 +01:00
Ondrej Zajicek (work)
0a3db4c680 Minor fixes for restricted builds 2021-03-17 15:56:12 +01:00
Ondrej Zajicek (work)
2f98153490 Pipe: Propagate debug flags from protocol to channels
Pipe channels are kind-of implicit, so setting protocol debug flags
should also set pipe debug flags.
2021-03-16 20:10:00 +01:00
Ondrej Zajicek (work)
ae9ae864d3 OSPFv3: Update neighbor authentication state from Hello packets
In OSPFv3, only Hello and DBDes packets contain flags specifying whether
RFC 7166 authentication trailer is used. Other packets are processed
based on stored authentication state in neighbor structure. Update this
state with each received Hello to handle authentication change from
reconfigurations.

Thanks to Joakim Tjernlund and Kenth Eriksson for the bugreport.
2021-03-16 16:34:42 +01:00
Ondrej Zajicek (work)
94abefc00b Filter: Update 'gw' to handle IPv6 link-local addresses
When a link-local address is set, use the existing iface for scope.

Thanks to Marcel Krüger for the bugreport.
2021-03-15 18:37:18 +01:00
Ondrej Zajicek (work)
0d1a11cca3 Doc: Document automatic RPKI reload 2021-03-15 17:51:33 +01:00
Ondrej Zajicek (work)
6489a2450e Doc: Document channel debug options 2021-03-15 16:16:32 +01:00
Ondrej Zajicek (work)
7be3af7fa6 Rate-limit scheduling of work-events
In general, events are code handling some some condition, which is
scheduled when such condition happened and executed independently from
I/O loop. Work-events are a subgroup of events that are scheduled
repeatedly until some (often significant) work is done (e.g. feeding
routes to protocol). All scheduled events are executed during each
I/O loop iteration.

Separate work-events from regular events to a separate queue and
rate limit their execution to a fixed number per I/O loop iteration.
That should prevent excess latency when many work-events are
scheduled at one time (e.g. simultaneous reload of many BGP sessions).
2021-03-12 15:35:56 +01:00
Ondrej Zajicek (work)
9cf3d53311 Static: Implement reload hook 2021-03-10 15:07:19 +01:00
Ondrej Zajicek (work)
211fe69c98 Nest: No automatic ROA reload on non-reloadable channels 2021-03-09 18:37:52 +01:00
Ondrej Zajicek (work)
d3782c72b9 Nest: Add option to control automatic RPKI reload
Also, no automatic reload for BGP channels without import/export table.
2021-02-12 05:05:18 +01:00
Ondrej Zajicek (work)
77ce849ecf Tests: Add missing mockup function to tests 2021-02-10 17:29:14 +01:00
Vincent Bernat
714238716e BGP: Add support for BGP hostname capability
This is an implementation of draft-walton-bgp-hostname-capability-02.
It is implemented since quite some time for FRR and in datacenter, this
gives a nice output to avoid using IP addresses.

It is disabled by default. The hostname is retrieved from uname(2) and
can be overriden with "hostname" option. The domain name is never set
nor displayed.

Minor changes by committer.
2021-02-10 16:53:57 +01:00
Ondrej Zajicek (work)
00b85905b9 Nest: Automatic channel reloads based on RPKI changes
If there are roa_check() calls in channel filters, then the channel
subscribes to ROA table notifications, which are sent when ROA tables
are updated (subject to settle time) and trigger channel reload or
refeed.
2021-02-10 03:09:57 +01:00
Ondrej Zajicek (work)
d06a875b04 Filter: Recursive filter iteration code
Add macros for recursive filter iteration that allows to examine
all instructions reachable from a filter.
2021-02-07 19:21:42 +01:00
Ondrej Zajicek (work)
5d414309ec MRT: Fix MP-BGP next hops
Flag signalling that MP-BGP mode should be used got reset after first
batch of routes, so remaining routes were processed without that, leading
to missing MP_REACH_NLRI attribute.

Thanks to Piotr Wydrych for the bugreport.
2021-01-22 04:34:15 +01:00
Ondrej Zajicek (work)
df83f62697 Netlink: Ignore dead routes
With net.ipv4.conf.XXX.ignore_routes_with_linkdown sysctl, a user can
ensure the kernel does not use a route whose target interface is down.
Such route is marked with a 'dead' / RTNH_F_DEAD flag.

Ignore these routes or multipath nexthops during scan.

Thanks to Vincent Bernat for the original patch.
2021-01-14 02:01:07 +01:00
Ondrej Zajicek (work)
a40ddf5c61 Build: Fix tags generation 2021-01-12 15:43:54 +01:00
Ondrej Zajicek (work)
d774f6d721 MRT: Fix IPv6 table dumps
Add fake MP_REACH_NLRI attribute with BGP next hop when encoding MRT
table dumps for IPv6 routes. That is necessary to encode next hop as
NEXT_HOP attribute is not used for MP-BGP.

Thanks to Santiago Aggio for the bugreport.
2021-01-12 15:37:01 +01:00
Ondrej Zajicek (work)
910adaa08b BFD: Dispatch sessions also by interface index
Direct BFD sessions needs to be dispatched not only by IP addresses, but
also by interfaces, in order to avoid collisions between neighbors with
the same IPv6 link-local addresses.

Extend BFD session hash_ip key by interface index to handle that. Use 0
for multihop sessions.

Thanks to Sebastian Hahn for the original patch.
2021-01-10 15:29:02 +01:00
43 changed files with 1060 additions and 105 deletions

57
.drone.yml Normal file
View 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

View File

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

View File

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

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

View 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() */
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 */
}
@ -891,10 +932,10 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, uint len)
#define WITHDRAW(msg, args...) \
({ REPORT(msg, ## args); s->err_withdraw = 1; return; })
#define BAD_AFI "Unexpected AF <%u/%u> in UPDATE"
#define BAD_NEXT_HOP "Invalid NEXT_HOP attribute"
#define NO_NEXT_HOP "Missing NEXT_HOP attribute"
#define NO_LABEL_STACK "Missing MPLS stack"
#define BAD_AFI "Unexpected AF <%u/%u> in UPDATE."
#define BAD_NEXT_HOP "Invalid NEXT_HOP attribute %I (%s)."
#define NO_NEXT_HOP "Missing NEXT_HOP attribute."
#define NO_LABEL_STACK "Missing MPLS stack."
static void
@ -914,7 +955,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
nbr = neigh_find(&p->p, ll, p->neigh->iface, 0);
if (!nbr || (nbr->scope == SCOPE_HOST))
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, gw, "missing or local neighbor");
a->dest = RTD_UNICAST;
a->nh.gw = nbr->addr;
@ -924,7 +965,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
else /* GW_RECURSIVE */
{
if (ipa_zero(gw))
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, gw, "zero address");
rtable *tab = ipa_is_ip4(gw) ? c->igp_table_ip4 : c->igp_table_ip6;
s->hostentry = rt_get_hostentry(tab, gw, ll, c->c.table);
@ -1086,16 +1127,16 @@ bgp_update_next_hop_ip(struct bgp_export_state *s, eattr *a, ea_list **to)
/* Forbid zero next hop */
if (ipa_zero(nh[0]) && ((len != 32) || ipa_zero(nh[1])))
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, nh[0], "zero address");
/* Forbid next hop equal to neighbor IP */
if (ipa_equal(peer, nh[0]) || ((len == 32) && ipa_equal(peer, nh[1])))
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, nh[0], "equals neighbor address");
/* Forbid next hop with non-matching AF */
if ((ipa_is_ip4(nh[0]) != bgp_channel_is_ipv4(s->channel)) &&
!s->channel->ext_next_hop)
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, nh[0], "wrong address family");
/* Just check if MPLS stack */
if (s->mpls && !bgp_find_attr(*to, BA_MPLS_LABEL_STACK))
@ -1170,7 +1211,7 @@ bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a)
ad->length = 16;
if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, nh[0], "wrong address family");
// XXXX validate next hop
@ -1251,7 +1292,7 @@ bgp_decode_next_hop_vpn(struct bgp_parse_state *s, byte *data, uint len, rta *a)
bgp_parse_error(s, 9);
if ((bgp_channel_is_ipv4(c) != ipa_is_ip4(nh[0])) && !c->ext_next_hop)
WITHDRAW(BAD_NEXT_HOP);
WITHDRAW(BAD_NEXT_HOP, nh[0], "wrong address family");
// XXXX validate next hop

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -143,13 +143,28 @@ static struct nl_sock nl_scan = {.fd = -1}; /* Netlink socket for synchronous sc
static struct nl_sock nl_req = {.fd = -1}; /* Netlink socket for requests */
static void
nl_open_sock(struct nl_sock *nl)
nl_open_sock(struct nl_sock *nl, int ext_ack)
{
if (nl->fd < 0)
{
nl->fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (nl->fd < 0)
die("Unable to open rtnetlink socket: %m");
#ifdef NETLINK_EXT_ACK
if (ext_ack)
{
/* enable extended ACK for more detailed error information */
const int ack_enable = 1;
int so_ok = setsockopt(nl->fd, SOL_NETLINK, NETLINK_EXT_ACK, (void *)&ack_enable, sizeof(ack_enable));
if (so_ok < 0)
/* failure isn't fatal, it will just mean less debug is available on errors */
log(L_WARN "nl_open_sock: Unable to set NETLINK_EXT_ACK: %m");
}
#endif
nl->seq = (u32) (current_time() TO_S); /* Or perhaps random_u32() ? */
nl->rx_buffer = xmalloc(NL_RX_SIZE);
nl->last_hdr = NULL;
@ -160,8 +175,8 @@ nl_open_sock(struct nl_sock *nl)
static void
nl_open(void)
{
nl_open_sock(&nl_scan);
nl_open_sock(&nl_req);
nl_open_sock(&nl_scan, 0);
nl_open_sock(&nl_req, 1);
}
static void
@ -241,6 +256,7 @@ nl_get_reply(struct nl_sock *nl)
}
static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
static void nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h);
static int
nl_error(struct nlmsghdr *h, int ignore_esrch)
@ -256,7 +272,84 @@ nl_error(struct nlmsghdr *h, int ignore_esrch)
e = (struct nlmsgerr *) NLMSG_DATA(h);
ec = -e->error;
if (ec && !(ignore_esrch && (ec == ESRCH)))
{
#ifdef NETLINK_EXT_ACK
/* check if extended error info was provided */
if (h->nlmsg_flags & NLM_F_ACK_TLVS)
{
/* parse the returned route data */
struct nl_parse_state s;
memset(&s, 0, sizeof(struct nl_parse_state));
s.pool = nl_linpool;
s.scan = 1; /* required to prevent nl_parse_route rejecting the route data */
nl_parse_route(&s, &e->msg);
/* scan eattrs to check if EA_KRT_PREFSRC was set */
int krt_prefsrc_found = 0;
ip_addr krt_prefsrc;
struct ea_list *eattrs = s.attrs->eattrs;
while(!krt_prefsrc_found && eattrs)
{
uint i;
eattr *attr = eattrs->attrs;
for(i=0; i < eattrs->count; i++,attr++)
{
if (attr->id == EA_KRT_PREFSRC)
{
memcpy(&krt_prefsrc, attr->u.ptr->data, sizeof(ip_addr));
krt_prefsrc_found = 1;
break;
}
}
eattrs = eattrs->next;
}
/* walk the extended attributes to find the error message */
struct nlattr *attr;
uint offset = NLMSG_HDRLEN + 4 + NLMSG_ALIGN(e->msg.nlmsg_len);
const char *msg = NULL;
while(!msg && (offset < h->nlmsg_len))
{
attr = (struct nlattr *)(((char *)h) + offset);
if (attr->nla_type == NLMSGERR_ATTR_MSG)
{
msg = ((const char *)attr + sizeof(struct nlattr));
break;
}
offset += attr->nla_len;
}
if (msg)
{
if (krt_prefsrc_found)
{
log_rl(&rl_netlink_err, L_WARN "Netlink Error: %s (%s, net=%N, nexthop=%I, krt_prefsrc=%I)", strerror(ec), msg, s.net->n.addr, s.attrs->nh.gw, krt_prefsrc);
}
else
{
log_rl(&rl_netlink_err, L_WARN "Netlink Error: %s (%s, net=%N, nexthop=%I)", strerror(ec), msg, s.net->n.addr, s.attrs->nh.gw);
}
/* exit here */
lp_flush(nl_linpool);
return ec;
}
/* cleanup */
lp_flush(nl_linpool);
}
#endif
/* default generic error if no other info available */
log_rl(&rl_netlink_err, L_WARN "Netlink: %s", strerror(ec));
}
return ec;
}
@ -697,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);
@ -772,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);
}
@ -1683,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)
{

View File

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

View File

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

View File

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

View File

@ -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) {}