Merge pull request #9259 from opensourcerouting/moar-json

*: can't get enough JSON
This commit is contained in:
Russ White 2021-08-03 09:13:12 -04:00 committed by GitHub
commit 1358f9d10a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1275 additions and 311 deletions

View File

@ -612,78 +612,118 @@ DEFUN (no_as_path_all,
return CMD_SUCCESS;
}
static void as_list_show(struct vty *vty, struct as_list *aslist)
static void as_list_show(struct vty *vty, struct as_list *aslist,
json_object *json)
{
struct as_filter *asfilter;
json_object *json_aslist = NULL;
vty_out(vty, "AS path access list %s\n", aslist->name);
for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) {
vty_out(vty, " %s %s\n", filter_type_str(asfilter->type),
asfilter->reg_str);
}
}
static void as_list_show_all(struct vty *vty)
{
struct as_list *aslist;
struct as_filter *asfilter;
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) {
if (json) {
json_aslist = json_object_new_array();
json_object_object_add(json, aslist->name, json_aslist);
} else
vty_out(vty, "AS path access list %s\n", aslist->name);
for (asfilter = aslist->head; asfilter;
asfilter = asfilter->next) {
for (asfilter = aslist->head; asfilter; asfilter = asfilter->next) {
if (json) {
json_object *json_asfilter = json_object_new_object();
json_object_int_add(json_asfilter, "sequenceNumber",
asfilter->seq);
json_object_string_add(json_asfilter, "type",
filter_type_str(asfilter->type));
json_object_string_add(json_asfilter, "regExp",
asfilter->reg_str);
json_object_array_add(json_aslist, json_asfilter);
} else
vty_out(vty, " %s %s\n",
filter_type_str(asfilter->type),
asfilter->reg_str);
}
}
}
static void as_list_show_all(struct vty *vty, json_object *json)
{
struct as_list *aslist;
for (aslist = as_list_master.str.head; aslist; aslist = aslist->next)
as_list_show(vty, aslist, json);
}
DEFUN (show_as_path_access_list,
show_bgp_as_path_access_list_cmd,
"show bgp as-path-access-list WORD",
"show bgp as-path-access-list WORD [json]",
SHOW_STR
BGP_STR
"List AS path access lists\n"
"AS path access list name\n")
"AS path access list name\n"
JSON_STR)
{
int idx_word = 3;
struct as_list *aslist;
bool uj = use_json(argc, argv);
json_object *json = NULL;
if (uj)
json = json_object_new_object();
aslist = as_list_lookup(argv[idx_word]->arg);
if (aslist)
as_list_show(vty, aslist);
as_list_show(vty, aslist, json);
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
ALIAS (show_as_path_access_list,
show_ip_as_path_access_list_cmd,
"show ip as-path-access-list WORD",
"show ip as-path-access-list WORD [json]",
SHOW_STR
IP_STR
"List AS path access lists\n"
"AS path access list name\n")
"AS path access list name\n"
JSON_STR)
DEFUN (show_as_path_access_list_all,
show_bgp_as_path_access_list_all_cmd,
"show bgp as-path-access-list",
"show bgp as-path-access-list [json]",
SHOW_STR
BGP_STR
"List AS path access lists\n")
"List AS path access lists\n"
JSON_STR)
{
as_list_show_all(vty);
bool uj = use_json(argc, argv);
json_object *json = NULL;
if (uj)
json = json_object_new_object();
as_list_show_all(vty, json);
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
ALIAS (show_as_path_access_list_all,
show_ip_as_path_access_list_all_cmd,
"show ip as-path-access-list",
"show ip as-path-access-list [json]",
SHOW_STR
IP_STR
"List AS path access lists\n")
"List AS path access lists\n"
JSON_STR)
static int config_write_as_list(struct vty *vty)
{

View File

@ -1896,7 +1896,17 @@ AS path access list is user defined AS path.
This command defines a new AS path access list.
.. clicmd:: show bgp as-path-access-list [json]
Display all BGP AS Path access lists.
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show bgp as-path-access-list WORD [json]
Display the specified BGP AS Path access list.
If the ``json`` option is specified, output is displayed in JSON format.
.. _bgp-bogon-filter-example:

View File

@ -35,6 +35,18 @@ IP Access List
access-list filter permit 10.0.0.0/8
access-list filter seq 13 permit 10.0.0.0/7
.. clicmd:: show <ip|ipv6> access-list [json]
Display all IPv4 or IPv6 access lists.
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show <ip|ipv6> access-list WORD [json]
Display the specified IPv4 or IPv6 access list.
If the ``json`` option is specified, output is displayed in JSON format.
IP Prefix List
==============
@ -111,19 +123,25 @@ ip prefix-list description
Showing ip prefix-list
----------------------
.. clicmd:: show ip prefix-list
.. clicmd:: show ip prefix-list [json]
Display all IP prefix lists.
.. clicmd:: show ip prefix-list NAME
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show ip prefix-list NAME [json]
Show IP prefix list can be used with a prefix list name.
.. clicmd:: show ip prefix-list NAME seq NUM
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show ip prefix-list NAME seq NUM [json]
Show IP prefix list can be used with a prefix list name and sequential
number.
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show ip prefix-list NAME A.B.C.D/M
If the command longer is used, all prefix lists with prefix lengths equal to
@ -132,10 +150,10 @@ Showing ip prefix-list
.. clicmd:: show ip prefix-list NAME A.B.C.D/M longer
.. clicmd:: show ip prefix-list NAME A.B.C.D/M first-match
.. clicmd:: show ip prefix-list summary
.. clicmd:: show ip prefix-list summary NAME
.. clicmd:: show ip prefix-list detail
.. clicmd:: show ip prefix-list detail NAME
.. clicmd:: show ip prefix-list summary [json]
.. clicmd:: show ip prefix-list summary NAME [json]
.. clicmd:: show ip prefix-list detail [json]
.. clicmd:: show ip prefix-list detail NAME [json]
.. clicmd:: debug prefix-list NAME match <A.B.C.D/M|X:X::X:X/M> [address-mode]

View File

@ -90,11 +90,13 @@ cont
.. _route-map-show-command:
.. clicmd:: show route-map [WORD]
.. clicmd:: show route-map [WORD] [json]
Display data about each daemons knowledge of individual route-maps.
If WORD is supplied narrow choice to that particular route-map.
If the ``json`` option is specified, output is displayed in JSON format.
.. _route-map-clear-counter-command:
.. clicmd:: clear route-map counter [WORD]

View File

@ -1139,6 +1139,10 @@ zebra Terminal Mode Commands
Display detailed information about a route. If [nexthop-group] is
included, it will display the nexthop group ID the route is using as well.
.. clicmd:: show interface [NAME] [{vrf VRF|brief}] [json]
.. clicmd:: show interface [NAME] [{vrf all|brief}] [json]
.. clicmd:: show interface [NAME] [{vrf VRF|brief}] [nexthop-group]
.. clicmd:: show interface [NAME] [{vrf all|brief}] [nexthop-group]
@ -1148,6 +1152,8 @@ zebra Terminal Mode Commands
detailed information about that single interface. If [nexthop-group] is
specified, it will display nexthop groups pointing out that interface.
If the ``json`` option is specified, output is displayed in JSON format.
.. clicmd:: show ip prefix-list [NAME]
.. clicmd:: show route-map [NAME]

View File

@ -30,6 +30,7 @@
#include "routemap.h"
#include "libfrr.h"
#include "northbound_cli.h"
#include "json.h"
DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
@ -443,71 +444,158 @@ void access_list_filter_add(struct access_list *access,
host A single host address
*/
static void config_write_access_zebra(struct vty *, struct filter *);
static void config_write_access_cisco(struct vty *, struct filter *);
static void config_write_access_zebra(struct vty *, struct filter *,
json_object *);
static void config_write_access_cisco(struct vty *, struct filter *,
json_object *);
static const char *filter_type2str(struct filter *filter)
{
if (filter->cisco) {
if (filter->u.cfilter.extended)
return "Extended";
else
return "Standard";
} else
return "Zebra";
}
/* show access-list command. */
static int filter_show(struct vty *vty, const char *name, afi_t afi)
static int filter_show(struct vty *vty, const char *name, afi_t afi,
bool use_json)
{
struct access_list *access;
struct access_master *master;
struct filter *mfilter;
struct filter_cisco *filter;
int write = 0;
bool first;
json_object *json = NULL;
json_object *json_proto = NULL;
master = access_master_get(afi);
if (master == NULL)
if (master == NULL) {
if (use_json)
vty_out(vty, "{}\n");
return 0;
}
if (use_json)
json = json_object_new_object();
/* Print the name of the protocol */
vty_out(vty, "%s:\n", frr_protoname);
if (json) {
json_proto = json_object_new_object();
json_object_object_add(json, frr_protoname, json_proto);
} else
vty_out(vty, "%s:\n", frr_protoname);
for (access = master->str.head; access; access = access->next) {
json_object *json_acl = NULL;
json_object *json_rules = NULL;
if (name && strcmp(access->name, name) != 0)
continue;
write = 1;
first = true;
for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
json_object *json_rule = NULL;
filter = &mfilter->u.cfilter;
if (write) {
vty_out(vty, "%s %s access list %s\n",
mfilter->cisco ? (filter->extended
? "Extended"
: "Standard")
: "Zebra",
(afi == AFI_IP)
? ("IP")
: ((afi == AFI_IP6) ? ("IPv6 ")
: ("MAC ")),
access->name);
write = 0;
if (first) {
const char *type = filter_type2str(mfilter);
if (json) {
json_acl = json_object_new_object();
json_object_object_add(json_proto,
access->name,
json_acl);
json_object_string_add(json_acl, "type",
type);
json_object_string_add(json_acl,
"addressFamily",
afi2str(afi));
json_rules = json_object_new_array();
json_object_object_add(
json_acl, "rules", json_rules);
} else {
vty_out(vty, "%s %s access list %s\n",
type,
(afi == AFI_IP)
? ("IP")
: ((afi == AFI_IP6)
? ("IPv6 ")
: ("MAC ")),
access->name);
}
first = false;
}
vty_out(vty, " seq %" PRId64, mfilter->seq);
vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " " : "");
if (json) {
json_rule = json_object_new_object();
json_object_array_add(json_rules, json_rule);
json_object_int_add(json_rule, "sequenceNumber",
mfilter->seq);
json_object_string_add(
json_rule, "filterType",
filter_type_str(mfilter));
} else {
vty_out(vty, " seq %" PRId64, mfilter->seq);
vty_out(vty, " %s%s", filter_type_str(mfilter),
mfilter->type == FILTER_DENY ? " "
: "");
}
if (!mfilter->cisco)
config_write_access_zebra(vty, mfilter);
config_write_access_zebra(vty, mfilter,
json_rule);
else if (filter->extended)
config_write_access_cisco(vty, mfilter);
config_write_access_cisco(vty, mfilter,
json_rule);
else {
if (filter->addr_mask.s_addr == 0xffffffff)
vty_out(vty, " any\n");
else {
vty_out(vty, " %pI4", &filter->addr);
if (json) {
char buf[BUFSIZ];
json_object_string_add(
json_rule, "address",
inet_ntop(AF_INET,
&filter->addr, buf,
sizeof(buf)));
json_object_string_add(
json_rule, "mask",
inet_ntop(AF_INET,
&filter->addr_mask,
buf, sizeof(buf)));
} else {
if (filter->addr_mask.s_addr
!= INADDR_ANY)
vty_out(vty,
", wildcard bits %pI4",
&filter->addr_mask);
vty_out(vty, "\n");
== 0xffffffff)
vty_out(vty, " any\n");
else {
vty_out(vty, " %pI4",
&filter->addr);
if (filter->addr_mask.s_addr
!= INADDR_ANY)
vty_out(vty,
", wildcard bits %pI4",
&filter->addr_mask);
vty_out(vty, "\n");
}
}
}
}
}
if (json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
@ -519,7 +607,7 @@ DEFUN (show_mac_access_list,
"mac access lists\n"
"List mac access lists\n")
{
return filter_show(vty, NULL, AFI_L2VPN);
return filter_show(vty, NULL, AFI_L2VPN, false);
}
DEFUN (show_mac_access_list_name,
@ -530,22 +618,24 @@ DEFUN (show_mac_access_list_name,
"List mac access lists\n"
"mac address\n")
{
return filter_show(vty, argv[3]->arg, AFI_L2VPN);
return filter_show(vty, argv[3]->arg, AFI_L2VPN, false);
}
DEFUN (show_ip_access_list,
show_ip_access_list_cmd,
"show ip access-list",
"show ip access-list [json]",
SHOW_STR
IP_STR
"List IP access lists\n")
"List IP access lists\n"
JSON_STR)
{
return filter_show(vty, NULL, AFI_IP);
bool uj = use_json(argc, argv);
return filter_show(vty, NULL, AFI_IP, uj);
}
DEFUN (show_ip_access_list_name,
show_ip_access_list_name_cmd,
"show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>",
"show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> [json]",
SHOW_STR
IP_STR
"List IP access lists\n"
@ -553,41 +643,64 @@ DEFUN (show_ip_access_list_name,
"IP extended access list\n"
"IP standard access list (expanded range)\n"
"IP extended access list (expanded range)\n"
"IP zebra access-list\n")
"IP zebra access-list\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
int idx_acl = 3;
return filter_show(vty, argv[idx_acl]->arg, AFI_IP);
return filter_show(vty, argv[idx_acl]->arg, AFI_IP, uj);
}
DEFUN (show_ipv6_access_list,
show_ipv6_access_list_cmd,
"show ipv6 access-list",
"show ipv6 access-list [json]",
SHOW_STR
IPV6_STR
"List IPv6 access lists\n")
"List IPv6 access lists\n"
JSON_STR)
{
return filter_show(vty, NULL, AFI_IP6);
bool uj = use_json(argc, argv);
return filter_show(vty, NULL, AFI_IP6, uj);
}
DEFUN (show_ipv6_access_list_name,
show_ipv6_access_list_name_cmd,
"show ipv6 access-list WORD",
"show ipv6 access-list WORD [json]",
SHOW_STR
IPV6_STR
"List IPv6 access lists\n"
"IPv6 zebra access-list\n")
"IPv6 zebra access-list\n"
JSON_STR)
{
bool uj = use_json(argc, argv);
int idx_word = 3;
return filter_show(vty, argv[idx_word]->arg, AFI_IP6);
return filter_show(vty, argv[idx_word]->arg, AFI_IP6, uj);
}
static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
static void config_write_access_cisco(struct vty *vty, struct filter *mfilter,
json_object *json)
{
struct filter_cisco *filter;
filter = &mfilter->u.cfilter;
if (filter->extended) {
if (json) {
char buf[BUFSIZ];
json_object_boolean_add(json, "extended", !!filter->extended);
json_object_string_add(
json, "sourceAddress",
inet_ntop(AF_INET, &filter->addr, buf, sizeof(buf)));
json_object_string_add(json, "sourceMask",
inet_ntop(AF_INET, &filter->addr_mask,
buf, sizeof(buf)));
json_object_string_add(
json, "destinationAddress",
inet_ntop(AF_INET, &filter->mask, buf, sizeof(buf)));
json_object_string_add(json, "destinationMask",
inet_ntop(AF_INET, &filter->mask_mask,
buf, sizeof(buf)));
} else {
vty_out(vty, " ip");
if (filter->addr_mask.s_addr == 0xffffffff)
vty_out(vty, " any");
@ -607,19 +720,11 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
vty_out(vty, " %pI4", &filter->mask_mask);
}
vty_out(vty, "\n");
} else {
if (filter->addr_mask.s_addr == 0xffffffff)
vty_out(vty, " any\n");
else {
vty_out(vty, " %pI4", &filter->addr);
if (filter->addr_mask.s_addr != INADDR_ANY)
vty_out(vty, " %pI4", &filter->addr_mask);
vty_out(vty, "\n");
}
}
}
static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
static void config_write_access_zebra(struct vty *vty, struct filter *mfilter,
json_object *json)
{
struct filter_zebra *filter;
struct prefix *p;
@ -628,21 +733,29 @@ static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
filter = &mfilter->u.zfilter;
p = &filter->prefix;
if (p->prefixlen == 0 && !filter->exact)
vty_out(vty, " any");
else if (p->family == AF_INET6 || p->family == AF_INET)
vty_out(vty, " %s/%d%s",
inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen, filter->exact ? " exact-match" : "");
else if (p->family == AF_ETHERNET) {
if (p->prefixlen == 0)
if (json) {
json_object_string_add(json, "prefix",
prefix2str(p, buf, sizeof(buf)));
json_object_boolean_add(json, "exact-match", !!filter->exact);
} else {
if (p->prefixlen == 0 && !filter->exact)
vty_out(vty, " any");
else
vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth),
buf, sizeof(buf)));
}
else if (p->family == AF_INET6 || p->family == AF_INET)
vty_out(vty, " %s/%d%s",
inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
p->prefixlen,
filter->exact ? " exact-match" : "");
else if (p->family == AF_ETHERNET) {
if (p->prefixlen == 0)
vty_out(vty, " any");
else
vty_out(vty, " %s",
prefix_mac2str(&(p->u.prefix_eth), buf,
sizeof(buf)));
}
vty_out(vty, "\n");
vty_out(vty, "\n");
}
}
static struct cmd_node access_mac_node = {

View File

@ -932,102 +932,206 @@ enum display_type {
first_match_display
};
static void vty_show_prefix_entry(struct vty *vty, afi_t afi,
static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi,
struct prefix_list *plist,
struct prefix_master *master,
enum display_type dtype, int seqnum)
{
struct prefix_list_entry *pentry;
json_object *json_pl = NULL;
/* Print the name of the protocol */
vty_out(vty, "%s: ", frr_protoname);
if (json) {
json_pl = json_object_new_object();
json_object_object_add(json, plist->name, json_pl);
} else
vty_out(vty, "%s: ", frr_protoname);
if (dtype == normal_display) {
vty_out(vty, "ip%s prefix-list %s: %d entries\n",
afi == AFI_IP ? "" : "v6", plist->name, plist->count);
if (plist->desc)
vty_out(vty, " Description: %s\n", plist->desc);
if (json) {
json_object_string_add(json_pl, "addressFamily",
afi2str(afi));
json_object_int_add(json_pl, "entries", plist->count);
if (plist->desc)
json_object_string_add(json_pl, "description",
plist->desc);
} else {
vty_out(vty, "ip%s prefix-list %s: %d entries\n",
afi == AFI_IP ? "" : "v6", plist->name,
plist->count);
if (plist->desc)
vty_out(vty, " Description: %s\n",
plist->desc);
}
} else if (dtype == summary_display || dtype == detail_display) {
vty_out(vty, "ip%s prefix-list %s:\n",
afi == AFI_IP ? "" : "v6", plist->name);
if (json) {
json_object_string_add(json_pl, "addressFamily",
afi2str(afi));
if (plist->desc)
json_object_string_add(json_pl, "description",
plist->desc);
json_object_int_add(json_pl, "count", plist->count);
json_object_int_add(json_pl, "rangeEntries",
plist->rangecount);
json_object_int_add(json_pl, "sequenceStart",
plist->head ? plist->head->seq : 0);
json_object_int_add(json_pl, "sequenceEnd",
plist->tail ? plist->tail->seq : 0);
} else {
vty_out(vty, "ip%s prefix-list %s:\n",
afi == AFI_IP ? "" : "v6", plist->name);
if (plist->desc)
vty_out(vty, " Description: %s\n", plist->desc);
if (plist->desc)
vty_out(vty, " Description: %s\n",
plist->desc);
vty_out(vty,
" count: %d, range entries: %d, sequences: %" PRId64 " - %" PRId64 "\n",
plist->count, plist->rangecount,
plist->head ? plist->head->seq : 0,
plist->tail ? plist->tail->seq : 0);
vty_out(vty,
" count: %d, range entries: %d, sequences: %" PRId64
" - %" PRId64 "\n",
plist->count, plist->rangecount,
plist->head ? plist->head->seq : 0,
plist->tail ? plist->tail->seq : 0);
}
}
if (dtype != summary_display) {
json_object *json_entries = NULL;
if (json) {
json_entries = json_object_new_array();
json_object_object_add(json_pl, "entries",
json_entries);
}
for (pentry = plist->head; pentry; pentry = pentry->next) {
if (dtype == sequential_display
&& pentry->seq != seqnum)
continue;
vty_out(vty, " ");
if (json) {
json_object *json_entry;
char buf[BUFSIZ];
vty_out(vty, "seq %" PRId64 " ", pentry->seq);
json_entry = json_object_new_object();
json_object_array_add(json_entries, json_entry);
vty_out(vty, "%s ", prefix_list_type_str(pentry));
if (pentry->any)
vty_out(vty, "any");
else {
struct prefix *p = &pentry->prefix;
vty_out(vty, "%pFX", p);
json_object_int_add(json_entry,
"sequenceNumber",
pentry->seq);
json_object_string_add(
json_entry, "type",
prefix_list_type_str(pentry));
json_object_string_add(
json_entry, "prefix",
prefix2str(&pentry->prefix, buf,
sizeof(buf)));
if (pentry->ge)
vty_out(vty, " ge %d", pentry->ge);
json_object_int_add(
json_entry,
"minimumPrefixLength",
pentry->ge);
if (pentry->le)
vty_out(vty, " le %d", pentry->le);
json_object_int_add(
json_entry,
"maximumPrefixLength",
pentry->le);
if (dtype == detail_display
|| dtype == sequential_display) {
json_object_int_add(json_entry,
"hitCount",
pentry->hitcnt);
json_object_int_add(json_entry,
"referenceCount",
pentry->refcnt);
}
} else {
vty_out(vty, " ");
vty_out(vty, "seq %" PRId64 " ", pentry->seq);
vty_out(vty, "%s ",
prefix_list_type_str(pentry));
if (pentry->any)
vty_out(vty, "any");
else {
struct prefix *p = &pentry->prefix;
vty_out(vty, "%pFX", p);
if (pentry->ge)
vty_out(vty, " ge %d",
pentry->ge);
if (pentry->le)
vty_out(vty, " le %d",
pentry->le);
}
if (dtype == detail_display
|| dtype == sequential_display)
vty_out(vty,
" (hit count: %ld, refcount: %ld)",
pentry->hitcnt, pentry->refcnt);
vty_out(vty, "\n");
}
if (dtype == detail_display
|| dtype == sequential_display)
vty_out(vty, " (hit count: %ld, refcount: %ld)",
pentry->hitcnt, pentry->refcnt);
vty_out(vty, "\n");
}
}
}
static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name,
const char *seq, enum display_type dtype)
const char *seq, enum display_type dtype,
bool uj)
{
struct prefix_list *plist;
struct prefix_master *master;
int64_t seqnum = 0;
json_object *json = NULL;
json_object *json_proto = NULL;
master = prefix_master_get(afi, 0);
if (master == NULL)
return CMD_WARNING;
if (uj) {
json = json_object_new_object();
json_proto = json_object_new_object();
json_object_object_add(json, frr_protoname, json_proto);
}
if (seq)
seqnum = (int64_t)atol(seq);
if (name) {
plist = prefix_list_lookup(afi, name);
if (!plist) {
vty_out(vty, "%% Can't find specified prefix-list\n");
if (!uj)
vty_out(vty,
"%% Can't find specified prefix-list\n");
return CMD_WARNING;
}
vty_show_prefix_entry(vty, afi, plist, master, dtype, seqnum);
vty_show_prefix_entry(vty, json_proto, afi, plist, master,
dtype, seqnum);
} else {
if (dtype == detail_display || dtype == summary_display) {
if (master->recent)
if (master->recent && !uj)
vty_out(vty,
"Prefix-list with the last deletion/insertion: %s\n",
master->recent->name);
}
for (plist = master->str.head; plist; plist = plist->next)
vty_show_prefix_entry(vty, afi, plist, master, dtype,
seqnum);
vty_show_prefix_entry(vty, json_proto, afi, plist,
master, dtype, seqnum);
}
if (uj) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
@ -1150,19 +1254,21 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
DEFPY (show_ip_prefix_list,
show_ip_prefix_list_cmd,
"show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
"show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
SHOW_STR
IP_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n")
"Sequence number\n"
JSON_STR)
{
enum display_type dtype = normal_display;
if (dseq)
dtype = sequential_display;
return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype);
return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype,
!!uj);
}
DEFPY (show_ip_prefix_list_prefix,
@ -1188,28 +1294,30 @@ DEFPY (show_ip_prefix_list_prefix,
DEFPY (show_ip_prefix_list_summary,
show_ip_prefix_list_summary_cmd,
"show ip prefix-list summary [WORD$prefix_list]",
"show ip prefix-list summary [WORD$prefix_list] [json$uj]",
SHOW_STR
IP_STR
PREFIX_LIST_STR
"Summary of prefix lists\n"
"Name of a prefix list\n")
"Name of a prefix list\n"
JSON_STR)
{
return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
summary_display);
summary_display, !!uj);
}
DEFPY (show_ip_prefix_list_detail,
show_ip_prefix_list_detail_cmd,
"show ip prefix-list detail [WORD$prefix_list]",
"show ip prefix-list detail [WORD$prefix_list] [json$uj]",
SHOW_STR
IP_STR
PREFIX_LIST_STR
"Detail of prefix lists\n"
"Name of a prefix list\n")
"Name of a prefix list\n"
JSON_STR)
{
return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
detail_display);
detail_display, !!uj);
}
DEFPY (clear_ip_prefix_list,
@ -1226,19 +1334,21 @@ DEFPY (clear_ip_prefix_list,
DEFPY (show_ipv6_prefix_list,
show_ipv6_prefix_list_cmd,
"show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
"show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
SHOW_STR
IPV6_STR
PREFIX_LIST_STR
"Name of a prefix list\n"
"sequence number of an entry\n"
"Sequence number\n")
"Sequence number\n"
JSON_STR)
{
enum display_type dtype = normal_display;
if (dseq)
dtype = sequential_display;
return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype);
return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype,
!!uj);
}
DEFPY (show_ipv6_prefix_list_prefix,
@ -1264,28 +1374,30 @@ DEFPY (show_ipv6_prefix_list_prefix,
DEFPY (show_ipv6_prefix_list_summary,
show_ipv6_prefix_list_summary_cmd,
"show ipv6 prefix-list summary [WORD$prefix-list]",
"show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]",
SHOW_STR
IPV6_STR
PREFIX_LIST_STR
"Summary of prefix lists\n"
"Name of a prefix list\n")
"Name of a prefix list\n"
JSON_STR)
{
return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
summary_display);
summary_display, !!uj);
}
DEFPY (show_ipv6_prefix_list_detail,
show_ipv6_prefix_list_detail_cmd,
"show ipv6 prefix-list detail [WORD$prefix-list]",
"show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]",
SHOW_STR
IPV6_STR
PREFIX_LIST_STR
"Detail of prefix lists\n"
"Name of a prefix list\n")
"Name of a prefix list\n"
JSON_STR)
{
return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
detail_display);
detail_display, !!uj);
}
DEFPY (clear_ipv6_prefix_list,

View File

@ -22,6 +22,7 @@
#include "linklist.h"
#include "memory.h"
#include "command.h"
#include "vector.h"
#include "prefix.h"
#include "vty.h"
@ -32,6 +33,7 @@
#include "libfrr.h"
#include "lib_errors.h"
#include "table.h"
#include "json.h"
DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map");
DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name");
@ -840,50 +842,140 @@ static const char *route_map_result_str(route_map_result_t res)
}
/* show route-map */
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map)
static void vty_show_route_map_entry(struct vty *vty, struct route_map *map,
json_object *json)
{
struct route_map_index *index;
struct route_map_rule *rule;
json_object *json_rmap = NULL;
json_object *json_rules = NULL;
vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s Processed Change: %s\n",
map->name, map->applied - map->applied_clear,
map->optimization_disabled ? "disabled" : "enabled",
map->to_be_processed ? "true" : "false");
if (json) {
json_rmap = json_object_new_object();
json_object_object_add(json, map->name, json_rmap);
json_rules = json_object_new_array();
json_object_int_add(json_rmap, "invoked",
map->applied - map->applied_clear);
json_object_boolean_add(json_rmap, "disabledOptimization",
map->optimization_disabled);
json_object_boolean_add(json_rmap, "processedChange",
map->to_be_processed);
json_object_object_add(json_rmap, "rules", json_rules);
} else {
vty_out(vty,
"route-map: %s Invoked: %" PRIu64
" Optimization: %s Processed Change: %s\n",
map->name, map->applied - map->applied_clear,
map->optimization_disabled ? "disabled" : "enabled",
map->to_be_processed ? "true" : "false");
}
for (index = map->head; index; index = index->next) {
vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
route_map_type_str(index->type), index->pref,
index->applied - index->applied_clear);
if (json) {
json_object *json_rule;
json_object *json_matches;
json_object *json_sets;
char action[BUFSIZ] = {};
/* Description */
if (index->description)
vty_out(vty, " Description:\n %s\n",
index->description);
json_rule = json_object_new_object();
json_object_array_add(json_rules, json_rule);
/* Match clauses */
vty_out(vty, " Match clauses:\n");
for (rule = index->match_list.head; rule; rule = rule->next)
vty_out(vty, " %s %s\n", rule->cmd->str,
rule->rule_str);
json_object_int_add(json_rule, "sequenceNumber",
index->pref);
json_object_string_add(json_rule, "type",
route_map_type_str(index->type));
json_object_int_add(json_rule, "invoked",
index->applied
- index->applied_clear);
vty_out(vty, " Set clauses:\n");
for (rule = index->set_list.head; rule; rule = rule->next)
vty_out(vty, " %s %s\n", rule->cmd->str,
rule->rule_str);
/* Description */
if (index->description)
json_object_string_add(json_rule, "description",
index->description);
/* Call clause */
vty_out(vty, " Call clause:\n");
if (index->nextrm)
vty_out(vty, " Call %s\n", index->nextrm);
/* Match clauses */
json_matches = json_object_new_array();
json_object_object_add(json_rule, "matchClauses",
json_matches);
for (rule = index->match_list.head; rule;
rule = rule->next) {
char buf[BUFSIZ];
/* Exit Policy */
vty_out(vty, " Action:\n");
if (index->exitpolicy == RMAP_GOTO)
vty_out(vty, " Goto %d\n", index->nextpref);
else if (index->exitpolicy == RMAP_NEXT)
vty_out(vty, " Continue to next entry\n");
else if (index->exitpolicy == RMAP_EXIT)
vty_out(vty, " Exit routemap\n");
snprintf(buf, sizeof(buf), "%s %s",
rule->cmd->str, rule->rule_str);
json_array_string_add(json_matches, buf);
}
/* Set clauses */
json_sets = json_object_new_array();
json_object_object_add(json_rule, "setClauses",
json_sets);
for (rule = index->set_list.head; rule;
rule = rule->next) {
char buf[BUFSIZ];
snprintf(buf, sizeof(buf), "%s %s",
rule->cmd->str, rule->rule_str);
json_array_string_add(json_sets, buf);
}
/* Call clause */
if (index->nextrm)
json_object_string_add(json_rule, "callClause",
index->nextrm);
/* Exit Policy */
if (index->exitpolicy == RMAP_GOTO)
snprintf(action, sizeof(action), "Goto %d",
index->nextpref);
else if (index->exitpolicy == RMAP_NEXT)
snprintf(action, sizeof(action),
"Continue to next entry");
else if (index->exitpolicy == RMAP_EXIT)
snprintf(action, sizeof(action),
"Exit routemap");
if (action[0] != '\0')
json_object_string_add(json_rule, "action",
action);
} else {
vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n",
route_map_type_str(index->type), index->pref,
index->applied - index->applied_clear);
/* Description */
if (index->description)
vty_out(vty, " Description:\n %s\n",
index->description);
/* Match clauses */
vty_out(vty, " Match clauses:\n");
for (rule = index->match_list.head; rule;
rule = rule->next)
vty_out(vty, " %s %s\n", rule->cmd->str,
rule->rule_str);
/* Set clauses */
vty_out(vty, " Set clauses:\n");
for (rule = index->set_list.head; rule;
rule = rule->next)
vty_out(vty, " %s %s\n", rule->cmd->str,
rule->rule_str);
/* Call clause */
vty_out(vty, " Call clause:\n");
if (index->nextrm)
vty_out(vty, " Call %s\n", index->nextrm);
/* Exit Policy */
vty_out(vty, " Action:\n");
if (index->exitpolicy == RMAP_GOTO)
vty_out(vty, " Goto %d\n", index->nextpref);
else if (index->exitpolicy == RMAP_NEXT)
vty_out(vty, " Continue to next entry\n");
else if (index->exitpolicy == RMAP_EXIT)
vty_out(vty, " Exit routemap\n");
}
}
}
@ -895,22 +987,28 @@ static int sort_route_map(const void **map1, const void **map2)
return strcmp(m1->name, m2->name);
}
static int vty_show_route_map(struct vty *vty, const char *name)
static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
{
struct route_map *map;
json_object *json = NULL;
json_object *json_proto = NULL;
vty_out(vty, "%s:\n", frr_protonameinst);
if (use_json) {
json = json_object_new_object();
json_proto = json_object_new_object();
json_object_object_add(json, frr_protonameinst, json_proto);
} else
vty_out(vty, "%s:\n", frr_protonameinst);
if (name) {
map = route_map_lookup_by_name(name);
if (map) {
vty_show_route_map_entry(vty, map);
vty_show_route_map_entry(vty, map, json_proto);
return CMD_SUCCESS;
} else {
} else if (!use_json) {
vty_out(vty, "%s: 'route-map %s' not found\n",
frr_protonameinst, name);
return CMD_SUCCESS;
}
} else {
@ -923,10 +1021,18 @@ static int vty_show_route_map(struct vty *vty, const char *name)
list_sort(maplist, sort_route_map);
for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
vty_show_route_map_entry(vty, map);
vty_show_route_map_entry(vty, map, json_proto);
list_delete(&maplist);
}
if (use_json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
@ -950,7 +1056,7 @@ static int vty_show_unused_route_map(struct vty *vty)
list_sort(maplist, sort_route_map);
for (ALL_LIST_ELEMENTS_RO(maplist, ln, map))
vty_show_route_map_entry(vty, map);
vty_show_route_map_entry(vty, map, NULL);
} else {
vty_out(vty, "\n%s: None\n", frr_protonameinst);
}
@ -2957,14 +3063,20 @@ DEFUN (rmap_clear_counters,
DEFUN (rmap_show_name,
rmap_show_name_cmd,
"show route-map [WORD]",
"show route-map [WORD] [json]",
SHOW_STR
"route-map information\n"
"route-map name\n")
"route-map name\n"
JSON_STR)
{
int idx_word = 2;
const char *name = (argc == 3) ? argv[idx_word]->arg : NULL;
return vty_show_route_map(vty, name);
bool uj = use_json(argc, argv);
int idx = 0;
const char *name = NULL;
if (argv_find(argv, argc, "WORD", &idx))
name = argv[idx]->arg;
return vty_show_route_map(vty, name, uj);
}
DEFUN (rmap_show_unused,

View File

@ -1205,59 +1205,77 @@ void zebra_if_set_protodown(struct interface *ifp, bool down)
#endif
}
/* Output prefix string to vty. */
static int prefix_vty_out(struct vty *vty, struct prefix *p)
{
char str[INET6_ADDRSTRLEN];
inet_ntop(p->family, &p->u.prefix, str, sizeof(str));
vty_out(vty, "%s", str);
return strlen(str);
}
/* Dump if address information to vty. */
static void connected_dump_vty(struct vty *vty, struct connected *connected)
static void connected_dump_vty(struct vty *vty, json_object *json,
struct connected *connected)
{
struct prefix *p;
json_object *json_addr = NULL;
char buf[PREFIX2STR_BUFFER];
/* Print interface address. */
p = connected->address;
vty_out(vty, " %s ", prefix_family_str(p));
prefix_vty_out(vty, p);
vty_out(vty, "/%d", p->prefixlen);
if (json) {
json_addr = json_object_new_object();
json_object_array_add(json, json_addr);
json_object_string_add(json_addr, "address",
prefix2str(p, buf, sizeof(buf)));
} else {
vty_out(vty, " %s %pFX", prefix_family_str(p), p);
}
/* If there is destination address, print it. */
if (CONNECTED_PEER(connected) && connected->destination) {
vty_out(vty, " peer ");
prefix_vty_out(vty, connected->destination);
vty_out(vty, "/%d", connected->destination->prefixlen);
if (json) {
json_object_string_add(
json_addr, "peer",
prefix2str(connected->destination, buf,
sizeof(buf)));
} else {
vty_out(vty, " peer %pFX", connected->destination);
}
}
if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY))
if (json)
json_object_boolean_add(
json_addr, "secondary",
CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY));
else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_SECONDARY))
vty_out(vty, " secondary");
if (CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED))
if (json)
json_object_boolean_add(
json_addr, "unnumbered",
CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED));
else if (CHECK_FLAG(connected->flags, ZEBRA_IFA_UNNUMBERED))
vty_out(vty, " unnumbered");
if (connected->label)
vty_out(vty, " %s", connected->label);
if (connected->label) {
if (json)
json_object_string_add(json_addr, "label",
connected->label);
else
vty_out(vty, " %s", connected->label);
}
vty_out(vty, "\n");
if (!json)
vty_out(vty, "\n");
}
/* Dump interface neighbor address information to vty. */
static void nbr_connected_dump_vty(struct vty *vty,
static void nbr_connected_dump_vty(struct vty *vty, json_object *json,
struct nbr_connected *connected)
{
struct prefix *p;
char buf[PREFIX2STR_BUFFER];
/* Print interface address. */
p = connected->address;
vty_out(vty, " %s ", prefix_family_str(p));
prefix_vty_out(vty, p);
vty_out(vty, "/%d", p->prefixlen);
vty_out(vty, "\n");
if (json)
json_array_string_add(json, prefix2str(p, buf, sizeof(buf)));
else
vty_out(vty, " %s %pFX\n", prefix_family_str(p), p);
}
static const char *zebra_zifslavetype_2str(zebra_slave_iftype_t zif_slave_type)
@ -1413,6 +1431,43 @@ static void ifs_dump_brief_vty(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n");
}
static void ifs_dump_brief_vty_json(json_object *json, struct vrf *vrf)
{
struct connected *connected;
struct listnode *node;
struct interface *ifp;
FOR_ALL_INTERFACES (vrf, ifp) {
json_object *json_if;
json_object *json_addrs;
json_if = json_object_new_object();
json_object_object_add(json, ifp->name, json_if);
json_object_string_add(json_if, "status",
if_is_up(ifp) ? "up" : "down");
json_object_string_add(json_if, "vrfName", vrf->name);
json_addrs = json_object_new_array();
json_object_object_add(json_if, "addresses", json_addrs);
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL)
&& !CHECK_FLAG(connected->flags,
ZEBRA_IFA_SECONDARY)
&& !(connected->address->family == AF_INET6
&& IN6_IS_ADDR_LINKLOCAL(
&connected->address->u.prefix6))) {
char buf[PREFIX2STR_BUFFER];
json_array_string_add(
json_addrs,
prefix2str(connected->address, buf,
sizeof(buf)));
}
}
}
}
const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc,
char *pd_buf, uint32_t pd_buf_len)
{
@ -1483,7 +1538,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
vty_out(vty, " Link downs: %5u last: %s\n", zebra_if->down_count,
zebra_if->down_last[0] ? zebra_if->down_last : "(never)");
zebra_ptm_show_status(vty, ifp);
zebra_ptm_show_status(vty, NULL, ifp);
vrf = vrf_lookup_by_id(ifp->vrf_id);
vty_out(vty, " vrf: %s\n", vrf->name);
@ -1531,13 +1586,13 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node,
connected))
connected_dump_vty(vty, connected);
connected_dump_vty(vty, NULL, connected);
}
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL)
&& (connected->address->family == AF_INET6))
connected_dump_vty(vty, connected);
connected_dump_vty(vty, NULL, connected);
}
vty_out(vty, " Interface Type %s\n",
@ -1637,7 +1692,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
if (zebra_if->flags & ZIF_FLAG_LACP_BYPASS)
vty_out(vty, " LACP bypass: on\n");
zebra_evpn_if_es_print(vty, zebra_if);
zebra_evpn_if_es_print(vty, NULL, zebra_if);
vty_out(vty, " protodown: %s %s\n",
(zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off",
if_is_protodown_applicable(ifp) ? "" : "(n/a)");
@ -1716,7 +1771,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
if (listhead(ifp->nbr_connected))
vty_out(vty, " Neighbor address(s):\n");
for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node, nbr_connected))
nbr_connected_dump_vty(vty, nbr_connected);
nbr_connected_dump_vty(vty, NULL, nbr_connected);
#ifdef HAVE_PROC_NET_DEV
/* Statistics print out using proc file system. */
@ -1774,6 +1829,382 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
#endif /* HAVE_NET_RT_IFLIST */
}
static void if_dump_vty_json(struct vty *vty, struct interface *ifp,
json_object *json)
{
struct connected *connected;
struct nbr_connected *nbr_connected;
struct listnode *node;
struct route_node *rn;
struct zebra_if *zebra_if;
struct vrf *vrf;
char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN];
char buf[BUFSIZ];
json_object *json_if;
json_object *json_addrs;
json_if = json_object_new_object();
json_object_object_add(json, ifp->name, json_if);
if (if_is_up(ifp)) {
json_object_string_add(json_if, "administrativeStatus", "up");
if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_LINKDETECTION)) {
json_object_string_add(json_if, "operationalStatus",
if_is_running(ifp) ? "up"
: "down");
json_object_boolean_add(json_if, "linkDetection", true);
} else {
json_object_boolean_add(json_if, "linkDetection",
false);
}
} else {
json_object_string_add(json_if, "administrativeStatus", "down");
}
zebra_if = ifp->info;
json_object_int_add(json_if, "linkUps", zebra_if->up_count);
json_object_int_add(json_if, "linkDowns", zebra_if->down_count);
if (zebra_if->up_last[0])
json_object_string_add(json_if, "lastLinkUp",
zebra_if->up_last);
if (zebra_if->down_last[0])
json_object_string_add(json_if, "lastLinkDown",
zebra_if->down_last);
zebra_ptm_show_status(vty, json, ifp);
vrf = vrf_lookup_by_id(ifp->vrf_id);
json_object_string_add(json_if, "vrfName", vrf->name);
if (ifp->desc)
json_object_string_add(json_if, "description", ifp->desc);
if (zebra_if->desc)
json_object_string_add(json_if, "OsDescription",
zebra_if->desc);
if (ifp->ifindex == IFINDEX_INTERNAL) {
json_object_boolean_add(json_if, "pseudoInterface", true);
return;
} else if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) {
json_object_int_add(json_if, "index", ifp->ifindex);
return;
}
json_object_boolean_add(json_if, "pseudoInterface", false);
json_object_int_add(json_if, "index", ifp->ifindex);
json_object_int_add(json_if, "metric", ifp->metric);
json_object_int_add(json_if, "mtu", ifp->mtu);
if (ifp->mtu6 != ifp->mtu)
json_object_int_add(json_if, "mtu6", ifp->mtu6);
json_object_int_add(json_if, "speed", ifp->speed);
json_object_string_add(json_if, "flags", if_flag_dump(ifp->flags));
/* Hardware address. */
json_object_string_add(json_if, "type", if_link_type_str(ifp->ll_type));
if (ifp->hw_addr_len != 0) {
char hwbuf[BUFSIZ];
hwbuf[0] = '\0';
for (int i = 0; i < ifp->hw_addr_len; i++) {
snprintf(buf, sizeof(buf), "%s%02x", i == 0 ? "" : ":",
ifp->hw_addr[i]);
strlcat(hwbuf, buf, sizeof(hwbuf));
}
json_object_string_add(json_if, "hardwareAddress", hwbuf);
}
/* Bandwidth in Mbps */
if (ifp->bandwidth != 0)
json_object_int_add(json_if, "bandwidth", ifp->bandwidth);
/* IP addresses. */
json_addrs = json_object_new_array();
json_object_object_add(json_if, "ipAddresses", json_addrs);
for (rn = route_top(zebra_if->ipv4_subnets); rn; rn = route_next(rn)) {
if (!rn->info)
continue;
for (ALL_LIST_ELEMENTS_RO((struct list *)rn->info, node,
connected))
connected_dump_vty(vty, json_addrs, connected);
}
for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
if (CHECK_FLAG(connected->conf, ZEBRA_IFC_REAL)
&& (connected->address->family == AF_INET6))
connected_dump_vty(vty, json_addrs, connected);
}
json_object_string_add(json_if, "interfaceType",
zebra_ziftype_2str(zebra_if->zif_type));
json_object_string_add(
json_if, "interfaceSlaveType",
zebra_zifslavetype_2str(zebra_if->zif_slave_type));
if (IS_ZEBRA_IF_BRIDGE(ifp)) {
struct zebra_l2info_bridge *bridge_info;
bridge_info = &zebra_if->l2info.br;
json_object_boolean_add(json_if, "bridgeVlanAware",
bridge_info->vlan_aware);
} else if (IS_ZEBRA_IF_VLAN(ifp)) {
struct zebra_l2info_vlan *vlan_info;
vlan_info = &zebra_if->l2info.vl;
json_object_int_add(json_if, "vlanId", vlan_info->vid);
} else if (IS_ZEBRA_IF_VXLAN(ifp)) {
struct zebra_l2info_vxlan *vxlan_info;
vxlan_info = &zebra_if->l2info.vxl;
json_object_int_add(json_if, "vxlanId", vxlan_info->vni);
if (vxlan_info->vtep_ip.s_addr != INADDR_ANY)
json_object_string_add(json_if, "vtepIp",
inet_ntop(AF_INET,
&vxlan_info->vtep_ip,
buf, sizeof(buf)));
if (vxlan_info->access_vlan)
json_object_int_add(json_if, "accessVlanId",
vxlan_info->access_vlan);
if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
json_object_string_add(json_if, "mcastGroup",
inet_ntop(AF_INET,
&vxlan_info->mcast_grp,
buf, sizeof(buf)));
if (vxlan_info->ifindex_link
&& (vxlan_info->link_nsid != NS_UNKNOWN)) {
struct interface *ifp;
ifp = if_lookup_by_index_per_ns(
zebra_ns_lookup(vxlan_info->link_nsid),
vxlan_info->ifindex_link);
json_object_string_add(json_if, "linkInterface",
ifp == NULL ? "Unknown"
: ifp->name);
}
} else if (IS_ZEBRA_IF_GRE(ifp)) {
struct zebra_l2info_gre *gre_info;
gre_info = &zebra_if->l2info.gre;
if (gre_info->vtep_ip.s_addr != INADDR_ANY) {
json_object_string_add(json_if, "vtepIp",
inet_ntop(AF_INET,
&gre_info->vtep_ip,
buf, sizeof(buf)));
if (gre_info->vtep_ip_remote.s_addr != INADDR_ANY)
json_object_string_add(
json_if, "vtepRemoteIp",
inet_ntop(AF_INET,
&gre_info->vtep_ip_remote,
buf, sizeof(buf)));
}
if (gre_info->ifindex_link
&& (gre_info->link_nsid != NS_UNKNOWN)) {
struct interface *ifp;
ifp = if_lookup_by_index_per_ns(
zebra_ns_lookup(gre_info->link_nsid),
gre_info->ifindex_link);
json_object_string_add(json_if, "linkInterface",
ifp == NULL ? "Unknown"
: ifp->name);
}
}
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp)) {
struct zebra_l2info_brslave *br_slave;
br_slave = &zebra_if->brslave_info;
if (br_slave->bridge_ifindex != IFINDEX_INTERNAL) {
if (br_slave->br_if)
json_object_string_add(json_if,
"masterInterface",
br_slave->br_if->name);
else
json_object_int_add(json_if, "masterIfindex",
br_slave->bridge_ifindex);
}
}
if (IS_ZEBRA_IF_BOND_SLAVE(ifp)) {
struct zebra_l2info_bondslave *bond_slave;
bond_slave = &zebra_if->bondslave_info;
if (bond_slave->bond_ifindex != IFINDEX_INTERNAL) {
if (bond_slave->bond_if)
json_object_string_add(
json_if, "masterInterface",
bond_slave->bond_if->name);
else
json_object_int_add(json_if, "masterIfindex",
bond_slave->bond_ifindex);
}
}
json_object_boolean_add(
json_if, "lacpBypass",
CHECK_FLAG(zebra_if->flags, ZIF_FLAG_LACP_BYPASS));
zebra_evpn_if_es_print(vty, json_if, zebra_if);
if (if_is_protodown_applicable(ifp)) {
json_object_string_add(
json_if, "protodown",
(zebra_if->flags & ZIF_FLAG_PROTODOWN) ? "on" : "off");
if (zebra_if->protodown_rc)
json_object_string_add(
json_if, "protodownReason",
zebra_protodown_rc_str(zebra_if->protodown_rc,
pd_buf, sizeof(pd_buf)));
}
if (zebra_if->link_ifindex != IFINDEX_INTERNAL) {
if (zebra_if->link)
json_object_string_add(json_if, "parentInterface",
zebra_if->link->name);
else
json_object_int_add(json_if, "parentIfindex",
zebra_if->link_ifindex);
}
if (HAS_LINK_PARAMS(ifp)) {
struct if_link_params *iflp = ifp->link_params;
json_object *json_te;
json_te = json_object_new_object();
json_object_object_add(
json_if, "trafficEngineeringLinkParameters", json_te);
if (IS_PARAM_SET(iflp, LP_TE_METRIC))
json_object_int_add(json_te, "teMetric",
iflp->te_metric);
if (IS_PARAM_SET(iflp, LP_MAX_BW))
json_object_double_add(json_te, "maximumBandwidth",
iflp->max_bw);
if (IS_PARAM_SET(iflp, LP_MAX_RSV_BW))
json_object_double_add(json_te,
"maximumReservableBandwidth",
iflp->max_rsv_bw);
if (IS_PARAM_SET(iflp, LP_UNRSV_BW)) {
json_object *json_bws;
json_bws = json_object_new_object();
json_object_object_add(json_te, "unreservedBandwidth",
json_bws);
for (unsigned int i = 0; i < MAX_CLASS_TYPE; ++i) {
char buf_ct[64];
snprintf(buf_ct, sizeof(buf_ct), "classType%u",
i);
json_object_double_add(json_bws, buf_ct,
iflp->unrsv_bw[i]);
}
}
if (IS_PARAM_SET(iflp, LP_ADM_GRP))
json_object_int_add(json_te, "administrativeGroup",
iflp->admin_grp);
if (IS_PARAM_SET(iflp, LP_DELAY)) {
json_object_int_add(json_te, "linkDelayAverage",
iflp->av_delay);
if (IS_PARAM_SET(iflp, LP_MM_DELAY)) {
json_object_int_add(json_te, "linkDelayMinimum",
iflp->min_delay);
json_object_int_add(json_te, "linkDelayMaximum",
iflp->max_delay);
}
}
if (IS_PARAM_SET(iflp, LP_DELAY_VAR))
json_object_int_add(json_te, "linkDelayVariation",
iflp->delay_var);
if (IS_PARAM_SET(iflp, LP_PKT_LOSS))
json_object_double_add(json_te, "linkPacketLoss",
iflp->pkt_loss);
if (IS_PARAM_SET(iflp, LP_AVA_BW))
json_object_double_add(json_te, "availableBandwidth",
iflp->ava_bw);
if (IS_PARAM_SET(iflp, LP_RES_BW))
json_object_double_add(json_te, "residualBandwidth",
iflp->res_bw);
if (IS_PARAM_SET(iflp, LP_USE_BW))
json_object_double_add(json_te, "utilizedBandwidth",
iflp->use_bw);
if (IS_PARAM_SET(iflp, LP_RMT_AS))
json_object_string_add(json_te, "neighborAsbrIp",
inet_ntop(AF_INET, &iflp->rmt_ip,
buf, sizeof(buf)));
json_object_int_add(json_te, "neighborAsbrAs", iflp->rmt_as);
}
if (listhead(ifp->nbr_connected)) {
json_object *json_nbr_addrs;
json_nbr_addrs = json_object_new_array();
json_object_object_add(json_if, "neighborIpAddresses",
json_nbr_addrs);
for (ALL_LIST_ELEMENTS_RO(ifp->nbr_connected, node,
nbr_connected))
nbr_connected_dump_vty(vty, json_nbr_addrs,
nbr_connected);
}
#ifdef HAVE_PROC_NET_DEV
json_object_int_add(json_if, "inputPackets", stats.rx_packets);
json_object_int_add(json_if, "inputBytes", ifp->stats.rx_bytes);
json_object_int_add(json_if, "inputDropped", ifp->stats.rx_dropped);
json_object_int_add(json_if, "inputMulticastPackets",
ifp->stats.rx_multicast);
json_object_int_add(json_if, "inputErrors", ifp->stats.rx_errors);
json_object_int_add(json_if, "inputLengthErrors",
ifp->stats.rx_length_errors);
json_object_int_add(json_if, "inputOverrunErrors",
ifp->stats.rx_over_errors);
json_object_int_add(json_if, "inputCrcErrors",
ifp->stats.rx_crc_errors);
json_object_int_add(json_if, "inputFrameErrors",
ifp->stats.rx_frame_errors);
json_object_int_add(json_if, "inputFifoErrors",
ifp->stats.rx_fifo_errors);
json_object_int_add(json_if, "inputMissedErrors",
ifp->stats.rx_missed_errors);
json_object_int_add(json_if, "outputPackets", ifp->stats.tx_packets);
json_object_int_add(json_if, "outputBytes", ifp->stats.tx_bytes);
json_object_int_add(json_if, "outputDroppedPackets",
ifp->stats.tx_dropped);
json_object_int_add(json_if, "outputErrors", ifp->stats.tx_errors);
json_object_int_add(json_if, "outputAbortedErrors",
ifp->stats.tx_aborted_errors);
json_object_int_add(json_if, "outputCarrierErrors",
ifp->stats.tx_carrier_errors);
json_object_int_add(json_if, "outputFifoErrors",
ifp->stats.tx_fifo_errors);
json_object_int_add(json_if, "outputHeartbeatErrors",
ifp->stats.tx_heartbeat_errors);
json_object_int_add(json_if, "outputWindowErrors",
ifp->stats.tx_window_errors);
json_object_int_add(json_if, "collisions", ifp->stats.collisions);
#endif /* HAVE_PROC_NET_DEV */
#ifdef HAVE_NET_RT_IFLIST
json_object_int_add(json_if, "inputPackets", ifp->stats.ifi_ipackets);
json_object_int_add(json_if, "inputBytes", ifp->stats.ifi_ibytes);
json_object_int_add(json_if, "inputDropd", ifp->stats.ifi_iqdrops);
json_object_int_add(json_if, "inputMulticastPackets",
ifp->stats.ifi_imcasts);
json_object_int_add(json_if, "inputErrors", ifp->stats.ifi_ierrors);
json_object_int_add(json_if, "outputPackets", ifp->stats.ifi_opackets);
json_object_int_add(json_if, "outputBytes", ifp->stats.ifi_obytes);
json_object_int_add(json_if, "outputMulticastPackets",
ifp->stats.ifi_omcasts);
json_object_int_add(json_if, "outputErrors", ifp->stats.ifi_oerrors);
json_object_int_add(json_if, "collisions", ifp->stats.ifi_collisions);
#endif /* HAVE_NET_RT_IFLIST */
}
static void interface_update_stats(void)
{
#ifdef HAVE_PROC_NET_DEV
@ -1791,31 +2222,52 @@ static void interface_update_stats(void)
#endif
/* Show all interfaces to vty. */
DEFPY(show_interface, show_interface_cmd,
"show interface vrf NAME$vrf_name [brief$brief]",
"show interface vrf NAME$vrf_name [brief$brief] [json$uj]",
SHOW_STR
"Interface status and configuration\n"
VRF_CMD_HELP_STR
"Interface status and configuration summary\n")
"Interface status and configuration summary\n"
JSON_STR)
{
struct vrf *vrf;
struct interface *ifp;
json_object *json = NULL;
interface_update_stats();
vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "%% VRF %s not found\n", vrf_name);
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VRF %s not found\n", vrf_name);
return CMD_WARNING;
}
if (uj)
json = json_object_new_object();
if (brief) {
ifs_dump_brief_vty(vty, vrf);
if (json)
ifs_dump_brief_vty_json(json, vrf);
else
ifs_dump_brief_vty(vty, vrf);
} else {
FOR_ALL_INTERFACES (vrf, ifp) {
if_dump_vty(vty, ifp);
if (json)
if_dump_vty_json(vty, ifp, json);
else
if_dump_vty(vty, ifp);
}
}
if (json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
@ -1823,85 +2275,140 @@ DEFPY(show_interface, show_interface_cmd,
/* Show all interfaces to vty. */
DEFPY (show_interface_vrf_all,
show_interface_vrf_all_cmd,
"show interface [vrf all] [brief$brief]",
"show interface [vrf all] [brief$brief] [json$uj]",
SHOW_STR
"Interface status and configuration\n"
VRF_ALL_CMD_HELP_STR
"Interface status and configuration summary\n")
"Interface status and configuration summary\n"
JSON_STR)
{
struct vrf *vrf;
struct interface *ifp;
json_object *json = NULL;
interface_update_stats();
if (uj)
json = json_object_new_object();
/* All interface print. */
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if (brief) {
ifs_dump_brief_vty(vty, vrf);
if (json)
ifs_dump_brief_vty_json(json, vrf);
else
ifs_dump_brief_vty(vty, vrf);
} else {
FOR_ALL_INTERFACES (vrf, ifp)
if_dump_vty(vty, ifp);
FOR_ALL_INTERFACES (vrf, ifp) {
if (json)
if_dump_vty_json(vty, ifp, json);
else
if_dump_vty(vty, ifp);
}
}
}
if (json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
/* Show specified interface to vty. */
DEFUN (show_interface_name_vrf,
DEFPY (show_interface_name_vrf,
show_interface_name_vrf_cmd,
"show interface IFNAME vrf NAME",
"show interface IFNAME$ifname vrf NAME$vrf_name [json$uj]",
SHOW_STR
"Interface status and configuration\n"
"Interface name\n"
VRF_CMD_HELP_STR)
VRF_CMD_HELP_STR
JSON_STR)
{
int idx_ifname = 2;
int idx_name = 4;
struct interface *ifp;
struct vrf *vrf;
json_object *json = NULL;
interface_update_stats();
vrf = vrf_lookup_by_name(argv[idx_name]->arg);
vrf = vrf_lookup_by_name(vrf_name);
if (!vrf) {
vty_out(vty, "%% VRF %s not found\n", argv[idx_name]->arg);
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% VRF %s not found\n", vrf_name);
return CMD_WARNING;
}
ifp = if_lookup_by_name_vrf(argv[idx_ifname]->arg, vrf);
ifp = if_lookup_by_name_vrf(ifname, vrf);
if (ifp == NULL) {
vty_out(vty, "%% Can't find interface %s\n",
argv[idx_ifname]->arg);
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% Can't find interface %s\n", ifname);
return CMD_WARNING;
}
if_dump_vty(vty, ifp);
if (uj)
json = json_object_new_object();
if (json)
if_dump_vty_json(vty, ifp, json);
else
if_dump_vty(vty, ifp);
if (json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}
/* Show specified interface to vty. */
DEFUN (show_interface_name_vrf_all,
DEFPY (show_interface_name_vrf_all,
show_interface_name_vrf_all_cmd,
"show interface IFNAME [vrf all]",
"show interface IFNAME$ifname [vrf all] [json$uj]",
SHOW_STR
"Interface status and configuration\n"
"Interface name\n"
VRF_ALL_CMD_HELP_STR)
VRF_ALL_CMD_HELP_STR
JSON_STR)
{
int idx_ifname = 2;
struct interface *ifp;
json_object *json = NULL;
interface_update_stats();
ifp = if_lookup_by_name_all_vrf(argv[idx_ifname]->arg);
ifp = if_lookup_by_name_all_vrf(ifname);
if (ifp == NULL) {
vty_out(vty, "%% Can't find interface %s\n",
argv[idx_ifname]->arg);
if (uj)
vty_out(vty, "{}\n");
else
vty_out(vty, "%% Can't find interface %s\n", ifname);
return CMD_WARNING;
}
if_dump_vty(vty, ifp);
if (uj)
json = json_object_new_object();
if (json)
if_dump_vty_json(vty, ifp, json);
else
if_dump_vty(vty, ifp);
if (json) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
json, JSON_C_TO_STRING_PRETTY));
json_object_free(json);
}
return CMD_SUCCESS;
}

View File

@ -2781,41 +2781,76 @@ bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
return false;
}
void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif)
void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
struct zebra_if *zif)
{
char buf[ETHER_ADDR_STRLEN];
char mh_buf[80];
bool vty_print = false;
char esi_buf[ESI_STR_LEN];
mh_buf[0] = '\0';
strlcat(mh_buf, " EVPN-MH:", sizeof(mh_buf));
if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
vty_print = true;
snprintf(
mh_buf + strlen(mh_buf),
sizeof(mh_buf) - strlen(mh_buf),
" ES id %u ES sysmac %s", zif->es_info.lid,
prefix_mac2str(&zif->es_info.sysmac, buf, sizeof(buf)));
} else if (memcmp(&zif->es_info.esi, zero_esi, sizeof(*zero_esi))) {
vty_print = true;
snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
sizeof(mh_buf) - strnlen(mh_buf, sizeof(mh_buf)),
" ES id %s",
esi_to_str(&zif->es_info.esi, esi_buf,
sizeof(esi_buf)));
}
if (json) {
json_object *json_evpn;
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
vty_print = true;
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
else
strlcat(mh_buf, " uplink (down)", sizeof(mh_buf));
}
json_evpn = json_object_new_object();
json_object_object_add(json, "evpnMh", json_evpn);
if (vty_print)
vty_out(vty, "%s\n", mh_buf);
if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
json_object_int_add(json_evpn, "esId",
zif->es_info.lid);
json_object_string_add(
json_evpn, "esSysmac",
prefix_mac2str(&zif->es_info.sysmac, buf,
sizeof(buf)));
} else if (memcmp(&zif->es_info.esi, zero_esi,
sizeof(*zero_esi))) {
json_object_string_add(json_evpn, "esId",
esi_to_str(&zif->es_info.esi,
esi_buf,
sizeof(esi_buf)));
}
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK)
json_object_string_add(
json_evpn, "uplink",
CHECK_FLAG(zif->flags,
ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
? "up"
: "down");
} else {
char mh_buf[80];
bool vty_print = false;
mh_buf[0] = '\0';
strlcat(mh_buf, " EVPN-MH:", sizeof(mh_buf));
if (zif->es_info.lid || !is_zero_mac(&zif->es_info.sysmac)) {
vty_print = true;
snprintf(mh_buf + strlen(mh_buf),
sizeof(mh_buf) - strlen(mh_buf),
" ES id %u ES sysmac %s", zif->es_info.lid,
prefix_mac2str(&zif->es_info.sysmac, buf,
sizeof(buf)));
} else if (memcmp(&zif->es_info.esi, zero_esi,
sizeof(*zero_esi))) {
vty_print = true;
snprintf(mh_buf + strnlen(mh_buf, sizeof(mh_buf)),
sizeof(mh_buf)
- strnlen(mh_buf, sizeof(mh_buf)),
" ES id %s",
esi_to_str(&zif->es_info.esi, esi_buf,
sizeof(esi_buf)));
}
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK) {
vty_print = true;
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)
strlcat(mh_buf, " uplink (up)", sizeof(mh_buf));
else
strlcat(mh_buf, " uplink (down)",
sizeof(mh_buf));
}
if (vty_print)
vty_out(vty, "%s\n", mh_buf);
}
}
static void zebra_evpn_local_mac_oper_state_change(struct zebra_evpn_es *es)

View File

@ -346,7 +346,8 @@ extern int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp);
extern void zebra_evpn_acc_vl_show(struct vty *vty, bool uj);
extern void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj);
extern void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid);
extern void zebra_evpn_if_es_print(struct vty *vty, struct zebra_if *zif);
extern void zebra_evpn_if_es_print(struct vty *vty, json_object *json,
struct zebra_if *zif);
extern void zebra_evpn_es_cleanup(void);
extern int zebra_evpn_mh_mac_holdtime_update(struct vty *vty,
uint32_t duration, bool set_default);

View File

@ -1092,14 +1092,20 @@ static const char *zebra_ptm_get_status_str(int status)
}
}
void zebra_ptm_show_status(struct vty *vty, struct interface *ifp)
void zebra_ptm_show_status(struct vty *vty, json_object *json,
struct interface *ifp)
{
vty_out(vty, " PTM status: ");
if (ifp->ptm_enable) {
vty_out(vty, "%s\n", zebra_ptm_get_status_str(ifp->ptm_status));
} else {
vty_out(vty, "disabled\n");
}
const char *status;
if (ifp->ptm_enable)
status = zebra_ptm_get_status_str(ifp->ptm_status);
else
status = "disabled";
if (json)
json_object_string_add(json, "ptmStatus", status);
else
vty_out(vty, " PTM status: %s\n", status);
}
void zebra_ptm_send_status_req(void)
@ -1537,6 +1543,7 @@ int zebra_ptm_get_enable_state(void)
}
void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
json_object *json __attribute__((__unused__)),
struct interface *ifp __attribute__((__unused__)))
{
/* NOTHING */

View File

@ -86,7 +86,8 @@ void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS);
void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS);
#endif /* HAVE_BFDD */
void zebra_ptm_show_status(struct vty *vty, struct interface *ifp);
void zebra_ptm_show_status(struct vty *vty, json_object *json,
struct interface *ifp);
void zebra_ptm_if_init(struct zebra_if *zebra_ifp);
void zebra_ptm_if_set_ptm_state(struct interface *ifp,
struct zebra_if *zebra_ifp);