Blame src/client/show.c

Packit e9ba0d
/* -*- mode: c; c-file-style: "openbsd" -*- */
Packit e9ba0d
/*
Packit e9ba0d
 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
Packit e9ba0d
 *
Packit e9ba0d
 * Permission to use, copy, modify, and/or distribute this software for any
Packit e9ba0d
 * purpose with or without fee is hereby granted, provided that the above
Packit e9ba0d
 * copyright notice and this permission notice appear in all copies.
Packit e9ba0d
 *
Packit e9ba0d
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Packit e9ba0d
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Packit e9ba0d
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Packit e9ba0d
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Packit e9ba0d
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Packit e9ba0d
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Packit e9ba0d
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Packit e9ba0d
 */
Packit e9ba0d
Packit e9ba0d
#include "client.h"
Packit e9ba0d
#include <string.h>
Packit e9ba0d
#include <limits.h>
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Show neighbors.
Packit e9ba0d
 *
Packit e9ba0d
 * The environment will contain the following keys:
Packit e9ba0d
 *  - C{ports} list of ports we want to restrict showing.
Packit e9ba0d
 *  - C{hidden} if we should show hidden ports.
Packit e9ba0d
 *  - C{summary} if we want to show only a summary
Packit e9ba0d
 *  - C{detailed} for a detailed overview
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_show_neighbors(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	log_debug("lldpctl", "show neighbors data (%s) %s hidden neighbors",
Packit e9ba0d
	    cmdenv_get(env, "summary")?"summary":
Packit e9ba0d
	    cmdenv_get(env, "detailed")?"detailed":
Packit e9ba0d
	    "normal", cmdenv_get(env, "hidden")?"with":"without");
Packit e9ba0d
	if (cmdenv_get(env, "ports"))
Packit e9ba0d
		log_debug("lldpctl", "restrict to the following ports: %s",
Packit e9ba0d
		    cmdenv_get(env, "ports"));
Packit e9ba0d
Packit e9ba0d
	display_interfaces(conn, w, env, !!cmdenv_get(env, "hidden"),
Packit e9ba0d
	    cmdenv_get(env, "summary")?DISPLAY_BRIEF:
Packit e9ba0d
	    cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
Packit e9ba0d
	    DISPLAY_NORMAL);
Packit e9ba0d
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Show interfaces.
Packit e9ba0d
 *
Packit e9ba0d
 * The environment will contain the following keys:
Packit e9ba0d
 *  - C{ports} list of ports we want to restrict showing.
Packit e9ba0d
 *  - C{hidden} if we should show hidden ports.
Packit e9ba0d
 *  - C{summary} if we want to show only a summary
Packit e9ba0d
 *  - C{detailed} for a detailed overview
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_show_interfaces(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	log_debug("lldpctl", "show interfaces data (%s) %s hidden interfaces",
Packit e9ba0d
	    cmdenv_get(env, "summary")?"summary":
Packit e9ba0d
	    cmdenv_get(env, "detailed")?"detailed":
Packit e9ba0d
	    "normal", cmdenv_get(env, "hidden")?"with":"without");
Packit e9ba0d
	if (cmdenv_get(env, "ports"))
Packit e9ba0d
		log_debug("lldpctl", "restrict to the following ports: %s",
Packit e9ba0d
		    cmdenv_get(env, "ports"));
Packit e9ba0d
Packit e9ba0d
	display_local_interfaces(conn, w, env, !!cmdenv_get(env, "hidden"),
Packit e9ba0d
	    cmdenv_get(env, "summary")?DISPLAY_BRIEF:
Packit e9ba0d
	    cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
Packit e9ba0d
	    DISPLAY_NORMAL);
Packit e9ba0d
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Show chassis.
Packit e9ba0d
 *
Packit e9ba0d
 * The environment will contain the following keys:
Packit e9ba0d
 *  - C{summary} if we want to show only a summary
Packit e9ba0d
 *  - C{detailed} for a detailed overview
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_show_chassis(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	log_debug("lldpctl", "show chassis data (%s)",
Packit e9ba0d
	    cmdenv_get(env, "summary")?"summary":
Packit e9ba0d
	    cmdenv_get(env, "detailed")?"detailed":
Packit e9ba0d
	    "normal");
Packit e9ba0d
Packit e9ba0d
	display_local_chassis(conn, w, env,
Packit e9ba0d
	    cmdenv_get(env, "summary")?DISPLAY_BRIEF:
Packit e9ba0d
	    cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
Packit e9ba0d
	    DISPLAY_NORMAL);
Packit e9ba0d
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Show stats.
Packit e9ba0d
 *
Packit e9ba0d
 * The environment will contain the following keys:
Packit e9ba0d
 *  - C{ports} list of ports we want to restrict showing.
Packit e9ba0d
 *  - C{summary} summary of stats
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_show_interface_stats(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	log_debug("lldpctl", "show stats data");
Packit e9ba0d
	if (cmdenv_get(env, "ports"))
Packit e9ba0d
		log_debug("lldpctl", "restrict to the following ports: %s",
Packit e9ba0d
		    cmdenv_get(env, "ports"));
Packit e9ba0d
	if (cmdenv_get(env, "summary"))
Packit e9ba0d
		log_debug("lldpctl", "show summary of stats across ports");
Packit e9ba0d
Packit e9ba0d
	display_interfaces_stats(conn, w, env);
Packit e9ba0d
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
static int
Packit e9ba0d
cmd_check_no_detailed_nor_summary(struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	if (cmdenv_get(env, "detailed")) return 0;
Packit e9ba0d
	if (cmdenv_get(env, "summary")) return 0;
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Show running configuration.
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_show_configuration(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	log_debug("lldpctl", "show running configuration");
Packit e9ba0d
	display_configuration(conn, w);
Packit e9ba0d
	return 1;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
struct watcharg {
Packit e9ba0d
	struct cmd_env *env;
Packit e9ba0d
	struct writer *w;
Packit e9ba0d
	size_t nb;
Packit e9ba0d
};
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Callback for the next function to display a new neighbor.
Packit e9ba0d
 */
Packit e9ba0d
static void
Packit e9ba0d
watchcb(lldpctl_conn_t *conn,
Packit e9ba0d
    lldpctl_change_t type,
Packit e9ba0d
    lldpctl_atom_t *interface,
Packit e9ba0d
    lldpctl_atom_t *neighbor,
Packit e9ba0d
    void *data)
Packit e9ba0d
{
Packit e9ba0d
	struct watcharg *wa = data;
Packit e9ba0d
	struct cmd_env *env = wa->env;
Packit e9ba0d
	struct writer *w = wa->w;
Packit e9ba0d
	const char *interfaces = cmdenv_get(env, "ports");
Packit e9ba0d
	const char *proto_str;
Packit e9ba0d
	int protocol = LLDPD_MODE_MAX;
Packit e9ba0d
Packit e9ba0d
	if (interfaces && !contains(interfaces, lldpctl_atom_get_str(interface,
Packit e9ba0d
		    lldpctl_k_interface_name)))
Packit e9ba0d
		return;
Packit e9ba0d
Packit e9ba0d
	/* user might have specified protocol to filter display results */
Packit e9ba0d
	proto_str = cmdenv_get(env, "protocol");
Packit e9ba0d
Packit e9ba0d
	if (proto_str) {
Packit e9ba0d
		log_debug("display", "filter protocol: %s ", proto_str);
Packit e9ba0d
Packit e9ba0d
		protocol = 0;	/* unsupported */
Packit e9ba0d
		for (lldpctl_map_t *protocol_map =
Packit e9ba0d
			 lldpctl_key_get_map(lldpctl_k_port_protocol);
Packit e9ba0d
		     protocol_map->string;
Packit e9ba0d
		     protocol_map++) {
Packit e9ba0d
			if (!strcasecmp(proto_str, protocol_map->string)) {
Packit e9ba0d
				protocol = protocol_map->value;
Packit e9ba0d
				break;
Packit e9ba0d
			}
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	switch (type) {
Packit e9ba0d
	case lldpctl_c_deleted:
Packit e9ba0d
		tag_start(w, "lldp-deleted", "LLDP neighbor deleted");
Packit e9ba0d
		break;
Packit e9ba0d
	case lldpctl_c_updated:
Packit e9ba0d
		tag_start(w, "lldp-updated", "LLDP neighbor updated");
Packit e9ba0d
		break;
Packit e9ba0d
	case lldpctl_c_added:
Packit e9ba0d
		tag_start(w, "lldp-added", "LLDP neighbor added");
Packit e9ba0d
		break;
Packit e9ba0d
	default: return;
Packit e9ba0d
	}
Packit e9ba0d
	display_interface(conn, w, 1, interface, neighbor,
Packit e9ba0d
	    cmdenv_get(env, "summary")?DISPLAY_BRIEF:
Packit e9ba0d
	    cmdenv_get(env, "detailed")?DISPLAY_DETAILS:
Packit e9ba0d
	    DISPLAY_NORMAL, protocol);
Packit e9ba0d
	tag_end(w);
Packit e9ba0d
	wa->nb++;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Watch for neighbor changes.
Packit e9ba0d
 */
Packit e9ba0d
static int
Packit e9ba0d
cmd_watch_neighbors(struct lldpctl_conn_t *conn, struct writer *w,
Packit e9ba0d
    struct cmd_env *env, void *arg)
Packit e9ba0d
{
Packit e9ba0d
	struct watcharg wa = {
Packit e9ba0d
		.env = env,
Packit e9ba0d
		.w = w,
Packit e9ba0d
		.nb = 0
Packit e9ba0d
	};
Packit e9ba0d
	const char *limit_str = cmdenv_get(env, "limit");
Packit e9ba0d
	size_t limit = 0;
Packit e9ba0d
Packit e9ba0d
	if (limit_str) {
Packit e9ba0d
		const char *errstr;
Packit e9ba0d
		limit = strtonum(limit_str, 1, LLONG_MAX, &errstr);
Packit e9ba0d
		if (errstr != NULL) {
Packit e9ba0d
			log_warnx("lldpctl", "specified limit (%s) is %s and ignored",
Packit e9ba0d
			    limit_str, errstr);
Packit e9ba0d
		}
Packit e9ba0d
	}
Packit e9ba0d
Packit e9ba0d
	log_debug("lldpctl", "watch for neighbor changes");
Packit e9ba0d
	if (lldpctl_watch_callback(conn, watchcb, &wa) < 0) {
Packit e9ba0d
		log_warnx("lldpctl", "unable to watch for neighbors. %s",
Packit e9ba0d
		    lldpctl_last_strerror(conn));
Packit e9ba0d
		return 0;
Packit e9ba0d
	}
Packit e9ba0d
	while (1) {
Packit e9ba0d
		if (lldpctl_watch(conn) < 0) {
Packit e9ba0d
			log_warnx("lldpctl", "unable to watch for neighbors. %s",
Packit e9ba0d
			    lldpctl_last_strerror(conn));
Packit e9ba0d
			return 0;
Packit e9ba0d
		}
Packit e9ba0d
		if (limit > 0 && wa.nb >= limit)
Packit e9ba0d
			return 1;
Packit e9ba0d
	}
Packit e9ba0d
	return 0;
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Register common subcommands for `watch` and `show neighbors` and `show chassis'
Packit e9ba0d
 */
Packit e9ba0d
void
Packit e9ba0d
register_common_commands(struct cmd_node *root, int neighbor)
Packit e9ba0d
{
Packit e9ba0d
	/* With more details */
Packit e9ba0d
	commands_new(root,
Packit e9ba0d
	    "details",
Packit e9ba0d
	    "With more details",
Packit e9ba0d
	    cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "detailed");
Packit e9ba0d
Packit e9ba0d
	/* With less details */
Packit e9ba0d
	commands_new(root,
Packit e9ba0d
	    "summary",
Packit e9ba0d
	    "With less details",
Packit e9ba0d
	    cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary");
Packit e9ba0d
Packit e9ba0d
	if (!neighbor) return;
Packit e9ba0d
Packit e9ba0d
	/* With hidden neighbors */
Packit e9ba0d
	commands_new(root,
Packit e9ba0d
	    "hidden",
Packit e9ba0d
	    "Include hidden neighbors",
Packit e9ba0d
	    cmd_check_no_env, cmd_store_env_and_pop, "hidden");
Packit e9ba0d
Packit e9ba0d
	/* Some specific port */
Packit e9ba0d
	cmd_restrict_ports(root);
Packit e9ba0d
Packit e9ba0d
	/* Specific protocol */
Packit e9ba0d
	cmd_restrict_protocol(root);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Register sub command summary
Packit e9ba0d
 */
Packit e9ba0d
void
Packit e9ba0d
register_summary_command(struct cmd_node *root)
Packit e9ba0d
{
Packit e9ba0d
	commands_new(root,
Packit e9ba0d
			"summary",
Packit e9ba0d
			"With less details",
Packit e9ba0d
			cmd_check_no_detailed_nor_summary, cmd_store_env_and_pop, "summary");
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Register subcommands to `show`
Packit e9ba0d
 *
Packit e9ba0d
 * @param root Root node
Packit e9ba0d
 */
Packit e9ba0d
void
Packit e9ba0d
register_commands_show(struct cmd_node *root)
Packit e9ba0d
{
Packit e9ba0d
	struct cmd_node *show = commands_new(
Packit e9ba0d
		root,
Packit e9ba0d
		"show",
Packit e9ba0d
		"Show running system information",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
	struct cmd_node *neighbors = commands_new(
Packit e9ba0d
		show,
Packit e9ba0d
		"neighbors",
Packit e9ba0d
		"Show neighbors data",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
Packit e9ba0d
	struct cmd_node *interfaces = commands_new(
Packit e9ba0d
		show,
Packit e9ba0d
		"interfaces",
Packit e9ba0d
		"Show interfaces data",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
Packit e9ba0d
	struct cmd_node *chassis = commands_new(
Packit e9ba0d
		show,
Packit e9ba0d
		"chassis",
Packit e9ba0d
		"Show local chassis data",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
Packit e9ba0d
	struct cmd_node *stats = commands_new(
Packit e9ba0d
		show,
Packit e9ba0d
		"statistics",
Packit e9ba0d
		"Show statistics",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
Packit e9ba0d
	/* Neighbors data */
Packit e9ba0d
	commands_new(neighbors,
Packit e9ba0d
	    NEWLINE,
Packit e9ba0d
	    "Show neighbors data",
Packit e9ba0d
	    NULL, cmd_show_neighbors, NULL);
Packit e9ba0d
Packit e9ba0d
	register_common_commands(neighbors, 1);
Packit e9ba0d
Packit e9ba0d
	/* Interfaces data */
Packit e9ba0d
	commands_new(interfaces,
Packit e9ba0d
	    NEWLINE,
Packit e9ba0d
	    "Show interfaces data",
Packit e9ba0d
	    NULL, cmd_show_interfaces, NULL);
Packit e9ba0d
Packit e9ba0d
	cmd_restrict_ports(interfaces);
Packit e9ba0d
	register_common_commands(interfaces, 0);
Packit e9ba0d
Packit e9ba0d
	/* Chassis data */
Packit e9ba0d
	commands_new(chassis,
Packit e9ba0d
	    NEWLINE,
Packit e9ba0d
	    "Show local chassis data",
Packit e9ba0d
	    NULL, cmd_show_chassis, NULL);
Packit e9ba0d
Packit e9ba0d
	register_common_commands(chassis, 0);
Packit e9ba0d
Packit e9ba0d
	/* Stats data */
Packit e9ba0d
	commands_new(stats,
Packit e9ba0d
	    NEWLINE,
Packit e9ba0d
	    "Show stats data",
Packit e9ba0d
	    NULL, cmd_show_interface_stats, NULL);
Packit e9ba0d
Packit e9ba0d
	cmd_restrict_ports(stats);
Packit e9ba0d
	register_summary_command(stats);
Packit e9ba0d
Packit e9ba0d
	/* Register "show configuration" and "show running-configuration" */
Packit e9ba0d
	commands_new(
Packit e9ba0d
		commands_new(show,
Packit e9ba0d
		    "configuration",
Packit e9ba0d
		    "Show running configuration",
Packit e9ba0d
		    NULL, NULL, NULL),
Packit e9ba0d
		NEWLINE,
Packit e9ba0d
		"Show running configuration",
Packit e9ba0d
		NULL, cmd_show_configuration, NULL);
Packit e9ba0d
	commands_new(
Packit e9ba0d
		commands_new(show,
Packit e9ba0d
		    "running-configuration",
Packit e9ba0d
		    "Show running configuration",
Packit e9ba0d
		    NULL, NULL, NULL),
Packit e9ba0d
		NEWLINE,
Packit e9ba0d
		"Show running configuration",
Packit e9ba0d
		NULL, cmd_show_configuration, NULL);
Packit e9ba0d
}
Packit e9ba0d
Packit e9ba0d
/**
Packit e9ba0d
 * Register subcommands to `watch`
Packit e9ba0d
 *
Packit e9ba0d
 * @param root Root node
Packit e9ba0d
 */
Packit e9ba0d
void
Packit e9ba0d
register_commands_watch(struct cmd_node *root)
Packit e9ba0d
{
Packit e9ba0d
	struct cmd_node *watch = commands_new(
Packit e9ba0d
		root,
Packit e9ba0d
		"watch",
Packit e9ba0d
		"Monitor neighbor changes",
Packit e9ba0d
		NULL, NULL, NULL);
Packit e9ba0d
Packit e9ba0d
	commands_new(watch,
Packit e9ba0d
	    NEWLINE,
Packit e9ba0d
	    "Monitor neighbors change",
Packit e9ba0d
	    NULL, cmd_watch_neighbors, NULL);
Packit e9ba0d
Packit e9ba0d
	commands_new(
Packit e9ba0d
		commands_new(watch,
Packit e9ba0d
		    "limit",
Packit e9ba0d
		    "Don't show more than X events",
Packit e9ba0d
		    cmd_check_no_env, NULL, "limit"),
Packit e9ba0d
		NULL,
Packit e9ba0d
		"Stop after getting X events",
Packit e9ba0d
		NULL, cmd_store_env_value_and_pop2, "limit");
Packit e9ba0d
Packit e9ba0d
	register_common_commands(watch, 1);
Packit e9ba0d
}