Skip to content
This repository has been archived by the owner on May 4, 2024. It is now read-only.

Commit

Permalink
support bridged mode
Browse files Browse the repository at this point in the history
Signed-off-by: Akihiro Suda <[email protected]>
  • Loading branch information
AkihiroSuda committed Jul 19, 2021
1 parent 8c17921 commit 2db93dd
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 15 deletions.
12 changes: 9 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Show host info
run: |
uname -a
sw_vers
ifconfig
- name: Install build dependencies
run: brew install vde
- name: Make
run: make
- name: Install
run: sudo make install
- name: Print launchd status
- name: Print launchd status (shared mode)
run: launchctl print system/io.github.AkihiroSuda.vde_vmnet.plist
- name: Install test dependencies
run: brew install qemu bash coreutils
- name: Test
run: ./test/test.sh
- name: Test (shared mode)
run: ./test/test.sh /var/run/vde.ctl
# Bridged mode cannot be tested on GHA
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ CFLAGS += -DVERSION=\"$(VERSION)\"

LDFLAGS += -lvdeplug -framework vmnet

# Interface name for bridged mode. Empty value (default) disables bridged mode.
BRIDGED ?=

all: vde_vmnet

OBJS = $(patsubst %.c, %.o, $(wildcard *.c))
Expand All @@ -23,10 +26,18 @@ install.bin: vde_vmnet
install.launchd.plist: launchd/*.plist
install launchd/io.github.virtualsquare.vde-2.vde_switch.plist "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
install launchd/io.github.AkihiroSuda.vde_vmnet.plist "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
ifneq ($(BRIDGED),)
sed -e "s/en0/$(BRIDGED)/g" launchd/io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist > "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
sed -e "s/en0/$(BRIDGED)/g" launchd/io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist > "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
endif

install.launchd: install.launchd.plist
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
ifneq ($(BRIDGED),)
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
endif

install: install.bin install.launchd

Expand All @@ -38,10 +49,18 @@ uninstall.bin:
uninstall.launchd:
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
ifneq ($(BRIDGED),)
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
endif

uninstall.launchd.plist: uninstall.launchd
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
ifneq ($(BRIDGED),)
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
endif

uninstall: uninstall.launchd.plist uninstall.bin

Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ Make sure to specify unique MAC addresses to VMs: `-device virtio-net-pci,netdev
NOTE: don't confuse MAC addresses of VMs with the MAC address of `vde_vmnet` itself that is printed as `vmnet_mac_address` in the debug log.
You do not need to configure (and you can't, currently) the MAC address of `vde_vmnet` itself.

### Bridged mode

Run `sudo make install BRIDGED=en0`.

The following additional files will be installed:
- `/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist`
- `/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist`

Use `/var/run/vde.bridged.en0.ctl` as the VDE socket path.

Needs macOS 10.15 or later.

## Advanced usage

### Testing without launchd

```console
Expand Down
51 changes: 48 additions & 3 deletions cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <getopt.h>

#include <availability.h>

#include "cli.h"

#ifndef VERSION
Expand All @@ -16,26 +18,38 @@ static void print_usage(const char *argv0) {
printf("vde_vmnet does not require QEMU to run as the root user, but "
"vde_vmnet itself has to run as the root, in most cases.\n");
printf("\n");
printf("--vde-group=GROUP VDE group name (default: \"staff\")\n");
printf("-h, --help display this help and exit\n");
printf("-v, --version display version information and exit\n");
printf("--vde-group=GROUP VDE group name (default: "
"\"staff\")\n");
printf(
"--vmnet-mode=(host|shared|bridged) vmnet mode (default: \"shared\")\n");
printf("--vmnet-interface=INTERFACE interface used for "
"--vmnet=bridged, e.g., \"en0\"\n");
printf("-h, --help display this help and exit\n");
printf("-v, --version display version information and "
"exit\n");
printf("\n");
printf("version: " VERSION "\n");
}

static void print_version() { puts(VERSION); }

#define CLI_OPTIONS_ID_VDE_GROUP -42
#define CLI_OPTIONS_ID_VMNET_MODE -43
#define CLI_OPTIONS_ID_VMNET_INTERFACE -44
struct cli_options *cli_options_parse(int argc, char *argv[]) {
struct cli_options *res = malloc(sizeof(*res));
if (res == NULL) {
goto error;
}
memset(res, 0, sizeof(*res));
res->vde_group = strdup("staff"); /* use strdup to make it freeable */
res->vmnet_mode = VMNET_SHARED_MODE;

const struct option longopts[] = {
{"vde-group", required_argument, NULL, CLI_OPTIONS_ID_VDE_GROUP},
{"vmnet-mode", required_argument, NULL, CLI_OPTIONS_ID_VMNET_MODE},
{"vmnet-interface", required_argument, NULL,
CLI_OPTIONS_ID_VMNET_INTERFACE},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{0, 0, 0, 0},
Expand All @@ -46,6 +60,27 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
case CLI_OPTIONS_ID_VDE_GROUP:
res->vde_group = strdup(optarg);
break;
case CLI_OPTIONS_ID_VMNET_MODE:
if (strcmp(optarg, "host") == 0) {
res->vmnet_mode = VMNET_HOST_MODE;
} else if (strcmp(optarg, "shared") == 0) {
res->vmnet_mode = VMNET_SHARED_MODE;
} else if (strcmp(optarg, "bridged") == 0) {
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
res->vmnet_mode = VMNET_BRIDGED_MODE;
#else
fprintf(stderr,
"vmnet mode \"bridged\" requires macOS 10.15 or later\n");
goto error;
#endif
} else {
fprintf(stderr, "Unknown vmnet mode \"%s\"\n", optarg);
goto error;
}
break;
case CLI_OPTIONS_ID_VMNET_INTERFACE:
res->vmnet_interface = strdup(optarg);
break;
case 'h':
print_usage(argv[0]);
cli_options_destroy(res);
Expand All @@ -67,6 +102,14 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
goto error;
}
res->vde_switch = strdup(argv[optind]);
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
if (res->vmnet_mode == VMNET_BRIDGED_MODE && res->vmnet_interface == NULL) {
fprintf(
stderr,
"vmnet mode \"bridged\" require --vmnet-interface to be specified\n");
goto error;
}
#endif
return res;
error:
print_usage(argv[0]);
Expand All @@ -82,5 +125,7 @@ void cli_options_destroy(struct cli_options *x) {
free(x->vde_group);
if (x->vde_switch != NULL)
free(x->vde_switch);
if (x->vmnet_interface != NULL)
free(x->vmnet_interface);
free(x);
}
8 changes: 6 additions & 2 deletions cli.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#ifndef VDE_VMNET_CLI_H
#define VDE_VMNET_CLI_H

#include <vmnet/vmnet.h>

struct cli_options {
char *vde_group; // --vde-group
char *vde_switch; // arg
char *vde_group; // --vde-group
operating_modes_t vmnet_mode; // --vmnet-mode
char *vmnet_interface; // --vmnet-interface
char *vde_switch; // arg
};

struct cli_options *cli_options_parse(int argc, char *argv[]);
Expand Down
33 changes: 33 additions & 0 deletions launchd/io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist</string>
<key>Program</key>
<string>/usr/local/bin/vde_vmnet</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/vde_vmnet</string>
<string>--vmnet-mode=bridged</string>
<string>--vmnet-interface=en0</string>
<string>/var/run/vde.bridged.en0.ctl</string>
</array>
<key>StandardErrorPath</key>
<string>/var/run/vde_vmnet.bridged.en0.stderr</string>
<key>StandardOutPath</key>
<string>/var/run/vde_vmnet.bridged.en0.stdout</string>
<key>RunAtLoad</key>
<true />
<key>UserName</key>
<string>root</string>
<key>KeepAlive</key>
<dict>
<key>PathState</key>
<dict>
<key>/var/run/vde.bridged.en0.pid</key>
<true />
</dict>
</dict>
</dict>
</plist>
33 changes: 33 additions & 0 deletions launchd/io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- vde_switch itself is maintained at github.com/virtualsquare/vde-2 , but this plist file is maintained at github.com/AkihiroSuda/vde_vmnet -->
<key>Label</key>
<string>io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist</string>
<key>Program</key>
<string>/usr/local/bin/vde_switch</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/vde_switch</string>
<string>--sock</string>
<string>/var/run/vde.bridged.en0.ctl</string>
<string>--pidfile</string>
<string>/var/run/vde.bridged.en0.pid</string>
<string>--group</string>
<string>staff</string>
<string>--dirmode</string>
<string>0770</string>
</array>
<key>StandardErrorPath</key>
<string>/var/run/vde.bridged.en0.stderr</string>
<key>StandardOutPath</key>
<string>/var/run/vde.bridged.en0.stdout</string>
<key>RunAtLoad</key>
<true />
<key>UserName</key>
<string>daemon</string>
<key>GroupName</key>
<string>staff</string>
</dict>
</plist>
16 changes: 10 additions & 6 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,16 @@ static void on_vmnet_packets_available(interface_ref iface, int64_t estim_count,
_on_vmnet_packets_available(iface, r, max_bytes, vdeconn);
}

static interface_ref start(VDECONN *vdeconn) {
printf("Initializing vmnet.framework (VMNET_SHARED_MODE, with random "
"interface ID)\n");
static interface_ref start(VDECONN *vdeconn, struct cli_options *cliopt) {
printf("Initializing vmnet.framework (mode %d, with random interface ID)\n",
cliopt->vmnet_mode);
xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
// TODO: support non-shared modes
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, VMNET_SHARED_MODE);
xpc_dictionary_set_uint64(dict, vmnet_operation_mode_key, cliopt->vmnet_mode);
if (cliopt->vmnet_interface != NULL) {
printf("Using network interface \"%s\"\n", cliopt->vmnet_interface);
xpc_dictionary_set_string(dict, vmnet_shared_interface_name_key,
cliopt->vmnet_interface);
}

uuid_t uuid;
// TODO: support deterministic UUID and MAC address
Expand Down Expand Up @@ -244,7 +248,7 @@ int main(int argc, char *argv[]) {
goto done;
}

iface = start(vdeconn);
iface = start(vdeconn, cliopt);
if (iface == NULL) {
perror("start");
goto done;
Expand Down
9 changes: 8 additions & 1 deletion test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
set -eux -o pipefail
cd "$(dirname "$0")"

if [ "$#" -ne 1 ]; then
echo >&2 "Usage: $0 VDESOCK"
exit 1
fi

VDESOCK="$1"

if [ ! -f ipxe.lkrn ]; then
curl -fSL -O https://boot.ipxe.org/ipxe.lkrn
fi
Expand All @@ -10,7 +17,7 @@ rm -f serial.log
echo >&2 "===== QEMU BEGIN ====="
qemu-system-x86_64 \
-device virtio-net-pci,netdev=net0 \
-netdev vde,id=net0,sock=/var/run/vde.ctl \
-netdev vde,id=net0,sock=$VDESOCK \
-kernel ipxe.lkrn \
-initrd test.ipxe \
-no-reboot \
Expand Down

0 comments on commit 2db93dd

Please sign in to comment.