1
0
Fork 0
frr/zebra/zebra_vty.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

4355 lines
114 KiB
C
Raw Permalink Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/* Zebra VTY functions
* Copyright (C) 2002 Kunihiro Ishiguro
*/
#include <zebra.h>
#include "memory.h"
#include "if.h"
#include "prefix.h"
#include "command.h"
#include "table.h"
#include "rib.h"
#include "nexthop.h"
#include "vrf.h"
#include "linklist.h"
#include "mpls.h"
#include "routemap.h"
#include "srcdest_table.h"
#include "vxlan.h"
#include "termtable.h"
#include "affinitymap.h"
#include "frrdistance.h"
#include "zebra/zebra_router.h"
#include "zebra/zserv.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_mpls.h"
#include "zebra/zebra_rnh.h"
#include "zebra/redistribute.h"
#include "zebra/zebra_affinitymap.h"
#include "zebra/zebra_routemap.h"
#include "lib/json.h"
#include "lib/route_opaque.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/zebra_vty_clippy.c"
#include "zebra/zserv.h"
#include "zebra/router-id.h"
#include "zebra/ipforward.h"
#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_pbr.h"
#include "zebra/zebra_nhg.h"
#include "zebra/zebra_evpn_mh.h"
#include "zebra/interface.h"
#include "northbound_cli.h"
#include "zebra/zebra_nb.h"
#include "zebra/kernel_netlink.h"
#include "zebra/if_netlink.h"
#include "zebra/table_manager.h"
#include "zebra/zebra_script.h"
#include "zebra/rtadv.h"
#include "zebra/zebra_neigh.h"
#include "zebra/zebra_ptm.h"
/* context to manage dumps in multiple tables or vrfs */
struct route_show_ctx {
bool multi; /* dump multiple tables or vrf */
bool header_done; /* common header already displayed */
};
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
safi_t safi, bool use_fib, bool use_json,
route_tag_t tag,
const struct prefix *longer_prefix_p,
bool supernets_only, int type,
unsigned short ospf_instance_id, uint32_t tableid,
bool show_ng, struct route_show_ctx *ctx);
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast, bool use_fib, bool show_ng);
static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table,
json_object *vrf_json, bool use_json);
static void vty_show_ip_route_summary_prefix(struct vty *vty,
struct route_table *table,
json_object *vrf_json,
bool use_json);
/* Helper api to format a nexthop in the 'detailed' output path. */
static void show_nexthop_detail_helper(struct vty *vty,
const struct route_node *rn,
const struct route_entry *re,
const struct nexthop *nexthop,
bool is_backup);
static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table, afi_t afi,
safi_t safi);
static void show_ip_route_nht_dump(struct vty *vty,
const struct nexthop *nexthop,
const struct route_node *rn,
const struct route_entry *re,
unsigned int num);
static char re_status_output_char(const struct route_entry *re,
const struct nexthop *nhop,
bool is_fib)
{
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
bool star_p = false;
if (nhop &&
!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) {
/* More-specific test for 'fib' output */
if (is_fib) {
star_p = !!CHECK_FLAG(nhop->flags,
NEXTHOP_FLAG_FIB);
} else if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_ACTIVE))
star_p = true;
}
if (zrouter.asic_offloaded &&
CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
return 'q';
if (zrouter.asic_offloaded
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED))
return 't';
if (zrouter.asic_offloaded
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
return 'o';
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OUTOFSYNC))
return 'd';
if (star_p)
return '*';
else
return ' ';
}
if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED)) {
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
return 'q';
return 'r';
}
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
return 'q';
return ' ';
}
/*
* Show backup nexthop info, in the 'detailed' output path
*/
static void show_nh_backup_helper(struct vty *vty, const struct route_node *rn,
const struct route_entry *re,
const struct nexthop *nexthop)
{
const struct nexthop *start, *backup, *temp;
int i, idx;
/* Double-check that there _is_ a backup */
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP) ||
re->nhe->backup_info == NULL || re->nhe->backup_info->nhe == NULL ||
re->nhe->backup_info->nhe->nhg.nexthop == NULL)
return;
/* Locate the backup nexthop(s) */
start = re->nhe->backup_info->nhe->nhg.nexthop;
for (i = 0; i < nexthop->backup_num; i++) {
/* Format the backup(s) (indented) */
backup = start;
for (idx = 0; idx < nexthop->backup_idx[i]; idx++) {
backup = backup->next;
if (backup == NULL)
break;
}
/* It's possible for backups to be recursive too,
* so walk the recursive resolution list if present.
*/
temp = backup;
while (backup) {
vty_out(vty, " ");
show_nexthop_detail_helper(vty, rn, re, backup,
true /*backup*/);
vty_out(vty, "\n");
if (backup->resolved && temp == backup)
backup = backup->resolved;
else
backup = nexthop_next(backup);
if (backup == temp->next)
break;
}
}
}
/*
* Helper api to format output for a nexthop, used in the 'detailed'
* output path.
*/
static void show_nexthop_detail_helper(struct vty *vty,
const struct route_node *rn,
const struct route_entry *re,
const struct nexthop *nexthop,
bool is_backup)
{
char buf[MPLS_LABEL_STRLEN];
int i;
if (is_backup)
vty_out(vty, " b%s",
nexthop->rparent ? " " : "");
else
vty_out(vty, " %c%s",
re_status_output_char(re, nexthop, false),
nexthop->rparent ? " " : "");
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out(vty, " %pI4",
&nexthop->gate.ipv4);
if (nexthop->ifindex)
vty_out(vty, ", via %s",
ifindex2ifname(
nexthop->ifindex,
nexthop->vrf_id));
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
vty_out(vty, " %s",
inet_ntop(AF_INET6, &nexthop->gate.ipv6,
buf, sizeof(buf)));
if (nexthop->ifindex)
vty_out(vty, ", via %s",
ifindex2ifname(
nexthop->ifindex,
nexthop->vrf_id));
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " directly connected, %s",
ifindex2ifname(nexthop->ifindex,
nexthop->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
vty_out(vty, " unreachable");
switch (nexthop->bh_type) {
case BLACKHOLE_REJECT:
vty_out(vty, " (ICMP unreachable)");
break;
case BLACKHOLE_ADMINPROHIB:
vty_out(vty,
" (ICMP admin-prohibited)");
break;
case BLACKHOLE_NULL:
vty_out(vty, " (blackhole)");
break;
case BLACKHOLE_UNSPEC:
break;
}
break;
}
if (re->vrf_id != nexthop->vrf_id && nexthop->type != NEXTHOP_TYPE_BLACKHOLE) {
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
vty_out(vty, "(vrf %s)", VRF_LOGNAME(vrf));
}
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
vty_out(vty, " (duplicate nexthop removed)");
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
vty_out(vty, " inactive");
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
vty_out(vty, " onlink");
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN))
vty_out(vty, " linkdown");
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
vty_out(vty, " (recursive)");
/* Source specified? */
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
if (nexthop->rmap_src.ipv4.s_addr)
vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4);
else if (nexthop->src.ipv4.s_addr)
vty_out(vty, ", src %pI4", &nexthop->src.ipv4);
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
/* Allow for 5549 ipv4 prefix with ipv6 nexthop */
if (rn->p.family == AF_INET && nexthop->rmap_src.ipv4.s_addr)
vty_out(vty, ", rmapsrc %pI4", &nexthop->rmap_src.ipv4);
else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any))
vty_out(vty, ", rmapsrc %pI6", &nexthop->rmap_src.ipv6);
else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any))
vty_out(vty, ", src %pI6", &nexthop->src.ipv6);
break;
case NEXTHOP_TYPE_IFINDEX:
case NEXTHOP_TYPE_BLACKHOLE:
break;
}
if (re->nexthop_mtu)
vty_out(vty, ", mtu %u", re->nexthop_mtu);
/* Label information */
if (nexthop->nh_label && nexthop->nh_label->num_labels) {
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
sizeof(buf), nexthop->nh_label_type,
1 /*pretty*/));
}
if (nexthop->weight)
vty_out(vty, ", weight %u", nexthop->weight);
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
vty_out(vty, ", backup %d", nexthop->backup_idx[0]);
for (i = 1; i < nexthop->backup_num; i++)
vty_out(vty, ",%d", nexthop->backup_idx[i]);
}
}
static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re,
struct json_object *json)
{
struct bgp_zebra_opaque bzo = {};
struct ospf_zebra_opaque ozo = {};
if (!re->opaque)
return;
switch (re->type) {
case ZEBRA_ROUTE_SHARP:
if (json)
json_object_string_add(json, "opaque",
(char *)re->opaque->data);
else
vty_out(vty, " Opaque Data: %s",
(char *)re->opaque->data);
break;
case ZEBRA_ROUTE_BGP:
memcpy(&bzo, re->opaque->data, re->opaque->length);
if (json) {
json_object_string_add(json, "asPath", bzo.aspath);
json_object_string_add(json, "communities",
bzo.community);
json_object_string_add(json, "largeCommunities",
bzo.lcommunity);
json_object_string_add(json, "selectionReason",
bzo.selection_reason);
} else {
vty_out(vty, " AS-Path : %s\n", bzo.aspath);
if (bzo.community[0] != '\0')
vty_out(vty, " Communities : %s\n",
bzo.community);
if (bzo.lcommunity[0] != '\0')
vty_out(vty, " Large-Communities: %s\n",
bzo.lcommunity);
vty_out(vty, " Selection reason : %s\n",
bzo.selection_reason);
}
break;
case ZEBRA_ROUTE_OSPF:
case ZEBRA_ROUTE_OSPF6:
memcpy(&ozo, re->opaque->data, re->opaque->length);
if (json) {
json_object_string_add(json, "ospfPathType",
ozo.path_type);
if (ozo.area_id[0] != '\0')
json_object_string_add(json, "ospfAreaId",
ozo.area_id);
if (ozo.tag[0] != '\0')
json_object_string_add(json, "ospfTag",
ozo.tag);
} else {
vty_out(vty, " OSPF path type : %s\n",
ozo.path_type);
if (ozo.area_id[0] != '\0')
vty_out(vty, " OSPF area ID : %s\n",
ozo.area_id);
if (ozo.tag[0] != '\0')
vty_out(vty, " OSPF tag : %s\n",
ozo.tag);
}
break;
default:
break;
}
}
static void uptime2str(time_t uptime, char *buf, size_t bufsize)
{
time_t cur;
cur = monotime(NULL);
cur -= uptime;
frrtime_to_interval(cur, buf, bufsize);
}
/* New RIB. Detailed information for IPv4 route. */
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
int mcast, bool use_fib, bool show_ng)
{
struct route_entry *re;
struct nexthop *nexthop;
char buf[SRCDEST2STR_BUFFER];
struct zebra_vrf *zvrf;
rib_dest_t *dest;
dest = rib_dest_from_rnode(rn);
RNODE_FOREACH_RE (rn, re) {
/*
* If re not selected for forwarding, skip re
* for "show ip/ipv6 fib <prefix>"
*/
if (use_fib && re != dest->selected_fib)
continue;
const char *mcast_info = "";
if (mcast) {
struct rib_table_info *info =
srcdest_rnode_table_info(rn);
mcast_info = (info->safi == SAFI_MULTICAST)
? " using Multicast RIB"
: " using Unicast RIB";
}
vty_out(vty, "Routing entry for %s%s\n",
srcdest_rnode2str(rn, buf, sizeof(buf)), mcast_info);
vty_out(vty, " Known via \"%s", zebra_route_string(re->type));
if (re->instance)
vty_out(vty, "[%d]", re->instance);
vty_out(vty, "\"");
vty_out(vty, ", distance %u, metric %u", re->distance,
re->metric);
if (re->tag) {
vty_out(vty, ", tag %u", re->tag);
#if defined(SUPPORT_REALMS)
if (re->tag > 0 && re->tag <= 255)
vty_out(vty, "(realm)");
#endif
}
if (re->mtu)
vty_out(vty, ", mtu %u", re->mtu);
if (re->vrf_id != VRF_DEFAULT) {
zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
vty_out(vty, ", vrf %s", zvrf_name(zvrf));
}
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
vty_out(vty, ", best");
vty_out(vty, "\n");
uptime2str(re->uptime, buf, sizeof(buf));
vty_out(vty, " Last update %s ago\n", buf);
if (show_ng) {
vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
if (re->nhe_installed_id != 0
&& re->nhe_id != re->nhe_installed_id)
vty_out(vty,
" Installed Nexthop Group ID: %u\n",
re->nhe_installed_id);
}
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
/* Use helper to format each nexthop */
show_nexthop_detail_helper(vty, rn, re, nexthop,
false /*not backup*/);
vty_out(vty, "\n");
/* Include backup(s), if present */
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
show_nh_backup_helper(vty, rn, re, nexthop);
}
zebra_show_ip_route_opaque(vty, re, NULL);
vty_out(vty, "\n");
}
}
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
struct route_entry *re, json_object *json,
bool is_fib, bool show_ng)
{
const struct nexthop *nexthop;
int len = 0;
char buf[SRCDEST2STR_BUFFER];
json_object *json_nexthops = NULL;
json_object *json_nexthop = NULL;
json_object *json_route = NULL;
const rib_dest_t *dest = rib_dest_from_rnode(rn);
const struct nexthop_group *nhg;
char up_str[MONOTIME_STRLEN];
bool first_p = true;
bool nhg_from_backup = false;
uptime2str(re->uptime, up_str, sizeof(up_str));
/* If showing fib information, use the fib view of the
* nexthops.
*/
if (is_fib)
nhg = rib_get_fib_nhg(re);
else
nhg = &(re->nhe->nhg);
if (json) {
json_route = json_object_new_object();
json_nexthops = json_object_new_array();
json_object_string_add(json_route, "prefix",
srcdest_rnode2str(rn, buf, sizeof(buf)));
json_object_int_add(json_route, "prefixLen", rn->p.prefixlen);
json_object_string_add(json_route, "protocol",
zebra_route_string(re->type));
if (re->instance)
json_object_int_add(json_route, "instance",
re->instance);
json_object_int_add(json_route, "vrfId", re->vrf_id);
json_object_string_add(json_route, "vrfName",
vrf_id_to_name(re->vrf_id));
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
json_object_boolean_true_add(json_route, "selected");
if (dest->selected_fib == re)
json_object_boolean_true_add(json_route,
"destSelected");
json_object_int_add(json_route, "distance",
re->distance);
json_object_int_add(json_route, "metric", re->metric);
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
json_object_boolean_true_add(json_route, "installed");
if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED))
json_object_boolean_true_add(json_route, "failed");
if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
json_object_boolean_true_add(json_route, "queued");
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED))
json_object_boolean_true_add(json_route, "trapped");
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED))
json_object_boolean_true_add(json_route, "offloaded");
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
json_object_boolean_false_add(json_route, "offloaded");
if (re->tag)
json_object_int_add(json_route, "tag", re->tag);
if (re->table)
json_object_int_add(json_route, "table", re->table);
json_object_int_add(json_route, "internalStatus",
re->status);
json_object_int_add(json_route, "internalFlags",
re->flags);
json_object_int_add(json_route, "internalNextHopNum",
nexthop_group_nexthop_num(&(re->nhe->nhg)));
json_object_int_add(json_route, "internalNextHopActiveNum",
nexthop_group_active_nexthop_num(
&(re->nhe->nhg)));
json_object_int_add(json_route, "nexthopGroupId", re->nhe_id);
if (re->nhe_installed_id != 0)
json_object_int_add(json_route,
"installedNexthopGroupId",
re->nhe_installed_id);
json_object_string_add(json_route, "uptime", up_str);
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
json_nexthop = json_object_new_object();
show_nexthop_json_helper(json_nexthop, nexthop, rn, re);
json_object_array_add(json_nexthops,
json_nexthop);
}
json_object_object_add(json_route, "nexthops", json_nexthops);
/* If there are backup nexthops, include them */
if (is_fib)
nhg = rib_get_fib_backup_nhg(re);
else
nhg = zebra_nhg_get_backup_nhg(re->nhe);
if (nhg && nhg->nexthop) {
json_nexthops = json_object_new_array();
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
json_nexthop = json_object_new_object();
show_nexthop_json_helper(json_nexthop, nexthop,
rn, re);
json_object_array_add(json_nexthops,
json_nexthop);
}
json_object_object_add(json_route, "backupNexthops",
json_nexthops);
}
zebra_show_ip_route_opaque(NULL, re, json_route);
json_object_array_add(json, json_route);
return;
}
/* Prefix information, and first nexthop. If we're showing 'fib',
* and there are no installed primary nexthops, see if there are any
* backup nexthops and start with those.
*/
if (is_fib && nhg->nexthop == NULL) {
nhg = rib_get_fib_backup_nhg(re);
nhg_from_backup = true;
}
len = vty_out(vty, "%c", zebra_route_char(re->type));
if (re->instance)
len += vty_out(vty, "[%d]", re->instance);
if (nhg_from_backup && nhg->nexthop) {
len += vty_out(
vty, "%cb%c %s",
CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
re_status_output_char(re, nhg->nexthop, is_fib),
srcdest_rnode2str(rn, buf, sizeof(buf)));
} else {
len += vty_out(
vty, "%c%c %s",
CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) ? '>' : ' ',
re_status_output_char(re, nhg->nexthop, is_fib),
srcdest_rnode2str(rn, buf, sizeof(buf)));
}
/* Distance and metric display. */
if (((re->type == ZEBRA_ROUTE_CONNECT ||
re->type == ZEBRA_ROUTE_LOCAL) &&
(re->distance || re->metric)) ||
(re->type != ZEBRA_ROUTE_CONNECT && re->type != ZEBRA_ROUTE_LOCAL))
len += vty_out(vty, " [%u/%u]", re->distance,
re->metric);
if (show_ng)
len += vty_out(vty, " (%u)", re->nhe_id);
/* Nexthop information. */
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
if (first_p) {
first_p = false;
} else if (nhg_from_backup) {
vty_out(vty, " b%c%*c",
re_status_output_char(re, nexthop, is_fib),
len - 3 + (2 * nexthop_level(nexthop)), ' ');
} else {
vty_out(vty, " %c%*c",
re_status_output_char(re, nexthop, is_fib),
len - 3 + (2 * nexthop_level(nexthop)), ' ');
}
show_route_nexthop_helper(vty, rn, re, nexthop);
vty_out(vty, ", %s\n", up_str);
}
/* If we only had backup nexthops, we're done */
if (nhg_from_backup)
return;
/* Check for backup nexthop info if present */
if (is_fib)
nhg = rib_get_fib_backup_nhg(re);
else
nhg = zebra_nhg_get_backup_nhg(re->nhe);
if (nhg == NULL)
return;
/* Print backup info */
for (ALL_NEXTHOPS_PTR(nhg, nexthop)) {
bool star_p = false;
if (is_fib)
star_p = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB);
/* TODO -- it'd be nice to be able to include
* the entire list of backups, *and* include the
* real installation state.
*/
vty_out(vty, " b%c %*c",
(star_p ? '*' : ' '),
len - 3 + (2 * nexthop_level(nexthop)), ' ');
show_route_nexthop_helper(vty, rn, re, nexthop);
vty_out(vty, "\n");
}
}
static void vty_show_ip_route_detail_json(struct vty *vty,
struct route_node *rn, bool use_fib)
{
json_object *json = NULL;
json_object *json_prefix = NULL;
struct route_entry *re;
char buf[BUFSIZ];
rib_dest_t *dest;
dest = rib_dest_from_rnode(rn);
json = json_object_new_object();
json_prefix = json_object_new_array();
RNODE_FOREACH_RE (rn, re) {
/*
* If re not selected for forwarding, skip re
* for "show ip/ipv6 fib <prefix> json"
*/
if (use_fib && re != dest->selected_fib)
continue;
vty_show_ip_route(vty, rn, re, json_prefix, use_fib, false);
}
prefix2str(&rn->p, buf, sizeof(buf));
json_object_object_add(json, buf, json_prefix);
vty_json(vty, json);
}
static void zebra_vty_display_vrf_header(struct vty *vty, struct zebra_vrf *zvrf, uint32_t tableid,
afi_t afi, safi_t safi)
{
if (!tableid)
vty_out(vty, "%s %s VRF %s:\n", afi2str(afi), safi2str(safi), zvrf_name(zvrf));
else {
if (vrf_is_backend_netns())
vty_out(vty, "%s %s VRF %s table %u:\n", afi2str(afi), safi2str(safi),
zvrf_name(zvrf), tableid);
else {
vrf_id_t vrf = zebra_vrf_lookup_by_table(tableid, zvrf->zns->ns_id);
if (vrf == VRF_DEFAULT && tableid != RT_TABLE_ID_MAIN)
vty_out(vty, "%s %s table %u:\n", afi2str(afi), safi2str(safi),
tableid);
else {
struct zebra_vrf *zvrf2 = zebra_vrf_lookup_by_id(vrf);
vty_out(vty, "%s %s VRF %s table %u:\n", afi2str(afi),
safi2str(safi), zvrf_name(zvrf2), tableid);
}
}
}
}
static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, struct route_table *table,
afi_t afi, safi_t safi, bool use_fib, route_tag_t tag,
const struct prefix *longer_prefix_p, bool supernets_only,
int type, unsigned short ospf_instance_id, bool use_json,
uint32_t tableid, bool show_ng, struct route_show_ctx *ctx)
{
struct route_node *rn;
struct route_entry *re;
bool first_json = true;
int first = 1;
rib_dest_t *dest;
json_object *json_prefix = NULL;
uint32_t addr;
char buf[BUFSIZ];
/*
* ctx->multi indicates if we are dumping multiple tables or vrfs.
* if set:
* => display the common header at most once
* => add newline at each call except first
* => always display the VRF and table
* else:
* => display the common header if at least one entry is found
* => display the VRF and table if specific
*/
/* Show all routes. */
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
dest = rib_dest_from_rnode(rn);
if (longer_prefix_p && !prefix_match(longer_prefix_p, &rn->p))
continue;
RNODE_FOREACH_RE (rn, re) {
if (use_fib && re != dest->selected_fib)
continue;
if (tag && re->tag != tag)
continue;
/* This can only be true when the afi is IPv4 */
if (supernets_only) {
addr = ntohl(rn->p.u.prefix4.s_addr);
if (IN_CLASSC(addr) && rn->p.prefixlen >= 24)
continue;
if (IN_CLASSB(addr) && rn->p.prefixlen >= 16)
continue;
if (IN_CLASSA(addr) && rn->p.prefixlen >= 8)
continue;
}
if (type && re->type != type)
continue;
if (ospf_instance_id
&& (re->type != ZEBRA_ROUTE_OSPF
|| re->instance != ospf_instance_id))
continue;
if (use_json) {
if (!json_prefix)
json_prefix = json_object_new_array();
} else if (first) {
if (!ctx->header_done) {
if (afi == AFI_IP)
vty_out(vty,
SHOW_ROUTE_V4_HEADER);
else
vty_out(vty,
SHOW_ROUTE_V6_HEADER);
}
if (ctx->multi && ctx->header_done)
vty_out(vty, "\n");
zebra_vty_display_vrf_header(vty, zvrf, tableid, afi, safi);
ctx->header_done = true;
first = 0;
}
vty_show_ip_route(vty, rn, re, json_prefix, use_fib,
show_ng);
}
if (json_prefix) {
prefix2str(&rn->p, buf, sizeof(buf));
vty_json_key(vty, buf, &first_json);
vty_json_no_pretty(vty, json_prefix);
json_prefix = NULL;
}
}
if (use_json)
vty_json_close(vty, first_json);
}
static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, safi_t safi,
bool use_fib, bool use_json, route_tag_t tag,
const struct prefix *longer_prefix_p, bool supernets_only,
int type, unsigned short ospf_instance_id, bool show_ng,
struct route_show_ctx *ctx)
{
struct zebra_router_table *zrt;
struct rib_table_info *info;
RB_FOREACH (zrt, zebra_router_table_head,
&zrouter.tables) {
info = route_table_get_info(zrt->table);
if (zvrf != info->zvrf)
continue;
if (zrt->afi != afi || zrt->safi != safi)
continue;
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, use_fib, use_json, tag,
longer_prefix_p, supernets_only, type, ospf_instance_id,
zrt->tableid, show_ng, ctx);
}
}
static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
safi_t safi, bool use_fib, bool use_json,
route_tag_t tag,
const struct prefix *longer_prefix_p,
bool supernets_only, int type,
unsigned short ospf_instance_id, uint32_t tableid,
bool show_ng, struct route_show_ctx *ctx)
{
struct route_table *table;
struct zebra_vrf *zvrf = NULL;
if (!(zvrf = zebra_vrf_lookup_by_name(vrf_name))) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "vrf %s not defined\n", vrf_name);
return CMD_SUCCESS;
}
if (zvrf_id(zvrf) == VRF_UNKNOWN) {
if (use_json)
vty_out(vty, "{}\n");
else
vty_out(vty, "vrf %s inactive\n", vrf_name);
return CMD_SUCCESS;
}
if (tableid)
table = zebra_router_find_table(zvrf, tableid, afi, safi);
else
table = zebra_vrf_table(afi, safi, zvrf_id(zvrf));
if (!table) {
if (use_json)
vty_out(vty, "{}\n");
return CMD_SUCCESS;
}
do_show_route_helper(vty, zvrf, table, afi, safi, use_fib, tag, longer_prefix_p,
supernets_only, type, ospf_instance_id, use_json, tableid, show_ng,
ctx);
return CMD_SUCCESS;
}
DEFPY (show_ip_nht,
show_ip_nht_cmd,
"show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
SHOW_STR
IP_STR
IP6_STR
"IP nexthop tracking table\n"
"IP import check tracking table\n"
"IPv4 Address\n"
"IPv6 Address\n"
VRF_CMD_HELP_STR
"IPv4 Address\n"
"IPv6 Address\n"
VRF_ALL_CMD_HELP_STR
"Show Multicast (MRIB) NHT state\n"
JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
bool uj = use_json(argc, argv);
json_object *json = NULL;
json_object *json_vrf = NULL;
json_object *json_nexthop = NULL;
struct zebra_vrf *zvrf;
bool resolve_via_default = false;
if (uj)
json = json_object_new_object();
if (vrf_all) {
struct vrf *vrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) != NULL) {
resolve_via_default =
(afi == AFI_IP)
? zvrf->zebra_rnh_ip_default_route
: zvrf->zebra_rnh_ipv6_default_route;
if (uj) {
json_vrf = json_object_new_object();
json_nexthop = json_object_new_object();
json_object_object_add(json,
zvrf_name(zvrf),
json_vrf);
json_object_object_add(json_vrf,
(afi == AFI_IP)
? "ipv4"
: "ipv6",
json_nexthop);
json_object_boolean_add(json_nexthop,
"resolveViaDefault",
resolve_via_default);
} else {
vty_out(vty, "\nVRF %s:\n",
zvrf_name(zvrf));
vty_out(vty,
" Resolve via default: %s\n",
resolve_via_default ? "on"
: "off");
}
zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
vty, NULL, json_nexthop);
}
}
if (uj)
vty_json(vty, json);
return CMD_SUCCESS;
}
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
memset(&prefix, 0, sizeof(prefix));
if (addr) {
p = sockunion2hostprefix(addr, &prefix);
if (!p) {
if (uj)
json_object_free(json);
return CMD_WARNING;
}
}
zvrf = zebra_vrf_lookup_by_id(vrf_id);
resolve_via_default = (afi == AFI_IP)
? zvrf->zebra_rnh_ip_default_route
: zvrf->zebra_rnh_ipv6_default_route;
if (uj) {
json_vrf = json_object_new_object();
json_nexthop = json_object_new_object();
if (vrf_name)
json_object_object_add(json, vrf_name, json_vrf);
else
json_object_object_add(json, "default", json_vrf);
json_object_object_add(json_vrf,
(afi == AFI_IP) ? "ipv4" : "ipv6",
json_nexthop);
json_object_boolean_add(json_nexthop, "resolveViaDefault",
resolve_via_default);
} else {
vty_out(vty, "VRF %s:\n", zvrf_name(zvrf));
vty_out(vty, " Resolve via default: %s\n",
resolve_via_default ? "on" : "off");
}
zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
if (uj)
vty_json(vty, json);
return CMD_SUCCESS;
}
static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe,
json_object *json_nhe_hdr)
{
struct nexthop *nexthop = NULL;
struct nhg_connected *rb_node_dep = NULL;
struct nexthop_group *backup_nhg;
char up_str[MONOTIME_STRLEN];
char time_left[MONOTIME_STRLEN];
json_object *json_dependants = NULL;
json_object *json_depends = NULL;
json_object *json_nexthop_array = NULL;
json_object *json_nexthops = NULL;
json_object *json = NULL;
json_object *json_backup_nexthop_array = NULL;
json_object *json_backup_nexthops = NULL;
uptime2str(nhe->uptime, up_str, sizeof(up_str));
if (json_nhe_hdr)
json = json_object_new_object();
if (json) {
json_object_string_add(json, "type",
zebra_route_string(nhe->type));
json_object_int_add(json, "refCount", nhe->refcnt);
if (event_is_scheduled(nhe->timer))
json_object_string_add(
json, "timeToDeletion",
event_timer_to_hhmmss(time_left,
sizeof(time_left),
nhe->timer));
json_object_string_add(json, "uptime", up_str);
json_object_string_add(json, "vrf",
vrf_id_to_name(nhe->vrf_id));
json_object_string_add(json, "afi", afi2str(nhe->afi));
} else {
vty_out(vty, "ID: %u (%s)\n", nhe->id,
zebra_route_string(nhe->type));
vty_out(vty, " RefCnt: %u", nhe->refcnt);
if (event_is_scheduled(nhe->timer))
vty_out(vty, " Time to Deletion: %s",
event_timer_to_hhmmss(time_left,
sizeof(time_left),
nhe->timer));
vty_out(vty, "\n");
vty_out(vty, " Uptime: %s\n", up_str);
vty_out(vty, " VRF: %s(%s)\n", vrf_id_to_name(nhe->vrf_id),
afi2str(nhe->afi));
}
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
if (json)
json_object_boolean_true_add(json, "valid");
else
vty_out(vty, " Valid");
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_REINSTALL)) {
if (json)
json_object_boolean_true_add(json, "reInstall");
else
vty_out(vty, ", Reinstall");
}
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
if (json)
json_object_boolean_true_add(json, "installed");
else
vty_out(vty, ", Installed");
}
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INITIAL_DELAY_INSTALL)) {
if (json)
json_object_boolean_true_add(json,
"initialDelay");
else
vty_out(vty, ", Initial Delay");
}
if (!json)
vty_out(vty, "\n");
}
if (nhe->ifp) {
if (json)
json_object_int_add(json, "interfaceIndex",
nhe->ifp->ifindex);
else
vty_out(vty, " Interface Index: %d\n",
nhe->ifp->ifindex);
}
if (!zebra_nhg_depends_is_empty(nhe)) {
if (json)
json_depends = json_object_new_array();
else
vty_out(vty, " Depends:");
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
if (json_depends)
json_object_array_add(
json_depends,
json_object_new_int(
rb_node_dep->nhe->id));
else
vty_out(vty, " (%u)", rb_node_dep->nhe->id);
}
if (!json_depends)
vty_out(vty, "\n");
else
json_object_object_add(json, "depends", json_depends);
}
/* Output nexthops */
if (json)
json_nexthop_array = json_object_new_array();
for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
if (json_nexthop_array) {
json_nexthops = json_object_new_object();
show_nexthop_json_helper(json_nexthops, nexthop, NULL,
NULL);
} else {
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
vty_out(vty, " ");
else
/* Make recursive nexthops a bit more clear */
vty_out(vty, " ");
show_route_nexthop_helper(vty, NULL, NULL, nexthop);
}
if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_HAS_BACKUP)) {
if (json)
json_object_int_add(
json_nexthops, "backup",
nexthop->backup_idx[0]);
else
vty_out(vty, " [backup %d]",
nexthop->backup_idx[0]);
}
if (!json)
vty_out(vty, "\n");
else
json_object_array_add(json_nexthop_array,
json_nexthops);
continue;
}
if (!json) {
/* TODO -- print more useful backup info */
if (CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_HAS_BACKUP)) {
int i;
vty_out(vty, "[backup");
for (i = 0; i < nexthop->backup_num; i++)
vty_out(vty, " %d",
nexthop->backup_idx[i]);
vty_out(vty, "]");
}
vty_out(vty, "\n");
} else {
json_object_array_add(json_nexthop_array,
json_nexthops);
}
}
if (json)
json_object_object_add(json, "nexthops", json_nexthop_array);
/* Output backup nexthops (if any) */
backup_nhg = zebra_nhg_get_backup_nhg(nhe);
if (backup_nhg) {
if (json)
json_backup_nexthop_array = json_object_new_array();
else
vty_out(vty, " Backups:\n");
for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
if (json_backup_nexthop_array) {
json_backup_nexthops = json_object_new_object();
show_nexthop_json_helper(json_backup_nexthops,
nexthop, NULL, NULL);
json_object_array_add(json_backup_nexthop_array,
json_backup_nexthops);
} else {
if (!CHECK_FLAG(nexthop->flags,
NEXTHOP_FLAG_RECURSIVE))
vty_out(vty, " ");
else
/* Make recursive nexthops a bit more
* clear
*/
vty_out(vty, " ");
show_route_nexthop_helper(vty, NULL, NULL,
nexthop);
vty_out(vty, "\n");
}
}
if (json)
json_object_object_add(json, "backupNexthops",
json_backup_nexthop_array);
}
if (!zebra_nhg_dependents_is_empty(nhe)) {
if (json)
json_dependants = json_object_new_array();
else
vty_out(vty, " Dependents:");
frr_each(nhg_connected_tree, &nhe->nhg_dependents,
rb_node_dep) {
if (json)
json_object_array_add(
json_dependants,
json_object_new_int(
rb_node_dep->nhe->id));
else
vty_out(vty, " (%u)", rb_node_dep->nhe->id);
}
if (json)
json_object_object_add(json, "dependents",
json_dependants);
else
vty_out(vty, "\n");
}
if (nhe->nhg.nhgr.buckets) {
if (json) {
json_object_int_add(json, "buckets",
nhe->nhg.nhgr.buckets);
json_object_int_add(json, "idleTimer",
nhe->nhg.nhgr.idle_timer);
json_object_int_add(json, "unbalancedTimer",
nhe->nhg.nhgr.unbalanced_timer);
json_object_int_add(json, "unbalancedTime",
nhe->nhg.nhgr.unbalanced_time);
} else {
vty_out(vty,
" Buckets: %u Idle Timer: %u Unbalanced Timer: %u Unbalanced time: %" PRIu64
"\n",
nhe->nhg.nhgr.buckets, nhe->nhg.nhgr.idle_timer,
nhe->nhg.nhgr.unbalanced_timer,
nhe->nhg.nhgr.unbalanced_time);
}
}
if (json_nhe_hdr)
json_object_object_addf(json_nhe_hdr, json, "%u", nhe->id);
}
static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id,
json_object *json)
{
struct nhg_hash_entry *nhe = NULL;
nhe = zebra_nhg_lookup_id(id);
if (nhe)
show_nexthop_group_out(vty, nhe, json);
else {
if (json)
vty_json(vty, json);
else
vty_out(vty, "Nexthop Group ID: %u does not exist\n",
id);
return CMD_WARNING;
}
if (json)
vty_json(vty, json);
return CMD_SUCCESS;
}
/* Helper function for iteration through the hash of nexthop-groups/nhe-s */
struct nhe_show_context {
struct vty *vty;
vrf_id_t vrf_id;
afi_t afi;
int type;
json_object *json;
};
static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
{
struct nhe_show_context *ctx = arg;
struct nhg_hash_entry *nhe;
nhe = bucket->data; /* We won't be offered NULL buckets */
if (ctx->afi && nhe->afi != ctx->afi)
goto done;
if (ctx->vrf_id && nhe->vrf_id != ctx->vrf_id)
goto done;
if (ctx->type && nhe->type != ctx->type)
goto done;
show_nexthop_group_out(ctx->vty, nhe, ctx->json);
done:
return HASHWALK_CONTINUE;
}
static void show_nexthop_group_cmd_helper(struct vty *vty,
struct zebra_vrf *zvrf, afi_t afi,
int type, json_object *json)
{
struct nhe_show_context ctx;
ctx.vty = vty;
ctx.afi = afi;
ctx.vrf_id = zvrf->vrf->vrf_id;
ctx.type = type;
ctx.json = json;
hash_walk(zrouter.nhgs_id, nhe_show_walker, &ctx);
}
static void if_nexthop_group_dump_vty(struct vty *vty, struct interface *ifp)
{
struct zebra_if *zebra_if = NULL;
struct nhg_connected *rb_node_dep = NULL;
bool first = true;
zebra_if = ifp->info;
frr_each (nhg_connected_tree, &zebra_if->nhg_dependents, rb_node_dep) {
if (first) {
vty_out(vty, "Interface %s:\n", ifp->name);
first = false;
}
vty_out(vty, " ");
show_nexthop_group_out(vty, rb_node_dep->nhe, NULL);
}
}
DEFPY (show_interface_nexthop_group,
show_interface_nexthop_group_cmd,
"show interface [IFNAME$if_name] nexthop-group",
SHOW_STR
"Interface status and configuration\n"
"Interface name\n"
"Show Nexthop Groups\n")
{
struct vrf *vrf = NULL;
struct interface *ifp = NULL;
bool found = false;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (if_name) {
ifp = if_lookup_by_name(if_name, vrf->vrf_id);
if (ifp) {
if_nexthop_group_dump_vty(vty, ifp);
found = true;
}
} else {
FOR_ALL_INTERFACES (vrf, ifp)
if_nexthop_group_dump_vty(vty, ifp);
found = true;
}
}
if (!found) {
vty_out(vty, "%% Can't find interface %s\n", if_name);
return CMD_WARNING;
}
return CMD_SUCCESS;
}
DEFPY(show_nexthop_group,
show_nexthop_group_cmd,
"show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]> [json]",
SHOW_STR
"Show Nexthop Groups\n"
"RIB information\n"
"Nexthop Group ID\n"
"Show Singleton Nexthop-Groups\n"
IP_STR
IP6_STR
"Kernel (not installed via the zebra RIB)\n"
"Zebra (implicitly created by zebra)\n"
"Border Gateway Protocol (BGP)\n"
"Super Happy Advanced Routing Protocol (SHARP)\n"
VRF_FULL_CMD_HELP_STR
JSON_STR)
{
struct zebra_vrf *zvrf = NULL;
afi_t afi = AFI_UNSPEC;
int type = 0;
bool uj = use_json(argc, argv);
json_object *json = NULL;
json_object *json_vrf = NULL;
if (uj)
json = json_object_new_object();
if (id)
return show_nexthop_group_id_cmd_helper(vty, id, json);
if (v4)
afi = AFI_IP;
else if (v6)
afi = AFI_IP6;
if (type_str) {
type = proto_redistnum((afi ? afi : AFI_IP), type_str);
if (type < 0) {
/* assume zebra */
type = ZEBRA_ROUTE_NHG;
}
}
if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
if (uj)
vty_json(vty, json);
else
vty_out(vty,
"VRF subcommand does not make any sense in l3mdev based vrf's\n");
return CMD_WARNING;
}
if (vrf_all) {
struct vrf *vrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
struct zebra_vrf *zvrf;
zvrf = vrf->info;
if (!zvrf)
continue;
if (uj)
json_vrf = json_object_new_object();
else
vty_out(vty, "VRF: %s\n", vrf->name);
show_nexthop_group_cmd_helper(vty, zvrf, afi, type,
json_vrf);
if (uj)
json_object_object_add(json, vrf->name,
json_vrf);
}
if (uj)
vty_json(vty, json);
return CMD_SUCCESS;
}
if (vrf_name)
zvrf = zebra_vrf_lookup_by_name(vrf_name);
else
zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
if (!zvrf) {
if (uj)
vty_json(vty, json);
else
vty_out(vty, "%% VRF '%s' specified does not exist\n",
vrf_name);
return CMD_WARNING;
}
show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json);
if (uj)
vty_json(vty, json);
return CMD_SUCCESS;
}
DEFPY_HIDDEN(nexthop_group_use_enable,
nexthop_group_use_enable_cmd,
"[no] zebra nexthop kernel enable",
NO_STR
ZEBRA_STR
"Nexthop configuration \n"
"Configure use of kernel nexthops\n"
"Enable kernel nexthops\n")
{
zebra_nhg_enable_kernel_nexthops(!no);
return CMD_SUCCESS;
}
DEFPY_HIDDEN(proto_nexthop_group_only, proto_nexthop_group_only_cmd,
"[no] zebra nexthop proto only",
NO_STR ZEBRA_STR
"Nexthop configuration\n"
"Configure exclusive use of proto nexthops\n"
"Only use proto nexthops\n")
{
zebra_nhg_set_proto_nexthops_only(!no);
return CMD_SUCCESS;
}
DEFPY_HIDDEN(backup_nexthop_recursive_use_enable,
backup_nexthop_recursive_use_enable_cmd,
"[no] zebra nexthop resolve-via-backup",
NO_STR
ZEBRA_STR
"Nexthop configuration \n"
"Configure use of backup nexthops in recursive resolution\n")
{
zebra_nhg_set_recursive_use_backups(!no);
return CMD_SUCCESS;
}
DEFPY_HIDDEN(rnh_hide_backups, rnh_hide_backups_cmd,
"[no] ip nht hide-backup-events",
NO_STR
IP_STR
"Nexthop-tracking configuration\n"
"Hide notification about backup nexthops\n")
{
rnh_set_hide_backups(!no);
return CMD_SUCCESS;
}
DEFPY (show_route,
show_route_cmd,
"show\
<\
ip$ipv4 <fib$fib|route>\
[{\
table <(1-4294967295)$table|all$table_all>\
|mrib$mrib\
|vrf <NAME$vrf_name|all$vrf_all>\
}]\
[{\
tag (1-4294967295)\
|A.B.C.D/M$prefix longer-prefixes\
|supernets-only$supernets_only\
}]\
[<\
" FRR_IP_REDIST_STR_ZEBRA "$type_str\
|ospf$type_str (1-65535)$ospf_instance_id\
>]\
|ipv6$ipv6 <fib$fib|route>\
[{\
table <(1-4294967295)$table|all$table_all>\
|mrib$mrib\
|vrf <NAME$vrf_name|all$vrf_all>\
}]\
[{\
tag (1-4294967295)\
|X:X::X:X/M$prefix longer-prefixes\
}]\
[" FRR_IP6_REDIST_STR_ZEBRA "$type_str]\
>\
[<json$json|nexthop-group$ng>]",
SHOW_STR
IP_STR
"IP forwarding table\n"
"IP routing table\n"
"Table to display\n"
"The table number to display\n"
"All tables\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR
"Show only routes with tag\n"
"Tag value\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
"Show route matching the specified Network/Mask pair only\n"
"Show supernet entries only\n"
FRR_IP_REDIST_HELP_STR_ZEBRA
"Open Shortest Path First (OSPFv2)\n"
"Instance ID\n"
IPV6_STR
"IP forwarding table\n"
"IP routing table\n"
"Table to display\n"
"The table number to display\n"
"All tables\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR
"Show only routes with tag\n"
"Tag value\n"
"IPv6 prefix\n"
"Show route matching the specified Network/Mask pair only\n"
FRR_IP6_REDIST_HELP_STR_ZEBRA
JSON_STR
"Nexthop Group Information\n")
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
bool first_vrf_json = true;
struct vrf *vrf;
int type = 0;
struct zebra_vrf *zvrf;
struct route_show_ctx ctx = {
.multi = vrf_all || table_all,
};
if (!vrf_is_backend_netns()) {
if ((vrf_all || vrf_name) && (table || table_all)) {
if (!!json)
vty_out(vty, "{}\n");
else {
vty_out(vty, "Linux vrf backend already points to table id\n");
vty_out(vty, "Either remove table parameter or vrf parameter\n");
}
return CMD_SUCCESS;
}
}
if (type_str) {
type = proto_redistnum(afi, type_str);
if (type < 0) {
vty_out(vty, "Unknown route type\n");
return CMD_WARNING;
}
}
if (vrf_all) {
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) == NULL || (zvrf->table[afi][safi] == NULL))
continue;
if (json)
vty_json_key(vty, zvrf_name(zvrf),
&first_vrf_json);
if (table_all)
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
prefix_str ? prefix : NULL, !!supernets_only,
type, ospf_instance_id, !!ng, &ctx);
else
do_show_ip_route(vty, zvrf_name(zvrf), afi, safi, !!fib, !!json,
tag, prefix_str ? prefix : NULL, !!supernets_only,
type, ospf_instance_id, table, !!ng, &ctx);
}
if (json)
vty_json_close(vty, first_vrf_json);
} else {
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, !!json);
vrf = vrf_lookup_by_id(vrf_id);
if (!vrf)
return CMD_SUCCESS;
zvrf = vrf->info;
if (!zvrf)
return CMD_SUCCESS;
if (table_all)
do_show_ip_route_all(vty, zvrf, afi, safi, !!fib, !!json, tag,
prefix_str ? prefix : NULL, !!supernets_only, type,
ospf_instance_id, !!ng, &ctx);
else
do_show_ip_route(vty, vrf->name, afi, safi, !!fib, !!json, tag,
prefix_str ? prefix : NULL, !!supernets_only, type,
ospf_instance_id, table, !!ng, &ctx);
}
return CMD_SUCCESS;
}
ALIAS_DEPRECATED (show_route,
show_ip_rpf_cmd,
"show <ip$ipv4|ipv6$ipv6> rpf$mrib [json$json]",
SHOW_STR
IP_STR
IPV6_STR
"Display RPF information for multicast source\n"
JSON_STR);
ALIAS_HIDDEN (show_route,
show_ro_cmd,
"show <ip$ipv4|ipv6$ipv6> ro",
SHOW_STR
IP_STR
IPV6_STR
"IP routing table\n");
DEFPY (show_route_detail,
show_route_detail_cmd,
"show\
<\
ip$ipv4 <fib$fib|route>\
[{\
mrib$mrib\
|vrf <NAME$vrf_name|all$vrf_all>\
}]\
<\
A.B.C.D$address\
|A.B.C.D/M$prefix\
>\
|ipv6$ipv6 <fib$fib|route>\
[{\
mrib$mrib\
|vrf <NAME$vrf_name|all$vrf_all>\
}]\
<\
X:X::X:X$address\
|X:X::X:X/M$prefix\
>\
>\
[json$json] [nexthop-group$ng]",
SHOW_STR
IP_STR
"IP forwarding table\n"
"IP routing table\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR
"Network in the IP routing table to display\n"
"IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
IP6_STR
"IPv6 forwarding table\n"
"IPv6 routing table\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR
"IPv6 Address\n"
"IPv6 prefix\n"
JSON_STR
"Nexthop Group Information\n")
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
struct route_table *table;
struct prefix p;
struct route_node *rn;
bool use_fib = !!fib;
rib_dest_t *dest;
bool network_found = false;
bool show_ng = !!ng;
int idx = 0;
/*
* Return error if V6 address/prefix is passed as an argument to
* "show ip route" cmd.
*
* When "show ip route <X:X::X:X|X:X::X:X/M>" is queried,
* argv[idx]->text will be set to "ipv6" but argv[idx]->arg will be set
* to "ip".
*/
if (argv_find(argv, argc, "ipv6", &idx) && !strcmp(argv[idx]->arg, "ip")) {
vty_out(vty, "%% Cannot specify IPv6 address/prefix for IPv4 table\n");
return CMD_WARNING;
}
if (address_str)
prefix_str = address_str;
if (str2prefix(prefix_str, &p) < 0) {
vty_out(vty, "%% Malformed address\n");
return CMD_WARNING;
}
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) == NULL || (table = zvrf->table[afi][safi]) == NULL)
continue;
rn = route_node_match(table, &p);
if (!rn)
continue;
if (!address_str && rn->p.prefixlen != p.prefixlen) {
route_unlock_node(rn);
continue;
}
dest = rib_dest_from_rnode(rn);
if (use_fib && !dest->selected_fib) {
route_unlock_node(rn);
continue;
}
network_found = true;
if (json)
vty_show_ip_route_detail_json(vty, rn, use_fib);
else
vty_show_ip_route_detail(vty, rn, (safi == SAFI_MULTICAST), use_fib,
show_ng);
route_unlock_node(rn);
}
if (!network_found) {
if (json)
vty_out(vty, "{}\n");
else {
if (use_fib)
vty_out(vty,
"%% Network not in FIB\n");
else
vty_out(vty,
"%% Network not in RIB\n");
}
return CMD_WARNING;
}
} else {
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
table = zebra_vrf_table(afi, safi, vrf_id);
if (!table)
return CMD_SUCCESS;
rn = route_node_match(table, &p);
if (rn)
dest = rib_dest_from_rnode(rn);
if (!rn || (!address_str && rn->p.prefixlen != p.prefixlen) ||
(use_fib && dest && !dest->selected_fib)) {
if (json)
vty_out(vty, "{}\n");
else {
if (use_fib)
vty_out(vty,
"%% Network not in FIB\n");
else
vty_out(vty,
"%% Network not in table\n");
}
if (rn)
route_unlock_node(rn);
return CMD_WARNING;
}
if (json)
vty_show_ip_route_detail_json(vty, rn, use_fib);
else
vty_show_ip_route_detail(vty, rn, (safi == SAFI_MULTICAST), use_fib,
show_ng);
route_unlock_node(rn);
}
return CMD_SUCCESS;
}
DEFPY (show_route_summary,
show_route_summary_cmd,
"show <ip$ipv4|ipv6$ipv6> route [{mrib$mrib|vrf <NAME$vrf_name|all$vrf_all>}] \
summary [table (1-4294967295)$table_id] [prefix$prefix] [json]",
SHOW_STR
IP_STR
IP6_STR
"IP routing table\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR
"Summary of all routes\n"
"Table to display summary for\n"
"The table number\n"
"Prefix routes\n"
JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
struct route_table *table;
bool uj = use_json(argc, argv);
json_object *vrf_json = NULL;
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
if (uj && !vrf_json)
vrf_json = json_object_new_object();
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) == NULL)
continue;
if (table_id == 0)
table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
else
table = zebra_vrf_lookup_table_with_table_id(afi, safi,
zvrf->vrf->vrf_id,
table_id);
if (!table)
continue;
if (prefix)
vty_show_ip_route_summary_prefix(vty, table,
vrf_json, uj);
else
vty_show_ip_route_summary(vty, table, vrf_json,
uj);
}
if (uj)
vty_json(vty, vrf_json);
} else {
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
if (table_id == 0)
table = zebra_vrf_table(afi, safi, vrf_id);
else
table = zebra_vrf_lookup_table_with_table_id(afi, safi, vrf_id, table_id);
if (!table)
return CMD_SUCCESS;
if (prefix)
vty_show_ip_route_summary_prefix(vty, table, NULL, uj);
else
vty_show_ip_route_summary(vty, table, NULL, uj);
}
return CMD_SUCCESS;
}
DEFPY_HIDDEN (show_route_zebra_dump,
show_route_zebra_dump_cmd,
"show <ip$ipv4|ipv6$ipv6> zebra route dump [{mrib$mrib|vrf <NAME$vrf_name|all$vrf_all>}]",
SHOW_STR
IP_STR
IP6_STR
"Zebra daemon\n"
"Routing table\n"
"All information\n"
"Multicast SAFI table\n"
VRF_FULL_CMD_HELP_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
struct route_table *table;
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = vrf->info;
if (zvrf == NULL)
continue;
table = zebra_vrf_table(afi, safi, zvrf->vrf->vrf_id);
if (!table)
continue;
show_ip_route_dump_vty(vty, table, afi, safi);
}
} else {
vrf_id_t vrf_id = VRF_DEFAULT;
if (vrf_name)
VRF_GET_ID(vrf_id, vrf_name, false);
table = zebra_vrf_table(afi, safi, vrf_id);
if (!table)
return CMD_SUCCESS;
show_ip_route_dump_vty(vty, table, afi, safi);
}
return CMD_SUCCESS;
}
static void show_ip_route_nht_dump(struct vty *vty,
const struct nexthop *nexthop,
const struct route_node *rn,
const struct route_entry *re,
unsigned int num)
{
char buf[SRCDEST2STR_BUFFER];
vty_out(vty, " Nexthop %u:\n", num);
vty_out(vty, " type: %u\n", nexthop->type);
vty_out(vty, " flags: %u\n", nexthop->flags);
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
vty_out(vty, " ip address: %s\n",
inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
sizeof(buf)));
vty_out(vty, " afi: ipv4\n");
if (nexthop->ifindex) {
vty_out(vty, " interface index: %d\n",
nexthop->ifindex);
vty_out(vty, " interface name: %s\n",
ifindex2ifname(nexthop->ifindex,
nexthop->vrf_id));
}
if (nexthop->rmap_src.ipv4.s_addr)
vty_out(vty, " rmapsrc: %pI4\n",
&nexthop->rmap_src.ipv4);
else if (nexthop->src.ipv4.s_addr)
vty_out(vty, " source: %pI4\n",
&nexthop->src.ipv4.s_addr);
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
vty_out(vty, " ip: %s\n",
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
sizeof(buf)));
vty_out(vty, " afi: ipv6\n");
if (nexthop->ifindex) {
vty_out(vty, " interface index: %d\n",
nexthop->ifindex);
vty_out(vty, " interface name: %s\n",
ifindex2ifname(nexthop->ifindex,
nexthop->vrf_id));
}
/* Allow for 5549 ipv4 prefix with ipv6 nexthop */
if (rn->p.family == AF_INET && nexthop->rmap_src.ipv4.s_addr)
vty_out(vty, " rmapsrc: %pI4\n",
&nexthop->rmap_src.ipv4);
else if (!IPV6_ADDR_SAME(&nexthop->rmap_src.ipv6, &in6addr_any))
vty_out(vty, " rmapsrc: %pI6\n",
&nexthop->rmap_src.ipv6);
else if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any))
vty_out(vty, " source: %pI6\n", &nexthop->src.ipv6);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty,
" Nexthop is an interface (directly connected).\n");
vty_out(vty, " interface index: %d\n", nexthop->ifindex);
vty_out(vty, " interface name: %s\n",
ifindex2ifname(nexthop->ifindex, nexthop->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
vty_out(vty, " Nexthop type is blackhole.\n");
switch (nexthop->bh_type) {
case BLACKHOLE_REJECT:
vty_out(vty, " Blackhole type: reject\n");
break;
case BLACKHOLE_ADMINPROHIB:
vty_out(vty,
" Blackhole type: admin-prohibited\n");
break;
case BLACKHOLE_NULL:
vty_out(vty, " Blackhole type: NULL0\n");
break;
case BLACKHOLE_UNSPEC:
break;
}
break;
}
}
static void show_ip_route_dump_vty(struct vty *vty, struct route_table *table, afi_t afi,
safi_t safi)
{
struct route_node *rn;
struct route_entry *re;
char buf[SRCDEST2STR_BUFFER];
char time[20];
time_t uptime;
struct tm tm;
struct timeval tv;
struct nexthop *nexthop = NULL;
int nexthop_num = 0;
vty_out(vty, "\n%s %s Routing table dump\n", afi2str(afi), safi2str(safi));
vty_out(vty, "----------------------------\n");
for (rn = route_top(table); rn; rn = route_next(rn)) {
RNODE_FOREACH_RE (rn, re) {
vty_out(vty, "Route: %s\n",
srcdest_rnode2str(rn, buf, sizeof(buf)));
vty_out(vty, " protocol: %s\n",
zebra_route_string(re->type));
vty_out(vty, " instance: %u\n", re->instance);
vty_out(vty, " VRF ID: %u\n", re->vrf_id);
vty_out(vty, " VRF name: %s\n",
vrf_id_to_name(re->vrf_id));
vty_out(vty, " flags: %u\n", re->flags);
if (re->type != ZEBRA_ROUTE_CONNECT &&
re->type != ZEBRA_ROUTE_LOCAL) {
vty_out(vty, " distance: %u\n", re->distance);
vty_out(vty, " metric: %u\n", re->metric);
}
vty_out(vty, " tag: %u\n", re->tag);
uptime = monotime(&tv);
uptime -= re->uptime;
gmtime_r(&uptime, &tm);
if (uptime < ONE_DAY_SECOND)
snprintf(time, sizeof(time), "%02d:%02d:%02d",
tm.tm_hour, tm.tm_min, tm.tm_sec);
else if (uptime < ONE_WEEK_SECOND)
snprintf(time, sizeof(time), "%dd%02dh%02dm",
tm.tm_yday, tm.tm_hour, tm.tm_min);
else
snprintf(time, sizeof(time), "%02dw%dd%02dh",
tm.tm_yday / 7,
tm.tm_yday - ((tm.tm_yday / 7) * 7),
tm.tm_hour);
vty_out(vty, " status: %u\n", re->status);
vty_out(vty, " nexthop_num: %u\n",
nexthop_group_nexthop_num(&(re->nhe->nhg)));
vty_out(vty, " nexthop_active_num: %u\n",
nexthop_group_active_nexthop_num(
&(re->nhe->nhg)));
vty_out(vty, " table: %u\n", re->table);
vty_out(vty, " uptime: %s\n", time);
for (ALL_NEXTHOPS_PTR(&(re->nhe->nhg), nexthop)) {
nexthop_num++;
show_ip_route_nht_dump(vty, nexthop, rn, re,
nexthop_num);
}
nexthop_num = 0;
vty_out(vty, "\n");
}
}
}
static void vty_show_ip_route_summary(struct vty *vty, struct route_table *table,
json_object *vrf_json, bool use_json)
{
struct route_node *rn;
struct route_entry *re;
#define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX
#define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1)
uint32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t offload_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t trap_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t i;
uint32_t is_ibgp;
json_object *json_route_summary = NULL;
json_object *json_route_routes = NULL;
const char *vrf_name = zvrf_name(
((struct rib_table_info *)route_table_get_info(table))->zvrf);
memset(&rib_cnt, 0, sizeof(rib_cnt));
memset(&fib_cnt, 0, sizeof(fib_cnt));
memset(&offload_cnt, 0, sizeof(offload_cnt));
memset(&trap_cnt, 0, sizeof(trap_cnt));
if (use_json) {
json_route_summary = json_object_new_object();
json_route_routes = json_object_new_array();
json_object_object_add(json_route_summary, "routes",
json_route_routes);
}
for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
RNODE_FOREACH_RE (rn, re) {
is_ibgp = (re->type == ZEBRA_ROUTE_BGP
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP));
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
if (is_ibgp)
rib_cnt[ZEBRA_ROUTE_IBGP]++;
else
rib_cnt[re->type]++;
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
if (is_ibgp)
fib_cnt[ZEBRA_ROUTE_IBGP]++;
else
fib_cnt[re->type]++;
}
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_TRAPPED)) {
if (is_ibgp)
trap_cnt[ZEBRA_ROUTE_IBGP]++;
else
trap_cnt[re->type]++;
}
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED)) {
if (is_ibgp)
offload_cnt[ZEBRA_ROUTE_IBGP]++;
else
offload_cnt[re->type]++;
}
}
if (!use_json)
vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
"Routes", "FIB", vrf_name);
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if ((rib_cnt[i] > 0) || (i == ZEBRA_ROUTE_BGP
&& rib_cnt[ZEBRA_ROUTE_IBGP] > 0)) {
if (i == ZEBRA_ROUTE_BGP) {
if (use_json) {
json_object *json_route_ebgp =
json_object_new_object();
json_object_int_add(
json_route_ebgp, "fib",
fib_cnt[ZEBRA_ROUTE_BGP]);
json_object_int_add(
json_route_ebgp, "rib",
rib_cnt[ZEBRA_ROUTE_BGP]);
json_object_int_add(
json_route_ebgp, "fibOffLoaded",
offload_cnt[ZEBRA_ROUTE_BGP]);
json_object_int_add(
json_route_ebgp, "fibTrapped",
trap_cnt[ZEBRA_ROUTE_BGP]);
json_object_string_add(json_route_ebgp,
"type", "ebgp");
json_object_array_add(json_route_routes,
json_route_ebgp);
json_object *json_route_ibgp =
json_object_new_object();
json_object_int_add(
json_route_ibgp, "fib",
fib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_int_add(
json_route_ibgp, "rib",
rib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_int_add(
json_route_ibgp, "fibOffLoaded",
offload_cnt[ZEBRA_ROUTE_IBGP]);
json_object_int_add(
json_route_ibgp, "fibTrapped",
trap_cnt[ZEBRA_ROUTE_IBGP]);
json_object_string_add(json_route_ibgp,
"type", "ibgp");
json_object_array_add(json_route_routes,
json_route_ibgp);
} else {
vty_out(vty, "%-20s %-20d %-20d \n",
"ebgp",
rib_cnt[ZEBRA_ROUTE_BGP],
fib_cnt[ZEBRA_ROUTE_BGP]);
vty_out(vty, "%-20s %-20d %-20d \n",
"ibgp",
rib_cnt[ZEBRA_ROUTE_IBGP],
fib_cnt[ZEBRA_ROUTE_IBGP]);
}
} else {
if (use_json) {
json_object *json_route_type =
json_object_new_object();
json_object_int_add(json_route_type,
"fib", fib_cnt[i]);
json_object_int_add(json_route_type,
"rib", rib_cnt[i]);
json_object_int_add(json_route_type,
"fibOffLoaded",
offload_cnt[i]);
json_object_int_add(json_route_type,
"fibTrapped",
trap_cnt[i]);
json_object_string_add(
json_route_type, "type",
zebra_route_string(i));
json_object_array_add(json_route_routes,
json_route_type);
} else
vty_out(vty, "%-20s %-20d %-20d \n",
zebra_route_string(i),
rib_cnt[i], fib_cnt[i]);
}
}
}
if (use_json) {
json_object_int_add(json_route_summary, "routesTotal",
rib_cnt[ZEBRA_ROUTE_TOTAL]);
json_object_int_add(json_route_summary, "routesTotalFib",
fib_cnt[ZEBRA_ROUTE_TOTAL]);
if (!vrf_json)
vty_json(vty, json_route_summary);
else
json_object_object_add(vrf_json, vrf_name,
json_route_summary);
} else {
vty_out(vty, "------\n");
vty_out(vty, "%-20s %-20d %-20d \n", "Totals",
rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL]);
vty_out(vty, "\n");
}
}
/*
* Implementation of the ip route summary prefix command.
*
* This command prints the primary prefixes that have been installed by various
* protocols on the box.
*
*/
static void vty_show_ip_route_summary_prefix(struct vty *vty,
struct route_table *table,
json_object *vrf_json,
bool use_json)
{
struct route_node *rn;
struct route_entry *re;
struct nexthop *nexthop;
#define ZEBRA_ROUTE_IBGP ZEBRA_ROUTE_MAX
#define ZEBRA_ROUTE_TOTAL (ZEBRA_ROUTE_IBGP + 1)
uint32_t rib_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t fib_cnt[ZEBRA_ROUTE_TOTAL + 1];
uint32_t i;
int cnt;
json_object *json_route_summary = NULL;
json_object *json_route_routes = NULL;
const char *vrf_name = zvrf_name(
((struct rib_table_info *)route_table_get_info(table))->zvrf);
memset(&rib_cnt, 0, sizeof(rib_cnt));
memset(&fib_cnt, 0, sizeof(fib_cnt));
if (use_json) {
json_route_summary = json_object_new_object();
json_route_routes = json_object_new_array();
json_object_object_add(json_route_summary, "prefixRoutes",
json_route_routes);
}
for (rn = route_top(table); rn; rn = srcdest_route_next(rn))
RNODE_FOREACH_RE (rn, re) {
/*
* In case of ECMP, count only once.
*/
cnt = 0;
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
fib_cnt[ZEBRA_ROUTE_TOTAL]++;
fib_cnt[re->type]++;
}
for (nexthop = re->nhe->nhg.nexthop; (!cnt && nexthop);
nexthop = nexthop->next) {
cnt++;
rib_cnt[ZEBRA_ROUTE_TOTAL]++;
rib_cnt[re->type]++;
if (re->type == ZEBRA_ROUTE_BGP
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP)) {
rib_cnt[ZEBRA_ROUTE_IBGP]++;
if (CHECK_FLAG(re->status,
ROUTE_ENTRY_INSTALLED))
fib_cnt[ZEBRA_ROUTE_IBGP]++;
}
}
}
if (!use_json)
vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
"Prefix Routes", "FIB", vrf_name);
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (rib_cnt[i] > 0) {
if (i == ZEBRA_ROUTE_BGP) {
if (use_json) {
json_object *json_route_ebgp =
json_object_new_object();
json_object_int_add(
json_route_ebgp, "fib",
fib_cnt[ZEBRA_ROUTE_BGP]
- fib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_int_add(
json_route_ebgp, "rib",
rib_cnt[ZEBRA_ROUTE_BGP]
- rib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_string_add(json_route_ebgp,
"type", "ebgp");
json_object_array_add(json_route_routes,
json_route_ebgp);
json_object *json_route_ibgp =
json_object_new_object();
json_object_int_add(
json_route_ibgp, "fib",
fib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_int_add(
json_route_ibgp, "rib",
rib_cnt[ZEBRA_ROUTE_IBGP]);
json_object_string_add(json_route_ibgp,
"type", "ibgp");
json_object_array_add(json_route_routes,
json_route_ibgp);
} else {
vty_out(vty, "%-20s %-20d %-20d \n",
"ebgp",
rib_cnt[ZEBRA_ROUTE_BGP]
- rib_cnt[ZEBRA_ROUTE_IBGP],
fib_cnt[ZEBRA_ROUTE_BGP]
- fib_cnt[ZEBRA_ROUTE_IBGP]);
vty_out(vty, "%-20s %-20d %-20d \n",
"ibgp",
rib_cnt[ZEBRA_ROUTE_IBGP],
fib_cnt[ZEBRA_ROUTE_IBGP]);
}
} else {
if (use_json) {
json_object *json_route_type =
json_object_new_object();
json_object_int_add(json_route_type,
"fib", fib_cnt[i]);
json_object_int_add(json_route_type,
"rib", rib_cnt[i]);
json_object_string_add(
json_route_type, "type",
zebra_route_string(i));
json_object_array_add(json_route_routes,
json_route_type);
} else
vty_out(vty, "%-20s %-20d %-20d \n",
zebra_route_string(i),
rib_cnt[i], fib_cnt[i]);
}
}
}
if (use_json) {
json_object_int_add(json_route_summary, "prefixRoutesTotal",
rib_cnt[ZEBRA_ROUTE_TOTAL]);
json_object_int_add(json_route_summary, "prefixRoutesTotalFib",
fib_cnt[ZEBRA_ROUTE_TOTAL]);
if (!vrf_json)
vty_json(vty, json_route_summary);
else
json_object_object_add(vrf_json, vrf_name,
json_route_summary);
} else {
vty_out(vty, "------\n");
vty_out(vty, "%-20s %-20d %-20d \n", "Totals",
rib_cnt[ZEBRA_ROUTE_TOTAL], fib_cnt[ZEBRA_ROUTE_TOTAL]);
vty_out(vty, "\n");
}
}
DEFUN (allow_external_route_update,
allow_external_route_update_cmd,
"allow-external-route-update",
"Allow FRR routes to be overwritten by external processes\n")
{
zrouter.allow_delete = true;
return CMD_SUCCESS;
}
DEFUN (no_allow_external_route_update,
no_allow_external_route_update_cmd,
"no allow-external-route-update",
NO_STR
"Allow FRR routes to be overwritten by external processes\n")
{
zrouter.allow_delete = false;
return CMD_SUCCESS;
}
/* show vrf */
DEFUN (show_vrf,
show_vrf_cmd,
"show vrf",
SHOW_STR
"VRF\n")
{
struct vrf *vrf;
struct zebra_vrf *zvrf;
if (vrf_is_backend_netns())
vty_out(vty, "netns-based vrfs\n");
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (!(zvrf = vrf->info))
continue;
if (zvrf_id(zvrf) == VRF_DEFAULT)
continue;
vty_out(vty, "vrf %s ", zvrf_name(zvrf));
if (zvrf_id(zvrf) == VRF_UNKNOWN || !zvrf_is_active(zvrf))
vty_out(vty, "inactive");
else if (zvrf_ns_name(zvrf))
vty_out(vty, "id %u netns %s", zvrf_id(zvrf),
zvrf_ns_name(zvrf));
else
vty_out(vty, "id %u table %u", zvrf_id(zvrf),
zvrf->table_id);
if (vrf_is_user_cfged(vrf))
vty_out(vty, " (configured)");
vty_out(vty, "\n");
}
return CMD_SUCCESS;
}
DEFPY (evpn_mh_mac_holdtime,
evpn_mh_mac_holdtime_cmd,
"[no$no] evpn mh mac-holdtime (0-86400)$duration",
NO_STR
"EVPN\n"
"Multihoming\n"
"MAC hold time\n"
"Duration in seconds\n")
{
return zebra_evpn_mh_mac_holdtime_update(vty, duration,
no ? true : false);
}
DEFPY (evpn_mh_neigh_holdtime,
evpn_mh_neigh_holdtime_cmd,
"[no$no] evpn mh neigh-holdtime (0-86400)$duration",
NO_STR
"EVPN\n"
"Multihoming\n"
"Neighbor entry hold time\n"
"Duration in seconds\n")
{
return zebra_evpn_mh_neigh_holdtime_update(vty, duration,
no ? true : false);
}
DEFPY (evpn_mh_startup_delay,
evpn_mh_startup_delay_cmd,
"[no] evpn mh startup-delay(0-3600)$duration",
NO_STR
"EVPN\n"
"Multihoming\n"
"Startup delay\n"
"duration in seconds\n")
{
return zebra_evpn_mh_startup_delay_update(vty, duration,
no ? true : false);
}
DEFPY(evpn_mh_redirect_off, evpn_mh_redirect_off_cmd,
"[no$no] evpn mh redirect-off",
NO_STR
"EVPN\n"
"Multihoming\n"
"ES bond redirect for fast-failover off\n")
{
bool redirect_off;
redirect_off = no ? false : true;
return zebra_evpn_mh_redirect_off(vty, redirect_off);
}
/* show vrf */
DEFPY (show_vrf_vni,
show_vrf_vni_cmd,
"show vrf [<NAME$vrf_name|all$vrf_all>] vni [json]",
SHOW_STR
VRF_FULL_CMD_HELP_STR
"VNI\n"
JSON_STR)
{
struct vrf *vrf;
struct zebra_vrf *zvrf;
json_object *json = NULL;
json_object *json_vrfs = NULL;
bool uj = use_json(argc, argv);
bool use_vrf = false;
if (uj)
json = json_object_new_object();
/* show vrf vni used to display across all vrfs
* This is enhanced to support only for specific
* vrf based output.
*/
if (vrf_all || !vrf_name) {
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = vrf->info;
if (!zvrf)
continue;
use_vrf = true;
break;
}
if (use_vrf) {
if (!uj)
vty_out(vty,
"%-37s %-10s %-20s %-20s %-5s %-18s\n",
"VRF", "VNI", "VxLAN IF", "L3-SVI",
"State", "Rmac");
else
json_vrfs = json_object_new_array();
} else {
if (uj)
vty_json(vty, json);
else
vty_out(vty, "%% VRF does not exist\n");
return CMD_WARNING;
}
}
if (use_vrf) {
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
zvrf = vrf->info;
if (!zvrf)
continue;
zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
}
} else if (vrf_name) {
zvrf = zebra_vrf_lookup_by_name(vrf_name);
if (!zvrf) {
if (uj)
vty_json(vty, json);
else
vty_out(vty,
"%% VRF '%s' specified does not exist\n",
vrf_name);
return CMD_WARNING;
}
if (!uj)
vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n",
"VRF", "VNI", "VxLAN IF", "L3-SVI", "State",
"Rmac");
else
json_vrfs = json_object_new_array();
zebra_vxlan_print_vrf_vni(vty, zvrf, json_vrfs);
}
if (uj) {
json_object_object_add(json, "vrfs", json_vrfs);
vty_json(vty, json);
}
return CMD_SUCCESS;
}
DEFUN (show_evpn_global,
show_evpn_global_cmd,
"show evpn [json]",
SHOW_STR
"EVPN\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
zebra_vxlan_print_evpn(vty, uj);
return CMD_SUCCESS;
}
DEFPY(show_evpn_neigh, show_neigh_cmd, "show ip neigh",
SHOW_STR IP_STR "neighbors\n")
{
zebra_neigh_show(vty);
return CMD_SUCCESS;
}
DEFPY(show_evpn_l2_nh,
show_evpn_l2_nh_cmd,
"show evpn l2-nh [json$json]",
SHOW_STR
"EVPN\n"
"Layer2 nexthops\n"
JSON_STR)
{
bool uj = !!json;
zebra_evpn_l2_nh_show(vty, uj);
return CMD_SUCCESS;
}
DEFPY(show_evpn_es,
show_evpn_es_cmd,
"show evpn es [NAME$esi_str|detail$detail] [json$json]",
SHOW_STR
"EVPN\n"
"Ethernet Segment\n"
"ES ID\n"
"Detailed information\n"
JSON_STR)
{
esi_t esi;
bool uj = !!json;
if (esi_str) {
if (!str_to_esi(esi_str, &esi)) {
vty_out(vty, "%% Malformed ESI\n");
return CMD_WARNING;
}
zebra_evpn_es_show_esi(vty, uj, &esi);
} else {
if (detail)
zebra_evpn_es_show_detail(vty, uj);
else
zebra_evpn_es_show(vty, uj);
}
return CMD_SUCCESS;
}
DEFPY(show_evpn_es_evi,
show_evpn_es_evi_cmd,
"show evpn es-evi [vni (1-16777215)$vni] [detail$detail] [json$json]",
SHOW_STR
"EVPN\n"
"Ethernet Segment per EVI\n"
"VxLAN Network Identifier\n"
"VNI\n"
"Detailed information\n"
JSON_STR)
{
bool uj = !!json;
bool ud = !!detail;
if (vni)
zebra_evpn_es_evi_show_vni(vty, uj, vni, ud);
else
zebra_evpn_es_evi_show(vty, uj, ud);
return CMD_SUCCESS;
}
DEFPY(show_evpn_access_vlan, show_evpn_access_vlan_cmd,
"show evpn access-vlan [IFNAME$if_name (1-4094)$vid | detail$detail] [json$json]",
SHOW_STR
"EVPN\n"
"Access VLANs\n"
"Interface Name\n"
"VLAN ID\n"
"Detailed information\n" JSON_STR)
{
bool uj = !!json;
if (if_name && vid) {
bool found = false;
struct vrf *vrf;
struct interface *ifp;
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (if_name) {
ifp = if_lookup_by_name(if_name, vrf->vrf_id);
if (ifp) {
zebra_evpn_acc_vl_show_vid(vty, uj, vid,
ifp);
found = true;
break;
}
}
}
if (!found) {
vty_out(vty, "%% Can't find interface %s\n", if_name);
return CMD_WARNING;
}
} else {
if (detail)
zebra_evpn_acc_vl_show_detail(vty, uj);
else
zebra_evpn_acc_vl_show(vty, uj);
}
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni,
show_evpn_vni_cmd,
"show evpn vni [json]",
SHOW_STR
"EVPN\n"
"VxLAN Network Identifier\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vnis(vty, zvrf, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni_detail, show_evpn_vni_detail_cmd,
"show evpn vni detail [json]",
SHOW_STR
"EVPN\n"
"VxLAN Network Identifier\n"
"Detailed Information On Each VNI\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vnis_detail(vty, zvrf, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_vni_vni,
show_evpn_vni_vni_cmd,
"show evpn vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"VxLAN Network Identifier\n"
"VNI number\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
bool uj = use_json(argc, argv);
vni = strtoul(argv[3]->arg, NULL, 10);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_vni(vty, zvrf, vni, uj, NULL);
return CMD_SUCCESS;
}
DEFUN (show_evpn_rmac_vni_mac,
show_evpn_rmac_vni_mac_cmd,
"show evpn rmac vni " CMD_VNI_RANGE " mac WORD [json]",
SHOW_STR
"EVPN\n"
"RMAC\n"
"L3 VNI\n"
"VNI number\n"
"MAC\n"
"mac-address (e.g. 0a:0a:0a:0a:0a:0a)\n"
JSON_STR)
{
vni_t l3vni = 0;
struct ethaddr mac;
bool uj = use_json(argc, argv);
l3vni = strtoul(argv[4]->arg, NULL, 10);
if (!prefix_str2mac(argv[6]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
zebra_vxlan_print_specific_rmac_l3vni(vty, l3vni, &mac, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_rmac_vni,
show_evpn_rmac_vni_cmd,
"show evpn rmac vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"RMAC\n"
"L3 VNI\n"
"VNI number\n"
JSON_STR)
{
vni_t l3vni = 0;
bool uj = use_json(argc, argv);
l3vni = strtoul(argv[4]->arg, NULL, 10);
zebra_vxlan_print_rmacs_l3vni(vty, l3vni, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_rmac_vni_all,
show_evpn_rmac_vni_all_cmd,
"show evpn rmac vni all [json]",
SHOW_STR
"EVPN\n"
"RMAC addresses\n"
"L3 VNI\n"
"All VNIs\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
zebra_vxlan_print_rmacs_all_l3vni(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_nh_vni_ip,
show_evpn_nh_vni_ip_cmd,
"show evpn next-hops vni " CMD_VNI_RANGE " ip WORD [json]",
SHOW_STR
"EVPN\n"
"Remote Vteps\n"
"L3 VNI\n"
"VNI number\n"
"Ip address\n"
"Host address (ipv4 or ipv6)\n"
JSON_STR)
{
vni_t l3vni;
struct ipaddr ip;
bool uj = use_json(argc, argv);
l3vni = strtoul(argv[4]->arg, NULL, 10);
if (str2ipaddr(argv[6]->arg, &ip) != 0) {
if (!uj)
vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
zebra_vxlan_print_specific_nh_l3vni(vty, l3vni, &ip, uj);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (show_evpn_nh_svd_ip,
show_evpn_nh_svd_ip_cmd,
"show evpn next-hops svd ip WORD [json]",
SHOW_STR
"EVPN\n"
"Remote Vteps\n"
"Single Vxlan Device\n"
"Ip address\n"
"Host address (ipv4 or ipv6)\n"
JSON_STR)
{
struct ipaddr ip;
bool uj = use_json(argc, argv);
if (str2ipaddr(argv[5]->arg, &ip) != 0) {
if (!uj)
vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
zebra_vxlan_print_specific_nh_l3vni(vty, 0, &ip, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_nh_vni,
show_evpn_nh_vni_cmd,
"show evpn next-hops vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"Remote Vteps\n"
"L3 VNI\n"
"VNI number\n"
JSON_STR)
{
vni_t l3vni;
bool uj = use_json(argc, argv);
l3vni = strtoul(argv[4]->arg, NULL, 10);
zebra_vxlan_print_nh_l3vni(vty, l3vni, uj);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (show_evpn_nh_svd,
show_evpn_nh_svd_cmd,
"show evpn next-hops svd [json]",
SHOW_STR
"EVPN\n"
"Remote VTEPs\n"
"Single Vxlan Device\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
zebra_vxlan_print_nh_svd(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_nh_vni_all,
show_evpn_nh_vni_all_cmd,
"show evpn next-hops vni all [json]",
SHOW_STR
"EVPN\n"
"Remote VTEPs\n"
"L3 VNI\n"
"All VNIs\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
zebra_vxlan_print_nh_all_l3vni(vty, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni,
show_evpn_mac_vni_cmd,
"show evpn mac vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj, false);
return CMD_SUCCESS;
}
DEFPY (show_evpn_mac_vni_detail,
show_evpn_mac_vni_detail_cmd,
"show evpn mac vni " CMD_VNI_RANGE " detail [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VXLAN Network Identifier\n"
"VNI number\n"
"Detailed Information On Each VNI MAC\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj, true);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all,
show_evpn_mac_vni_all_cmd,
"show evpn mac vni all [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all_detail, show_evpn_mac_vni_all_detail_cmd,
"show evpn mac vni all detail [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Detailed Information On Each VNI MAC\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni_detail(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_all_vtep,
show_evpn_mac_vni_all_vtep_cmd,
"show evpn mac vni all vtep A.B.C.D [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Remote VTEP\n"
"Remote VTEP IP address\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
struct in_addr vtep_ip;
bool uj = use_json(argc, argv);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_mac,
show_evpn_mac_vni_mac_cmd,
"show evpn mac vni " CMD_VNI_RANGE " mac WORD [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"MAC\n"
"MAC address (e.g., 00:e0:ec:20:12:62)\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct ethaddr mac;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (!prefix_str2mac(argv[6]->arg, &mac)) {
vty_out(vty, "%% Malformed MAC address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_specific_mac_vni(vty, zvrf, vni, &mac, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_mac_vni_vtep,
show_evpn_mac_vni_vtep_cmd,
"show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D" "[json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
"Remote VTEP IP address\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
DEFPY (show_evpn_mac_vni_all_dad,
show_evpn_mac_vni_all_dad_cmd,
"show evpn mac vni all duplicate [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Duplicate address list\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_all_vni(vty, zvrf, true, uj);
return CMD_SUCCESS;
}
DEFPY (show_evpn_mac_vni_dad,
show_evpn_mac_vni_dad_cmd,
"show evpn mac vni " CMD_VNI_RANGE " duplicate [json]",
SHOW_STR
"EVPN\n"
"MAC addresses\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Duplicate address list\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_macs_vni_dad(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFPY (show_evpn_neigh_vni_dad,
show_evpn_neigh_vni_dad_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE "duplicate [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Duplicate address list\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni_dad(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFPY (show_evpn_neigh_vni_all_dad,
show_evpn_neigh_vni_all_dad_cmd,
"show evpn arp-cache vni all duplicate [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Duplicate address list\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni(vty, zvrf, true, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni,
show_evpn_neigh_vni_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE "[json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_all,
show_evpn_neigh_vni_all_cmd,
"show evpn arp-cache vni all [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_all_detail, show_evpn_neigh_vni_all_detail_cmd,
"show evpn arp-cache vni all detail [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"All VNIs\n"
"Neighbor details for all vnis in detail\n" JSON_STR)
{
struct zebra_vrf *zvrf;
bool uj = use_json(argc, argv);
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_all_vni_detail(vty, zvrf, false, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_neigh,
show_evpn_neigh_vni_neigh_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Neighbor\n"
"Neighbor address (IPv4 or IPv6 address)\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct ipaddr ip;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (str2ipaddr(argv[6]->arg, &ip) != 0) {
if (!uj)
vty_out(vty, "%% Malformed Neighbor address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj);
return CMD_SUCCESS;
}
DEFUN (show_evpn_neigh_vni_vtep,
show_evpn_neigh_vni_vtep_cmd,
"show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D [json]",
SHOW_STR
"EVPN\n"
"ARP and ND cache\n"
"VxLAN Network Identifier\n"
"VNI number\n"
"Remote VTEP\n"
"Remote VTEP IP address\n"
JSON_STR)
{
struct zebra_vrf *zvrf;
vni_t vni;
struct in_addr vtep_ip;
bool uj = use_json(argc, argv);
vni = strtoul(argv[4]->arg, NULL, 10);
if (!inet_aton(argv[6]->arg, &vtep_ip)) {
if (!uj)
vty_out(vty, "%% Malformed VTEP IP address\n");
return CMD_WARNING;
}
zvrf = zebra_vrf_get_evpn();
zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj);
return CMD_SUCCESS;
}
/* policy routing contexts */
DEFUN (show_pbr_ipset,
show_pbr_ipset_cmd,
"show pbr ipset [WORD]",
SHOW_STR
"Policy-Based Routing\n"
"IPset Context information\n"
"IPset Name information\n")
{
int idx = 0;
int found = 0;
found = argv_find(argv, argc, "WORD", &idx);
if (!found)
zebra_pbr_show_ipset_list(vty, NULL);
else
zebra_pbr_show_ipset_list(vty, argv[idx]->arg);
return CMD_SUCCESS;
}
/* policy routing contexts */
DEFUN (show_pbr_iptable,
show_pbr_iptable_cmd,
"show pbr iptable [WORD]",
SHOW_STR
"Policy-Based Routing\n"
"IPtable Context information\n"
"IPtable Name information\n")
{
int idx = 0;
int found = 0;
found = argv_find(argv, argc, "WORD", &idx);
if (!found)
zebra_pbr_show_iptable(vty, NULL);
else
zebra_pbr_show_iptable(vty, argv[idx]->arg);
return CMD_SUCCESS;
}
/* policy routing contexts */
DEFPY (show_pbr_rule,
show_pbr_rule_cmd,
"show pbr rule",
SHOW_STR
"Policy-Based Routing\n"
"Rule\n")
{
zebra_pbr_show_rule(vty);
return CMD_SUCCESS;
}
DEFPY (pbr_nexthop_resolve,
pbr_nexthop_resolve_cmd,
"[no$no] pbr nexthop-resolve",
NO_STR
"Policy Based Routing\n"
"Resolve nexthop for dataplane programming\n")
{
zebra_pbr_expand_action_update(!no);
return CMD_SUCCESS;
}
DEFPY (clear_evpn_dup_addr,
clear_evpn_dup_addr_cmd,
"clear evpn dup-addr vni <all$vni_all |" CMD_VNI_RANGE"$vni [mac X:X:X:X:X:X | ip <A.B.C.D|X:X::X:X>]>",
CLEAR_STR
"EVPN\n"
"Duplicate address \n"
"VxLAN Network Identifier\n"
"VNI number\n"
"All VNIs\n"
"MAC\n"
"MAC address (e.g., 00:e0:ec:20:12:62)\n"
"IP\n"
"IPv4 address\n"
"IPv6 address\n")
{
if (!vni_str) {
nb_cli_rpc_enqueue(vty, "all-vnis", NULL);
} else {
nb_cli_rpc_enqueue(vty, "vni-id", vni_str);
if (mac_str)
nb_cli_rpc_enqueue(vty, "mac-addr", mac_str);
else if (ip_str)
nb_cli_rpc_enqueue(vty, "vni-ipaddr", ip_str);
}
return nb_cli_rpc(vty, "/frr-zebra:clear-evpn-dup-addr", NULL);
}
DEFPY_HIDDEN (evpn_accept_bgp_seq,
evpn_accept_bgp_seq_cmd,
"evpn accept-bgp-seq",
"EVPN\n"
"Accept all sequence numbers from BGP\n")
{
zebra_vxlan_set_accept_bgp_seq(true);
return CMD_SUCCESS;
}
DEFPY_HIDDEN (no_evpn_accept_bgp_seq,
no_evpn_accept_bgp_seq_cmd,
"no evpn accept-bgp-seq",
NO_STR
"EVPN\n"
"Accept all sequence numbers from BGP\n")
{
zebra_vxlan_set_accept_bgp_seq(false);
return CMD_SUCCESS;
}
/* Static ip route configuration write function. */
static int zebra_ip_config(struct vty *vty)
{
int write = 0;
write += zebra_import_table_config(vty, VRF_DEFAULT);
return write;
}
DEFPY (ip_zebra_import_table_distance,
ip_zebra_import_table_distance_cmd,
"ip import-table (1-252)$table_id [mrib]$mrib [distance (1-255)$distance] [route-map RMAP_NAME$rmap]",
IP_STR
"import routes from non-main kernel table\n"
"kernel routing table id\n"
"Import into the MRIB instead of the URIB\n"
"Distance for imported routes\n"
"Default distance value\n"
"route-map for filtering\n"
"route-map name\n")
{
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
if (distance_str == NULL)
distance = ZEBRA_TABLE_DISTANCE_DEFAULT;
if (!is_zebra_valid_kernel_table(table_id)) {
vty_out(vty, "Invalid routing table ID, %ld. Must be in range 1-252\n", table_id);
return CMD_WARNING;
}
if (is_zebra_main_routing_table(table_id)) {
vty_out(vty, "Invalid routing table ID, %ld. Must be non-default table\n", table_id);
return CMD_WARNING;
}
return zebra_import_table(AFI_IP, safi, VRF_DEFAULT, table_id, distance, rmap, true);
}
DEFUN_HIDDEN (zebra_packet_process,
zebra_packet_process_cmd,
"zebra zapi-packets (1-10000)",
ZEBRA_STR
"Zapi Protocol\n"
"Number of packets to process before relinquishing thread\n")
{
uint32_t packets = strtoul(argv[2]->arg, NULL, 10);
atomic_store_explicit(&zrouter.packets_to_process, packets,
memory_order_relaxed);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (no_zebra_packet_process,
no_zebra_packet_process_cmd,
"no zebra zapi-packets [(1-10000)]",
NO_STR
ZEBRA_STR
"Zapi Protocol\n"
"Number of packets to process before relinquishing thread\n")
{
atomic_store_explicit(&zrouter.packets_to_process,
ZEBRA_ZAPI_PACKETS_TO_PROCESS,
memory_order_relaxed);
return CMD_SUCCESS;
}
DEFUN_HIDDEN (zebra_workqueue_timer,
zebra_workqueue_timer_cmd,
"zebra work-queue (0-10000)",
ZEBRA_STR
"Work Queue\n"
"Time in milliseconds\n")
{
uint32_t timer = strtoul(argv[2]->arg, NULL, 10);
zrouter.ribq->spec.hold = timer;
return CMD_SUCCESS;
}
DEFUN_HIDDEN (no_zebra_workqueue_timer,
no_zebra_workqueue_timer_cmd,
"no zebra work-queue [(0-10000)]",
NO_STR
ZEBRA_STR
"Work Queue\n"
"Time in milliseconds\n")
{
zrouter.ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
return CMD_SUCCESS;
}
DEFPY (no_ip_zebra_import_table,
no_ip_zebra_import_table_cmd,
"no ip import-table (1-252)$table_id [mrib]$mrib [distance (1-255)] [route-map NAME]",
NO_STR
IP_STR
"import routes from non-main kernel table\n"
"kernel routing table id\n"
"Import into the MRIB instead of the URIB\n"
"Distance for imported routes\n"
"Default distance value\n"
"route-map for filtering\n"
"route-map name\n")
{
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
if (!is_zebra_valid_kernel_table(table_id)) {
vty_out(vty,
"Invalid routing table ID. Must be in range 1-252\n");
return CMD_WARNING;
}
if (is_zebra_main_routing_table(table_id)) {
vty_out(vty, "Invalid routing table ID, %ld. Must be non-default table\n", table_id);
return CMD_WARNING;
}
if (!is_zebra_import_table_enabled(AFI_IP, safi, VRF_DEFAULT, table_id))
return CMD_SUCCESS;
return (zebra_import_table(AFI_IP, safi, VRF_DEFAULT, table_id, 0, NULL, false));
}
DEFPY (zebra_nexthop_group_keep,
zebra_nexthop_group_keep_cmd,
"[no] zebra nexthop-group keep (1-3600)",
NO_STR
ZEBRA_STR
"Nexthop-Group\n"
"How long to keep\n"
"Time in seconds from 1-3600\n")
{
if (no)
zrouter.nhg_keep = ZEBRA_DEFAULT_NHG_KEEP_TIMER;
else
zrouter.nhg_keep = keep;
return CMD_SUCCESS;
}
static int config_write_protocol(struct vty *vty)
{
if (zrouter.allow_delete)
vty_out(vty, "allow-external-route-update\n");
if (zrouter.nhg_keep != ZEBRA_DEFAULT_NHG_KEEP_TIMER)
vty_out(vty, "zebra nexthop-group keep %u\n", zrouter.nhg_keep);
if (zrouter.ribq->spec.hold != ZEBRA_RIB_PROCESS_HOLD_TIME)
vty_out(vty, "zebra work-queue %u\n", zrouter.ribq->spec.hold);
if (zrouter.packets_to_process != ZEBRA_ZAPI_PACKETS_TO_PROCESS)
vty_out(vty, "zebra zapi-packets %u\n",
zrouter.packets_to_process);
/* Include dataplane info */
dplane_config_write_helper(vty);
zebra_evpn_mh_config_write(vty);
zebra_pbr_config_write(vty);
if (!zebra_vxlan_get_accept_bgp_seq())
vty_out(vty, "no evpn accept-bgp-seq\n");
/* Include nexthop-group config */
if (!zebra_nhg_kernel_nexthops_enabled())
vty_out(vty, "no zebra nexthop kernel enable\n");
if (zebra_nhg_proto_nexthops_only())
vty_out(vty, "zebra nexthop proto only\n");
if (!zebra_nhg_recursive_use_backups())
vty_out(vty, "no zebra nexthop resolve-via-backup\n");
#ifdef HAVE_SCRIPTING
frrscript_names_config_write(vty);
#endif
if (rnh_get_hide_backups())
vty_out(vty, "ip nht hide-backup-events\n");
#ifdef HAVE_NETLINK
/* Include netlink info */
netlink_config_write_helper(vty);
#endif /* HAVE_NETLINK */
return 1;
}
static inline bool zebra_vty_v6_rr_semantics_used(void)
{
if (zebra_nhg_kernel_nexthops_enabled())
return true;
if (zrouter.v6_rr_semantics)
return true;
return false;
}
DEFUN (show_zebra,
show_zebra_cmd,
"show zebra",
SHOW_STR
ZEBRA_STR)
{
struct vrf *vrf;
struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
char *out;
char timebuf[MONOTIME_STRLEN];
time_to_string(zrouter.startup_time, timebuf);
vty_out(vty, "Zebra started%s at time %s",
zrouter.graceful_restart ? " gracefully" : "", timebuf);
if (zrouter.t_rib_sweep)
vty_out(vty,
"Zebra RIB sweep timer running, remaining time %lds\n",
event_timer_remain_second(zrouter.t_rib_sweep));
else {
time_to_string(zrouter.rib_sweep_time, timebuf);
vty_out(vty, "Zebra RIB sweep happened at %s", timebuf);
}
ttable_rowseps(table, 0, BOTTOM, true, '-');
ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get());
ttable_add_row(table, "ECMP Maximum|%d", zrouter.multipath_num);
ttable_add_row(table, "v4 Forwarding|%s", ipforward() ? "On" : "Off");
ttable_add_row(table, "v6 Forwarding|%s",
ipforward_ipv6() ? "On" : "Off");
ttable_add_row(table, "MPLS|%s", mpls_enabled ? "On" : "Off");
ttable_add_row(table, "EVPN|%s", is_evpn_enabled() ? "On" : "Off");
ttable_add_row(table, "Kernel socket buffer size|%d", rcvbufsize);
ttable_add_row(table, "v6 Route Replace Semantics|%s",
zebra_vty_v6_rr_semantics_used() ? "Replace"
: "Delete then Add");
#ifdef GNU_LINUX
if (!vrf_is_backend_netns())
ttable_add_row(table, "VRF|l3mdev Available");
else
ttable_add_row(table, "VRF|Namespaces");
#else
ttable_add_row(table, "VRF|Not Available");
#endif
ttable_add_row(table, "v6 with v4 nexthop|%s",
zrouter.v6_with_v4_nexthop ? "Used" : "Unavaliable");
ttable_add_row(table, "ASIC offload|%s",
zrouter.asic_offloaded ? "Used" : "Unavailable");
/*
* Do not display this unless someone is actually using it
*
* Why this distinction? I think this is effectively dead code
* and should not be exposed. Maybe someone proves me wrong.
*/
if (zrouter.asic_notification_nexthop_control)
ttable_add_row(table, "ASIC offload and nexthop control|Used");
ttable_add_row(table, "RA|%s",
rtadv_compiled_in() ? "Compiled in" : "Not Compiled in");
ttable_add_row(table, "RFC 5549|%s",
rtadv_get_interfaces_configured_from_bgp()
? "BGP is using"
: "BGP is not using");
ttable_add_row(table, "Kernel NHG|%s",
zrouter.supports_nhgs ? "Available" : "Unavailable");
ttable_add_row(table, "Allow Non FRR route deletion|%s",
zrouter.allow_delete ? "Yes" : "No");
ttable_add_row(table, "v4 All LinkDown Routes|%s",
zrouter.all_linkdownv4 ? "On" : "Off");
ttable_add_row(table, "v4 Default LinkDown Routes|%s",
zrouter.default_linkdownv4 ? "On" : "Off");
ttable_add_row(table, "v6 All LinkDown Routes|%s",
zrouter.all_linkdownv6 ? "On" : "Off");
ttable_add_row(table, "v6 Default LinkDown Routes|%s",
zrouter.default_linkdownv6 ? "On" : "Off");
ttable_add_row(table, "v4 All MC Forwarding|%s",
zrouter.all_mc_forwardingv4 ? "On" : "Off");
ttable_add_row(table, "v4 Default MC Forwarding|%s",
zrouter.default_mc_forwardingv4 ? "On" : "Off");
ttable_add_row(table, "v6 All MC Forwarding|%s",
zrouter.all_mc_forwardingv6 ? "On" : "Off");
ttable_add_row(table, "v6 Default MC Forwarding|%s",
zrouter.default_mc_forwardingv6 ? "On" : "Off");
out = ttable_dump(table, "\n");
vty_out(vty, "%s\n", out);
XFREE(MTYPE_TMP_TTABLE, out);
ttable_del(table);
vty_out(vty,
" Route Route Neighbor LSP LSP\n");
vty_out(vty,
"VRF Installs Removals Updates Installs Removals\n");
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
struct zebra_vrf *zvrf = vrf->info;
vty_out(vty, "%-25s %10" PRIu64 " %10" PRIu64 " %10" PRIu64" %10" PRIu64 " %10" PRIu64 "\n",
vrf->name, zvrf->installs, zvrf->removals,
zvrf->neigh_updates, zvrf->lsp_installs,
zvrf->lsp_removals);
}
return CMD_SUCCESS;
}
DEFUN (ip_forwarding,
ip_forwarding_cmd,
"ip forwarding",
IP_STR
"Turn on IP forwarding\n")
{
int ret;
ret = ipforward();
if (ret == 0)
ret = ipforward_on();
if (ret == 0) {
vty_out(vty, "Can't turn on IP forwarding\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
DEFUN (no_ip_forwarding,
no_ip_forwarding_cmd,
"no ip forwarding",
NO_STR
IP_STR
"Turn off IP forwarding\n")
{
int ret;
ret = ipforward();
if (ret != 0)
ret = ipforward_off();
if (ret != 0) {
vty_out(vty, "Can't turn off IP forwarding\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
/* Only display ip forwarding is enabled or not. */
DEFUN (show_ip_forwarding,
show_ip_forwarding_cmd,
"show ip forwarding",
SHOW_STR
IP_STR
"IP forwarding status\n")
{
int ret;
ret = ipforward();
if (ret == 0)
vty_out(vty, "IP forwarding is off\n");
else
vty_out(vty, "IP forwarding is on\n");
return CMD_SUCCESS;
}
/* Only display ipv6 forwarding is enabled or not. */
DEFUN (show_ipv6_forwarding,
show_ipv6_forwarding_cmd,
"show ipv6 forwarding",
SHOW_STR
"IPv6 information\n"
"Forwarding status\n")
{
int ret;
ret = ipforward_ipv6();
switch (ret) {
case -1:
vty_out(vty, "ipv6 forwarding is unknown\n");
break;
case 0:
vty_out(vty, "ipv6 forwarding is %s\n", "off");
break;
case 1:
vty_out(vty, "ipv6 forwarding is %s\n", "on");
break;
default:
vty_out(vty, "ipv6 forwarding is %s\n", "off");
break;
}
return CMD_SUCCESS;
}
DEFUN (ipv6_forwarding,
ipv6_forwarding_cmd,
"ipv6 forwarding",
IPV6_STR
"Turn on IPv6 forwarding\n")
{
int ret;
ret = ipforward_ipv6();
if (ret == 0)
ret = ipforward_ipv6_on();
if (ret == 0) {
vty_out(vty, "Can't turn on IPv6 forwarding\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
DEFUN (no_ipv6_forwarding,
no_ipv6_forwarding_cmd,
"no ipv6 forwarding",
NO_STR
IPV6_STR
"Turn off IPv6 forwarding\n")
{
int ret;
ret = ipforward_ipv6();
if (ret != 0)
ret = ipforward_ipv6_off();
if (ret != 0) {
vty_out(vty, "Can't turn off IPv6 forwarding\n");
return CMD_WARNING_CONFIG_FAILED;
}
return CMD_SUCCESS;
}
/* Display dataplane info */
DEFUN (show_dataplane,
show_dataplane_cmd,
"show zebra dplane [detailed]",
SHOW_STR
ZEBRA_STR
"Zebra dataplane information\n"
"Detailed output\n")
{
int idx = 0;
bool detailed = false;
if (argv_find(argv, argc, "detailed", &idx))
detailed = true;
return dplane_show_helper(vty, detailed);
}
/* Display dataplane providers info */
DEFUN (show_dataplane_providers,
show_dataplane_providers_cmd,
"show zebra dplane providers [detailed]",
SHOW_STR
ZEBRA_STR
"Zebra dataplane information\n"
"Zebra dataplane provider information\n"
"Detailed output\n")
{
int idx = 0;
bool detailed = false;
if (argv_find(argv, argc, "detailed", &idx))
detailed = true;
return dplane_show_provs_helper(vty, detailed);
}
/* Configure dataplane incoming queue limit */
DEFUN (zebra_dplane_queue_limit,
zebra_dplane_queue_limit_cmd,
"zebra dplane limit (0-10000)",
ZEBRA_STR
"Zebra dataplane\n"
"Limit incoming queued updates\n"
"Number of queued updates\n")
{
uint32_t limit = 0;
limit = strtoul(argv[3]->arg, NULL, 10);
dplane_set_in_queue_limit(limit, true);
return CMD_SUCCESS;
}
/* Reset dataplane queue limit to default value */
DEFUN (no_zebra_dplane_queue_limit,
no_zebra_dplane_queue_limit_cmd,
"no zebra dplane limit [(0-10000)]",
NO_STR
ZEBRA_STR
"Zebra dataplane\n"
"Limit incoming queued updates\n"
"Number of queued updates\n")
{
dplane_set_in_queue_limit(0, false);
return CMD_SUCCESS;
}
DEFUN (zebra_show_routing_tables_summary,
zebra_show_routing_tables_summary_cmd,
"show zebra router table summary",
SHOW_STR
ZEBRA_STR
"The Zebra Router Information\n"
"Table Information about this Zebra Router\n"
"Summary Information\n")
{
zebra_router_show_table_summary(vty);
return CMD_SUCCESS;
}
/* IPForwarding configuration write function. */
static int config_write_forwarding(struct vty *vty)
{
if (!ipforward())
vty_out(vty, "no ip forwarding\n");
if (!ipforward_ipv6())
vty_out(vty, "no ipv6 forwarding\n");
vty_out(vty, "!\n");
return 0;
}
DEFUN_HIDDEN (show_frr,
show_frr_cmd,
"show frr",
SHOW_STR
"FRR\n")
{
vty_out(vty, "........ .. . .. . ..... ...77:................................................\n");
vty_out(vty, ".............................7777:..............................................\n");
vty_out(vty, ".............................777777,............................................\n");
vty_out(vty, "... .........................77777777,..........................................\n");
vty_out(vty, "............................=7777777777:........................................\n");
vty_out(vty, "........................:7777777777777777,......................................\n");
vty_out(vty, ".................... ~7777777777777?~,..........................................\n");
vty_out(vty, "...................I7777777777+.................................................\n");
vty_out(vty, "................,777777777?............ .......................................\n");
vty_out(vty, "..............:77777777?..........~?77777.......................................\n");
vty_out(vty, ".............77777777~........=7777777777.......................................\n");
vty_out(vty, ".......... +7777777,.......?7777777777777.......................................\n");
vty_out(vty, "..........7777777~......:7777777777777777......77?,.............................\n");
vty_out(vty, "........:777777?......+777777777777777777......777777I,.........................\n");
vty_out(vty, ".......?777777,.....+77777777777777777777......777777777?.......................\n");
vty_out(vty, "......?777777......7777777777777777777777......,?777777777?.....................\n");
vty_out(vty, ".....?77777?.....=7777777777777777777I~............,I7777777~...................\n");
vty_out(vty, "....+77777+.....I77777777777777777:...................+777777I..................\n");
vty_out(vty, "...~77777+.....7777777777777777=........................?777777...... .......\n");
vty_out(vty, "...77777I.....I77777777777777~.........:?................,777777.....I777.......\n");
vty_out(vty, "..777777.....I7777777777777I .......?7777..................777777.....777?......\n");
vty_out(vty, ".~77777,....=7777777777777:......,7777777..................,77777+....+777......\n");
vty_out(vty, ".77777I.....7777777777777,......777777777.......ONNNN.......=77777.....777~.....\n");
vty_out(vty, ",77777.....I777777777777,.....:7777777777......DNNNNNN.......77777+ ...7777.....\n");
vty_out(vty, "I7777I.....777777777777=.....~77777777777......NNNNNNN~......=7777I....=777.....\n");
vty_out(vty, "77777:....=777777777777.....,777777777777......$NNNNND ......:77777....:777.....\n");
vty_out(vty, "77777. ...777777777777~.....7777777777777........7DZ,........:77777.....777.....\n");
vty_out(vty, "????? . ..777777777777.....,7777777777777....................:77777I....777.....\n");
vty_out(vty, "....... ..777777777777.....+7777777777777....................=7777777+...?7.....\n");
vty_out(vty, "..........77777777777I.....I7777777777777....................7777777777:........\n");
vty_out(vty, "..........77777777777I.....?7777777777777...................~777777777777.......\n");
vty_out(vty, "..........777777777777.....~7777777777777..................,77777777777777+.....\n");
vty_out(vty, "..........777777777777......7777777777777..................77777777777777777,...\n");
vty_out(vty, "..... ....?77777777777I.....~777777777777................,777777.....,:+77777I..\n");
vty_out(vty, "........ .:777777777777,.....?77777777777...............?777777..............,:=\n");
vty_out(vty, ".......... 7777777777777..... ?7777777777.............=7777777.....~777I........\n");
vty_out(vty, "...........:777777777777I......~777777777...........I7777777~.....+777I.........\n");
vty_out(vty, "..... ......7777777777777I.......I7777777.......+777777777I......7777I..........\n");
vty_out(vty, ".............77777777777777........?77777......777777777?......=7777=...........\n");
vty_out(vty, ".............,77777777777777+.........~77......777777I,......:77777.............\n");
vty_out(vty, "..............~777777777777777~................777777......:77777=..............\n");
vty_out(vty, "...............:7777777777777777?..............:777777,.....=77=................\n");
vty_out(vty, "................,777777777777777777?,...........,777777:.....,..................\n");
vty_out(vty, "........... ......I777777777777777777777I.........777777~.......................\n");
vty_out(vty, "...................,777777777777777777777..........777777+......................\n");
vty_out(vty, ".....................+7777777777777777777...........777777?.....................\n");
vty_out(vty, ".......................=77777777777777777............777777I....................\n");
vty_out(vty, ".........................:777777777777777.............I77777I...................\n");
vty_out(vty, "............................~777777777777..............+777777..................\n");
vty_out(vty, "................................~77777777...............=777777.................\n");
vty_out(vty, ".....................................:=?I................~777777................\n");
vty_out(vty, "..........................................................:777777,..............\n");
vty_out(vty, ".... ... ... . . .... ....... ....... ....................:777777..............\n");
return CMD_SUCCESS;
}
#ifdef HAVE_NETLINK
DEFUN_HIDDEN(zebra_kernel_netlink_batch_tx_buf,
zebra_kernel_netlink_batch_tx_buf_cmd,
"zebra kernel netlink batch-tx-buf (1-1048576) (1-1048576)",
ZEBRA_STR
"Zebra kernel interface\n"
"Set Netlink parameters\n"
"Set batch buffer size and send threshold\n"
"Size of the buffer\n"
"Send threshold\n")
{
uint32_t bufsize = 0, threshold = 0;
bufsize = strtoul(argv[4]->arg, NULL, 10);
threshold = strtoul(argv[5]->arg, NULL, 10);
netlink_set_batch_buffer_size(bufsize, threshold, true);
return CMD_SUCCESS;
}
DEFUN_HIDDEN(no_zebra_kernel_netlink_batch_tx_buf,
no_zebra_kernel_netlink_batch_tx_buf_cmd,
"no zebra kernel netlink batch-tx-buf [(0-1048576)] [(0-1048576)]",
NO_STR ZEBRA_STR
"Zebra kernel interface\n"
"Set Netlink parameters\n"
"Set batch buffer size and send threshold\n"
"Size of the buffer\n"
"Send threshold\n")
{
netlink_set_batch_buffer_size(0, 0, false);
return CMD_SUCCESS;
}
DEFPY (zebra_protodown_bit,
zebra_protodown_bit_cmd,
"zebra protodown reason-bit (0-31)$bit",
ZEBRA_STR
"Protodown Configuration\n"
"Reason Bit used in the kernel for application\n"
"Reason Bit range\n")
{
if_netlink_set_frr_protodown_r_bit(bit);
return CMD_SUCCESS;
}
DEFPY (no_zebra_protodown_bit,
no_zebra_protodown_bit_cmd,
"no zebra protodown reason-bit [(0-31)$bit]",
NO_STR
ZEBRA_STR
"Protodown Configuration\n"
"Reason Bit used in the kernel for setting protodown\n"
"Reason Bit Range\n")
{
if_netlink_unset_frr_protodown_r_bit();
return CMD_SUCCESS;
}
#endif /* HAVE_NETLINK */
#ifdef HAVE_SCRIPTING
DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd,
"zebra on-rib-process script SCRIPT",
ZEBRA_STR
"on_rib_process_dplane_results hook call\n"
"Set a script\n"
"Script name (same as filename in /etc/frr/scripts/, without .lua)\n")
{
if (frrscript_names_set_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL,
argv[3]->arg)
== 0) {
vty_out(vty, "Successfully added script %s for hook call %s\n",
argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
} else {
vty_out(vty, "Failed to add script %s for hook call %s\n",
argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL);
}
return CMD_SUCCESS;
}
#endif /* HAVE_SCRIPTING */
/* IP node for static routes. */
static int zebra_ip_config(struct vty *vty);
static struct cmd_node ip_node = {
.name = "static ip",
.node = IP_NODE,
.prompt = "",
.config_write = zebra_ip_config,
};
static int config_write_protocol(struct vty *vty);
static struct cmd_node protocol_node = {
.name = "protocol",
.node = PROTOCOL_NODE,
.prompt = "",
.config_write = config_write_protocol,
};
static int config_write_forwarding(struct vty *vty);
static struct cmd_node forwarding_node = {
.name = "forwarding",
.node = FORWARDING_NODE,
.prompt = "",
.config_write = config_write_forwarding,
};
/* Route VTY. */
void zebra_vty_init(void)
{
/* Install configuration write function. */
install_node(&forwarding_node);
install_element(VIEW_NODE, &show_ip_forwarding_cmd);
install_element(CONFIG_NODE, &ip_forwarding_cmd);
install_element(CONFIG_NODE, &no_ip_forwarding_cmd);
install_element(ENABLE_NODE, &show_zebra_cmd);
install_element(VIEW_NODE, &show_ipv6_forwarding_cmd);
install_element(CONFIG_NODE, &ipv6_forwarding_cmd);
install_element(CONFIG_NODE, &no_ipv6_forwarding_cmd);
/* Route-map */
zebra_route_map_init();
zebra_affinity_map_init();
install_node(&ip_node);
install_node(&protocol_node);
install_element(CONFIG_NODE, &allow_external_route_update_cmd);
install_element(CONFIG_NODE, &no_allow_external_route_update_cmd);
install_element(CONFIG_NODE, &zebra_nexthop_group_keep_cmd);
install_element(CONFIG_NODE, &ip_zebra_import_table_distance_cmd);
install_element(CONFIG_NODE, &no_ip_zebra_import_table_cmd);
install_element(CONFIG_NODE, &zebra_workqueue_timer_cmd);
install_element(CONFIG_NODE, &no_zebra_workqueue_timer_cmd);
install_element(CONFIG_NODE, &zebra_packet_process_cmd);
install_element(CONFIG_NODE, &no_zebra_packet_process_cmd);
install_element(CONFIG_NODE, &nexthop_group_use_enable_cmd);
install_element(CONFIG_NODE, &proto_nexthop_group_only_cmd);
install_element(CONFIG_NODE, &backup_nexthop_recursive_use_enable_cmd);
install_element(VIEW_NODE, &show_nexthop_group_cmd);
install_element(VIEW_NODE, &show_interface_nexthop_group_cmd);
install_element(VIEW_NODE, &show_vrf_cmd);
install_element(VIEW_NODE, &show_vrf_vni_cmd);
install_element(VIEW_NODE, &show_route_cmd);
install_element(VIEW_NODE, &show_ip_rpf_cmd);
install_element(VIEW_NODE, &show_ro_cmd);
install_element(VIEW_NODE, &show_route_detail_cmd);
install_element(VIEW_NODE, &show_route_summary_cmd);
install_element(VIEW_NODE, &show_ip_nht_cmd);
install_element(CONFIG_NODE, &rnh_hide_backups_cmd);
install_element(VIEW_NODE, &show_frr_cmd);
install_element(VIEW_NODE, &show_evpn_global_cmd);
install_element(VIEW_NODE, &show_evpn_vni_cmd);
install_element(VIEW_NODE, &show_evpn_vni_detail_cmd);
install_element(VIEW_NODE, &show_evpn_vni_vni_cmd);
install_element(VIEW_NODE, &show_evpn_l2_nh_cmd);
install_element(VIEW_NODE, &show_evpn_es_cmd);
install_element(VIEW_NODE, &show_evpn_es_evi_cmd);
install_element(VIEW_NODE, &show_evpn_access_vlan_cmd);
install_element(VIEW_NODE, &show_evpn_rmac_vni_mac_cmd);
install_element(VIEW_NODE, &show_evpn_rmac_vni_cmd);
install_element(VIEW_NODE, &show_evpn_rmac_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_ip_cmd);
install_element(VIEW_NODE, &show_evpn_nh_svd_ip_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_cmd);
install_element(VIEW_NODE, &show_evpn_nh_svd_cmd);
install_element(VIEW_NODE, &show_evpn_nh_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_all_detail_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_detail_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_all_vtep_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_mac_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_vtep_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_dad_cmd);
install_element(VIEW_NODE, &show_evpn_mac_vni_all_dad_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_detail_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_neigh_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_vtep_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_dad_cmd);
install_element(VIEW_NODE, &show_evpn_neigh_vni_all_dad_cmd);
install_element(ENABLE_NODE, &clear_evpn_dup_addr_cmd);
install_element(CONFIG_NODE, &evpn_accept_bgp_seq_cmd);
install_element(CONFIG_NODE, &no_evpn_accept_bgp_seq_cmd);
install_element(VIEW_NODE, &show_neigh_cmd);
install_element(VIEW_NODE, &show_pbr_ipset_cmd);
install_element(VIEW_NODE, &show_pbr_iptable_cmd);
install_element(VIEW_NODE, &show_pbr_rule_cmd);
install_element(CONFIG_NODE, &pbr_nexthop_resolve_cmd);
install_element(VIEW_NODE, &show_route_zebra_dump_cmd);
install_element(CONFIG_NODE, &evpn_mh_mac_holdtime_cmd);
install_element(CONFIG_NODE, &evpn_mh_neigh_holdtime_cmd);
install_element(CONFIG_NODE, &evpn_mh_startup_delay_cmd);
install_element(CONFIG_NODE, &evpn_mh_redirect_off_cmd);
install_element(VIEW_NODE, &show_dataplane_cmd);
install_element(VIEW_NODE, &show_dataplane_providers_cmd);
install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd);
install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd);
#ifdef HAVE_NETLINK
install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd);
install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);
install_element(CONFIG_NODE, &zebra_protodown_bit_cmd);
install_element(CONFIG_NODE, &no_zebra_protodown_bit_cmd);
#endif /* HAVE_NETLINK */
#ifdef HAVE_SCRIPTING
install_element(CONFIG_NODE, &zebra_on_rib_process_script_cmd);
#endif /* HAVE_SCRIPTING */
install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd);
}