GET_CONFIG, /* Get global configuration */
SET_CONFIG, /* Change global configuration */
GET_INTERFACES, /* Get list of interfaces */
+ GET_CHASSIS, /* Get local chassis */
GET_INTERFACE, /* Get all information related to an interface */
SET_PORT, /* Set port-related information (location, power, policy) */
SUBSCRIBE, /* Subscribe to neighbor changes */
return output_len;
}
+/* Return the local chassis.
+ Input: nothing.
+ Output: local chassis (lldpd_chassis)
+*/
+static ssize_t
+client_handle_get_local_chassis(struct lldpd *cfg, enum hmsg_type *type,
+ void *input, int input_len, void **output, int *subscribed)
+{
+ struct lldpd_chassis *chassis = LOCAL_CHASSIS(cfg);
+ ssize_t output_len;
+
+ log_debug("rpc", "client request the local chassis");
+ output_len = lldpd_chassis_serialize(chassis, output);
+ if (output_len <= 0) {
+ output_len = 0;
+ *type = NONE;
+ }
+
+ return output_len;
+}
+
/* Return all available information related to an interface
Input: name of the interface (serialized)
Output: Information about the interface (lldpd_hardware)
{ SET_CONFIG, "Set configuration", client_handle_set_configuration },
{ GET_INTERFACES, "Get interfaces", client_handle_get_interfaces },
{ GET_INTERFACE, "Get interface", client_handle_get_interface },
+ { GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis },
{ SET_PORT, "Set port", client_handle_set_port },
{ SUBSCRIBE, "Subscribe", client_handle_subscribe },
{ 0, NULL } };
lldpctl.h atom.h errors.c connection.c atom.c helpers.c helpers.h \
atoms/config.c atoms/dot1.c atoms/dot3.c \
atoms/interface.c atoms/med.c atoms/mgmt.c atoms/port.c \
- atoms/custom.c
+ atoms/custom.c atoms/chassis.c
liblldpctl_la_LIBADD = $(top_builddir)/src/libcommon-daemon-lib.la libfixedpoint.la
# -version-info format is `current`:`revision`:`age`. For more details, see:
# -version-number could be computed from -version-info, mostly major
# is `current` - `age`, minor is `age` and revision is `revision' and
# major.minor should be used when updaing lldpctl.map.
-liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 10:0:6
+liblldpctl_la_LDFLAGS = $(AM_LDFLAGS) -version-info 11:0:7
liblldpctl_la_DEPENDENCIES = libfixedpoint.la
if HAVE_LD_VERSION_SCRIPT
return NULL;
}
+lldpctl_atom_t*
+lldpctl_get_local_chassis(lldpctl_conn_t *conn)
+{
+ struct lldpd_chassis *chassis;
+ void *p;
+ int rc;
+
+ RESET_ERROR(conn);
+
+ rc = _lldpctl_do_something(conn,
+ CONN_STATE_GET_CHASSIS_SEND, CONN_STATE_GET_CHASSIS_RECV, NULL,
+ GET_CHASSIS,
+ NULL, NULL,
+ &p, &MARSHAL_INFO(lldpd_chassis));
+ if (rc == 0) {
+ chassis = p;
+ return _lldpctl_new_atom(conn, atom_chassis, chassis, NULL);
+ }
+ return NULL;
+}
+
lldpctl_atom_t*
lldpctl_get_port(lldpctl_atom_t *atom)
{
#define CONN_STATE_GET_CONFIG_RECV 9
#define CONN_STATE_SET_CONFIG_SEND 10
#define CONN_STATE_SET_CONFIG_RECV 11
+#define CONN_STATE_GET_CHASSIS_SEND 12
+#define CONN_STATE_GET_CHASSIS_RECV 13
int state; /* Current state */
char *state_data; /* Data attached to the state. It is used to
* check that we are using the same data as a
atom_custom_list,
atom_custom,
#endif
+ atom_chassis,
} atom_t;
void *_lldpctl_alloc_in_atom(lldpctl_atom_t *, size_t);
char *name;
};
+struct _lldpctl_atom_chassis_t {
+ lldpctl_atom_t base;
+ struct lldpd_chassis *chassis;
+ struct _lldpctl_atom_port_t *parent; /* Optional: parent of this atom (owning our reference) */
+};
+
struct _lldpctl_atom_port_t {
lldpctl_atom_t base;
struct lldpd_hardware *hardware; /* Local port only */
struct _lldpctl_atom_mgmts_list_t {
lldpctl_atom_t base;
- struct _lldpctl_atom_port_t *parent;
+ lldpctl_atom_t *parent;
struct lldpd_chassis *chassis; /* Chassis containing the list of IP addresses */
};
struct _lldpctl_atom_mgmt_t {
lldpctl_atom_t base;
- struct _lldpctl_atom_port_t *parent;
+ lldpctl_atom_t *parent;
struct lldpd_mgmt *mgmt;
};
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2015 Vincent Bernat <vincent@bernat.im>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "lldpctl.h"
+#include "../log.h"
+#include "atom.h"
+#include "helpers.h"
+
+static lldpctl_map_t chassis_id_subtype_map[] = {
+ { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname"},
+ { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" },
+ { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" },
+ { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" },
+ { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" },
+ { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" },
+ { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" },
+ { 0, NULL},
+};
+
+#ifdef ENABLE_LLDPMED
+
+static lldpctl_map_t chassis_med_type_map[] = {
+ { LLDP_MED_CLASS_I, "Generic Endpoint (Class I)" },
+ { LLDP_MED_CLASS_II, "Media Endpoint (Class II)" },
+ { LLDP_MED_CLASS_III, "Communication Device Endpoint (Class III)" },
+ { LLDP_MED_NETWORK_DEVICE, "Network Connectivity Device" },
+ { 0, NULL },
+};
+
+#endif
+
+static int
+_lldpctl_atom_new_chassis(lldpctl_atom_t *atom, va_list ap)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ p->chassis = va_arg(ap, struct lldpd_chassis*);
+ p->parent = va_arg(ap, struct _lldpctl_atom_port_t*);
+ if (p->parent)
+ lldpctl_atom_inc_ref((lldpctl_atom_t*)p->parent);
+ return 1;
+}
+
+static void
+_lldpctl_atom_free_chassis(lldpctl_atom_t *atom)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ /* When we have a parent, the chassis structure is in fact part of the
+ * parent, just decrement the reference count of the parent. Otherwise,
+ * we need to free the whole chassis. */
+ if (p->parent) lldpctl_atom_dec_ref((lldpctl_atom_t*)p->parent);
+ else lldpd_chassis_cleanup(p->chassis, 1);
+}
+
+static lldpctl_atom_t*
+_lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ switch (key) {
+ case lldpctl_k_chassis_mgmt:
+ return _lldpctl_new_atom(atom->conn, atom_mgmts_list,
+ p, chassis);
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static const char*
+_lldpctl_atom_get_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+ char *ipaddress = NULL; size_t len;
+
+ /* Local and remote port */
+ switch (key) {
+
+ case lldpctl_k_chassis_id_subtype:
+ return map_lookup(chassis_id_subtype_map, chassis->c_id_subtype);
+ case lldpctl_k_chassis_id:
+ switch (chassis->c_id_subtype) {
+ case LLDP_CHASSISID_SUBTYPE_IFNAME:
+ case LLDP_CHASSISID_SUBTYPE_IFALIAS:
+ case LLDP_CHASSISID_SUBTYPE_LOCAL:
+ return chassis->c_id;
+ case LLDP_CHASSISID_SUBTYPE_LLADDR:
+ return _lldpctl_dump_in_atom(atom,
+ (uint8_t*)chassis->c_id, chassis->c_id_len,
+ ':', 0);
+ case LLDP_CHASSISID_SUBTYPE_ADDR:
+ switch (chassis->c_id[0]) {
+ case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
+ case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
+ default: len = 0;
+ }
+ if (len > 0) {
+ ipaddress = _lldpctl_alloc_in_atom(atom, len);
+ if (!ipaddress) return NULL;
+ if (inet_ntop((chassis->c_id[0] == LLDP_MGMT_ADDR_IP4)?
+ AF_INET:AF_INET6,
+ &chassis->c_id[1], ipaddress, len) == NULL)
+ break;
+ return ipaddress;
+ }
+ break;
+ }
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ case lldpctl_k_chassis_name: return chassis->c_name;
+ case lldpctl_k_chassis_descr: return chassis->c_descr;
+
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_chassis_med_type:
+ return map_lookup(chassis_med_type_map, chassis->c_med_type);
+ case lldpctl_k_chassis_med_inventory_hw:
+ return chassis->c_med_hw;
+ case lldpctl_k_chassis_med_inventory_sw:
+ return chassis->c_med_sw;
+ case lldpctl_k_chassis_med_inventory_fw:
+ return chassis->c_med_fw;
+ case lldpctl_k_chassis_med_inventory_sn:
+ return chassis->c_med_sn;
+ case lldpctl_k_chassis_med_inventory_manuf:
+ return chassis->c_med_manuf;
+ case lldpctl_k_chassis_med_inventory_model:
+ return chassis->c_med_model;
+ case lldpctl_k_chassis_med_inventory_asset:
+ return chassis->c_med_asset;
+#endif
+
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static long int
+_lldpctl_atom_get_int_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ /* Local and remote port */
+ switch (key) {
+ case lldpctl_k_chassis_index:
+ return chassis->c_index;
+ case lldpctl_k_chassis_id_subtype:
+ return chassis->c_id_subtype;
+ case lldpctl_k_chassis_cap_available:
+ return chassis->c_cap_available;
+ case lldpctl_k_chassis_cap_enabled:
+ return chassis->c_cap_enabled;
+#ifdef ENABLE_LLDPMED
+ case lldpctl_k_chassis_med_type:
+ return chassis->c_med_type;
+ case lldpctl_k_chassis_med_cap:
+ return chassis->c_med_cap_available;
+#endif
+ default:
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ }
+ return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+}
+
+static const uint8_t*
+_lldpctl_atom_get_buf_chassis(lldpctl_atom_t *atom, lldpctl_key_t key, size_t *n)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *)atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ switch (key) {
+ case lldpctl_k_chassis_id:
+ *n = chassis->c_id_len;
+ return (uint8_t*)chassis->c_id;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+}
+
+static struct atom_builder chassis =
+ { atom_chassis, sizeof(struct _lldpctl_atom_chassis_t),
+ .init = _lldpctl_atom_new_chassis,
+ .free = _lldpctl_atom_free_chassis,
+ .get = _lldpctl_atom_get_atom_chassis,
+ .get_str = _lldpctl_atom_get_str_chassis,
+ .get_int = _lldpctl_atom_get_int_chassis,
+ .get_buffer = _lldpctl_atom_get_buf_chassis };
+
+ATOM_BUILDER_REGISTER(chassis, 3);
{
struct _lldpctl_atom_mgmts_list_t *plist =
(struct _lldpctl_atom_mgmts_list_t *)atom;
- plist->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ plist->parent = va_arg(ap, lldpctl_atom_t *);
plist->chassis = va_arg(ap, struct lldpd_chassis *);
- lldpctl_atom_inc_ref((lldpctl_atom_t *)plist->parent);
+ lldpctl_atom_inc_ref(plist->parent);
return 1;
}
{
struct _lldpctl_atom_mgmts_list_t *plist =
(struct _lldpctl_atom_mgmts_list_t *)atom;
- lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent);
+ lldpctl_atom_dec_ref(plist->parent);
}
static lldpctl_atom_iter_t*
{
struct _lldpctl_atom_mgmt_t *mgmt =
(struct _lldpctl_atom_mgmt_t *)atom;
- mgmt->parent = va_arg(ap, struct _lldpctl_atom_port_t *);
+ mgmt->parent = va_arg(ap, lldpctl_atom_t *);
mgmt->mgmt = va_arg(ap, struct lldpd_mgmt *);
- lldpctl_atom_inc_ref((lldpctl_atom_t *)mgmt->parent);
+ lldpctl_atom_inc_ref(mgmt->parent);
return 1;
}
{
struct _lldpctl_atom_mgmt_t *mgmt =
(struct _lldpctl_atom_mgmt_t *)atom;
- lldpctl_atom_dec_ref((lldpctl_atom_t *)mgmt->parent);
+ lldpctl_atom_dec_ref(mgmt->parent);
}
static const char*
{ 0, NULL},
};
-static lldpctl_map_t chassis_id_subtype_map[] = {
- { LLDP_CHASSISID_SUBTYPE_IFNAME, "ifname"},
- { LLDP_CHASSISID_SUBTYPE_IFALIAS, "ifalias" },
- { LLDP_CHASSISID_SUBTYPE_LOCAL, "local" },
- { LLDP_CHASSISID_SUBTYPE_LLADDR, "mac" },
- { LLDP_CHASSISID_SUBTYPE_ADDR, "ip" },
- { LLDP_CHASSISID_SUBTYPE_PORT, "unhandled" },
- { LLDP_CHASSISID_SUBTYPE_CHASSIS, "unhandled" },
- { 0, NULL},
-};
-
static lldpctl_map_t operational_mau_type_values[] = {
{ 1, "AUI - no internal MAU, view from AUI" },
{ 2, "10Base5 - thick coax MAU" },
{ 0, NULL }
};
-#ifdef ENABLE_LLDPMED
-
-static lldpctl_map_t chassis_med_type_map[] = {
- { LLDP_MED_CLASS_I, "Generic Endpoint (Class I)" },
- { LLDP_MED_CLASS_II, "Media Endpoint (Class II)" },
- { LLDP_MED_CLASS_III, "Communication Device Endpoint (Class III)" },
- { LLDP_MED_NETWORK_DEVICE, "Network Connectivity Device" },
- { 0, NULL },
-};
-
-#endif
-
static lldpctl_atom_iter_t*
_lldpctl_atom_iter_ports_list(lldpctl_atom_t *atom)
{
/* Local and remote port */
switch (key) {
- case lldpctl_k_chassis_mgmt:
- return _lldpctl_new_atom(atom->conn, atom_mgmts_list,
- p, port->p_chassis);
+ case lldpctl_k_port_chassis:
+ return _lldpctl_new_atom(atom->conn, atom_chassis,
+ port->p_chassis, p);
#ifdef ENABLE_DOT3
case lldpctl_k_port_dot3_power:
return _lldpctl_new_atom(atom->conn, atom_dot3_power,
(struct _lldpctl_atom_port_t *)atom;
struct lldpd_port *port = p->port;
struct lldpd_hardware *hardware = p->hardware;
- struct lldpd_chassis *chassis = port->p_chassis;
char *ipaddress = NULL; size_t len;
/* Local port only */
port->p_macphy.mau_type);
#endif
- case lldpctl_k_chassis_id_subtype:
- return map_lookup(chassis_id_subtype_map, chassis->c_id_subtype);
- case lldpctl_k_chassis_id:
- switch (chassis->c_id_subtype) {
- case LLDP_CHASSISID_SUBTYPE_IFNAME:
- case LLDP_CHASSISID_SUBTYPE_IFALIAS:
- case LLDP_CHASSISID_SUBTYPE_LOCAL:
- return chassis->c_id;
- case LLDP_CHASSISID_SUBTYPE_LLADDR:
- return _lldpctl_dump_in_atom(atom,
- (uint8_t*)chassis->c_id, chassis->c_id_len,
- ':', 0);
- case LLDP_CHASSISID_SUBTYPE_ADDR:
- switch (chassis->c_id[0]) {
- case LLDP_MGMT_ADDR_IP4: len = INET_ADDRSTRLEN + 1; break;
- case LLDP_MGMT_ADDR_IP6: len = INET6_ADDRSTRLEN + 1; break;
- default: len = 0;
- }
- if (len > 0) {
- ipaddress = _lldpctl_alloc_in_atom(atom, len);
- if (!ipaddress) return NULL;
- if (inet_ntop((chassis->c_id[0] == LLDP_MGMT_ADDR_IP4)?
- AF_INET:AF_INET6,
- &chassis->c_id[1], ipaddress, len) == NULL)
- break;
- return ipaddress;
- }
- break;
- }
- SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
- return NULL;
- case lldpctl_k_chassis_name: return chassis->c_name;
- case lldpctl_k_chassis_descr: return chassis->c_descr;
-
-#ifdef ENABLE_LLDPMED
- case lldpctl_k_chassis_med_type:
- return map_lookup(chassis_med_type_map, chassis->c_med_type);
- case lldpctl_k_chassis_med_inventory_hw:
- return chassis->c_med_hw;
- case lldpctl_k_chassis_med_inventory_sw:
- return chassis->c_med_sw;
- case lldpctl_k_chassis_med_inventory_fw:
- return chassis->c_med_fw;
- case lldpctl_k_chassis_med_inventory_sn:
- return chassis->c_med_sn;
- case lldpctl_k_chassis_med_inventory_manuf:
- return chassis->c_med_manuf;
- case lldpctl_k_chassis_med_inventory_model:
- return chassis->c_med_model;
- case lldpctl_k_chassis_med_inventory_asset:
- return chassis->c_med_asset;
-#endif
-
default:
SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
return NULL;
(struct _lldpctl_atom_port_t *)atom;
struct lldpd_port *port = p->port;
struct lldpd_hardware *hardware = p->hardware;
- struct lldpd_chassis *chassis = port->p_chassis;
/* Local port only */
if (hardware != NULL) {
#ifdef ENABLE_DOT1
case lldpctl_k_port_vlan_pvid:
return port->p_pvid;
-#endif
- case lldpctl_k_chassis_index:
- return chassis->c_index;
- case lldpctl_k_chassis_id_subtype:
- return chassis->c_id_subtype;
- case lldpctl_k_chassis_cap_available:
- return chassis->c_cap_available;
- case lldpctl_k_chassis_cap_enabled:
- return chassis->c_cap_enabled;
-#ifdef ENABLE_LLDPMED
- case lldpctl_k_chassis_med_type:
- return chassis->c_med_type;
- case lldpctl_k_chassis_med_cap:
- return chassis->c_med_cap_available;
#endif
default:
return SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
struct _lldpctl_atom_port_t *p =
(struct _lldpctl_atom_port_t *)atom;
struct lldpd_port *port = p->port;
- struct lldpd_chassis *chassis = port->p_chassis;
switch (key) {
case lldpctl_k_port_id:
*n = port->p_id_len;
return (uint8_t*)port->p_id;
- case lldpctl_k_chassis_id:
- *n = chassis->c_id_len;
- return (uint8_t*)chassis->c_id;
default:
SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
return NULL;
*/
lldpctl_atom_t *lldpctl_get_interfaces(lldpctl_conn_t *conn);
+/**
+ * Retrieve the information related to the local chassis.
+ *
+ * @param conn Previously allocated handler to a connection to lldpd.
+ * @return Atom related to the local chassis which may be used in subsequent functions.
+ *
+ * This function may have to do IO to get the information related to the local
+ * chassis. Depending on the IO mode, information may not be available right now
+ * and the function should be called again later. If @c NULL is returned, check
+ * what the last error is. If it is @c LLDPCTL_ERR_WOULDBLOCK, try again later
+ * (when more data is available).
+ */
+lldpctl_atom_t *lldpctl_get_local_chassis(lldpctl_conn_t *conn);
+
/**
* Retrieve the information related to a given interface.
*
* @return Atom related to this port which may be used in subsequent functions.
*
* This functions may have to do IO to get the information related to the given
- * port. Depending on the IO mode, information may not be available tight now
+ * port. Depending on the IO mode, information may not be available right now
* and the function should be called again later. If @c NULL is returned, check
* what the last error is. If it is @c LLDPCTL_ERR_WOULDBLOCK, try again later
* (when more data is available).
lldpctl_k_port_id, /**< `(BS,WO)` The ID of this port. */
lldpctl_k_port_descr, /**< `(S,WO)` The description of this port. */
lldpctl_k_port_hidden, /**< `(I)` Is this port hidden (or should it be displayed?)? */
+ lldpctl_k_port_chassis, /**< `(A)` Chassis associated to the port */
lldpctl_k_port_dot3_mfs = 1300, /**< `(I)` MFS */
lldpctl_k_port_dot3_aggregid, /**< `(I)` Port aggregation ID */
+LIBLLDPCTL_4.7 {
+ global:
+ lldpctl_get_local_chassis;
+};
+
LIBLLDPCTL_4.6 {
global:
lldpctl_atom_create;