]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldp: add ability to control propagation of LLDPDU
authorVincent Bernat <vincent@bernat.im>
Tue, 14 Jun 2016 19:44:42 +0000 (21:44 +0200)
committerVincent Bernat <vincent@bernat.im>
Tue, 14 Jun 2016 19:46:13 +0000 (21:46 +0200)
In 802.1AB-2009, two additional target addresses were added to allow an
LLDPDU to not be stopped by some equipments. Expose this ability as a
configure command.

Fix #171

src/client/conf-lldp.c
src/client/display.c
src/client/lldpcli.8.in
src/daemon/client.c
src/daemon/protocols/lldp.c
src/lib/atoms/config.c
src/lib/lldpctl.h
src/lldp-const.h
src/lldpd-structs.h

index 8b6aa2cbadad4a05691fd764d708ed7b2a3f4798..c16219bd44c60be9410afb0a3dcf8e403a8c72c9 100644 (file)
@@ -94,6 +94,52 @@ cmd_status(struct lldpctl_conn_t *conn, struct writer *w,
        return 1;
 }
 
+static int
+cmd_agent_type(struct lldpctl_conn_t *conn, struct writer *w,
+    struct cmd_env *env, void *arg)
+{
+       const char *str = arg;
+       int value = -1;
+
+       log_debug("lldpctl", "set agent type to '%s'", str);
+
+       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;
+       }
+
+       for (lldpctl_map_t *b_map =
+                    lldpctl_key_get_map(lldpctl_k_config_lldp_agent_type);
+            b_map->string; b_map++) {
+               if (!strcmp(b_map->string, 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_agent_type, value) == NULL) {
+               log_warnx("lldpctl", "unable to set LLDP agent type."
+                         " %s", lldpctl_last_strerror(conn));
+               lldpctl_atom_dec_ref(config);
+               return 0;
+       }
+
+       log_info("lldpctl", "agent type set to new value : %s", str);
+       lldpctl_atom_dec_ref(config);
+
+       return 1;
+}
+
 static int
 cmd_portid_type_local(struct lldpctl_conn_t *conn, struct writer *w,
                struct cmd_env *env, void *arg)
@@ -488,10 +534,30 @@ register_commands_configure_lldp(struct cmd_node *configure,
                        NULL, cmd_status, NULL);
        }
 
+       /* Configure the various agent type we can configure. */
+       struct cmd_node *configure_lldp_agent_type = commands_new(
+               configure_lldp,
+               "agent-type",
+               "LLDP agent type",
+               NULL, NULL, NULL);
+       for (lldpctl_map_t *b_map =
+                lldpctl_key_get_map(lldpctl_k_config_lldp_agent_type);
+            b_map->string; b_map++) {
+               const char *tag = strdup(totag(b_map->string));
+               SUPPRESS_LEAK(tag);
+               commands_new(
+                       commands_new(configure_lldp_agent_type,
+                           tag,
+                           b_map->string,
+                           NULL, NULL, NULL),
+                       NEWLINE, "Set LLDP agent type",
+                       NULL, cmd_agent_type, b_map->string);
+       }
+
        /* 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 ",
+               "portidsubtype", "LLDP PortID TLV Subtype",
                NULL, NULL, NULL);
 
        for (lldpctl_map_t *b_map =
index b4da61eacb89699848c77ad9f29adaa9ada8f6c4..77938c0beceb960217f3bc24bed174418b7b2c5d 100644 (file)
@@ -853,10 +853,14 @@ 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",
+       tag_datatag(w, "lldp-portid-type",
+               "Port ID TLV subtype for LLDP frames",
                lldpctl_atom_get_str(configuration,
                        lldpctl_k_config_lldp_portid_type));
+       tag_datatag(w, "lldp-agent-type",
+               "Agent type",
+               lldpctl_atom_get_str(configuration,
+                       lldpctl_k_config_lldp_agent_type));
 
        tag_end(w);
        tag_end(w);
index 01a8ab4d20a78a64452fda5a99ef492ae312c02f..57f59c07ef145186059f39d9dcf027b8a4663145 100644 (file)
@@ -287,7 +287,7 @@ neighbor. This option undoes the previous one.
 Enable promiscuous mode on managed interfaces.
 .Pp
 When the interface is not managed any more (or when quitting
-.Nm ) ,
+.Nm lldpd ) ,
 the interface is left in promiscuous mode as it is difficult to know
 if someone else also put the interface in promiscuous mode.
 .Pp
@@ -365,6 +365,30 @@ might lead to a duplicate MAC address on the network (but this is
 quite unlikely).
 .Ed
 
+.Cd configure
+.Cd lldp agent-type
+.Cd nearest-bridge | nearest-non-tpmr-bridge | nearest-customer-bridge
+.Bd -ragged -offset XXXXXX
+The destination MAC address used to send LLDPDU allows an agent to
+control the propagation of LLDPDUs. By default, the
+.Li 01:80:c2:00:00:0e
+MAC address is used and limit the propagation of the LLDPDU to the
+nearest bridge
+.Cd ( nearest-bridge ) .
+To instruct
+.Nm lldpd
+to use the
+.Li 01:80:c2:00:00:03
+MAC address instead, use
+.Cd nearest-nontpmr-bridge
+instead.
+To use the
+.Li 01:80:c2:00:00:00
+MAC address instead, use
+.Cd nearest-customer-bridge
+instead.
+.Ed
+
 .Cd configure
 .Cd lldp portidsubtype
 .Cd ifname | macaddress
@@ -375,7 +399,7 @@ quite unlikely).
 .Cd local Ar value Op Cd description Ar description
 .Bd -ragged -offset XXXXXX
 Force port ID subtype. By default,
-.Nm
+.Nm lldpd
 will use the MAC address as port identifier and the interface name as
 port description, unless the interface has an alias. In this case, the
 interface name will be used as port identifier and the description
index 34d403e2e77e86a79a65e55c43e2079c9854b027..8382d020aa15b6096a575bcb60d6a7e0676c16da 100644 (file)
@@ -95,6 +95,14 @@ client_handle_set_configuration(struct lldpd *cfg, enum hmsg_type *type,
                cfg->g_config.c_lldp_portid_type = config->c_lldp_portid_type;
                levent_update_now(cfg);
        }
+       if (CHANGED(c_lldp_agent_type) &&
+           config->c_lldp_agent_type > LLDP_AGENT_TYPE_UNKNOWN &&
+           config->c_lldp_agent_type <= LLDP_AGENT_TYPE_MAX) {
+               log_debug("rpc", "change lldp agent type to %d",
+                   config->c_lldp_agent_type);
+               cfg->g_config.c_lldp_agent_type = config->c_lldp_agent_type;
+               levent_update_now(cfg);
+       }
        /* Pause/resume */
        if (CHANGED(c_paused)) {
                log_debug("rpc", "client asked to %s lldpd",
index 74ca8387564ed36b4c6ed28b100661460d8efc2b..59b9f1c2161c19251ad7c7608fdd5109da8487a3 100644 (file)
@@ -69,7 +69,10 @@ static int _lldp_send(struct lldpd *global,
        struct lldpd_mgmt *mgmt;
        int proto;
 
-       u_int8_t mcastaddr[] = LLDP_ADDR_NEAREST_BRIDGE;
+       u_int8_t mcastaddr_regular[] = LLDP_ADDR_NEAREST_BRIDGE;
+       u_int8_t mcastaddr_nontpmr[] = LLDP_ADDR_NEAREST_NONTPMR_BRIDGE;
+       u_int8_t mcastaddr_customer[] = LLDP_ADDR_NEAREST_CUSTOMER_BRIDGE;
+       u_int8_t *mcastaddr;
 #ifdef ENABLE_DOT1
        const u_int8_t dot1[] = LLDP_TLV_ORG_DOT1;
        struct lldpd_vlan *vlan;
@@ -94,9 +97,15 @@ static int _lldp_send(struct lldpd *global,
        pos = packet;
 
        /* Ethernet header */
+       switch (global->g_config.c_lldp_agent_type) {
+       case LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE: mcastaddr = mcastaddr_nontpmr; break;
+       case LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE: mcastaddr = mcastaddr_customer; break;
+       case LLDP_AGENT_TYPE_NEAREST_BRIDGE:
+       default: mcastaddr = mcastaddr_regular; break;
+       }
        if (!(
              /* LLDP multicast address */
-             POKE_BYTES(mcastaddr, sizeof(mcastaddr)) &&
+             POKE_BYTES(mcastaddr, ETHER_ADDR_LEN) &&
              /* Source MAC address */
              POKE_BYTES(&hardware->h_lladdr, ETHER_ADDR_LEN) &&
              /* LLDP frame */
index f2b138a5bf8d60487c3fae5f99b46036cc78318a..fc64cb362edc598490296e38f70a3ac17851a5cd 100644 (file)
@@ -46,8 +46,19 @@ static struct atom_map lldp_portid_map = {
        },
 };
 
+static struct atom_map lldp_agent_map = {
+       .key = lldpctl_k_config_lldp_agent_type,
+       .map = {
+               { LLDP_AGENT_TYPE_NEAREST_BRIDGE,          "nearest bridge"},
+               { LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE,  "nearest non-TPMR bridge"},
+               { LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE, "nearest customer bridge"},
+               { LLDP_AGENT_TYPE_UNKNOWN, NULL},
+       },
+};
+
 ATOM_MAP_REGISTER(bond_slave_src_mac_map, 1);
 ATOM_MAP_REGISTER(lldp_portid_map,        2);
+ATOM_MAP_REGISTER(lldp_agent_map,         3);
 
 static int
 _lldpctl_atom_new_config(lldpctl_atom_t *atom, va_list ap)
@@ -92,6 +103,9 @@ _lldpctl_atom_get_str_config(lldpctl_atom_t *atom, lldpctl_key_t key)
        case lldpctl_k_config_lldp_portid_type:
                return map_lookup(lldp_portid_map.map,
                    c->config->c_lldp_portid_type);
+       case lldpctl_k_config_lldp_agent_type:
+               return map_lookup(lldp_agent_map.map,
+                   c->config->c_lldp_agent_type);
        default:
                SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
                return NULL;
@@ -270,6 +284,10 @@ _lldpctl_atom_set_int_config(lldpctl_atom_t *atom, lldpctl_key_t key,
                config.c_lldp_portid_type = value;
                c->config->c_lldp_portid_type = value;
                break;
+       case lldpctl_k_config_lldp_agent_type:
+               config.c_lldp_agent_type = value;
+               c->config->c_lldp_agent_type = value;
+               break;
        default:
                SET_ERROR(atom->conn, LLDPCTL_ERR_NOT_EXIST);
                return NULL;
index 54c15ad592a502332fdbff7cce9a01cc1e03c739..ea19fae5dcb4f3552bea6bc8185aa285ef989cb0 100644 (file)
@@ -783,6 +783,7 @@ typedef enum {
        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_k_config_lldp_agent_type, /**< `(I,WO)` LLDP agent type */
 
        lldpctl_k_custom_tlvs = 5000,           /**< `(AL)` custom TLVs */
        lldpctl_k_custom_tlvs_clear,            /** `(I,WO)` clear list of custom TLVs */
index 509b08fd5f7e2064cb76ac0bd49628d53007f76c..6e0a60e0071144b094f99c63e6c551e595e2f86a 100644 (file)
 #define LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED 4
 #define LLDP_BOND_SLAVE_SRC_MAC_TYPE_MAX LLDP_BOND_SLAVE_SRC_MAC_TYPE_LOCALLY_ADMINISTERED
 
+/* Agent types */
+#define LLDP_AGENT_TYPE_UNKNOWN                        0
+#define LLDP_AGENT_TYPE_NEAREST_BRIDGE         1
+#define LLDP_AGENT_TYPE_NEAREST_NONTPMR_BRIDGE 2
+#define LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE        3
+#define LLDP_AGENT_TYPE_MAX                    LLDP_AGENT_TYPE_NEAREST_CUSTOMER_BRIDGE
+
 #endif /* _LLDP_H */
index 4c65db31338aa8d7cde48a405ad87129ea6c726c..0cbb6bdcf4ed195d4132c317a3f0a9b1c5d1a119 100644 (file)
@@ -399,6 +399,7 @@ struct lldpd_config {
        int c_bond_slave_src_mac_type; /* Src mac type in lldp frames over bond
                                          slaves */
        int c_lldp_portid_type; /* The PortID type */
+       int c_lldp_agent_type;  /* The agent type */
 };
 MARSHAL_BEGIN(lldpd_config)
 MARSHAL_STR(lldpd_config, c_mgmt_pattern)