]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldpd: don't rely on a checksum to detect a port change
authorVincent Bernat <vincent@bernat.im>
Sat, 6 Dec 2014 23:05:53 +0000 (00:05 +0100)
committerVincent Bernat <vincent@bernat.im>
Sat, 6 Dec 2014 23:05:53 +0000 (00:05 +0100)
Instead, just compare the serialized copies. This is more reliable than
a checksum and also (a bit) faster.

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

index 437efc2bd8138060ebb25a0edfc7477c008ff633..c4b923df62d0b7939d19c3b28d6e178e8a037760 100644 (file)
@@ -207,6 +207,7 @@ lldpd_hardware_cleanup(struct lldpd *cfg, struct lldpd_hardware *hardware)
 {
        log_debug("alloc", "cleanup hardware port %s", hardware->h_ifname);
 
+       free(hardware->h_lport_previous);
        lldpd_port_cleanup(&hardware->h_lport, 1);
        if (hardware->h_ops && hardware->h_ops->cleanup)
                hardware->h_ops->cleanup(cfg, hardware);
@@ -292,11 +293,10 @@ lldpd_reset_timer(struct lldpd *cfg)
        /* Reset timer for ports that have been changed. */
        struct lldpd_hardware *hardware;
        TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries) {
-               /* We need to compute a checksum of the local port. To do this,
-                * we zero out fields that are not significant, marshal the
-                * port, compute the checksum, then restore. */
+               /* We keep a flat copy of the local port to see if there is any
+                * change. To do this, we zero out fields that are not
+                * significant, marshal the port, then restore. */
                struct lldpd_port *port = &hardware->h_lport;
-               u_int32_t cksum;
                u_int8_t *output = NULL;
                ssize_t output_len;
                char save[LLDPD_PORT_START_MARKER];
@@ -312,24 +312,25 @@ lldpd_reset_timer(struct lldpd *cfg)
                            hardware->h_ifname);
                        continue;
                }
-               /* Port change is detected by computing a checksum. 0 means the
-                * checksum never was computed (new interface). */
-               cksum  = frame_checksum(output, output_len/2, 0) << 16;
-               cksum += frame_checksum(output + output_len/2,
-                   output_len - output_len/2, 0);
-               cksum  = cksum?cksum:1;
-               free(output);
-               if (cksum != hardware->h_lport_cksum) {
+
+               /* Compare with the previous value */
+               if (hardware->h_lport_previous &&
+                   output_len == hardware->h_lport_previous_len &&
+                   !memcmp(output, hardware->h_lport_previous, output_len)) {
                        log_debug("localchassis",
-                           "change detected for port %s, resetting its timer",
+                           "no change detected for port %s",
                            hardware->h_ifname);
-                       hardware->h_lport_cksum = cksum;
-                       levent_schedule_pdu(hardware);
                } else {
                        log_debug("localchassis",
-                           "no change detected for port %s",
+                           "change detected for port %s, resetting its timer",
                            hardware->h_ifname);
+                       levent_schedule_pdu(hardware);
                }
+
+               /* Update the value */
+               free(hardware->h_lport_previous);
+               hardware->h_lport_previous = output;
+               hardware->h_lport_previous_len = output_len;
        }
 }
 
index e97276813e8b8e6bfa714964b327d13c8f7da0a1..b0828d2f20add9d290887dd2f0bf2313d9c72184 100644 (file)
@@ -398,7 +398,8 @@ struct lldpd_hardware {
        u_int64_t                h_delete_cnt;
        u_int64_t                h_drop_cnt;
 
-       u_int32_t                h_lport_cksum; /* Checksum on local port to see if there is a change */
+       void                    *h_lport_previous; /* Backup of last value for localport */
+       ssize_t                  h_lport_previous_len;
        struct lldpd_port        h_lport;  /* Port attached to this hardware port */
        TAILQ_HEAD(, lldpd_port) h_rports; /* Remote ports */