1050b1
From 9ac315c16bf8441145f5b4b8a3308ae9f03582ab 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
---
1050b1
 lib/isc/include/isc/result.h    |  4 ++--
1050b1
 lib/isc/include/isc/util.h      |  4 ++++
1050b1
 lib/isc/result.c                |  2 ++
1050b1
 lib/isc/unix/app.c              | 41 +++++++++++++++++++++++++++++++--
1050b1
 lib/isc/unix/include/isc/time.h | 20 ++++++++++++++++
1050b1
 lib/isc/unix/time.c             | 22 ++++++++++++++++++
1050b1
 6 files changed, 89 insertions(+), 4 deletions(-)
1050b1
1050b1
diff --git a/lib/isc/include/isc/result.h b/lib/isc/include/isc/result.h
1050b1
index 246aefb..70d4b64 100644
1050b1
--- a/lib/isc/include/isc/result.h
1050b1
+++ b/lib/isc/include/isc/result.h
1050b1
@@ -83,9 +83,9 @@
1050b1
 #define ISC_R_UNSET			61	/*%< unset */
1050b1
 #define ISC_R_MULTIPLE			62	/*%< multiple */
1050b1
 #define ISC_R_WOULDBLOCK		63	/*%< would block */
1050b1
-
1050b1
+#define ISC_R_TIMESHIFTED               64      /*%< system time changed */
1050b1
 /*% Not a result code: the number of results. */
1050b1
-#define ISC_R_NRESULTS 			64
1050b1
+#define ISC_R_NRESULTS 			65
1050b1
 
1050b1
 ISC_LANG_BEGINDECLS
1050b1
 
1050b1
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
1050b1
index 332dc0c..f81967d 100644
1050b1
--- a/lib/isc/include/isc/util.h
1050b1
+++ b/lib/isc/include/isc/util.h
1050b1
@@ -233,6 +233,10 @@
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
 
1050b1
 /*%
1050b1
  * Misc
1050b1
diff --git a/lib/isc/result.c b/lib/isc/result.c
1050b1
index a707c32..6776fc6 100644
1050b1
--- a/lib/isc/result.c
1050b1
+++ b/lib/isc/result.c
1050b1
@@ -99,6 +99,7 @@ static const char *description[ISC_R_NRESULTS] = {
1050b1
 	"unset",				/*%< 61 */
1050b1
 	"multiple",				/*%< 62 */
1050b1
 	"would block",				/*%< 63 */
1050b1
+        "time changed",                         /*%< 64 */
1050b1
 };
1050b1
 
1050b1
 static const char *identifier[ISC_R_NRESULTS] = {
1050b1
@@ -166,6 +167,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
1050b1
 	"ISC_R_UNSET",
1050b1
 	"ISC_R_MULTIPLE",
1050b1
 	"ISC_R_WOULDBLOCK",
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
1050b1
index bace2bd..e9814d2 100644
1050b1
--- a/lib/isc/unix/app.c
1050b1
+++ b/lib/isc/unix/app.c
1050b1
@@ -441,15 +441,51 @@ 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;
1050b1
+        isc_uint64_t diff  = 0;
1050b1
+#else
1050b1
+        isc_time_t prev;
1050b1
+        TIME_NOW(&prev;;
1050b1
+#endif
1050b1
+
1050b1
+
1050b1
+
1050b1
 
1050b1
 	while (!ctx->want_shutdown) {
1050b1
 		int n;
1050b1
-		isc_time_t when, now;
1050b1
+		isc_time_t when;
1050b1
+                
1050b1
 		struct timeval tv, *tvp;
1050b1
 		isc_socketwait_t *swait;
1050b1
 		isc_boolean_t readytasks;
1050b1
 		isc_boolean_t call_timer_dispatch = ISC_FALSE;
1050b1
 
1050b1
+                isc_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);
1050b1
+                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;;
1050b1
+#endif                
1050b1
 		/*
1050b1
 		 * Check the reload (or suspend) case first for exiting the
1050b1
 		 * loop as fast as possible in case:
1050b1
@@ -474,9 +510,10 @@ evloop(isc__appctx_t *ctx) {
1050b1
 			if (result != ISC_R_SUCCESS)
1050b1
 				tvp = NULL;
1050b1
 			else {
1050b1
-				isc_uint64_t us;
1050b1
+
1050b1
 
1050b1
 				TIME_NOW(&now;;
1050b1
+
1050b1
 				us = isc_time_microdiff(&when, &now;;
1050b1
 				if (us == 0)
1050b1
 					call_timer_dispatch = ISC_TRUE;
1050b1
diff --git a/lib/isc/unix/include/isc/time.h b/lib/isc/unix/include/isc/time.h
1050b1
index 75e24b9..de8b399 100644
1050b1
--- a/lib/isc/unix/include/isc/time.h
1050b1
+++ b/lib/isc/unix/include/isc/time.h
1050b1
@@ -129,6 +129,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
1050b1
index 2210240..d7613b8 100644
1050b1
--- a/lib/isc/unix/time.c
1050b1
+++ b/lib/isc/unix/time.c
1050b1
@@ -496,3 +496,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