Skip to content

Commit 7b3096d

Browse files
committed
feat: vsock support for remote console access
Having a remote console access can be helpful for different reasons, e.g. an easy way to have multiple terminals, not using a serial which can be slow to print a lot of text, etc. With this new support, a user can simply use vng like before, and add the new --vsock option: vng --vsock (...) Then in another terminal, it can connect to the existing VM: vng --vsock-connect Advanced users can set a different CID with --vsock-cid, useful when multiple VMs are started in parallel. It is also possible to change the command that is executed when connected inside the VM. By default, 'bash -i' is used, but it is possible to pass something else, e.g. vng --vsock byobu Or zsh, fish, tmux, etc. Or a script, for example to set env vars, change dir and set other dimensions, etc., e.g. starting the VM with: $ vng --vsock "${PWD}/console.sh" ... and connecting to it from another terminal with: $ read -r rows columns <<< "$(stty size)" $ cat <<-EOF > console.sh #! /bin/bash stty rows ${rows} columns ${columns} cd "\${virtme_chdir}" HOME=${HOME} byobu EOF $ chmod +x console.sh $ vng --vsock-connect Note: on my side, 'bash' is a bit weird: I cannot see the command I'm typing. I didn't try to find a solution for a too long time as I'm usually not using bash. Regarding the kernel config, two new config are now required: VSOCKETS and VIRTIO_VSOCKETS. They seem light enough. While at it, fixed a typo in the README file with the --network option. Link: #151 Signed-off-by: Matthieu Baerts (NGI0) <matttbe@kernel.org>
1 parent d22b9a1 commit 7b3096d

File tree

6 files changed

+114
-2
lines changed

6 files changed

+114
-2
lines changed

README.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,33 @@ Examples
345345
# vmlinux available in the system.
346346
```
347347

348+
- Connect to a simple remote shell:
349+
```
350+
# Start the vng instance with vsock support:
351+
$ vng --vsock
352+
353+
# In a separate terminal run the following command to connect to a remote shell:
354+
$ vng --vsock-connect
355+
```
356+
357+
- Connect to a remote shell with proper dimensions, env vars, and using 'Fish':
358+
```
359+
# Start the vng instance with vsock support:
360+
$ vng --vsock "${PWD}/console.sh"
361+
362+
# In a separate terminal run the following commands:
363+
$ read -r rows columns <<< "$(stty size)"
364+
$ cat <<-EOF > console.sh
365+
#! /bin/bash
366+
stty rows ${rows} columns ${columns}
367+
cd "\${virtme_chdir}"
368+
HOME=${HOME}
369+
fish # use use zsh, tmux, byobu, screen, etc.
370+
EOF
371+
$ chmod +x console.sh
372+
$ vng --vsock-connect
373+
```
374+
348375
- Run virtme-ng inside a docker container:
349376
```
350377
$ docker run -it --privileged ubuntu:23.10 /bin/bash
@@ -449,7 +476,7 @@ Troubleshooting
449476
$ groups | grep "kvm\|libvirt"
450477
```
451478

452-
- When using `--net bridge` to create a bridged network in the guest you
479+
- When using `--network bridge` to create a bridged network in the guest you
453480
may get the following error:
454481
```
455482
...

virtme/commands/configkernel.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ def arg_fail(message):
159159
"CONFIG_ZONE_DEVICE=y",
160160
"CONFIG_FUSE_FS=y",
161161
"CONFIG_VIRTIO_FS=y",
162+
"##: vsock support",
163+
"CONFIG_VSOCKETS=y",
164+
"CONFIG_VIRTIO_VSOCKETS=y",
162165
]
163166

164167
_GENERIC_CONFIG_OPTIONAL = [

virtme/commands/run.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,25 @@ def make_parser() -> argparse.ArgumentParser:
130130
help="The MAC address to assign to the NIC interface, e.g. 52:54:00:12:34:56. "
131131
+ "The last octet will be incremented for the next network devices.",
132132
)
133+
g.add_argument(
134+
"--vsock",
135+
action="store",
136+
default=None,
137+
help="Enable a VSock to communicate from the host to the device and "
138+
+ "execute the specified command.",
139+
)
140+
g.add_argument(
141+
"--vsock-cid",
142+
action="store",
143+
type=int,
144+
default=3,
145+
help="CID for the VSock.",
146+
)
147+
g.add_argument(
148+
"--vsock-connect",
149+
action="store_true",
150+
help="Connect to a VM using VSock.",
151+
)
133152
g.add_argument(
134153
"--balloon",
135154
action="store_true",
@@ -847,6 +866,13 @@ def is_subpath(path, potential_parent):
847866
def do_it() -> int:
848867
args = _ARGPARSER.parse_args()
849868

869+
if args.vsock_connect:
870+
tty = os.ttyname(sys.stdin.fileno())
871+
command = ['socat', f'file:{tty},raw,echo=0',
872+
f'VSOCK-CONNECT:{args.vsock_cid}:1024']
873+
os.execvp('socat', command)
874+
sys.exit(0)
875+
850876
arch = architectures.get(args.arch)
851877
is_native = args.arch == platform.machine()
852878

@@ -1383,6 +1409,10 @@ def get_net_mac(index):
13831409
]
13841410
)
13851411

1412+
if args.vsock:
1413+
kernelargs.extend([f"virtme.vsockexec=`{args.vsock}`"])
1414+
qemuargs.extend(["-device", "vhost-vsock-pci,guest-cid=%d" % args.vsock_cid])
1415+
13861416
if args.pwd:
13871417
rel_pwd = os.path.relpath(os.getcwd(), args.root)
13881418
if rel_pwd.startswith(".."):

virtme/guest/virtme-init

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ if cat /proc/cmdline |grep -q -E '(^| )virtme.snapd($| )'; then
275275
fi
276276
fi
277277

278+
vsock_exec=$(sed -ne "s/.*virtme.vsockexec=\`\(.*\)\`.*/\1/p" /proc/cmdline)
279+
if [[ -n "${vsock_exec}" ]]; then
280+
socat "VSOCK-LISTEN:1024,reuseaddr,fork" \
281+
"EXEC:\"${vsock_exec}\",pty,stderr,setsid,sigint,sane,echo=0" &
282+
fi
283+
278284
user_cmd=$(sed -ne "s/.*virtme.exec=\`\(.*\)\`.*/\1/p" /proc/cmdline)
279285
if [[ -n "${user_cmd}" ]]; then
280286
if [[ ! -e "/dev/virtio-ports/virtme.stdin" ||

virtme_ng/run.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,28 @@ def make_parser():
359359
+ "The last octet will be incremented for the next network devices.",
360360
)
361361

362+
parser.add_argument(
363+
"--vsock",
364+
action="store",
365+
const="bash -i",
366+
nargs="?",
367+
help="Enable a VSock to communicate from the host to the device. "
368+
+ "An argument can be optionally specify to start a different shell.",
369+
)
370+
371+
parser.add_argument(
372+
"--vsock-cid",
373+
action="store",
374+
type=int,
375+
help="CID for the VSock.",
376+
)
377+
378+
parser.add_argument(
379+
"--vsock-connect",
380+
action="store_true",
381+
help="Connect to a VM using VSock.",
382+
)
383+
362384
parser.add_argument(
363385
"--disk",
364386
"-D",
@@ -947,6 +969,24 @@ def _get_virtme_net_mac_address(self, args):
947969
else:
948970
self.virtme_param["net_mac_address"] = ""
949971

972+
def _get_virtme_vsock(self, args):
973+
if args.vsock is not None:
974+
self.virtme_param["vsock"] = "--vsock '" + args.vsock + "'"
975+
else:
976+
self.virtme_param["vsock"] = ""
977+
978+
def _get_virtme_vsock_cid(self, args):
979+
if args.vsock_cid is not None:
980+
self.virtme_param["vsock_cid"] = "--vsock-cid " + str(args.vsock_cid)
981+
else:
982+
self.virtme_param["vsock_cid"] = ""
983+
984+
def _get_virtme_vsock_connect(self, args):
985+
if args.vsock_connect:
986+
self.virtme_param["vsock_connect"] = "--vsock-connect"
987+
else:
988+
self.virtme_param["vsock_connect"] = ""
989+
950990
def _get_virtme_disk(self, args):
951991
if args.disk is not None:
952992
disk_str = ""
@@ -1102,6 +1142,9 @@ def run(self, args):
11021142
self._get_virtme_mods(args)
11031143
self._get_virtme_network(args)
11041144
self._get_virtme_net_mac_address(args)
1145+
self._get_virtme_vsock(args)
1146+
self._get_virtme_vsock_cid(args)
1147+
self._get_virtme_vsock_connect(args)
11051148
self._get_virtme_disk(args)
11061149
self._get_virtme_sound(args)
11071150
self._get_virtme_disable_microvm(args)
@@ -1141,6 +1184,9 @@ def run(self, args):
11411184
+ f'{self.virtme_param["mods"]} '
11421185
+ f'{self.virtme_param["network"]} '
11431186
+ f'{self.virtme_param["net_mac_address"]} '
1187+
+ f'{self.virtme_param["vsock"]} '
1188+
+ f'{self.virtme_param["vsock_cid"]} '
1189+
+ f'{self.virtme_param["vsock_connect"]} '
11441190
+ f'{self.virtme_param["disk"]} '
11451191
+ f'{self.virtme_param["sound"]} '
11461192
+ f'{self.virtme_param["disable_microvm"]} '

virtme_ng_init

0 commit comments

Comments
 (0)