]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-lldp: take triple timestamp when reading LLDP packets
authorLennart Poettering <lennart@poettering.net>
Mon, 30 May 2016 20:11:47 +0000 (22:11 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 6 Jun 2016 17:59:07 +0000 (19:59 +0200)
It's a good idea to store away the recption time of LLDP packets in the
neighbor object, simply because the LLDP data only has a validity of a certain
amount of time.

Hence, let's record the timestamp when we receive the datagram and expose an
API for it. Also, automatically expire LLDP neighbors based on this new
timestamp.

src/libsystemd-network/lldp-neighbor.c
src/libsystemd-network/lldp-neighbor.h
src/libsystemd-network/sd-lldp.c
src/systemd/sd-lldp.h

index 6a716430e3fe0190aff15d651dee83472fd58375..c14126b60ab51237df4fb7d4bb9938c7e8c1fbdb 100644 (file)
@@ -360,9 +360,16 @@ end_marker:
 void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
         assert(n);
 
-        if (n->ttl > 0)
-                n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC);
-        else
+        if (n->ttl > 0) {
+                usec_t base;
+
+                /* Use the packet's timestamp if there is one known */
+                base = triple_timestamp_by_clock(&n->timestamp, clock_boottime_or_monotonic());
+                if (base <= 0 || base == USEC_INFINITY)
+                        base = now(clock_boottime_or_monotonic()); /* Otherwise, take the current time */
+
+                n->until = usec_add(base, n->ttl * USEC_PER_SEC);
+        } else
                 n->until = 0;
 
         if (n->lldp)
@@ -792,3 +799,16 @@ _public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret,
 
         return 0;
 }
+
+int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret) {
+        assert_return(n, -EINVAL);
+        assert_return(TRIPLE_TIMESTAMP_HAS_CLOCK(clock), -EOPNOTSUPP);
+        assert_return(clock_supported(clock), -EOPNOTSUPP);
+        assert_return(ret, -EINVAL);
+
+        if (!triple_timestamp_is_set(&n->timestamp))
+                return -ENODATA;
+
+        *ret = triple_timestamp_by_clock(&n->timestamp, clock);
+        return 0;
+}
index f203bfa6048a56a8c258e8c0392d5ed7d68beabf..27a27055f119de0491e3c89069241523a28e86de 100644 (file)
@@ -43,6 +43,8 @@ struct sd_lldp_neighbor {
         sd_lldp *lldp;
         unsigned n_ref;
 
+        triple_timestamp timestamp;
+
         usec_t until;
         unsigned prioq_idx;
 
index 9d4587c80e65522fa5b019d2f5c06b71819b8cc7..223a5ac02f0b4a82a3c5c2054d909db3a718b47e 100644 (file)
@@ -138,6 +138,7 @@ static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
 
                 if (lldp_neighbor_equal(n, old)) {
                         /* Is this equal, then restart the TTL counter, but don't do anyting else. */
+                        old->timestamp = n->timestamp;
                         lldp_start_timer(lldp, old);
                         lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
                         return 0;
@@ -202,6 +203,7 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
         _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
         ssize_t space, length;
         sd_lldp *lldp = userdata;
+        struct timespec ts;
 
         assert(fd >= 0);
         assert(lldp);
@@ -223,6 +225,12 @@ static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, v
                 return -EINVAL;
         }
 
+        /* Try to get the timestamp of this packet if it is known */
+        if (ioctl(fd, SIOCGSTAMPNS, &ts) >= 0)
+                triple_timestamp_from_realtime(&n->timestamp, timespec_load(&ts));
+        else
+                triple_timestamp_get(&n->timestamp);
+
         return lldp_handle_datagram(lldp, n);
 }
 
index 5772d5794a19380f67906606e6a374500b030633..617e0f1e17becda86f4dbc493473d62efdea8f92 100644 (file)
@@ -145,6 +145,7 @@ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
 /* Access to LLDP frame metadata */
 int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
 int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
+int sd_lldp_neighbor_get_timestamp(sd_lldp_neighbor *n, clockid_t clock, uint64_t *ret);
 int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
 
 /* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */