]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldpd: limit the maximum of neighbors per port and per protocol
authorVincent Bernat <bernat@luffy.cx>
Sun, 31 Mar 2013 10:59:09 +0000 (12:59 +0200)
committerVincent Bernat <bernat@luffy.cx>
Sun, 31 Mar 2013 11:01:58 +0000 (13:01 +0200)
lldpd memory can be exhausted by adding too many neighbors. Moreover,
the communication with lldpcli is limited to a fixed number of
neighbors (packets may not exceed 1 << 19 in size). Therefore, we put
a hard limit to the number of neighbors accepted for a given port, for
a given protocol.

The limit will be tunable in the future.

Feature suggested by Chris Yang. Closes #32.

NEWS
src/daemon/agent.c
src/daemon/lldpd.c
src/daemon/lldpd.h
src/lldpd-structs.h
tests/check_snmp.c

diff --git a/NEWS b/NEWS
index 0ffd37ba48db0c174e3a8319430c840f79f96365..d240a97792a409e051aa03f7d35ab8da40df921b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,7 @@ lldpd (0.7.2)
       /etc/lldpd.d. All commands accepted by lldpcli are accepted.
     + Lock BPF interfaces before handing them to chrooted process on
       BSD.
+    + Limit the number of neighbors for each port to 4 (per protocol).
   * Fixes:
     + Driver whitelisting is done before checking if an interface has
       a lower interface in Linux.
index fb888fea2f2ab7e405587e3ebd3918bb6bf2ac79..539df21e9a5cc94c993a72f88a1e62032030a122 100644 (file)
@@ -645,8 +645,9 @@ agent_h_scalars(struct variable *vp, oid *name, size_t *length,
                    long_ret += hardware->h_delete_cnt;
                return (u_char *)&long_ret;
        case LLDP_SNMP_STATS_DROPS:
-               /* We assume that we never have insufficient resources */
                long_ret = 0;
+               TAILQ_FOREACH(hardware, &scfg->g_hardware, h_entries)
+                   long_ret += hardware->h_drop_cnt;
                return (u_char *)&long_ret;
        default:
                break;
@@ -1743,7 +1744,7 @@ agent_notify(struct lldpd_hardware *hardware, int type,
                inserts += h->h_insert_cnt;
                deletes += h->h_delete_cnt;
                ageouts += h->h_ageout_cnt;
-               /* We don't count drops */
+               drops   += h->h_drop_cnt;
        }
 
        /* snmpTrapOID */
index a19760b4ecfa9cc00fc438de523eb75548908c74..032f9b7a4d89f9a07f7a86462242596c92a8c844 100644 (file)
@@ -427,21 +427,35 @@ lldpd_decode(struct lldpd *cfg, char *frame, int s,
        }
 
        /* Do we already have the same MSAP somewhere? */
+       int count = 0;
        log_debug("decode", "search for the same MSAP");
        TAILQ_FOREACH(oport, &hardware->h_rports, p_entries) {
-               if ((port->p_protocol == oport->p_protocol) &&
-                   (port->p_id_subtype == oport->p_id_subtype) &&
-                   (port->p_id_len == oport->p_id_len) &&
-                   (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
-                   (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
-                   (chassis->c_id_len == oport->p_chassis->c_id_len) &&
-                   (memcmp(chassis->c_id, oport->p_chassis->c_id,
-                       chassis->c_id_len) == 0)) {
-                       ochassis = oport->p_chassis;
-                       log_debug("decode", "MSAP is already known");
-                       break;
+               if (port->p_protocol == oport->p_protocol) {
+                       count++;
+                       if ((port->p_id_subtype == oport->p_id_subtype) &&
+                           (port->p_id_len == oport->p_id_len) &&
+                           (memcmp(port->p_id, oport->p_id, port->p_id_len) == 0) &&
+                           (chassis->c_id_subtype == oport->p_chassis->c_id_subtype) &&
+                           (chassis->c_id_len == oport->p_chassis->c_id_len) &&
+                           (memcmp(chassis->c_id, oport->p_chassis->c_id,
+                               chassis->c_id_len) == 0)) {
+                               ochassis = oport->p_chassis;
+                               log_debug("decode", "MSAP is already known");
+                               break;
+                       }
                }
        }
+       /* Do we have room for a new MSAP? */
+       if (!oport && cfg->g_config.c_max_neighbors &&
+           count > cfg->g_config.c_max_neighbors) {
+               log_info("decode",
+                   "too many neighbors for port %s, drop this new one",
+                   hardware->h_ifname);
+               lldpd_port_cleanup(port, 1);
+               lldpd_chassis_cleanup(chassis, 1);
+               free(port);
+               return;
+       }
        /* No, but do we already know the system? */
        if (!oport) {
                log_debug("decode", "MSAP is unknown, search for the chassis");
@@ -1398,6 +1412,7 @@ lldpd_main(int argc, char *argv[])
                cfg->g_config.c_paused = 1;
        cfg->g_config.c_receiveonly = receiveonly;
        cfg->g_config.c_tx_interval = LLDPD_TX_INTERVAL;
+       cfg->g_config.c_max_neighbors = LLDPD_MAX_NEIGHBORS;
 #ifdef USE_SNMP
        cfg->g_snmp = snmp;
        cfg->g_snmp_agentx = agentx;
index e289156f545cf6d778fe17a88ae62d30b5c0b190..38e8f83e09397966a5fb557f53ae181a2934a895 100644 (file)
@@ -65,6 +65,7 @@ struct event_base;
 #define LLDPD_TTL              120
 #define LLDPD_TX_INTERVAL      30
 #define LLDPD_TX_MSGDELAY      1
+#define LLDPD_MAX_NEIGHBORS    4
 #define LLDPD_PID_FILE         "/var/run/lldpd.pid"
 
 #define USING_AGENTX_SUBAGENT_MODULE 1
index 34e536a05415553f60be32be2985927dc9af8dda..18b728c7362aa48df054d98d84fbe571922b4bf3 100644 (file)
@@ -315,6 +315,7 @@ struct lldpd_config {
        int c_tx_interval;      /* Transmit interval */
        int c_smart;            /* Bitmask for smart configuration (see SMART_*) */
        int c_receiveonly;      /* Receive only mode */
+       int c_max_neighbors;    /* Maximum number of neighbors (per protocol) */
 
        char *c_mgmt_pattern;   /* Pattern to match a management address */
        char *c_cid_pattern;    /* Pattern to match interfaces to use for chassis ID */
@@ -383,6 +384,7 @@ struct lldpd_hardware {
        u_int64_t                h_ageout_cnt;
        u_int64_t                h_insert_cnt;
        u_int64_t                h_delete_cnt;
+       u_int64_t                h_drop_cnt;
 
        u_int16_t                h_lport_cksum; /* Checksum on local port to see if there is a change */
        struct lldpd_port        h_lport;  /* Port attached to this hardware port */
index 4b79cb1be51f863fa0379e1684a3719f1c5c2abe..b1aed92b19da6dc32fe76a938cfc3236937c05cd 100644 (file)
@@ -102,6 +102,7 @@ struct lldpd_hardware hardware1 = {
        .h_insert_cnt = 100,
        .h_delete_cnt = 5,
        .h_ageout_cnt = 20,
+       .h_drop_cnt = 1,
        .h_lport = {
                .p_chassis    = &chassis1,
                .p_lastchange = 200,
@@ -184,6 +185,7 @@ struct lldpd_hardware hardware2 = {
        .h_insert_cnt = 1000,
        .h_delete_cnt = 51,
        .h_ageout_cnt = 210,
+       .h_drop_cnt = 1,
        .h_lport = {
                .p_chassis    = &chassis1,
                .p_lastchange = 50,
@@ -362,7 +364,7 @@ struct tree_node snmp_tree[] = {
        { {1, 2, 1, 0}, 4, ASN_TIMETICKS, { .integer = 10000 } },/* lldpStatsRemTablesLastChangeTime */
        { {1, 2, 2, 0}, 4, ASN_GAUGE,     { .integer = 1100 } }, /* lldpStatsRemTablesInserts */
        { {1, 2, 3, 0}, 4, ASN_GAUGE,     { .integer = 56 } }, /* lldpStatsRemTablesDeletes */
-       { {1, 2, 4, 0}, 4, ASN_GAUGE,     { .integer = 0 } }, /* lldpStatsRemTablesDrops */
+       { {1, 2, 4, 0}, 4, ASN_GAUGE,     { .integer = 2 } }, /* lldpStatsRemTablesDrops */
        { {1, 2, 5, 0}, 4, ASN_GAUGE,     { .integer = 230 } }, /* lldpStatsRemTablesAgeouts */
 
        { {1, 2, 6, 1, 2, 3}, 6, ASN_COUNTER, { .integer = 1352 } }, /* lldpStatsTxPortFramesTotal.3 */