diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2008-10-27 00:03:30 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2008-10-27 00:03:30 +0100 |
commit | a3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6 (patch) | |
tree | 3f84228385adf271232d582f170cb40e7e711b17 | |
parent | 68fa95cfec78f1bfe790949bf747d578ad583ec2 (diff) | |
download | bird-a3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6.tar bird-a3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6.zip |
Two new informative CLI commands for OSPF.
Two new CLI commands for OSPF giving nice informative (and still machine
parsable) representation of OSPF network graph (based on datas from the
LSA database).
The first command (show ospf topology) shows routers, networks and stub
networks, The second command (show ospf state) shows also external
routes and area-external networks and routers propagated by given area
boundary router.
-rw-r--r-- | proto/ospf/config.Y | 10 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 213 |
2 files changed, 221 insertions, 2 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 0c6a408..dfcab4e 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -255,14 +255,20 @@ CF_ADDTO(dynamic_attr, OSPF_METRIC2 { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF CF_ADDTO(dynamic_attr, OSPF_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT | EAF_TEMP, T_INT, EA_OSPF_TAG); }) CF_CLI(SHOW OSPF, optsym, [<name>], [[Show information about OSPF protocol]]) -{ ospf_sh(proto_get_named($3, &proto_ospf)); } ; +{ ospf_sh(proto_get_named($3, &proto_ospf)); }; CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]]) -{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); } ; +{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); }; CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]]) { ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); }; +CF_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[Show information about OSPF network topology]]) +{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0); }; + +CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about OSPF network state]]) +{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1); }; + CF_CODE CF_END diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c index b382df0..1fce709 100644 --- a/proto/ospf/ospf.c +++ b/proto/ospf/ospf.c @@ -73,6 +73,7 @@ * and conserves memory. */ +#include <stdlib.h> #include "ospf.h" static int ospf_rte_better(struct rte *new, struct rte *old); @@ -982,6 +983,218 @@ ospf_sh_iface(struct proto *p, char *iff) cli_msg(0, ""); } +/* First we want to separate network-LSAs and other LSAs (because network-LSAs + * will be presented as network nodes and other LSAs together as router nodes) + * Network-LSAs are sorted according to network prefix, other LSAs are sorted + * according to originating router id (to get all LSA needed to represent one + * router node together). Then, according to LSA type, ID and age. + */ +static int +he_compare(const void *p1, const void *p2) +{ + struct top_hash_entry * he1 = * (struct top_hash_entry **) p1; + struct top_hash_entry * he2 = * (struct top_hash_entry **) p2; + struct ospf_lsa_header *lsa1 = &(he1->lsa); + struct ospf_lsa_header *lsa2 = &(he2->lsa); + int nt1 = (lsa1->type == LSA_T_NET); + int nt2 = (lsa2->type == LSA_T_NET); + + if (he1->oa->areaid != he2->oa->areaid) + return he1->oa->areaid - he2->oa->areaid; + + if (nt1 != nt2) + return nt1 - nt2; + + if (nt1) + { + // we are cheating for now + if (lsa1->id != lsa2->id) + return lsa1->id - lsa2->id; + + return lsa1->age - lsa2->age; + } + else + { + if (lsa1->rt != lsa2->rt) + return lsa1->rt - lsa2->rt; + + if (lsa1->type != lsa2->type) + return lsa1->type - lsa2->type; + + if (lsa1->id != lsa2->id) + return lsa1->id - lsa2->id; + + return lsa1->age - lsa2->age; + } +} + +static inline void +show_lsa_router(struct top_hash_entry *he) +{ + struct ospf_lsa_header *lsa = &(he->lsa); + struct ospf_lsa_rt *rt = he->lsa_body; + struct ospf_lsa_rt_link *rr = (struct ospf_lsa_rt_link *) (rt + 1); + u32 i; + + for (i = 0; i < rt->links; i++) + if (rr[i].type == LSART_PTP) + cli_msg(-1016, "\t\trouter %I metric %u ", rr[i].id, rr[i].metric); + + for (i = 0; i < rt->links; i++) + if (rr[i].type == LSART_NET) + { + struct proto_ospf *po = he->oa->po; + struct top_hash_entry *net_he = ospf_hash_find(po->gr, he->oa->areaid, rr[i].id, rr[i].id, LSA_T_NET); + if (net_he) + { + struct ospf_lsa_header *net_lsa = &(net_he->lsa); + struct ospf_lsa_net *net_ln = net_he->lsa_body; + cli_msg(-1016, "\t\tnetwork %I/%d metric %u ", ipa_and(ipa_from_u32(net_lsa->id), net_ln->netmask), ipa_mklen(net_ln->netmask), rr[i].metric); + } + else + cli_msg(-1016, "\t\tnetwork ??? metric %u ", rr[i].id, ipa_mklen(rr[i].data), rr[i].metric); + } + + for (i = 0; i < rt->links; i++) + if (rr[i].type == LSART_STUB) + cli_msg(-1016, "\t\tstubnet %I/%d metric %u ", rr[i].id, ipa_mklen(rr[i].data), rr[i].metric); + + for (i = 0; i < rt->links; i++) + if (rr[i].type == LSART_VLNK) + cli_msg(-1016, "\t\tvlink %I metric %u ", rr[i].id, rr[i].metric); +} + +static inline void +show_lsa_network(struct top_hash_entry *he) +{ + struct ospf_lsa_header *lsa = &(he->lsa); + struct ospf_lsa_net *ln = he->lsa_body; + u32 *rts = (u32 *) (ln + 1); + u32 max = (lsa->length - sizeof(struct ospf_lsa_header) - sizeof(struct ospf_lsa_net)) / sizeof(u32); + u32 i; + + cli_msg(-1016, ""); + cli_msg(-1016, "\tnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), ln->netmask), ipa_mklen(ln->netmask)); + cli_msg(-1016, "\t\tdr %I", lsa->rt); + + for (i = 0; i < max; i++) + cli_msg(-1016, "\t\trouter %I", rts[i]); +} + +static inline void +show_lsa_sum_net(struct top_hash_entry *he) +{ + struct ospf_lsa_header *lsa = &(he->lsa); + struct ospf_lsa_sum *sm = he->lsa_body; + + cli_msg(-1016, "\t\txnetwork %I/%d", ipa_and(ipa_from_u32(lsa->id), sm->netmask), ipa_mklen(sm->netmask)); +} + +static inline void +show_lsa_sum_rt(struct top_hash_entry *he) +{ + cli_msg(-1016, "\t\txrouter %I", he->lsa.id); +} + + +static inline void +show_lsa_external(struct top_hash_entry *he) +{ + struct ospf_lsa_header *lsa = &(he->lsa); + struct ospf_lsa_ext *ext = he->lsa_body; + struct ospf_lsa_ext_tos *et = (struct ospf_lsa_ext_tos *) (ext + 1); + + char str_via[STD_ADDRESS_P_LENGTH + 8] = ""; + char str_tag[16] = ""; + + if (et->fwaddr) + bsprintf(str_via, " via %I", et->fwaddr); + + if (et->tag) + bsprintf(str_tag, " tag %08x", et->tag); + + cli_msg(-1016, "\t\texternal %I/%d metric%s %u%s%s", + ipa_and(ipa_from_u32(lsa->id), ext->netmask), + ipa_mklen(ext->netmask), et->etm.etos.ebit ? "2" : "", + et->etm.metric & METRIC_MASK, str_via, str_tag); +} + + +void +ospf_sh_state(struct proto *p, int verbose) +{ + struct proto_ospf *po = (struct proto_ospf *) p; + struct top_graph *f = po->gr; + unsigned int i, j; + u32 last_rt = 0xFFFFFFFF; + u32 last_area = 0xFFFFFFFF; + + if (p->proto_state != PS_UP) + { + cli_msg(-1016, "%s: is not up", p->name); + cli_msg(0, ""); + return; + } + + struct top_hash_entry *hea[f->hash_entries]; + struct top_hash_entry *he; + + j = 0; + for (i = 0; i < f->hash_size; i++) + for (he = f->hash_table[i]; he != NULL; he = he->next) + hea[j++] = he; + + if (j == f->hash_size) + die("Fatal mismatch"); + + qsort(hea, j, sizeof(struct top_hash_entry *), he_compare); + + for (i = 0; i < j; i++) + { + if ((verbose == 0) && (hea[i]->lsa.type > LSA_T_NET)) + continue; + + if (last_area != hea[i]->oa->areaid) + { + cli_msg(-1016, ""); + cli_msg(-1016, "area %I", hea[i]->oa->areaid); + last_area = hea[i]->oa->areaid; + last_rt = 0xFFFFFFFF; + } + + if ((hea[i]->lsa.rt != last_rt) && (hea[i]->lsa.type != LSA_T_NET)) + { + cli_msg(-1016, ""); + cli_msg(-1016, (hea[i]->lsa.type != LSA_T_EXT) ? "\trouter %I" : "\txrouter %I", hea[i]->lsa.rt); + last_rt = hea[i]->lsa.rt; + } + + switch (hea[i]->lsa.type) + { + case LSA_T_RT: + show_lsa_router(hea[i]); + break; + + case LSA_T_NET: + show_lsa_network(hea[i]); + break; + + case LSA_T_SUM_NET: + show_lsa_sum_net(hea[i]); + break; + + case LSA_T_SUM_RT: + show_lsa_sum_rt(hea[i]); + break; + case LSA_T_EXT: + show_lsa_external(hea[i]); + break; + } + } + + cli_msg(0, ""); +} + struct protocol proto_ospf = { name:"OSPF", template:"ospf%d", |