0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-22 09:41:54 +00:00

Merge remote-tracking branch 'origin/master' into soft-int

This commit is contained in:
Ondrej Zajicek 2014-10-14 17:23:34 +02:00
commit 78342404ff
35 changed files with 281 additions and 102 deletions

16
NEWS
View File

@ -1,3 +1,17 @@
Version 1.4.5 (2014-10-06)
o New 'show route noexport' command option.
o Port option for BGP sessions.
o Better constant handling in set literals.
o Better rate filtering of log messages.
o Several minor bugfixes.
Version 1.4.4 (2014-07-09)
o Extended OSPF multipath support.
o Default router preference for RAdv.
o Significant changes in socket layer.
o Important bugfix in BGP.
o Several minor bugfixes.
Version 1.4.3 (2014-04-14) Version 1.4.3 (2014-04-14)
o Important bugfix in IPv6 BGP. o Important bugfix in IPv6 BGP.
@ -32,7 +46,7 @@ Version 1.4.0 (2013-11-25)
- Import of device routes from kernel protocol allowed. - Import of device routes from kernel protocol allowed.
- Last state change now tracks just protocol state change. - Last state change now tracks just protocol state change.
- Minor changes to default router ID calculation. - Minor changes to default router ID calculation.
Version 1.3.11 (2013-07-27) Version 1.3.11 (2013-07-27)
o OSPF stub router option (RFC 3137). o OSPF stub router option (RFC 3137).
o TTL security for OSPF and RIP. o TTL security for OSPF and RIP.

View File

@ -646,7 +646,7 @@ cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos)
char * char *
cf_symbol_class_name(struct symbol *sym) cf_symbol_class_name(struct symbol *sym)
{ {
if ((sym->class & 0xff00) == SYM_CONSTANT) if (cf_symbol_is_constant(sym))
return "constant"; return "constant";
switch (sym->class) switch (sym->class)

View File

@ -149,6 +149,10 @@ void cf_pop_scope(void);
struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos); struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos);
char *cf_symbol_class_name(struct symbol *sym); char *cf_symbol_class_name(struct symbol *sym);
static inline int cf_symbol_is_constant(struct symbol *sym)
{ return (sym->class & 0xff00) == SYM_CONSTANT; }
/* Parser */ /* Parser */
int cf_parse(void); int cf_parse(void);

View File

@ -72,7 +72,7 @@ CF_DECLS
%token <t> TEXT %token <t> TEXT
%type <iface> ipa_scope %type <iface> ipa_scope
%type <i> expr bool pxlen %type <i> expr bool pxlen ipa_port
%type <i32> expr_us %type <i32> expr_us
%type <time> datetime %type <time> datetime
%type <a> ipa %type <a> ipa
@ -88,7 +88,7 @@ CF_DECLS
%left '!' %left '!'
%nonassoc '.' %nonassoc '.'
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US) CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT)
CF_GRAMMAR CF_GRAMMAR
@ -161,6 +161,14 @@ ipa_scope:
| '%' SYM { $$ = if_get_by_name($2->name); } | '%' SYM { $$ = if_get_by_name($2->name); }
; ;
ipa_port:
/* empty */ { $$ = 0; }
| PORT expr {
if (($2 < 1) || ($2 > 65535)) cf_error("Invalid port number");
$$ = $2;
}
;
prefix: prefix:
ipa pxlen { ipa pxlen {
if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix"); if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix");

View File

@ -318,7 +318,7 @@ protocol rip {
<p><descrip> <p><descrip>
<tag>include "<m/filename/"</tag> <tag>include "<m/filename/"</tag>
This statement causes inclusion of a new file. <m/Filename/ could also This statement causes inclusion of a new file. <m/Filename/ could also
be a wildcard. The maximal depth is 5. Note that this statement could be be a wildcard. The maximal depth is 8. Note that this statement could be
used anywhere in the config file, not just as a top-level option. used anywhere in the config file, not just as a top-level option.
<tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag> <tag><label id="dsc-log">log "<m/filename/"|syslog [name <m/name/]|stderr all|{ <m/list of classes/ }</tag>
@ -735,7 +735,7 @@ This argument can be omitted if there exists only a single instance.
Show the list of symbols defined in the configuration (names of Show the list of symbols defined in the configuration (names of
protocols, routing tables etc.). protocols, routing tables etc.).
<tag>show route [[for] <m/prefix/|<m/IP/] [table <m/sym/] [filter <m/f/|where <m/c/] [(export|preexport) <m/p/] [protocol <m/p/] [<m/options/]</tag> <tag>show route [[for] <m/prefix/|<m/IP/] [table <m/sym/] [filter <m/f/|where <m/c/] [(export|preexport|noexport) <m/p/] [protocol <m/p/] [<m/options/]</tag>
Show contents of a routing table (by default of the main one or the Show contents of a routing table (by default of the main one or the
table attached to a respective protocol), that is routes, their metrics table attached to a respective protocol), that is routes, their metrics
and (in case the <cf/all/ switch is given) all their attributes. and (in case the <cf/all/ switch is given) all their attributes.
@ -750,9 +750,14 @@ This argument can be omitted if there exists only a single instance.
<p>You can also ask for printing only routes processed and accepted by <p>You can also ask for printing only routes processed and accepted by
a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ } a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ }
</cf> or matching a given condition (<cf>where <m/condition/</cf>). </cf> or matching a given condition (<cf>where <m/condition/</cf>).
The <cf/export/ and <cf/preexport/ switches ask for printing of entries
that are exported to the specified protocol. With <cf/preexport/, the The <cf/export/, <cf/preexport/ and <cf/noexport/ switches ask for
export filter of the protocol is skipped. printing of routes that are exported to the specified protocol.
With <cf/preexport/, the export filter of the protocol is skipped.
With <cf/noexport/, routes rejected by the export filter are printed
instead. Note that routes not exported to the protocol for other reasons
(e.g. secondary routes or routes imported from that protocol) are not
printed even with <cf/noexport/.
<p>You can also select just routes added by a specific protocol. <p>You can also select just routes added by a specific protocol.
<cf>protocol <m/p/</cf>. <cf>protocol <m/p/</cf>.
@ -1004,7 +1009,6 @@ foot).
So <cf>1.2.0.0/16.pxlen = 16</cf> is true. So <cf>1.2.0.0/16.pxlen = 16</cf> is true.
<tag/ec/ <tag/ec/
This is a specialized type used to represent BGP extended community This is a specialized type used to represent BGP extended community
values. It is essentially a 64bit value, literals of this type are values. It is essentially a 64bit value, literals of this type are
usually written as <cf>(<m/kind/, <m/key/, <m/value/)</cf>, where usually written as <cf>(<m/kind/, <m/key/, <m/value/)</cf>, where
@ -1014,7 +1018,7 @@ foot).
used kind. Similarly to pairs, ECs can be constructed using expressions used kind. Similarly to pairs, ECs can be constructed using expressions
for <cf/key/ and <cf/value/ parts, (e.g. <cf/(ro, myas, 3*10)/, where for <cf/key/ and <cf/value/ parts, (e.g. <cf/(ro, myas, 3*10)/, where
<cf/myas/ is an integer variable). <cf/myas/ is an integer variable).
<tag/int|pair|quad|ip|prefix|ec|enum set/ <tag/int|pair|quad|ip|prefix|ec|enum set/
Filters recognize four types of sets. Sets are similar to strings: you Filters recognize four types of sets. Sets are similar to strings: you
can pass them around but you can't modify them. Literals of type <cf>int can pass them around but you can't modify them. Literals of type <cf>int
@ -1616,7 +1620,7 @@ using the following configuration parameters:
address, equivalent to the <cf/source address/ option (see below). This address, equivalent to the <cf/source address/ option (see below). This
parameter is mandatory. parameter is mandatory.
<tag>neighbor <m/ip/ as <m/number/</tag> <tag>neighbor <m/ip/ [port <m/number/] as <m/number/</tag>
Define neighboring router this instance will be talking to and what AS Define neighboring router this instance will be talking to and what AS
it's located in. In case the neighbor is in the same AS as we are, we it's located in. In case the neighbor is in the same AS as we are, we
automatically switch to iBGP. This parameter is mandatory. automatically switch to iBGP. This parameter is mandatory.
@ -3036,6 +3040,10 @@ definitions, prefix definitions and DNS definitions:
as a default router. For <cf/sensitive/ option, see <ref id="dsc-trigger" name="trigger">. as a default router. For <cf/sensitive/ option, see <ref id="dsc-trigger" name="trigger">.
Default: 3 * <cf/max ra interval/, <cf/sensitive/ yes. Default: 3 * <cf/max ra interval/, <cf/sensitive/ yes.
<tag>default preference low|medium|high</tag>
This option specifies the Default Router Preference value to advertise
to hosts. Default: medium.
<tag>rdnss local <m/switch/</tag> <tag>rdnss local <m/switch/</tag>
Use only local (interface-specific) RDNSS definitions for this Use only local (interface-specific) RDNSS definitions for this
interface. Otherwise, both global and local definitions are used. Could interface. Otherwise, both global and local definitions are used. Could

View File

@ -25,6 +25,23 @@ static inline u32 pair_b(u32 p) { return p & 0xFFFF; }
* to the last item in a list (right ptr). For convenience, even items * to the last item in a list (right ptr). For convenience, even items
* are handled as one-item lists. Lists are merged by f_merge_items(). * are handled as one-item lists. Lists are merged by f_merge_items().
*/ */
static int
f_valid_set_type(int type)
{
switch (type)
{
case T_INT:
case T_PAIR:
case T_QUAD:
case T_ENUM:
case T_IP:
case T_EC:
return 1;
default:
return 0;
}
}
static inline struct f_tree * static inline struct f_tree *
f_new_item(struct f_val from, struct f_val to) f_new_item(struct f_val from, struct f_val to)
@ -473,10 +490,19 @@ fipa:
*/ */
set_atom: set_atom:
expr { $$.type = T_INT; $$.val.i = $1; } NUM { $$.type = T_INT; $$.val.i = $1; }
| RTRID { $$.type = T_QUAD; $$.val.i = $1; } | RTRID { $$.type = T_QUAD; $$.val.i = $1; }
| fipa { $$ = $1; } | fipa { $$ = $1; }
| ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); } | ENUM { $$.type = pair_a($1); $$.val.i = pair_b($1); }
| '(' term ')' {
$$ = f_eval($2, cfg_mem);
if (!f_valid_set_type($$.type)) cf_error("Set-incompatible type");
}
| SYM {
if (!cf_symbol_is_constant($1)) cf_error("%s: constant expected", $1->name);
if (!f_valid_set_type(SYM_TYPE($1))) cf_error("%s: set-incompatible type", $1->name);
$$ = *(struct f_val *)($1->def);
}
; ;
switch_atom: switch_atom:

View File

@ -493,7 +493,7 @@ f_rta_cow(void)
} }
} }
static struct rate_limit rl_runtime_err; static struct tbf rl_runtime_err = TBF_DEFAULT_LOG_LIMITS;
#define runtime(x) do { \ #define runtime(x) do { \
log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \ log_rl(&rl_runtime_err, L_ERR "filters, line %d: %s", what->lineno, x); \
@ -1492,7 +1492,7 @@ f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struc
if (res.type != T_RETURN) { if (res.type != T_RETURN) {
log( L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name); log_rl(&rl_runtime_err, L_ERR "Filter %s did not return accept nor reject. Make up your mind", filter->name);
return F_ERROR; return F_ERROR;
} }
DBG( "done (%u)\n", res.val.i ); DBG( "done (%u)\n", res.val.i );

View File

@ -13,6 +13,9 @@ define '1a-a1' = (20+10);
define one = 1; define one = 1;
define ten = 10; define ten = 10;
define p23 = (2, 3);
define ip1222 = 1.2.2.2;
function onef(int a) function onef(int a)
{ {
return 1; return 1;
@ -78,7 +81,7 @@ function test_roa()
" ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID; " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID;
} }
function paths() function path_test()
bgpmask pm1; bgpmask pm1;
bgpmask pm2; bgpmask pm2;
bgppath p2; bgppath p2;
@ -98,7 +101,7 @@ eclist el2;
print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20]; print "Should be true: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 3 ~ p2, " ", p2 ~ [2, 10..20], " ", p2 ~ [4, 10..20];
print "4 = ", p2.len; print "4 = ", p2.len;
p2 = prepend( p2, 5 ); p2 = prepend( p2, 5 );
print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, 10..20],; print "Should be false: ", p2 ~ pm1, " ", p2 ~ pm2, " ", 10 ~ p2, " ", p2 ~ [8, ten..(2*ten)];
print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /; print "Should be true: ", p2 ~ / ? 4 3 2 1 /, " ", p2, " ", / ? 4 3 2 1 /;
print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =]; print "Should be true: ", p2 ~ [= * 4 3 * 1 =], " ", p2, " ", [= * 4 3 * 1 =];
print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4); print "Should be true: ", p2 ~ [= (3+2) (2*2) 3 2 1 =], " ", p2 ~ mkpath(5, 4);
@ -124,7 +127,7 @@ eclist el2;
print "Should be always true: ", l ~ [(*,*)]; print "Should be always true: ", l ~ [(*,*)];
l = add( l, (2,one+2) ); l = add( l, (2,one+2) );
print "Community list (1,2) (2,3) ", l; print "Community list (1,2) (2,3) ", l;
print "Should be true: ", (2,3) ~ l, " ", l ~ [(1,*)], " ", l ~ [(2,3)]," ", l ~ [(2,2..3)], " ", l ~ [(1,1..2)], " ", l ~ [(1,1)..(1,2)]; print "Should be true: ", (2,3) ~ l, " ", l ~ [(1,*)], " ", l ~ [p23]," ", l ~ [(2,2..3)], " ", l ~ [(1,1..2)], " ", l ~ [(1,1)..(1,2)];
l = add( l, (2,5) ); l = add( l, (2,5) );
l = add( l, (5,one) ); l = add( l, (5,one) );
l = add( l, (6,one) ); l = add( l, (6,one) );
@ -361,7 +364,7 @@ string st;
if ( b = true ) then print "Testing bool comparison b = true: ", b; if ( b = true ) then print "Testing bool comparison b = true: ", b;
else { print "*** FAIL: TRUE test failed" ; quitbird; } else { print "*** FAIL: TRUE test failed" ; quitbird; }
ips = [ 1.1.1.0 .. 1.1.1.255, 1.2.2.2]; ips = [ 1.1.1.0 .. 1.1.1.255, ip1222];
print "Testing IP sets: "; print "Testing IP sets: ";
print ips; print ips;
print " must be true: ", 1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips; print " must be true: ", 1.1.1.0 ~ ips, ",", 1.1.1.100 ~ ips, ",", 1.2.2.2 ~ ips;
@ -389,7 +392,7 @@ string st;
i = fifteen(); i = fifteen();
print "Testing function calls: 15 = ", i; print "Testing function calls: 15 = ", i;
paths(); path_test();
print "1.2.3.4 = ", onetwo; print "1.2.3.4 = ", onetwo;

View File

@ -1,7 +1,7 @@
H Library functions H Library functions
S ip.c ipv4.c ipv6.c S ip.c ipv4.c ipv6.c
S lists.c S lists.c
S checksum.c bitops.c patmatch.c printf.c xmalloc.c S checksum.c bitops.c patmatch.c printf.c xmalloc.c tbf.c
D resource.sgml D resource.sgml
S resource.c S resource.c
S mempool.c S mempool.c

View File

@ -19,6 +19,7 @@ resource.c
resource.h resource.h
slab.c slab.c
socket.h socket.h
tbf.c
unaligned.h unaligned.h
xmalloc.c xmalloc.c
printf.c printf.c

View File

@ -74,6 +74,38 @@ typedef s64 btime;
#endif #endif
/* Rate limiting */
struct tbf {
bird_clock_t timestamp; /* Last update */
u16 count; /* Available tokens */
u16 burst; /* Max number of tokens */
u16 rate; /* Rate of replenishment */
u16 mark; /* Whether last op was limited */
};
/* Default TBF values for rate limiting log messages */
#define TBF_DEFAULT_LOG_LIMITS { .rate = 1, .burst = 5 }
void tbf_update(struct tbf *f);
static inline int
tbf_limit(struct tbf *f)
{
tbf_update(f);
if (!f->count)
{
f->mark = 1;
return 1;
}
f->count--;
f->mark = 0;
return 0;
}
/* Logging and dying */ /* Logging and dying */
typedef struct buffer { typedef struct buffer {
@ -94,16 +126,10 @@ typedef struct buffer {
#define LOG_BUFFER_SIZE 1024 #define LOG_BUFFER_SIZE 1024
struct rate_limit {
bird_clock_t timestamp;
int count;
};
#define log log_msg #define log log_msg
void log_commit(int class, buffer *buf); void log_commit(int class, buffer *buf);
void log_msg(char *msg, ...); void log_msg(char *msg, ...);
void log_rl(struct rate_limit *rl, char *msg, ...); void log_rl(struct tbf *rl, char *msg, ...);
void die(char *msg, ...) NORET; void die(char *msg, ...) NORET;
void bug(char *msg, ...) NORET; void bug(char *msg, ...) NORET;

View File

@ -123,7 +123,7 @@ static size_t
slab_memsize(resource *r) slab_memsize(resource *r)
{ {
slab *s = (slab *) r; slab *s = (slab *) r;
int cnt = 0; size_t cnt = 0;
struct sl_obj *o; struct sl_obj *o;
WALK_LIST(o, s->objs) WALK_LIST(o, s->objs)
@ -346,7 +346,7 @@ static size_t
slab_memsize(resource *r) slab_memsize(resource *r)
{ {
slab *s = (slab *) r; slab *s = (slab *) r;
int heads = 0; size_t heads = 0;
struct sl_head *h; struct sl_head *h;
WALK_LIST(h, s->empty_heads) WALK_LIST(h, s->empty_heads)

29
lib/tbf.c Normal file
View File

@ -0,0 +1,29 @@
/*
* BIRD Library -- Token Bucket Filter
*
* (c) 2014 Ondrej Zajicek <santiago@crfreenet.org>
* (c) 2014 CZ.NIC z.s.p.o.
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
#include "nest/bird.h"
void
tbf_update(struct tbf *f)
{
bird_clock_t delta = now - f->timestamp;
if (delta == 0)
return;
f->timestamp = now;
if ((0 < delta) && (delta < f->burst))
{
u32 next = f->count + delta * f->rate;
f->count = MIN(next, f->burst);
}
else
f->count = f->burst;
}

View File

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

View File

@ -57,10 +57,10 @@ CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OF
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS) CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES) CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, GENERATE, ROA, MAX, FLUSH, AS) CF_KEYWORDS(PRIMARY, STATS, COUNT, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE, ROA)
CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED) CF_KEYWORDS(LISTEN, BGP, V6ONLY, DUAL, ADDRESS, PORT, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP) CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT) CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT, CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE) RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE)
@ -77,7 +77,7 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
%type <ro> roa_args %type <ro> roa_args
%type <rot> roa_table_arg %type <rot> roa_table_arg
%type <sd> sym_args %type <sd> sym_args
%type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_or_preexport roa_mode limit_action tab_sorted tos %type <i> proto_start echo_mask echo_size debug_mask debug_list debug_flag mrtdump_mask mrtdump_list mrtdump_flag export_mode roa_mode limit_action tab_sorted tos
%type <ps> proto_patt proto_patt2 %type <ps> proto_patt proto_patt2
%type <g> limit_spec %type <g> limit_spec
@ -443,7 +443,7 @@ CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]])
{ if_show_summary(); } ; { if_show_summary(); } ;
CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]]) CF_CLI_HELP(SHOW ROUTE, ..., [[Show routing table]])
CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]]) CF_CLI(SHOW ROUTE, r_args, [[[<prefix>|for <prefix>|for <ip>] [table <t>] [filter <f>|where <cond>] [all] [primary] [filtered] [(export|preexport|noexport) <p>] [protocol <p>] [stats|count]]], [[Show routing table]])
{ rt_show($3); } ; { rt_show($3); } ;
r_args: r_args:
@ -492,7 +492,7 @@ r_args:
$$ = $1; $$ = $1;
$$->filtered = 1; $$->filtered = 1;
} }
| r_args export_or_preexport SYM { | r_args export_mode SYM {
struct proto_config *c = (struct proto_config *) $3->def; struct proto_config *c = (struct proto_config *) $3->def;
$$ = $1; $$ = $1;
if ($$->export_mode) cf_error("Protocol specified twice"); if ($$->export_mode) cf_error("Protocol specified twice");
@ -519,9 +519,10 @@ r_args:
} }
; ;
export_or_preexport: export_mode:
PREEXPORT { $$ = 1; } PREEXPORT { $$ = RSEM_PREEXPORT; }
| EXPORT { $$ = 2; } | EXPORT { $$ = RSEM_EXPORT; }
| NOEXPORT { $$ = RSEM_NOEXPORT; }
; ;

View File

@ -301,6 +301,12 @@ struct rt_show_data {
}; };
void rt_show(struct rt_show_data *); void rt_show(struct rt_show_data *);
/* Value of export_mode in struct rt_show_data */
#define RSEM_NONE 0 /* Export mode not used */
#define RSEM_PREEXPORT 1 /* Routes ready for export, before filtering */
#define RSEM_EXPORT 2 /* Routes accepted by export filter */
#define RSEM_NOEXPORT 3 /* Routes rejected by export filter */
/* /*
* Route Attributes * Route Attributes
* *

View File

@ -815,7 +815,7 @@ rta_alloc_hash(void)
static inline unsigned int static inline unsigned int
rta_hash(rta *a) rta_hash(rta *a)
{ {
return (((unsigned) a->src) ^ ipa_hash(a->gw) ^ return (((uint) (uintptr_t) a->src) ^ ipa_hash(a->gw) ^
mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff; mpnh_hash(a->nexthops) ^ ea_hash(a->eattrs)) & 0xffff;
} }

View File

@ -645,7 +645,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str
struct proto *p = ah->proto; struct proto *p = ah->proto;
struct rtable *table = ah->table; struct rtable *table = ah->table;
struct proto_stats *stats = ah->stats; struct proto_stats *stats = ah->stats;
static struct rate_limit rl_pipe; static struct tbf rl_pipe = TBF_DEFAULT_LOG_LIMITS;
rte *before_old = NULL; rte *before_old = NULL;
rte *old_best = net->routes; rte *old_best = net->routes;
rte *old = NULL; rte *old = NULL;
@ -1367,7 +1367,7 @@ rt_init(void)
static int static int
rt_prune_step(rtable *tab, int step, int *limit) rt_prune_step(rtable *tab, int step, int *limit)
{ {
static struct rate_limit rl_flush; static struct tbf rl_flush = TBF_DEFAULT_LOG_LIMITS;
struct fib_iterator *fit = &tab->prune_fit; struct fib_iterator *fit = &tab->prune_fit;
DBG("Pruning route table %s\n", tab->name); DBG("Pruning route table %s\n", tab->name);
@ -2255,6 +2255,9 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
if (d->export_mode) if (d->export_mode)
{ {
if (! d->export_protocol->rt_notify)
return;
a = proto_find_announce_hook(d->export_protocol, d->table); a = proto_find_announce_hook(d->export_protocol, d->table);
if (!a) if (!a)
return; return;
@ -2287,18 +2290,20 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
if (ic < 0) if (ic < 0)
goto skip; goto skip;
if (d->export_mode > 1) if (d->export_mode > RSEM_PREEXPORT)
{ {
/* /*
* FIXME - This shows what should be exported according to current * FIXME - This shows what should be exported according to current
* filters, but not what was really exported. 'configure soft' * filters, but not what was really exported. 'configure soft'
* command may change the export filter and do not update routes. * command may change the export filter and do not update routes.
*/ */
int do_export = (ic > 0) ||
(f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
if (!ic && (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) if (do_export != (d->export_mode == RSEM_EXPORT))
goto skip; goto skip;
if (ep->accept_ra_types == RA_ACCEPTED) if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED))
pass = 1; pass = 1;
} }
} }

View File

@ -1062,7 +1062,7 @@ bfd_copy_config(struct proto_config *dest, struct proto_config *src)
// struct bfd_config *s = (struct bfd_config *) src; // struct bfd_config *s = (struct bfd_config *) src;
/* We clean up patt_list and neigh_list, neighbors and ifaces are non-sharable */ /* We clean up patt_list and neigh_list, neighbors and ifaces are non-sharable */
init_list(&d->patt_list); init_list(&d->patt_list);
init_list(&d->neigh_list); init_list(&d->neigh_list);
} }
@ -1071,7 +1071,7 @@ bfd_show_sessions(struct proto *P)
{ {
byte tbuf[TM_DATETIME_BUFFER_SIZE]; byte tbuf[TM_DATETIME_BUFFER_SIZE];
struct bfd_proto *p = (struct bfd_proto *) P; struct bfd_proto *p = (struct bfd_proto *) P;
uint state, diag; uint state, diag UNUSED;
u32 tx_int, timeout; u32 tx_int, timeout;
const char *ifname; const char *ifname;

View File

@ -680,8 +680,8 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c
s->type = SK_TCP_ACTIVE; s->type = SK_TCP_ACTIVE;
s->saddr = p->source_addr; s->saddr = p->source_addr;
s->daddr = p->cf->remote_ip; s->daddr = p->cf->remote_ip;
s->dport = p->cf->remote_port;
s->iface = p->neigh ? p->neigh->iface : NULL; s->iface = p->neigh ? p->neigh->iface : NULL;
s->dport = BGP_PORT;
s->ttl = p->cf->ttl_security ? 255 : hops; s->ttl = p->cf->ttl_security ? 255 : hops;
s->rbsize = BGP_RX_BUFFER_SIZE; s->rbsize = BGP_RX_BUFFER_SIZE;
s->tbsize = BGP_TX_BUFFER_SIZE; s->tbsize = BGP_TX_BUFFER_SIZE;
@ -1016,9 +1016,9 @@ bgp_start(struct proto *P)
lock = p->lock = olock_new(P->pool); lock = p->lock = olock_new(P->pool);
lock->addr = p->cf->remote_ip; lock->addr = p->cf->remote_ip;
lock->port = p->cf->remote_port;
lock->iface = p->cf->iface; lock->iface = p->cf->iface;
lock->type = OBJLOCK_TCP; lock->type = OBJLOCK_TCP;
lock->port = BGP_PORT;
lock->hook = bgp_start_locked; lock->hook = bgp_start_locked;
lock->data = p; lock->data = p;
olock_acquire(lock); olock_acquire(lock);

View File

@ -23,6 +23,7 @@ struct bgp_config {
ip_addr remote_ip; ip_addr remote_ip;
ip_addr source_addr; /* Source address to use */ ip_addr source_addr; /* Source address to use */
struct iface *iface; /* Interface for link-local addresses */ struct iface *iface; /* Interface for link-local addresses */
u16 remote_port; /* Neighbor destination port */
int multihop; /* Number of hops if multihop */ int multihop; /* Number of hops if multihop */
int ttl_security; /* Enable TTL security [RFC5082] */ int ttl_security; /* Enable TTL security [RFC5082] */
int next_hop_self; /* Always set next hop to local IP address */ int next_hop_self; /* Always set next hop to local IP address */

View File

@ -60,7 +60,7 @@ bgp_proto:
| bgp_proto proto_item ';' | bgp_proto proto_item ';'
| bgp_proto LOCAL AS expr ';' { BGP_CFG->local_as = $4; } | bgp_proto LOCAL AS expr ';' { BGP_CFG->local_as = $4; }
| bgp_proto LOCAL ipa AS expr ';' { BGP_CFG->source_addr = $3; BGP_CFG->local_as = $5; } | bgp_proto LOCAL ipa AS expr ';' { BGP_CFG->source_addr = $3; BGP_CFG->local_as = $5; }
| bgp_proto NEIGHBOR ipa ipa_scope AS expr ';' { | bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' {
if (ipa_nonzero(BGP_CFG->remote_ip)) if (ipa_nonzero(BGP_CFG->remote_ip))
cf_error("Only one neighbor per BGP instance is allowed"); cf_error("Only one neighbor per BGP instance is allowed");
if (!ipa_has_link_scope($3) != !$4) if (!ipa_has_link_scope($3) != !$4)
@ -68,7 +68,8 @@ bgp_proto:
BGP_CFG->remote_ip = $3; BGP_CFG->remote_ip = $3;
BGP_CFG->iface = $4; BGP_CFG->iface = $4;
BGP_CFG->remote_as = $6; BGP_CFG->remote_port = ($5 > 0) ? $5 : BGP_PORT;
BGP_CFG->remote_as = $7;
} }
| bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; } | bgp_proto RR CLUSTER ID idval ';' { BGP_CFG->rr_cluster_id = $5; }
| bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; } | bgp_proto RR CLIENT ';' { BGP_CFG->rr_client = 1; }

View File

@ -22,7 +22,8 @@
#include "bgp.h" #include "bgp.h"
static struct rate_limit rl_rcv_update, rl_snd_update; static struct tbf rl_rcv_update = TBF_DEFAULT_LOG_LIMITS;
static struct tbf rl_snd_update = TBF_DEFAULT_LOG_LIMITS;
/* Table for state -> RFC 6608 FSM error subcodes */ /* Table for state -> RFC 6608 FSM error subcodes */
static byte fsm_err_subcode[BS_MAX] = { static byte fsm_err_subcode[BS_MAX] = {

View File

@ -30,9 +30,9 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS, MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS,
TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
LOCAL, TRIGGER, SENSITIVE) LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH)
%type<i> radv_mult radv_sensitive %type<i> radv_mult radv_sensitive radv_preference
CF_GRAMMAR CF_GRAMMAR
@ -84,6 +84,7 @@ radv_iface_start:
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT; RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
RADV_IFACE->default_lifetime = -1; RADV_IFACE->default_lifetime = -1;
RADV_IFACE->default_lifetime_sensitive = 1; RADV_IFACE->default_lifetime_sensitive = 1;
RADV_IFACE->default_preference = RA_PREF_MEDIUM;
}; };
radv_iface_item: radv_iface_item:
@ -101,6 +102,7 @@ radv_iface_item:
if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000");
if ($4 != -1) RADV_IFACE->default_lifetime_sensitive = $4; if ($4 != -1) RADV_IFACE->default_lifetime_sensitive = $4;
} }
| DEFAULT PREFERENCE radv_preference { RADV_IFACE->default_preference = $3; }
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); } | PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); } | RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); } | DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
@ -108,6 +110,11 @@ radv_iface_item:
| DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; } | DNSSL LOCAL bool { RADV_IFACE->dnssl_local = $3; }
; ;
radv_preference:
LOW { $$ = RA_PREF_LOW; }
| MEDIUM { $$ = RA_PREF_MEDIUM; }
| HIGH { $$ = RA_PREF_HIGH; }
radv_iface_finish: radv_iface_finish:
{ {
struct radv_iface_config *ic = RADV_IFACE; struct radv_iface_config *ic = RADV_IFACE;

View File

@ -251,10 +251,11 @@ radv_prepare_ra(struct radv_iface *ifa)
pkt->code = 0; pkt->code = 0;
pkt->checksum = 0; pkt->checksum = 0;
pkt->current_hop_limit = ic->current_hop_limit; pkt->current_hop_limit = ic->current_hop_limit;
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
(ic->other_config ? OPT_RA_OTHER_CFG : 0);
pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ? pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ?
htons(ic->default_lifetime) : 0; htons(ic->default_lifetime) : 0;
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
(ic->other_config ? OPT_RA_OTHER_CFG : 0) |
(pkt->router_lifetime ? ic->default_preference : 0);
pkt->reachable_time = htonl(ic->reachable_time); pkt->reachable_time = htonl(ic->reachable_time);
pkt->retrans_timer = htonl(ic->retrans_timer); pkt->retrans_timer = htonl(ic->retrans_timer);
buf += sizeof(*pkt); buf += sizeof(*pkt);
@ -330,10 +331,15 @@ radv_send_ra(struct radv_iface *ifa, int shutdown)
if (shutdown) if (shutdown)
{ {
/* Modify router lifetime to 0, it is not restored because /*
we suppose that the iface will be removed */ * Modify router lifetime to 0, it is not restored because we suppose that
* the iface will be removed. The preference value also has to be zeroed.
* (RFC 4191 2.2: If router lifetime is 0, the preference value must be 0.)
*/
struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf; struct radv_ra_packet *pkt = (void *) ifa->sk->tbuf;
pkt->router_lifetime = 0; pkt->router_lifetime = 0;
pkt->flags &= ~RA_PREF_MASK;
} }
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);

View File

@ -40,6 +40,7 @@
* Supported standards: * Supported standards:
* - RFC 4861 - main RA standard * - RFC 4861 - main RA standard
* - RFC 6106 - DNS extensions (RDDNS, DNSSL) * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
* - RFC 4191 (partial) - Default Router Preference
*/ */
static void static void

View File

@ -80,6 +80,7 @@ struct radv_iface_config
u32 current_hop_limit; u32 current_hop_limit;
u32 default_lifetime; u32 default_lifetime;
u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */ u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
u8 default_preference; /* Default Router Preference (RFC 4191) */
}; };
struct radv_prefix_config struct radv_prefix_config
@ -144,6 +145,11 @@ struct radv_iface
#define RA_EV_CHANGE 2 /* Change of options or prefixes */ #define RA_EV_CHANGE 2 /* Change of options or prefixes */
#define RA_EV_RS 3 /* Received RS */ #define RA_EV_RS 3 /* Received RS */
/* Default Router Preferences (RFC 4191) */
#define RA_PREF_LOW 0x18
#define RA_PREF_MEDIUM 0x00
#define RA_PREF_HIGH 0x08
#define RA_PREF_MASK 0x18
#ifdef LOCAL_DEBUG #ifdef LOCAL_DEBUG

View File

@ -261,6 +261,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
msg.rtm.rtm_flags |= RTF_GATEWAY; msg.rtm.rtm_flags |= RTF_GATEWAY;
msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_addrs |= RTA_GATEWAY;
break; break;
#ifdef RTF_REJECT #ifdef RTF_REJECT
case RTD_UNREACHABLE: case RTD_UNREACHABLE:
#endif #endif
@ -280,7 +281,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
return -1; return -1;
} }
sockaddr_fill(&dst, BIRD_AF, i->addr->ip, NULL, 0); sockaddr_fill(&gate, BIRD_AF, i->addr->ip, NULL, 0);
msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_addrs |= RTA_GATEWAY;
} }
break; break;

View File

@ -141,6 +141,7 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
#ifdef IP_SENDSRCADDR #ifdef IP_SENDSRCADDR
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_addr *sa; struct in_addr *sa;
int controllen = 0;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
@ -149,11 +150,12 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
cm->cmsg_level = IPPROTO_IP; cm->cmsg_level = IPPROTO_IP;
cm->cmsg_type = IP_SENDSRCADDR; cm->cmsg_type = IP_SENDSRCADDR;
cm->cmsg_len = CMSG_LEN(sizeof(*sa)); cm->cmsg_len = CMSG_LEN(sizeof(*sa));
controllen += CMSG_SPACE(sizeof(*sa));
sa = (struct in_addr *) CMSG_DATA(cm); sa = (struct in_addr *) CMSG_DATA(cm);
*sa = ipa_to_in4(s->saddr); *sa = ipa_to_in4(s->saddr);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = controllen;
#endif #endif
} }

View File

@ -7,7 +7,7 @@
#define _BIRD_CONFIG_H_ #define _BIRD_CONFIG_H_
/* BIRD version */ /* BIRD version */
#define BIRD_VERSION "1.4.3" #define BIRD_VERSION "1.4.5"
/* Include parameters determined by configure script */ /* Include parameters determined by configure script */
#include "sysdep/autoconf.h" #include "sysdep/autoconf.h"

View File

@ -151,7 +151,7 @@ nl_get_reply(struct nl_sock *nl)
} }
} }
static struct rate_limit rl_netlink_err; static struct tbf rl_netlink_err = TBF_DEFAULT_LOG_LIMITS;
static int static int
nl_error(struct nlmsghdr *h) nl_error(struct nlmsghdr *h)

View File

@ -154,6 +154,7 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in_pktinfo *pi; struct in_pktinfo *pi;
int controllen = 0;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
@ -162,13 +163,14 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
cm->cmsg_level = SOL_IP; cm->cmsg_level = SOL_IP;
cm->cmsg_type = IP_PKTINFO; cm->cmsg_type = IP_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(*pi)); cm->cmsg_len = CMSG_LEN(sizeof(*pi));
controllen += CMSG_SPACE(sizeof(*pi));
pi = (struct in_pktinfo *) CMSG_DATA(cm); pi = (struct in_pktinfo *) CMSG_DATA(cm);
pi->ipi_ifindex = s->iface ? s->iface->index : 0; pi->ipi_ifindex = s->iface ? s->iface->index : 0;
pi->ipi_spec_dst = ipa_to_in4(s->saddr); pi->ipi_spec_dst = ipa_to_in4(s->saddr);
pi->ipi_addr = ipa_to_in4(IPA_NONE); pi->ipi_addr = ipa_to_in4(IPA_NONE);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = controllen;
} }

View File

@ -705,6 +705,7 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
{ {
struct cmsghdr *cm; struct cmsghdr *cm;
struct in6_pktinfo *pi; struct in6_pktinfo *pi;
int controllen = 0;
msg->msg_control = cbuf; msg->msg_control = cbuf;
msg->msg_controllen = cbuflen; msg->msg_controllen = cbuflen;
@ -713,12 +714,13 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
cm->cmsg_level = SOL_IPV6; cm->cmsg_level = SOL_IPV6;
cm->cmsg_type = IPV6_PKTINFO; cm->cmsg_type = IPV6_PKTINFO;
cm->cmsg_len = CMSG_LEN(sizeof(*pi)); cm->cmsg_len = CMSG_LEN(sizeof(*pi));
controllen += CMSG_SPACE(sizeof(*pi));
pi = (struct in6_pktinfo *) CMSG_DATA(cm); pi = (struct in6_pktinfo *) CMSG_DATA(cm);
pi->ipi6_ifindex = s->iface ? s->iface->index : 0; pi->ipi6_ifindex = s->iface ? s->iface->index : 0;
pi->ipi6_addr = ipa_to_in6(s->saddr); pi->ipi6_addr = ipa_to_in6(s->saddr);
msg->msg_controllen = cm->cmsg_len; msg->msg_controllen = controllen;
} }
@ -1965,7 +1967,7 @@ io_loop(void)
while (current_sock && count < MAX_RX_STEPS) while (current_sock && count < MAX_RX_STEPS)
{ {
sock *s = current_sock; sock *s = current_sock;
int e; int e UNUSED;
if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook)
{ {

View File

@ -36,7 +36,7 @@
* only once for all the instances. * only once for all the instances.
* *
* The code uses OS-dependent parts for kernel updates and scans. These parts are * The code uses OS-dependent parts for kernel updates and scans. These parts are
* in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_* * in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
* and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file. * and kif_sys_* (and some others like krt_replace_rte()) and krt-sys.h header file.
* This is also used for platform specific protocol options and route attributes. * This is also used for platform specific protocol options and route attributes.
* *
@ -117,7 +117,7 @@ kif_request_scan(void)
static inline int static inline int
prefer_addr(struct ifa *a, struct ifa *b) prefer_addr(struct ifa *a, struct ifa *b)
{ {
int sa = a->scope > SCOPE_LINK; int sa = a->scope > SCOPE_LINK;
int sb = b->scope > SCOPE_LINK; int sb = b->scope > SCOPE_LINK;
@ -300,10 +300,10 @@ krt_trace_in(struct krt_proto *p, rte *e, char *msg)
} }
static inline void static inline void
krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg) krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
{ {
if (p->p.debug & D_PACKETS) if (p->p.debug & D_PACKETS)
log_rl(rl, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg); log_rl(f, L_TRACE "%s: %I/%d: %s", p->p.name, e->net->n.prefix, e->net->n.pxlen, msg);
} }
/* /*
@ -312,7 +312,7 @@ krt_trace_in_rl(struct rate_limit *rl, struct krt_proto *p, rte *e, char *msg)
#ifdef KRT_ALLOW_LEARN #ifdef KRT_ALLOW_LEARN
static struct rate_limit rl_alien_seen, rl_alien_updated, rl_alien_created, rl_alien_ignored; static struct tbf rl_alien = TBF_DEFAULT_LOG_LIMITS;
/* /*
* krt_same_key() specifies what (aside from the net) is the key in * krt_same_key() specifies what (aside from the net) is the key in
@ -378,20 +378,20 @@ krt_learn_scan(struct krt_proto *p, rte *e)
{ {
if (krt_uptodate(m, e)) if (krt_uptodate(m, e))
{ {
krt_trace_in_rl(&rl_alien_seen, p, e, "[alien] seen"); krt_trace_in_rl(&rl_alien, p, e, "[alien] seen");
rte_free(e); rte_free(e);
m->u.krt.seen = 1; m->u.krt.seen = 1;
} }
else else
{ {
krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated"); krt_trace_in(p, e, "[alien] updated");
*mm = m->next; *mm = m->next;
rte_free(m); rte_free(m);
m = NULL; m = NULL;
} }
} }
else else
krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created"); krt_trace_in(p, e, "[alien] created");
if (!m) if (!m)
{ {
e->next = n->routes; e->next = n->routes;
@ -637,7 +637,7 @@ krt_got_route(struct krt_proto *p, rte *e)
krt_learn_scan(p, e); krt_learn_scan(p, e);
else else
{ {
krt_trace_in_rl(&rl_alien_ignored, p, e, "[alien] ignored"); krt_trace_in_rl(&rl_alien, p, e, "[alien] ignored");
rte_free(e); rte_free(e);
} }
return; return;
@ -737,7 +737,7 @@ krt_prune(struct krt_proto *p)
if (! krt_export_rte(p, &new, &tmpa)) if (! krt_export_rte(p, &new, &tmpa))
{ {
/* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */ /* Route rejected, should not happen (KRF_INSTALLED) but to be sure .. */
verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE; verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
} }
else else
{ {
@ -910,7 +910,7 @@ krt_scan_timer_stop(struct krt_proto *p)
} }
static void static void
krt_scan_timer_kick(struct krt_proto *p UNUSED) krt_scan_timer_kick(struct krt_proto *p)
{ {
tm_start(p->scan_timer, 0); tm_start(p->scan_timer, 0);
} }
@ -962,8 +962,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
if (e->attrs->src->proto == P) if (e->attrs->src->proto == P)
return -1; return -1;
if (!KRT_CF->devroutes && if (!KRT_CF->devroutes &&
(e->attrs->dest == RTD_DEVICE) && (e->attrs->dest == RTD_DEVICE) &&
(e->attrs->source != RTS_STATIC_DEVICE)) (e->attrs->source != RTS_STATIC_DEVICE))
return -1; return -1;
@ -974,8 +974,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
} }
static void static void
krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
rte *new, rte *old, struct ea_list *eattrs) rte *new, rte *old, struct ea_list *eattrs)
{ {
struct krt_proto *p = (struct krt_proto *) P; struct krt_proto *p = (struct krt_proto *) P;
@ -991,6 +991,36 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net,
krt_replace_rte(p, net, new, old, eattrs); krt_replace_rte(p, net, new, old, eattrs);
} }
static void
krt_if_notify(struct proto *P, uint flags, struct iface *iface UNUSED)
{
struct krt_proto *p = (struct krt_proto *) P;
/*
* When interface went down, we should remove routes to it. In the ideal world,
* OS kernel would send us route removal notifications in such cases, but we
* cannot rely on it as it is often not true. E.g. Linux kernel removes related
* routes when an interface went down, but it does not notify userspace about
* that. To be sure, we just schedule a scan to ensure synchronization.
*/
if ((flags & IF_CHANGE_DOWN) && KRT_CF->learn)
krt_scan_timer_kick(p);
}
static int
krt_reload_routes(struct proto *P)
{
struct krt_proto *p = (struct krt_proto *) P;
/* Although we keep learned routes in krt_table, we rather schedule a scan */
if (KRT_CF->learn)
krt_scan_timer_kick(p);
return 1;
}
static void static void
krt_feed_done(struct proto *P) krt_feed_done(struct proto *P)
{ {
@ -1022,7 +1052,9 @@ krt_init(struct proto_config *c)
p->p.accept_ra_types = RA_OPTIMAL; p->p.accept_ra_types = RA_OPTIMAL;
p->p.import_control = krt_import_control; p->p.import_control = krt_import_control;
p->p.rt_notify = krt_notify; p->p.rt_notify = krt_rt_notify;
p->p.if_notify = krt_if_notify;
p->p.reload_routes = krt_reload_routes;
p->p.feed_done = krt_feed_done; p->p.feed_done = krt_feed_done;
p->p.make_tmp_attrs = krt_make_tmp_attrs; p->p.make_tmp_attrs = krt_make_tmp_attrs;
p->p.store_tmp_attrs = krt_store_tmp_attrs; p->p.store_tmp_attrs = krt_store_tmp_attrs;

View File

@ -32,9 +32,6 @@ static FILE *dbgf;
static list *current_log_list; static list *current_log_list;
static char *current_syslog_name; /* NULL -> syslog closed */ static char *current_syslog_name; /* NULL -> syslog closed */
static const bird_clock_t rate_limit_time = 5;
static const int rate_limit_count = 5;
#ifdef USE_PTHREADS #ifdef USE_PTHREADS
@ -154,7 +151,6 @@ vlog(int class, const char *msg, va_list args)
} }
/** /**
* log - log a message * log - log a message
* @msg: printf-like formatting string with message class information * @msg: printf-like formatting string with message class information
@ -180,31 +176,21 @@ log_msg(char *msg, ...)
} }
void void
log_rl(struct rate_limit *rl, char *msg, ...) log_rl(struct tbf *f, char *msg, ...)
{ {
int last_hit = f->mark;
int class = 1; int class = 1;
va_list args; va_list args;
bird_clock_t delta = now - rl->timestamp; /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */
if ((0 <= delta) && (delta < rate_limit_time)) if (tbf_limit(f) && last_hit)
{
rl->count++;
}
else
{
rl->timestamp = now;
rl->count = 1;
}
if (rl->count > rate_limit_count)
return; return;
va_start(args, msg);
if (*msg >= 1 && *msg <= 8) if (*msg >= 1 && *msg <= 8)
class = *msg++; class = *msg++;
vlog(class, msg, args);
if (rl->count == rate_limit_count) va_start(args, msg);
vlog(class, "...", args); vlog(class, (f->mark ? "..." : msg), args);
va_end(args); va_end(args);
} }