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

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).
parent 1d44ddf2
......@@ -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 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 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 [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.
......
......@@ -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)); };
......
......@@ -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);
}
......@@ -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
......
......@@ -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_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)
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)
{
cli_msg(-1016, "");
cli_msg(-1016, "area %R", hea[i]->domain);
last_area = hea[i]->domain;
last_rt = 0xFFFFFFFF;
}
he = hea[i];
if ((hea[i]->lsa.rt != last_rt) && (hea[i]->lsa.type != LSA_T_NET)
#ifdef OSPFv3
&& (hea[i]->lsa.type != LSA_T_PREFIX)
#endif
)
/* If there is no opened node, we open the LSA (if appropriate) or skip to the next one */
if (!cnode)
{
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;
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", he->domain);
last_area = he->domain;
ix = 0;
}
}
else
continue;
}
switch (hea[i]->lsa.type)
ASSERT(cnode && (he->domain == last_area) && (he->lsa.rt == cnode->rt));
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);
......
......@@ -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);
......
......@@ -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 */
......
......@@ -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
......
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