On Wed, Nov 07, 2018 at 06:40:20PM +0000, Gareth Ansell scribbled:
# Hi, I can confirm that this is also happening on my VM, also hosted at
# openbsd.amsterdam.
# Gareth

Same here, and none of the tricks I was finding worked.  I was also
unsatisfied with the idea of running rdate or restarting ntpd often
enough to keep things in sync.  Making use of the vmmci(4) timedelta
sensor, I found and modified a piece of existing code by Ted U. to
work around this problem until someone far smarter than I figures out
a proper solution.

Attached, but linked as well in case the attachment doesn't make it.

  https://slite.zenbsd.net/~jontow/vmtimed.c

Neither perfect nor desirable, but workable!  It makes a lot of
adjustments and has been doing an ok job so far.  Doesn't seem to
perfectly keep the clock in a synced state according to "ntpctl -sa".
Here's what it looks like running, and these are the sorts of deltas
it regularly sees and applies.

Nov  6 00:54:43 frea vmtimed: fixing time! -1.152683
Nov  6 00:56:11 frea vmtimed: fixing time! -1.045395
Nov  6 00:58:08 frea vmtimed: fixing time! -1.236222

Here's "ntpctl -sa" as of right now:

4/4 peers valid, 1/1 sensors valid, constraint offset -198s (16 errors), clock 
synced, stratum 1

peer
   wt tl st  next  poll          offset       delay      jitter
80.127.152.30 from pool pool.ntp.org
    1 10  2  332s 3126s       705.111ms     5.394ms     0.974ms
195.242.98.57 from pool pool.ntp.org
    1 10  2  245s 3183s       657.527ms     2.126ms     0.410ms
93.94.224.67 from pool pool.ntp.org
    1 10  2   53s 3147s       687.997ms     1.931ms     0.532ms
95.211.212.5 from pool pool.ntp.org
    1 10  2 2657s 3118s        73.136ms     2.432ms     0.829ms

sensor
   wt gd st  next  poll          offset  correction
vmmci0  
 *  1  1  0    8s   15s       689.722ms     0.000ms

-- Jonathan Towne
/*
 * Original code by Ted Unangst <t...@tedunangst.com>
 * https://https.www.google.com.tedunangst.com/flak/post/vmtimed
 *
 * Lightly modified by Jonathan Towne <jon...@mototowne.com>
 * For use in vmd(8) hosted VMs using vmmci(4) timedelta sensor.
 * Still probably works with VMware vmt(4), but untested.
 * Works best in concert with ntpd(8) running normally.
 */

/* If time drifts more than +/- SENSITIVITY seconds, hard adjust */
#define SENSITIVITY 1
/* Check timedelta sensor value every SLEEPFOR seconds */ 
#define SLEEPFOR 15

#undef DEBUG

#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/sensors.h>
#include <sys/time.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <err.h>

void
error(const char *msg)
{
        syslog(LOG_DAEMON | LOG_ERR, "%s", msg);
        exit(1);
}

int
findvmt0(void)
{
        struct sensordev sdev;
        size_t slen;
        int mib[5];
        int i;

        mib[0] = CTL_HW;
        mib[1] = HW_SENSORS;
        for (i = 0; i < 20; i++) {
                mib[2] = i;
                slen = sizeof(sdev);
                if (sysctl(mib, 3, &sdev, &slen, NULL, 0) == -1)
                        break;
                if (strcmp(sdev.xname, "vmmci0") == 0)
                        return i;
                if (strcmp(sdev.xname, "vmt0") == 0)
                        return i;
        }
        return -1;
}

void
timeloop(int vmt0)
{
        struct sensor sensor;
        size_t slen;
        int mib[5];
        struct timeval tv;
        double delta;

        mib[0] = CTL_HW;
        mib[1] = HW_SENSORS;
        mib[2] = vmt0;
        mib[3] = SENSOR_TIMEDELTA;
        mib[4] = 0;
        while (1) {
                slen = sizeof(sensor);
                if (sysctl(mib, 5, &sensor, &slen, NULL, 0) == -1)
                        err(1, "sysctl");
                delta = sensor.value / 1000000000.0;
#ifdef DEBUG
                printf("%f: timeloop()\n", delta);
#endif
                if (delta < (-1 * SENSITIVITY) || delta > SENSITIVITY) {
                        syslog(LOG_DAEMON | LOG_NOTICE,
                            "fixing time! %f\n", delta);
                        if (gettimeofday(&tv, NULL) == -1)
                                error("gettimeofday");
                        tv.tv_sec -= delta;
                        if (settimeofday(&tv, NULL) == -1)
                                error("settimeofday");
                }
                sleep(SLEEPFOR);
        }
}

int
main(int argc, char **argv)
{
        int vmt0;

        vmt0 = findvmt0();
        if (vmt0 == -1)
                error("can't find vmt0");

        timeloop(vmt0);
}

Reply via email to