]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes and enhancements in 'show ospf state' command.
authorOndrej Zajicek <santiago@crfreenet.org>
Sat, 24 Apr 2010 13:18:21 +0000 (15:18 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Sat, 24 Apr 2010 13:18:21 +0000 (15:18 +0200)
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).

doc/bird.sgml
proto/ospf/config.Y
proto/ospf/iface.c
proto/ospf/lsalib.c
proto/ospf/ospf.c
proto/ospf/ospf.h
proto/ospf/rt.c
proto/ospf/topology.h

index 64185e90e122555baa1400fedc27e5e5b850fc8b..61ebc7a5003478dce5c5087c7d092025a9eaaea9 100644 (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 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.
index 2196af7a6d2006b87b0ef57b5ce2f42eb65405c0..5caba00666c22890e24cfc3afe1c1061c8ff6037 100644 (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)); };
index f4013263f485e93086d0fb2ac4ed70dd3b7332ac..b5a509a7c26de5559113834d7af1e6d761dfabef 100644 (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);
 }
index 35f02dcd4ad8ff6c3be90a2ee55da967aca618ce..53c25623c000b9c468a4357ee36a30c5b96dcce5 100644 (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
index 107e3a411e5bd87b69895294ce17ab25406b3687..59299198f60963b360892ecb54376bb4deafa9f9 100644 (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_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);
index bb0b6afcbd1863ae87b2cf9e87ab080ab2d61f3a..103ca550b8e8fe7a6c4e15d54f564547c7178f52 100644 (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);
 
 
index d685961de0f5ed82ea19fb0b92608ede2f343101..9e63d2c68383cf3c32e1ba806e77bcbf2e0159a3 100644 (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 */
index 7aa1625ba74e876c49fe083b99ada8f4ac36f3fc..2481676822548c3e5d3e5040a251a957d4d17aa7 100644 (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