From 8ef9c766be010f465bc750a9853961a04b6dccd4 Mon Sep 17 00:00:00 2001 From: Harshal Gohel Date: Mon, 11 Apr 2022 18:12:50 +0530 Subject: [PATCH] med: Add configure inventory commands 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` --- src/client/Makefile.am | 2 +- src/client/client.h | 1 + src/client/conf-inv.c | 215 ++++++++++++++++++++++++++++++++++++++++ src/client/conf.c | 1 + src/ctl.h | 1 + src/daemon/client.c | 83 ++++++++++++++++ src/daemon/lldpd.c | 32 +++--- src/lib/atom.h | 3 + src/lib/atoms/chassis.c | 71 ++++++++++++- src/lib/helpers.c | 7 ++ src/lib/helpers.h | 2 + src/lib/lldpctl.h | 14 +-- 12 files changed, 409 insertions(+), 23 deletions(-) create mode 100644 src/client/conf-inv.c diff --git a/src/client/Makefile.am b/src/client/Makefile.am index d1c16872..23a3225c 100644 --- a/src/client/Makefile.am +++ b/src/client/Makefile.am @@ -13,7 +13,7 @@ uninstall-local: 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 \ diff --git a/src/client/client.h b/src/client/client.h index 84e6e6c6..78a074e2 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -148,6 +148,7 @@ void register_commands_configure(struct cmd_node *); 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 *); diff --git a/src/client/conf-inv.c b/src/client/conf-inv.c new file mode 100644 index 00000000..6b043f21 --- /dev/null +++ b/src/client/conf-inv.c @@ -0,0 +1,215 @@ +/* -*- mode: c; c-file-style: "openbsd" -*- */ +/* + * SPDX-FileCopyrightText: 2022 Koninklijke Philips N.V. + * SPDX-License-Identifier: ISC + */ + +#include +#include + +#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); +} + diff --git a/src/client/conf.c b/src/client/conf.c index ba5743f7..72688b2a 100644 --- a/src/client/conf.c +++ b/src/client/conf.c @@ -45,5 +45,6 @@ register_commands_configure(struct cmd_node *root) 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); } diff --git a/src/ctl.h b/src/ctl.h index 86425b62..7cb4ced9 100644 --- a/src/ctl.h +++ b/src/ctl.h @@ -30,6 +30,7 @@ enum hmsg_type { 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 */ diff --git a/src/daemon/client.c b/src/daemon/client.c index 0d0f3ea3..56e57590 100644 --- a/src/daemon/client.c +++ b/src/daemon/client.c @@ -18,6 +18,10 @@ #include "lldpd.h" #include "trace.h" +#ifdef ENABLE_LLDPMED +#include +#endif + static ssize_t client_handle_none(struct lldpd *cfg, enum hmsg_type *type, void *input, int input_len, void **output, int *subscribed) @@ -273,6 +277,82 @@ client_handle_get_interfaces(struct lldpd *cfg, enum hmsg_type *type, 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) @@ -572,6 +652,9 @@ static struct client_handle client_handles[] = { { 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 }, diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index 22ae7463..6d885347 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -1156,16 +1156,25 @@ lldpd_send(struct lldpd_hardware *hardware) #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; } } @@ -1242,12 +1251,7 @@ lldpd_update_localchassis(struct lldpd *cfg) #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)) diff --git a/src/lib/atom.h b/src/lib/atom.h index 0b1d4bc0..66bf692a 100644 --- a/src/lib/atom.h +++ b/src/lib/atom.h @@ -55,6 +55,9 @@ struct lldpctl_conn_t { #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 diff --git a/src/lib/atoms/chassis.c b/src/lib/atoms/chassis.c index f0012df7..1d2ed27b 100644 --- a/src/lib/atoms/chassis.c +++ b/src/lib/atoms/chassis.c @@ -99,6 +99,71 @@ _lldpctl_atom_get_atom_chassis(lldpctl_atom_t *atom, lldpctl_key_t key) } } +#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) { @@ -222,6 +287,10 @@ static struct atom_builder 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 }; + .get_buffer = _lldpctl_atom_get_buf_chassis, +#ifdef ENABLE_LLDPMED + .set_str = _lldpctl_atom_set_str_chassis, +#endif + }; ATOM_BUILDER_REGISTER(chassis, 3); diff --git a/src/lib/helpers.c b/src/lib/helpers.c index f7ea51d0..2fa0f78a 100644 --- a/src/lib/helpers.c +++ b/src/lib/helpers.c @@ -71,3 +71,10 @@ _lldpctl_atom_free_any_list(lldpctl_atom_t *atom) lldpctl_atom_dec_ref((lldpctl_atom_t *)plist->parent); } +char* +xstrdup(const char *str) +{ + if (!str) return NULL; + return strdup(str); +} + diff --git a/src/lib/helpers.h b/src/lib/helpers.h index d1b9415a..8d63ec56 100644 --- a/src/lib/helpers.h +++ b/src/lib/helpers.h @@ -21,3 +21,5 @@ int map_reverse_lookup(lldpctl_map_t *list, const char *string); 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 *); + diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index d152e2b7..56b3bf48 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -800,13 +800,13 @@ typedef enum { 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. */ -- 2.39.5