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.
This commit is contained in:
Ondrej Zajicek 2008-10-27 00:03:30 +01:00
parent 68fa95cfec
commit a3b70dc499
2 changed files with 221 additions and 2 deletions

View file

@ -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

View file

@ -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",