diff --git a/README.md b/README.md index 2956596..a4a7215 100644 --- a/README.md +++ b/README.md @@ -345,6 +345,33 @@ Examples # vmlinux available in the system. ``` + - Connect to a simple remote shell: +``` + # Start the vng instance with vsock support: + $ vng --vsock + + # In a separate terminal run the following command to connect to a remote shell: + $ vng --vsock-connect +``` + + - Connect to a remote shell with proper dimensions, env vars, and using 'Fish': +``` + # Start the vng instance with vsock support: + $ vng --vsock "${PWD}/console.sh" + + # In a separate terminal run the following commands: + $ read -r rows columns <<< "$(stty size)" + $ cat <<-EOF > console.sh + #! /bin/bash + stty rows ${rows} columns ${columns} + cd "\${virtme_chdir}" + HOME=${HOME} + fish # use use zsh, tmux, byobu, screen, etc. + EOF + $ chmod +x console.sh + $ vng --vsock-connect +``` + - Run virtme-ng inside a docker container: ``` $ docker run -it --privileged ubuntu:23.10 /bin/bash @@ -449,7 +476,7 @@ Troubleshooting $ groups | grep "kvm\|libvirt" ``` - - When using `--net bridge` to create a bridged network in the guest you + - When using `--network bridge` to create a bridged network in the guest you may get the following error: ``` ... diff --git a/virtme/commands/configkernel.py b/virtme/commands/configkernel.py index 3d1a919..1ed6592 100644 --- a/virtme/commands/configkernel.py +++ b/virtme/commands/configkernel.py @@ -159,6 +159,9 @@ def arg_fail(message): "CONFIG_ZONE_DEVICE=y", "CONFIG_FUSE_FS=y", "CONFIG_VIRTIO_FS=y", + "##: vsock support", + "CONFIG_VSOCKETS=y", + "CONFIG_VIRTIO_VSOCKETS=y", ] _GENERIC_CONFIG_OPTIONAL = [ diff --git a/virtme/commands/run.py b/virtme/commands/run.py index b491f8b..0b2cbd1 100644 --- a/virtme/commands/run.py +++ b/virtme/commands/run.py @@ -130,6 +130,25 @@ def make_parser() -> argparse.ArgumentParser: help="The MAC address to assign to the NIC interface, e.g. 52:54:00:12:34:56. " + "The last octet will be incremented for the next network devices.", ) + g.add_argument( + "--vsock", + action="store", + default=None, + help="Enable a VSock to communicate from the host to the device and " + + "execute the specified command.", + ) + g.add_argument( + "--vsock-cid", + action="store", + type=int, + default=3, + help="CID for the VSock.", + ) + g.add_argument( + "--vsock-connect", + action="store_true", + help="Connect to a VM using VSock.", + ) g.add_argument( "--balloon", action="store_true", @@ -847,6 +866,13 @@ def is_subpath(path, potential_parent): def do_it() -> int: args = _ARGPARSER.parse_args() + if args.vsock_connect: + tty = os.ttyname(sys.stdin.fileno()) + command = ['socat', f'file:{tty},raw,echo=0', + f'VSOCK-CONNECT:{args.vsock_cid}:1024'] + os.execvp('socat', command) + sys.exit(0) + arch = architectures.get(args.arch) is_native = args.arch == platform.machine() @@ -1383,6 +1409,10 @@ def get_net_mac(index): ] ) + if args.vsock: + kernelargs.extend([f"virtme.vsockexec=`{args.vsock}`"]) + qemuargs.extend(["-device", "vhost-vsock-pci,guest-cid=%d" % args.vsock_cid]) + if args.pwd: rel_pwd = os.path.relpath(os.getcwd(), args.root) if rel_pwd.startswith(".."): diff --git a/virtme/guest/virtme-init b/virtme/guest/virtme-init index 8a3325f..2681ad7 100755 --- a/virtme/guest/virtme-init +++ b/virtme/guest/virtme-init @@ -275,6 +275,12 @@ if cat /proc/cmdline |grep -q -E '(^| )virtme.snapd($| )'; then fi fi +vsock_exec=$(sed -ne "s/.*virtme.vsockexec=\`\(.*\)\`.*/\1/p" /proc/cmdline) +if [[ -n "${vsock_exec}" ]]; then + socat "VSOCK-LISTEN:1024,reuseaddr,fork" \ + "EXEC:\"${vsock_exec}\",pty,stderr,setsid,sigint,sane,echo=0" & +fi + user_cmd=$(sed -ne "s/.*virtme.exec=\`\(.*\)\`.*/\1/p" /proc/cmdline) if [[ -n "${user_cmd}" ]]; then if [[ ! -e "/dev/virtio-ports/virtme.stdin" || diff --git a/virtme_ng/run.py b/virtme_ng/run.py index e95eb83..6fe8aee 100644 --- a/virtme_ng/run.py +++ b/virtme_ng/run.py @@ -359,6 +359,28 @@ def make_parser(): + "The last octet will be incremented for the next network devices.", ) + parser.add_argument( + "--vsock", + action="store", + const="bash -i", + nargs="?", + help="Enable a VSock to communicate from the host to the device. " + + "An argument can be optionally specify to start a different shell.", + ) + + parser.add_argument( + "--vsock-cid", + action="store", + type=int, + help="CID for the VSock.", + ) + + parser.add_argument( + "--vsock-connect", + action="store_true", + help="Connect to a VM using VSock.", + ) + parser.add_argument( "--disk", "-D", @@ -947,6 +969,24 @@ def _get_virtme_net_mac_address(self, args): else: self.virtme_param["net_mac_address"] = "" + def _get_virtme_vsock(self, args): + if args.vsock is not None: + self.virtme_param["vsock"] = "--vsock '" + args.vsock + "'" + else: + self.virtme_param["vsock"] = "" + + def _get_virtme_vsock_cid(self, args): + if args.vsock_cid is not None: + self.virtme_param["vsock_cid"] = "--vsock-cid " + str(args.vsock_cid) + else: + self.virtme_param["vsock_cid"] = "" + + def _get_virtme_vsock_connect(self, args): + if args.vsock_connect: + self.virtme_param["vsock_connect"] = "--vsock-connect" + else: + self.virtme_param["vsock_connect"] = "" + def _get_virtme_disk(self, args): if args.disk is not None: disk_str = "" @@ -1102,6 +1142,9 @@ def run(self, args): self._get_virtme_mods(args) self._get_virtme_network(args) self._get_virtme_net_mac_address(args) + self._get_virtme_vsock(args) + self._get_virtme_vsock_cid(args) + self._get_virtme_vsock_connect(args) self._get_virtme_disk(args) self._get_virtme_sound(args) self._get_virtme_disable_microvm(args) @@ -1141,6 +1184,9 @@ def run(self, args): + f'{self.virtme_param["mods"]} ' + f'{self.virtme_param["network"]} ' + f'{self.virtme_param["net_mac_address"]} ' + + f'{self.virtme_param["vsock"]} ' + + f'{self.virtme_param["vsock_cid"]} ' + + f'{self.virtme_param["vsock_connect"]} ' + f'{self.virtme_param["disk"]} ' + f'{self.virtme_param["sound"]} ' + f'{self.virtme_param["disable_microvm"]} ' diff --git a/virtme_ng_init b/virtme_ng_init index f9d3c4a..c43ba1c 160000 --- a/virtme_ng_init +++ b/virtme_ng_init @@ -1 +1 @@ -Subproject commit f9d3c4aef44834351fc93ecd1d5f5860f44bc85c +Subproject commit c43ba1ca5d91953a723eb1d6d0f7b4b88da327ca