diff --git a/proto/stats/config.Y b/proto/stats/config.Y index cf9a9066..e66f18d1 100644 --- a/proto/stats/config.Y +++ b/proto/stats/config.Y @@ -1,7 +1,8 @@ /* - * BIRD -- Table-to-Table Protocol Configuration + * BIRD -- Statistics Protocol Configuration * - * (c) 1999 Martin Mares + * (c) 2022 Vojtech Vilimek + * (c) 2022 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -19,8 +20,9 @@ CF_DEFINES CF_DECLS /* TODO here add more keywords */ -/* old: CF_KEYWORDS(PIPE, PEER, TABLE, MAX, GENERATION) */ -CF_KEYWORDS(STATS, PEER, TABLE, MAX, GENERATION) +CF_KEYWORDS(STATS, TABLE, MAX, GENERATION) + +%type stats_channel_start CF_GRAMMAR @@ -31,31 +33,21 @@ stats_proto_start: proto_start STATS this_proto = proto_config_new(&proto_stats, $1); STATS_CFG->max_generation = 16; } -proto_name + +proto_name ; + +stats_proto_channel: stats_channel_start channel_opt_list channel_end ; + +stats_channel_start: net_type symbol { - this_channel = proto_cf_main_channel(this_proto); - if (!this_channel) { - this_channel = channel_config_new(NULL, NULL, 0, this_proto); - this_channel->in_filter = FILTER_ACCEPT; - this_channel->out_filter = FILTER_ACCEPT; - } -}; + $$ = this_channel = channel_config_get(NULL, $2->name, $1, this_proto); +} stats_proto: stats_proto_start '{' | stats_proto proto_item ';' - | stats_proto channel_item_ ';' - | stats_proto IMPORT IN net_any imexport ';' { - if (this_channel->net_type && ($4->type != this_channel->net_type)) - cf_error("Incompatible export prefilter type"); - STATS_CFG->in_subprefix = $4; - this_channel->in_filter = $5; - } - | stats_proto PEER TABLE rtable ';' { STATS_CFG->peer = $4; } - | stats_proto MAX GENERATION expr ';' { - if (($4 < 1) || ($4 > 254)) cf_error("Max generation must be in range 1..254, got %u", $4); - STATS_CFG->max_generation = $4; - } + | stats_proto stats_proto_channel ';' + | stats_proto ';' ; CF_CODE diff --git a/proto/stats/stats.c b/proto/stats/stats.c index c4af70f1..8f240710 100644 --- a/proto/stats/stats.c +++ b/proto/stats/stats.c @@ -1,33 +1,15 @@ /* * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe * - * (c) 1999--2000 Martin Mares + * (c) 2022 Vojtech Vilimek + * (c) 2022 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. */ /** - * DOC: Pipe + * DOC: Stats * - * The Pipe protocol is very simple. It just connects to two routing tables - * using proto_add_announce_hook() and whenever it receives a rt_notify() - * about a change in one of the tables, it converts it to a rte_update() - * in the other one. - * - * To avoid pipe loops, Pipe keeps a `being updated' flag in each routing - * table. - * - * A pipe has two announce hooks, the first connected to the main - * table, the second connected to the peer table. When a new route is - * announced on the main table, it gets checked by an export filter in - * ahook 1, and, after that, it is announced to the peer table via - * rte_update(), an import filter in ahook 2 is called. When a new - * route is announced in the peer table, an export filter in ahook2 - * and an import filter in ahook 1 are used. Oviously, there is no - * need in filtering the same route twice, so both import filters are - * set to accept, while user configured 'import' and 'export' filters - * are used as export filters in ahooks 2 and 1. Route limits are - * handled similarly, but on the import side of ahooks. */ #undef LOCAL_DEBUG @@ -51,25 +33,6 @@ static void stats_rt_notify(struct proto *P, struct channel *src_ch, const net_addr *n, rte *new, const rte *old) { struct stats_proto *p = (void *) P; - struct channel *dst = (src_ch == p->pri) ? p->sec : p->pri; - - if (!new && !old) - return; - - if (new) - { - rte e0 = { - .attrs = new->attrs, - .src = new->src, - .generation = new->generation + 1, - }; - - ea_unset_attr(&e0.attrs, 0, &ea_gen_hostentry); - - rte_update(dst, n, &e0, new->src); - } - else - rte_update(dst, n, NULL, old->src); } static int @@ -77,21 +40,6 @@ stats_preexport(struct channel *c, rte *e) { struct stats_proto *p = (void *) c->proto; - /* Avoid direct loopbacks */ - if (e->sender == c->in_req.hook) - return -1; - - /* Indirection check */ - uint max_generation = ((struct stats_config *) p->p.cf)->max_generation; - if (e->generation >= max_generation) - { - log_rl(&p->rl_gen, L_ERR "Route overpiped (%u hops of %u configured in %s) in table %s: %N %s/%u:%u", - e->generation, max_generation, c->proto->name, - c->table->name, e->net, e->src->proto->name, e->src->private_id, e->src->global_id); - - return -1; - } - return 0; } @@ -101,77 +49,10 @@ stats_reload_routes(struct channel *C) struct stats_proto *p = (void *) C->proto; /* Route reload on one channel is just refeed on the other */ - channel_request_feeding((C == p->pri) ? p->sec : p->pri); + channel_request_feeding(p->c); } -static void -stats_postconfig(struct proto_config *CF) -{ - struct stats_config *cf = (void *) CF; - struct channel_config *cc = proto_cf_main_channel(CF); - - if (!cc->table) - cf_error("Primary routing table not specified"); - - if (!cf->peer) - cf_error("Secondary routing table not specified"); - - if (cc->table == cf->peer) - cf_error("Primary table and peer table must be different"); - - if (cc->table->addr_type != cf->peer->addr_type) - cf_error("Primary table and peer table must have the same type"); - - if (cc->out_subprefix && (cc->table->addr_type != cc->out_subprefix->type)) - cf_error("Export subprefix must match table type"); - - if (cf->in_subprefix && (cc->table->addr_type != cf->in_subprefix->type)) - cf_error("Import subprefix must match table type"); - - if (cc->rx_limit.action) - cf_error("Pipe protocol does not support receive limits"); - - if (cc->in_keep) - cf_error("Pipe protocol prohibits keeping filtered routes"); - - cc->debug = cf->c.debug; -} - -static int -stats_configure_channels(struct stats_proto *s, struct stats_config *cf) -{ - struct channel_config *cc = proto_cf_main_channel(&cf->c); - - struct channel_config pri_cf = { - .name = "pri", - .channel = cc->channel, - .table = cc->table, - .out_filter = cc->out_filter, - .out_subprefix = cc->out_subprefix, - .in_limit = cc->in_limit, - .ra_mode = RA_ANY, - .debug = cc->debug, - .rpki_reload = cc->rpki_reload, - }; - - struct channel_config sec_cf = { - .name = "sec", - .channel = cc->channel, - .table = cf->peer, - .out_filter = cc->in_filter, - .out_subprefix = cf->in_subprefix, - .in_limit = cc->out_limit, - .ra_mode = RA_ANY, - .debug = cc->debug, - .rpki_reload = cc->rpki_reload, - }; - - return - proto_configure_channel(&s->p, &s->pri, &pri_cf) && - proto_configure_channel(&s->p, &s->sec, &sec_cf); -} - static struct proto * stats_init(struct proto_config *CF) { @@ -185,7 +66,12 @@ stats_init(struct proto_config *CF) p->rl_gen = (struct tbf) TBF_DEFAULT_LOG_LIMITS; - stats_configure_channels(p, cf); + struct channel_config *cc; + WALK_LIST(cc, CF->channels) + { + struct channel *c = NULL; + proto_configure_channel(P, &c, cc); + } return P; } @@ -196,7 +82,8 @@ stats_reconfigure(struct proto *P, struct proto_config *CF) struct stats_proto *p = (void *) P; struct stats_config *cf = (void *) CF; - return stats_configure_channels(p, cf); + //return stats_configure_channels(p, cf); + return 1; } static void @@ -209,62 +96,12 @@ static void stats_get_status(struct proto *P, byte *buf) { struct stats_proto *p = (void *) P; - - bsprintf(buf, "%s <=> %s", p->pri->table->name, p->sec->table->name); } static void stats_show_stats(struct stats_proto *p) { - struct channel_import_stats *s1i = &p->pri->import_stats; - struct channel_export_stats *s1e = &p->pri->export_stats; - struct channel_import_stats *s2i = &p->sec->import_stats; - struct channel_export_stats *s2e = &p->sec->export_stats; - struct rt_import_stats *rs1i = p->pri->in_req.hook ? &p->pri->in_req.hook->stats : NULL; - struct rt_export_stats *rs1e = p->pri->out_req.hook ? &p->pri->out_req.hook->stats : NULL; - struct rt_import_stats *rs2i = p->sec->in_req.hook ? &p->sec->in_req.hook->stats : NULL; - struct rt_export_stats *rs2e = p->sec->out_req.hook ? &p->sec->out_req.hook->stats : NULL; - - u32 pri_routes = p->pri->in_limit.count; - u32 sec_routes = p->sec->in_limit.count; - - /* - * Pipe stats (as anything related to pipes) are a bit tricky. There - * are two sets of stats - s1 for ahook to the primary routing and - * s2 for the ahook to the secondary routing table. The user point - * of view is that routes going from the primary routing table to - * the secondary routing table are 'exported', while routes going in - * the other direction are 'imported'. - * - * Each route going through a pipe is, technically, first exported - * to the pipe and then imported from that pipe and such operations - * are counted in one set of stats according to the direction of the - * route propagation. Filtering is done just in the first part - * (export). Therefore, we compose stats for one directon for one - * user direction from both import and export stats, skipping - * immediate and irrelevant steps (exp_updates_accepted, - * imp_updates_received, imp_updates_filtered, ...). - * - * Rule of thumb is that stats s1 have the correct 'polarity' - * (imp/exp), while stats s2 have switched 'polarity'. - */ - - cli_msg(-1006, " Routes: %u imported, %u exported", - pri_routes, sec_routes); - cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); - cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", - rs2e->updates_received, s2e->updates_rejected + s1i->updates_invalid, - s2e->updates_filtered, rs1i->updates_ignored, rs1i->updates_accepted); - cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", - rs2e->withdraws_received, s1i->withdraws_invalid, - rs1i->withdraws_ignored, rs1i->withdraws_accepted); - cli_msg(-1006, " Export updates: %10u %10u %10u %10u %10u", - rs1e->updates_received, s1e->updates_rejected + s2i->updates_invalid, - s1e->updates_filtered, rs2i->updates_ignored, rs2i->updates_accepted); - cli_msg(-1006, " Export withdraws: %10u %10u --- %10u %10u", - rs1e->withdraws_received, s2i->withdraws_invalid, - rs2i->withdraws_ignored, rs2i->withdraws_accepted); } static void @@ -272,23 +109,6 @@ stats_show_proto_info(struct proto *P) { struct stats_proto *p = (void *) P; - cli_msg(-1006, " Channel %s", "main"); - cli_msg(-1006, " Table: %s", p->pri->table->name); - cli_msg(-1006, " Peer table: %s", p->sec->table->name); - cli_msg(-1006, " Import state: %s", rt_export_state_name(rt_export_get_state(p->sec->out_req.hook))); - cli_msg(-1006, " Export state: %s", rt_export_state_name(rt_export_get_state(p->pri->out_req.hook))); - cli_msg(-1006, " Import filter: %s", filter_name(p->sec->out_filter)); - cli_msg(-1006, " Export filter: %s", filter_name(p->pri->out_filter)); - - - - channel_show_limit(&p->pri->in_limit, "Import limit:", - (p->pri->limit_active & (1 << PLD_IN)), p->pri->limit_actions[PLD_IN]); - channel_show_limit(&p->sec->in_limit, "Export limit:", - (p->sec->limit_active & (1 << PLD_IN)), p->sec->limit_actions[PLD_IN]); - - if (P->proto_state != PS_DOWN) - stats_show_stats(p); } void @@ -296,16 +116,16 @@ stats_update_debug(struct proto *P) { struct stats_proto *p = (void *) P; - p->pri->debug = p->sec->debug = p->p.debug; + p->c->debug = p->p.debug; } 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), - .postconfig = stats_postconfig, .init = stats_init, .reconfigure = stats_reconfigure, .copy_config = stats_copy_config, diff --git a/proto/stats/stats.h b/proto/stats/stats.h index 2634e51a..6d448d4b 100644 --- a/proto/stats/stats.h +++ b/proto/stats/stats.h @@ -1,7 +1,8 @@ /* * BIRD -- Table-to-Table Routing Protocol a.k.a Pipe * - * (c) 1999 Martin Mares + * (c) 2022 Vojtech Vilimek + * (c) 2022 CZ.NIC z.s.p.o. * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -11,15 +12,13 @@ struct stats_config { struct proto_config c; - struct rtable_config *peer; /* Table we're connected to */ const net_addr *in_subprefix; u8 max_generation; }; struct stats_proto { struct proto p; - struct channel *pri; - struct channel *sec; + struct channel *c; struct tbf rl_gen; };