]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
Support for modifying PortID TLV
authorSam Tannous <stannous@cumulusnetworks.com>
Wed, 21 May 2014 14:11:24 +0000 (10:11 -0400)
committerVincent Bernat <vincent@bernat.im>
Wed, 21 May 2014 15:19:13 +0000 (17:19 +0200)
This patch adds the ability to change the behavior of what
lldpd sends in the PortID TLV.

By default, lldpd sets the MAC address in the PortID and the ifname
in the PortDescr field.  This patch allows the user to
configure lldpd via the CLI (lldpcli or /etc/lldpd.conf)
to send either the interface name
(ifname) or the MAC address in the PortID TLV.

Signed-off-by: Sam Tannous <stannous@cumulusnetworks.com>
src/client/conf-lldp.c
src/client/display.c
src/daemon/client.c
src/daemon/interfaces-linux.c
src/daemon/interfaces.c
src/daemon/lldpd.h
src/lib/atom-private.c
src/lib/lldpctl.h
src/lldp-const.h
src/lldpd-structs.c
src/lldpd-structs.h

index e5389ad1bff3a3539068e31bd2f3e180a238867b..a8ba655e1cdb6d5f68be1b3ebbf39f485652b0f4 100644 (file)
@@ -69,6 +69,53 @@ cmd_txhold(struct lldpctl_conn_t *conn, struct writer *w,
        return 1;
 }
 
+static int
+cmd_portid_type(struct lldpctl_conn_t *conn, struct writer *w,
+               struct cmd_env *env, void *arg)
+{
+       char *value_str;
+       int m = 0, value = -1;
+
+       log_debug("lldpctl", "lldp PortID TLV Subtype");
+
+       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;
+       }
+
+       value_str = arg;
+       for (lldpctl_map_t *b_map =
+                    lldpctl_key_get_map(lldpctl_k_config_lldp_portid_type);
+            b_map->string; b_map++) {
+               if (!strcmp(b_map->string, value_str)) {
+                       value = b_map->value;
+                       break;
+               }
+       }
+
+       if (value == -1) {
+               log_warnx("lldpctl", "invalid value");
+               lldpctl_atom_dec_ref(config);
+               return 0;
+       }
+
+       if (lldpctl_atom_set_int(config,
+                                lldpctl_k_config_lldp_portid_type, value) == NULL) {
+               log_warnx("lldpctl", "unable to set LLDP PortID type."
+                         " %s", lldpctl_last_strerror(conn));
+               lldpctl_atom_dec_ref(config);
+               return 0;
+       }
+
+       log_info("lldpctl", "LLDP PortID TLV type set to new value : %s", arg);
+       lldpctl_atom_dec_ref(config);
+
+       return 1;
+}
+
 /**
  * Register `configure lldp` commands.
  *
@@ -102,4 +149,32 @@ register_commands_configure_lldp(struct cmd_node *configure)
                        NULL, cmd_store_env_value, "tx-hold"),
                NEWLINE, "Set LLDP transmit hold",
                NULL, cmd_txhold, NULL);
+
+       /* Now handle the various portid subtypes we can configure. */
+       struct cmd_node *configure_lldp_portid_type = commands_new(
+               configure_lldp,
+               "portidsubtype", "LLDP PortID TLV Subtype ",
+               NULL, NULL, NULL);
+
+       for (lldpctl_map_t *b_map =
+                    lldpctl_key_get_map(lldpctl_k_config_lldp_portid_type);
+            b_map->string; b_map++) {
+               if (!strcmp(b_map->string, "ifname")) {
+                       commands_new(
+                               commands_new(configure_lldp_portid_type,
+                                            b_map->string, "Interface Name",
+                                            NULL, NULL, NULL),
+                               NEWLINE, NULL,
+                               NULL, cmd_portid_type,
+                               b_map->string);
+               } else if (!strcmp(b_map->string, "macaddress")) {
+                       commands_new(
+                               commands_new(configure_lldp_portid_type,
+                                            b_map->string, "MAC Address",
+                                            NULL, NULL, NULL),
+                               NEWLINE, NULL,
+                               NULL, cmd_portid_type,
+                               b_map->string);
+               }
+       }
 }
index 28d4c397963eec2a2694b71c4c6b7e9c6bf411a3..fb221bffd93234c6b6037512a542919211b7ea93 100644 (file)
@@ -743,6 +743,10 @@ display_configuration(lldpctl_conn_t *conn, struct writer *w)
                "Source MAC for LLDP frames on bond slaves",
                lldpctl_atom_get_str(configuration,
                        lldpctl_k_config_bond_slave_src_mac_type));
+       tag_datatag(w, "lldp_portid-type",
+               "Portid TLV Subtype for lldp frames",
+               lldpctl_atom_get_str(configuration,
+                       lldpctl_k_config_lldp_portid_type));
 
        tag_end(w);
        tag_end(w);
index dffe605199bb45c424e1a3d5107ec8bc60d1760b..201efff565c3db79c59985f78350cd09bcbf0d61 100644 (file)
@@ -42,6 +42,32 @@ client_handle_get_configuration(struct lldpd *cfg, enum hmsg_type *type,
        return output_len;
 }
 
+/* Change the PortID Subtype configuration for all interfaces */
+void
+portid_subtype_update(struct lldpd *cfg)
+{
+       struct lldpd_hardware *hardware;
+       struct interfaces_device_list *interfaces;
+       struct interfaces_address_list *addresses;
+       struct interfaces_device *iface;
+       interfaces = netlink_get_interfaces();
+       addresses = netlink_get_addresses();
+
+       if (interfaces == NULL || addresses == NULL) {
+               log_warnx("interfaces", "cannot update the list of local interfaces");
+               return;
+       }
+        log_debug("interfaces", "portid_subtype_update called....");
+       TAILQ_FOREACH(iface, interfaces, next) {
+               if ((hardware = lldpd_get_hardware(cfg, iface->name,
+                                               iface->index,NULL)) == NULL)
+                       continue;
+
+                /* do some port->p_id and port->p_descr settings so we get updates */
+               interfaces_helper_port_name_desc(cfg, hardware, iface);
+       }
+}
+
 /* Change the global configuration */
 static int
 client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type,
@@ -75,6 +101,14 @@ client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type,
                log_debug("rpc", "client asked for immediate retransmission");
                levent_send_now(cfg);
        }
+       if (config->c_lldp_portid_type > LLDP_PORTID_SUBTYPE_UNKNOWN &&
+            config->c_lldp_portid_type <= LLDP_PORTID_SUBTYPE_MAX) {
+            log_debug("rpc", "change lldp portid tlv subtype to %d",
+                      config->c_lldp_portid_type);
+            cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type;
+            /* update the interfaces since our portid type has changed */
+            portid_subtype_update(cfg);
+       }
        /* Pause/resume */
        if (config->c_paused != cfg->g_config.c_paused) {
                log_debug("rpc", "client asked to %s lldpd",
index 72cf71fade9b4f289e3f1fe091a9da2001c4b13e..c3b4f28a9ba2ef0918ce951443f5e0dc11b0de01 100644 (file)
@@ -582,7 +582,7 @@ iflinux_handle_bond(struct lldpd *cfg, struct interfaces_device_list *interfaces
                memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
 
                /* Fill information about port */
-               interfaces_helper_port_name_desc(hardware, iface);
+               interfaces_helper_port_name_desc(cfg, hardware, iface);
 
                /* Fill additional info */
 #ifdef ENABLE_DOT3
index 9460782a0a78f295fcf3fd98d94b56af1607cb02..2bd7e1b9c874b2c5750fc54278f9d85aab7b5bb3 100644 (file)
@@ -435,44 +435,60 @@ interfaces_helper_mgmt(struct lldpd *cfg,
 
 /* Fill up port name and description */
 void
-interfaces_helper_port_name_desc(struct lldpd_hardware *hardware,
+interfaces_helper_port_name_desc(struct lldpd *cfg,
+    struct lldpd_hardware *hardware,
     struct interfaces_device *iface)
 {
        struct lldpd_port *port = &hardware->h_lport;
 
-       /* There are two cases:
-
-            1. We have a kernel recent enough to support ifAlias
-            _and_ a non empty ifAlias, then we will use it for
-            description and use ifname for port ID.
-
-            2. Otherwise, we will use the MAC address as ID and the
-            port name in description.
+       /* We need to set the portid to what the client configured.
+          This can be done from the CLI.
        */
-
-       if (iface->alias == NULL || strlen(iface->alias) == 0) {
-               /* Case 2: MAC address and port name */
-               log_debug("interfaces", "use ifname and MAC address for %s",
-                   hardware->h_ifname);
+       switch (cfg->g_config.c_lldp_portid_type) {
+       case LLDP_PORTID_SUBTYPE_IFNAME:
+               log_debug("interfaces", "use ifname for %s",
+                         hardware->h_ifname);
+               port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
+               port->p_id_len = strlen(hardware->h_ifname);
+               if (port->p_id != NULL) {
+                       free(port->p_id);
+               }
+               if ((port->p_id = calloc(1, port->p_id_len)) == NULL)
+                       fatal("interfaces", NULL);
+               memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
+               break;
+       case LLDP_PORTID_SUBTYPE_LLADDR:
+               /* fall through so we use the mac address */
+       default:
+               log_debug("interfaces", "use MAC address for %s",
+                         hardware->h_ifname);
                port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
-               if ((port->p_id =
-                       calloc(1, ETHER_ADDR_LEN)) == NULL)
+               if (port->p_id != NULL) {
+                       free(port->p_id);
+               }
+               if ((port->p_id = calloc(1, ETHER_ADDR_LEN)) == NULL)
                        fatal("interfaces", NULL);
                memcpy(port->p_id, hardware->h_lladdr, ETHER_ADDR_LEN);
                port->p_id_len = ETHER_ADDR_LEN;
+       }
+
+       if (iface->alias != NULL && strlen(iface->alias) != 0) {
+               /* use the actual alias in the port description */
+               log_debug("interfaces", "using alias in description for %s",
+                         hardware->h_ifname);
+               if (port->p_descr != NULL) {
+                       free(port->p_descr);
+               }
+               port->p_descr = strdup(iface->alias);
+       } else {
+               /* use the ifname in the port description until alias is set */
+               log_debug("interfaces", "using ifname in description for %s",
+                         hardware->h_ifname);
+               if (port->p_descr != NULL) {
+                       free(port->p_descr);
+               }
                port->p_descr = strdup(hardware->h_ifname);
-               return;
        }
-       /* Case 1: port name and port description */
-       log_debug("interfaces", "use ifname and ifalias for %s",
-           hardware->h_ifname);
-       port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
-       port->p_id_len = strlen(hardware->h_ifname);
-       if ((port->p_id =
-               calloc(1, port->p_id_len)) == NULL)
-               fatal("interfaces", NULL);
-       memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
-       port->p_descr = strdup(iface->alias);
 }
 
 void
@@ -535,7 +551,7 @@ interfaces_helper_physical(struct lldpd *cfg,
                memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
 
                /* Fill information about port */
-               interfaces_helper_port_name_desc(hardware, iface);
+               interfaces_helper_port_name_desc(cfg, hardware, iface);
 
                /* Fill additional info */
                hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
index 3ef34b241402f17f8d8d625039104c71de503e35..fcf2a7bfc30327ee37139dc33e02ee61ae3dcfff 100644 (file)
@@ -377,7 +377,8 @@ void interfaces_helper_physical(struct lldpd *,
     struct interfaces_device_list *,
     struct lldpd_ops *,
     int(*init)(struct lldpd *, struct lldpd_hardware *));
-void interfaces_helper_port_name_desc(struct lldpd_hardware *,
+void interfaces_helper_port_name_desc(struct lldpd *,
+    struct lldpd_hardware *,
     struct interfaces_device *);
 void interfaces_helper_mgmt(struct lldpd *,
     struct interfaces_address_list *);
index 318daff26c0c78e0a72cacd49542bf779f256e6b..936b00d91340dadbf973d2c64f48158ef2580fd1 100644 (file)
@@ -268,6 +268,12 @@ static lldpctl_map_t bond_slave_src_mac_map[] = {
        { LLDP_BOND_SLAVE_SRC_MAC_TYPE_UNKNOWN, NULL},
 };
 
+static lldpctl_map_t lldp_portid_map[] = {
+       { LLDP_PORTID_SUBTYPE_IFNAME,   "ifname"},
+       { LLDP_PORTID_SUBTYPE_LLADDR,   "macaddress"},
+       { LLDP_PORTID_SUBTYPE_UNKNOWN,  NULL},
+};
+
 static const char*
 map_lookup(lldpctl_map_t *list, int n)
 {
@@ -326,6 +332,8 @@ lldpctl_key_get_map(lldpctl_key_t key)
 #endif
        case lldpctl_k_config_bond_slave_src_mac_type:
                return bond_slave_src_mac_map;
+       case lldpctl_k_config_lldp_portid_type:
+               return lldp_portid_map;
        default: return empty_map;
        }
 }
@@ -372,6 +380,9 @@ _lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key)
        case lldpctl_k_config_bond_slave_src_mac_type:
                return map_lookup(bond_slave_src_mac_map,
                                c->config->c_bond_slave_src_mac_type);
+       case lldpctl_k_config_lldp_portid_type:
+               return map_lookup(lldp_portid_map,
+                   c->config->c_lldp_portid_type);
        default:
                SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
                return NULL;
@@ -521,6 +532,10 @@ _lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key,
                config.c_bond_slave_src_mac_type = value;
                c->config->c_bond_slave_src_mac_type = value;
                break;
+       case lldpctl_k_config_lldp_portid_type:
+               config.c_lldp_portid_type = value;
+               c->config->c_lldp_portid_type = value;
+               break;
        default:
                SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
                return NULL;
index 306bb5ba77e377df849f5cf3e6869fcc2bf497ca..6e6eb9bd60895a14faf225432b58f0cdd586e6d3 100644 (file)
@@ -710,6 +710,7 @@ typedef enum {
        lldpctl_k_delete_cnt,   /**< `(I)` delete cnt. Only works for a local port. */
        lldpctl_k_config_tx_hold, /**< `(I,WO)` Transmit hold interval. */
        lldpctl_k_config_bond_slave_src_mac_type, /**< `(I,WO)` bond slave src mac type. */
+       lldpctl_k_config_lldp_portid_type, /**< `(I,WO)` LLDP PortID TLV Subtype */
 } lldpctl_key_t;
 
 /**
index 31b604d19eb517cfd72449b69789ecab0f1dcdbe..7181f12a1b09ac282c6585e90e1ae981206e74f8 100644 (file)
@@ -33,6 +33,7 @@
 #define LLDP_CHASSISID_SUBTYPE_LOCAL   7
 
 /* Port ID subtype */
+#define LLDP_PORTID_SUBTYPE_UNKNOWN    0
 #define LLDP_PORTID_SUBTYPE_IFALIAS    1
 #define LLDP_PORTID_SUBTYPE_PORT       2
 #define LLDP_PORTID_SUBTYPE_LLADDR     3
@@ -40,6 +41,7 @@
 #define LLDP_PORTID_SUBTYPE_IFNAME     5
 #define LLDP_PORTID_SUBTYPE_AGENTCID   6
 #define LLDP_PORTID_SUBTYPE_LOCAL      7
+#define LLDP_PORTID_SUBTYPE_MAX                LLDP_PORTID_SUBTYPE_LOCAL
 
 /* Operational MAU Type field, from RFC 3636 */
 #define LLDP_DOT3_MAU_AUI              1
index 63a824bf5e5b928d4e5f4a1de3eeaa707aa6beb7..063115102ea33349ce9ba0c8b4699bd2a80d9a22 100644 (file)
@@ -159,8 +159,12 @@ lldpd_port_cleanup(struct lldpd_port *port, int all)
        lldpd_ppvid_cleanup(port);
        lldpd_pi_cleanup(port);
 #endif
+       /* will set these to NULL so we don't free wrong memory */
+
        free(port->p_id);
+       port->p_id = NULL;
        free(port->p_descr);
+       port->p_descr = NULL;
        if (all) {
                free(port->p_lastframe);
                if (port->p_chassis) { /* chassis may not have been attributed, yet */
index 245dd8ccc8f1223db0e2747582d0b2c76aaedfe5..ac4e6339b449c559c5aea07b4f6366be7cb3dfde 100644 (file)
@@ -336,6 +336,7 @@ struct lldpd_config {
        int c_tx_hold;          /* Transmit hold */
        int c_bond_slave_src_mac_type; /* Src mac type in lldp frames over bond
                                          slaves */
+       int c_lldp_portid_type; /* The PortID type */
 };
 MARSHAL_BEGIN(lldpd_config)
 MARSHAL_STR(lldpd_config, c_mgmt_pattern)