mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +00:00
Protocol stats: a WIP implementation of conditional routes
Add new global counter for stats channel New symbol is added for each stats protocol channel, the symbol is accessed by same name as the underlying channel. Symbols evaluate to the sum of all routes exported from connected table with generation less than max generation of particular channel. Default max generation is 16. Beware you shouldn't make cyclic references as the behavior of such configuration is not defined!
This commit is contained in:
parent
860fbf0d65
commit
d648c6b602
@ -112,6 +112,7 @@ void cfg_copy_list(list *dest, list *src, unsigned node_size);
|
||||
|
||||
extern int (*cf_read_hook)(byte *buf, uint max, int fd);
|
||||
|
||||
struct stats_term_config;
|
||||
struct symbol {
|
||||
node n; /* In list of symbols in config */
|
||||
struct symbol *next;
|
||||
@ -127,6 +128,8 @@ struct symbol {
|
||||
struct ea_class *attribute; /* For SYM_ATTRIBUTE */
|
||||
struct f_val *val; /* For SYM_CONSTANT */
|
||||
uint offset; /* For SYM_VARIABLE */
|
||||
struct channel_config *ch_config; /* For SYM_COUNTER */
|
||||
struct stats_term_config *term; /* For SYM_COUNTER_TERM */
|
||||
};
|
||||
|
||||
char name[0];
|
||||
@ -161,6 +164,8 @@ struct bytestring {
|
||||
#define SYM_FILTER 4
|
||||
#define SYM_TABLE 5
|
||||
#define SYM_ATTRIBUTE 6
|
||||
#define SYM_COUNTER 7
|
||||
#define SYM_COUNTER_TERM 8
|
||||
|
||||
#define SYM_VARIABLE 0x100 /* 0x100-0x1ff are variable types */
|
||||
#define SYM_VARIABLE_RANGE SYM_VARIABLE ... (SYM_VARIABLE | 0xff)
|
||||
|
@ -307,7 +307,7 @@ if test "$enable_mpls_kernel" != no ; then
|
||||
fi
|
||||
|
||||
# temporarily removed "mrt" from all_protocols to speed up 3.0-alpha1 release
|
||||
all_protocols="bfd babel bgp ospf perf pipe radv rip rpki static"
|
||||
all_protocols="bfd babel bgp ospf perf pipe radv rip rpki static stats"
|
||||
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
|
||||
|
||||
if test "$with_protocols" = all ; then
|
||||
|
@ -5560,6 +5560,64 @@ protocol static {
|
||||
}
|
||||
</code>
|
||||
|
||||
<sect>Stats
|
||||
<label id="stats">
|
||||
|
||||
<sect1>
|
||||
<label id="stats-intro">
|
||||
|
||||
<p>The Statistics protocol allows you to measure number of exported routes from
|
||||
a table. You can also narrow the view by applying export filter inside stats
|
||||
channel. One instance of stats protocol can have multiple channels attached.
|
||||
Stats protocol could be particullary useful when making conditional route advertising.
|
||||
|
||||
<p>Statistics are accessed in filters by same name as channel connected to desired
|
||||
table. Value of this expresion is evaluated to the sum of all routes with
|
||||
generation smaller than max generation (see below).
|
||||
|
||||
<sect1>Configuration
|
||||
<label id="stats-config">
|
||||
|
||||
<p><descrtip>
|
||||
<tag><label id="stats-max-generation">max generation <m/expr/</tag>
|
||||
Statistics counter contains sum of all routes with generation less
|
||||
than or equal to max generation. This copies behavior of pipe's
|
||||
<ref id="pipe-max-generation" name="max generetion">. Must be in range
|
||||
from 0 to 254. Default: 16.
|
||||
|
||||
<tab><label id="stats-min-settle-time">min settle time <m/time/ </tag>
|
||||
Specify a minimum value of the settle time. When a stats counter changes,
|
||||
automatic recalcualtion of route filters may be triggered, after a short
|
||||
settle time. Minimum settle time is a delay from the last counter change
|
||||
to wait for more updates. No action is done if counter has same value
|
||||
before and after changes. Default: 1 s.
|
||||
|
||||
<tab><label id="stats-max-settle-time">max settle time <m/time/ </tag>
|
||||
Specify a maximum value of the settle time. When stats counter changes,
|
||||
automatic route filter recalculation may be triggered, after a short
|
||||
settle time. Maximum settle time is an upper limit to the settle time
|
||||
from initial counter change even if there are consecutive updates
|
||||
gradually renewing the settle time. No action is done if counter has
|
||||
same value before and after changes. Defualt: 20 s.
|
||||
|
||||
</descrip>
|
||||
|
||||
<p>Example
|
||||
<code>
|
||||
protocol stats {
|
||||
ipv4 stats1 { table bgp_tab1; };
|
||||
}
|
||||
|
||||
protocol static {
|
||||
# note that the stats1 is unrelated
|
||||
ipv4 { import where stats1 > 200; };
|
||||
route 0.0.0.0:0;
|
||||
}
|
||||
</code>
|
||||
|
||||
<p>Beware that configuration with cyclic references (even logical ones) are
|
||||
considered invalid and the behaviour is not defined! You <em>should</em> avoid
|
||||
them. No detection is implemented yet.
|
||||
|
||||
<chapt>Conclusions
|
||||
<label id="conclusion">
|
||||
|
@ -801,6 +801,12 @@ symbol_value: symbol_known
|
||||
case SYM_ATTRIBUTE:
|
||||
$$ = f_new_inst(FI_EA_GET, $1->attribute);
|
||||
break;
|
||||
case SYM_COUNTER:
|
||||
$$ = f_new_inst(FI_COUNTER, $1);
|
||||
break;
|
||||
case SYM_COUNTER_TERM:
|
||||
$$ = f_new_inst(FI_COUNTER_TERM, $1);
|
||||
break;
|
||||
default:
|
||||
cf_error("Can't get value of symbol %s", $1->name);
|
||||
}
|
||||
|
@ -542,6 +542,20 @@
|
||||
RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
|
||||
}
|
||||
|
||||
INST(FI_COUNTER, 0, 1) {
|
||||
SYMBOL;
|
||||
NEVER_CONSTANT;
|
||||
RESULT(T_INT, i, stats_get_counter(sym));
|
||||
}
|
||||
|
||||
INST(FI_COUNTER_TERM, 0, 1) {
|
||||
SYMBOL;
|
||||
NEVER_CONSTANT;
|
||||
|
||||
RESULT_TYPE(sym->val->type);
|
||||
RESULT_VAL(*sym->val);
|
||||
}
|
||||
|
||||
INST(FI_CONSTANT, 0, 1) {
|
||||
FID_MEMBER(
|
||||
struct f_val,
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "filter/filter.h"
|
||||
#include "filter/f-inst.h"
|
||||
#include "filter/data.h"
|
||||
#include "proto/stats/stats-pub.h" /* provides function get_stats_counter() used in f-inst.c */
|
||||
|
||||
|
||||
/* Exception bits */
|
||||
|
68
lib/timer.c
68
lib/timer.c
@ -325,3 +325,71 @@ tm_format_real_time(char *x, size_t max, const char *fmt, btime t)
|
||||
|
||||
return strftime(x, max, tbuf, &tm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Settle timer
|
||||
*/
|
||||
|
||||
static inline btime
|
||||
settled_time(struct settle_timer *st)
|
||||
{
|
||||
ASSUME(st->base_settle_time != 0);
|
||||
|
||||
return MIN_(st->last_change + st->min_settle_time,
|
||||
st->base_settle_time + st->max_settle_time);
|
||||
}
|
||||
|
||||
inline void
|
||||
settle_timer_changed(struct settle_timer *st)
|
||||
{
|
||||
st->last_change = current_time();
|
||||
}
|
||||
|
||||
void
|
||||
settle_timer(timer *t)
|
||||
{
|
||||
struct settle_timer *st = t->data;
|
||||
|
||||
if (!st->base_settle_time)
|
||||
return;
|
||||
|
||||
btime settled_t = settled_time(st);
|
||||
if (current_time() < settled_t)
|
||||
{
|
||||
tm_set(t, settled_t);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Settled */
|
||||
st->base_settle_time = 0;
|
||||
|
||||
/* t->hook already occupied by settle_timer() */
|
||||
if (st->settle_hook)
|
||||
st->settle_hook(st);
|
||||
}
|
||||
|
||||
void
|
||||
stm_init(struct settle_timer *st, pool *p, void *data,
|
||||
void (*settle_hook)(struct settle_timer *st))
|
||||
{
|
||||
st->t = tm_new_init(p, (void *) st, settle_timer, 0, 0);
|
||||
st->t->hook = settle_timer;
|
||||
st->t->data = (void *) st;
|
||||
|
||||
st->settle_data = data;
|
||||
st->settle_hook = settle_hook;
|
||||
}
|
||||
|
||||
void
|
||||
kick_settle_timer(struct settle_timer *st)
|
||||
{
|
||||
ASSUME(st != NULL);
|
||||
|
||||
st->base_settle_time = current_time();
|
||||
|
||||
timer *t = st->t;
|
||||
if (!tm_active(t))
|
||||
tm_set(t, settled_time(st));
|
||||
}
|
||||
|
18
lib/timer.h
18
lib/timer.h
@ -134,4 +134,22 @@ btime tm_parse_time(const char *x);
|
||||
void tm_format_time(char *x, struct timeformat *fmt, btime t);
|
||||
int tm_format_real_time(char *x, size_t max, const char *fmt, btime t);
|
||||
|
||||
/*
|
||||
* Settle timer
|
||||
*/
|
||||
|
||||
struct settle_timer {
|
||||
btime min_settle_time;
|
||||
btime max_settle_time;
|
||||
btime base_settle_time;
|
||||
btime last_change;
|
||||
timer *t;
|
||||
void (*settle_hook)(struct settle_timer *t);
|
||||
void *settle_data;
|
||||
};
|
||||
|
||||
void stm_init(struct settle_timer *st, pool *p, void *data, void (*settle_hook)(struct settle_timer *st));
|
||||
void kick_settle_timer(struct settle_timer *st);
|
||||
void settle_timer_changed(struct settle_timer *st);
|
||||
|
||||
#endif
|
||||
|
@ -1031,6 +1031,10 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
|
||||
}
|
||||
}
|
||||
|
||||
/* update pointers from config to channel and vice versa */
|
||||
cf->channel = c;
|
||||
c->config = cf;
|
||||
|
||||
/* Execute channel-specific reconfigure hook */
|
||||
if (c->class->reconfigure && !c->class->reconfigure(c, cf, &import_changed, &export_changed))
|
||||
return 0;
|
||||
|
@ -93,7 +93,8 @@ void protos_dump_all(void);
|
||||
extern struct protocol
|
||||
proto_device, proto_radv, proto_rip, proto_static, proto_mrt,
|
||||
proto_ospf, proto_perf,
|
||||
proto_pipe, proto_bgp, proto_bfd, proto_babel, proto_rpki;
|
||||
proto_pipe, proto_bgp, proto_bfd, proto_babel, proto_rpki,
|
||||
proto_stats;
|
||||
|
||||
/*
|
||||
* Routing Protocol Instance
|
||||
@ -492,6 +493,7 @@ struct channel_class {
|
||||
};
|
||||
|
||||
extern struct channel_class channel_bgp;
|
||||
extern struct channel_class channel_stats;
|
||||
|
||||
struct channel_config {
|
||||
node n;
|
||||
|
1
proto/stats/Doc
Normal file
1
proto/stats/Doc
Normal file
@ -0,0 +1 @@
|
||||
S stats.c
|
7
proto/stats/Makefile
Normal file
7
proto/stats/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
src := stats.c
|
||||
obj := $(src-o-files)
|
||||
$(all-daemon)
|
||||
$(cf-local)
|
||||
$(call proto-build,stats_build)
|
||||
|
||||
tests_objs := $(tests_objs) $(src-o-files)
|
90
proto/stats/config.Y
Normal file
90
proto/stats/config.Y
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* BIRD -- Statistics Protocol Configuration
|
||||
*
|
||||
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
||||
* (c) 2022 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
CF_HDR
|
||||
|
||||
#include "proto/stats/stats.h"
|
||||
|
||||
CF_DEFINES
|
||||
|
||||
#define STATS_CFG ((struct stats_config *) this_proto)
|
||||
#define STATS_CC ((struct stats_channel_config *) this_channel)
|
||||
|
||||
CF_DECLS
|
||||
|
||||
CF_KEYWORDS(STATS, TABLE, MAX, MIN, SETTLE, TIME)
|
||||
|
||||
%type <cc> stats_channel_start
|
||||
|
||||
CF_GRAMMAR
|
||||
|
||||
proto: stats_proto '}' { this_channel = NULL; } ;
|
||||
|
||||
stats_proto_start: proto_start STATS
|
||||
{
|
||||
this_proto = proto_config_new(&proto_stats, $1);
|
||||
init_list(&STATS_CFG->terms);
|
||||
}
|
||||
|
||||
proto_name ;
|
||||
|
||||
stats_channel_opt_list:
|
||||
/* empty */
|
||||
| '{' stats_opts '}'
|
||||
;
|
||||
|
||||
stats_opt:
|
||||
type symbol '=' term {
|
||||
|
||||
struct stats_term_config *tc = cfg_alloc(sizeof(struct stats_term_config));
|
||||
struct f_val *val = cfg_allocz(sizeof(struct stats_term_config));
|
||||
tc->code = (const struct f_line *) f_linearize($4);
|
||||
tc->type = $1;
|
||||
tc->name = $2->name;
|
||||
tc->val = val;
|
||||
|
||||
/* greater then F_RETURN, therefore 2 */
|
||||
//if (f_eval(f_linearize($4), &val) > 2) cf_error("Runtime error");
|
||||
//if (val.type != $1) cf_error("The expresion does not match defined type");
|
||||
|
||||
add_tail(&STATS_CFG->terms, (node *) tc);
|
||||
stats_eval_term(tc);
|
||||
|
||||
$2 = cf_define_symbol($2, SYM_COUNTER_TERM, val, val);
|
||||
}
|
||||
| MIN SETTLE TIME expr_us { STATS_CC->min_settle_time = $4; }
|
||||
| MAX SETTLE TIME expr_us { STATS_CC->max_settle_time = $4; }
|
||||
;
|
||||
|
||||
stats_opts:
|
||||
/* empty */
|
||||
| stats_opts channel_item ';'
|
||||
| stats_opts stats_opt ';'
|
||||
;
|
||||
|
||||
stats_proto_channel: stats_channel_start stats_channel_opt_list channel_end ;
|
||||
|
||||
stats_channel_start: net_type symbol
|
||||
{
|
||||
this_channel = channel_config_get(&channel_stats, $2->name, $1, this_proto);
|
||||
STATS_CC->min_settle_time = 1 S_;
|
||||
STATS_CC->max_settle_time = 20 S_;
|
||||
$2 = cf_define_symbol($2, SYM_COUNTER, ch_config, this_channel);
|
||||
}
|
||||
|
||||
stats_proto:
|
||||
stats_proto_start '{'
|
||||
| stats_proto proto_item ';'
|
||||
| stats_proto stats_proto_channel ';'
|
||||
| stats_proto ';'
|
||||
;
|
||||
|
||||
CF_CODE
|
||||
|
||||
CF_END
|
5
proto/stats/stats-pub.h
Normal file
5
proto/stats/stats-pub.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef _BIRD_STATS_PUB_H_
|
||||
#define _BIRD_STATS_PUB_H_
|
||||
|
||||
extern int stats_get_counter(struct symbol *sym);
|
||||
#endif
|
280
proto/stats/stats.c
Normal file
280
proto/stats/stats.c
Normal file
@ -0,0 +1,280 @@
|
||||
/*
|
||||
* BIRD -- Statistics Protocol
|
||||
*
|
||||
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
||||
* (c) 2022 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DOC: Stats
|
||||
*
|
||||
*/
|
||||
|
||||
#undef LOCAL_DEBUG
|
||||
|
||||
#include "nest/bird.h"
|
||||
#include "nest/iface.h"
|
||||
#include "nest/protocol.h"
|
||||
#include "nest/rt.h"
|
||||
#include "nest/cli.h"
|
||||
#include "conf/conf.h"
|
||||
#include "filter/filter.h"
|
||||
#include "lib/string.h"
|
||||
#include "lib/timer.h"
|
||||
|
||||
#include "stats.h"
|
||||
|
||||
static void stats_settle_timer(struct settle_timer *st);
|
||||
|
||||
static void
|
||||
stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *n UNUSED, rte *new, const rte *old)
|
||||
{
|
||||
struct stats_channel *ch = (void *) src_ch;
|
||||
|
||||
int changed = 0;
|
||||
if (new && old)
|
||||
/* count of exported routes stays the same */
|
||||
;
|
||||
else if (!old)
|
||||
{
|
||||
ch->_counter++;
|
||||
changed = 1;
|
||||
}
|
||||
else if (!new)
|
||||
{
|
||||
ch->_counter--;
|
||||
changed = 1;
|
||||
}
|
||||
else /* shouldn't happen */
|
||||
{
|
||||
bug("Both pointers *new and *old in rt_notify are NULL");
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
settle_timer_changed(&ch->settle_timer);
|
||||
kick_settle_timer(&ch->settle_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stats_reload_routes(struct channel *C)
|
||||
{
|
||||
// TODO
|
||||
struct stats_channel *c = (void *) C;
|
||||
|
||||
c->_counter = c->counter = 0;
|
||||
channel_request_feeding(C);
|
||||
}
|
||||
|
||||
static struct proto *
|
||||
stats_init(struct proto_config *CF)
|
||||
{
|
||||
struct proto *P = proto_new(CF);
|
||||
struct stats_proto *p = (void *) P;
|
||||
|
||||
P->rt_notify = stats_rt_notify;
|
||||
P->reload_routes = stats_reload_routes;
|
||||
|
||||
p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS;
|
||||
|
||||
return P;
|
||||
}
|
||||
|
||||
static void
|
||||
stats_configure_channels(struct proto *P, struct proto_config *CF)
|
||||
{
|
||||
struct channel_config *cc;
|
||||
WALK_LIST(cc, CF->channels)
|
||||
{
|
||||
struct channel *c = proto_find_channel_by_name(P, cc->name);
|
||||
proto_configure_channel(P, &c, cc);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
stats_start(struct proto *P)
|
||||
{
|
||||
stats_configure_channels(P, P->cf);
|
||||
|
||||
/* evaluate terms on protocol start */
|
||||
struct stats_term_config *tc;
|
||||
WALK_LIST(tc, ((struct stats_config *) P->cf)->terms)
|
||||
{
|
||||
stats_eval_term(tc);
|
||||
}
|
||||
|
||||
return PS_UP;
|
||||
}
|
||||
|
||||
static int
|
||||
stats_reconfigure(struct proto *P, struct proto_config *CF)
|
||||
{
|
||||
struct stats_proto *p = (void *) P;
|
||||
struct stats_config *new = (void *) CF;
|
||||
|
||||
struct channel *c;
|
||||
WALK_LIST(c, p->p.channels)
|
||||
c->stale = 1;
|
||||
|
||||
struct channel_config *cc;
|
||||
WALK_LIST(cc, new->c.channels)
|
||||
{
|
||||
c = proto_find_channel_by_name(P, cc->name);
|
||||
if (!proto_configure_channel(P, &c, cc))
|
||||
return 0;
|
||||
|
||||
if (c)
|
||||
{
|
||||
struct stats_channel *sc = (void *) c;
|
||||
struct stats_channel_config *scc = (void *) cc;
|
||||
|
||||
sc->settle_timer.min_settle_time = scc->min_settle_time;
|
||||
sc->settle_timer.max_settle_time = scc->max_settle_time;
|
||||
|
||||
if (sc->counter != sc->_counter)
|
||||
{
|
||||
sc->counter = sc->_counter;
|
||||
|
||||
/* notify all hooked filters */
|
||||
// TODO here
|
||||
}
|
||||
|
||||
c->stale = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct channel *c2;
|
||||
WALK_LIST_DELSAFE(c, c2, p->p.channels)
|
||||
if (c->stale && !proto_configure_channel(P, &c, NULL))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
stats_show_proto_info(struct proto *P)
|
||||
{
|
||||
struct stats_proto *p = (void *) P;
|
||||
|
||||
struct stats_channel *sc;
|
||||
WALK_LIST(sc, p->p.channels)
|
||||
{
|
||||
cli_msg(-1006, " Channel %s", sc->c.name);
|
||||
cli_msg(-1006, " Exports: %10u (currently: %10u)",
|
||||
sc->counter,
|
||||
sc->_counter);
|
||||
if (!P->disabled)
|
||||
{
|
||||
cli_msg(-1006, " Settle time: %4u s", sc->settle_timer.min_settle_time TO_S);
|
||||
cli_msg(-1006, " Settle time: %4u s", sc->settle_timer.max_settle_time TO_S);
|
||||
}
|
||||
}
|
||||
|
||||
cli_msg(-1006, " Terms:");
|
||||
|
||||
struct stats_term_config *tc;
|
||||
WALK_LIST(tc, ((struct stats_config *) P->cf)->terms)
|
||||
{
|
||||
stats_eval_term(tc);
|
||||
cli_msg(-1006, " %s = %s", tc->name, val_dump(tc->val));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
stats_update_debug(struct proto *P)
|
||||
{
|
||||
struct channel *c;
|
||||
WALK_LIST(c, P->channels)
|
||||
{
|
||||
c->debug = P->debug;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stats_settle_timer(struct settle_timer *st)
|
||||
{
|
||||
struct stats_channel *c = st->settle_data;
|
||||
|
||||
/* update only if real change happen */
|
||||
if (c->counter != c->_counter)
|
||||
{
|
||||
c->counter = c->_counter;
|
||||
/* do update here */
|
||||
// WALK_LIST(s, subscribers)
|
||||
// { ... }
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
stats_channel_start(struct channel *C)
|
||||
{
|
||||
struct stats_channel *c = (void *) C;
|
||||
struct stats_channel_config *cc = (void *) C->config;
|
||||
struct stats_proto *p = (void *) C->proto;
|
||||
|
||||
c->pool = p->p.pool;
|
||||
|
||||
stm_init(&c->settle_timer, c->pool, (void *)c, stats_settle_timer);
|
||||
|
||||
c->settle_timer.min_settle_time = cc->min_settle_time;
|
||||
c->settle_timer.max_settle_time = cc->max_settle_time;
|
||||
|
||||
c->_counter = 0;
|
||||
c->counter = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stats_channel_shutdown(struct channel *C)
|
||||
{
|
||||
struct stats_channel *c = (void *) C;
|
||||
|
||||
tm_stop(c->settle_timer.t);
|
||||
|
||||
c->_counter = 0;
|
||||
c->counter = 0;
|
||||
c->pool = NULL;
|
||||
}
|
||||
|
||||
int
|
||||
stats_get_counter(struct symbol *sym)
|
||||
{
|
||||
if (sym->ch_config->channel)
|
||||
return (int) ((struct stats_channel *) sym->ch_config->channel)->counter;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stats_eval_term(struct stats_term_config *tc)
|
||||
{
|
||||
f_eval(tc->code, tc->val);
|
||||
}
|
||||
|
||||
struct channel_class channel_stats = {
|
||||
.channel_size = sizeof(struct stats_channel),
|
||||
.config_size = sizeof(struct stats_channel_config),
|
||||
.start = stats_channel_start,
|
||||
.shutdown = stats_channel_shutdown,
|
||||
};
|
||||
|
||||
struct protocol proto_stats = {
|
||||
.name = "Stats",
|
||||
.template = "stat%d",
|
||||
.channel_mask = NB_ANY,
|
||||
.proto_size = sizeof(struct stats_proto),
|
||||
.config_size = sizeof(struct stats_config),
|
||||
.init = stats_init,
|
||||
.start = stats_start,
|
||||
.reconfigure = stats_reconfigure,
|
||||
.show_proto_info = stats_show_proto_info
|
||||
};
|
||||
|
||||
void
|
||||
stats_build(void)
|
||||
{
|
||||
proto_build(&proto_stats);
|
||||
}
|
53
proto/stats/stats.h
Normal file
53
proto/stats/stats.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* BIRD -- Statistics Protocol
|
||||
*
|
||||
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
||||
* (c) 2022 CZ.NIC z.s.p.o.
|
||||
*
|
||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||
*/
|
||||
|
||||
#ifndef _BIRD_STATS_H_
|
||||
#define _BIRD_STATS_H_
|
||||
#include "lib/timer.h"
|
||||
#include "filter/data.h"
|
||||
|
||||
struct stats_channel;
|
||||
|
||||
struct stats_term_config {
|
||||
node n;
|
||||
const struct f_line *code;
|
||||
struct f_val *val;
|
||||
int type; /* type declared in configuration */
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct stats_config {
|
||||
struct proto_config c;
|
||||
list terms; /* list of counter terms */
|
||||
};
|
||||
|
||||
struct stats_proto {
|
||||
struct proto p;
|
||||
struct stats_channel *c;
|
||||
struct tbf rl_gen;
|
||||
};
|
||||
|
||||
struct stats_channel {
|
||||
struct channel c;
|
||||
pool *pool; /* copy of procotol pool */
|
||||
u32 _counter; /* internal counter */
|
||||
u32 counter; /* publicly accessible counter */
|
||||
struct settle_timer settle_timer;
|
||||
};
|
||||
|
||||
struct stats_channel_config {
|
||||
struct channel_config c;
|
||||
btime min_settle_time; /* wait before notifying filters */
|
||||
btime max_settle_time;
|
||||
};
|
||||
|
||||
int stats_get_counter(struct symbol *sym);
|
||||
void stats_eval_term(struct stats_term_config *tc);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user