struct cmd_env *, void *);
int cmd_store_something_env_value_and_pop2(const char *, struct cmd_env *,
void *);
+int cmd_store_something_env_value(const char *, struct cmd_env *,
+ void *);
lldpctl_atom_t* cmd_iterate_on_interfaces(struct lldpctl_conn_t *,
struct cmd_env *);
lldpctl_atom_t* cmd_iterate_on_ports(struct lldpctl_conn_t *,
return (cmdenv_put(env, what, value) != -1 &&
cmdenv_pop(env, 2) != -1);
}
+int
+cmd_store_something_env_value(const char *what,
+ struct cmd_env *env, void *value)
+{
+ return (cmdenv_put(env, what, value) != -1);
+}
/**
* Provide an iterator on all interfaces contained in "ports".
return 1;
}
+static int
+cmd_status(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, void *arg)
+{
+ lldpctl_atom_t *port;
+ const char *name;
+ const char *status = cmdenv_get(env, "status");
+
+ log_debug("lldpctl", "lldp administrative port status set to '%s'", status);
+
+ if (!status || !strlen(status)) {
+ log_warnx("lldpctl", "no status specified");
+ return 0;
+ }
+
+ while ((port = cmd_iterate_on_ports(conn, env, &name))) {
+ if (lldpctl_atom_set_str(port, lldpctl_k_port_status, status) == NULL) {
+ log_warnx("lldpctl", "unable to set LLDP status for %s."
+ " %s", name, lldpctl_last_strerror(conn));
+ }
+ }
+
+ return 1;
+}
+
static int
cmd_portid_type_local(struct lldpctl_conn_t *conn, struct writer *w,
struct cmd_env *env, void *arg)
}
#endif /* ENABLE_CUSTOM */
+static int
+cmd_store_status_env_value(struct lldpctl_conn_t *conn, struct writer *w,
+ struct cmd_env *env, void *value)
+{
+ return cmd_store_something_env_value("status", env, value);
+}
+
/**
* Register `configure lldp` commands.
*
NEWLINE, "Set LLDP transmit hold",
NULL, cmd_txhold, NULL);
+ struct cmd_node *status = commands_new(configure_lldp,
+ "status", "Set administrative status",
+ NULL, NULL, NULL);
+
+ for (lldpctl_map_t *status_map =
+ lldpctl_key_get_map(lldpctl_k_port_status);
+ status_map->string;
+ status_map++) {
+ const char *tag = strdup(totag(status_map->string));
+ commands_new(
+ commands_new(status,
+ tag,
+ status_map->string,
+ NULL, cmd_store_status_env_value, status_map->string),
+ NEWLINE, "Set port administrative status",
+ NULL, cmd_status, NULL);
+ }
+
/* Now handle the various portid subtypes we can configure. */
struct cmd_node *configure_lldp_portid_type = commands_new(
configure_lldp,
the default TTL is 120 seconds.
.Ed
+.Cd configure
+.Op ports Ar ethX Op ,...
+.Cd lldp
+.Cd status Ar rx-and-tx | rx-only | tx-only | disabled
+.Bd -ragged -offset XXXXXX
+Configure the administrative status of the given port. By default, all
+ports are configured to be in
+.Ar rxAndTx
+mode. This means they can receive and transmit LLDP frames (as well as
+other protocols if needed). In
+.Ar rxOnly
+mode, they won't emit any frames and in
+.Ar txOnly
+mode, they won't receive any frames. In
+.Ar disabled
+mode, no frame will be sent and any incoming frame will be
+discarded. This settings do not override the operational mode of the
+main daemon. If it is configured in receive-only mode (with the
+.Fl r
+flag), setting any transmit mode won't have any effect.
+.Ed
+
.Cd configure
.Cd lldp custom-tlv oui Ar oui
.Cd subtype Ar subtype
free(port->p_descr);
port->p_descr = strdup(set->local_descr);
}
+ switch (set->rxtx) {
+ case LLDPD_RXTX_TXONLY:
+ log_debug("rpc", "requested TX only mode");
+ port->p_disable_rx = 1;
+ port->p_disable_tx = 0;
+ break;
+ case LLDPD_RXTX_RXONLY:
+ log_debug("rpc", "requested RX only mode");
+ port->p_disable_rx = 0;
+ port->p_disable_tx = 1;
+ break;
+ case LLDPD_RXTX_BOTH:
+ log_debug("rpc", "requested RX/TX mode");
+ port->p_disable_rx = port->p_disable_tx = 0;
+ break;
+ case LLDPD_RXTX_DISABLED:
+ log_debug("rpc", "requested disabled mode");
+ port->p_disable_rx = port->p_disable_tx = 1;
+ break;
+ }
#ifdef ENABLE_LLDPMED
if (set->med_policy && set->med_policy->type > 0) {
log_debug("rpc", "requested change to MED policy");
free(buffer);
return;
}
+ if (hardware->h_lport.p_disable_rx) {
+ log_debug("receive", "RX disabled, ignore the frame on %s",
+ hardware->h_ifname);
+ free(buffer);
+ return;
+ }
if (cfg->g_config.c_paused) {
log_debug("receive", "paused, ignore the frame on %s",
hardware->h_ifname);
{
struct lldpd *cfg = hardware->h_cfg;
if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) return;
+ if (hardware->h_lport.p_disable_tx) return;
if ((hardware->h_flags & IFF_RUNNING) == 0)
return;
int i, sent;
if (cfg->g_config.c_receiveonly || cfg->g_config.c_paused) return;
+ if (hardware->h_lport.p_disable_tx) return;
if ((hardware->h_flags & IFF_RUNNING) == 0)
return;
{ 0, NULL},
};
+static struct atom_map port_status_map = {
+ .key = lldpctl_k_port_status,
+ .map = {
+ { LLDPD_RXTX_TXONLY, "TX only" },
+ { LLDPD_RXTX_RXONLY, "RX only" },
+ { LLDPD_RXTX_DISABLED, "disabled" },
+ { LLDPD_RXTX_BOTH, "RX and TX" },
+ { 0, NULL },
+ }
+};
+
+ATOM_MAP_REGISTER(port_status_map, 3);
+
static lldpctl_map_t operational_mau_type_values[] = {
{ 1, "AUI - no internal MAU, view from AUI" },
{ 2, "10Base5 - thick coax MAU" },
case lldpctl_k_port_descr:
set.local_descr = p->port->p_descr;
break;
+ case lldpctl_k_port_status:
+ set.rxtx = LLDPD_RXTX_FROM_PORT(p->port);
+ break;
#ifdef ENABLE_DOT3
case lldpctl_k_port_dot3_power:
if (value->type != atom_dot3_power) {
char *ipaddress = NULL; size_t len;
/* Local port only */
- if (hardware != NULL) {
- switch (key) {
- case lldpctl_k_port_name:
- return hardware->h_ifname;
- default: break;
- }
+ switch (key) {
+ case lldpctl_k_port_name:
+ if (hardware != NULL) return hardware->h_ifname;
+ break;
+ case lldpctl_k_port_status:
+ if (p->local) return map_lookup(port_status_map.map,
+ LLDPD_RXTX_FROM_PORT(port));
+ break;
+ default: break;
}
/* Local and remote port */
}
}
+static lldpctl_atom_t*
+_lldpctl_atom_set_int_port(lldpctl_atom_t *atom, lldpctl_key_t key,
+ long int value)
+{
+ struct _lldpctl_atom_port_t *p =
+ (struct _lldpctl_atom_port_t *)atom;
+ struct lldpd_port *port = p->port;
+
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ port->p_disable_rx = !LLDPD_RXTX_RXENABLED(value);
+ port->p_disable_tx = !LLDPD_RXTX_TXENABLED(value);
+ break;
+ default:
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+ } else {
+ SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
+ return NULL;
+ }
+
+ return _lldpctl_atom_set_atom_port(atom, key, NULL);
+}
+
static lldpctl_atom_t*
_lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key,
const char *value)
if (!value || !strlen(value))
return NULL;
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ return _lldpctl_atom_set_int_port(atom, key,
+ map_reverse_lookup(port_status_map.map, value));
+ default: break;
+ }
+ }
+
switch (key) {
case lldpctl_k_port_id:
free(port->p_id);
default: break;
}
}
+ if (p->local) {
+ switch (key) {
+ case lldpctl_k_port_status:
+ return LLDPD_RXTX_FROM_PORT(port);
+ default: break;
+ }
+ }
/* Local and remote port */
switch (key) {
.get_str = _lldpctl_atom_get_str_port,
.set_str = _lldpctl_atom_set_str_port,
.get_int = _lldpctl_atom_get_int_port,
+ .set_int = _lldpctl_atom_set_int_port,
.get_buffer = _lldpctl_atom_get_buf_port };
ATOM_BUILDER_REGISTER(ports_list, 4);
lldpctl_k_port_id, /**< `(BS,WO)` The ID of this port. */
lldpctl_k_port_descr, /**< `(S,WO)` The description of this port. */
lldpctl_k_port_hidden, /**< `(I)` Is this port hidden (or should it be displayed?)? */
+ 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_dot3_mfs = 1300, /**< `(I)` MFS */
u_int8_t p_protocol; /* Protocol used to get this port */
u_int8_t p_hidden_in:1; /* Considered as hidden for reception */
u_int8_t p_hidden_out:2; /* Considered as hidden for emission */
+ u_int8_t p_disable_rx:3; /* Should RX be disabled for this port? */
+ u_int8_t p_disable_tx:4; /* Should TX be disabled for this port? */
/* Important: all fields that should be ignored to check if a port has
* been changed should be before this mark. */
#define LLDPD_PORT_START_MARKER (offsetof(struct lldpd_port, p_id_subtype))
MARSHAL_END(lldpd_port);
/* Used to modify some port related settings */
+#define LLDPD_RXTX_UNCHANGED 0
+#define LLDPD_RXTX_TXONLY 1
+#define LLDPD_RXTX_RXONLY 2
+#define LLDPD_RXTX_DISABLED 3
+#define LLDPD_RXTX_BOTH 4
+#define LLDPD_RXTX_FROM_PORT(p) (((p)->p_disable_rx && (p)->p_disable_tx)?LLDPD_RXTX_DISABLED: \
+ ((p)->p_disable_rx && !(p)->p_disable_tx)?LLDPD_RXTX_TXONLY: \
+ (!(p)->p_disable_rx && (p)->p_disable_tx)?LLDPD_RXTX_RXONLY: \
+ LLDPD_RXTX_BOTH)
+#define LLDPD_RXTX_RXENABLED(v) ((v) == LLDPD_RXTX_RXONLY || (v) == LLDPD_RXTX_BOTH)
+#define LLDPD_RXTX_TXENABLED(v) ((v) == LLDPD_RXTX_TXONLY || (v) == LLDPD_RXTX_BOTH)
struct lldpd_port_set {
char *ifname;
char *local_id;
char *local_descr;
+ int rxtx;
#ifdef ENABLE_LLDPMED
struct lldpd_med_policy *med_policy;
struct lldpd_med_loc *med_location;
configure lldp portidsubtype local Batman description Batman
configure lldp tx-interval 30
configure lldp tx-hold 4
+configure lldp ports eth0 status txOnly
+configure lldp status rxAndTx
configure lldp custom-tlv oui 33,44,55 subtype 44
configure lldp custom-tlv oui 33,44,55 subtype 44 oui-info 45,45,45,45,45
unconfigure lldp custom-tlv