summaryrefslogtreecommitdiffstats
path: root/ldpd/ldp_vty_exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldpd/ldp_vty_exec.c')
-rw-r--r--ldpd/ldp_vty_exec.c2145
1 files changed, 2145 insertions, 0 deletions
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
new file mode 100644
index 0000000..906b5c1
--- /dev/null
+++ b/ldpd/ldp_vty_exec.c
@@ -0,0 +1,2145 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2016 by Open Source Routing.
+ */
+
+#include <zebra.h>
+#include <sys/un.h>
+#include "lib/printfrr.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,
+ SHOW_LDP_SYNC
+};
+
+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_ldp_sync_msg(struct vty *, struct imsg *,
+ struct show_params *);
+static int show_ldp_sync_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_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_ldp_sync_msg(struct vty *vty, struct imsg *imsg,
+ struct show_params *params)
+{
+ struct ctl_ldp_sync *iface;
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_LDP_SYNC:
+ iface = imsg->data;
+
+ vty_out (vty, "%s:\n", iface->name);
+ if (iface->in_sync)
+ vty_out (vty, " Status: initial label exchange complete\n");
+ else
+ vty_out (vty, " Status: label exchange not complete\n");
+
+ if (iface->timer_running) {
+ vty_out (vty, " Wait time: %d seconds (%d seconds left)\n",
+ iface->wait_time, iface->wait_time_remaining);
+ vty_out (vty, " Timer is running\n");
+ } else {
+ vty_out (vty, " Wait time: %d seconds\n",
+ iface->wait_time);
+ vty_out (vty, " Timer is not running\n");
+ }
+
+ if (iface->peer_ldp_id.s_addr)
+ vty_out (vty, " Peer LDP Identifier: %pI4:0\n",
+ &iface->peer_ldp_id);
+
+ break;
+ case IMSG_CTL_END:
+ return (1);
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static int
+show_ldp_sync_msg_json(struct imsg *imsg, struct show_params *params,
+ json_object *json)
+{
+ struct ctl_ldp_sync *iface;
+ json_object *json_iface;
+ char buf[PREFIX_STRLEN];
+
+ switch (imsg->hdr.type) {
+ case IMSG_CTL_SHOW_LDP_SYNC:
+ iface = imsg->data;
+
+ json_iface = json_object_new_object();
+ json_object_string_add(json_iface, "state",
+ iface->in_sync
+ ? "labelExchangeComplete"
+ : "labelExchangeNotComplete");
+ json_object_int_add(json_iface, "waitTime",
+ iface->wait_time);
+ json_object_int_add(json_iface, "waitTimeRemaining",
+ iface->wait_time_remaining);
+
+ if (iface->timer_running)
+ json_object_boolean_true_add(json_iface, "timerRunning");
+ else
+ json_object_boolean_false_add(json_iface, "timerRunning");
+
+ json_object_string_add(json_iface, "peerLdpId",
+ iface->peer_ldp_id.s_addr ?
+ inet_ntop(AF_INET, &iface->peer_ldp_id, buf, sizeof(buf)) :
+ "");
+
+ json_object_object_add(json, iface->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 %-15pI4 ", af_name(adj->af), &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);
+
+ snprintfrr(buffer + buflen, LDPBUFSIZ - buflen,
+ " LSR Id: %pI4:0\n", &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: %pI4:0\n",&rtr_id);
+ if (CHECK_FLAG(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 (CHECK_FLAG(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_addf(json_adj, "neighborId", "%pI4",
+ &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_addf(json_adj, "lsrId", "%pI4", &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_addf(json, "lsrId", "%pI4", &rtr_id);
+ if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED))
+ json_object_string_add(json, "transportAddressIPv4",
+ log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr));
+ if (CHECK_FLAG(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 %-15pI4 %-11s %-15s",
+ af_name(nbr->af), &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: %pI4:0\n",
+ &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_addf(json_nbr, "neighborId", "%pI4",
+ &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;
+ char buf[PREFIX_STRLEN];
+ 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_ntop(AF_INET, &nbr->id, buf,
+ sizeof(buf)), json_nbr);
+ json_object_string_addf(json_nbr, "peerId", "%pI4", &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 (CHECK_FLAG(nbr->flags, F_NBR_CAP_DYNAMIC))
+ vty_out (vty," - Dynamic Announcement (0x0506)\n");
+ if (CHECK_FLAG(nbr->flags, F_NBR_CAP_TWCARD))
+ vty_out (vty, " - Typed Wildcard (0x050B)\n");
+ if (CHECK_FLAG(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: %pI4:0\n",
+ &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 (CHECK_FLAG(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 (CHECK_FLAG(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 (CHECK_FLAG(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;
+ char buf[PREFIX_STRLEN];
+ 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_ntop(AF_INET, &nbr->id, buf,
+ sizeof(buf)), 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, " %-15pI4 %-11s %-13s %6s\n",
+ &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);
+ snprintfrr(sent_buffer + buflen, LDPBUFSIZ - buflen,
+ "%12s%pI4:0\n", "", &rt->nexthop);
+ break;
+ case IMSG_CTL_SHOW_LIB_RCVD:
+ rt = imsg->data;
+ downstream = 1;
+ buflen = strlen(rcvd_buffer);
+ snprintfrr(rcvd_buffer + buflen, LDPBUFSIZ - buflen,
+ "%12s%pI4:0, label %s%s\n", "", &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_addf(json_lib_entry, "neighborId", "%pI4",
+ &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_addf(json_adv_label, "neighborId", "%pI4",
+ &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_addf(json_remote_label, "neighborId", "%pI4",
+ &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: %pI4, VC ID: %u\n",
+ &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_addf(json_pw, "destination", "%pI4",
+ &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");
+
+ snprintfrr(key_name, sizeof(key_name), "%pI4: %u",
+ &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 %-15pI4 %-10u %-16s %-10s\n", pw->ifname,
+ &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_addf(json_pw, "peerId", "%pI4", &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_ldp_sync(struct vty *vty, struct imsg *imsg,
+ struct show_params *params, json_object *json)
+{
+ int ret;
+
+ if (params->json)
+ ret = show_ldp_sync_msg_json(imsg, params, json);
+ else
+ ret = show_ldp_sync_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(&params->lib.prefix, &prefix)) {
+ filtered = true;
+ return (0);
+ } else if (params->lib.longer_prefixes &&
+ !prefix_match(&params->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));
+ case SHOW_LDP_SYNC:
+ return (ldp_vty_dispatch_ldp_sync(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_json(vty, 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(&params, 0, sizeof(params));
+ params.family = af;
+ params.detail = (detail) ? 1 : 0;
+ params.json = (json) ? 1 : 0;
+ if (prefix) {
+ (void)str2prefix(prefix, &params.lib.prefix);
+ params.lib.longer_prefixes = longer_prefixes;
+ }
+ if (neighbor &&
+ (inet_pton(AF_INET, neighbor, &params.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, &params));
+}
+
+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(&params, 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, &params));
+}
+
+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(&params, 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, &params));
+}
+
+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_json(vty, 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(&params, 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, &params.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, &params));
+}
+
+int
+ldp_vty_show_ldp_sync(struct vty *vty, const char *json)
+{
+ struct imsgbuf ibuf;
+ struct show_params params;
+
+ if (ldp_vty_connect(&ibuf) < 0)
+ return (CMD_WARNING);
+
+ memset(&params, 0, sizeof(params));
+ params.json = (json) ? 1 : 0;
+
+ imsg_compose(&ibuf, IMSG_CTL_SHOW_LDP_SYNC, 0, 0, -1, NULL, 0);
+ return (ldp_vty_dispatch(vty, &ibuf, SHOW_LDP_SYNC, &params));
+}
+
+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(&params, 0, sizeof(params));
+ params.json = (json) ? 1 : 0;
+ if (peer &&
+ (inet_pton(AF_INET, peer, &params.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, &params));
+}
+
+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(&params, 0, sizeof(params));
+ params.json = (json) ? 1 : 0;
+ if (peer &&
+ (inet_pton(AF_INET, peer, &params.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, &params));
+}
+
+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);
+}