]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldpd: enforce TTL on remote chassis
authorVincent Bernat <bernat@luffy.cx>
Sun, 31 Mar 2013 16:33:33 +0000 (18:33 +0200)
committerVincent Bernat <bernat@luffy.cx>
Sun, 31 Mar 2013 16:33:33 +0000 (18:33 +0200)
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.

NEWS
src/daemon/event.c
src/daemon/lldpd.c
src/daemon/lldpd.h
src/lldpd-structs.c

diff --git a/NEWS b/NEWS
index d240a97792a409e051aa03f7d35ab8da40df921b..27ac150eb296220357eb0cb5a74aac54265d39d9 100644 (file)
--- 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
index 31903ee5601e569d5d52158a96f8a11c6d5f6928..07734bb9ab80a9f3e7267f7fd70505cc447dcac6 100644 (file)
@@ -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)
 {
index 032f9b7a4d89f9a07f7a86462242596c92a8c844..303ee52f34586b506b2ef9e6406aceebc5079153 100644 (file)
@@ -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
index 38e8f83e09397966a5fb557f53ae181a2934a895..b8fe940063b23a5edbc90f08b82c3540a194ca83 100644 (file)
@@ -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);
index 1ce898e8affb0f5aec48964755fab75c203b4c38..758be94faba762d0393cff1a670f97eae6983949 100644 (file)
@@ -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);