summaryrefslogtreecommitdiff
path: root/proto/ospf/ospf.c
diff options
context:
space:
mode:
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 107e3a41..59299198 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);