From 4258966022fc22c6e673b3de10f95ebc20aa8380 Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sun, 31 Mar 2013 12:59:09 +0200 Subject: [PATCH] lldpd: limit the maximum of neighbors per port and per protocol 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 | 1 + src/daemon/agent.c | 5 +++-- src/daemon/lldpd.c | 37 ++++++++++++++++++++++++++----------- src/daemon/lldpd.h | 1 + src/lldpd-structs.h | 2 ++ tests/check_snmp.c | 4 +++- 6 files changed, 36 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 0ffd37ba..d240a977 100644 --- 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. diff --git a/src/daemon/agent.c b/src/daemon/agent.c index fb888fea..539df21e 100644 --- a/src/daemon/agent.c +++ b/src/daemon/agent.c @@ -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 */ diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index a19760b4..032f9b7a 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -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; diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index e289156f..38e8f83e 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -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 diff --git a/src/lldpd-structs.h b/src/lldpd-structs.h index 34e536a0..18b728c7 100644 --- a/src/lldpd-structs.h +++ b/src/lldpd-structs.h @@ -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 */ diff --git a/tests/check_snmp.c b/tests/check_snmp.c index 4b79cb1b..b1aed92b 100644 --- a/tests/check_snmp.c +++ b/tests/check_snmp.c @@ -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 */ -- 2.39.5