summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-06-07 13:52:01 +0200
committerThomas Haller <thaller@redhat.com>2014-06-19 22:26:10 +0200
commita2791f54da771cf7354dfdc4a420aaf772a8c6ee (patch)
treeef4a5901fa53b9e05e00c7980ad11578875dce60
parent31db488396373e06aa5694cb34213f0f30f727d1 (diff)
downloadNetworkManager-a2791f54da771cf7354dfdc4a420aaf772a8c6ee.tar.gz
platform: set timestamp in platform addresses to last_update_time()
Previous patch 8310a039d81e3a316cf657aa9f28edabb9be125c modified platform to set the timestamp of addresses always to 1. So, when adding an address platform logging looked like: signal: address 4 added: 192.168.232.3/24 lft 2000sec pref 1000sec lifetime 12345-1[13344,14344] dev em1 src kernel This is confusing in the log file and during debugging. Instead set the timestamp to the last modification time of the address so that it will look like: signal: address 4 added: 192.168.232.3/24 lft 2000sec pref 1000sec lifetime 12345-12345[1000,2000] dev em1 src kernel Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/platform/nm-linux-platform.c85
-rw-r--r--src/platform/nm-platform.h5
2 files changed, 79 insertions, 11 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 7e8ba66e8a..f5da671380 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -1049,6 +1049,75 @@ _get_remaining_time (guint32 start_timestamp, guint32 end_timestamp)
return end_timestamp - start_timestamp;
}
+/* _timestamp_nl_to_ms:
+ * @timestamp_nl: a timestamp from ifa_cacheinfo.
+ * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
+ * uptime and how often timestamp_nl wrapped.
+ *
+ * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
+ * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
+ * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
+ * the uint32 counter wraps every 497 days of uptime, so we have to compensate
+ * for that. */
+static gint64
+_timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
+{
+ const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
+ gint64 timestamp_nl_ms;
+
+ /* convert timestamp from 1/100th of a second to msec. */
+ timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);
+
+ /* timestamp wraps every 497 days. Try to compensate for that.*/
+ if (timestamp_nl_ms > monotonic_ms) {
+ /* timestamp_nl_ms is in the future. Truncate it to *now* */
+ timestamp_nl_ms = monotonic_ms;
+ } else if (monotonic_ms >= WRAP_INTERVAL) {
+ timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
+ if (timestamp_nl_ms > monotonic_ms)
+ timestamp_nl_ms -= WRAP_INTERVAL;
+ }
+
+ return timestamp_nl_ms;
+}
+
+static guint32
+_rtnl_addr_last_update_time_to_nm (const struct rtnl_addr *rtnladdr)
+{
+ guint32 last_update_time = rtnl_addr_get_last_update_time ((struct rtnl_addr *) rtnladdr);
+ struct timespec tp;
+ gint64 now_nl, now_nm, result;
+
+ /* timestamp is unset. Default to 1. */
+ if (!last_update_time)
+ return 1;
+
+ /* do all the calculations in milliseconds scale */
+
+ clock_gettime (CLOCK_MONOTONIC, &tp);
+ now_nm = nm_utils_get_monotonic_timestamp_ms ();
+ now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
+ (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
+
+ result = now_nm - (now_nl - _timestamp_nl_to_ms (last_update_time, now_nl));
+
+ /* converting the last_update_time into nm_utils_get_monotonic_timestamp_ms() scale is
+ * a good guess but fails in the following situations:
+ *
+ * - If the address existed before start of the process, the timestamp in nm scale would
+ * be negative or zero. In this case we default to 1.
+ * - during hibernation, the CLOCK_MONOTONIC/last_update_time drifts from
+ * nm_utils_get_monotonic_timestamp_ms() scale.
+ */
+ if (result <= 1000)
+ return 1;
+
+ if (result > now_nm)
+ return now_nm / 1000;
+
+ return result / 1000;
+}
+
static void
_init_ip_address_lifetime (NMPlatformIPAddress *address, const struct rtnl_addr *rtnladdr)
{
@@ -1083,17 +1152,15 @@ _init_ip_address_lifetime (NMPlatformIPAddress *address, const struct rtnl_addr
return;
}
- /* The correct timestamp value would probably be rtnl_addr_get_last_update_time()
- * (after converting into the proper time scale).
- * But this is relatively complicated to convert and we don't actually need it.
- * Especially, because rtnl_addr_get_last_update_time() might be negative in
- * nm_utils_get_monotonic_timestamp_s() scale -- which we want to avoid.
- *
- * Remember: timestamp has no meaning, beyond anchoring the relative lifetimes
- * at some point in time. We choose this point to be "1 second".
+ /* _rtnl_addr_last_update_time_to_nm() might be wrong, so don't rely on
+ * timestamp to have any meaning beyond anchoring the relative durations
+ * @lifetime and @preferred.
*/
- address->timestamp = 1;
+ address->timestamp = _rtnl_addr_last_update_time_to_nm (rtnladdr);
+ /* We would expect @timestamp to be less then @a_valid. Just to be sure,
+ * fix it up. */
+ address->timestamp = MIN (address->timestamp, a_valid - 1);
address->lifetime = _get_remaining_time (address->timestamp, a_valid);
address->preferred = _get_remaining_time (address->timestamp, a_preferred);
}
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index f7b14b7b9b..7dc0127648 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -169,8 +169,9 @@ typedef struct {
/* Timestamp in seconds in the reference system of nm_utils_get_monotonic_timestamp_*().
* This value is mainly used to anchor the relative lifetime and preferred values.
* For addresses originating from DHCP it might be set to nm_utils_get_monotonic_timestamp_s()
- * of when the lease was received. For addresses from platform/kernel it is set to 1.
- * For permanent addresses it is mostly set to 0.
+ * of when the lease was received. For addresses from platform/kernel it might be set to
+ * when the address was last modified. For permanent addresses it is mostly set to 0.
+ * For non-permanent addresses it should not be 0 (because 0 is not a valid timestamp).
*/ \
guint32 timestamp; \
guint32 lifetime; /* seconds since timestamp */ \