Skip to content

Conversation

norio-nomura
Copy link
Contributor

@norio-nomura norio-nomura commented Sep 6, 2025

Description:

Since systemd v256 (Ubuntu 24.10), SSH is bound to AF_VSOCK port 22.

https://github.com/systemd/systemd/releases/tag/v256

  • If the system is run in a VM providing AF_VSOCK support, it automatically
    binds sshd to AF_VSOCK port 22.

https://discourse.ubuntu.com/t/oracular-oriole-release-notes/44878

  • When sshd is installed on a system, a new systemd generator, systemd-ssh-generator
    binds a socket-activated SSH server to local AF_VSOCK and AF_UNIX sockets under certain conditions.

This PR changes to delay starting SSH port forwarding until the SSH server on the VM becomes ready. If AF_VSOCK port 22 can be connected, start a local SSH port as a proxy for AF_VSOCK port 22, instead of starting gvisor's port forwarder.

SSH over VSOCK is faster than SSH over gvisor's port forwarder.

This change is opt-out because it requires VZ and VM with systemd v256+,
setting LIMA_SSH_OVER_VSOCK=true does not mean it works.
To disable, set LIMA_SSH_OVER_VSOCK=false.

Benchmark logs:

On MacBook Pro 14 inch, 2023 with Apple M2 Pro

SETUP:

$ sw_vers
ProductName:		macOS
ProductVersion:		15.7
BuildVersion:		24G219
$ limactl start template://ubuntu-24.10 --rosetta --containerd=none --log-level error
<snip>
$ limactl shell ubuntu-24.10 sudo apt-get -U install -y iperf3 -qqq
<snip>

GRPC Port Forwarder (Current):

$ limactl shell ubuntu-24.10 iperf3 -s
WARN[0000] Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated. 
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
Accepted connection from ::1, port 53668
[  5] local ::1 port 5201 connected to ::1 port 53672
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   354 MBytes  2.97 Gbits/sec                  
[  5]   1.00-2.00   sec   359 MBytes  3.01 Gbits/sec                  
[  5]   2.00-3.00   sec   354 MBytes  2.97 Gbits/sec                  
[  5]   3.00-4.00   sec   354 MBytes  2.97 Gbits/sec                  
[  5]   4.00-5.00   sec   357 MBytes  3.00 Gbits/sec                  
[  5]   5.00-6.00   sec   354 MBytes  2.97 Gbits/sec                  
[  5]   6.00-7.00   sec   355 MBytes  2.98 Gbits/sec                  
[  5]   7.00-8.00   sec   355 MBytes  2.98 Gbits/sec                  
[  5]   8.00-9.00   sec   355 MBytes  2.98 Gbits/sec                  
[  5]   9.00-9.98   sec   352 MBytes  3.01 Gbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-9.98   sec  3.47 GBytes  2.98 Gbits/sec                  receiver
-----------------------------------------------------------
Server listening on 5201 (test #2)
-----------------------------------------------------------
^Ciperf3: interrupt - the server has terminated

SSH Port Forwarder on gvisor's virtual network (Old):

$ LIMA_SSH_PORT_FORWARDER=true LIMA_SSH_OVER_VSOCK=false limactl restart ubuntu-24.10 --log-level error
$ limactl shell ubuntu-24.10 iperf3 -s
WARN[0000] Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated. 
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
Accepted connection from ::1, port 43814
[  5] local ::1 port 5201 connected to ::1 port 43824
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   277 MBytes  2.32 Gbits/sec                  
[  5]   1.00-2.00   sec   280 MBytes  2.35 Gbits/sec                  
[  5]   2.00-3.00   sec   278 MBytes  2.34 Gbits/sec                  
[  5]   3.00-4.00   sec   279 MBytes  2.34 Gbits/sec                  
[  5]   4.00-5.00   sec   279 MBytes  2.34 Gbits/sec                  
[  5]   5.00-6.00   sec   279 MBytes  2.34 Gbits/sec                  
[  5]   6.00-7.00   sec   281 MBytes  2.36 Gbits/sec                  
[  5]   7.00-8.00   sec   280 MBytes  2.35 Gbits/sec                  
[  5]   8.00-9.00   sec   281 MBytes  2.36 Gbits/sec                  
[  5]   9.00-10.00  sec   279 MBytes  2.34 Gbits/sec                  
[  5]  10.00-10.03  sec  9.00 MBytes  2.34 Gbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.03  sec  2.74 GBytes  2.34 Gbits/sec                  receiver
-----------------------------------------------------------
Server listening on 5201 (test #2)
-----------------------------------------------------------
^Ciperf3: interrupt - the server has terminated

SSH Port Forwarder over AF_VSOCK (New):

$ LIMA_SSH_PORT_FORWARDER=true limactl restart ubuntu-24.10 --log-level error
$ limactl shell ubuntu-24.10 iperf3 -s
WARN[0000] Both top-level 'rosetta' and 'vmOpts.vz.rosetta' are configured. Using vmOpts.vz.rosetta. Top-level 'rosetta' is deprecated. 
-----------------------------------------------------------
Server listening on 5201 (test #1)
-----------------------------------------------------------
Accepted connection from ::1, port 57942
[  5] local ::1 port 5201 connected to ::1 port 57948
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-1.00   sec   422 MBytes  3.54 Gbits/sec                  
[  5]   1.00-2.00   sec   425 MBytes  3.57 Gbits/sec                  
[  5]   2.00-3.00   sec   427 MBytes  3.58 Gbits/sec                  
[  5]   3.00-4.00   sec   426 MBytes  3.58 Gbits/sec                  
[  5]   4.00-5.00   sec   426 MBytes  3.58 Gbits/sec                  
[  5]   5.00-6.00   sec   428 MBytes  3.59 Gbits/sec                  
[  5]   6.00-7.00   sec   426 MBytes  3.58 Gbits/sec                  
[  5]   7.00-8.00   sec   428 MBytes  3.59 Gbits/sec                  
[  5]   8.00-9.00   sec   425 MBytes  3.57 Gbits/sec                  
[  5]   9.00-10.00  sec   425 MBytes  3.57 Gbits/sec                  
[  5]  10.00-10.00  sec  1.62 MBytes  3.83 Gbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-10.00  sec  4.16 GBytes  3.57 Gbits/sec                  receiver
-----------------------------------------------------------
Server listening on 5201 (test #2)
-----------------------------------------------------------
^Ciperf3: interrupt - the server has terminated

@AkihiroSuda AkihiroSuda added this to the v2.0.0 milestone Sep 6, 2025
if err != nil {
return err
}
logrus.Infof("started vsock forwarder: localhost:%d -> vsock:%d on VM", hostPort, vsockPort)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be another PR, but wondering if we can further optimize the performance with (an equivalent of) systemd-ssh-proxy — SSH client plugin for connecting to AF_VSOCK and AF_UNIX sockets
https://www.freedesktop.org/software/systemd/man/256/systemd-ssh-proxy.html

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the meaning of the comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it might be possible to eliminate the TCP->vsock forwarder and let ssh directly connect to the vsock.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VM's VSOCK should not be open to the host unless the process that is starting the VM is mediated. As this PR is doing.

@norio-nomura norio-nomura force-pushed the ssh-over-vsock-on-vz branch 2 times, most recently from 4ea3d0f to a549d55 Compare September 6, 2025 12:42
@norio-nomura
Copy link
Contributor Author

Ubuntu 24.04 and earlier, SSH over AF_VSOCK can be enabled with:

provision:
- mode: yq
  path: /etc/systemd/system/ssh.socket.d/vsock.conf
  format: ini
  expression: |
    .Socket.ListenStream="vsock::22"

and upgraded SSH tracked at sshd socket activation does not support AF_VSOCK

@norio-nomura
Copy link
Contributor Author

norio-nomura commented Sep 7, 2025

How to enable SSH over AF_VSOCK on Ubuntu 20.04, 22.04, and 24.04

Ubuntu 20.04, 22.04:

Since the patched version of SSH has already been released, it requires:

  • Add ListenStream="vsock::22" to ssh.socket configuration
  • Change ssh.service to use socket-based activation
$ limactl start template://ubuntu-20.04 --rosetta --containerd=none --set '.provision|=.//empty + [{
  "mode": "yq",
  "format": "ini",
  "path": "/etc/systemd/system/ssh.socket.d/vsock.conf",
  "expression": ".Socket.ListenStream=\"vsock::22\""
}, {
  "mode": "system",
  "script": ("#!/bin/bash
set -eux -o pipefail
systemctl is-enabled ssh.service || exit 0
# use socket based activation
systemctl disable --now ssh.service
systemctl enable --now ssh.socket
"|. style="literal")
}]'
$ limactl restart ubuntu-20.04 2>&1 |grep -i vsock
time="2025-09-07T17:01:40+09:00" level=info msg="[hostagent] started vsock forwarder: localhost:59291 -> vsock:22 on VM"
time="2025-09-07T17:01:40+09:00" level=info msg="[hostagent] Detected SSH server is listening on the vsock port; changed localhost:59291 to proxy for the vsock port"

Ubuntu 24.04:

Since the patched version of SSH is not yet released (2025/09/07), it requires installing the proposed version.
The patched version of SSH has been released (2025/09/09), update openssh-server to latest release.

  • Add ListenStream="vsock::22" to the ssh.socket configuration.
  • Install the proposed version of SSH. Update openssh-server to patched version (1:9.6p1-3ubuntu13.14)
  • Already, SSH has been changed to default socket-based activation.
$ limactl start template://ubuntu-24.04 --rosetta --containerd=none --set '.provision|=.//empty + [{
  "mode": "yq",
  "format": "ini",
  "path": "/etc/systemd/system/ssh.socket.d/vsock.conf",
  "expression": ".Socket.ListenStream=\"vsock::22\""
}, {
  "mode": "system",
  "script": ("#!/bin/bash
ss -l --vsock|grep \*:22 -q && exit 0
apt-get --update install --assume-yes openssh-server
"|. style="literal")
}]'
$ limactl restart ubuntu-24.04 2>&1 |grep -i vsock
time="2025-09-07T17:01:56+09:00" level=info msg="[hostagent] started vsock forwarder: localhost:59299 -> vsock:22 on VM"
time="2025-09-07T17:01:56+09:00" level=info msg="[hostagent] Detected SSH server is listening on the vsock port; changed localhost:59299 to proxy for the vsock port"

Edit: The patched version of openssh-server has been released on Ubuntu 24.04

@norio-nomura norio-nomura force-pushed the ssh-over-vsock-on-vz branch 2 times, most recently from 2d98aa5 to 5161063 Compare September 8, 2025 07:45
@norio-nomura
Copy link
Contributor Author

I'm considering another PR for the port forwarder implementation to VSOCK, which can be defined in lima.yaml, but I'm not sure if it's better to mix the rules with .portForwards[]. 🤔

@norio-nomura norio-nomura force-pushed the ssh-over-vsock-on-vz branch 2 times, most recently from e3bc0bd to 9238459 Compare September 9, 2025 09:49
@norio-nomura
Copy link
Contributor Author

Ubuntu 24.04:

Since the patched version of SSH is not yet released (2025/09/07), it requires installing the proposed version.

The patched version of SSH has been released (2025/09/09), update openssh-server to latest release.

@norio-nomura norio-nomura marked this pull request as draft September 10, 2025 03:56
@norio-nomura
Copy link
Contributor Author

To support custom usernet, I will move WaitOpeningSSHPort logic to the server side.

Since systemd v256 (Ubuntu 24.10), SSH is bound to AF_VSOCK port 22.

https://github.com/systemd/systemd/releases/tag/v256
> - If the system is run in a VM providing AF_VSOCK support, it automatically
binds sshd to AF_VSOCK port 22.

https://discourse.ubuntu.com/t/oracular-oriole-release-notes/44878
> - When sshd is installed on a system, a new systemd generator, systemd-ssh-generator
binds a socket-activated SSH server to local AF_VSOCK and AF_UNIX sockets under certain conditions.

This changes to delay starting SSH port forwarding until the SSH server on the VM becomes ready.
If AF_VSOCK port 22 can be connected, start a local SSH port as a proxy for AF_VSOCK port 22,
instead of starting gvisor's port forwarder.

SSH over VSOCK is faster than SSH over gvisor's port forwarder.

This change is opt-out because it requires VZ and VM with systemd v256+,
setting `LIMA_SSH_OVER_VSOCK=true` does not mean it works.
To disable, set `LIMA_SSH_OVER_VSOCK=false`.

Signed-off-by: Norio Nomura <[email protected]>
@norio-nomura norio-nomura marked this pull request as ready for review September 10, 2025 05:33
@norio-nomura
Copy link
Contributor Author

To support custom usernet, I will move WaitOpeningSSHPort logic to the server side.

done.

@norio-nomura
Copy link
Contributor Author

To support custom usernet, I will move WaitOpeningSSHPort logic to the server side.

This added an entry point /extension/wait_port?ip=<ip address>&port=<port> to endpoint sock of usernet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants