mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-02 20:44:29 +00:00

Provide a way for the data plane to indicate pseudowire status (such as: not forwarding, AC failure). On a data plane pseudowire install failure, data plane sets the pseudowire status. Zebra relays the pseudowire status to LDP. LDP includes the pseudowire status in the LDP notification to the LDP peer. Signed-off-by: Karen Schoener <karen@voltanet.io>
2043 lines
54 KiB
C
2043 lines
54 KiB
C
/*
|
|
* Copyright (C) 2016 by Open Source Routing.
|
|
*
|
|
* This program 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 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 <sys/un.h>
|
|
|
|
#include "ldpd.h"
|
|
#include "ldpe.h"
|
|
#include "lde.h"
|
|
#include "log.h"
|
|
#include "ldp_vty.h"
|
|
#include "lib/json.h"
|
|
|
|
#include "command.h"
|
|
#include "vty.h"
|
|
#include "mpls.h"
|
|
|
|
enum show_command {
|
|
SHOW_DISC,
|
|
SHOW_IFACE,
|
|
SHOW_NBR,
|
|
SHOW_LIB,
|
|
SHOW_L2VPN_PW,
|
|
SHOW_L2VPN_BINDING
|
|
};
|
|
|
|
struct show_params {
|
|
int family;
|
|
union ldpd_addr addr;
|
|
uint8_t prefixlen;
|
|
int detail;
|
|
int json;
|
|
union {
|
|
struct {
|
|
struct in_addr lsr_id;
|
|
int capabilities;
|
|
} neighbor;
|
|
struct {
|
|
struct prefix prefix;
|
|
int longer_prefixes;
|
|
struct in_addr neighbor;
|
|
uint32_t local_label;
|
|
uint32_t remote_label;
|
|
} lib;
|
|
struct {
|
|
struct in_addr peer;
|
|
uint32_t local_label;
|
|
uint32_t remote_label;
|
|
char ifname[IFNAMSIZ];
|
|
uint32_t vcid;
|
|
} l2vpn;
|
|
};
|
|
};
|
|
|
|
#define LDPBUFSIZ 65535
|
|
|
|
static int show_interface_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_interface_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static int show_discovery_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static void show_discovery_detail_adj(struct vty *, char *,
|
|
struct ctl_adj *);
|
|
static int show_discovery_detail_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_discovery_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static void show_discovery_detail_adj_json(json_object *,
|
|
struct ctl_adj *);
|
|
static int show_discovery_detail_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
|
|
static int show_nbr_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_nbr_msg_json(struct imsg *, struct show_params *,
|
|
json_object *);
|
|
static void show_nbr_detail_adj(struct vty *, char *,
|
|
struct ctl_adj *);
|
|
static int show_nbr_detail_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static void show_nbr_detail_adj_json(struct ctl_adj *,
|
|
json_object *);
|
|
static int show_nbr_detail_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static void show_nbr_capabilities(struct vty *, struct ctl_nbr *);
|
|
static int show_nbr_capabilities_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static void show_nbr_capabilities_json(struct ctl_nbr *,
|
|
json_object *);
|
|
static int show_nbr_capabilities_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static int show_lib_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_lib_detail_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_lib_msg_json(struct imsg *, struct show_params *,
|
|
json_object *);
|
|
static int show_lib_detail_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static int show_l2vpn_binding_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_l2vpn_binding_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static int show_l2vpn_pw_msg(struct vty *, struct imsg *,
|
|
struct show_params *);
|
|
static int show_l2vpn_pw_msg_json(struct imsg *,
|
|
struct show_params *, json_object *);
|
|
static int ldp_vty_connect(struct imsgbuf *);
|
|
static int ldp_vty_dispatch_msg(struct vty *, struct imsg *,
|
|
enum show_command, struct show_params *,
|
|
json_object *);
|
|
static int ldp_vty_dispatch(struct vty *, struct imsgbuf *,
|
|
enum show_command, struct show_params *);
|
|
static int ldp_vty_get_af(const char *, int *);
|
|
|
|
static int
|
|
show_interface_msg(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params)
|
|
{
|
|
struct ctl_iface *iface;
|
|
char timers[BUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_INTERFACE:
|
|
iface = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != iface->af)
|
|
break;
|
|
|
|
snprintf(timers, sizeof(timers), "%u/%u",
|
|
iface->hello_interval, iface->hello_holdtime);
|
|
|
|
vty_out (vty, "%-4s %-11s %-6s %-8s %-12s %3u\n",
|
|
af_name(iface->af), iface->name,
|
|
if_state_name(iface->state), iface->uptime == 0 ?
|
|
"00:00:00" : log_time(iface->uptime), timers,
|
|
iface->adj_cnt);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_interface_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_iface *iface;
|
|
json_object *json_iface;
|
|
char key_name[64];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_INTERFACE:
|
|
iface = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != iface->af)
|
|
break;
|
|
|
|
json_iface = json_object_new_object();
|
|
json_object_string_add(json_iface, "name", iface->name);
|
|
json_object_string_add(json_iface, "addressFamily",
|
|
af_name(iface->af));
|
|
json_object_string_add(json_iface, "state",
|
|
if_state_name(iface->state));
|
|
json_object_string_add(json_iface, "upTime",
|
|
log_time(iface->uptime));
|
|
json_object_int_add(json_iface, "helloInterval",
|
|
iface->hello_interval);
|
|
json_object_int_add(json_iface, "helloHoldtime",
|
|
iface->hello_holdtime);
|
|
json_object_int_add(json_iface, "adjacencyCount",
|
|
iface->adj_cnt);
|
|
|
|
snprintf(key_name, sizeof(key_name), "%s: %s", iface->name,
|
|
af_name(iface->af));
|
|
json_object_object_add(json, key_name, json_iface);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_discovery_msg(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params)
|
|
{
|
|
struct ctl_adj *adj;
|
|
const char *addr;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_DISCOVERY:
|
|
adj = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != adj->af)
|
|
break;
|
|
|
|
vty_out(vty, "%-4s %-15s ", af_name(adj->af),
|
|
inet_ntoa(adj->id));
|
|
switch(adj->type) {
|
|
case HELLO_LINK:
|
|
vty_out(vty, "%-8s %-15s ", "Link", adj->ifname);
|
|
break;
|
|
case HELLO_TARGETED:
|
|
addr = log_addr(adj->af, &adj->src_addr);
|
|
|
|
vty_out(vty, "%-8s %-15s ", "Targeted", addr);
|
|
if (strlen(addr) > 15)
|
|
vty_out(vty, "\n%46s", " ");
|
|
break;
|
|
}
|
|
vty_out (vty, "%9u\n", adj->holdtime);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
show_discovery_detail_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
|
|
{
|
|
size_t buflen = strlen(buffer);
|
|
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" LSR Id: %s:0\n", inet_ntoa(adj->id));
|
|
buflen = strlen(buffer);
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Source address: %s\n",
|
|
log_addr(adj->af, &adj->src_addr));
|
|
buflen = strlen(buffer);
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Transport address: %s\n",
|
|
log_addr(adj->af, &adj->trans_addr));
|
|
buflen = strlen(buffer);
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Hello hold time: %u secs (due in %u secs)\n",
|
|
adj->holdtime, adj->holdtime_remaining);
|
|
buflen = strlen(buffer);
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Dual-stack capability TLV: %s\n",
|
|
(adj->ds_tlv) ? "yes" : "no");
|
|
}
|
|
|
|
static int
|
|
show_discovery_detail_msg(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params)
|
|
{
|
|
struct ctl_adj *adj;
|
|
struct ctl_disc_if *iface;
|
|
struct ctl_disc_tnbr *tnbr;
|
|
struct in_addr rtr_id;
|
|
union ldpd_addr *trans_addr;
|
|
size_t buflen;
|
|
static char ifaces_buffer[LDPBUFSIZ];
|
|
static char tnbrs_buffer[LDPBUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_DISCOVERY:
|
|
ifaces_buffer[0] = '\0';
|
|
tnbrs_buffer[0] = '\0';
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_IFACE:
|
|
iface = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC &&
|
|
((params->family == AF_INET && !iface->active_v4) ||
|
|
(params->family == AF_INET6 && !iface->active_v6)))
|
|
break;
|
|
|
|
buflen = strlen(ifaces_buffer);
|
|
snprintf(ifaces_buffer + buflen, LDPBUFSIZ - buflen,
|
|
" %s: %s\n", iface->name, (iface->no_adj) ?
|
|
"(no adjacencies)" : "");
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_TNBR:
|
|
tnbr = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != tnbr->af)
|
|
break;
|
|
|
|
trans_addr = &(ldp_af_conf_get(ldpd_conf,
|
|
tnbr->af))->trans_addr;
|
|
buflen = strlen(tnbrs_buffer);
|
|
snprintf(tnbrs_buffer + buflen, LDPBUFSIZ - buflen,
|
|
" %s -> %s: %s\n", log_addr(tnbr->af, trans_addr),
|
|
log_addr(tnbr->af, &tnbr->addr), (tnbr->no_adj) ?
|
|
"(no adjacencies)" : "");
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_ADJ:
|
|
adj = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != adj->af)
|
|
break;
|
|
|
|
switch(adj->type) {
|
|
case HELLO_LINK:
|
|
show_discovery_detail_adj(vty, ifaces_buffer, adj);
|
|
break;
|
|
case HELLO_TARGETED:
|
|
show_discovery_detail_adj(vty, tnbrs_buffer, adj);
|
|
break;
|
|
}
|
|
break;
|
|
case IMSG_CTL_END:
|
|
rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
|
|
vty_out (vty, "Local:\n");
|
|
vty_out (vty, " LSR Id: %s:0\n",inet_ntoa(rtr_id));
|
|
if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
|
|
vty_out (vty, " Transport Address (IPv4): %s\n",
|
|
log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr));
|
|
if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
|
|
vty_out (vty, " Transport Address (IPv6): %s\n",
|
|
log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr));
|
|
vty_out (vty, "Discovery Sources:\n");
|
|
vty_out (vty, " Interfaces:\n");
|
|
vty_out(vty, "%s", ifaces_buffer);
|
|
vty_out (vty, " Targeted Hellos:\n");
|
|
vty_out(vty, "%s", tnbrs_buffer);
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_discovery_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_adj *adj;
|
|
json_object *json_array;
|
|
json_object *json_adj;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_DISCOVERY:
|
|
adj = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != adj->af)
|
|
break;
|
|
|
|
json_object_object_get_ex(json, "adjacencies", &json_array);
|
|
if (!json_array) {
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json, "adjacencies", json_array);
|
|
}
|
|
|
|
json_adj = json_object_new_object();
|
|
json_object_string_add(json_adj, "addressFamily",
|
|
af_name(adj->af));
|
|
json_object_string_add(json_adj, "neighborId",
|
|
inet_ntoa(adj->id));
|
|
switch(adj->type) {
|
|
case HELLO_LINK:
|
|
json_object_string_add(json_adj, "type", "link");
|
|
json_object_string_add(json_adj, "interface",
|
|
adj->ifname);
|
|
break;
|
|
case HELLO_TARGETED:
|
|
json_object_string_add(json_adj, "type", "targeted");
|
|
json_object_string_add(json_adj, "peer",
|
|
log_addr(adj->af, &adj->src_addr));
|
|
break;
|
|
}
|
|
json_object_int_add(json_adj, "helloHoldtime", adj->holdtime);
|
|
|
|
json_object_array_add(json_array, json_adj);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
show_discovery_detail_adj_json(json_object *json, struct ctl_adj *adj)
|
|
{
|
|
json_object *json_adj;
|
|
json_object *json_array;
|
|
|
|
json_object_object_get_ex(json, "adjacencies", &json_array);
|
|
if (!json_array) {
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json, "adjacencies", json_array);
|
|
}
|
|
|
|
json_adj = json_object_new_object();
|
|
json_object_string_add(json_adj, "lsrId", inet_ntoa(adj->id));
|
|
json_object_string_add(json_adj, "sourceAddress", log_addr(adj->af,
|
|
&adj->src_addr));
|
|
json_object_string_add(json_adj, "transportAddress", log_addr(adj->af,
|
|
&adj->trans_addr));
|
|
json_object_int_add(json_adj, "helloHoldtime", adj->holdtime);
|
|
json_object_int_add(json_adj, "helloHoldtimeRemaining",
|
|
adj->holdtime_remaining);
|
|
json_object_int_add(json_adj, "dualStackCapabilityTlv",
|
|
adj->ds_tlv);
|
|
json_object_array_add(json_array, json_adj);
|
|
}
|
|
|
|
static int
|
|
show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_adj *adj;
|
|
struct ctl_disc_if *iface;
|
|
struct ctl_disc_tnbr *tnbr;
|
|
struct in_addr rtr_id;
|
|
union ldpd_addr *trans_addr;
|
|
json_object *json_interface;
|
|
json_object *json_target;
|
|
static json_object *json_interfaces;
|
|
static json_object *json_targets;
|
|
static json_object *json_container;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_DISCOVERY:
|
|
rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf);
|
|
json_object_string_add(json, "lsrId", inet_ntoa(rtr_id));
|
|
if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED)
|
|
json_object_string_add(json, "transportAddressIPv4",
|
|
log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr));
|
|
if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED)
|
|
json_object_string_add(json, "transportAddressIPv6",
|
|
log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr));
|
|
json_interfaces = json_object_new_object();
|
|
json_object_object_add(json, "interfaces", json_interfaces);
|
|
json_targets = json_object_new_object();
|
|
json_object_object_add(json, "targetedHellos", json_targets);
|
|
json_container = NULL;
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_IFACE:
|
|
iface = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC &&
|
|
((params->family == AF_INET && !iface->active_v4) ||
|
|
(params->family == AF_INET6 && !iface->active_v6)))
|
|
break;
|
|
|
|
json_interface = json_object_new_object();
|
|
json_object_object_add(json_interfaces, iface->name,
|
|
json_interface);
|
|
json_container = json_interface;
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_TNBR:
|
|
tnbr = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != tnbr->af)
|
|
break;
|
|
|
|
trans_addr = &(ldp_af_conf_get(ldpd_conf, tnbr->af))->trans_addr;
|
|
|
|
json_target = json_object_new_object();
|
|
json_object_string_add(json_target, "sourceAddress",
|
|
log_addr(tnbr->af, trans_addr));
|
|
json_object_object_add(json_targets, log_addr(tnbr->af,
|
|
&tnbr->addr), json_target);
|
|
json_container = json_target;
|
|
break;
|
|
case IMSG_CTL_SHOW_DISC_ADJ:
|
|
adj = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != adj->af)
|
|
break;
|
|
|
|
switch(adj->type) {
|
|
case HELLO_LINK:
|
|
show_discovery_detail_adj_json(json_container, adj);
|
|
break;
|
|
case HELLO_TARGETED:
|
|
show_discovery_detail_adj_json(json_container, adj);
|
|
break;
|
|
}
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
const char *addr;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
addr = log_addr(nbr->af, &nbr->raddr);
|
|
|
|
vty_out(vty, "%-4s %-15s %-11s %-15s",
|
|
af_name(nbr->af), inet_ntoa(nbr->id),
|
|
nbr_state_name(nbr->nbr_state), addr);
|
|
if (strlen(addr) > 15)
|
|
vty_out(vty, "\n%48s", " ");
|
|
vty_out (vty, " %8s\n", log_time(nbr->uptime));
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
show_nbr_detail_adj(struct vty *vty, char *buffer, struct ctl_adj *adj)
|
|
{
|
|
size_t buflen = strlen(buffer);
|
|
|
|
switch (adj->type) {
|
|
case HELLO_LINK:
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Interface: %s\n", adj->ifname);
|
|
break;
|
|
case HELLO_TARGETED:
|
|
snprintf(buffer + buflen, LDPBUFSIZ - buflen,
|
|
" Targeted Hello: %s\n", log_addr(adj->af,
|
|
&adj->src_addr));
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int
|
|
show_nbr_detail_msg(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
struct ldp_stats *stats;
|
|
struct ctl_adj *adj;
|
|
static char v4adjs_buffer[LDPBUFSIZ];
|
|
static char v6adjs_buffer[LDPBUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
v4adjs_buffer[0] = '\0';
|
|
v6adjs_buffer[0] = '\0';
|
|
vty_out (vty, "Peer LDP Identifier: %s:0\n",
|
|
inet_ntoa(nbr->id));
|
|
vty_out (vty, " TCP connection: %s:%u - %s:%u\n",
|
|
log_addr(nbr->af, &nbr->laddr), ntohs(nbr->lport),
|
|
log_addr(nbr->af, &nbr->raddr),ntohs(nbr->rport));
|
|
vty_out (vty, " Authentication: %s\n",
|
|
(nbr->auth_method == AUTH_MD5SIG) ? "TCP MD5 Signature" : "none");
|
|
vty_out(vty, " Session Holdtime: %u secs; "
|
|
"KeepAlive interval: %u secs\n", nbr->holdtime,
|
|
nbr->holdtime / KEEPALIVE_PER_PERIOD);
|
|
vty_out(vty, " State: %s; Downstream-Unsolicited\n",
|
|
nbr_state_name(nbr->nbr_state));
|
|
vty_out (vty, " Up time: %s\n",log_time(nbr->uptime));
|
|
|
|
stats = &nbr->stats;
|
|
vty_out (vty, " Messages sent/rcvd:\n");
|
|
vty_out (vty, " - Keepalive Messages: %u/%u\n",
|
|
stats->kalive_sent, stats->kalive_rcvd);
|
|
vty_out (vty, " - Address Messages: %u/%u\n",
|
|
stats->addr_sent, stats->addr_rcvd);
|
|
vty_out (vty, " - Address Withdraw Messages: %u/%u\n",
|
|
stats->addrwdraw_sent, stats->addrwdraw_rcvd);
|
|
vty_out (vty, " - Notification Messages: %u/%u\n",
|
|
stats->notif_sent, stats->notif_rcvd);
|
|
vty_out (vty, " - Capability Messages: %u/%u\n",
|
|
stats->capability_sent, stats->capability_rcvd);
|
|
vty_out (vty, " - Label Mapping Messages: %u/%u\n",
|
|
stats->labelmap_sent, stats->labelmap_rcvd);
|
|
vty_out (vty, " - Label Request Messages: %u/%u\n",
|
|
stats->labelreq_sent, stats->labelreq_rcvd);
|
|
vty_out (vty, " - Label Withdraw Messages: %u/%u\n",
|
|
stats->labelwdraw_sent, stats->labelwdraw_rcvd);
|
|
vty_out (vty, " - Label Release Messages: %u/%u\n",
|
|
stats->labelrel_sent, stats->labelrel_rcvd);
|
|
vty_out (vty, " - Label Abort Request Messages: %u/%u\n",
|
|
stats->labelabreq_sent, stats->labelabreq_rcvd);
|
|
|
|
show_nbr_capabilities(vty, nbr);
|
|
break;
|
|
case IMSG_CTL_SHOW_NBR_DISC:
|
|
adj = imsg->data;
|
|
|
|
switch (adj->af) {
|
|
case AF_INET:
|
|
show_nbr_detail_adj(vty, v4adjs_buffer, adj);
|
|
break;
|
|
case AF_INET6:
|
|
show_nbr_detail_adj(vty, v6adjs_buffer, adj);
|
|
break;
|
|
default:
|
|
fatalx("show_nbr_detail_msg: unknown af");
|
|
}
|
|
break;
|
|
case IMSG_CTL_SHOW_NBR_END:
|
|
vty_out (vty, " LDP Discovery Sources:\n");
|
|
if (v4adjs_buffer[0] != '\0') {
|
|
vty_out (vty, " IPv4:\n");
|
|
vty_out(vty, "%s", v4adjs_buffer);
|
|
}
|
|
if (v6adjs_buffer[0] != '\0') {
|
|
vty_out (vty, " IPv6:\n");
|
|
vty_out(vty, "%s", v6adjs_buffer);
|
|
}
|
|
vty_out (vty, "\n");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_nbr_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
json_object *json_array;
|
|
json_object *json_nbr;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
json_object_object_get_ex(json, "neighbors", &json_array);
|
|
if (!json_array) {
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json, "neighbors", json_array);
|
|
}
|
|
|
|
json_nbr = json_object_new_object();
|
|
json_object_string_add(json_nbr, "addressFamily",
|
|
af_name(nbr->af));
|
|
json_object_string_add(json_nbr, "neighborId",
|
|
inet_ntoa(nbr->id));
|
|
json_object_string_add(json_nbr, "state",
|
|
nbr_state_name(nbr->nbr_state));
|
|
json_object_string_add(json_nbr, "transportAddress",
|
|
log_addr(nbr->af, &nbr->raddr));
|
|
json_object_string_add(json_nbr, "upTime",
|
|
log_time(nbr->uptime));
|
|
|
|
json_object_array_add(json_array, json_nbr);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
show_nbr_detail_adj_json(struct ctl_adj *adj, json_object *adj_list)
|
|
{
|
|
char adj_string[128];
|
|
|
|
switch (adj->type) {
|
|
case HELLO_LINK:
|
|
strlcpy(adj_string, "interface: ", sizeof(adj_string));
|
|
strlcat(adj_string, adj->ifname, sizeof(adj_string));
|
|
break;
|
|
case HELLO_TARGETED:
|
|
strlcpy(adj_string, "targetedHello: ", sizeof(adj_string));
|
|
strlcat(adj_string, log_addr(adj->af, &adj->src_addr),
|
|
sizeof(adj_string));
|
|
break;
|
|
}
|
|
|
|
json_object_array_add(adj_list, json_object_new_string(adj_string));
|
|
}
|
|
|
|
static int
|
|
show_nbr_detail_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
struct ldp_stats *stats;
|
|
struct ctl_adj *adj;
|
|
json_object *json_nbr;
|
|
json_object *json_array;
|
|
json_object *json_counter;
|
|
static json_object *json_nbr_sources;
|
|
static json_object *json_v4adjs;
|
|
static json_object *json_v6adjs;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
json_nbr = json_object_new_object();
|
|
json_object_object_add(json, inet_ntoa(nbr->id), json_nbr);
|
|
|
|
json_object_string_add(json_nbr, "peerId", inet_ntoa(nbr->id));
|
|
json_object_string_add(json_nbr, "tcpLocalAddress",
|
|
log_addr(nbr->af, &nbr->laddr));
|
|
json_object_int_add(json_nbr, "tcpLocalPort",
|
|
ntohs(nbr->lport));
|
|
json_object_string_add(json_nbr, "tcpRemoteAddress",
|
|
log_addr(nbr->af, &nbr->raddr));
|
|
json_object_int_add(json_nbr, "tcpRemotePort",
|
|
ntohs(nbr->rport));
|
|
json_object_string_add(json_nbr, "authentication",
|
|
(nbr->auth_method == AUTH_MD5SIG) ? "TCP MD5 Signature" :
|
|
"none");
|
|
json_object_int_add(json_nbr, "sessionHoldtime", nbr->holdtime);
|
|
json_object_int_add(json_nbr, "keepAliveInterval",
|
|
nbr->holdtime / KEEPALIVE_PER_PERIOD);
|
|
json_object_string_add(json_nbr, "state",
|
|
nbr_state_name(nbr->nbr_state));
|
|
json_object_string_add(json_nbr, "upTime",
|
|
log_time(nbr->uptime));
|
|
|
|
/* message_counters */
|
|
stats = &nbr->stats;
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json_nbr, "sentMessages", json_array);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "keepalive",
|
|
stats->kalive_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "address",
|
|
stats->addr_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "addressWithdraw",
|
|
stats->addrwdraw_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "notification",
|
|
stats->notif_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "capability",
|
|
stats->capability_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelMapping",
|
|
stats->labelmap_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelRequest",
|
|
stats->labelreq_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelWithdraw",
|
|
stats->labelwdraw_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelRelease",
|
|
stats->labelrel_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelAbortRequest",
|
|
stats->labelabreq_sent);
|
|
json_object_array_add(json_array, json_counter);
|
|
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json_nbr, "receivedMessages", json_array);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "keepalive",
|
|
stats->kalive_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "address",
|
|
stats->addr_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "addressWithdraw",
|
|
stats->addrwdraw_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "notification",
|
|
stats->notif_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "capability",
|
|
stats->capability_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelMapping",
|
|
stats->labelmap_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelRequest",
|
|
stats->labelreq_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelWithdraw",
|
|
stats->labelwdraw_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelRelease",
|
|
stats->labelrel_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
json_counter = json_object_new_object();
|
|
json_object_int_add(json_counter, "labelAbortRequest",
|
|
stats->labelabreq_rcvd);
|
|
json_object_array_add(json_array, json_counter);
|
|
|
|
/* capabilities */
|
|
show_nbr_capabilities_json(nbr, json_nbr);
|
|
|
|
/* discovery sources */
|
|
json_nbr_sources = json_object_new_object();
|
|
json_object_object_add(json_nbr, "discoverySources",
|
|
json_nbr_sources);
|
|
json_v4adjs = NULL;
|
|
json_v6adjs = NULL;
|
|
break;
|
|
case IMSG_CTL_SHOW_NBR_DISC:
|
|
adj = imsg->data;
|
|
|
|
switch (adj->af) {
|
|
case AF_INET:
|
|
if (!json_v4adjs) {
|
|
json_v4adjs = json_object_new_array();
|
|
json_object_object_add(json_nbr_sources, "ipv4",
|
|
json_v4adjs);
|
|
}
|
|
show_nbr_detail_adj_json(adj, json_v4adjs);
|
|
break;
|
|
case AF_INET6:
|
|
if (!json_v6adjs) {
|
|
json_v6adjs = json_object_new_array();
|
|
json_object_object_add(json_nbr_sources, "ipv6",
|
|
json_v6adjs);
|
|
}
|
|
show_nbr_detail_adj_json(adj, json_v6adjs);
|
|
break;
|
|
default:
|
|
fatalx("show_nbr_detail_msg_json: unknown af");
|
|
}
|
|
break;
|
|
case IMSG_CTL_SHOW_NBR_END:
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
show_nbr_capabilities(struct vty *vty, struct ctl_nbr *nbr)
|
|
{
|
|
vty_out (vty, " Capabilities Sent:\n"
|
|
" - Dynamic Announcement (0x0506)\n"
|
|
" - Typed Wildcard (0x050B)\n"
|
|
" - Unrecognized Notification (0x0603)\n");
|
|
vty_out (vty, " Capabilities Received:\n");
|
|
if (nbr->flags & F_NBR_CAP_DYNAMIC)
|
|
vty_out (vty," - Dynamic Announcement (0x0506)\n");
|
|
if (nbr->flags & F_NBR_CAP_TWCARD)
|
|
vty_out (vty, " - Typed Wildcard (0x050B)\n");
|
|
if (nbr->flags & F_NBR_CAP_UNOTIF)
|
|
vty_out (vty," - Unrecognized Notification (0x0603)\n");
|
|
}
|
|
|
|
static int
|
|
show_nbr_capabilities_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
if (nbr->nbr_state != NBR_STA_OPER)
|
|
break;
|
|
|
|
vty_out (vty, "Peer LDP Identifier: %s:0\n",
|
|
inet_ntoa(nbr->id));
|
|
show_nbr_capabilities(vty, nbr);
|
|
vty_out (vty, "\n");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr)
|
|
{
|
|
json_object *json_array;
|
|
json_object *json_cap;
|
|
|
|
/* sent capabilities */
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json_nbr, "sentCapabilities", json_array);
|
|
|
|
/* Dynamic Announcement (0x0506) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description", "Dynamic Announcement");
|
|
json_object_string_add(json_cap, "tlvType", "0x0506");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
/* Typed Wildcard (0x050B) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description", "Typed Wildcard");
|
|
json_object_string_add(json_cap, "tlvType", "0x050B");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
/* Unrecognized Notification (0x0603) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Unrecognized Notification");
|
|
json_object_string_add(json_cap, "tlvType", "0x0603");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
/* received capabilities */
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json_nbr, "receivedCapabilities", json_array);
|
|
|
|
/* Dynamic Announcement (0x0506) */
|
|
if (nbr->flags & F_NBR_CAP_DYNAMIC) {
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Dynamic Announcement");
|
|
json_object_string_add(json_cap, "tlvType", "0x0506");
|
|
json_object_array_add(json_array, json_cap);
|
|
}
|
|
|
|
/* Typed Wildcard (0x050B) */
|
|
if (nbr->flags & F_NBR_CAP_TWCARD) {
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Typed Wildcard");
|
|
json_object_string_add(json_cap, "tlvType", "0x050B");
|
|
json_object_array_add(json_array, json_cap);
|
|
}
|
|
|
|
/* Unrecognized Notification (0x0603) */
|
|
if (nbr->flags & F_NBR_CAP_UNOTIF) {
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Unrecognized Notification");
|
|
json_object_string_add(json_cap, "tlvType", "0x0603");
|
|
json_object_array_add(json_array, json_cap);
|
|
}
|
|
}
|
|
|
|
static int
|
|
show_nbr_capabilities_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_nbr *nbr;
|
|
json_object *json_nbr;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
nbr = imsg->data;
|
|
|
|
if (nbr->nbr_state != NBR_STA_OPER)
|
|
break;
|
|
|
|
json_nbr = json_object_new_object();
|
|
json_object_object_add(json, inet_ntoa(nbr->id), json_nbr);
|
|
show_nbr_capabilities_json(nbr, json_nbr);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_lib_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
|
|
{
|
|
struct ctl_rt *rt;
|
|
char dstnet[BUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
rt = imsg->data;
|
|
|
|
if (params->lib.remote_label != NO_LABEL &&
|
|
params->lib.remote_label != rt->remote_label)
|
|
return (0);
|
|
/* FALLTHROUGH */
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
rt = imsg->data;
|
|
|
|
if (imsg->hdr.type == IMSG_CTL_SHOW_LIB_BEGIN &&
|
|
!rt->no_downstream)
|
|
break;
|
|
|
|
snprintf(dstnet, sizeof(dstnet), "%s/%d",
|
|
log_addr(rt->af, &rt->prefix), rt->prefixlen);
|
|
|
|
vty_out(vty, "%-4s %-20s", af_name(rt->af), dstnet);
|
|
if (strlen(dstnet) > 20)
|
|
vty_out(vty, "\n%25s", " ");
|
|
vty_out (vty, " %-15s %-11s %-13s %6s\n", inet_ntoa(rt->nexthop),
|
|
log_label(rt->local_label), log_label(rt->remote_label),
|
|
rt->in_use ? "yes" : "no");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_lib_detail_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
|
|
{
|
|
struct ctl_rt *rt = NULL;
|
|
static char dstnet[BUFSIZ];
|
|
static int upstream, downstream;
|
|
size_t buflen;
|
|
static char sent_buffer[LDPBUFSIZ];
|
|
static char rcvd_buffer[LDPBUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
rt = imsg->data;
|
|
|
|
upstream = 0;
|
|
downstream = 0;
|
|
sent_buffer[0] = '\0';
|
|
rcvd_buffer[0] = '\0';
|
|
snprintf(dstnet, sizeof(dstnet), "%s/%d",
|
|
log_addr(rt->af, &rt->prefix), rt->prefixlen);
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_SENT:
|
|
rt = imsg->data;
|
|
|
|
upstream = 1;
|
|
buflen = strlen(sent_buffer);
|
|
snprintf(sent_buffer + buflen, LDPBUFSIZ - buflen,
|
|
"%12s%s:0\n", "", inet_ntoa(rt->nexthop));
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
rt = imsg->data;
|
|
downstream = 1;
|
|
buflen = strlen(rcvd_buffer);
|
|
snprintf(rcvd_buffer + buflen, LDPBUFSIZ - buflen,
|
|
"%12s%s:0, label %s%s\n", "", inet_ntoa(rt->nexthop),
|
|
log_label(rt->remote_label),
|
|
rt->in_use ? " (in use)" : "");
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_END:
|
|
rt = imsg->data;
|
|
|
|
if (params->lib.remote_label != NO_LABEL &&
|
|
!downstream)
|
|
break;
|
|
vty_out(vty, "%s\n", dstnet);
|
|
vty_out(vty, "%-8sLocal binding: label: %s\n", "",
|
|
log_label(rt->local_label));
|
|
if (upstream) {
|
|
vty_out (vty, "%-8sAdvertised to:\n", "");
|
|
vty_out(vty, "%s", sent_buffer);
|
|
}
|
|
if (downstream) {
|
|
vty_out (vty, "%-8sRemote bindings:\n", "");
|
|
vty_out(vty, "%s", rcvd_buffer);
|
|
} else
|
|
vty_out (vty, "%-8sNo remote bindings\n","");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_lib_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_rt *rt;
|
|
json_object *json_array;
|
|
json_object *json_lib_entry;
|
|
char dstnet[BUFSIZ];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
rt = imsg->data;
|
|
|
|
if (imsg->hdr.type == IMSG_CTL_SHOW_LIB_BEGIN &&
|
|
!rt->no_downstream)
|
|
break;
|
|
|
|
json_object_object_get_ex(json, "bindings", &json_array);
|
|
if (!json_array) {
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json, "bindings", json_array);
|
|
}
|
|
|
|
json_lib_entry = json_object_new_object();
|
|
json_object_string_add(json_lib_entry, "addressFamily",
|
|
af_name(rt->af));
|
|
snprintf(dstnet, sizeof(dstnet), "%s/%d",
|
|
log_addr(rt->af, &rt->prefix), rt->prefixlen);
|
|
json_object_string_add(json_lib_entry, "prefix", dstnet);
|
|
json_object_string_add(json_lib_entry, "neighborId",
|
|
inet_ntoa(rt->nexthop));
|
|
json_object_string_add(json_lib_entry, "localLabel",
|
|
log_label(rt->local_label));
|
|
json_object_string_add(json_lib_entry, "remoteLabel",
|
|
log_label(rt->remote_label));
|
|
json_object_int_add(json_lib_entry, "inUse", rt->in_use);
|
|
|
|
json_object_array_add(json_array, json_lib_entry);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_lib_detail_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_rt *rt = NULL;
|
|
char dstnet[BUFSIZ];
|
|
static json_object *json_lib_entry;
|
|
static json_object *json_adv_labels;
|
|
json_object *json_adv_label;
|
|
static json_object *json_remote_labels;
|
|
json_object *json_remote_label;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
rt = imsg->data;
|
|
|
|
snprintf(dstnet, sizeof(dstnet), "%s/%d",
|
|
log_addr(rt->af, &rt->prefix), rt->prefixlen);
|
|
|
|
json_lib_entry = json_object_new_object();
|
|
json_object_string_add(json_lib_entry, "localLabel",
|
|
log_label(rt->local_label));
|
|
|
|
json_adv_labels = json_object_new_array();
|
|
json_object_object_add(json_lib_entry, "advertisedTo",
|
|
json_adv_labels);
|
|
|
|
json_remote_labels = json_object_new_array();
|
|
json_object_object_add(json_lib_entry, "remoteLabels",
|
|
json_remote_labels);
|
|
|
|
json_object_object_add(json, dstnet, json_lib_entry);
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_SENT:
|
|
rt = imsg->data;
|
|
|
|
json_adv_label = json_object_new_object();
|
|
json_object_string_add(json_adv_label, "neighborId",
|
|
inet_ntoa(rt->nexthop));
|
|
json_object_array_add(json_adv_labels, json_adv_label);
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
rt = imsg->data;
|
|
|
|
json_remote_label = json_object_new_object();
|
|
json_object_string_add(json_remote_label, "neighborId",
|
|
inet_ntoa(rt->nexthop));
|
|
json_object_string_add(json_remote_label, "label",
|
|
log_label(rt->remote_label));
|
|
json_object_int_add(json_remote_label, "inUse", rt->in_use);
|
|
json_object_array_add(json_remote_labels, json_remote_label);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params)
|
|
{
|
|
struct ctl_pw *pw;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_BINDING:
|
|
pw = imsg->data;
|
|
|
|
vty_out (vty, " Destination Address: %s, VC ID: %u\n",
|
|
inet_ntoa(pw->lsr_id), pw->pwid);
|
|
|
|
/* local binding */
|
|
if (pw->local_label != NO_LABEL) {
|
|
vty_out (vty, " Local Label: %u\n",
|
|
pw->local_label);
|
|
vty_out (vty, "%-8sCbit: %u, VC Type: %s, "
|
|
"GroupID: %u\n", "", pw->local_cword,
|
|
pw_type_name(pw->type),pw->local_gid);
|
|
vty_out (vty, "%-8sMTU: %u\n", "",pw->local_ifmtu);
|
|
vty_out (vty, "%-8sLast failure: %s\n", "",
|
|
pw_error_code(pw->reason));
|
|
} else
|
|
vty_out (vty," Local Label: unassigned\n");
|
|
|
|
/* remote binding */
|
|
if (pw->remote_label != NO_LABEL) {
|
|
vty_out (vty, " Remote Label: %u\n",
|
|
pw->remote_label);
|
|
vty_out (vty, "%-8sCbit: %u, VC Type: %s, "
|
|
"GroupID: %u\n", "", pw->remote_cword,
|
|
pw_type_name(pw->type),pw->remote_gid);
|
|
vty_out (vty, "%-8sMTU: %u\n", "",pw->remote_ifmtu);
|
|
} else
|
|
vty_out (vty," Remote Label: unassigned\n");
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_l2vpn_binding_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_pw *pw;
|
|
json_object *json_pw;
|
|
char key_name[64];
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_BINDING:
|
|
pw = imsg->data;
|
|
|
|
json_pw = json_object_new_object();
|
|
json_object_string_add(json_pw, "destination",
|
|
inet_ntoa(pw->lsr_id));
|
|
json_object_int_add(json_pw, "vcId", pw->pwid);
|
|
|
|
/* local binding */
|
|
if (pw->local_label != NO_LABEL) {
|
|
json_object_int_add(json_pw, "localLabel",
|
|
pw->local_label);
|
|
json_object_int_add(json_pw, "localControlWord",
|
|
pw->local_cword);
|
|
json_object_string_add(json_pw, "localVcType",
|
|
pw_type_name(pw->type));
|
|
json_object_int_add(json_pw, "localGroupID",
|
|
pw->local_gid);
|
|
json_object_int_add(json_pw, "localIfMtu",
|
|
pw->local_ifmtu);
|
|
json_object_string_add(json_pw, "lastFailureReason",
|
|
pw_error_code(pw->reason));
|
|
} else
|
|
json_object_string_add(json_pw, "localLabel",
|
|
"unassigned");
|
|
|
|
/* remote binding */
|
|
if (pw->remote_label != NO_LABEL) {
|
|
json_object_int_add(json_pw, "remoteLabel",
|
|
pw->remote_label);
|
|
json_object_int_add(json_pw, "remoteControlWord",
|
|
pw->remote_cword);
|
|
json_object_string_add(json_pw, "remoteVcType",
|
|
pw_type_name(pw->type));
|
|
json_object_int_add(json_pw, "remoteGroupID",
|
|
pw->remote_gid);
|
|
json_object_int_add(json_pw, "remoteIfMtu",
|
|
pw->remote_ifmtu);
|
|
} else
|
|
json_object_string_add(json_pw, "remoteLabel",
|
|
"unassigned");
|
|
|
|
snprintf(key_name, sizeof(key_name), "%s: %u",
|
|
inet_ntoa(pw->lsr_id), pw->pwid);
|
|
json_object_object_add(json, key_name, json_pw);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_l2vpn_pw_msg(struct vty *vty, struct imsg *imsg, struct show_params *params)
|
|
{
|
|
struct ctl_pw *pw;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_PW:
|
|
pw = imsg->data;
|
|
|
|
vty_out (vty, "%-9s %-15s %-10u %-16s %-10s\n", pw->ifname,
|
|
inet_ntoa(pw->lsr_id), pw->pwid, pw->l2vpn_name,
|
|
(pw->status == PW_FORWARDING ? "UP" : "DOWN"));
|
|
break;
|
|
case IMSG_CTL_END:
|
|
vty_out (vty, "\n");
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
show_l2vpn_pw_msg_json(struct imsg *imsg, struct show_params *params,
|
|
json_object *json)
|
|
{
|
|
struct ctl_pw *pw;
|
|
json_object *json_pw;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_PW:
|
|
pw = imsg->data;
|
|
|
|
json_pw = json_object_new_object();
|
|
json_object_string_add(json_pw, "peerId", inet_ntoa(pw->lsr_id));
|
|
json_object_int_add(json_pw, "vcId", pw->pwid);
|
|
json_object_string_add(json_pw, "VpnName", pw->l2vpn_name);
|
|
if (pw->status == PW_FORWARDING)
|
|
json_object_string_add(json_pw, "status", "up");
|
|
else
|
|
json_object_string_add(json_pw, "status", "down");
|
|
json_object_object_add(json, pw->ifname, json_pw);
|
|
break;
|
|
case IMSG_CTL_END:
|
|
return (1);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_connect(struct imsgbuf *ibuf)
|
|
{
|
|
struct sockaddr_un s_un;
|
|
int ctl_sock;
|
|
|
|
/* connect to ldpd control socket */
|
|
if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
|
|
log_warn("%s: socket", __func__);
|
|
return (-1);
|
|
}
|
|
|
|
memset(&s_un, 0, sizeof(s_un));
|
|
s_un.sun_family = AF_UNIX;
|
|
strlcpy(s_un.sun_path, ctl_sock_path, sizeof(s_un.sun_path));
|
|
if (connect(ctl_sock, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) {
|
|
log_warn("%s: connect: %s", __func__, ctl_sock_path);
|
|
close(ctl_sock);
|
|
return (-1);
|
|
}
|
|
|
|
imsg_init(ibuf, ctl_sock);
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_iface(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
int ret;
|
|
|
|
if (params->json)
|
|
ret = show_interface_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_interface_msg(vty, imsg, params);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_disc(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
int ret;
|
|
|
|
if (params->detail) {
|
|
if (params->json)
|
|
ret = show_discovery_detail_msg_json(imsg, params,
|
|
json);
|
|
else
|
|
ret = show_discovery_detail_msg(vty, imsg, params);
|
|
} else {
|
|
if (params->json)
|
|
ret = show_discovery_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_discovery_msg(vty, imsg, params);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_nbr(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
static bool filtered = false;
|
|
struct ctl_nbr *nbr;
|
|
int ret;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_NBR:
|
|
filtered = false;
|
|
nbr = imsg->data;
|
|
|
|
if (params->neighbor.lsr_id.s_addr != INADDR_ANY &&
|
|
params->neighbor.lsr_id.s_addr != nbr->id.s_addr) {
|
|
filtered = true;
|
|
return (0);
|
|
}
|
|
break;
|
|
case IMSG_CTL_SHOW_NBR_DISC:
|
|
case IMSG_CTL_SHOW_NBR_END:
|
|
if (filtered)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (params->neighbor.capabilities) {
|
|
if (params->json)
|
|
ret = show_nbr_capabilities_msg_json(imsg, params,
|
|
json);
|
|
else
|
|
ret = show_nbr_capabilities_msg(vty, imsg, params);
|
|
} else if (params->detail) {
|
|
if (params->json)
|
|
ret = show_nbr_detail_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_nbr_detail_msg(vty, imsg, params);
|
|
} else {
|
|
if (params->json)
|
|
ret = show_nbr_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_nbr_msg(vty, imsg, params);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_lib(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
static bool filtered = false;
|
|
struct ctl_rt *rt = NULL;
|
|
struct prefix prefix;
|
|
int ret;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
filtered = false;
|
|
break;
|
|
case IMSG_CTL_SHOW_LIB_SENT:
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
case IMSG_CTL_SHOW_LIB_END:
|
|
if (filtered)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_BEGIN:
|
|
case IMSG_CTL_SHOW_LIB_SENT:
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
case IMSG_CTL_SHOW_LIB_END:
|
|
rt = imsg->data;
|
|
|
|
if (params->family != AF_UNSPEC && params->family != rt->af) {
|
|
filtered = true;
|
|
return (0);
|
|
}
|
|
|
|
prefix.family = rt->af;
|
|
prefix.prefixlen = rt->prefixlen;
|
|
memcpy(&prefix.u.val, &rt->prefix, sizeof(prefix.u.val));
|
|
if (params->lib.prefix.family != AF_UNSPEC) {
|
|
if (!params->lib.longer_prefixes &&
|
|
!prefix_same(¶ms->lib.prefix, &prefix)) {
|
|
filtered = true;
|
|
return (0);
|
|
} else if (params->lib.longer_prefixes &&
|
|
!prefix_match(¶ms->lib.prefix, &prefix)) {
|
|
filtered = true;
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
if (params->lib.local_label != NO_LABEL &&
|
|
params->lib.local_label != rt->local_label) {
|
|
filtered = true;
|
|
return (0);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_SENT:
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
if (params->lib.neighbor.s_addr != INADDR_ANY &&
|
|
params->lib.neighbor.s_addr != rt->nexthop.s_addr)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_LIB_RCVD:
|
|
if (params->lib.remote_label != NO_LABEL &&
|
|
params->lib.remote_label != rt->remote_label)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (params->detail) {
|
|
if (params->json)
|
|
ret = show_lib_detail_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_lib_detail_msg(vty, imsg, params);
|
|
} else {
|
|
if (params->json)
|
|
ret = show_lib_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_lib_msg(vty, imsg, params);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_l2vpn_pw(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
struct ctl_pw *pw;
|
|
int ret;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_PW:
|
|
pw = imsg->data;
|
|
if (params->l2vpn.peer.s_addr != INADDR_ANY &&
|
|
params->l2vpn.peer.s_addr != pw->lsr_id.s_addr)
|
|
return (0);
|
|
if (params->l2vpn.ifname[0] != '\0' &&
|
|
strcmp(params->l2vpn.ifname, pw->ifname))
|
|
return (0);
|
|
if (params->l2vpn.vcid && params->l2vpn.vcid != pw->pwid)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (params->json)
|
|
ret = show_l2vpn_pw_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_l2vpn_pw_msg(vty, imsg, params);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_l2vpn_binding(struct vty *vty, struct imsg *imsg,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
struct ctl_pw *pw;
|
|
int ret;
|
|
|
|
switch (imsg->hdr.type) {
|
|
case IMSG_CTL_SHOW_L2VPN_BINDING:
|
|
pw = imsg->data;
|
|
if (params->l2vpn.peer.s_addr != INADDR_ANY &&
|
|
params->l2vpn.peer.s_addr != pw->lsr_id.s_addr)
|
|
return (0);
|
|
if (params->l2vpn.local_label != NO_LABEL &&
|
|
params->l2vpn.local_label != pw->local_label)
|
|
return (0);
|
|
if (params->l2vpn.remote_label != NO_LABEL &&
|
|
params->l2vpn.remote_label != pw->remote_label)
|
|
return (0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (params->json)
|
|
ret = show_l2vpn_binding_msg_json(imsg, params, json);
|
|
else
|
|
ret = show_l2vpn_binding_msg(vty, imsg, params);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch_msg(struct vty *vty, struct imsg *imsg, enum show_command cmd,
|
|
struct show_params *params, json_object *json)
|
|
{
|
|
switch (cmd) {
|
|
case SHOW_IFACE:
|
|
return (ldp_vty_dispatch_iface(vty, imsg, params, json));
|
|
case SHOW_DISC:
|
|
return (ldp_vty_dispatch_disc(vty, imsg, params, json));
|
|
case SHOW_NBR:
|
|
return (ldp_vty_dispatch_nbr(vty, imsg, params, json));
|
|
case SHOW_LIB:
|
|
return (ldp_vty_dispatch_lib(vty, imsg, params, json));
|
|
case SHOW_L2VPN_PW:
|
|
return (ldp_vty_dispatch_l2vpn_pw(vty, imsg, params, json));
|
|
case SHOW_L2VPN_BINDING:
|
|
return (ldp_vty_dispatch_l2vpn_binding(vty, imsg, params,
|
|
json));
|
|
default:
|
|
return (0);
|
|
}
|
|
}
|
|
|
|
static int
|
|
ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd,
|
|
struct show_params *params)
|
|
{
|
|
struct imsg imsg;
|
|
int n, done = 0, ret = CMD_SUCCESS;
|
|
json_object *json = NULL;
|
|
|
|
while (ibuf->w.queued)
|
|
if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) {
|
|
log_warn("write error");
|
|
close(ibuf->fd);
|
|
return (CMD_WARNING);
|
|
}
|
|
|
|
if (params->json)
|
|
json = json_object_new_object();
|
|
|
|
while (!done) {
|
|
if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) {
|
|
log_warnx("imsg_read error");
|
|
ret = CMD_WARNING;
|
|
goto done;
|
|
}
|
|
if (n == 0) {
|
|
log_warnx("pipe closed");
|
|
ret = CMD_WARNING;
|
|
goto done;
|
|
}
|
|
|
|
while (!done) {
|
|
if ((n = imsg_get(ibuf, &imsg)) == -1) {
|
|
log_warnx("imsg_get error");
|
|
ret = CMD_WARNING;
|
|
goto done;
|
|
}
|
|
if (n == 0)
|
|
break;
|
|
done = ldp_vty_dispatch_msg(vty, &imsg, cmd, params,
|
|
json);
|
|
imsg_free(&imsg);
|
|
}
|
|
}
|
|
|
|
done:
|
|
close(ibuf->fd);
|
|
if (json) {
|
|
vty_out (vty, "%s\n",
|
|
json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
ldp_vty_get_af(const char *str, int *af)
|
|
{
|
|
if (str == NULL) {
|
|
*af = AF_UNSPEC;
|
|
return (0);
|
|
} else if (strcmp(str, "ipv4") == 0) {
|
|
*af = AF_INET;
|
|
return (0);
|
|
} else if (strcmp(str, "ipv6") == 0) {
|
|
*af = AF_INET6;
|
|
return (0);
|
|
}
|
|
|
|
return (-1);
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_binding(struct vty *vty, const char *af_str, const char *prefix,
|
|
int longer_prefixes, const char *neighbor, unsigned long local_label,
|
|
unsigned long remote_label, const char *detail, const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
int af;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
if (ldp_vty_get_af(af_str, &af) < 0)
|
|
return (CMD_ERR_NO_MATCH);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.family = af;
|
|
params.detail = (detail) ? 1 : 0;
|
|
params.json = (json) ? 1 : 0;
|
|
if (prefix) {
|
|
(void)str2prefix(prefix, ¶ms.lib.prefix);
|
|
params.lib.longer_prefixes = longer_prefixes;
|
|
}
|
|
if (neighbor &&
|
|
(inet_pton(AF_INET, neighbor, ¶ms.lib.neighbor) != 1 ||
|
|
bad_addr_v4(params.lib.neighbor))) {
|
|
vty_out (vty, "%% Malformed address\n");
|
|
return (CMD_SUCCESS);
|
|
}
|
|
params.lib.local_label = local_label;
|
|
params.lib.remote_label = remote_label;
|
|
|
|
if (!params.detail && !params.json)
|
|
vty_out (vty, "%-4s %-20s %-15s %-11s %-13s %6s\n", "AF",
|
|
"Destination", "Nexthop", "Local Label", "Remote Label",
|
|
"In Use");
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_LIB, 0, 0, -1, NULL, 0);
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_LIB, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_discovery(struct vty *vty, const char *af_str, const char *detail,
|
|
const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
int af;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
if (ldp_vty_get_af(af_str, &af) < 0)
|
|
return (CMD_ERR_NO_MATCH);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.family = af;
|
|
params.detail = (detail) ? 1 : 0;
|
|
params.json = (json) ? 1 : 0;
|
|
|
|
if (!params.detail && !params.json)
|
|
vty_out (vty, "%-4s %-15s %-8s %-15s %9s\n",
|
|
"AF", "ID", "Type", "Source", "Holdtime");
|
|
|
|
if (params.detail)
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY_DTL, 0, 0, -1,
|
|
NULL, 0);
|
|
else
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_DISCOVERY, 0, 0, -1, NULL, 0);
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_DISC, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_interface(struct vty *vty, const char *af_str, const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
unsigned int ifidx = 0;
|
|
int af;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
if (ldp_vty_get_af(af_str, &af) < 0)
|
|
return (CMD_ERR_NO_MATCH);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.family = af;
|
|
params.json = (json) ? 1 : 0;
|
|
|
|
/* header */
|
|
if (!params.json) {
|
|
vty_out (vty, "%-4s %-11s %-6s %-8s %-12s %3s\n", "AF",
|
|
"Interface", "State", "Uptime", "Hello Timers","ac");
|
|
}
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, &ifidx,
|
|
sizeof(ifidx));
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_IFACE, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_capabilities(struct vty *vty, const char *json)
|
|
{
|
|
if (json) {
|
|
json_object *json;
|
|
json_object *json_array;
|
|
json_object *json_cap;
|
|
|
|
json = json_object_new_object();
|
|
json_array = json_object_new_array();
|
|
json_object_object_add(json, "capabilities", json_array);
|
|
|
|
/* Dynamic Announcement (0x0506) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Dynamic Announcement");
|
|
json_object_string_add(json_cap, "tlvType",
|
|
"0x0506");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
/* Typed Wildcard (0x050B) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Typed Wildcard");
|
|
json_object_string_add(json_cap, "tlvType",
|
|
"0x050B");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
/* Unrecognized Notification (0x0603) */
|
|
json_cap = json_object_new_object();
|
|
json_object_string_add(json_cap, "description",
|
|
"Unrecognized Notification");
|
|
json_object_string_add(json_cap, "tlvType",
|
|
"0x0603");
|
|
json_object_array_add(json_array, json_cap);
|
|
|
|
vty_out (vty, "%s\n",
|
|
json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
|
|
json_object_free(json);
|
|
return (0);
|
|
}
|
|
|
|
vty_out (vty,
|
|
"Supported LDP Capabilities\n"
|
|
" * Dynamic Announcement (0x0506)\n"
|
|
" * Typed Wildcard (0x050B)\n"
|
|
" * Unrecognized Notification (0x0603)\n\n");
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_neighbor(struct vty *vty, const char *lsr_id, int capabilities,
|
|
const char *detail, const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.detail = (detail) ? 1 : 0;
|
|
params.json = (json) ? 1 : 0;
|
|
params.neighbor.capabilities = capabilities;
|
|
if (lsr_id &&
|
|
(inet_pton(AF_INET, lsr_id, ¶ms.neighbor.lsr_id) != 1 ||
|
|
bad_addr_v4(params.neighbor.lsr_id))) {
|
|
vty_out (vty, "%% Malformed address\n");
|
|
return (CMD_SUCCESS);
|
|
}
|
|
|
|
if (params.neighbor.capabilities)
|
|
params.detail = 1;
|
|
|
|
if (!params.detail && !params.json)
|
|
vty_out (vty, "%-4s %-15s %-11s %-15s %8s\n",
|
|
"AF", "ID", "State", "Remote Address","Uptime");
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0);
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_NBR, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_atom_binding(struct vty *vty, const char *peer,
|
|
unsigned long local_label, unsigned long remote_label, const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.json = (json) ? 1 : 0;
|
|
if (peer &&
|
|
(inet_pton(AF_INET, peer, ¶ms.l2vpn.peer) != 1 ||
|
|
bad_addr_v4(params.l2vpn.peer))) {
|
|
vty_out (vty, "%% Malformed address\n");
|
|
return (CMD_SUCCESS);
|
|
}
|
|
params.l2vpn.local_label = local_label;
|
|
params.l2vpn.remote_label = remote_label;
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_BINDING, 0, 0, -1, NULL, 0);
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_BINDING, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_show_atom_vc(struct vty *vty, const char *peer, const char *ifname,
|
|
const char *vcid, const char *json)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct show_params params;
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
memset(¶ms, 0, sizeof(params));
|
|
params.json = (json) ? 1 : 0;
|
|
if (peer &&
|
|
(inet_pton(AF_INET, peer, ¶ms.l2vpn.peer) != 1 ||
|
|
bad_addr_v4(params.l2vpn.peer))) {
|
|
vty_out (vty, "%% Malformed address\n");
|
|
return (CMD_SUCCESS);
|
|
}
|
|
if (ifname)
|
|
strlcpy(params.l2vpn.ifname, ifname,
|
|
sizeof(params.l2vpn.ifname));
|
|
if (vcid)
|
|
params.l2vpn.vcid = atoi(vcid);
|
|
|
|
if (!params.json) {
|
|
/* header */
|
|
vty_out (vty, "%-9s %-15s %-10s %-16s %-10s\n",
|
|
"Interface", "Peer ID", "VC ID", "Name","Status");
|
|
vty_out (vty, "%-9s %-15s %-10s %-16s %-10s\n",
|
|
"---------", "---------------", "----------",
|
|
"----------------", "----------");
|
|
}
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_SHOW_L2VPN_PW, 0, 0, -1, NULL, 0);
|
|
return (ldp_vty_dispatch(vty, &ibuf, SHOW_L2VPN_PW, ¶ms));
|
|
}
|
|
|
|
int
|
|
ldp_vty_clear_nbr(struct vty *vty, const char *addr_str)
|
|
{
|
|
struct imsgbuf ibuf;
|
|
struct ctl_nbr nbr;
|
|
|
|
memset(&nbr, 0, sizeof(nbr));
|
|
if (addr_str &&
|
|
(ldp_get_address(addr_str, &nbr.af, &nbr.raddr) == -1 ||
|
|
bad_addr(nbr.af, &nbr.raddr))) {
|
|
vty_out (vty, "%% Malformed address\n");
|
|
return (CMD_WARNING);
|
|
}
|
|
|
|
if (ldp_vty_connect(&ibuf) < 0)
|
|
return (CMD_WARNING);
|
|
|
|
imsg_compose(&ibuf, IMSG_CTL_CLEAR_NBR, 0, 0, -1, &nbr, sizeof(nbr));
|
|
|
|
while (ibuf.w.queued)
|
|
if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN) {
|
|
log_warn("write error");
|
|
close(ibuf.fd);
|
|
return (CMD_WARNING);
|
|
}
|
|
|
|
close(ibuf.fd);
|
|
|
|
return (CMD_SUCCESS);
|
|
}
|