From 925fe2d3de0e12c644f91f94d13bf388aeda9b57 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Thu, 4 Jun 2009 01:22:56 +0200 Subject: [PATCH] Implements route statistics and fixes some minor bugs. --- doc/bird.sgml | 2 +- nest/proto.c | 30 +++++++++++++++++-- nest/protocol.h | 26 ++++++++++++++++ nest/rt-table.c | 79 +++++++++++++++++++++++++++++++++++++++++++------ 4 files changed, 124 insertions(+), 13 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index 5027c3e4..c504dbb8 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -1450,7 +1450,7 @@ of routes from the primary table to the secondary one, import filters control th direction.

The Pipe protocol may work in the opaque mode or in the transparent -mode. In the opaque mode, thee Pipe protocol retransmits optimal route +mode. In the opaque mode, the Pipe protocol retransmits optimal route from one table to the other table in a similar way like other protocols send and receive routes. Retransmitted route will have the source set to the Pipe protocol, which may limit access to protocol diff --git a/nest/proto.c b/nest/proto.c index 0ad7229c..ef0587b2 100644 --- a/nest/proto.c +++ b/nest/proto.c @@ -512,6 +512,9 @@ static void proto_fell_down(struct proto *p) { DBG("Protocol %s down\n", p->name); + ASSERT(p->stats.imp_routes == 0); + + bzero(&p->stats, sizeof(struct proto_stats)); rt_unlock_table(p->table); proto_rethink_goal(p); } @@ -693,9 +696,30 @@ proto_do_show(struct proto *p, int verbose) buf); if (verbose) { - cli_msg(-1006, "\tPreference: %d", p->preference); - cli_msg(-1006, "\tInput filter: %s", filter_name(p->in_filter)); - cli_msg(-1006, "\tOutput filter: %s", filter_name(p->out_filter)); + cli_msg(-1006, " Preference: %d", p->preference); + cli_msg(-1006, " Input filter: %s", filter_name(p->in_filter)); + cli_msg(-1006, " Output filter: %s", filter_name(p->out_filter)); + + if (p->proto_state != PS_DOWN) + { + cli_msg(-1006, " Routes: %u imported, %u exported, %u preferred", + p->stats.imp_routes, p->stats.exp_routes, p->stats.pref_routes); + cli_msg(-1006, " Route change stats: received rejected filtered ignored accepted"); + cli_msg(-1006, " Import updates: %10u %10u %10u %10u %10u", + p->stats.imp_updates_received, p->stats.imp_updates_invalid, + p->stats.imp_updates_filtered, p->stats.imp_updates_ignored, + p->stats.imp_updates_accepted); + cli_msg(-1006, " Import withdraws: %10u %10u --- %10u %10u", + p->stats.imp_withdraws_received, p->stats.imp_withdraws_invalid, + p->stats.imp_withdraws_ignored, p->stats.imp_withdraws_accepted); + cli_msg(-1006, " Export updates: %10u %10u %10u --- %10u", + p->stats.exp_updates_received, p->stats.exp_updates_rejected, + p->stats.exp_updates_filtered, p->stats.exp_updates_accepted); + cli_msg(-1006, " Export withdraws: %10u --- --- --- %10u", + p->stats.exp_withdraws_received, p->stats.exp_withdraws_accepted); + } + + cli_msg(-1006, ""); } } diff --git a/nest/protocol.h b/nest/protocol.h index 865b2b38..eee3a746 100644 --- a/nest/protocol.h +++ b/nest/protocol.h @@ -87,6 +87,31 @@ struct proto_config { /* Protocol-specific data follow... */ }; + /* Protocol statistics */ +struct proto_stats { + /* Import - from protocol to core */ + u32 imp_routes; /* Number of routes successfully imported to the (adjacent) routing table */ + u32 pref_routes; /* Number of routes that are preferred, sum over all routing table */ + u32 imp_updates_received; /* Number of route updates received */ + u32 imp_updates_invalid; /* Number of route updates rejected as invalid */ + u32 imp_updates_filtered; /* Number of route updates rejected by filters */ + u32 imp_updates_ignored; /* Number of route updates rejected as already in route table */ + u32 imp_updates_accepted; /* Number of route updates accepted and imported */ + u32 imp_withdraws_received; /* Number of route withdraws received */ + u32 imp_withdraws_invalid; /* Number of route withdraws rejected as invalid */ + u32 imp_withdraws_ignored; /* Number of route withdraws rejected as already not in route table */ + u32 imp_withdraws_accepted; /* Number of route withdraws accepted and processed */ + + /* Export - from core to protocol */ + u32 exp_routes; /* Number of routes successfully exported to the protocol */ + u32 exp_updates_received; /* Number of route updates received */ + u32 exp_updates_rejected; /* Number of route updates rejected by protocol */ + u32 exp_updates_filtered; /* Number of route updates rejected by filters */ + u32 exp_updates_accepted; /* Number of route updates accepted and exported */ + u32 exp_withdraws_received; /* Number of route withdraws received */ + u32 exp_withdraws_accepted; /* Number of route withdraws accepted and processed */ +}; + struct proto { node n; /* Node in *_proto_list */ node glob_node; /* Node in global proto_list */ @@ -109,6 +134,7 @@ struct proto { u32 hash_key; /* Random key used for hashing of neighbors */ bird_clock_t last_state_change; /* Time of last state transition */ char *last_state_name_announced; /* Last state name we've announced to the user */ + struct proto_stats stats; /* Current protocol statistics */ /* * General protocol hooks: diff --git a/nest/rt-table.c b/nest/rt-table.c index d608117b..fb2feaca 100644 --- a/nest/rt-table.c +++ b/nest/rt-table.c @@ -167,16 +167,27 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, if (new) { + p->stats.exp_updates_received++; + char *drop_reason = NULL; if ((class & IADDR_SCOPE_MASK) < p->min_scope) - drop_reason = "out of scope"; + { + p->stats.exp_updates_rejected++; + drop_reason = "out of scope"; + } else if ((ok = p->import_control ? p->import_control(p, &new, &tmpa, rte_update_pool) : 0) < 0) - drop_reason = "rejected by protocol"; + { + p->stats.exp_updates_rejected++; + drop_reason = "rejected by protocol"; + } else if (ok) rte_trace_out(D_FILTERS, p, new, "forced accept by protocol"); else if (p->out_filter == FILTER_REJECT || p->out_filter && f_run(p->out_filter, &new, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT) - drop_reason = "filtered out"; + { + p->stats.exp_updates_filtered++; + drop_reason = "filtered out"; + } if (drop_reason) { rte_trace_out(D_FILTERS, p, new, drop_reason); @@ -185,7 +196,10 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, new = NULL; } } - if (old && p->out_filter) + else + p->stats.exp_withdraws_received++; + + if (old) { if (p->out_filter == FILTER_REJECT) old = NULL; @@ -193,7 +207,7 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, { ea_list *tmpb = p->make_tmp_attrs ? p->make_tmp_attrs(old, rte_update_pool) : NULL; ok = p->import_control ? p->import_control(p, &old, &tmpb, rte_update_pool) : 0; - if (ok < 0 || (!ok && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) + if (ok < 0 || (!ok && p->out_filter && f_run(p->out_filter, &old, &tmpb, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)) { if (old != old0) rte_free(old); @@ -201,6 +215,20 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, } } } + + if (!new && !old) + return; + + if (new) + p->stats.exp_updates_accepted++; + else + p->stats.exp_withdraws_accepted++; + + if (new) + p->stats.exp_routes++; + if (old) + p->stats.exp_routes--; + if (p->debug & D_ROUTES) { if (new && old) @@ -210,8 +238,6 @@ do_rte_announce(struct announce_hook *a, int type, net *net, rte *new, rte *old, else if (old) rte_trace_out(D_ROUTES, p, old, "removed"); } - if (!new && !old) - return; if (!new) p->rt_notify(p, net, NULL, old, NULL); else if (tmpa) @@ -266,6 +292,14 @@ rte_announce(rtable *tab, int type, net *net, rte *new, rte *old, ea_list *tmpa) struct announce_hook *a; int class = ipa_classify(net->n.prefix); + if (type == RA_OPTIMAL) + { + if (new) + new->attrs->proto->stats.pref_routes++; + if (old) + old->attrs->proto->stats.pref_routes--; + } + WALK_LIST(a, tab->hooks) { ASSERT(a->proto->core_state == FS_HAPPY || a->proto->core_state == FS_FEEDING); @@ -363,6 +397,7 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte if (new && rte_same(old, new)) { /* No changes, ignore the new route */ + p->stats.imp_updates_ignored++; rte_trace_in(D_ROUTES, p, new, "ignored"); rte_free_quick(new); old->lastmod = now; @@ -374,6 +409,22 @@ rte_recalculate(rtable *table, net *net, struct proto *p, struct proto *src, rte k = &old->next; } + if (!old && !new) + { + p->stats.imp_withdraws_ignored++; + return; + } + + if (new) + p->stats.imp_updates_accepted++; + else + p->stats.imp_withdraws_accepted++; + + if (new) + p->stats.imp_routes++; + if (old) + p->stats.imp_routes--; + rte_announce(table, RA_ANY, net, new, old, tmpa); if (new && rte_better(new, old_best)) /* It's a new optimal route => announce and relink it */ @@ -514,13 +565,16 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new if (p->table != table) filter = FILTER_ACCEPT; + p->stats.imp_updates_received++; if (!rte_validate(new)) { rte_trace_in(D_FILTERS, p, new, "invalid"); + p->stats.imp_updates_invalid++; goto drop; } if (filter == FILTER_REJECT) { + p->stats.imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -532,6 +586,7 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new int fr = f_run(filter, &new, &tmpa, rte_update_pool, 0); if (fr > F_ACCEPT) { + p->stats.imp_updates_filtered++; rte_trace_in(D_FILTERS, p, new, "filtered out"); goto drop; } @@ -542,6 +597,9 @@ rte_update(rtable *table, net *net, struct proto *p, struct proto *src, rte *new new->attrs = rta_lookup(new->attrs); new->flags |= REF_COW; } + else + p->stats.imp_withdraws_received++; + rte_recalculate(table, net, p, src, new, tmpa); rte_update_unlock(); return; @@ -1025,8 +1083,11 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d) if (p2 && p2 != p0) ok = 0; if (ok && d->export_mode) { - int ic = (p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0); - if (ic < 0) + int class = ipa_classify(n->n.prefix); + int ic; + if ((class & IADDR_SCOPE_MASK) < p1->min_scope) + ok = 0; + else if ((ic = p1->import_control ? p1->import_control(p1, &e, &tmpa, rte_update_pool) : 0) < 0) ok = 0; else if (!ic && d->export_mode > 1) {