diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2010-04-24 15:18:21 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2010-04-24 15:18:21 +0200 |
commit | 0ea8fb4abe5acad0b8f470bbdc5cc929b6a58ced (patch) | |
tree | 5d8d0538e2ce7e138df1936b8cf64aadbc063bce /proto/ospf | |
parent | 1d44ddf20f3ecef864d4bd20355251839fcd10ee (diff) | |
download | bird-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')
-rw-r--r-- | proto/ospf/config.Y | 18 | ||||
-rw-r--r-- | proto/ospf/iface.c | 1 | ||||
-rw-r--r-- | proto/ospf/lsalib.c | 8 | ||||
-rw-r--r-- | proto/ospf/ospf.c | 224 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 3 | ||||
-rw-r--r-- | proto/ospf/rt.c | 9 | ||||
-rw-r--r-- | proto/ospf/topology.h | 2 |
7 files changed, 197 insertions, 68 deletions
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y index 2196af7..5caba00 100644 --- a/proto/ospf/config.Y +++ b/proto/ospf/config.Y @@ -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)); }; diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index f401326..b5a509a 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -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); } diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index 35f02dc..53c2562 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -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 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); diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index bb0b6af..103ca55 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -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); diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index d685961..9e63d2c 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -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 */ diff --git a/proto/ospf/topology.h b/proto/ospf/topology.h index 7aa1625..2481676 100644 --- a/proto/ospf/topology.h +++ b/proto/ospf/topology.h @@ -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 |