+// SPDX-License-Identifier: GPL-2.0-or-later
/* Zebra VTY functions
* Copyright (C) 2002 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * GNU Zebra is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
#include "srcdest_table.h"
#include "vxlan.h"
#include "termtable.h"
+#include "affinitymap.h"
#include "zebra/zebra_router.h"
#include "zebra/zserv.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"
}
-DEFUN (show_ip_rpf,
+DEFPY (show_ip_rpf,
show_ip_rpf_cmd,
- "show ip rpf [json]",
+ "show [ip$ip|ipv6$ipv6] rpf [json]",
SHOW_STR
IP_STR
+ IPV6_STR
"Display RPF information for multicast source\n"
JSON_STR)
{
.multi = false,
};
- return do_show_ip_route(vty, VRF_DEFAULT_NAME, AFI_IP, SAFI_MULTICAST,
- false, uj, 0, NULL, false, 0, 0, 0, false,
- &ctx);
+ return do_show_ip_route(vty, VRF_DEFAULT_NAME, ip ? AFI_IP : AFI_IP6,
+ SAFI_MULTICAST, false, uj, 0, NULL, false, 0, 0,
+ 0, false, &ctx);
}
-DEFUN (show_ip_rpf_addr,
+DEFPY (show_ip_rpf_addr,
show_ip_rpf_addr_cmd,
- "show ip rpf A.B.C.D",
+ "show ip rpf A.B.C.D$address",
SHOW_STR
IP_STR
"Display RPF information for multicast source\n"
"IP multicast source address (e.g. 10.0.0.0)\n")
{
- int idx_ipv4 = 3;
- struct in_addr addr;
struct route_node *rn;
struct route_entry *re;
- int ret;
- ret = inet_aton(argv[idx_ipv4]->arg, &addr);
- if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING;
- }
+ re = rib_match_multicast(AFI_IP, VRF_DEFAULT, (union g_addr *)&address,
+ &rn);
- re = rib_match_ipv4_multicast(VRF_DEFAULT, addr, &rn);
+ if (re)
+ vty_show_ip_route_detail(vty, rn, 1, false, false);
+ else
+ vty_out(vty, "%% No match for RPF lookup\n");
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ipv6_rpf_addr,
+ show_ipv6_rpf_addr_cmd,
+ "show ipv6 rpf X:X::X:X$address",
+ SHOW_STR
+ IPV6_STR
+ "Display RPF information for multicast source\n"
+ "IPv6 multicast source address\n")
+{
+ struct route_node *rn;
+ struct route_entry *re;
+
+ re = rib_match_multicast(AFI_IP6, VRF_DEFAULT, (union g_addr *)&address,
+ &rn);
if (re)
vty_show_ip_route_detail(vty, rn, 1, false, false);
}
break;
- default:
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
break;
}
vty_out(vty, ", label %s",
mpls_label2str(nexthop->nh_label->num_labels,
nexthop->nh_label->label, buf,
- sizeof(buf), 1 /*pretty*/));
+ sizeof(buf), nexthop->nh_label_type,
+ 1 /*pretty*/));
}
if (nexthop->weight)
if (re->mtu)
vty_out(vty, ", mtu %u", re->mtu);
if (re->vrf_id != VRF_DEFAULT) {
- zvrf = vrf_info_lookup(re->vrf_id);
+ 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))
}
}
-/*
- * Helper for nexthop output, used in the 'show ip route' path
- */
-static void show_route_nexthop_helper(struct vty *vty,
- const struct route_entry *re,
- const struct nexthop *nexthop)
-{
- char buf[MPLS_LABEL_STRLEN];
- int i;
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " via %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
-
- case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is 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 == NULL || (nexthop->vrf_id != re->vrf_id)))
- vty_out(vty, " (vrf %s)", vrf_id_to_name(nexthop->vrf_id));
-
- 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)");
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- /* SR-TE information */
- if (nexthop->srte_color)
- vty_out(vty, ", SR-TE color %u",
- nexthop->srte_color);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
- if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
- sizeof(buf)))
- vty_out(vty, ", src %s", buf);
- }
- break;
- default:
- break;
- }
-
- /* 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), 1));
- }
-
- if (nexthop->nh_srv6) {
- seg6local_context2str(buf, sizeof(buf),
- &nexthop->nh_srv6->seg6local_ctx,
- nexthop->nh_srv6->seg6local_action);
- vty_out(vty, ", seg6local %s %s", seg6local_action2str(
- nexthop->nh_srv6->seg6local_action), buf);
-
- inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf,
- sizeof(buf));
- vty_out(vty, ", seg6 %s", buf);
- }
-
- 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]);
- }
-}
-
-/*
- * Render a nexthop into a json object; the caller allocates and owns
- * the json object memory.
- */
-static void show_nexthop_json_helper(json_object *json_nexthop,
- const struct nexthop *nexthop,
- const struct route_entry *re)
-{
- char buf[SRCDEST2STR_BUFFER];
- json_object *json_labels = NULL;
- json_object *json_backups = NULL;
- json_object *json_seg6local = NULL;
- json_object *json_seg6 = NULL;
- int i;
-
- json_object_int_add(json_nexthop, "flags",
- nexthop->flags);
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- json_object_boolean_true_add(json_nexthop,
- "duplicate");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
- json_object_boolean_true_add(json_nexthop,
- "fib");
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- json_object_string_addf(json_nexthop, "ip", "%pI4",
- &nexthop->gate.ipv4);
- json_object_string_add(json_nexthop, "afi",
- "ipv4");
-
- if (nexthop->ifindex) {
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- json_object_string_addf(json_nexthop, "ip", "%pI6",
- &nexthop->gate.ipv6);
- json_object_string_add(json_nexthop, "afi",
- "ipv6");
-
- if (nexthop->ifindex) {
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(
- nexthop->ifindex,
- nexthop->vrf_id));
- }
- break;
-
- case NEXTHOP_TYPE_IFINDEX:
- json_object_boolean_true_add(
- json_nexthop, "directlyConnected");
- json_object_int_add(json_nexthop,
- "interfaceIndex",
- nexthop->ifindex);
- json_object_string_add(
- json_nexthop, "interfaceName",
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
- break;
- case NEXTHOP_TYPE_BLACKHOLE:
- json_object_boolean_true_add(json_nexthop,
- "unreachable");
- switch (nexthop->bh_type) {
- case BLACKHOLE_REJECT:
- json_object_boolean_true_add(
- json_nexthop, "reject");
- break;
- case BLACKHOLE_ADMINPROHIB:
- json_object_boolean_true_add(
- json_nexthop,
- "admin-prohibited");
- break;
- case BLACKHOLE_NULL:
- json_object_boolean_true_add(
- json_nexthop, "blackhole");
- break;
- case BLACKHOLE_UNSPEC:
- break;
- }
- break;
- }
-
- /* This nexthop is a resolver for the parent nexthop.
- * Set resolver flag for better clarity and delimiter
- * in flat list of nexthops in json.
- */
- if (nexthop->rparent)
- json_object_boolean_true_add(json_nexthop, "resolver");
-
- if (nexthop->vrf_id != re->vrf_id)
- json_object_string_add(json_nexthop, "vrf",
- vrf_id_to_name(nexthop->vrf_id));
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
- json_object_boolean_true_add(json_nexthop,
- "duplicate");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
- json_object_boolean_true_add(json_nexthop,
- "active");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
- json_object_boolean_true_add(json_nexthop,
- "onLink");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_LINKDOWN))
- json_object_boolean_true_add(json_nexthop, "linkDown");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- json_object_boolean_true_add(json_nexthop,
- "recursive");
-
- if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
- json_backups = json_object_new_array();
- for (i = 0; i < nexthop->backup_num; i++) {
- json_object_array_add(
- json_backups,
- json_object_new_int(nexthop->backup_idx[i]));
- }
-
- json_object_object_add(json_nexthop, "backupIndex",
- json_backups);
- }
-
- switch (nexthop->type) {
- case NEXTHOP_TYPE_IPV4:
- case NEXTHOP_TYPE_IPV4_IFINDEX:
- if (nexthop->src.ipv4.s_addr) {
- if (inet_ntop(AF_INET,
- &nexthop->src.ipv4, buf,
- sizeof(buf)))
- json_object_string_add(
- json_nexthop, "source",
- buf);
- }
- break;
- case NEXTHOP_TYPE_IPV6:
- case NEXTHOP_TYPE_IPV6_IFINDEX:
- if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
- &in6addr_any)) {
- if (inet_ntop(AF_INET6,
- &nexthop->src.ipv6, buf,
- sizeof(buf)))
- json_object_string_add(
- json_nexthop, "source",
- buf);
- }
- break;
- default:
- break;
- }
-
- if (nexthop->nh_label
- && nexthop->nh_label->num_labels) {
- json_labels = json_object_new_array();
-
- for (int label_index = 0;
- label_index
- < nexthop->nh_label->num_labels;
- label_index++)
- json_object_array_add(
- json_labels,
- json_object_new_int(
- nexthop->nh_label->label
- [label_index]));
-
- json_object_object_add(json_nexthop, "labels",
- json_labels);
- }
-
- if (nexthop->weight)
- json_object_int_add(json_nexthop, "weight",
- nexthop->weight);
-
- if (nexthop->srte_color)
- json_object_int_add(json_nexthop, "srteColor",
- nexthop->srte_color);
-
- if (nexthop->nh_srv6) {
- json_seg6local = json_object_new_object();
- json_object_string_add(
- json_seg6local, "action", seg6local_action2str(
- nexthop->nh_srv6->seg6local_action));
- json_object_object_add(json_nexthop, "seg6local",
- json_seg6local);
-
- json_seg6 = json_object_new_object();
- inet_ntop(AF_INET6, &nexthop->nh_srv6->seg6_segs, buf,
- sizeof(buf));
- json_object_string_add(json_seg6, "segs", buf);
- json_object_object_add(json_nexthop, "seg6", json_seg6);
- }
-}
-
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)
zvrf_name(zvrf),
json_vrf);
json_object_object_add(json_vrf,
- "nexthops",
+ (afi == AFI_IP)
+ ? "ipv4"
+ : "ipv6",
json_nexthop);
} else {
vty_out(vty, "\nVRF %s:\n",
else
json_object_object_add(json, "default", json_vrf);
- json_object_object_add(json_vrf, "nexthops", json_nexthop);
+ json_object_object_add(json_vrf,
+ (afi == AFI_IP) ? "ipv4" : "ipv6",
+ json_nexthop);
}
zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
return CMD_SUCCESS;
}
-static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
+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));
- vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type));
- vty_out(vty, " RefCnt: %u", nhe->refcnt);
- if (thread_is_scheduled(nhe->timer))
- vty_out(vty, " Time to Deletion: %s",
- thread_timer_to_hhmmss(time_left, sizeof(time_left),
- nhe->timer));
- vty_out(vty, "\n");
+ 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));
- vty_out(vty, " Uptime: %s\n", up_str);
- vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));
+ } 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\n", vrf_id_to_name(nhe->vrf_id));
+ }
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_VALID)) {
- vty_out(vty, " Valid");
- if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED))
- vty_out(vty, ", Installed");
- vty_out(vty, "\n");
+ if (json)
+ json_object_boolean_true_add(json, "valid");
+ else
+ vty_out(vty, " Valid");
+
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
+ if (json)
+ json_object_boolean_true_add(json, "installed");
+ else
+ vty_out(vty, ", Installed");
+ }
+ 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 (nhe->ifp)
- vty_out(vty, " Interface Index: %d\n", nhe->ifp->ifindex);
if (!zebra_nhg_depends_is_empty(nhe)) {
- vty_out(vty, " Depends:");
+ if (json)
+ json_depends = json_object_new_array();
+ else
+ vty_out(vty, " Depends:");
frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) {
- vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ 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);
}
- vty_out(vty, "\n");
+ if (!json_depends)
+ vty_out(vty, "\n");
+ else
+ json_object_object_add(json, "depends", json_depends);
}
/* Output nexthops */
- for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " ");
- else
- /* Make recursive nexthops a bit more clear */
- vty_out(vty, " ");
+ if (json)
+ json_nexthop_array = json_object_new_array();
- show_route_nexthop_helper(vty, NULL, nexthop);
+
+ for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
+ if (json_nexthop_array) {
+ json_nexthops = json_object_new_object();
+ show_nexthop_json_helper(json_nexthops, nexthop, 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, nexthop);
+ }
if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
if (CHECK_FLAG(nexthop->flags,
- NEXTHOP_FLAG_HAS_BACKUP))
- vty_out(vty, " [backup %d]",
- nexthop->backup_idx[0]);
+ 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);
- vty_out(vty, "\n");
continue;
}
- /* 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, "]");
+ 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);
}
-
- vty_out(vty, "\n");
}
+ 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) {
- vty_out(vty, " Backups:\n");
+ if (json)
+ json_backup_nexthop_array = json_object_new_array();
+ else
+ vty_out(vty, " Backups:\n");
for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
- if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
- vty_out(vty, " ");
- else
- /* Make recursive nexthops a bit more clear */
- vty_out(vty, " ");
+ if (json_backup_nexthop_array) {
+ json_backup_nexthops = json_object_new_object();
+ show_nexthop_json_helper(json_backup_nexthops,
+ nexthop, NULL);
+ json_object_array_add(json_backup_nexthop_array,
+ json_backup_nexthops);
+ } else {
- show_route_nexthop_helper(vty, NULL, nexthop);
- vty_out(vty, "\n");
+ 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, nexthop);
+ vty_out(vty, "\n");
+ }
}
+
+ if (json)
+ json_object_object_add(json, "backupNexthops",
+ json_backup_nexthop_array);
}
if (!zebra_nhg_dependents_is_empty(nhe)) {
- vty_out(vty, " Dependents:");
+ if (json)
+ json_dependants = json_object_new_array();
+ else
+ vty_out(vty, " Dependents:");
frr_each(nhg_connected_tree, &nhe->nhg_dependents,
rb_node_dep) {
- vty_out(vty, " (%u)", rb_node_dep->nhe->id);
+ 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);
}
- vty_out(vty, "\n");
+ if (json)
+ json_object_object_add(json, "dependents",
+ json_dependants);
+ else
+ vty_out(vty, "\n");
}
- if (nhe->nhg.nhgr.buckets)
- 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 (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)
+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);
+ show_nexthop_group_out(vty, nhe, json);
else {
- vty_out(vty, "Nexthop Group ID: %u does not exist\n", id);
+ 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;
}
vrf_id_t vrf_id;
afi_t afi;
int type;
+ json_object *json;
};
static int nhe_show_walker(struct hash_bucket *bucket, void *arg)
if (ctx->type && nhe->type != ctx->type)
goto done;
- show_nexthop_group_out(ctx->vty, nhe);
+ 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)
+ int type, json_object *json)
{
struct nhe_show_context ctx;
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);
}
frr_each(nhg_connected_tree, &zebra_if->nhg_dependents,
rb_node_dep) {
vty_out(vty, " ");
- show_nexthop_group_out(vty, rb_node_dep->nhe);
+ show_nexthop_group_out(vty, rb_node_dep->nhe, NULL);
}
}
}
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>]>",
- 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)
+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);
+ return show_nexthop_group_id_cmd_helper(vty, id, json);
if (v4)
afi = AFI_IP;
}
if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
- vty_out(vty,
- "VRF subcommand does not make any sense in l3mdev based vrf's\n");
+ 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;
}
zvrf = vrf->info;
if (!zvrf)
continue;
+ if (uj)
+ json_vrf = json_object_new_object();
+ else
+ vty_out(vty, "VRF: %s\n", vrf->name);
- vty_out(vty, "VRF: %s\n", vrf->name);
- show_nexthop_group_cmd_helper(vty, zvrf, afi, type);
+ 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;
}
zvrf = zebra_vrf_lookup_by_name(VRF_DEFAULT_NAME);
if (!zvrf) {
- vty_out(vty, "%% VRF '%s' specified does not exist\n",
- vrf_name);
+ 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);
+ show_nexthop_group_cmd_helper(vty, zvrf, afi, type, json);
+
+ if (uj)
+ vty_json(vty, json);
return CMD_SUCCESS;
}
[json$json] [nexthop-group$ng]",
SHOW_STR
IP_STR
- "IPv6 forwarding table\n"
+ "IP forwarding table\n"
"IP routing table\n"
VRF_FULL_CMD_HELP_STR
"Network in the IP routing table to display\n"
struct zebra_vrf *zvrf = NULL;
int filter = 0;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
if (!zvrf)
return CMD_WARNING;
vni_t vni = strtoul(argv[2]->arg, NULL, 10);
struct zebra_vrf *zvrf = NULL;
- zvrf = vrf_info_lookup(VRF_DEFAULT);
+ zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT);
if (!zvrf)
return CMD_WARNING;
}
/* show vrf */
-DEFUN (show_vrf_vni,
+DEFPY (show_vrf_vni,
show_vrf_vni_cmd,
- "show vrf vni [json]",
+ "show vrf [<NAME$vrf_name|all$vrf_all>] vni [json]",
SHOW_STR
- "VRF\n"
+ VRF_FULL_CMD_HELP_STR
"VNI\n"
JSON_STR)
{
json_object *json = NULL;
json_object *json_vrfs = NULL;
bool uj = use_json(argc, argv);
+ bool use_vrf = false;
- if (uj) {
+ if (uj)
json = json_object_new_object();
- json_vrfs = json_object_new_array();
+
+ /* 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 (!uj)
- vty_out(vty, "%-37s %-10s %-20s %-20s %-5s %-18s\n", "VRF",
- "VNI", "VxLAN IF", "L3-SVI", "State", "Rmac");
+ 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);
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- zvrf = vrf->info;
- if (!zvrf)
- continue;
+ 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);
}
return CMD_SUCCESS;
}
-DEFPY(show_evpn_access_vlan,
- show_evpn_access_vlan_cmd,
- "show evpn access-vlan [(1-4094)$vid | detail$detail] [json$json]",
+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)
+ "Detailed information\n" JSON_STR)
{
bool uj = !!json;
- if (vid) {
- zebra_evpn_acc_vl_show_vid(vty, uj, vid);
+ 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);
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]",
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]",
vni = strtoul(argv[4]->arg, NULL, 10);
zvrf = zebra_vrf_get_evpn();
- zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj);
+ 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;
}
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",
/* Route-map */
zebra_route_map_init();
+ zebra_affinity_map_init();
+
install_node(&ip_node);
install_node(&protocol_node);
install_element(VIEW_NODE, &show_ip_rpf_cmd);
install_element(VIEW_NODE, &show_ip_rpf_addr_cmd);
+ install_element(VIEW_NODE, &show_ipv6_rpf_addr_cmd);
install_element(CONFIG_NODE, &ip_nht_default_route_cmd);
install_element(CONFIG_NODE, &no_ip_nht_default_route_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);