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:
parent
68fa95cfec
commit
a3b70dc499
2 changed files with 221 additions and 2 deletions
|
@ -263,6 +263,12 @@ CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show i
|
||||||
CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
|
CF_CLI(SHOW OSPF INTERFACE, optsym opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
|
||||||
{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
|
{ 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_CODE
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
* and conserves memory.
|
* and conserves memory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include "ospf.h"
|
#include "ospf.h"
|
||||||
|
|
||||||
static int ospf_rte_better(struct rte *new, struct rte *old);
|
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, "");
|
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 = {
|
struct protocol proto_ospf = {
|
||||||
name:"OSPF",
|
name:"OSPF",
|
||||||
template:"ospf%d",
|
template:"ospf%d",
|
||||||
|
|
Loading…
Reference in a new issue