Fixes and enhancements in 'show ospf state' command.

Now it shows a distance, option to change showing reachable/all network
nodes and better handling of AS-external LSAs in multiple areas. The
command 'show ospf topology' was changed to not show stubnets in both
OSPFv2 and OSPFv3 (previously it displayed stubnets in OSPFv2).
This commit is contained in:
Ondrej Zajicek 2010-04-24 15:18:21 +02:00
parent 1d44ddf20f
commit 0ea8fb4abe
8 changed files with 208 additions and 74 deletions

View file

@ -490,13 +490,18 @@ This argument can be omitted if there exists only a single instance.
<tag>show ospf neighbors [<m/name/] ["<m/interface/"]</tag>
Show a list of OSPF neighbors and a state of adjacency to them.
<tag>show ospf state [<m/name/]</tag>
Show detailed information about OSPF areas based on a content of link-state database.
It shows network topology, aggregated networks and routers from other areas and external routes.
<tag>show ospf state [all] [<m/name/]</tag>
Show detailed information about OSPF areas based on a content
of the link-state database. It shows network topology, stub
networks, aggregated networks and routers from other areas and
external routes. The command shows information about reachable
network nodes, use option <cf/all/ to show information about
all network nodes in the link-state database.
<tag>show ospf topology [<m/name/]</tag>
Show a topology of OSPF areas based on a content of link-state database.
It is just a stripped-down version of 'show ospf state'.
<tag>show ospf topology [all] [<m/name/]</tag>
Show a topology of OSPF areas based on a content of the
link-state database. It is just a stripped-down version of
'show ospf state'.
<tag>show static [<m/name/]</tag>
Show detailed information about static routes.

View file

@ -314,11 +314,21 @@ CF_CLI(SHOW OSPF NEIGHBORS, optsym opttext, [<name>] [\"<interface>\"], [[Show i
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_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
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_CLI(SHOW OSPF TOPOLOGY, optsym opttext, [<name>], [[Show information about reachable OSPF network topology]])
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 0, 1); };
CF_CLI(SHOW OSPF TOPOLOGY ALL, optsym opttext, [<name>], [[Show information about all OSPF network topology]])
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 0, 0); };
CF_CLI_HELP(SHOW OSPF STATE, [all] [<name>], [[Show information about OSPF network state]])
CF_CLI(SHOW OSPF STATE, optsym opttext, [<name>], [[Show information about reachable OSPF network state]])
{ ospf_sh_state(proto_get_named($4, &proto_ospf), 1, 1); };
CF_CLI(SHOW OSPF STATE ALL, optsym opttext, [<name>], [[Show information about all OSPF network state]])
{ ospf_sh_state(proto_get_named($5, &proto_ospf), 1, 0); };
CF_CLI(SHOW OSPF LSADB, optsym opttext, [<name>], [[Show content of OSPF LSA database]])
{ ospf_sh_lsadb(proto_get_named($4, &proto_ospf)); };

View file

@ -804,5 +804,4 @@ ospf_iface_shutdown(struct ospf_iface *ifa)
{
init_list(&ifa->neigh_list);
hello_timer_hook(ifa->hello_timer);
ospf_sk_close(ifa);
}

View file

@ -45,19 +45,16 @@ ospf_age(struct proto_ospf *po)
struct top_hash_entry *en, *nxt;
int flush = can_flush_lsa(po);
if (po->cleanup) OSPF_TRACE(D_EVENTS, "Running ospf_age cleanup");
WALK_SLIST_DELSAFE(en, nxt, po->lsal)
{
if (po->cleanup)
if (po->calcrt)
{
/* Cleanup before ospf_rt_spf() */
en->color = OUTSPF;
en->dist = LSINFINITY;
en->nhi = NULL;
en->nh = IPA_NONE;
en->lb = IPA_NONE;
DBG("Infinitying Type: %u, Id: %R, Rt: %R\n", en->lsa.type,
en->lsa.id, en->lsa.rt);
}
if (en->lsa.age == LSA_MAXAGE)
{
@ -88,7 +85,6 @@ ospf_age(struct proto_ospf *po)
en->lsa.age = LSA_MAXAGE;
}
}
po->cleanup = 0;
}
void

View file

@ -75,7 +75,7 @@
*
* The function area_disp() is
* responsible for late originating of router LSA and network LSA
* and for cleanup after routing table calculation process in
* and for cleanup before routing table calculation process in
* the area.
* To every &ospf_iface, we connect one or more
* &ospf_neighbor's -- a structure containing many timers and queues
@ -161,7 +161,6 @@ ospf_start(struct proto *p)
fib_init(&po->rtf, p->pool, sizeof(ort), 16, ospf_rt_initort);
po->areano = 0;
po->gr = ospf_top_new(p->pool);
po->cleanup = 1;
s_init_list(&(po->lsal));
if (EMPTY_LIST(c->area_list))
{
@ -1134,8 +1133,34 @@ lsa_compare_for_state(const void *p1, const void *p2)
}
}
static int
ext_compare_for_state(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);
if (lsa1->rt != lsa2->rt)
return lsa1->rt - lsa2->rt;
if (lsa1->id != lsa2->id)
return lsa1->id - lsa2->id;
return lsa1->sn - lsa2->sn;
}
static inline void
show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he)
show_lsa_distance(struct top_hash_entry *he)
{
if (he->color == INSPF)
cli_msg(-1016, "\t\tdistance %u", he->dist);
else
cli_msg(-1016, "\t\tunreachable");
}
static inline void
show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he, int first, int verbose)
{
struct ospf_lsa_header *lsa = &(he->lsa);
struct ospf_lsa_rt *rt = he->lsa_body;
@ -1143,6 +1168,14 @@ show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he)
int max = lsa_rt_count(lsa);
int i;
if (first)
{
cli_msg(-1016, "");
cli_msg(-1016, "\trouter %R", he->lsa.rt);
show_lsa_distance(he);
}
for (i = 0; i < max; i++)
if (rr[i].type == LSART_VLNK)
cli_msg(-1016, "\t\tvlink %R metric %u", rr[i].id, rr[i].metric);
@ -1175,6 +1208,9 @@ show_lsa_router(struct proto_ospf *po, struct top_hash_entry *he)
}
#ifdef OSPFv2
if (!verbose)
return;
for (i = 0; i < max; i++)
if (rr[i].type == LSART_STUB)
cli_msg(-1016, "\t\tstubnet %I/%d metric %u", ipa_from_u32(rr[i].id),
@ -1198,6 +1234,8 @@ show_lsa_network(struct top_hash_entry *he)
cli_msg(-1016, "\tnetwork [%R-%u]", lsa->rt, lsa->id);
#endif
show_lsa_distance(he);
for (i = 0; i < lsa_net_count(lsa); i++)
cli_msg(-1016, "\t\trouter %R", ln->routers[i]);
}
@ -1251,6 +1289,8 @@ show_lsa_external(struct top_hash_entry *he)
int pxlen, ebit, rt_fwaddr_valid;
u32 rt_tag, rt_metric;
he->domain = 0; /* Unmark the LSA */
rt_metric = ext->metric & METRIC_MASK;
ebit = ext->metric & LSA_EXT_EBIT;
#ifdef OSPFv2
@ -1289,7 +1329,7 @@ show_lsa_external(struct top_hash_entry *he)
#ifdef OSPFv3
static inline void
show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa)
show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *cnode)
{
struct ospf_lsa_prefix *px = he->lsa_body;
ip_addr pxa;
@ -1299,10 +1339,14 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa)
u32 *buf;
int i;
/* We check whether given prefix-LSA is related to the last non-prefix-LSA */
if ((olsa == NULL) || (olsa->type != px->ref_type) || (olsa->rt != px->ref_rt) ||
!(((px->ref_type == LSA_T_RT) && (px->ref_id == 0)) ||
((px->ref_type == LSA_T_NET) && (px->ref_id == olsa->id))))
/* We check whether given prefix-LSA is related to the current node */
if ((px->ref_type != cnode->type) || (px->ref_rt != cnode->rt))
return;
if ((px->ref_type == LSA_T_RT) && (px->ref_id != 0))
return;
if ((px->ref_type == LSA_T_NET) && (px->ref_id != cnode->id))
return;
buf = px->rest;
@ -1319,18 +1363,14 @@ show_lsa_prefix(struct top_hash_entry *he, struct ospf_lsa_header *olsa)
#endif
void
ospf_sh_state(struct proto *p, int verbose)
ospf_sh_state(struct proto *p, int verbose, int reachable)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct top_graph *f = po->gr;
unsigned int i, j1, j2;
u32 last_rt = 0xFFFFFFFF;
struct ospf_lsa_header *cnode = NULL;
int num = po->gr->hash_entries;
unsigned int i, ix, j1, j2, jx;
u32 last_area = 0xFFFFFFFF;
#ifdef OSPFv3
struct ospf_lsa_header *olsa = NULL;
#endif
if (p->proto_state != PS_UP)
{
cli_msg(-1016, "%s: is not up", p->name);
@ -1338,10 +1378,14 @@ ospf_sh_state(struct proto *p, int verbose)
return;
}
struct top_hash_entry *hea[f->hash_entries];
/* We store interesting area-scoped LSAs in array hea and
global-scoped (LSA_T_EXT) LSAs in array hex */
struct top_hash_entry *hea[num];
struct top_hash_entry *hex[verbose ? num : 0];
struct top_hash_entry *he;
j1 = j2 = 0;
j1 = j2 = jx = 0;
WALK_SLIST(he, po->lsal)
{
int accept;
@ -1355,13 +1399,18 @@ ospf_sh_state(struct proto *p, int verbose)
case LSA_T_SUM_NET:
case LSA_T_SUM_RT:
case LSA_T_EXT:
#ifdef OSPFv3
case LSA_T_PREFIX:
#endif
accept = verbose;
break;
case LSA_T_EXT:
if (verbose)
{
he->domain = 1; /* Abuse domain field to mark the LSA */
hex[jx++] = he;
}
default:
accept = 0;
}
@ -1372,66 +1421,137 @@ ospf_sh_state(struct proto *p, int verbose)
j2++;
}
if ((j1 + j2) != f->hash_entries)
if ((j1 + j2) != num)
die("Fatal mismatch");
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
/*
* This code is a bit tricky, we have a primary LSAs (router and
* network) that are presented as a node, and secondary LSAs that
* are presented as a part of a primary node. cnode represents an
* currently opened node (whose header was presented). The LSAs are
* sorted to get secondary LSAs just after related primary LSA (if
* available). We present secondary LSAs only when related primary
* LSA is opened.
*
* AS-external LSAs are stored separately as they might be presented
* several times (for each area when related ASBR is opened). When
* the node is closed, related external routes are presented. We
* also have to take into account that in OSPFv3, there might be
* more router-LSAs and only the first should be considered as a
* primary. This is handled by not closing old router-LSA when next
* one is processed (which is not opened because there is already
* one opened).
*/
ix = 0;
for (i = 0; i < j1; i++)
{
if (last_area != hea[i]->domain)
he = hea[i];
/* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
if (!cnode)
{
if (((he->lsa.type == LSA_T_RT) || (he->lsa.type == LSA_T_NET))
&& ((he->color == INSPF) || !reachable))
{
cnode = &(he->lsa);
if (he->domain != last_area)
{
cli_msg(-1016, "");
cli_msg(-1016, "area %R", hea[i]->domain);
last_area = hea[i]->domain;
last_rt = 0xFFFFFFFF;
cli_msg(-1016, "area %R", he->domain);
last_area = he->domain;
ix = 0;
}
}
else
continue;
}
if ((hea[i]->lsa.rt != last_rt) && (hea[i]->lsa.type != LSA_T_NET)
#ifdef OSPFv3
&& (hea[i]->lsa.type != LSA_T_PREFIX)
#endif
)
{
cli_msg(-1016, "");
cli_msg(-1016, (hea[i]->lsa.type != LSA_T_EXT) ? "\trouter %R" : "\txrouter %R", hea[i]->lsa.rt);
last_rt = hea[i]->lsa.rt;
}
ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt));
switch (hea[i]->lsa.type)
switch (he->lsa.type)
{
case LSA_T_RT:
show_lsa_router(po, hea[i]);
show_lsa_router(po, he, he->lsa.id == cnode->id, verbose);
break;
case LSA_T_NET:
show_lsa_network(hea[i]);
show_lsa_network(he);
break;
case LSA_T_SUM_NET:
show_lsa_sum_net(hea[i]);
if (cnode->type == LSA_T_RT)
show_lsa_sum_net(he);
break;
case LSA_T_SUM_RT:
show_lsa_sum_rt(hea[i]);
break;
case LSA_T_EXT:
show_lsa_external(hea[i]);
if (cnode->type == LSA_T_RT)
show_lsa_sum_rt(he);
break;
#ifdef OSPFv3
case LSA_T_PREFIX:
show_lsa_prefix(hea[i], olsa);
show_lsa_prefix(he, cnode);
break;
#endif
case LSA_T_EXT:
show_lsa_external(he);
break;
}
#ifdef OSPFv3
if (hea[i]->lsa.type != LSA_T_PREFIX)
olsa = &(hea[i]->lsa);
#endif
/* In these cases, we close the current node */
if ((i+1 == j1)
|| (hea[i+1]->domain != last_area)
|| (hea[i+1]->lsa.rt != cnode->rt)
|| (hea[i+1]->lsa.type == LSA_T_NET))
{
while ((ix < jx) && (hex[ix]->lsa.rt < cnode->rt))
ix++;
while ((ix < jx) && (hex[ix]->lsa.rt == cnode->rt))
show_lsa_external(hex[ix++]);
cnode = NULL;
}
}
int hdr = 0;
u32 last_rt = 0xFFFFFFFF;
for (ix = 0; ix < jx; ix++)
{
he = hex[ix];
/* If it is still marked, we show it now. */
if (he->domain)
{
he->domain = 0;
if ((he->color != INSPF) && reachable)
continue;
if (!hdr)
{
cli_msg(-1016, "");
cli_msg(-1016, "other ASBRs");
hdr = 1;
}
if (he->lsa.rt != last_rt)
{
cli_msg(-1016, "");
cli_msg(-1016, "\trouter %R", he->lsa.rt);
last_rt = he->lsa.rt;
}
show_lsa_external(he);
}
}
cli_msg(0, "");
}
@ -1468,7 +1588,7 @@ void
ospf_sh_lsadb(struct proto *p)
{
struct proto_ospf *po = (struct proto_ospf *) p;
struct top_graph *f = po->gr;
int num = po->gr->hash_entries;
unsigned int i, j;
int last_dscope = -1;
u32 last_domain = 0;
@ -1480,14 +1600,14 @@ ospf_sh_lsadb(struct proto *p)
return;
}
struct top_hash_entry *hea[f->hash_entries];
struct top_hash_entry *hea[num];
struct top_hash_entry *he;
j = 0;
WALK_SLIST(he, po->lsal)
hea[j++] = he;
if (j != f->hash_entries)
if (j != num)
die("Fatal mismatch");
qsort(hea, j, sizeof(struct top_hash_entry *), lsa_compare_for_lsadb);

View file

@ -722,7 +722,6 @@ struct proto_ospf
slist lsal; /* List of all LSA's */
int calcrt; /* Routing table calculation scheduled?
0=no, 1=normal, 2=forced reload */
int cleanup; /* Should I cleanup after RT calculation? */
list iface_list; /* Interfaces we really use */
list area_list;
int areano; /* Number of area I belong to */
@ -808,7 +807,7 @@ static inline void schedule_link_lsa(struct ospf_iface *ifa UNUSED) {}
void ospf_sh_neigh(struct proto *p, char *iff);
void ospf_sh(struct proto *p);
void ospf_sh_iface(struct proto *p, char *iff);
void ospf_sh_state(struct proto *p, int verbose);
void ospf_sh_state(struct proto *p, int verbose, int reachable);
void ospf_sh_lsadb(struct proto *p);

View file

@ -681,6 +681,10 @@ ospf_rt_sum(struct ospf_area *oa)
if (!(abr->n.options & ORTA_ABR))
continue;
/* This check is not mentioned in RFC 2328 */
if (abr->n.type != RTS_OSPF)
continue;
/* 16.2. (5) */
orta nf = {
.type = RTS_OSPF_IA,
@ -966,6 +970,9 @@ ospf_ext_spf(struct proto_ospf *po)
nfa.metric2 = LSINFINITY;
}
/* Mark the LSA as reachable */
en->color = INSPF;
/* Whether the route is preferred in route selection according to 16.4.1 */
nfa.options = epath_preferred(&nf2->n) ? ORTA_PREF : 0;
@ -1046,8 +1053,6 @@ ospf_rt_spf(struct proto_ospf *po)
if (po->areano == 0) return;
po->cleanup = 1;
OSPF_TRACE(D_EVENTS, "Starting routing table calculation");
/* 16. (1) - Invalidate old routing table */

View file

@ -22,7 +22,7 @@ struct top_hash_entry
bird_clock_t inst_t; /* Time of installation into DB */
ip_addr nh; /* Next hop */
ip_addr lb; /* In OSPFv2, link back address. In OSPFv3, any global address in the area useful for vlinks */
struct ospf_iface *nhi; /* Next hop interface */
struct ospf_iface *nhi; /* Next hop interface - valid only in ospf_rt_spf()*/
#ifdef OSPFv3
u32 lb_id; /* Interface ID of link back iface (for bcast or NBMA networks) */
#endif