From: Sam Tannous Date: Wed, 21 May 2014 14:11:24 +0000 (-0400) Subject: Support for modifying PortID TLV X-Git-Tag: 0.7.9~7 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8fbd319539577cd2ad3ba95329dc7881849e4827;p=thirdparty%2Flldpd.git Support for modifying PortID TLV 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 --- diff --git a/src/client/conf-lldp.c b/src/client/conf-lldp.c index e5389ad1..a8ba655e 100644 --- a/src/client/conf-lldp.c +++ b/src/client/conf-lldp.c @@ -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); + } + } } diff --git a/src/client/display.c b/src/client/display.c index 28d4c397..fb221bff 100644 --- a/src/client/display.c +++ b/src/client/display.c @@ -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); diff --git a/src/daemon/client.c b/src/daemon/client.c index dffe6051..201efff5 100644 --- a/src/daemon/client.c +++ b/src/daemon/client.c @@ -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", diff --git a/src/daemon/interfaces-linux.c b/src/daemon/interfaces-linux.c index 72cf71fa..c3b4f28a 100644 --- a/src/daemon/interfaces-linux.c +++ b/src/daemon/interfaces-linux.c @@ -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 diff --git a/src/daemon/interfaces.c b/src/daemon/interfaces.c index 9460782a..2bd7e1b9 100644 --- a/src/daemon/interfaces.c +++ b/src/daemon/interfaces.c @@ -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; diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index 3ef34b24..fcf2a7bf 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -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 *); diff --git a/src/lib/atom-private.c b/src/lib/atom-private.c index 318daff2..936b00d9 100644 --- a/src/lib/atom-private.c +++ b/src/lib/atom-private.c @@ -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; diff --git a/src/lib/lldpctl.h b/src/lib/lldpctl.h index 306bb5ba..6e6eb9bd 100644 --- a/src/lib/lldpctl.h +++ b/src/lib/lldpctl.h @@ -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; /** diff --git a/src/lldp-const.h b/src/lldp-const.h index 31b604d1..7181f12a 100644 --- a/src/lldp-const.h +++ b/src/lldp-const.h @@ -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 diff --git a/src/lldpd-structs.c b/src/lldpd-structs.c index 63a824bf..06311510 100644 --- a/src/lldpd-structs.c +++ b/src/lldpd-structs.c @@ -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 */ diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 245dd8cc..ac4e6339 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -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)