Default inventory information is fetched from dmi table.
Most of embedded devices do not run EFI bootloader hence dmi information
will not be available in /sys/class/dmi
- Add `configure inventory` commands
- Add `unconfigure inventory` commands
- New code is dependent on enable-lldpmed
- Add write support on lldpctl atoms
- Add support for setting inventory configuration in daemon
- Refactor `lldp_med` to assign `c_med_sw` only once.
We have the configurability of inventory information, So
it is not required for daemon to keep assigning `c_med_sw`
cd $(DESTDIR)$(sbindir) && rm -f lldpctl
lldpcli_SOURCES = client.h lldpcli.c display.c \
- conf.c conf-med.c conf-dot3.c conf-power.c \
+ conf.c conf-med.c conf-inv.c conf-dot3.c conf-power.c \
conf-lldp.c conf-system.c \
commands.c show.c \
misc.c tokenizer.c \
void register_commands_configure_system(struct cmd_node *, struct cmd_node *);
void register_commands_configure_lldp(struct cmd_node *, struct cmd_node *);
void register_commands_configure_med(struct cmd_node *, struct cmd_node *);
+void register_commands_configure_inventory(struct cmd_node *, struct cmd_node *);
void register_commands_configure_dot3(struct cmd_node *);
void register_commands_medpow(struct cmd_node *);
void register_commands_dot3pow(struct cmd_node *);
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * SPDX-FileCopyrightText: 2022 Koninklijke Philips N.V.
+ * SPDX-License-Identifier: ISC
+ */
+
+#include <unistd.h>
+#include <string.h>
+
+#include "client.h"
+#include "../log.h"
+
+static int
+cmd_inventory(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, void *arg)
+{
+ log_debug("lldpctl", "configure inventory information");
+
+ lldpctl_atom_t *chassis = lldpctl_get_local_chassis(conn);
+
+ if (chassis == NULL) {
+ log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
+ lldpctl_last_strerror(conn));
+ return 0;
+ }
+
+ char *action = arg;
+ if ((!strcmp(action, "hardware-revision") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_hw,
+ cmdenv_get(env, "hardware-revision")) == NULL)) ||
+ (!strcmp(action, "software-revision") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_sw,
+ cmdenv_get(env, "software-revision")) == NULL)) ||
+ (!strcmp(action, "firmware-revision") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_fw,
+ cmdenv_get(env, "firmware-revision")) == NULL)) ||
+ (!strcmp(action, "serial-number") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_sn,
+ cmdenv_get(env, "serial-number")) == NULL)) ||
+ (!strcmp(action, "manufacturer") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_manuf,
+ cmdenv_get(env, "manufacturer")) == NULL)) ||
+ (!strcmp(action, "model") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_model,
+ cmdenv_get(env, "model")) == NULL)) ||
+ (!strcmp(action, "asset") &&
+ (lldpctl_atom_set_str(chassis,
+ lldpctl_k_chassis_med_inventory_asset,
+ cmdenv_get(env, "asset")) == NULL))) {
+ log_warnx("lldpctl", "Unable to setup inventory. %s",
+ lldpctl_last_strerror(conn));
+ lldpctl_atom_dec_ref(chassis);
+ return 0;
+ }
+
+ log_info("lldpctl", "Configuration for inventory is applied");
+ lldpctl_atom_dec_ref(chassis);
+ return 1;
+}
+
+/**
+ * Register `configure inventory *` commands
+ *
+ */
+static void
+register_commands_inv(struct cmd_node *configure_inv, struct cmd_node *unconfigure_inv)
+{
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "hardware-revision", "Set hardware-revision string",
+ NULL, NULL, NULL),
+ NULL, "Inventory hardware-revision string",
+ NULL, cmd_store_env_value, "hardware-revision"),
+ NEWLINE, "Set hardware-revision string",
+ NULL, cmd_inventory, "hardware-revision");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "hardware-revision", "Unset hardware-revision string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset hardware-revision string",
+ NULL, cmd_inventory, "hardware-revision");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "software-revision", "Set software-revision string",
+ NULL, NULL, NULL),
+ NULL, "Inventory software-revision string",
+ NULL, cmd_store_env_value, "software-revision"),
+ NEWLINE, "Set software-revision string",
+ NULL, cmd_inventory, "software-revision");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "software-revision", "Unset software-revision string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset software-revision string",
+ NULL, cmd_inventory, "software-revision");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "firmware-revision", "Set firmware-revision string",
+ NULL, NULL, NULL),
+ NULL, "Inventory firmware-revision string",
+ NULL, cmd_store_env_value, "firmware-revision"),
+ NEWLINE, "Set firmware-revision string",
+ NULL, cmd_inventory, "firmware-revision");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "firmware-revision", "Unset firmware-revision string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset firmware-revision string",
+ NULL, cmd_inventory, "firmware-revision");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "serial-number", "Set serial-number string",
+ NULL, NULL, NULL),
+ NULL, "Inventory serial-number string",
+ NULL, cmd_store_env_value, "serial-number"),
+ NEWLINE, "Set serial-number string",
+ NULL, cmd_inventory, "serial-number");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "serial-number", "Unset serial-number string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset serial-number string",
+ NULL, cmd_inventory, "serial-number");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "manufacturer", "Set manufacturer string",
+ NULL, NULL, NULL),
+ NULL, "Inventory manufacturer string",
+ NULL, cmd_store_env_value, "manufacturer"),
+ NEWLINE, "Set manufacturer string",
+ NULL, cmd_inventory, "manufacturer");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "manufacturer", "Unset manufacturer string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset manufacturer string",
+ NULL, cmd_inventory, "manufacturer");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "model", "Set model string",
+ NULL, NULL, NULL),
+ NULL, "Inventory model string",
+ NULL, cmd_store_env_value, "model"),
+ NEWLINE, "Set model string",
+ NULL, cmd_inventory, "model");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "model", "Unset model string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset model string",
+ NULL, cmd_inventory, "model");
+
+ commands_new(
+ commands_new(
+ commands_new(configure_inv,
+ "asset", "Set asset string",
+ NULL, NULL, NULL),
+ NULL, "Inventory asset string",
+ NULL, cmd_store_env_value, "asset"),
+ NEWLINE, "Set asset string",
+ NULL, cmd_inventory, "asset");
+
+ commands_new(
+ commands_new(unconfigure_inv,
+ "asset", "Unset asset string",
+ NULL, NULL, NULL),
+ NEWLINE, "Unset asset string",
+ NULL, cmd_inventory, "asset");
+}
+
+/**
+ * Register `configure inventory *`
+ *
+ */
+void
+register_commands_configure_inventory(struct cmd_node *configure, struct cmd_node *unconfigure) {
+ if(lldpctl_key_get_map(
+ lldpctl_k_med_policy_type)[0].value <= 0)
+ return;
+
+ struct cmd_node *configure_inv = commands_new(
+ configure,
+ "inventory", "Inventory configuration",
+ NULL, NULL, NULL);
+ struct cmd_node *unconfigure_inv = commands_new(
+ unconfigure,
+ "inventory", "Inventory configuration",
+ NULL, NULL, NULL);
+
+ register_commands_inv(configure_inv, unconfigure_inv);
+}
+
register_commands_configure_system(configure, unconfigure);
register_commands_configure_lldp(configure, unconfigure);
register_commands_configure_med(configure, unconfigure);
+ register_commands_configure_inventory(configure, unconfigure);
register_commands_configure_dot3(configure);
}
GET_CONFIG, /* Get global configuration */
SET_CONFIG, /* Change global configuration */
GET_INTERFACES, /* Get list of interfaces */
+ SET_CHASSIS, /* Set local chassis */
GET_CHASSIS, /* Get local chassis */
GET_INTERFACE, /* Get all information related to an interface */
GET_DEFAULT_PORT, /* Get all information related to default port */
#include "lldpd.h"
#include "trace.h"
+#ifdef ENABLE_LLDPMED
+#include <sys/utsname.h>
+#endif
+
static ssize_t
client_handle_none(struct lldpd *cfg, enum hmsg_type *type,
void *input, int input_len, void **output, int *subscribed)
return output_len;
}
+#ifdef ENABLE_LLDPMED
+/**
+ * Set local chassis inventory info
+ * Input: chassis object
+ * Output: updated chassis object
+ */
+static ssize_t
+client_handle_set_local_chassis(struct lldpd *cfg, enum hmsg_type *type,
+ void *input, int input_len, void **output, int *subscribed)
+{
+ struct lldpd_chassis *chassis = NULL;
+ struct lldpd_chassis *local_chassis = NULL;
+ struct utsname un;
+
+ log_debug("rpc", "client request a change in chassis configuration");
+ if (lldpd_chassis_unserialize(input, input_len, &chassis) <= 0) {
+ *type = NONE;
+ return 0;
+ }
+
+ local_chassis = LOCAL_CHASSIS(cfg);
+
+ free(local_chassis->c_med_hw);
+ local_chassis->c_med_hw = (!chassis->c_med_hw) ? dmi_hw() : strdup(chassis->c_med_hw);
+
+ // Follows lldpd.c - only set sw if advertising is enabled
+ if (cfg->g_config.c_advertise_version) {
+ free(local_chassis->c_med_sw);
+
+ if (!chassis->c_med_sw) {
+ if (uname(&un) < 0) {
+ log_warn("rpc", "Could not get default uname. Will continue anyway.");
+ local_chassis->c_med_sw = NULL;
+ } else {
+ local_chassis->c_med_sw = strdup(un.release);
+ }
+ } else {
+ local_chassis->c_med_sw = strdup(chassis->c_med_sw);
+ }
+ }
+
+ free(local_chassis->c_med_fw);
+ local_chassis->c_med_fw = (!chassis->c_med_fw) ? dmi_fw() : strdup(chassis->c_med_fw);
+
+ free(local_chassis->c_med_sn);
+ local_chassis->c_med_sn = (!chassis->c_med_sn) ? dmi_sn() : strdup(chassis->c_med_sn);
+
+ free(local_chassis->c_med_manuf);
+ local_chassis->c_med_manuf = (!chassis->c_med_manuf) ? dmi_manuf() : strdup(chassis->c_med_manuf);
+
+ free(local_chassis->c_med_model);
+ local_chassis->c_med_model = (!chassis->c_med_model) ? dmi_model() : strdup(chassis->c_med_model);
+
+ free(local_chassis->c_med_asset);
+ local_chassis->c_med_asset = (!chassis->c_med_asset) ? dmi_asset() : strdup(chassis->c_med_asset);
+
+ log_debug("rpc", "change hardware-revision to: %s", local_chassis->c_med_hw);
+ log_debug("rpc", "change software-revision to: %s", local_chassis->c_med_sw);
+ log_debug("rpc", "change firmware-revision to: %s", local_chassis->c_med_fw);
+ log_debug("rpc", "change serial-number to: %s", local_chassis->c_med_sn);
+ log_debug("rpc", "change manufacturer to: %s", local_chassis->c_med_manuf);
+ log_debug("rpc", "change model to: %s", local_chassis->c_med_model);
+ log_debug("rpc", "change asset to: %s", local_chassis->c_med_asset);
+
+ lldpd_chassis_cleanup(chassis, 1);
+
+ ssize_t output_len = lldpd_chassis_serialize(local_chassis, output);
+ if (output_len <= 0) {
+ *type = NONE;
+ return 0;
+ }
+
+ return output_len;
+}
+#endif /* ENABLE_LLDPMED */
+
/* Return the local chassis.
Input: nothing.
Output: local chassis (lldpd_chassis)
{ GET_INTERFACES, "Get interfaces", client_handle_get_interfaces },
{ GET_INTERFACE, "Get interface", client_handle_get_interface },
{ GET_DEFAULT_PORT, "Get default port", client_handle_get_default_port },
+#ifdef ENABLE_LLDPMED
+ { SET_CHASSIS, "Set local chassis", client_handle_set_local_chassis },
+#endif
{ GET_CHASSIS, "Get local chassis", client_handle_get_local_chassis },
{ SET_PORT, "Set port", client_handle_set_port },
{ SUBSCRIBE, "Subscribe", client_handle_subscribe },
#ifdef ENABLE_LLDPMED
static void
-lldpd_med(struct lldpd_chassis *chassis)
+lldpd_med(struct lldpd *cfg, struct utsname *un)
{
static short int once = 0;
- if (!once) {
- chassis->c_med_hw = dmi_hw();
- chassis->c_med_fw = dmi_fw();
- chassis->c_med_sn = dmi_sn();
- chassis->c_med_manuf = dmi_manuf();
- chassis->c_med_model = dmi_model();
- chassis->c_med_asset = dmi_asset();
+ if (!once && cfg) {
+ LOCAL_CHASSIS(cfg)->c_med_hw = dmi_hw();
+ LOCAL_CHASSIS(cfg)->c_med_fw = dmi_fw();
+ LOCAL_CHASSIS(cfg)->c_med_sn = dmi_sn();
+ LOCAL_CHASSIS(cfg)->c_med_manuf = dmi_manuf();
+ LOCAL_CHASSIS(cfg)->c_med_model = dmi_model();
+ LOCAL_CHASSIS(cfg)->c_med_asset = dmi_asset();
+ if (un) {
+ if (LOCAL_CHASSIS(cfg)->c_med_sw)
+ free(LOCAL_CHASSIS(cfg)->c_med_sw);
+
+ if (cfg->g_config.c_advertise_version)
+ LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un->release);
+ else
+ LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
+ }
once = 1;
}
}
#ifdef ENABLE_LLDPMED
if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
- lldpd_med(LOCAL_CHASSIS(cfg));
- free(LOCAL_CHASSIS(cfg)->c_med_sw);
- if (cfg->g_config.c_advertise_version)
- LOCAL_CHASSIS(cfg)->c_med_sw = strdup(un.release);
- else
- LOCAL_CHASSIS(cfg)->c_med_sw = strdup("Unknown");
+ lldpd_med(cfg, &un);
#endif
if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
(LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
#define CONN_STATE_GET_DEFAULT_PORT_SEND 15
#define CONN_STATE_GET_DEFAULT_PORT_RECV 16
#define CONN_STATE_WATCHING 17
+#define CONN_STATE_SET_CHASSIS_SEND 18
+#define CONN_STATE_SET_CHASSIS_RECV 19
+
int state; /* Current state */
/* Data attached to the state. It is used to check that we are using the
* same data as a previous call until the state machine goes to
}
}
+#ifdef ENABLE_LLDPMED
+static lldpctl_atom_t*
+_lldpctl_atom_set_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key,
+ const char *value)
+{
+ struct _lldpctl_atom_chassis_t *p =
+ (struct _lldpctl_atom_chassis_t *) atom;
+ struct lldpd_chassis *chassis = p->chassis;
+
+ char *canary = NULL;
+
+ int rc;
+
+ switch (key) {
+ case lldpctl_k_chassis_med_inventory_hw:
+ free(chassis->c_med_hw);
+ chassis->c_med_hw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_sw:
+ free(chassis->c_med_sw);
+ chassis->c_med_sw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_fw:
+ free(chassis->c_med_fw);
+ chassis->c_med_fw = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_sn:
+ free(chassis->c_med_sn);
+ chassis->c_med_sn = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_manuf:
+ free(chassis->c_med_manuf);
+ chassis->c_med_manuf = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_model:
+ free(chassis->c_med_model);
+ chassis->c_med_model = xstrdup(value);
+ break;
+ case lldpctl_k_chassis_med_inventory_asset:
+ free(chassis->c_med_asset);
+ chassis->c_med_asset = xstrdup(value);
+ break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ if (asprintf(&canary, "%d%s", key, value ? value : "(NULL)") == -1) {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOMEM);
+ return NULL;
+ }
+
+ rc = _lldpctl_do_something(atom->conn,
+ CONN_STATE_SET_CHASSIS_SEND, CONN_STATE_SET_CHASSIS_RECV,
+ canary,
+ SET_CHASSIS, chassis, &MARSHAL_INFO(lldpd_chassis),
+ NULL, NULL);
+
+ free(canary);
+ if (rc == 0)
+ return atom;
+ return NULL;
+}
+#endif /* ENABLE_LLDPMED */
+
static const char*
_lldpctl_atom_get_str_chassis(lldpctl_atom_t *atom, lldpctl_key_t key)
{
.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 };
+ .get_buffer = _lldpctl_atom_get_buf_chassis,
+#ifdef ENABLE_LLDPMED
+ .set_str = _lldpctl_atom_set_str_chassis,
+#endif
+ };
ATOM_BUILDER_REGISTER(chassis, 3);
lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent);
}
+char*
+xstrdup(const char *str)
+{
+ if (!str) return NULL;
+ return strdup(str);
+}
+
int _lldpctl_atom_new_any_list(lldpctl_atom_t *atom, va_list ap);
void _lldpctl_atom_free_any_list(lldpctl_atom_t *atom);
+char *xstrdup(const char *);
+
lldpctl_k_chassis_med_type = 1900, /**< `(IS)` Chassis MED type. See `LLDP_MED_CLASS_*` */
lldpctl_k_chassis_med_cap, /**< `(I)` Available MED capabilitied. See `LLDP_MED_CAP_*` */
- lldpctl_k_chassis_med_inventory_hw, /**< `(S)` LLDP MED inventory "Hardware Revision" */
- lldpctl_k_chassis_med_inventory_sw, /**< `(S)` LLDP MED inventory "Software Revision" */
- lldpctl_k_chassis_med_inventory_fw, /**< `(S)` LLDP MED inventory "Firmware Revision" */
- lldpctl_k_chassis_med_inventory_sn, /**< `(S)` LLDP MED inventory "Serial Number" */
- lldpctl_k_chassis_med_inventory_manuf, /**< `(S)` LLDP MED inventory "Manufacturer" */
- lldpctl_k_chassis_med_inventory_model, /**< `(S)` LLDP MED inventory "Model" */
- lldpctl_k_chassis_med_inventory_asset, /**< `(S)` LLDP MED inventory "Asset ID" */
+ lldpctl_k_chassis_med_inventory_hw, /**< `(S,W)` LLDP MED inventory "Hardware Revision" */
+ lldpctl_k_chassis_med_inventory_sw, /**< `(S,W)` LLDP MED inventory "Software Revision" */
+ lldpctl_k_chassis_med_inventory_fw, /**< `(S,W)` LLDP MED inventory "Firmware Revision" */
+ lldpctl_k_chassis_med_inventory_sn, /**< `(S,W)` LLDP MED inventory "Serial Number" */
+ lldpctl_k_chassis_med_inventory_manuf, /**< `(S,W)` LLDP MED inventory "Manufacturer" */
+ lldpctl_k_chassis_med_inventory_model, /**< `(S,W)` LLDP MED inventory "Model" */
+ lldpctl_k_chassis_med_inventory_asset, /**< `(S,W)` LLDP MED inventory "Asset ID" */
lldpctl_k_port_med_policies = 2000, /**< `(AL,WO)` MED policies attached to a port. */
lldpctl_k_med_policy_type, /**< `(IS,W)` MED policy app type. See `LLDP_MED_APPTYPE_*`. 0 if a policy is not defined. */