2022-07-13 13:39:14 +00:00
|
|
|
/*
|
2022-07-14 15:08:03 +00:00
|
|
|
* BIRD -- Statistics Protocol
|
2022-07-13 13:39:14 +00:00
|
|
|
*
|
2022-07-14 12:51:03 +00:00
|
|
|
* (c) 2022 Vojtech Vilimek <vojtech.vilimek@nic.cz>
|
|
|
|
* (c) 2022 CZ.NIC z.s.p.o.
|
2022-07-13 13:39:14 +00:00
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2022-07-14 12:51:03 +00:00
|
|
|
* DOC: Stats
|
2022-07-13 13:39:14 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#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"
|
2022-07-21 14:54:13 +00:00
|
|
|
#include "lib/timer.h"
|
2022-07-13 13:39:14 +00:00
|
|
|
|
|
|
|
#include "stats.h"
|
|
|
|
|
2022-07-21 14:54:13 +00:00
|
|
|
#define COUNTER 255
|
|
|
|
|
|
|
|
static void stats_kick_timer(struct stats_channel *c);
|
2022-07-13 13:39:14 +00:00
|
|
|
|
|
|
|
static void
|
2022-07-19 10:15:24 +00:00
|
|
|
stats_rt_notify(struct proto *P UNUSED, struct channel *src_ch, const net_addr *n UNUSED, rte *new, const rte *old)
|
2022-07-13 13:39:14 +00:00
|
|
|
{
|
2022-07-19 10:15:24 +00:00
|
|
|
struct stats_channel *ch = (void *) src_ch;
|
2022-07-14 15:08:03 +00:00
|
|
|
|
2022-07-21 14:54:13 +00:00
|
|
|
int changed = 0;
|
2022-07-15 11:59:14 +00:00
|
|
|
if (old)
|
2022-07-14 15:08:03 +00:00
|
|
|
{
|
2022-07-20 08:29:46 +00:00
|
|
|
ch->counters[old->generation]--;
|
2022-07-19 08:21:43 +00:00
|
|
|
if (old->generation < ch->max_generation)
|
2022-07-21 14:54:13 +00:00
|
|
|
{
|
|
|
|
changed = 1;
|
|
|
|
ch->counters[COUNTER]--;
|
|
|
|
}
|
2022-07-14 15:08:03 +00:00
|
|
|
}
|
2022-07-15 11:59:14 +00:00
|
|
|
|
|
|
|
if (new)
|
2022-07-14 15:08:03 +00:00
|
|
|
{
|
2022-07-20 08:29:46 +00:00
|
|
|
ch->counters[new->generation]++;
|
2022-07-19 08:21:43 +00:00
|
|
|
if (new->generation < ch->max_generation)
|
2022-07-21 14:54:13 +00:00
|
|
|
{
|
|
|
|
changed = 1;
|
|
|
|
ch->counters[COUNTER]++;
|
|
|
|
}
|
2022-07-19 08:21:43 +00:00
|
|
|
}
|
2022-07-21 14:54:13 +00:00
|
|
|
|
|
|
|
if (changed)
|
|
|
|
{
|
|
|
|
log(L_INFO "stats: timer kicked with time %u", ch->settle);
|
|
|
|
stats_kick_timer((struct stats_channel *) ch);
|
|
|
|
}
|
2022-07-13 13:39:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2022-07-19 10:15:24 +00:00
|
|
|
stats_reload_routes(struct channel *C UNUSED)
|
2022-07-13 13:39:14 +00:00
|
|
|
{
|
|
|
|
/* Route reload on one channel is just refeed on the other */
|
2022-07-15 11:33:42 +00:00
|
|
|
//channel_request_feeding(p->c);
|
2022-07-13 13:39:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-15 11:33:42 +00:00
|
|
|
static void
|
|
|
|
stats_configure_channels(struct proto *P, struct proto_config *CF)
|
|
|
|
{
|
|
|
|
struct channel_config *cc;
|
|
|
|
WALK_LIST(cc, CF->channels)
|
|
|
|
{
|
|
|
|
struct channel *c = NULL;
|
|
|
|
proto_configure_channel(P, &c, cc);
|
2022-07-19 09:58:23 +00:00
|
|
|
|
|
|
|
struct stats_channel *sc = (void *) c;
|
|
|
|
struct stats_channel_config *scc = (void *) cc;
|
|
|
|
|
|
|
|
sc->max_generation = scc->max_generation;
|
2022-07-21 14:54:13 +00:00
|
|
|
sc->settle = scc->settle;
|
2022-07-15 11:33:42 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-13 13:39:14 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2022-07-15 11:33:42 +00:00
|
|
|
stats_configure_channels(P, CF);
|
2022-07-13 13:39:14 +00:00
|
|
|
|
|
|
|
return P;
|
|
|
|
}
|
|
|
|
|
2022-07-14 15:08:03 +00:00
|
|
|
static int
|
2022-07-19 10:15:24 +00:00
|
|
|
stats_start(struct proto *P UNUSED)
|
2022-07-14 15:08:03 +00:00
|
|
|
{
|
|
|
|
return PS_UP;
|
|
|
|
}
|
|
|
|
|
2022-07-13 13:39:14 +00:00
|
|
|
static int
|
|
|
|
stats_reconfigure(struct proto *P, struct proto_config *CF)
|
|
|
|
{
|
|
|
|
struct stats_proto *p = (void *) P;
|
2022-07-15 11:33:42 +00:00
|
|
|
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)
|
|
|
|
{
|
2022-07-20 10:55:30 +00:00
|
|
|
c = proto_find_channel_by_name(P, cc->name);
|
2022-07-15 11:33:42 +00:00
|
|
|
if (!proto_configure_channel(P, &c, cc))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (c)
|
2022-07-19 09:58:23 +00:00
|
|
|
{
|
|
|
|
struct stats_channel *sc = (void *) c;
|
|
|
|
struct stats_channel_config *scc = (void *) cc;
|
|
|
|
|
2022-07-20 08:29:46 +00:00
|
|
|
sc->max_generation = scc->max_generation;
|
2022-07-21 14:54:13 +00:00
|
|
|
sc->settle = scc->settle;
|
2022-07-19 09:58:23 +00:00
|
|
|
|
2022-07-20 08:29:46 +00:00
|
|
|
/* recalculate sum */
|
2022-07-21 14:54:13 +00:00
|
|
|
sc->counters[COUNTER] = 0;
|
2022-07-20 08:29:46 +00:00
|
|
|
for (u8 i = 0; i < sc->max_generation; i++)
|
2022-07-21 14:54:13 +00:00
|
|
|
sc->counters[COUNTER] += sc->counters[i];
|
|
|
|
|
|
|
|
sc->sum = sc->counters[COUNTER];
|
|
|
|
|
|
|
|
/* notify all hooked filters */
|
|
|
|
// TODO here
|
2022-07-19 09:58:23 +00:00
|
|
|
|
2022-07-15 11:33:42 +00:00
|
|
|
c->stale = 0;
|
2022-07-19 09:58:23 +00:00
|
|
|
}
|
2022-07-15 11:33:42 +00:00
|
|
|
}
|
2022-07-13 13:39:14 +00:00
|
|
|
|
2022-07-15 11:33:42 +00:00
|
|
|
struct channel *c2;
|
|
|
|
WALK_LIST_DELSAFE(c, c2, p->p.channels)
|
|
|
|
if (c->stale && !proto_configure_channel(P, &c, NULL))
|
|
|
|
return 0;
|
|
|
|
|
2022-07-14 12:51:03 +00:00
|
|
|
return 1;
|
2022-07-13 13:39:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stats_show_proto_info(struct proto *P)
|
|
|
|
{
|
|
|
|
struct stats_proto *p = (void *) P;
|
2022-07-19 08:21:43 +00:00
|
|
|
|
2022-07-20 08:29:46 +00:00
|
|
|
/* indexes of non-zero counters */
|
2022-07-19 09:58:23 +00:00
|
|
|
u32 *arr = mb_alloc(p->p.pool, 256 * sizeof(u32));
|
2022-07-13 13:39:14 +00:00
|
|
|
|
2022-07-19 08:21:43 +00:00
|
|
|
struct stats_channel *sc;
|
|
|
|
WALK_LIST(sc, p->p.channels)
|
2022-07-14 15:08:03 +00:00
|
|
|
{
|
2022-07-19 08:21:43 +00:00
|
|
|
for (uint i = 0; i < 256; i++)
|
|
|
|
{
|
2022-07-19 09:58:23 +00:00
|
|
|
arr[i] = 0;
|
2022-07-19 08:21:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
u8 len = 0;
|
|
|
|
for (u8 i = 0; i < sc->max_generation; i++)
|
2022-07-19 09:58:23 +00:00
|
|
|
if (sc->counters[i])
|
2022-07-19 08:21:43 +00:00
|
|
|
{
|
2022-07-19 09:58:23 +00:00
|
|
|
arr[len] = i;
|
2022-07-19 08:21:43 +00:00
|
|
|
len++;
|
|
|
|
}
|
|
|
|
|
2022-07-19 09:58:23 +00:00
|
|
|
cli_msg(-1006, " Channel %s", sc->c.name);
|
|
|
|
cli_msg(-1006, " Max generation: %3u", sc->max_generation);
|
2022-07-21 14:54:13 +00:00
|
|
|
// FIXME : actual or visible to filters ? AND TIME below in the comment
|
|
|
|
cli_msg(-1006, " Exports: %10u (currently: %10u)",
|
|
|
|
sc->sum,
|
|
|
|
sc->counters[COUNTER]);
|
|
|
|
cli_msg(-1006, " Settle time: %7u s", sc->settle / 1000000 );
|
2022-07-19 09:58:23 +00:00
|
|
|
cli_msg(-1006, " Counter exported");
|
|
|
|
|
|
|
|
for (u8 i = 0; i < len; i++)
|
|
|
|
cli_msg(-1006, " %3u: %10u ", arr[i], sc->counters[arr[i]]);
|
|
|
|
|
|
|
|
if (!len)
|
|
|
|
cli_msg(-1006, " <all zeroes>");
|
2022-07-19 08:21:43 +00:00
|
|
|
|
2022-07-19 09:58:23 +00:00
|
|
|
cli_msg(-1006, "");
|
2022-07-19 08:21:43 +00:00
|
|
|
}
|
|
|
|
|
2022-07-19 09:58:23 +00:00
|
|
|
mb_free(arr);
|
2022-07-13 13:39:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-07-20 08:29:46 +00:00
|
|
|
stats_update_debug(struct proto *P)
|
2022-07-13 13:39:14 +00:00
|
|
|
{
|
2022-07-20 08:29:46 +00:00
|
|
|
struct channel *c;
|
|
|
|
WALK_LIST(c, P->channels)
|
|
|
|
{
|
|
|
|
c->debug = P->debug;
|
|
|
|
}
|
2022-07-13 13:39:14 +00:00
|
|
|
}
|
|
|
|
|
2022-07-21 14:54:13 +00:00
|
|
|
static void
|
|
|
|
stats_timer(timer *t)
|
|
|
|
{
|
|
|
|
log(L_INFO "timer executing update");
|
|
|
|
struct stats_channel *c = (struct stats_channel *) t->data;
|
|
|
|
|
|
|
|
/* update the sum correct counter data */
|
|
|
|
c->sum = c->counters[COUNTER];
|
|
|
|
|
|
|
|
/* notify all filters to reevaluate them */
|
|
|
|
// TODO here
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stats_kick_timer(struct stats_channel *c)
|
|
|
|
{
|
|
|
|
|
|
|
|
/* if set to zero execute immediately */
|
|
|
|
if (!c->settle)
|
|
|
|
stats_timer(c->timer);
|
|
|
|
|
|
|
|
if (!tm_active(c->timer))
|
|
|
|
tm_start(c->timer, c->settle);
|
|
|
|
}
|
|
|
|
|
2022-07-19 08:21:43 +00:00
|
|
|
static int
|
|
|
|
stats_channel_start(struct channel *C)
|
|
|
|
{
|
|
|
|
struct stats_channel *c = (void *) C;
|
2022-07-19 10:15:24 +00:00
|
|
|
struct stats_proto *p = (void *) C->proto;
|
2022-07-19 08:21:43 +00:00
|
|
|
|
|
|
|
c->pool = p->p.pool;
|
|
|
|
|
2022-07-21 14:54:13 +00:00
|
|
|
c->timer = tm_new_init(c->pool, stats_timer, (void *) c, 0, 0);
|
|
|
|
|
2022-07-20 08:29:46 +00:00
|
|
|
c->counters = mb_allocz(c->pool, 256 * sizeof(u32));
|
|
|
|
c->sum = 0;
|
2022-07-19 08:21:43 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
stats_channel_shutdown(struct channel *C)
|
|
|
|
{
|
|
|
|
struct stats_channel *c = (void *) C;
|
|
|
|
|
|
|
|
mb_free(c->counters);
|
2022-07-21 14:54:13 +00:00
|
|
|
|
|
|
|
/* FIXME freed automatically by the resource pool ?
|
|
|
|
rfree(c->timer);
|
|
|
|
*/
|
2022-07-19 08:21:43 +00:00
|
|
|
|
|
|
|
c->max_generation = 0;
|
|
|
|
c->counters = NULL;
|
|
|
|
c->pool = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
2022-07-13 13:39:14 +00:00
|
|
|
|
|
|
|
struct protocol proto_stats = {
|
|
|
|
.name = "Stats",
|
|
|
|
.template = "stat%d",
|
2022-07-14 12:51:03 +00:00
|
|
|
.channel_mask = NB_ANY,
|
2022-07-13 13:39:14 +00:00
|
|
|
.proto_size = sizeof(struct stats_proto),
|
|
|
|
.config_size = sizeof(struct stats_config),
|
|
|
|
.init = stats_init,
|
2022-07-14 15:08:03 +00:00
|
|
|
.start = stats_start,
|
2022-07-13 13:39:14 +00:00
|
|
|
.reconfigure = stats_reconfigure,
|
|
|
|
.show_proto_info = stats_show_proto_info
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
stats_build(void)
|
|
|
|
{
|
|
|
|
proto_build(&proto_stats);
|
|
|
|
}
|