diff options
Diffstat (limited to 'ldpd/ldp_vty_exec.c')
-rw-r--r-- | ldpd/ldp_vty_exec.c | 2145 |
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(¶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)); + 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(¶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_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(¶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_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(¶ms, 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, ¶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); +} |