74b53c
From 6010876e561b4345e569ffd11eaec9ea52725817 Mon Sep 17 00:00:00 2001
1050b1
From: Pavel Zhukov <pzhukov@redhat.com>
1050b1
Date: Wed, 24 Jul 2019 17:15:55 +0200
1050b1
Subject: [PATCH] Detect system time jumps
1050b1
1050b1
In case if system time was changed backward it's possible to have ip
1050b1
address dropped by the kernel due to lifetime expirity. Try to detect
1050b1
this situation using either monotonic time or saved timestamp and execute
1050b1
go_reboot() procedure to request lease extention
1050b1
---
371a1e
 lib/isc/include/isc/result.h    |  3 ++-
371a1e
 lib/isc/include/isc/util.h      |  3 +++
1050b1
 lib/isc/result.c                |  2 ++
371a1e
 lib/isc/unix/app.c              | 39 +++++++++++++++++++++++++++++----
371a1e
 lib/isc/unix/include/isc/time.h | 20 +++++++++++++++++
371a1e
 lib/isc/unix/time.c             | 22 +++++++++++++++++++
371a1e
 6 files changed, 84 insertions(+), 5 deletions(-)
1050b1
1050b1
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
74b53c
index 0389efa..149cde5 100644
1050b1
--- a/lib/isc/include/isc/result.h
1050b1
+++ b/lib/isc/include/isc/result.h
74b53c
@@ -89,7 +89,8 @@
371a1e
 #define ISC_R_DISCFULL			67	/*%< disc full */
74b53c
 #define ISC_R_DEFAULT			68	/*%< default */
74b53c
 #define ISC_R_IPV4PREFIX		69	/*%< IPv4 prefix */
74b53c
-#define ISC_R_NRESULTS 			70
74b53c
+#define ISC_R_TIMESHIFTED               70      /*%< system time changed */
74b53c
+#define ISC_R_NRESULTS 			71
1050b1
 
1050b1
 ISC_LANG_BEGINDECLS
1050b1
 
1050b1
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
371a1e
index 973c348..8160dd3 100644
1050b1
--- a/lib/isc/include/isc/util.h
1050b1
+++ b/lib/isc/include/isc/util.h
371a1e
@@ -289,6 +289,9 @@ extern void mock_assert(const int result, const char* const expression,
1050b1
  * Time
1050b1
  */
1050b1
 #define TIME_NOW(tp) 	RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+#define TIME_MONOTONIC(tp) 	RUNTIME_CHECK(isc_time_boottime((tp)) == ISC_R_SUCCESS)
1050b1
+#endif
1050b1
 
1050b1
 /*%
371a1e
  * Alignment
1050b1
diff --git a/lib/isc/result.c b/lib/isc/result.c
74b53c
index a9db132..7c04831 100644
1050b1
--- a/lib/isc/result.c
1050b1
+++ b/lib/isc/result.c
74b53c
@@ -105,6 +105,7 @@ static const char *description[ISC_R_NRESULTS] = {
371a1e
 	"disc full",				/*%< 67 */
74b53c
 	"default",				/*%< 68 */
74b53c
 	"IPv4 prefix",				/*%< 69 */
74b53c
+        "time changed",                         /*%< 70 */
1050b1
 };
1050b1
 
1050b1
 static const char *identifier[ISC_R_NRESULTS] = {
74b53c
@@ -178,6 +179,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
371a1e
 	"ISC_R_DISCFULL",
74b53c
 	"ISC_R_DEFAULT",
74b53c
 	"ISC_R_IPV4PREFIX",
1050b1
+        "ISC_R_TIMESHIFTED",
1050b1
 };
1050b1
 
1050b1
 #define ISC_RESULT_RESULTSET			2
1050b1
diff --git a/lib/isc/unix/app.c b/lib/isc/unix/app.c
74b53c
index a6e9882..52eb3e0 100644
1050b1
--- a/lib/isc/unix/app.c
1050b1
+++ b/lib/isc/unix/app.c
371a1e
@@ -442,15 +442,48 @@ isc__app_ctxonrun(isc_appctx_t *ctx0, isc_mem_t *mctx, isc_task_t *task,
1050b1
 static isc_result_t
1050b1
 evloop(isc__appctx_t *ctx) {
1050b1
 	isc_result_t result;
1050b1
+        isc_time_t now;
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+        isc_time_t monotonic;
371a1e
+        uint64_t diff  = 0;
1050b1
+#else
1050b1
+        isc_time_t prev;
1050b1
+        TIME_NOW(&prev;;
1050b1
+#endif
1050b1
+
1050b1
+
1050b1
 
1050b1
 	while (!ctx->want_shutdown) {
1050b1
 		int n;
1050b1
-		isc_time_t when, now;
1050b1
+		isc_time_t when;
1050b1
 		struct timeval tv, *tvp;
1050b1
 		isc_socketwait_t *swait;
371a1e
 		bool readytasks;
371a1e
 		bool call_timer_dispatch = false;
371a1e
-
371a1e
+                uint64_t us;
1050b1
+
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+                // TBD macros for following three lines
1050b1
+                TIME_NOW(&now;;
1050b1
+                TIME_MONOTONIC(&monotonic);
1050b1
+                INSIST(now.seconds > monotonic.seconds)
1050b1
+                us = isc_time_microdiff (&now, &monotonic);
371a1e
+                if (us < diff){
1050b1
+                  us = diff - us;
1050b1
+                  if (us > 1000000){ // ignoring shifts less than one second
1050b1
+                    return ISC_R_TIMESHIFTED;
1050b1
+                  };
1050b1
+                  diff = isc_time_microdiff (&now, &monotonic);
1050b1
+                } else {
1050b1
+                  diff = isc_time_microdiff (&now, &monotonic);
1050b1
+                  // not implemented
1050b1
+                }
1050b1
+#else
1050b1
+                TIME_NOW(&now;;
1050b1
+                if (isc_time_compare (&now, &prev) < 0)
1050b1
+                  return ISC_R_TIMESHIFTED;
1050b1
+                TIME_NOW(&prev;;
371a1e
+#endif
1050b1
 		/*
1050b1
 		 * Check the reload (or suspend) case first for exiting the
1050b1
 		 * loop as fast as possible in case:
371a1e
@@ -475,8 +508,6 @@ evloop(isc__appctx_t *ctx) {
1050b1
 			if (result != ISC_R_SUCCESS)
1050b1
 				tvp = NULL;
1050b1
 			else {
371a1e
-				uint64_t us;
371a1e
-
1050b1
 				TIME_NOW(&now;;
1050b1
 				us = isc_time_microdiff(&when, &now;;
1050b1
 				if (us == 0)
1050b1
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
371a1e
index b864c29..5dd43c9 100644
1050b1
--- a/lib/isc/unix/include/isc/time.h
1050b1
+++ b/lib/isc/unix/include/isc/time.h
371a1e
@@ -132,6 +132,26 @@ isc_time_isepoch(const isc_time_t *t);
1050b1
  *\li	't' is a valid pointer.
1050b1
  */
1050b1
 
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+isc_result_t
1050b1
+isc_time_boottime(isc_time_t *t);
1050b1
+/*%<
1050b1
+ * Set 't' to monotonic time from previous boot
1050b1
+ * it's not affected by system time change. It also
1050b1
+ * includes the time system was suspended
1050b1
+ *
1050b1
+ * Requires:
1050b1
+ *\li	't' is a valid pointer.
1050b1
+ *
1050b1
+ * Returns:
1050b1
+ *
1050b1
+ *\li	Success
1050b1
+ *\li	Unexpected error
1050b1
+ *		Getting the time from the system failed.
1050b1
+ */
1050b1
+#endif /* CLOCK_BOOTTIME */
1050b1
+ 
1050b1
+
1050b1
 isc_result_t
1050b1
 isc_time_now(isc_time_t *t);
1050b1
 /*%<
1050b1
diff --git a/lib/isc/unix/time.c b/lib/isc/unix/time.c
371a1e
index 8edc9df..fe0bb91 100644
1050b1
--- a/lib/isc/unix/time.c
1050b1
+++ b/lib/isc/unix/time.c
371a1e
@@ -498,3 +498,25 @@ isc_time_formatISO8601ms(const isc_time_t *t, char *buf, unsigned int len) {
1050b1
 			 t->nanoseconds / NS_PER_MS);
1050b1
 	}
1050b1
 }
1050b1
+
1050b1
+
1050b1
+#ifdef CLOCK_BOOTTIME
1050b1
+isc_result_t
1050b1
+isc_time_boottime(isc_time_t *t) {
1050b1
+  struct timespec ts;
1050b1
+  
1050b1
+  char strbuf[ISC_STRERRORSIZE];
1050b1
+
1050b1
+  if (clock_gettime (CLOCK_BOOTTIME, &ts) != 0){
1050b1
+    isc__strerror(errno, strbuf, sizeof(strbuf));
1050b1
+    UNEXPECTED_ERROR(__FILE__, __LINE__, "%s", strbuf);
1050b1
+    return (ISC_R_UNEXPECTED);    
1050b1
+  }
1050b1
+
1050b1
+  t->seconds = ts.tv_sec;
1050b1
+  t->nanoseconds = ts.tv_nsec;
1050b1
+
1050b1
+  return (ISC_R_SUCCESS);
1050b1
+  
1050b1
+};
1050b1
+#endif
1050b1
-- 
1050b1
2.20.1
1050b1