Skip to content

Commit

Permalink
isisd: introduce command to display IS-IS routes
Browse files Browse the repository at this point in the history
Introduce the "show isis route" command to display the routes
associated to an SPF tree. Different from the "show ip route" command,
"show isis route" displays the L1 and L2 routes separately (and not
the best routes only).

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
  • Loading branch information
rwestphal committed Aug 26, 2020
1 parent 3694479 commit 675269d
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 2 deletions.
4 changes: 2 additions & 2 deletions doc/user/isisd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,8 +418,8 @@ Showing ISIS information
Show topology IS-IS paths to Intermediate Systems, globally, in area
(level-1) or domain (level-2).

.. index:: show ip route isis
.. clicmd:: show ip route isis
.. index:: show isis route [level-1|level-2]
.. clicmd:: show isis route [level-1|level-2]

Show the ISIS routing table, as determined by the most recent SPF
calculation.
Expand Down
178 changes: 178 additions & 0 deletions isisd/isis_spf.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "vty.h"
#include "log.h"
#include "command.h"
#include "termtable.h"
#include "memory.h"
#include "prefix.h"
#include "if.h"
Expand Down Expand Up @@ -1520,9 +1521,186 @@ DEFUN(show_isis_topology, show_isis_topology_cmd,
return CMD_SUCCESS;
}

static void isis_print_routes(struct vty *vty, struct isis_spftree *spftree)
{
struct ttable *tt;
struct route_node *rn;
const char *tree_id_text = NULL;

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_routes shouldn't be called with SPFTREE_COUNT as type");
return;
}

vty_out(vty, "IS-IS %s %s routing table:\n\n",
circuit_t2string(spftree->level), tree_id_text);

/* Prepare table. */
tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
ttable_add_row(tt, "Prefix|Metric|Interface|Nexthop|Label(s)");
tt->style.cell.rpad = 2;
tt->style.corner = '+';
ttable_restyle(tt);
ttable_rowseps(tt, 0, BOTTOM, true, '-');

for (rn = route_top(spftree->route_table); rn; rn = route_next(rn)) {
struct isis_route_info *rinfo;
struct isis_nexthop *nexthop;
struct listnode *node;
bool first = true;
char buf_prefix[BUFSIZ];

rinfo = rn->info;
if (!rinfo)
continue;

(void)prefix2str(&rn->p, buf_prefix, sizeof(buf_prefix));
for (ALL_LIST_ELEMENTS_RO(rinfo->nexthops, node, nexthop)) {
struct interface *ifp;
char buf_iface[BUFSIZ];
char buf_nhop[BUFSIZ];
char buf_labels[BUFSIZ] = {};

inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
sizeof(buf_nhop));
ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
if (ifp)
strlcpy(buf_iface, ifp->name,
sizeof(buf_iface));
else
snprintf(buf_iface, sizeof(buf_iface),
"ifindex %u", nexthop->ifindex);

if (nexthop->sr.label != MPLS_INVALID_LABEL)
label2str(nexthop->sr.label, buf_labels,
sizeof(buf_labels));
else
strlcpy(buf_labels, "-", sizeof(buf_labels));

if (first) {
ttable_add_row(tt, "%s|%u|%s|%s|%s", buf_prefix,
rinfo->cost, buf_iface, buf_nhop,
buf_labels);
first = false;
} else
ttable_add_row(tt, "||%s|%s|%s", buf_iface,
buf_nhop, buf_labels);
}
}

/* Dump the generated table. */
if (tt->nrows > 1) {
char *table;

table = ttable_dump(tt, "\n");
vty_out(vty, "%s\n", table);
XFREE(MTYPE_TMP, table);
}
ttable_del(tt);
}

static void show_isis_route_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_routes(
vty,
area->spftree[SPFTREE_IPV4][level - 1]);
}
if (area->ipv6_circuits > 0) {
isis_print_routes(
vty,
area->spftree[SPFTREE_IPV6][level - 1]);
}
if (isis_area_ipv6_dstsrc_enabled(area)) {
isis_print_routes(vty,
area->spftree[SPFTREE_DSTSRC]
[level - 1]);
}
}
}
}

DEFUN(show_isis_route, show_isis_route_cmd,
"show " PROTO_NAME
" [vrf <NAME|all>] route"
#ifndef FABRICD
" [<level-1|level-2>]"
#endif
,
SHOW_STR PROTO_HELP VRF_FULL_CMD_HELP_STR
"IS-IS routing table\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_route_common(vty, levels, isis);
return CMD_SUCCESS;
}
isis = isis_lookup_by_vrfname(vrf_name);
if (isis != NULL)
show_isis_route_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);

/* Register hook(s). */
hook_register(isis_adj_state_change_hook, spf_adj_state_change);
Expand Down

0 comments on commit 675269d

Please sign in to comment.