lldpd (1.0.15)
+ * Changes
+ + Add configure command to override system capabilities (#526)
* Fix:
+ Really don't send VLANs when there are too many (#520)
+ Ignore temporary IPv6 addresses (#521)
return 1;
}
+static int
+cmd_capability(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, void *arg)
+{
+ log_debug("lldpctl", "set capabilities");
+
+ int ret = 0;
+ lldpctl_atom_t *config = lldpctl_get_configuration(conn);
+ lldpctl_atom_t *chassis = NULL;
+ if (config == NULL) {
+ log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
+ lldpctl_last_strerror(conn));
+ goto cmd_capability_end;
+ }
+
+ if (!strcmp(arg, "configure")) {
+
+ const char *s = cmdenv_get(env, "capabilities");
+ if (s) {
+ chassis = lldpctl_get_local_chassis(conn);
+ if (chassis == NULL) {
+ log_warnx("lldpctl", "unable to get local chassis from lldpd. %s",
+ lldpctl_last_strerror(conn));
+ goto cmd_capability_end;
+ }
+ u_int16_t value = 0;
+ const char delim[] = ",";
+ char *s_copy = strdup(s);
+ char *token = strtok(s_copy, delim);
+ while (token != NULL) {
+ if (!strcmp(token, "other")) {
+ value |= LLDP_CAP_OTHER;
+ } else if (!strcmp(token, "repeater")) {
+ value |= LLDP_CAP_REPEATER;
+ } else if (!strcmp(token, "bridge")) {
+ value |= LLDP_CAP_BRIDGE;
+ } else if (!strcmp(token, "wlan")) {
+ value |= LLDP_CAP_WLAN;
+ } else if (!strcmp(token, "router")) {
+ value |= LLDP_CAP_ROUTER;
+ } else if (!strcmp(token, "telephone")) {
+ value |= LLDP_CAP_TELEPHONE;
+ } else if (!strcmp(token, "docsis")) {
+ value |= LLDP_CAP_DOCSIS;
+ } else if (!strcmp(token, "station")) {
+ value |= LLDP_CAP_STATION;
+ } else {
+ log_warnx("lldpctl", "capability %s not found", token);
+ }
+ token = strtok(NULL, delim);
+ }
+ free(s_copy);
+
+ if (lldpctl_atom_set_int(chassis, lldpctl_k_chassis_cap_enabled, value) == NULL) {
+ log_warnx("lldpctl", "unable to set system capabilities. %s",
+ lldpctl_last_strerror(conn));
+ goto cmd_capability_end;
+ }
+ if (lldpctl_atom_set_int(config, lldpctl_k_config_chassis_cap_override, 1) == NULL) {
+ log_warnx("lldpctl", "unable to set system capabilities override. %s",
+ lldpctl_last_strerror(conn));
+ goto cmd_capability_end;
+ }
+ log_debug("lldpctl", "system capabilities set to new value %d",
+ value);
+ }
+ } else {
+ if (lldpctl_atom_set_int(config, lldpctl_k_config_chassis_cap_override, 0) == NULL) {
+ log_warnx("lldpctl", "unable to set system capabilities to not override. %s",
+ lldpctl_last_strerror(conn));
+ goto cmd_capability_end;
+ }
+ }
+
+ ret = 1;
+ cmd_capability_end:
+ lldpctl_atom_dec_ref(chassis);
+ lldpctl_atom_dec_ref(config);
+ return ret;
+}
+
static int
cmd_update_descriptions(struct lldpctl_conn_t *conn, struct writer *w,
struct cmd_env *env, void *arg)
}
}
+static void
+register_commands_capabilities(struct cmd_node *configure, struct cmd_node *unconfigure)
+{
+ struct cmd_node *configure_capability = commands_new(
+ configure,
+ "capabilities", "Capabilities configuration",
+ cmd_check_no_env, NULL, "ports");
+ struct cmd_node *unconfigure_capability = commands_new(
+ unconfigure,
+ "capabilities", "Capabilities configuration",
+ cmd_check_no_env, NULL, "ports");
+
+ /* Override */
+ commands_new(
+ commands_new(
+ commands_new(configure_capability,
+ "enabled", "Override capabilities",
+ NULL, NULL, NULL),
+ NULL, " Set of capabilities separated by commas",
+ NULL, cmd_store_env_value, "capabilities"),
+ NEWLINE, "Override capabilities",
+ NULL, cmd_capability, "configure");
+
+ /* Do not override */
+ commands_new(
+ commands_new(unconfigure_capability,
+ "enabled", "Do not override capabilities",
+ NULL, NULL, NULL),
+ NEWLINE, "Do not override capabilities",
+ NULL, cmd_capability, "unconfigure");
+}
+
/**
* Register `configure system` commands.
*
NEWLINE, "Don't enable promiscuous mode on managed interfaces",
NULL, cmd_iface_promisc, NULL);
+ register_commands_capabilities(configure_system, unconfigure_system);
register_commands_srcmac_type(configure_system);
}
N(lldpctl_atom_get_str(configuration, lldpctl_k_config_platform)));
tag_datatag(w, "hostname", "Override system name with",
N(lldpctl_atom_get_str(configuration, lldpctl_k_config_hostname)));
+ tag_datatag(w, "capabilities", "Override system capabilities",
+ lldpctl_atom_get_int(configuration, lldpctl_k_config_chassis_cap_override)?
+ "yes":"no");
tag_datatag(w, "advertise-version", "Advertise version",
lldpctl_atom_get_int(configuration, lldpctl_k_config_advertise_version)?
"yes":"no");
option undoes the previous one.
.Ed
+.Cd configure
+.Cd system capabilities enabled Ar capabilities
+.Bd -ragged -offset XXXXXX
+Override system capabilities with the provided value instead of using
+kernel information. Several capabilities can be specified separated by
+commas. Only available capabilities can be enabled. Valid capabilities are:
+.Bl -tag -width "XXX." -compact -offset XX
+.It Sy other
+.It Sy repeater
+.It Sy bridge
+.It Sy wlan
+.It Sy router
+.It Sy telephone
+.It Sy docsis
+.It Sy station
+.El
+Here is an example of use:
+.D1 configure system capabilities enabled bridge,router
+.Pp
+.Ed
+
+.Cd unconfigure
+.Cd system capabilities enabled
+.Bd -ragged -offset XXXXXX
+Do not override capabilities and use the kernel information. This option
+undoes the previous one.
+.Ed
+
.Cd configure
.Cd system interface pattern Ar pattern
.Bd -ragged -offset XXXXXX
#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,
cfg->g_config.c_cap_advertise = config->c_cap_advertise;
levent_update_now(cfg);
}
+ if (CHANGED(c_cap_override)) {
+ log_debug("rpc", "%s chassis capabilities override",
+ config->c_cap_override?"enable":"disable");
+ cfg->g_config.c_cap_override = config->c_cap_override;
+ levent_update_now(cfg);
+ }
if (CHANGED(c_mgmt_advertise)) {
log_debug("rpc", "%s management addresses advertisement",
config->c_mgmt_advertise?"enable":"disable");
return output_len;
}
-#ifdef ENABLE_LLDPMED
/**
- * Set local chassis inventory info
+ * Set local chassis info
* Input: chassis object
* Output: updated chassis object
*/
{
struct lldpd_chassis *chassis = NULL;
struct lldpd_chassis *local_chassis = NULL;
+#ifdef ENABLE_LLDPMED
struct utsname un;
+#endif
log_debug("rpc", "client request a change in chassis configuration");
if (lldpd_chassis_unserialize(input, input_len, &chassis) <= 0) {
local_chassis = LOCAL_CHASSIS(cfg);
+#ifdef ENABLE_LLDPMED
free(local_chassis->c_med_hw);
local_chassis->c_med_hw = (!chassis->c_med_hw) ? dmi_hw() : strdup(chassis->c_med_hw);
free(local_chassis->c_med_asset);
local_chassis->c_med_asset = (!chassis->c_med_asset) ? dmi_asset() : strdup(chassis->c_med_asset);
+#endif
+
+ if(chassis->c_cap_enabled != local_chassis->c_cap_enabled){
+ local_chassis->c_cap_enabled = chassis->c_cap_enabled;
+ log_debug("rpc", "change capabilities enabled to: %d", local_chassis->c_cap_enabled);
+ }
+#ifdef ENABLE_LLDPMED
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 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);
+#endif
lldpd_chassis_cleanup(chassis, 1);
return output_len;
}
-#endif /* ENABLE_LLDPMED */
/* Return the local chassis.
Input: nothing.
{ 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 },
struct lldpd_hardware *hardware;
char *name = NULL;
- LOCAL_CHASSIS(cfg)->c_cap_enabled &=
- ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
- TAILQ_FOREACH(iface, interfaces, next) {
- if (iface->type & IFACE_BRIDGE_T)
- LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
- if (iface->type & IFACE_WIRELESS_T)
- LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
+ if (!cfg->g_config.c_cap_override) {
+ LOCAL_CHASSIS(cfg)->c_cap_enabled &=
+ ~(LLDP_CAP_BRIDGE | LLDP_CAP_WLAN | LLDP_CAP_STATION);
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->type & IFACE_BRIDGE_T)
+ LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
+ if (iface->type & IFACE_WIRELESS_T)
+ LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
+ }
+ if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
+ (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
+ LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
}
- if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
- (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
- LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
/* Do not modify the chassis if it's already set to a MAC address or if
* it's set to a local address equal to the user-provided
if (cfg->g_config.c_platform == NULL)
cfg->g_config.c_platform = strdup(un.sysname);
- /* Check routing */
- if (lldpd_routing_enabled(cfg)) {
- log_debug("localchassis", "routing is enabled, enable router capability");
- LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_ROUTER;
- } else
- LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER;
+ if (!cfg->g_config.c_cap_override) {
+ /* Check routing */
+ if (lldpd_routing_enabled(cfg)) {
+ log_debug("localchassis", "routing is enabled, enable router capability");
+ LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_ROUTER;
+ } else
+ LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_ROUTER;
#ifdef ENABLE_LLDPMED
- if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
- LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
- lldpd_med(cfg, &un);
+ if (LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_TELEPHONE)
+ LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_TELEPHONE;
+ lldpd_med(cfg, &un);
#endif
- if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
- (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
- LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
- else if (LOCAL_CHASSIS(cfg)->c_cap_enabled != LLDP_CAP_STATION)
- LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_STATION;
+ if ((LOCAL_CHASSIS(cfg)->c_cap_available & LLDP_CAP_STATION) &&
+ (LOCAL_CHASSIS(cfg)->c_cap_enabled == 0))
+ LOCAL_CHASSIS(cfg)->c_cap_enabled = LLDP_CAP_STATION;
+ else if (LOCAL_CHASSIS(cfg)->c_cap_enabled != LLDP_CAP_STATION)
+ LOCAL_CHASSIS(cfg)->c_cap_enabled &= ~LLDP_CAP_STATION;
+ }
/* Set chassis ID if needed. This is only done if chassis ID
has not been set previously (with the MAC address of an
2. Update local chassis information
*/
log_debug("loop", "start new loop");
- LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
+ if(!cfg->g_config.c_cap_override)
+ LOCAL_CHASSIS(cfg)->c_cap_enabled = 0;
/* Information for local ports is triggered even when it is possible to
* update them on some other event because we want to refresh them if we
* missed something. */
calloc(1, sizeof(struct lldpd_chassis))) == NULL)
fatal("localchassis", NULL);
cfg->g_config.c_cap_advertise = 1;
+ cfg->g_config.c_cap_override = 0;
lchassis->c_cap_available = LLDP_CAP_BRIDGE | LLDP_CAP_WLAN |
LLDP_CAP_ROUTER | LLDP_CAP_STATION;
cfg->g_config.c_mgmt_advertise = 1;
}
}
+static lldpctl_atom_t*
+_lldpctl_atom_set_int_chassis(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ int rc;
+ char *canary = NULL;
+ struct _lldpctl_atom_chassis_t *c =
+ (struct _lldpctl_atom_chassis_t *) atom;
+ struct lldpd_chassis chassis;
+ memcpy(&chassis, c->chassis, sizeof(struct lldpd_chassis));
+
+ switch (key) {
+ case lldpctl_k_chassis_cap_enabled:
+ chassis.c_cap_enabled = c->chassis->c_cap_enabled = chassis.c_cap_available & value;
+ break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ if (asprintf(&canary, "%d%ld", key, value) == -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;
+}
+
static long int
_lldpctl_atom_get_int_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,
+ .set_int = _lldpctl_atom_set_int_chassis,
.get_buffer = _lldpctl_atom_get_buf_chassis,
#ifdef ENABLE_LLDPMED
.set_str = _lldpctl_atom_set_str_chassis,
return c->config->c_promisc;
case lldpctl_k_config_chassis_cap_advertise:
return c->config->c_cap_advertise;
+ case lldpctl_k_config_chassis_cap_override:
+ return c->config->c_cap_override;
case lldpctl_k_config_chassis_mgmt_advertise:
return c->config->c_mgmt_advertise;
#ifdef ENABLE_LLDPMED
case lldpctl_k_config_chassis_cap_advertise:
config.c_cap_advertise = c->config->c_cap_advertise = value;
break;
+ case lldpctl_k_config_chassis_cap_override:
+ config.c_cap_override = c->config->c_cap_override = value;
+ break;
case lldpctl_k_config_chassis_mgmt_advertise:
config.c_mgmt_advertise = c->config->c_mgmt_advertise = value;
break;
lldpctl_k_config_cid_string, /**< `(S,WON)` User defined string for the chassis ID */
lldpctl_k_config_perm_iface_pattern, /**< `(S,WON)` Pattern of permanent interfaces */
lldpctl_k_config_tx_interval_ms, /**< `(I,WO)` Transmit interval in milliseconds. Set to -1 to transmit now. */
+ lldpctl_k_config_chassis_cap_override, /**< `(I,WO)` Override chassis capabilities */
lldpctl_k_interface_name = 1000, /**< `(S)` The interface name. */
lldpctl_k_chassis_id, /**< `(BS)` The ID of this chassis. */
lldpctl_k_chassis_name, /**< `(S)` The name of this chassis. */
lldpctl_k_chassis_descr, /**< `(S)` The description of this chassis. */
- lldpctl_k_chassis_cap_available, /**< `(I)` Available capabalities (see `LLDP_CAP_*`) */
+ lldpctl_k_chassis_cap_available, /**< `(I)` Available capabilities (see `LLDP_CAP_*`) */
lldpctl_k_chassis_cap_enabled, /**< `(I)` Enabled capabilities (see `LLDP_CAP_*`) */
lldpctl_k_chassis_mgmt, /**< `(AL)` List of management addresses */
lldpctl_k_chassis_ttl, /**< Deprecated */
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_cap, /**< `(I)` Available MED capabilities. See `LLDP_MED_CAP_*` */
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" */
int c_set_ifdescr; /* Set interface description */
int c_promisc; /* Interfaces should be in promiscuous mode */
int c_cap_advertise; /* Chassis capabilities advertisement */
+ int c_cap_override; /* Override chassis capabilities enabled */
int c_mgmt_advertise; /* Management addresses advertisement */
#ifdef ENABLE_LLDPMED
assert result.returncode == 0
out = lldpcli("-f", "keyvalue", "show", "configuration")
assert out['configuration.config.{}'.format(name)] == str(expected)
+
+
+def test_config_capabilities(lldpd1, lldpcli, namespaces):
+ with namespaces(1):
+ out = lldpcli("-f", "keyvalue", "show", "chassis")
+
+ # Save values to check after unconfigure
+ bridge = out['local-chassis.chassis.Bridge.enabled']
+ router = out['local-chassis.chassis.Router.enabled']
+ wlan = out['local-chassis.chassis.Wlan.enabled']
+ station = out['local-chassis.chassis.Station.enabled']
+
+ # Configure only bridge capability
+ lldpcli("configure", "system", "capabilities", "enabled", "bridge")
+
+ # Check only bridge capability on
+ out = lldpcli("-f", "keyvalue", "show", "chassis")
+ assert out['local-chassis.chassis.Bridge.enabled'] == "on"
+ assert out['local-chassis.chassis.Router.enabled'] == "off"
+ assert out['local-chassis.chassis.Wlan.enabled'] == "off"
+ assert out['local-chassis.chassis.Station.enabled'] == "off"
+
+ # Configure router and wlan capabilities.
+ lldpcli("configure", "system", "capabilities", "enabled", "router,wlan")
+
+ # This shoud enable only router and wlan and set to off the bridge capability again
+ out = lldpcli("-f", "keyvalue", "show", "chassis")
+ assert out['local-chassis.chassis.Bridge.enabled'] == "off"
+ assert out['local-chassis.chassis.Router.enabled'] == "on"
+ assert out['local-chassis.chassis.Wlan.enabled'] == "on"
+ assert out['local-chassis.chassis.Station.enabled'] == "off"
+
+ # Unconfigure system capabilities and use again the kernel information to enable capabilities
+ lldpcli("unconfigure", "system", "capabilities", "enabled")
+
+ # Check if the capabilities have the same values as before start the configurations
+ out = lldpcli("-f", "keyvalue", "show", "chassis")
+ assert out['local-chassis.chassis.Bridge.enabled'] == bridge
+ assert out['local-chassis.chassis.Router.enabled'] == router
+ assert out['local-chassis.chassis.Wlan.enabled'] == wlan
+ assert out['local-chassis.chassis.Station.enabled'] == station