UTM icon indicating copy to clipboard operation
UTM copied to clipboard

Time inside VM goes out of sync

Open JaiganeshKumaran opened this issue 2 years ago • 16 comments

Describe the issue When running VMs in the background over a long period of time, the time inside the VM goes out of sync after not using the VM for some time. This happens in all VMs regardless of the guest operating system.

Configuration

  • UTM Version: 2.3.1 (38)
  • Intel or Apple Silicon? Apple Silicon

JaiganeshKumaran avatar Oct 28 '21 14:10 JaiganeshKumaran

I also have this issue, every time the host suspends. I thought the right thing to do was to install the qemu-guest-agent, but I cannot get that to work, as /dev/virtio-ports/org.qemu.guest_agent.0 doesn't exist.

mdillavou avatar Oct 28 '21 16:10 mdillavou

@mdillavou for UTM VMs with "Full Graphics" display mode (default) you need to use SPICE guest agent instead of the QEMU guest agent. (sudo apt install spice-vdagent) This might not be entirely useful for this issue, as spice-vdagent is only for the mouse and resolution features.

When running VMs through (non-SPICE) QEMU, it looks like the QEMU guest agent uses a serial port interface. QEMU wiki contains very similar looking arguments to enable the guest agent serial port like the ones in use by UTM for the SPICE agent (note that UTM uses QMP to communicate with running VMs). I am confused if these are compatible or even if they can be used at the same time.

I wanted to try this, so I pasted these lines to the QEMU tab of the UTM VM configuration UI:

 -chardev qga_proxy,id=qga0
 -device virtio-serial
 -device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0

Results in an error message when I attempt to start the VM:

qemu-aarch64-softmmu: -chardev qga_proxy,id=qga0: 'qga_proxy' is not a valid char driver name

I am out of my depth here, but I guess the QEMU included with UTM is built without the guest agent included.

conath avatar Oct 29 '21 21:10 conath

As far as I know, SPICE only deals with the display and clipboard, not time.

For the guest agent, I configured mine with the following:

-chardev socket,path=qga.sock,server,nowait,id=qga0
-device virtio-serial
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0

My VM started up fine, and I was able to successfully start the guest agent, as the /dev/virtio-ports/org.qemu.guest_agent.0 now exists, but it doesn't appear to do anything. I think the problem is the path=qga.sock, as I am not sure what the host path should be as I don't know what UTM tries to connect to.

mdillavou avatar Nov 02 '21 17:11 mdillavou

@mdillavou If you install socat, then you can do this:

  1. Run the VM with these additional qemu arguments:
-chardev socket,path=qga.sock,server,nowait,id=qga0
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
  1. (Inside the VM): Start the qemu-ga
  2. (In the host Mac): Run socat unix-connect:/Users/$USERNAME/Library/Containers/com.utmapp.QEMUHelper/Data/qga.sock readline
  3. (In the socat session): Type in {"execute":"guest-sync", "arguments":{"id":1234}} and press enter (this is just a safety step to make sure guest and host communication is in sync)
  4. (In the socat session): Type in {"execute":"guest-set-time"} and press enter. There's no need to specify the time argument since it can use host time.

Although this works, why not just run ntp in the guest (either manually or by restarting the ntp service)?

Technically all the additional QEMU arguments do is make a virtio serial port. It's just that it matches the name the qemu-ga expects but in theory you could specify name=anythingyouwant and run qemu-ga -p /dev/virtio-ports/anythingyouwant. The path=qga.sock is the entry point for communication to the /dev/virtio-ports/org.qemu.guest_agent port, and since it's a relative path it ends up in the Data folder of the com.utmapp.QEMUHelper sandbox.

ktprograms avatar Nov 04 '21 03:11 ktprograms

Interesting. That does work, but does UTM/qemu not come with an application to run on the host to connect to the socket and run those commands as appropriate? I suppose I could script something to manually connect an run every time my laptop wakes up.

I do use NTP in my guest. The problem is that:

  1. It can be slow to refresh, so I my time can be several minutes off without me noticing, and since I run in full screen, I've been late to meetings and my TOTP authentication fails
  2. If my computer has been asleep too long, then there is too much drift, and NTP won't update the clock. (I am running fedora 34 in my guest)

In my guest, I have a hot key to force the time to reset, but it'd be nice to not have to.

mdillavou avatar Nov 05 '21 15:11 mdillavou

I'm thinking of adding (with a config toggle) a virtio serial port with

-chardev socket,port=4321,host=127.0.0.1,server,nowait,id=qga0
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0

and use NSWorkspace.shared.notificationCenter.addObserver(forName: NSWorkspace.didWakeNotification in order to run the {"execute":"guest-set-time"} command on host wakeup.

What do you think of in the System pane under Advanced Settings having a checkbox like Enable QEMU guest agent port and Automatically sync guest time when host wakes up?

Edit: Might be a while before I get this done since I need to figure out how UTM handles JSON and extend it for QEMU guest agent.

ktprograms avatar Nov 07 '21 09:11 ktprograms

Any updates on this? Any successful workarounds?

navels avatar Jan 10 '22 19:01 navels

I've taken some time to write a proper Swift program that sets the guest time when the host wakes. Here's the instructions on how to use it:

Steps before launching the VM

  1. Open the VM Configuration
  2. Go to the QEMU tab and scroll to the bottom.
  3. Click on the text box with the grey text New...
  4. Paste these two lines into it:
-chardev socket,port=4321,host=127.0.0.1,server,nowait,id=qga0
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
  1. Save the VM Configuration and Start the VM

Steps inside the VM

  1. Install the QEMU Guest Agent. On Debian/Ubuntu based systems run sudo apt install qemu-guest-agent. For other distros, you should be able to find a qemu-guest-agent package.
  2. Start the qemu-ga program. You can either start the qemu-guest-agent service if your distro has it included in the package, otherwise just run qemu-ga -d (which starts the QEMU Guest Agent in the background).

Steps on the Host Mac

  1. Download the UTMSetTimeOnWake.swift file from my gist.
  2. In the Terminal, go to the directory containing the downloaded file.
  3. Run swift UTMSetTimeOnWake.swift
  4. This will run continuously with no output, but when you wake your computer, it will automatically sync the guest time and print the message Successfully re-synced guest time.

ktprograms avatar Jan 11 '22 07:01 ktprograms

Thanks! I added a cron job to start this up on boot and it works great.

navels avatar Jan 12 '22 17:01 navels

a cron job to start this up on boot

If you're talking about starting up the Guest Agent inside the VM, it might be better to just use the init system service and enable it to run at boot.

ktprograms avatar Jan 13 '22 00:01 ktprograms

a cron job to start this up on boot

If you're talking about starting up the Guest Agent inside the VM, it might be better to just use the init system service and enable it to run at boot.

Ah, no, I mean that swift script on the host.

navels avatar Jan 13 '22 00:01 navels

In that case you might want to create a workflow that runs the script to the background, and add that to your Startup Applications?

ktprograms avatar Jan 13 '22 00:01 ktprograms

Any reason why that would be better than a cron task?

navels avatar Jan 13 '22 01:01 navels

Not really. If your current solution is working fine then just keep using it.

ktprograms avatar Jan 13 '22 01:01 ktprograms

Is there a solution/workaround for a MacOS guest? I'm running Monterey and have seen the clock go out of sync.

lukaso avatar May 31 '22 10:05 lukaso

For macOS guest I've used ChronyControl and then set

# As a VM the time can get badly out of sync. This allows big steps

makestep 1 -1

Since it can get wildly out of step. This may cause excess jumps, so it doesn't stop the problem, but it's a workaround.

lukaso avatar Jun 04 '22 19:06 lukaso

this seemed to resolve it for me sudo sntp -sS time.apple.com

I didn't use the container over the weekend and it was three days behind.

https://forums.macrumors.com/threads/time-synchronization-command-line-in-macos-big-sur.2279396/

wheel5up avatar Dec 05 '22 14:12 wheel5up

Just a reminder for @osy to look into providing guest IP address using QEMU guest agent as well.

ktprograms avatar Dec 31 '22 01:12 ktprograms

I think this may go into v4.2 instead as v4.1 is already getting late...

osy avatar Dec 31 '22 01:12 osy

No problem, don't rush yourself. Would you like this to be in a separate issue then? Or do you want to track guest agent implementation in only one placee?

ktprograms avatar Dec 31 '22 01:12 ktprograms

Let's just keep this here for now.

osy avatar Dec 31 '22 01:12 osy

this seemed to resolve it for me sudo sntp -sS time.apple.com

I didn't use the container over the weekend and it was three days behind.

https://forums.macrumors.com/threads/time-synchronization-command-line-in-macos-big-sur.2279396/

Thanks for this workaround!

jtran19 avatar Jan 05 '23 14:01 jtran19

Hello, I came across this issue while trying to sync time in my VM.

I found with UTM 4.2.5 I'm able to force a time sync in the guest VM by restarting qemu-guest-agent.service / qemu-ga, causing the following log lines to be printed out by UTM:

2023-04-27 13:56:25.164 UTM[25390:347692] QMP disconnected
2023-04-27 13:56:25.164 UTM[25390:347692] QEMU guest agent has disconnected.
2023-04-27 13:56:25.186 UTM[25390:347692] QEMU guest agent has connected.
2023-04-27 13:56:25.187 UTM[25390:487901] Debug JSON send -> {
    arguments =     {
        id = 1751658945;
    };
    execute = "guest-sync-delimited";
}
2023-04-27 13:56:25.187 UTM[25390:490494] Debug JSON recieved <- {
    return = 1751658945;
}
2023-04-27 13:56:25.188 UTM[25390:487901] Debug JSON send -> {
    arguments =     {
        time = 1682618185186910208;
    };
    execute = "guest-set-time";
}

I took this clue from https://github.com/utmapp/UTM/commit/d0d3b1bb2ad35966830c3f2bd6a46d1bfbbc992c.

My issue though, is that when I close my Macbook to place my host to sleep at t=x, resuming from sleep y seconds later, no guest-set-time command is issued, resulting in drift where my host OS is at t=x+y while the guest is still at t=x.

May I request that additional hooks be added into UTM to call guest-set-time when resuming the host from sleep?

Please also let me know if you'd like me to file a new issue. Thanks!


Edit: I see #5252 has been filed for this follow-up issue. Will follow there, thanks!

ahrex avatar Apr 27 '23 18:04 ahrex