diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2014-10-14 17:23:34 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2014-10-14 17:23:34 +0200 |
commit | 78342404ff573e85e396f0611014b90cea9b4c0a (patch) | |
tree | 39fd70db506dc05d83528b7afab258b07b8ac482 | |
parent | 178a197afb77770d8a90765e39065679936a45d1 (diff) | |
parent | cfdea7b85f6c520cc5a62eb907d2190db14c9900 (diff) |
Merge remote-tracking branch 'origin/master' into soft-int
-rw-r--r-- | NEWS | 16 | ||||
-rw-r--r-- | conf/cf-lex.l | 2 | ||||
-rw-r--r-- | conf/conf.h | 4 | ||||
-rw-r--r-- | conf/confbase.Y | 12 | ||||
-rw-r--r-- | doc/bird.sgml | 24 | ||||
-rw-r--r-- | filter/config.Y | 28 | ||||
-rw-r--r-- | filter/filter.c | 4 | ||||
-rw-r--r-- | filter/test.conf | 13 | ||||
-rw-r--r-- | lib/Doc | 2 | ||||
-rw-r--r-- | lib/Modules | 1 | ||||
-rw-r--r-- | lib/birdlib.h | 40 | ||||
-rw-r--r-- | lib/slab.c | 4 | ||||
-rw-r--r-- | lib/tbf.c | 29 | ||||
-rw-r--r-- | misc/bird.spec | 2 | ||||
-rw-r--r-- | nest/config.Y | 17 | ||||
-rw-r--r-- | nest/route.h | 6 | ||||
-rw-r--r-- | nest/rt-attr.c | 2 | ||||
-rw-r--r-- | nest/rt-table.c | 15 | ||||
-rw-r--r-- | proto/bfd/bfd.c | 4 | ||||
-rw-r--r-- | proto/bgp/bgp.c | 4 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 1 | ||||
-rw-r--r-- | proto/bgp/config.Y | 5 | ||||
-rw-r--r-- | proto/bgp/packets.c | 3 | ||||
-rw-r--r-- | proto/radv/config.Y | 11 | ||||
-rw-r--r-- | proto/radv/packets.c | 14 | ||||
-rw-r--r-- | proto/radv/radv.c | 1 | ||||
-rw-r--r-- | proto/radv/radv.h | 6 | ||||
-rw-r--r-- | sysdep/bsd/krt-sock.c | 3 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 4 | ||||
-rw-r--r-- | sysdep/config.h | 2 | ||||
-rw-r--r-- | sysdep/linux/netlink.c | 2 | ||||
-rw-r--r-- | sysdep/linux/sysio.h | 4 | ||||
-rw-r--r-- | sysdep/unix/io.c | 6 | ||||
-rw-r--r-- | sysdep/unix/krt.c | 64 | ||||
-rw-r--r-- | sysdep/unix/log.c | 28 |
35 files changed, 281 insertions, 102 deletions
@@ -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) 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. - Last state change now tracks just protocol state change. - Minor changes to default router ID calculation. - + Version 1.3.11 (2013-07-27) o OSPF stub router option (RFC 3137). o TTL security for OSPF and RIP. diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 99785057..35b590bb 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -646,7 +646,7 @@ cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos) char * cf_symbol_class_name(struct symbol *sym) { - if ((sym->class & 0xff00) == SYM_CONSTANT) + if (cf_symbol_is_constant(sym)) return "constant"; switch (sym->class) diff --git a/conf/conf.h b/conf/conf.h index fa14d7b5..799873d2 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -149,6 +149,10 @@ void cf_pop_scope(void); struct symbol *cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos); 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 */ int cf_parse(void); diff --git a/conf/confbase.Y b/conf/confbase.Y index cba6fc56..49831b1a 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -72,7 +72,7 @@ CF_DECLS %token <t> TEXT %type <iface> ipa_scope -%type <i> expr bool pxlen +%type <i> expr bool pxlen ipa_port %type <i32> expr_us %type <time> datetime %type <a> ipa @@ -88,7 +88,7 @@ CF_DECLS %left '!' %nonassoc '.' -CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US) +CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT) CF_GRAMMAR @@ -161,6 +161,14 @@ ipa_scope: | '%' 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: ipa pxlen { if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix"); diff --git a/doc/bird.sgml b/doc/bird.sgml index 46900227..10a09025 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -318,7 +318,7 @@ protocol rip { <p><descrip> <tag>include "<m/filename/"</tag> 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. <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 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 table attached to a respective protocol), that is routes, their metrics 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 a given filter (<cf>filter <m/name/</cf> or <cf>filter { <m/filter/ } </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 - export filter of the protocol is skipped. + + The <cf/export/, <cf/preexport/ and <cf/noexport/ switches ask for + 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. <cf>protocol <m/p/</cf>. @@ -1004,7 +1009,6 @@ foot). So <cf>1.2.0.0/16.pxlen = 16</cf> is true. <tag/ec/ - This is a specialized type used to represent BGP extended community values. It is essentially a 64bit value, literals of this type are 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 for <cf/key/ and <cf/value/ parts, (e.g. <cf/(ro, myas, 3*10)/, where <cf/myas/ is an integer variable). - + <tag/int|pair|quad|ip|prefix|ec|enum set/ 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 @@ -1616,7 +1620,7 @@ using the following configuration parameters: address, equivalent to the <cf/source address/ option (see below). This 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 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. @@ -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">. 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> Use only local (interface-specific) RDNSS definitions for this interface. Otherwise, both global and local definitions are used. Could diff --git a/filter/config.Y b/filter/config.Y index 04acfbab..e50e75ca 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -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 * 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 * f_new_item(struct f_val from, struct f_val to) @@ -473,10 +490,19 @@ fipa: */ set_atom: - expr { $$.type = T_INT; $$.val.i = $1; } + NUM { $$.type = T_INT; $$.val.i = $1; } | RTRID { $$.type = T_QUAD; $$.val.i = $1; } | fipa { $$ = $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: diff --git a/filter/filter.c b/filter/filter.c index 88763302..63c2cd86 100644 --- a/filter/filter.c +++ b/filter/filter.c @@ -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 { \ 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) { - 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; } DBG( "done (%u)\n", res.val.i ); diff --git a/filter/test.conf b/filter/test.conf index ae8a95a6..a99d0a51 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -13,6 +13,9 @@ define '1a-a1' = (20+10); define one = 1; define ten = 10; +define p23 = (2, 3); +define ip1222 = 1.2.2.2; + function onef(int a) { return 1; @@ -78,7 +81,7 @@ function test_roa() " ", roa_check(rl, 10.130.130.0/24, 3000) = ROA_VALID; } -function paths() +function path_test() bgpmask pm1; bgpmask pm2; 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 "4 = ", p2.len; 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 * 1 =], " ", p2, " ", [= * 4 3 * 1 =]; 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 ~ [(*,*)]; l = add( l, (2,one+2) ); 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, (5,one) ); l = add( l, (6,one) ); @@ -361,7 +364,7 @@ string st; if ( b = true ) then print "Testing bool comparison b = true: ", b; 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 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(); print "Testing function calls: 15 = ", i; - paths(); + path_test(); print "1.2.3.4 = ", onetwo; @@ -1,7 +1,7 @@ H Library functions S ip.c ipv4.c ipv6.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 S resource.c S mempool.c diff --git a/lib/Modules b/lib/Modules index c585c9a8..7131f0b2 100644 --- a/lib/Modules +++ b/lib/Modules @@ -19,6 +19,7 @@ resource.c resource.h slab.c socket.h +tbf.c unaligned.h xmalloc.c printf.c diff --git a/lib/birdlib.h b/lib/birdlib.h index c49c5b99..84a6c1b4 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -74,6 +74,38 @@ typedef s64 btime; #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 */ typedef struct buffer { @@ -94,16 +126,10 @@ typedef struct buffer { #define LOG_BUFFER_SIZE 1024 - -struct rate_limit { - bird_clock_t timestamp; - int count; -}; - #define log log_msg void log_commit(int class, buffer *buf); 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 bug(char *msg, ...) NORET; @@ -123,7 +123,7 @@ static size_t slab_memsize(resource *r) { slab *s = (slab *) r; - int cnt = 0; + size_t cnt = 0; struct sl_obj *o; WALK_LIST(o, s->objs) @@ -346,7 +346,7 @@ static size_t slab_memsize(resource *r) { slab *s = (slab *) r; - int heads = 0; + size_t heads = 0; struct sl_head *h; WALK_LIST(h, s->empty_heads) diff --git a/lib/tbf.c b/lib/tbf.c new file mode 100644 index 00000000..39e18e57 --- /dev/null +++ b/lib/tbf.c @@ -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; +} diff --git a/misc/bird.spec b/misc/bird.spec index 0c730982..30601a91 100644 --- a/misc/bird.spec +++ b/misc/bird.spec @@ -1,6 +1,6 @@ Summary: BIRD Internet Routing Daemon Name: bird -Version: 1.4.3 +Version: 1.4.5 Release: 1 Copyright: GPL Group: Networking/Daemons diff --git a/nest/config.Y b/nest/config.Y index eef7422c..59a776bf 100644 --- a/nest/config.Y +++ b/nest/config.Y @@ -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(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED) 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(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, 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 <rot> roa_table_arg %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 <g> limit_spec @@ -443,7 +443,7 @@ CF_CLI(SHOW INTERFACES SUMMARY,,, [[Show summary of network interfaces]]) { if_show_summary(); } ; 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); } ; r_args: @@ -492,7 +492,7 @@ r_args: $$ = $1; $$->filtered = 1; } - | r_args export_or_preexport SYM { + | r_args export_mode SYM { struct proto_config *c = (struct proto_config *) $3->def; $$ = $1; if ($$->export_mode) cf_error("Protocol specified twice"); @@ -519,9 +519,10 @@ r_args: } ; -export_or_preexport: - PREEXPORT { $$ = 1; } - | EXPORT { $$ = 2; } +export_mode: + PREEXPORT { $$ = RSEM_PREEXPORT; } + | EXPORT { $$ = RSEM_EXPORT; } + | NOEXPORT { $$ = RSEM_NOEXPORT; } ; diff --git a/nest/route.h b/nest/route.h index 82d9e202..5ee04a30 100644 --- a/nest/route.h +++ b/nest/route.h @@ -301,6 +301,12 @@ 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 * diff --git a/nest/rt-attr.c b/nest/rt-attr.c index 97a1bc27..09691bf1 100644 --- a/nest/rt-attr.c +++ b/nest/rt-attr.c @@ -815,7 +815,7 @@ rta_alloc_hash(void) static inline unsigned int 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; } diff --git a/nest/rt-table.c b/nest/rt-table.c index 4c889d0d..59fd0711 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -645,7 +645,7 @@ rte_recalculate(struct announce_hook *ah, net *net, rte *new, ea_list *tmpa, str struct proto *p = ah->proto; struct rtable *table = ah->table; 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 *old_best = net->routes; rte *old = NULL; @@ -1367,7 +1367,7 @@ rt_init(void) static int 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; 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_protocol->rt_notify) + return; + a = proto_find_announce_hook(d->export_protocol, d->table); if (!a) return; @@ -2287,18 +2290,20 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (ic < 0) goto skip; - if (d->export_mode > 1) + if (d->export_mode > RSEM_PREEXPORT) { /* * FIXME - This shows what should be exported according to current * filters, but not what was really exported. 'configure soft' * 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; - if (ep->accept_ra_types == RA_ACCEPTED) + if ((d->export_mode == RSEM_EXPORT) && (ep->accept_ra_types == RA_ACCEPTED)) pass = 1; } } diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c index 7bbe8c21..23e04e40 100644 --- a/proto/bfd/bfd.c +++ b/proto/bfd/bfd.c @@ -1062,7 +1062,7 @@ bfd_copy_config(struct proto_config *dest, struct proto_config *src) // struct bfd_config *s = (struct bfd_config *) src; /* 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); } @@ -1071,7 +1071,7 @@ bfd_show_sessions(struct proto *P) { byte tbuf[TM_DATETIME_BUFFER_SIZE]; struct bfd_proto *p = (struct bfd_proto *) P; - uint state, diag; + uint state, diag UNUSED; u32 tx_int, timeout; const char *ifname; diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index b6239971..e2339112 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -680,8 +680,8 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c s->type = SK_TCP_ACTIVE; s->saddr = p->source_addr; s->daddr = p->cf->remote_ip; + s->dport = p->cf->remote_port; s->iface = p->neigh ? p->neigh->iface : NULL; - s->dport = BGP_PORT; s->ttl = p->cf->ttl_security ? 255 : hops; s->rbsize = BGP_RX_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->addr = p->cf->remote_ip; + lock->port = p->cf->remote_port; lock->iface = p->cf->iface; lock->type = OBJLOCK_TCP; - lock->port = BGP_PORT; lock->hook = bgp_start_locked; lock->data = p; olock_acquire(lock); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index da0114c2..0fd3a73c 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -23,6 +23,7 @@ struct bgp_config { ip_addr remote_ip; ip_addr source_addr; /* Source address to use */ struct iface *iface; /* Interface for link-local addresses */ + u16 remote_port; /* Neighbor destination port */ int multihop; /* Number of hops if multihop */ int ttl_security; /* Enable TTL security [RFC5082] */ int next_hop_self; /* Always set next hop to local IP address */ diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y index 4d085d42..8e0b2412 100644 --- a/proto/bgp/config.Y +++ b/proto/bgp/config.Y @@ -60,7 +60,7 @@ bgp_proto: | bgp_proto proto_item ';' | 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 NEIGHBOR ipa ipa_scope AS expr ';' { + | bgp_proto NEIGHBOR ipa ipa_scope ipa_port AS expr ';' { if (ipa_nonzero(BGP_CFG->remote_ip)) cf_error("Only one neighbor per BGP instance is allowed"); if (!ipa_has_link_scope($3) != !$4) @@ -68,7 +68,8 @@ bgp_proto: BGP_CFG->remote_ip = $3; 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 CLIENT ';' { BGP_CFG->rr_client = 1; } diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 4464523d..0b9de8c1 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -22,7 +22,8 @@ #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 */ static byte fsm_err_subcode[BS_MAX] = { diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 88a9e298..a26ea88e 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -30,9 +30,9 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, 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 @@ -84,6 +84,7 @@ radv_iface_start: RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT; RADV_IFACE->default_lifetime = -1; RADV_IFACE->default_lifetime_sensitive = 1; + RADV_IFACE->default_preference = RA_PREF_MEDIUM; }; 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 ($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); } | 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); } @@ -108,6 +110,11 @@ radv_iface_item: | 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: { struct radv_iface_config *ic = RADV_IFACE; diff --git a/proto/radv/packets.c b/proto/radv/packets.c index 1d7e04f4..ef869722 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -251,10 +251,11 @@ radv_prepare_ra(struct radv_iface *ifa) pkt->code = 0; pkt->checksum = 0; 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) ? 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->retrans_timer = htonl(ic->retrans_timer); buf += sizeof(*pkt); @@ -330,10 +331,15 @@ radv_send_ra(struct radv_iface *ifa, int 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; pkt->router_lifetime = 0; + pkt->flags &= ~RA_PREF_MASK; } RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 90408536..6be7cd84 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -40,6 +40,7 @@ * Supported standards: * - RFC 4861 - main RA standard * - RFC 6106 - DNS extensions (RDDNS, DNSSL) + * - RFC 4191 (partial) - Default Router Preference */ static void diff --git a/proto/radv/radv.h b/proto/radv/radv.h index f80e4530..bb80d65f 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -80,6 +80,7 @@ struct radv_iface_config u32 current_hop_limit; u32 default_lifetime; u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */ + u8 default_preference; /* Default Router Preference (RFC 4191) */ }; struct radv_prefix_config @@ -144,6 +145,11 @@ struct radv_iface #define RA_EV_CHANGE 2 /* Change of options or prefixes */ #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 diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 26710375..621f7309 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -261,6 +261,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) msg.rtm.rtm_flags |= RTF_GATEWAY; msg.rtm.rtm_addrs |= RTA_GATEWAY; break; + #ifdef RTF_REJECT case RTD_UNREACHABLE: #endif @@ -280,7 +281,7 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e) 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; } break; diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index fa3969bd..df5e0236 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -141,6 +141,7 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) #ifdef IP_SENDSRCADDR struct cmsghdr *cm; struct in_addr *sa; + int controllen = 0; msg->msg_control = cbuf; 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_type = IP_SENDSRCADDR; cm->cmsg_len = CMSG_LEN(sizeof(*sa)); + controllen += CMSG_SPACE(sizeof(*sa)); sa = (struct in_addr *) CMSG_DATA(cm); *sa = ipa_to_in4(s->saddr); - msg->msg_controllen = cm->cmsg_len; + msg->msg_controllen = controllen; #endif } diff --git a/sysdep/config.h b/sysdep/config.h index e2ea7642..02f62762 100644 --- a/sysdep/config.h +++ b/sysdep/config.h @@ -7,7 +7,7 @@ #define _BIRD_CONFIG_H_ /* BIRD version */ -#define BIRD_VERSION "1.4.3" +#define BIRD_VERSION "1.4.5" /* Include parameters determined by configure script */ #include "sysdep/autoconf.h" diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c index a0f85186..132403af 100644 --- a/sysdep/linux/netlink.c +++ b/sysdep/linux/netlink.c @@ -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 nl_error(struct nlmsghdr *h) diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 5fd75c90..c1561cbf 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -154,6 +154,7 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { struct cmsghdr *cm; struct in_pktinfo *pi; + int controllen = 0; msg->msg_control = cbuf; 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_type = IP_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(*pi)); + controllen += CMSG_SPACE(sizeof(*pi)); pi = (struct in_pktinfo *) CMSG_DATA(cm); pi->ipi_ifindex = s->iface ? s->iface->index : 0; pi->ipi_spec_dst = ipa_to_in4(s->saddr); pi->ipi_addr = ipa_to_in4(IPA_NONE); - msg->msg_controllen = cm->cmsg_len; + msg->msg_controllen = controllen; } diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index 5a0c07e5..164038ec 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -705,6 +705,7 @@ sk_prepare_cmsgs6(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen) { struct cmsghdr *cm; struct in6_pktinfo *pi; + int controllen = 0; msg->msg_control = cbuf; 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_type = IPV6_PKTINFO; cm->cmsg_len = CMSG_LEN(sizeof(*pi)); + controllen += CMSG_SPACE(sizeof(*pi)); pi = (struct in6_pktinfo *) CMSG_DATA(cm); pi->ipi6_ifindex = s->iface ? s->iface->index : 0; 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) { sock *s = current_sock; - int e; + int e UNUSED; if ((s->type < SK_MAGIC) && FD_ISSET(s->fd, &rd) && s->rx_hook) { diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c index bff3001f..a2fb83d9 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -36,7 +36,7 @@ * only once for all the instances. * * 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. * This is also used for platform specific protocol options and route attributes. * @@ -117,7 +117,7 @@ kif_request_scan(void) static inline int prefer_addr(struct ifa *a, struct ifa *b) -{ +{ int sa = a->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 -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) - 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 -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 @@ -378,20 +378,20 @@ krt_learn_scan(struct krt_proto *p, rte *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); m->u.krt.seen = 1; } else { - krt_trace_in_rl(&rl_alien_updated, p, e, "[alien] updated"); + krt_trace_in(p, e, "[alien] updated"); *mm = m->next; rte_free(m); m = NULL; } } else - krt_trace_in_rl(&rl_alien_created, p, e, "[alien] created"); + krt_trace_in(p, e, "[alien] created"); if (!m) { e->next = n->routes; @@ -637,7 +637,7 @@ krt_got_route(struct krt_proto *p, rte *e) krt_learn_scan(p, e); 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); } return; @@ -737,7 +737,7 @@ krt_prune(struct krt_proto *p) if (! krt_export_rte(p, &new, &tmpa)) { /* 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 { @@ -910,7 +910,7 @@ krt_scan_timer_stop(struct krt_proto *p) } 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); } @@ -962,8 +962,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool * if (e->attrs->src->proto == P) return -1; - if (!KRT_CF->devroutes && - (e->attrs->dest == RTD_DEVICE) && + if (!KRT_CF->devroutes && + (e->attrs->dest == RTD_DEVICE) && (e->attrs->source != RTS_STATIC_DEVICE)) return -1; @@ -974,8 +974,8 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool * } static void -krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, - rte *new, rte *old, struct ea_list *eattrs) +krt_rt_notify(struct proto *P, struct rtable *table UNUSED, net *net, + rte *new, rte *old, struct ea_list *eattrs) { struct krt_proto *p = (struct krt_proto *) P; @@ -992,6 +992,36 @@ krt_notify(struct proto *P, struct rtable *table UNUSED, net *net, } 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 krt_feed_done(struct proto *P) { struct krt_proto *p = (struct krt_proto *) P; @@ -1022,7 +1052,9 @@ krt_init(struct proto_config *c) p->p.accept_ra_types = RA_OPTIMAL; 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.make_tmp_attrs = krt_make_tmp_attrs; p->p.store_tmp_attrs = krt_store_tmp_attrs; diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c index 66a5581c..ccf35bf3 100644 --- a/sysdep/unix/log.c +++ b/sysdep/unix/log.c @@ -32,9 +32,6 @@ static FILE *dbgf; static list *current_log_list; 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 @@ -154,7 +151,6 @@ vlog(int class, const char *msg, va_list args) } - /** * log - log a message * @msg: printf-like formatting string with message class information @@ -180,31 +176,21 @@ log_msg(char *msg, ...) } void -log_rl(struct rate_limit *rl, char *msg, ...) +log_rl(struct tbf *f, char *msg, ...) { + int last_hit = f->mark; int class = 1; va_list args; - bird_clock_t delta = now - rl->timestamp; - if ((0 <= delta) && (delta < rate_limit_time)) - { - rl->count++; - } - else - { - rl->timestamp = now; - rl->count = 1; - } - - if (rl->count > rate_limit_count) + /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */ + if (tbf_limit(f) && last_hit) return; - va_start(args, msg); if (*msg >= 1 && *msg <= 8) class = *msg++; - vlog(class, msg, args); - if (rl->count == rate_limit_count) - vlog(class, "...", args); + + va_start(args, msg); + vlog(class, (f->mark ? "..." : msg), args); va_end(args); } |