From 16fed825d60ca1efa57d0b9231842cda9aae7a68 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 30 May 2016 22:11:47 +0200 Subject: sd-lldp: take triple timestamp when reading LLDP packets 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 | 26 +++++++++++++++++++++++--- src/libsystemd-network/lldp-neighbor.h | 2 ++ src/libsystemd-network/sd-lldp.c | 8 ++++++++ src/systemd/sd-lldp.h | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c index 6a716430e3..c14126b60a 100644 --- a/src/libsystemd-network/lldp-neighbor.c +++ b/src/libsystemd-network/lldp-neighbor.c @@ -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; +} diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h index f203bfa604..27a27055f1 100644 --- a/src/libsystemd-network/lldp-neighbor.h +++ b/src/libsystemd-network/lldp-neighbor.h @@ -43,6 +43,8 @@ struct sd_lldp_neighbor { sd_lldp *lldp; unsigned n_ref; + triple_timestamp timestamp; + usec_t until; unsigned prioq_idx; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 9d4587c80e..223a5ac02f 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -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); } diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 5772d5794a..617e0f1e17 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -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. */ -- cgit v1.2.3-54-g00ecf