.Nd control LLDP daemon
.Sh SYNOPSIS
.Nm
-.Op Fl advw
+.Op Fl advwC
.Op Fl L Ar location
.Op Fl P Ar policy
.Op Fl O Ar poe
Display all remote ports, including those hidden by the smart filter.
.It Fl w
Monitor neighbor changes. Each changed neighbor will be displayed.
+.It Fl C
+Display global configuration of lldpd daemon.
.It Fl f Ar format
Choose the output format. Currently
.Em plain ,
#include "../lldp-const.h"
#include "writer.h"
-#define LLDPCTL_ARGS "hdvaf:L:P:O:o:w"
+#define LLDPCTL_ARGS "hdvaf:L:P:O:o:wC"
/* display.c */
void display_interfaces(lldpctl_conn_t *, struct writer *, int, int, char **);
void display_interface(lldpctl_conn_t *, struct writer *, int,
lldpctl_atom_t *, lldpctl_atom_t *);
+void display_configuration(lldpctl_conn_t *, struct writer *);
/* actions.c */
void modify_interfaces(lldpctl_conn_t *, int, char **, int);
iface_list = lldpctl_get_interfaces(conn);
if (!iface_list) {
- LLOG_WARNX("not able to get the list of interfaces: %s", lldpctl_strerror(lldpctl_last_error(conn)));
+ LLOG_WARNX("not able to get the list of interfaces. %s",
+ lldpctl_last_strerror(conn));
return;
}
lldpctl_atom_dec_ref(iface_list);
tag_end(w);
}
+
+const char *
+N(const char *str) {
+ if (str == NULL || strlen(str) == 0) return "(none)";
+ return str;
+}
+
+void
+display_configuration(lldpctl_conn_t *conn, struct writer *w)
+{
+ lldpctl_atom_t *configuration;
+
+ configuration = lldpctl_get_configuration(conn);
+ if (!configuration) {
+ LLOG_WARNX("not able to get configuration. %s",
+ lldpctl_last_strerror(conn));
+ return;
+ }
+
+ tag_start(w, "configuration", "Global configuration");
+ tag_start(w, "config", "Configuration");
+
+ tag_datatag(w, "tx-delay", "Transmit delay",
+ lldpctl_atom_get_str(configuration, lldpctl_k_config_delay));
+ tag_datatag(w, "rx-only", "Receive mode",
+ lldpctl_atom_get_int(configuration, lldpctl_k_config_receiveonly)?
+ "yes":"no");
+ tag_datatag(w, "mgmt-pattern", "Pattern for management addresses",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_mgmt_pattern)));
+ tag_datatag(w, "iface-pattern", "Interface pattern",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_iface_pattern)));
+ tag_datatag(w, "cid-pattern", "Interface pattern for chassis ID",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_cid_pattern)));
+ tag_datatag(w, "description", "Override description with",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_description)));
+ tag_datatag(w, "platform", "Override platform with",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_platform)));
+ tag_datatag(w, "advertise-version", "Advertise version",
+ lldpctl_atom_get_int(configuration, lldpctl_k_config_advertise_version)?
+ "yes":"no");
+ tag_datatag(w, "lldpmed-no-inventory", "Disable LLDP-MED inventory",
+ (lldpctl_atom_get_int(configuration, lldpctl_k_config_lldpmed_noinventory) == 0)?
+ "no":"yes");
+
+ tag_end(w);
+ tag_end(w);
+
+ lldpctl_atom_dec_ref(configuration);
+}
fprintf(stderr, "-d Enable more debugging information.\n");
fprintf(stderr, "-a Display all remote ports, including hidden ones.\n");
fprintf(stderr, "-w Watch for changes.\n");
+ fprintf(stderr, "-C Display global configuration of lldpd.\n");
fprintf(stderr, "-f format Choose output format (plain, keyvalue or xml).\n");
fprintf(stderr, "-L location Enable the transmission of LLDP-MED location TLV for the\n");
fprintf(stderr, " given interfaces. Can be repeated to enable the transmission\n");
{
int ch, debug = 1;
char *fmt = "plain";
- int action = 0, hidden = 0, watch = 0;
+ int action = 0, hidden = 0, watch = 0, configuration = 0;
lldpctl_conn_t *conn;
struct cbargs args;
case 'w':
watch = 1;
break;
+ case 'C':
+ configuration = 1;
+ break;
default:
usage();
}
}
do {
- if (!action || watch) {
- if (strcmp(fmt, "plain") == 0) {
- args.w = txt_init(stdout);
- } else if (strcmp(fmt, "keyvalue") == 0) {
- args.w = kv_init(stdout);
- }
+ if (strcmp(fmt, "plain") == 0) {
+ args.w = txt_init(stdout);
+ } else if (strcmp(fmt, "keyvalue") == 0) {
+ args.w = kv_init(stdout);
+ }
#ifdef USE_XML
- else if (strcmp(fmt,"xml") == 0 ) {
- args.w = xml_init(stdout);
- }
+ else if (strcmp(fmt,"xml") == 0 ) {
+ args.w = xml_init(stdout);
+ }
#endif
- else {
- args.w = txt_init(stdout);
- }
+ else {
+ args.w = txt_init(stdout);
}
- if (!watch && !action) {
+ if (!watch && !action && !configuration) {
display_interfaces(conn, args.w,
hidden, argc, argv);
- args.w->finish(args.w);
- } else if (!watch) {
+ } else if (action) {
modify_interfaces(conn, argc, argv, optind);
- } else {
+ } else if (watch) {
if (lldpctl_watch(conn) < 0) {
LLOG_WARNX("unable to watch for neighbors. %s",
lldpctl_last_strerror(conn));
watch = 0;
}
- args.w->finish(args.w);
+ } else if (configuration) {
+ display_configuration(conn, args.w);
}
+ args.w->finish(args.w);
} while (watch);
lldpctl_release(conn);
#define tag_attr(w,...) w->attr(w,## __VA_ARGS__)
#define tag_data(w,...) w->data(w,## __VA_ARGS__)
#define tag_end(w,...) w->end(w,## __VA_ARGS__)
-#define tag_datatag(w,t,d,v) do { if (!v) break; w->start(w,t,d); w->data(w,v); w->end(w); } while(0);
+#define tag_datatag(w,t,d,v) do { if (!(v)) break; w->start(w,t,d); w->data(w,v); w->end(w); } while(0);
extern struct writer * txt_init( FILE * );
extern struct writer * kv_init( FILE * );
enum hmsg_type {
NONE,
+ GET_CONFIG, /* Get global configuration */
GET_INTERFACES, /* Get list of interfaces */
GET_INTERFACE, /* Get all information related to an interface */
SET_PORT, /* Set port-related information (location, power, policy) */
return 0;
}
+/* Return the global configuration */
+static int
+client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type,
+ void *input, int input_len, void **output, int *subscribed)
+{
+ ssize_t output_len;
+ output_len = marshal_serialize(lldpd_config, &cfg->g_config, output);
+ if (output_len <= 0) {
+ output_len = 0;
+ *type = NONE;
+ }
+ return output_len;
+}
+
/* Return the list of interfaces.
Input: nothing.
Output: list of interface names (lldpd_interface_list)
static struct client_handle client_handles[] = {
{ NONE, client_handle_none },
+ { GET_CONFIG, client_handle_get_configuration },
{ GET_INTERFACES, client_handle_get_interfaces },
{ GET_INTERFACE, client_handle_get_interface },
{ SET_PORT, client_handle_set_port },
/* Atom methods */
+static int
+_lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_config_t *c =
+ (struct _lldpctl_atom_config_t *)atom;
+ c->config = va_arg(ap, struct lldpd_config *);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_config(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_config_t *c =
+ (struct _lldpctl_atom_config_t *)atom;
+ lldpd_config_cleanup(c->config);
+ free(c->config);
+}
+
+static const char*
+_lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ char *res = NULL;
+ struct _lldpctl_atom_config_t *c =
+ (struct _lldpctl_atom_config_t *)atom;
+ switch (key) {
+ case lldpctl_k_config_mgmt_pattern:
+ res = c->config->c_mgmt_pattern; break;
+ case lldpctl_k_config_iface_pattern:
+ res = c->config->c_iface_pattern; break;
+ case lldpctl_k_config_cid_pattern:
+ res = c->config->c_cid_pattern; break;
+ case lldpctl_k_config_description:
+ res = c->config->c_description; break;
+ case lldpctl_k_config_platform:
+ res = c->config->c_platform; break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ return res?res:"";
+}
+
+static long int
+_lldpctl_atom_get_int_config(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_config_t *c =
+ (struct _lldpctl_atom_config_t *)atom;
+ switch (key) {
+ case lldpctl_k_config_delay:
+ return c->config->c_delay;
+ case lldpctl_k_config_receiveonly:
+ return c->config->c_receiveonly;
+ case lldpctl_k_config_advertise_version:
+ return c->config->c_advertise_version;
+ case lldpctl_k_config_lldpmed_noinventory:
+ return c->config->c_noinventory;
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+}
+
static int
_lldpctl_atom_new_interfaces_list(lldpctl_atom_t *atom, va_list ap)
{
};
struct atom_builder builders[] = {
+ { atom_config, sizeof(struct _lldpctl_atom_config_t),
+ .init = _lldpctl_atom_new_config,
+ .free = _lldpctl_atom_free_config,
+ .get_str = _lldpctl_atom_get_str_config,
+ .get_int = _lldpctl_atom_get_int_config },
{ atom_interfaces_list, sizeof(struct _lldpctl_atom_interfaces_list_t),
.init = _lldpctl_atom_new_interfaces_list,
.free = _lldpctl_atom_free_interfaces_list,
return 0;
}
+lldpctl_atom_t*
+lldpctl_get_configuration(lldpctl_conn_t *conn)
+{
+ int rc;
+ struct lldpd_config *config;
+
+ RESET_ERROR(conn);
+
+ rc = _lldpctl_do_something(conn,
+ CONN_STATE_GET_CONFIG_SEND, CONN_STATE_GET_CONFIG_RECV, NULL,
+ GET_CONFIG,
+ NULL, NULL,
+ (void **)&config, &MARSHAL_INFO(lldpd_config));
+ if (rc == 0)
+ return _lldpctl_new_atom(conn, atom_config, config);
+ return NULL;
+}
+
lldpctl_atom_t*
lldpctl_get_interfaces(lldpctl_conn_t *conn)
{
*/
int lldpctl_watch(lldpctl_conn_t *conn);
+/**
+ * Retrieve global configuration of lldpd daemon.
+ *
+ * @param conn Connection with lldpd.
+ * @return The global configuration or @c NULL if an error happened.
+ *
+ * This function will make IO with the daemon to get the
+ * configuration. Depending on the IO model, information may not be available
+ * right now and the function should be called again later. If @c NULL is
+ * returned, check the last error. If it is @c LLDPCTL_ERR_WOULDBLOCK, try again
+ * later.
+ */
+lldpctl_atom_t *lldpctl_get_configuration(lldpctl_conn_t *conn);
+
/**
* Retrieve the list of available interfaces.
*
* first write to a (A,W), then to a (A,WO)).
*/
typedef enum {
+ lldpctl_k_config_delay, /* (I) Transmit delay */
+ lldpctl_k_config_receiveonly, /* (I) Receive only mode */
+ lldpctl_k_config_mgmt_pattern, /* (S) Pattern to choose the management address */
+ lldpctl_k_config_iface_pattern, /* (S) Pattern of enabled interfaces */
+ lldpctl_k_config_cid_pattern, /* (S) Interface pattern to choose the chassis ID */
+ lldpctl_k_config_description, /* (S) Chassis description overriden */
+ lldpctl_k_config_platform, /* (S) Platform description overriden (CDP) */
+ lldpctl_k_config_advertise_version, /* (I) Advertise version */
+ lldpctl_k_config_lldpmed_noinventory, /* (I) Disable LLDP-MED inventory */
+
lldpctl_k_interface_name, /**< (S) The interface name. */
lldpctl_k_port_name, /**< (S) The port name. Only works for a local port. */
#define CONN_STATE_SET_PORT_RECV 6
#define CONN_STATE_SET_WATCH_SEND 7
#define CONN_STATE_SET_WATCH_RECV 8
+#define CONN_STATE_GET_CONFIG_SEND 9
+#define CONN_STATE_GET_CONFIG_RECV 9
int state; /* Current state */
void *state_data; /* Data attached to the state. It is used to
* check that we are using the same data as a
/* atom.c and atom-private.c */
typedef enum {
+ atom_config,
atom_interfaces_list,
atom_interface,
atom_ports_list,
lldpctl_atom_t *(*create)(lldpctl_atom_t *);
};
+struct _lldpctl_atom_config_t {
+ lldpctl_atom_t base;
+ struct lldpd_config *config;
+};
+
struct _lldpctl_atom_interfaces_list_t {
lldpctl_atom_t base;
struct lldpd_interface_list *ifs;