return 1;
}
+static int
+cmd_set_vlan_pattern(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env,
+ const void *arg)
+{
+ lldpctl_atom_t *port;
+ const char *name;
+
+ const char *value = cmdenv_get(env, "vlan-pattern");
+
+ log_info("lldpctl", "VLAN pattern set to new value %s",value ? value : "(none)");
+
+ while ((port = cmd_iterate_on_ports(conn, env, &name))) {
+ if (lldpctl_atom_set_str(port, lldpctl_k_port_vlan_advertise_pattern, value) ==
+ NULL) {
+ log_warnx("lldpctl",
+ "unable to set VLAN pattern config on %s."
+ " %s",
+ name, lldpctl_last_strerror(conn));
+ }
+ }
+
+ return 1;
+}
+
+static int
+cmd_unset_vlan_pattern(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env,
+ const void *arg)
+{
+ log_debug("lldpctl", "unset VLAN pattern");
+ lldpctl_atom_t *port;
+ const char *name;
+
+ while ((port = cmd_iterate_on_ports(conn, env, &name))) {
+ if (lldpctl_atom_set_str(port, lldpctl_k_port_vlan_advertise_pattern, "*") ==
+ NULL) {
+ log_warnx("lldpctl",
+ "unable to set VLAN pattern config on %s."
+ " %s",
+ name, lldpctl_last_strerror(conn));
+ }
+ }
+
+ return 1;
+}
+
+
#ifdef ENABLE_CUSTOM
static int
cmd_custom_tlv_set(struct lldpctl_conn_t *conn, struct writer *w, struct cmd_env *env,
NEWLINE, "Disable VLAN tagging of transmitted LLDP frames", NULL,
cmd_vlan_tx, NULL);
+
+ /* Now handle vlan advertisements configuration. */
+ struct cmd_node *configure_lldp_vlan_advertisements = commands_new(configure_lldp,
+ "vlan-advertisements", "Configure vlan address advertisements", NULL, NULL, NULL);
+ commands_new(commands_new(commands_new(configure_lldp_vlan_advertisements, "pattern",
+ "Set VLAN pattern", NULL, NULL, NULL),
+ NULL, "VLAN pattern (comma-separated list of wildcards)",
+ NULL, cmd_store_env_value, "vlan-pattern"),
+ NEWLINE, "Set active VLAN pattern", NULL, cmd_set_vlan_pattern, NULL);
+
+ struct cmd_node *unconfigure_vlan_advertisements =
+ commands_new(unconfigure_lldp, "vlan-advertisements", "Unconfigure vlan address advertisements", NULL, NULL, NULL);
+ commands_new(commands_new(unconfigure_vlan_advertisements, "pattern",
+ "Delete any VLAN pattern", NULL, NULL, NULL),
+ NEWLINE, "Clear VLAN pattern", NULL, cmd_unset_vlan_pattern, NULL);
+
#ifdef ENABLE_CUSTOM
register_commands_configure_lldp_custom_tlvs(configure_lldp, unconfigure_lldp);
#endif
is specified, remove specific instances of custom TLV.
.Ed
+.Cd configure
+.Op ports Ar ethX Op ,...
+.Cd lldp vlan-advertisements pattern Ar pattern
+.Bd -ragged -offset XXXXXX
+Configure VLAN advertisements for the given port as a comma separated values (CSV).
+As for interfaces (described above), this option can use wildcards and inversions.
+Without this option,
+.Nm lldpd
+will advertise all VLANS.
+.Ed
+
+.Cd unconfigure
+.Op ports Ar ethX Op ,...
+.Cd lldp vlan-advertisements pattern
+.Bd -ragged -offset XXXXXX
+Remove any previously configured VLAN advertisements pattern for the given port.
+.Ed
+
.Cd configure lldp fast-start
.Cd enable | tx-interval Ar interval
.Bd -ragged -offset XXXXXX
port->p_vlan_tx_enabled = set->vlan_tx_enabled;
port->p_vlan_tx_tag = set->vlan_tx_tag;
}
+ if (set->vlan_advertise_pattern) {
+ log_debug("rpc", "requested change to VLAN advertise pattern");
+ free(port->p_vlan_advertise_pattern);
+ port->p_vlan_advertise_pattern = strdup(set->vlan_advertise_pattern);
+ }
#ifdef ENABLE_LLDPMED
if (set->med_policy && set->med_policy->type > 0) {
log_debug("rpc", "requested change to MED policy");
vlan_id = (i * 32) + bit;
if (asprintf(&name, "vlan%d", vlan_id) == -1) return;
+ //match vlan id with pattern
+ if (port->p_vlan_advertise_pattern &&
+ (PATTERN_MATCH_DENIED == pattern_match(name+4, port->p_vlan_advertise_pattern, 0))){
+ log_debug("interfaces", "exlude VLAN %s advertisement", name);
+ free(name);
+ return;
+ }
+
/* Check if the VLAN is already here. */
TAILQ_FOREACH (v, &port->p_vlans, v_entries)
if (strncmp(name, v->v_name, IFNAMSIZ) == 0) {
set.vlan_tx_tag = p->port->p_vlan_tx_tag;
set.vlan_tx_enabled = p->port->p_vlan_tx_enabled;
break;
+ case lldpctl_k_port_vlan_advertise_pattern:
+ set.vlan_advertise_pattern = p->port->p_vlan_advertise_pattern;
+ break;
#ifdef ENABLE_DOT3
case lldpctl_k_port_dot3_power:
if (value->type != atom_dot3_power) {
return NULL;
case lldpctl_k_port_descr:
return port->p_descr;
-
+ case lldpctl_k_port_vlan_advertise_pattern:
+ return port->p_vlan_advertise_pattern;
#ifdef ENABLE_DOT3
case lldpctl_k_port_dot3_mautype:
return map_lookup(operational_mau_type_values, port->p_macphy.mau_type);
free(port->p_descr);
port->p_descr = strdup(value);
break;
+ case lldpctl_k_port_vlan_advertise_pattern:
+ free(port->p_vlan_advertise_pattern);
+ port->p_vlan_advertise_pattern = strdup(value);
+ break;
default:
SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
return NULL;
lldpctl_k_port_status, /**< `(IS,WO)` Operational status of this (local) port */
lldpctl_k_port_chassis, /**< `(A)` Chassis associated to the port */
lldpctl_k_port_ttl, /**< `(I)` TTL for port, 0 if info is attached to chassis */
- lldpctl_k_port_vlan_tx, /**< `(I,W)` VLAN tag for TX on port, -1 VLAN disabled
- */
+ lldpctl_k_port_vlan_tx, /**< `(I,W)` VLAN tag for TX on port, -1 VLAN disabled */
+ lldpctl_k_port_vlan_advertise_pattern, /**< `(S,W)` Pattern of enabled vlan advertisements */
lldpctl_k_port_dot3_mfs = 1300, /**< `(I)` MFS */
lldpctl_k_port_dot3_aggregid, /**< `(I)` Port aggregation ID */
port->p_chassis->c_refcount--;
port->p_chassis = NULL;
}
+ free(port->p_vlan_advertise_pattern);
+ port->p_vlan_advertise_pattern = NULL;
#ifdef ENABLE_CUSTOM
lldpd_custom_list_cleanup(port);
#endif
u_int16_t p_ttl; /* TTL for remote port */
int p_vlan_tx_tag;
int p_vlan_tx_enabled;
-
+ char *p_vlan_advertise_pattern;
#ifdef ENABLE_DOT3
/* Dot3 stuff */
u_int32_t p_aggregid;
MARSHAL_IGNORE(lldpd_port, p_lastframe)
MARSHAL_FSTR(lldpd_port, p_id, p_id_len)
MARSHAL_STR(lldpd_port, p_descr)
+MARSHAL_STR(lldpd_port, p_vlan_advertise_pattern)
#ifdef ENABLE_LLDPMED
MARSHAL_SUBSTRUCT(lldpd_port, lldpd_med_loc, p_med_location[0])
MARSHAL_SUBSTRUCT(lldpd_port, lldpd_med_loc, p_med_location[1])
char *ifname;
char *local_id;
char *local_descr;
+ char *vlan_advertise_pattern;
int rxtx;
int vlan_tx_tag;
int vlan_tx_enabled;
MARSHAL_STR(lldpd_port_set, ifname)
MARSHAL_STR(lldpd_port_set, local_id)
MARSHAL_STR(lldpd_port_set, local_descr)
+MARSHAL_STR(lldpd_port_set, vlan_advertise_pattern)
#ifdef ENABLE_LLDPMED
MARSHAL_POINTER(lldpd_port_set, lldpd_med_policy, med_policy)
MARSHAL_POINTER(lldpd_port_set, lldpd_med_loc, med_location)
assert "lldp.eth0.vlan" not in out
assert "lldp.eth0.age" in out
+ def test_vlan_advertisement_inclusive(self, lldpd1, lldpd, lldpcli, namespaces, links):
+ vlan = [100, 200, 300, 4000]
+ with namespaces(1):
+ lldpd()
+ for v in vlan:
+ links.vlan("vlan{}".format(v), v, "eth0")
+ result = lldpcli("configure", "ports", "eth0", "lldp", "vlan-advertisements", "pattern","300,4000")
+ assert result.returncode == 0 == 0
+ out = lldpcli("-f", "keyvalue", "show", "interface", "details")
+ # We know that lldpd is walking interfaces in index order
+ assert out["lldp.eth0.vlan"] == [
+ "vlan300",
+ "vlan4000",
+ ]
+ assert out["lldp.eth0.vlan.vlan-id"] == ["300", "4000"]
+
+ def test_vlan_advertisement_exclusive(self, lldpd1, lldpd, lldpcli, namespaces, links):
+ vlan = [100, 200, 300, 4000]
+ with namespaces(1):
+ lldpd()
+ for v in vlan:
+ links.vlan("vlan{}".format(v), v, "eth0")
+ result = lldpcli("configure", "ports", "eth0", "lldp", "vlan-advertisements", "pattern","*,!300,!4000")
+ assert result.returncode == 0 == 0
+ out = lldpcli("-f", "keyvalue", "show", "interface", "details")
+ # We know that lldpd is walking interfaces in index order
+ assert out["lldp.eth0.vlan"] == [
+ "vlan100",
+ "vlan200",
+ ]
+ assert out["lldp.eth0.vlan.vlan-id"] == ["100", "200"]
+
+ def test_vlan_advertisement_unconfigure(self, lldpd1, lldpd, lldpcli, namespaces, links):
+ vlan = [100, 200, 300, 4000]
+ with namespaces(1):
+ lldpd()
+ for v in vlan:
+ links.vlan("vlan{}".format(v), v, "eth0")
+ result = lldpcli("configure", "ports", "eth0", "lldp", "vlan-advertisements", "pattern","*,!300,!4000")
+ assert result.returncode == 0 == 0
+ result = lldpcli("unconfigure", "ports", "eth0", "lldp", "vlan-advertisements", "pattern")
+ assert result.returncode == 0 == 0
+ out = lldpcli("-f", "keyvalue", "show", "interface", "details")
+ # We know that lldpd is walking interfaces in index order
+ assert out["lldp.eth0.vlan"] == [
+ "vlan100",
+ "vlan200",
+ "vlan300",
+ "vlan4000",
+ ]
+ assert out["lldp.eth0.vlan.vlan-id"] == ["100", "200", "300", "4000"]
# TODO: PI and PPVID (but lldpd doesn't know how to generate them)
configure dot3 power pse supported enabled paircontrol powerpairs spare class class-3
configure ports eth0 dot3 power pse supported enabled paircontrol powerpairs spare class class-3
configure dot3 power pd supported enabled powerpairs spare class class-3 type 1 source pse priority low requested 10000 allocated 15000
+configure ports eth0 lldp vlan-advertisements pattern "*,!300,!4000"
+unconfigure ports eth0 lldp vlan-advertisements pattern
configure inventory hardware-revision "SQRT2-1.41421356237309504880"
configure inventory software-revision "E-2.7182818284590452354"