chassisid".
+ Port description can be overriden directly with "configure lldp
portdescription".
+ + Command "configure system interface permanent" enables one to
+ specify a pattern for interfaces to be kept in memory even when
+ they are removed from the system.
* Fix:
+ Ensure chassis-related changes are propagated immediately.
+ Ensure management address change is correctly detected.
return 1;
}
+static int
+cmd_perm_iface_pattern(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, void *arg)
+{
+ log_debug("lldpctl", "set permanent iface pattern");
+
+ lldpctl_atom_t *config = lldpctl_get_configuration(conn);
+ if (config == NULL) {
+ log_warnx("lldpctl", "unable to get configuration from lldpd. %s",
+ lldpctl_last_strerror(conn));
+ return 0;
+ }
+
+ const char *value = cmdenv_get(env, "iface-pattern");
+ if (lldpctl_atom_set_str(config,
+ lldpctl_k_config_perm_iface_pattern,
+ value) == NULL) {
+ log_warnx("lldpctl", "unable to set permanent iface pattern. %s",
+ lldpctl_last_strerror(conn));
+ lldpctl_atom_dec_ref(config);
+ return 0;
+ }
+ log_info("lldpctl", "permanent iface pattern set to new value %s",
+ value?value:"(none)");
+ lldpctl_atom_dec_ref(config);
+ return 1;
+}
+
static int
cmd_iface_promisc(struct lldpctl_conn_t *conn, struct writer *w,
struct cmd_env *env, void *arg)
commands_new(unconfigure_interface,
"pattern", "Delete any interface pattern",
NULL, NULL, NULL),
- NEWLINE, "Delete any interface pattern",
+ NEWLINE, "Clear interface pattern",
NULL, cmd_iface_pattern, NULL);
+ commands_new(
+ commands_new(
+ commands_new(configure_interface,
+ "permanent", "Set permanent interface pattern",
+ NULL, NULL, NULL),
+ NULL, "Permanent interface pattern (comma-separated list of wildcards)",
+ NULL, cmd_store_env_value, "iface-pattern"),
+ NEWLINE, "Set permanent interface pattern",
+ NULL, cmd_perm_iface_pattern, NULL);
+ commands_new(
+ commands_new(unconfigure_interface,
+ "permanent", "Clear permanent interface pattern",
+ NULL, NULL, NULL),
+ NEWLINE, "Delete any interface pattern",
+ NULL, cmd_perm_iface_pattern, NULL);
+
commands_new(
commands_new(configure_interface,
"description", "Update interface descriptions with neighbor name",
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, "perm-iface-pattern", "Permanent interface pattern",
+ N(lldpctl_atom_get_str(configuration, lldpctl_k_config_perm_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, "cid-string", "Override chassis ID with",
physical interfaces. This option undoes the previous one.
.Ed
+.Cd configure
+.Cd system interface permanent Ar pattern
+.Bd -ragged -offset XXXXXX
+Specify interfaces whose configuration is permanently kept by
+.Nm lldpd .
+By default,
+.Nm lldpd
+disregard any data about interfaces when they are removed from the
+system (statistics, custom configuration). This option allows one to
+specify a pattern similar to the interface pattern. If an interface
+disappear but matches the pattern, its data is kept in memory and
+reused if the interface reappear at some point. For example, on Linux,
+one could use the pattern
+.Em eth*,eno*,enp* ,
+which should match fixed interfaces on most systems.
+.Ed
+
+.Cd unconfigure
+.Cd system interface permanent
+.Bd -ragged -offset XXXXXX
+Remove any previously configured permanent interface pattern. Any
+interface removed from the system will be forgotten. This option
+undoes the previous one.
+.Ed
+
.Cd configure
.Cd system interface description
.Bd -ragged -offset XXXXXX
cfg->g_config.c_iface_pattern = xstrdup(config->c_iface_pattern);
levent_update_now(cfg);
}
+ if (CHANGED_STR(c_perm_ifaces)) {
+ log_debug("rpc", "change permanent interface pattern to %s",
+ config->c_perm_ifaces?config->c_perm_ifaces:"(NULL)");
+ free(cfg->g_config.c_perm_ifaces);
+ cfg->g_config.c_perm_ifaces = xstrdup(config->c_perm_ifaces);
+ levent_update_now(cfg);
+ }
if (CHANGED_STR(c_mgmt_pattern)) {
log_debug("rpc", "change management pattern to %s",
config->c_mgmt_pattern?config->c_mgmt_pattern:"(NULL)");
{
struct lldpd_hardware *hardware;
TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
- if ((strcmp(hardware->h_ifname, name) == 0) &&
- (hardware->h_ifindex == index))
- break;
+ if (strcmp(hardware->h_ifname, name) == 0) {
+ if (hardware->h_flags == 0) {
+ hardware->h_ifindex = index;
+ break;
+ }
+ if (hardware->h_ifindex == index)
+ break;
+ }
}
return hardware;
}
hardware = hardware_next) {
hardware_next = TAILQ_NEXT(hardware, h_entries);
if (!hardware->h_flags) {
- TRACE(LLDPD_INTERFACES_DELETE(hardware->h_ifname));
- TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
- lldpd_remote_cleanup(hardware, notify_clients_deletion, 1);
- lldpd_hardware_cleanup(cfg, hardware);
+ int m = cfg->g_config.c_perm_ifaces?
+ pattern_match(hardware->h_ifname, cfg->g_config.c_perm_ifaces, 0):
+ 0;
+ switch (m) {
+ case 0:
+ log_debug("localchassis", "delete non-permanent interface %s",
+ hardware->h_ifname);
+ TRACE(LLDPD_INTERFACES_DELETE(hardware->h_ifname));
+ TAILQ_REMOVE(&cfg->g_hardware, hardware, h_entries);
+ lldpd_remote_cleanup(hardware, notify_clients_deletion, 1);
+ lldpd_hardware_cleanup(cfg, hardware);
+ break;
+ case 1:
+ case 2:
+ log_debug("localchassis", "do not delete %s, permanent",
+ hardware->h_ifname);
+ break;
+ }
} else {
lldpd_remote_cleanup(hardware, notify_clients_deletion,
!(hardware->h_flags & IFF_RUNNING));
res = c->config->c_mgmt_pattern; break;
case lldpctl_k_config_iface_pattern:
res = c->config->c_iface_pattern; break;
+ case lldpctl_k_config_perm_iface_pattern:
+ res = c->config->c_perm_ifaces; break;
case lldpctl_k_config_cid_pattern:
res = c->config->c_cid_pattern; break;
case lldpctl_k_config_cid_string:
int rc;
switch (key) {
+ case lldpctl_k_config_perm_iface_pattern:
+ if (!__lldpctl_atom_set_str_config(c,
+ &config.c_perm_ifaces, &c->config->c_perm_ifaces,
+ value))
+ return NULL;
+ break;
case lldpctl_k_config_iface_pattern:
if (!__lldpctl_atom_set_str_config(c,
&config.c_iface_pattern, &c->config->c_iface_pattern,
lldpctl_k_config_chassis_cap_advertise, /**< `(I,WO)` Enable or disable chassis capabilities advertisement */
lldpctl_k_config_chassis_mgmt_advertise, /**< `(I,WO)` Enable or disable management addresses advertisement */
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_interface_name = 1000, /**< `(S)` The interface name. */
free(config->c_cid_pattern);
free(config->c_cid_string);
free(config->c_iface_pattern);
+ free(config->c_perm_ifaces);
free(config->c_hostname);
free(config->c_platform);
free(config->c_description);
char *c_cid_pattern; /* Pattern to match interfaces to use for chassis ID */
char *c_cid_string; /* User defined string for chassis ID */
char *c_iface_pattern; /* Pattern to match interfaces to use */
+ char *c_perm_ifaces; /* Pattern to match interfaces to keep */
char *c_platform; /* Override platform description (for CDP) */
char *c_description; /* Override chassis description */
MARSHAL_STR(lldpd_config, c_cid_pattern)
MARSHAL_STR(lldpd_config, c_cid_string)
MARSHAL_STR(lldpd_config, c_iface_pattern)
+MARSHAL_STR(lldpd_config, c_perm_ifaces)
MARSHAL_STR(lldpd_config, c_hostname)
MARSHAL_STR(lldpd_config, c_platform)
MARSHAL_STR(lldpd_config, c_description)
assert 'lldp.eth3.port.power.device-type' not in out
+@pytest.mark.skipif('Dot3' not in pytest.config.lldpd.features,
+ reason="Dot3 not supported")
+def test_port_keep_configuration_of_permanent_ports(lldpd, lldpcli,
+ namespaces, links):
+ with namespaces(1):
+ links.dummy('eth3')
+ links.dummy('noteth3')
+ lldpd()
+ result = lldpcli(*("configure system interface permanent e*").split())
+ assert result.returncode == 0
+ result = lldpcli(*("configure dot3 power "
+ "pse supported enabled paircontrol powerpairs "
+ "spare class class-3").split())
+ assert result.returncode == 0
+ time.sleep(3)
+ links.remove('eth3')
+ links.remove('noteth3')
+ time.sleep(4)
+ # eth3 configuration is kept because it matches the permanent
+ # port pattern.
+ out = lldpcli("-f", "keyvalue", "show", "interfaces", "details")
+ assert out['lldp.eth3.port.power.device-type'] == 'PSE'
+ assert 'lldp.noteth3.port.power.device-type' not in out
+
+ links.dummy('eth3')
+ links.dummy('noteth3')
+ time.sleep(4)
+ # eth3 configuration is unchanged
+ out = lldpcli("-f", "keyvalue", "show", "interfaces", "details")
+ assert out['lldp.eth3.port.power.device-type'] == 'PSE'
+ # noteth3 inherited from default
+ assert out['lldp.noteth3.port.power.device-type'] == 'PSE'
+
+
def test_watch(lldpd1, lldpd, lldpcli, namespaces, links):
with namespaces(2):
lldpd()