From 6285793f18817091060c7257f7d4af0db010a67a Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 7 Jul 2014 22:23:37 +0200 Subject: Replaces function name in test.conf as it collided with new keyword. --- filter/test.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'filter') diff --git a/filter/test.conf b/filter/test.conf index ae8a95a6..84faca0e 100644 --- a/filter/test.conf +++ b/filter/test.conf @@ -78,7 +78,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; @@ -389,7 +389,7 @@ string st; i = fifteen(); print "Testing function calls: 15 = ", i; - paths(); + path_test(); print "1.2.3.4 = ", onetwo; -- cgit v1.2.3 From b2f008378a39104152b20a969942cd6c99644984 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 2 Oct 2014 11:02:14 +0200 Subject: Allows more constants in set literals. Thanks to Michael Fincham for the bugreport. --- conf/cf-lex.l | 2 +- conf/conf.h | 4 ++++ filter/config.Y | 28 +++++++++++++++++++++++++++- filter/test.conf | 9 ++++++--- 4 files changed, 38 insertions(+), 5 deletions(-) (limited to 'filter') 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/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/test.conf b/filter/test.conf index 84faca0e..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; @@ -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; -- cgit v1.2.3 From 1123e707400984108f48ac7c1be559f7ed8d9306 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 2 Oct 2014 11:41:34 +0200 Subject: Implements token bucket filter for rate limiting. --- filter/filter.c | 4 ++-- lib/Doc | 2 +- lib/Modules | 1 + lib/birdlib.h | 40 +++++++++++++++++++++++++++++++++------- lib/tbf.c | 29 +++++++++++++++++++++++++++++ nest/rt-table.c | 4 ++-- proto/bgp/packets.c | 3 ++- sysdep/linux/netlink.c | 2 +- sysdep/unix/krt.c | 14 +++++++------- sysdep/unix/log.c | 28 +++++++--------------------- 10 files changed, 85 insertions(+), 42 deletions(-) create mode 100644 lib/tbf.c (limited to 'filter') 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/lib/Doc b/lib/Doc index 6be6250d..8f513821 100644 --- a/lib/Doc +++ b/lib/Doc @@ -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 04fb7fed..c489c45f 100644 --- a/lib/birdlib.h +++ b/lib/birdlib.h @@ -68,6 +68,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 { @@ -88,16 +120,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; 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 + * (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/nest/rt-table.c b/nest/rt-table.c index 4c889d0d..37dbb33d 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); 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/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/unix/krt.c b/sysdep/unix/krt.c index 51950ec9..a2fb83d9 100644 --- a/sysdep/unix/krt.c +++ b/sysdep/unix/krt.c @@ -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; 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); } -- cgit v1.2.3