Commit a3b70dc4 authored by Ondřej Zajíček's avatar Ondřej Zajíček

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.
parent 68fa95cf
......@@ -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
......@@ -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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment