From: Vincent Bernat Date: Sun, 31 Mar 2013 16:33:33 +0000 (+0200) Subject: lldpd: enforce TTL on remote chassis X-Git-Tag: 0.7.2~16 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3333d2a8a81053b4522576f8e4b12c93beab0a26;p=thirdparty%2Flldpd.git lldpd: enforce TTL on remote chassis Remote chassis were not expired in a timely manner. They were only expired when a change happened on an interface. To fix this, we maintain a timer that will be triggered when an interface is about to expire. The timer is updated when a change happens and rescheduled once it is run. --- diff --git a/NEWS b/NEWS index d240a977..27ac150e 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,7 @@ lldpd (0.7.2) * Fixes: + Driver whitelisting is done before checking if an interface has a lower interface in Linux. + + Expire remote ports and chassis in a timely manner. lldpd (0.7.1) * Features diff --git a/src/daemon/event.c b/src/daemon/event.c index 31903ee5..07734bb9 100644 --- a/src/daemon/event.c +++ b/src/daemon/event.c @@ -512,6 +512,7 @@ levent_hardware_recv(evutil_socket_t fd, short what, void *arg) log_debug("event", "received something for %s", hardware->h_ifname); lldpd_recv(cfg, hardware, fd); + levent_schedule_cleanup(cfg); } void @@ -657,6 +658,52 @@ levent_iface_subscribe(struct lldpd *cfg, int socket) return 0; } +static void +levent_trigger_cleanup(evutil_socket_t fd, short what, void *arg) +{ + struct lldpd *cfg = arg; + lldpd_cleanup(cfg); +} + +void +levent_schedule_cleanup(struct lldpd *cfg) +{ + log_debug("event", "schedule next cleanup"); + if (cfg->g_cleanup_timer != NULL) { + event_free(cfg->g_cleanup_timer); + } + cfg->g_cleanup_timer = evtimer_new(cfg->g_base, levent_trigger_cleanup, cfg); + if (cfg->g_cleanup_timer == NULL) { + log_warnx("event", + "unable to allocate a new event for cleanup tasks"); + return; + } + + /* Compute the next TTL event */ + struct timeval tv = { LOCAL_CHASSIS(cfg)->c_ttl, 0 }; + time_t now = time(NULL); + time_t next; + struct lldpd_hardware *hardware; + struct lldpd_port *port; + TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) { + TAILQ_FOREACH(port, &hardware->h_rports, p_entries) { + next = port->p_chassis->c_ttl - (now - port->p_lastupdate); + if (next > 0 && next < tv.tv_sec) + tv.tv_sec = next; + } + } + + log_debug("event", "next cleanup in %ld seconds", + (long)tv.tv_sec); + if (event_add(cfg->g_cleanup_timer, &tv) == -1) { + log_warnx("event", + "unable to schedula cleanup task"); + event_free(cfg->g_cleanup_timer); + cfg->g_cleanup_timer = NULL; + return; + } +} + static void levent_send_pdu(evutil_socket_t fd, short what, void *arg) { diff --git a/src/daemon/lldpd.c b/src/daemon/lldpd.c index 032f9b7a..303ee52f 100644 --- a/src/daemon/lldpd.c +++ b/src/daemon/lldpd.c @@ -271,13 +271,13 @@ lldpd_reset_timer(struct lldpd *cfg) } } -static void +void lldpd_cleanup(struct lldpd *cfg) { struct lldpd_hardware *hardware, *hardware_next; struct lldpd_chassis *chassis, *chassis_next; - log_debug("alloc", "cleanup all local ports"); + log_debug("localchassis", "cleanup all ports"); for (hardware = TAILQ_FIRST(&cfg->g_hardware); hardware != NULL; hardware = hardware_next) { @@ -290,7 +290,7 @@ lldpd_cleanup(struct lldpd *cfg) lldpd_remote_cleanup(hardware, notify_clients_deletion); } - log_debug("alloc", "cleanup all chassis"); + log_debug("localchassis", "cleanup all chassis"); for (chassis = TAILQ_FIRST(&cfg->g_chassis); chassis; chassis = chassis_next) { @@ -300,6 +300,8 @@ lldpd_cleanup(struct lldpd *cfg) lldpd_chassis_cleanup(chassis, 1); } } + + levent_schedule_cleanup(cfg); } /* Update chassis `ochassis' with values from `chassis'. The later one is not diff --git a/src/daemon/lldpd.h b/src/daemon/lldpd.h index 38e8f83e..b8fe9400 100644 --- a/src/daemon/lldpd.h +++ b/src/daemon/lldpd.h @@ -98,6 +98,7 @@ struct lldpd { struct protocol *g_protocols; int g_lastrid; struct event *g_main_loop; + struct event *g_cleanup_timer; #ifdef USE_SNMP int g_snmp; struct event *g_snmp_timeout; @@ -130,6 +131,7 @@ void lldpd_send(struct lldpd_hardware *); void lldpd_loop(struct lldpd *); int lldpd_main(int, char **); void lldpd_update_localports(struct lldpd *); +void lldpd_cleanup(struct lldpd *); /* frame.c */ u_int16_t frame_checksum(const u_int8_t *, int, int); @@ -143,6 +145,7 @@ void levent_ctl_notify(char *, int, struct lldpd_port *); void levent_send_now(struct lldpd *); int levent_iface_subscribe(struct lldpd *, int); void levent_schedule_pdu(struct lldpd_hardware *); +void levent_schedule_cleanup(struct lldpd *); /* lldp.c */ int lldp_send(PROTO_SEND_SIG); diff --git a/src/lldpd-structs.c b/src/lldpd-structs.c index 1ce898e8..758be94f 100644 --- a/src/lldpd-structs.c +++ b/src/lldpd-structs.c @@ -112,6 +112,7 @@ lldpd_remote_cleanup(struct lldpd_hardware *hardware, { struct lldpd_port *port, *port_next; int del; + time_t now = time(NULL); log_debug("alloc", "cleanup remote port on %s", hardware->h_ifname); @@ -121,7 +122,7 @@ lldpd_remote_cleanup(struct lldpd_hardware *hardware, port_next = TAILQ_NEXT(port, p_entries); del = (expire == NULL); if (expire && - (time(NULL) - port->p_lastupdate > port->p_chassis->c_ttl)) { + (now - port->p_lastupdate > port->p_chassis->c_ttl)) { hardware->h_ageout_cnt++; hardware->h_delete_cnt++; expire(hardware, port);