]> git.puffer.fish Git - matthieu/frr.git/commitdiff
isisd: add the "show isis fast-reroute summary" command
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 20 Nov 2020 22:55:42 +0000 (19:55 -0300)
committerRenato Westphal <renato@opensourcerouting.org>
Tue, 24 Nov 2020 23:15:52 +0000 (20:15 -0300)
Add new "show" command to make it easy to see the protection coverage
provided by LFA/rLFA/TI-LFA.

Example output:

debian# show isis fast-reroute summary
Area 1:
 IS-IS L1 IPv4 Fast ReRoute summary:

 Protection \ Priority     Critical  High      Medium    Low       Total
 --------------------------------------------------------------------------
 Classic LFA               0         0         1         3         4
 Remote LFA                0         0         0         0         0
 Topology Independent LFA  0         0         0         0         0
 ECMP                      0         0         0         0         0
 Unprotected               0         0         2         1         3
 Protection coverage       0.00%     0.00%     33.33%    75.00%    54.17%

 IS-IS L1 IPv6 Fast ReRoute summary:

 Protection \ Priority     Critical  High      Medium    Low       Total
 --------------------------------------------------------------------------
 Classic LFA               0         0         1         0         1
 Remote LFA                0         0         0         0         0
 Topology Independent LFA  0         0         0         0         0
 ECMP                      0         0         0         0         0
 Unprotected               0         0         2         0         2
 Protection coverage       0.00%     0.00%     33.33%    0.00%     33.33%

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
doc/user/isisd.rst
isisd/isis_lfa.c
isisd/isis_spf.c
isisd/isis_spf_private.h

index a470f4e809073296f9af92799f4afdfb426f413b..f991e3f07397e2cd6f72057494d043af1609eb94 100644 (file)
@@ -469,6 +469,12 @@ Showing ISIS information
    Show the ISIS routing table, as determined by the most recent SPF
    calculation.
 
+.. index:: show isis fast-reroute summary [level-1|level-2]
+.. clicmd:: show isis fast-reroute summary [level-1|level-2]
+
+   Show information about the number of prefixes having LFA protection,
+   and network-wide LFA coverage.
+
 .. _isis-traffic-engineering:
 
 Traffic Engineering
index 7d516dc933e193d98a585fa49cd76d49f39216eb..fc6b435b62763ad2ebca0812b4916c52c4acd2c7 100644 (file)
@@ -1713,6 +1713,8 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
                                  best_metric, vertex->depth, &vertex->N.ip.sr,
                                  filtered_lfa_list, allow_ecmp, area,
                                  spftree->route_table_backup);
+               spftree->lfa.protection_counters.lfa[vertex->N.ip.priority] +=
+                       1;
 
                list_delete(&filtered_lfa_list);
                list_delete(&lfa_list);
index 947db9e92c1645e4da697eda2f555e265503d923..4a425753da3965560ff4ff20512e85573225bf07 100644 (file)
@@ -1429,6 +1429,8 @@ static void init_spt(struct isis_spftree *spftree, int mtid)
        list_delete_all_node(spftree->sadj_list);
        isis_vertex_queue_clear(&spftree->tents);
        isis_vertex_queue_clear(&spftree->paths);
+       memset(&spftree->lfa.protection_counters, 0,
+              sizeof(spftree->lfa.protection_counters));
 
        spftree->mtid = mtid;
 }
@@ -1525,9 +1527,23 @@ static void spf_path_process(struct isis_spftree *spftree,
                                pre_spftree = spftree->lfa.old.spftree;
                                route_table = pre_spftree->route_table_backup;
                                allow_ecmp = area->lfa_load_sharing[level - 1];
+                               pre_spftree->lfa.protection_counters
+                                       .tilfa[vertex->N.ip.priority] += 1;
                        } else {
                                route_table = spftree->route_table;
                                allow_ecmp = true;
+
+                               /*
+                                * Update LFA protection counters (ignore local
+                                * routes).
+                                */
+                               if (vertex->depth > 1) {
+                                       spftree->lfa.protection_counters
+                                               .total[priority] += 1;
+                                       if (listcount(vertex->Adj_N) > 1)
+                                               spftree->lfa.protection_counters
+                                                       .ecmp[priority] += 1;
+                               }
                        }
 
                        isis_route_create(
@@ -2347,10 +2363,223 @@ DEFUN(show_isis_route, show_isis_route_cmd,
        return CMD_SUCCESS;
 }
 
+static void isis_print_frr_summary_line(struct ttable *tt,
+                                       const char *protection,
+                                       uint32_t counters[SPF_PREFIX_PRIO_MAX])
+{
+       uint32_t critical, high, medium, low, total;
+
+       critical = counters[SPF_PREFIX_PRIO_CRITICAL];
+       high = counters[SPF_PREFIX_PRIO_HIGH];
+       medium = counters[SPF_PREFIX_PRIO_MEDIUM];
+       low = counters[SPF_PREFIX_PRIO_LOW];
+       total = critical + high + medium + low;
+
+       ttable_add_row(tt, "%s|%u|%u|%u|%u|%u", protection, critical, high,
+                      medium, low, total);
+}
+
+static void
+isis_print_frr_summary_line_coverage(struct ttable *tt, const char *protection,
+                                    double counters[SPF_PREFIX_PRIO_MAX],
+                                    double total)
+{
+       double critical, high, medium, low;
+
+       critical = counters[SPF_PREFIX_PRIO_CRITICAL] * 100;
+       high = counters[SPF_PREFIX_PRIO_HIGH] * 100;
+       medium = counters[SPF_PREFIX_PRIO_MEDIUM] * 100;
+       low = counters[SPF_PREFIX_PRIO_LOW] * 100;
+       total *= 100;
+
+       ttable_add_row(tt, "%s|%.2f%%|%.2f%%|%.2f%%|%.2f%%|%.2f%%", protection,
+                      critical, high, medium, low, total);
+}
+
+static void isis_print_frr_summary(struct vty *vty,
+                                  struct isis_spftree *spftree)
+{
+       struct ttable *tt;
+       char *table;
+       const char *tree_id_text = NULL;
+       uint32_t protectd[SPF_PREFIX_PRIO_MAX] = {0};
+       uint32_t unprotected[SPF_PREFIX_PRIO_MAX] = {0};
+       double coverage[SPF_PREFIX_PRIO_MAX] = {0};
+       uint32_t protected_total = 0, grand_total = 0;
+       double coverage_total;
+
+       if (!spftree)
+               return;
+
+       switch (spftree->tree_id) {
+       case SPFTREE_IPV4:
+               tree_id_text = "IPv4";
+               break;
+       case SPFTREE_IPV6:
+               tree_id_text = "IPv6";
+               break;
+       case SPFTREE_DSTSRC:
+               tree_id_text = "IPv6 (dst-src routing)";
+               break;
+       case SPFTREE_COUNT:
+               assert(!"isis_print_frr_summary shouldn't be called with SPFTREE_COUNT as type");
+               return;
+       }
+
+       vty_out(vty, " IS-IS %s %s Fast ReRoute summary:\n\n",
+               circuit_t2string(spftree->level), tree_id_text);
+
+       /* Prepare table. */
+       tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+       ttable_add_row(
+               tt,
+               "Protection \\ Priority|Critical|High    |Medium  |Low     |Total");
+       tt->style.cell.rpad = 2;
+       tt->style.corner = '+';
+       ttable_restyle(tt);
+       ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+       /* Compute unprotected and coverage totals. */
+       for (int priority = SPF_PREFIX_PRIO_CRITICAL;
+            priority < SPF_PREFIX_PRIO_MAX; priority++) {
+               uint32_t *lfa = spftree->lfa.protection_counters.lfa;
+               uint32_t *rlfa = spftree->lfa.protection_counters.rlfa;
+               uint32_t *tilfa = spftree->lfa.protection_counters.tilfa;
+               uint32_t *ecmp = spftree->lfa.protection_counters.ecmp;
+               uint32_t *total = spftree->lfa.protection_counters.total;
+
+               protectd[priority] = lfa[priority] + rlfa[priority]
+                                    + tilfa[priority] + ecmp[priority];
+               /* Safeguard to protect against possible inconsistencies. */
+               if (protectd[priority] > total[priority])
+                       protectd[priority] = total[priority];
+               unprotected[priority] = total[priority] - protectd[priority];
+               protected_total += protectd[priority];
+               grand_total += total[priority];
+
+               if (!total[priority])
+                       coverage[priority] = 0;
+               else
+                       coverage[priority] =
+                               protectd[priority] / (double)total[priority];
+       }
+
+       if (!grand_total)
+               coverage_total = 0;
+       else
+               coverage_total = protected_total / (double)grand_total;
+
+       /* Add rows. */
+       isis_print_frr_summary_line(tt, "Classic LFA",
+                                   spftree->lfa.protection_counters.lfa);
+       isis_print_frr_summary_line(tt, "Remote LFA",
+                                   spftree->lfa.protection_counters.rlfa);
+       isis_print_frr_summary_line(tt, "Topology Independent LFA",
+                                   spftree->lfa.protection_counters.tilfa);
+       isis_print_frr_summary_line(tt, "ECMP",
+                                   spftree->lfa.protection_counters.ecmp);
+       isis_print_frr_summary_line(tt, "Unprotected", unprotected);
+       isis_print_frr_summary_line_coverage(tt, "Protection coverage",
+                                            coverage, coverage_total);
+
+       /* Dump the generated table. */
+       table = ttable_dump(tt, "\n");
+       vty_out(vty, "%s\n", table);
+       XFREE(MTYPE_TMP, table);
+       ttable_del(tt);
+}
+
+static void show_isis_frr_summary_common(struct vty *vty, int levels,
+                                        struct isis *isis)
+{
+       struct listnode *node;
+       struct isis_area *area;
+
+       if (!isis->area_list || isis->area_list->count == 0)
+               return;
+
+       for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+               vty_out(vty, "Area %s:\n",
+                       area->area_tag ? area->area_tag : "null");
+
+               for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+                       if ((level & levels) == 0)
+                               continue;
+
+                       if (area->ip_circuits > 0) {
+                               isis_print_frr_summary(
+                                       vty,
+                                       area->spftree[SPFTREE_IPV4][level - 1]);
+                       }
+                       if (area->ipv6_circuits > 0) {
+                               isis_print_frr_summary(
+                                       vty,
+                                       area->spftree[SPFTREE_IPV6][level - 1]);
+                       }
+                       if (isis_area_ipv6_dstsrc_enabled(area)) {
+                               isis_print_frr_summary(
+                                       vty, area->spftree[SPFTREE_DSTSRC]
+                                                         [level - 1]);
+                       }
+               }
+       }
+}
+
+DEFUN(show_isis_frr_summary, show_isis_frr_summary_cmd,
+      "show " PROTO_NAME
+      " [vrf <NAME|all>] fast-reroute summary"
+#ifndef FABRICD
+      " [<level-1|level-2>]"
+#endif
+      ,
+      SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
+      "IS-IS FRR information\n"
+      "FRR summary\n"
+#ifndef FABRICD
+      "level-1 routes\n"
+      "level-2 routes\n"
+#endif
+)
+{
+       int levels;
+       struct isis *isis;
+       struct listnode *node;
+       const char *vrf_name = VRF_DEFAULT_NAME;
+       bool all_vrf = false;
+       int idx = 0;
+
+       if (argv_find(argv, argc, "level-1", &idx))
+               levels = ISIS_LEVEL1;
+       else if (argv_find(argv, argc, "level-2", &idx))
+               levels = ISIS_LEVEL2;
+       else
+               levels = ISIS_LEVEL1 | ISIS_LEVEL2;
+
+       if (!im) {
+               vty_out(vty, "IS-IS Routing Process not enabled\n");
+               return CMD_SUCCESS;
+       }
+       ISIS_FIND_VRF_ARGS(argv, argc, idx, vrf_name, all_vrf);
+
+       if (vrf_name) {
+               if (all_vrf) {
+                       for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis))
+                               show_isis_frr_summary_common(vty, levels, isis);
+                       return CMD_SUCCESS;
+               }
+               isis = isis_lookup_by_vrfname(vrf_name);
+               if (isis != NULL)
+                       show_isis_frr_summary_common(vty, levels, isis);
+       }
+
+       return CMD_SUCCESS;
+}
+
 void isis_spf_init(void)
 {
        install_element(VIEW_NODE, &show_isis_topology_cmd);
        install_element(VIEW_NODE, &show_isis_route_cmd);
+       install_element(VIEW_NODE, &show_isis_frr_summary_cmd);
 
        /* Register hook(s). */
        hook_register(isis_adj_state_change_hook, spf_adj_state_change);
index f128b4b585995c6b4e0deff9a78aff5ee139e67a..b7f326ca864692cf8477f2d5d09b73a25ebb3aa0 100644 (file)
@@ -348,6 +348,15 @@ struct isis_spftree {
                /* P-space and Q-space. */
                struct isis_spf_nodes p_space;
                struct isis_spf_nodes q_space;
+
+               /* Protection counters. */
+               struct {
+                       uint32_t lfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t rlfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t tilfa[SPF_PREFIX_PRIO_MAX];
+                       uint32_t ecmp[SPF_PREFIX_PRIO_MAX];
+                       uint32_t total[SPF_PREFIX_PRIO_MAX];
+               } protection_counters;
        } lfa;
        uint8_t flags;
 };