]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Ability to enable/disable RX/TX individually on each port
authorVincent Bernat <vincent@bernat.im>
Sun, 23 Aug 2015 14:01:48 +0000 (16:01 +0200)
committerVincent Bernat <vincent@bernat.im>
Sun, 23 Aug 2015 14:01:48 +0000 (16:01 +0200)
src/client/client.h
src/client/commands.c
src/client/conf-lldp.c
src/client/lldpcli.8.in
src/daemon/client.c
src/daemon/lldpd.c
src/lib/atoms/port.c
src/lib/lldpctl.h
src/lldpd-structs.h
tests/lldpcli.conf

index 64de5faabd759e526c4a02eff3f05cf00ed20bca..62174b3c9a61ec28028abbb01e9bb2771a4875de 100644 (file)
@@ -96,6 +96,8 @@ int cmd_store_env_value_and_pop3(struct lldpctl_conn_t *, struct writer *,
     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 *,
index de96ea722610f65d066811c24303403b713d52e5..e8e47d00708adfa0ff6c58400a1bc6ca8dbb5794 100644 (file)
@@ -664,6 +664,12 @@ cmd_store_something_env_value_and_pop2(const char *what,
        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".
index 0d21ef737e2cdf11726425a8915564a11cfd3d53..10cf5dd4852ad356c9e712419662416b1a9c412a 100644 (file)
@@ -69,6 +69,31 @@ cmd_txhold(struct lldpctl_conn_t *conn, struct writer *w,
        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)
@@ -330,6 +355,13 @@ register_commands_configure_lldp_custom_tlvs(struct cmd_node *configure_lldp)
 }
 #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.
  *
@@ -369,6 +401,24 @@ register_commands_configure_lldp(struct cmd_node *configure,
                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,
index 20a0dc5a59e28e964e7435c5a7bdaff48c9e250e..3abc00b1ec6d8d6ee0c03126857f1dae0d8c5cea 100644 (file)
@@ -403,6 +403,28 @@ value and of the transmit delay. The default value is 4 and therefore
 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
index 80d501042ee9a4ed61691db7ca5b647c63595f69..89520cf46de7d258907149b556e817676d9ad3e6 100644 (file)
@@ -333,6 +333,26 @@ _client_handle_set_port(struct lldpd *cfg,
                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");
index 935b9c0ac126f65c3d0e26e125c91d6a2020e5cf..ab1ad613d851c66a8ee0c23eb4bf87fc562b0a39 100644 (file)
@@ -950,6 +950,12 @@ lldpd_recv(struct lldpd *cfg, struct lldpd_hardware *hardware, int fd)
                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);
@@ -971,6 +977,7 @@ lldpd_send_shutdown(struct lldpd_hardware *hardware)
 {
        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;
 
@@ -989,6 +996,7 @@ lldpd_send(struct lldpd_hardware *hardware)
        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;
 
index 5719616e589bd670f11360c863f53cdeda05b509..046813aa380113fe929442e90ef2700efde17e1f 100644 (file)
@@ -51,6 +51,19 @@ static lldpctl_map_t port_id_subtype_map[] = {
        { 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" },
@@ -314,6 +327,9 @@ _lldpctl_atom_set_atom_port(lldpctl_atom_t *atom, lldpctl_key_t key, lldpctl_ato
        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) {
@@ -396,12 +412,15 @@ _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
        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 */
@@ -454,6 +473,32 @@ _lldpctl_atom_get_str_port(lldpctl_atom_t *atom, lldpctl_key_t key)
        }
 }
 
+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)
@@ -465,6 +510,15 @@ _lldpctl_atom_set_str_port(lldpctl_atom_t *atom, lldpctl_key_t key,
        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);
@@ -513,6 +567,13 @@ _lldpctl_atom_get_int_port(lldpctl_atom_t *atom, lldpctl_key_t key)
                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) {
@@ -587,6 +648,7 @@ static struct atom_builder port =
          .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);
index c76ccd5c39e0736a6ce36cc829a590b33d1374f7..3fc52037dcddf77d7b5bd4c2b8c94ef622c2c9ab 100644 (file)
@@ -672,6 +672,7 @@ typedef enum {
        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 */
index 27779b40e2b162224456f45bb1dfcc67d5af3e8e..26b1cb131e56528ed07055c8439e54f59d1ad84b 100644 (file)
@@ -243,6 +243,8 @@ struct lldpd_port {
        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))
@@ -299,10 +301,22 @@ MARSHAL_SUBTQ(lldpd_port, lldpd_custom, p_custom_list)
 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;
index aa63f0728abb56ae207b8900806ae6dfc71f26d2..2246a47c09e486395de9645915fbc8a83a6e524e 100644 (file)
@@ -29,6 +29,8 @@ configure lldp portidsubtype local Batman
 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