summaryrefslogtreecommitdiffstats
path: root/proto/ospf/ospf.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-04-24 15:18:21 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2010-04-24 15:18:21 +0200
commit0ea8fb4abe5acad0b8f470bbdc5cc929b6a58ced (patch)
tree5d8d0538e2ce7e138df1936b8cf64aadbc063bce /proto/ospf/ospf.c
parent1d44ddf20f3ecef864d4bd20355251839fcd10ee (diff)
downloadbird-0ea8fb4abe5acad0b8f470bbdc5cc929b6a58ced.tar
bird-0ea8fb4abe5acad0b8f470bbdc5cc929b6a58ced.zip
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).
Diffstat (limited to 'proto/ospf/ospf.c')
-rw-r--r--proto/ospf/ospf.c224
1 files changed, 172 insertions, 52 deletions
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 107e3a4..5929919 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -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);