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