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

Commit 82bf427

Browse files
authored
Merge pull request #6 from AkihiroSuda/dev
support bridged mode
2 parents 8c17921 + 2db93dd commit 82bf427

9 files changed

+180
-15
lines changed

.github/workflows/test.yml

+9-3
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@ jobs:
1616
- uses: actions/checkout@v2
1717
with:
1818
fetch-depth: 1
19+
- name: Show host info
20+
run: |
21+
uname -a
22+
sw_vers
23+
ifconfig
1924
- name: Install build dependencies
2025
run: brew install vde
2126
- name: Make
2227
run: make
2328
- name: Install
2429
run: sudo make install
25-
- name: Print launchd status
30+
- name: Print launchd status (shared mode)
2631
run: launchctl print system/io.github.AkihiroSuda.vde_vmnet.plist
2732
- name: Install test dependencies
2833
run: brew install qemu bash coreutils
29-
- name: Test
30-
run: ./test/test.sh
34+
- name: Test (shared mode)
35+
run: ./test/test.sh /var/run/vde.ctl
36+
# Bridged mode cannot be tested on GHA

Makefile

+19
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ CFLAGS += -DVERSION=\"$(VERSION)\"
77

88
LDFLAGS += -lvdeplug -framework vmnet
99

10+
# Interface name for bridged mode. Empty value (default) disables bridged mode.
11+
BRIDGED ?=
12+
1013
all: vde_vmnet
1114

1215
OBJS = $(patsubst %.c, %.o, $(wildcard *.c))
@@ -23,10 +26,18 @@ install.bin: vde_vmnet
2326
install.launchd.plist: launchd/*.plist
2427
install launchd/io.github.virtualsquare.vde-2.vde_switch.plist "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
2528
install launchd/io.github.AkihiroSuda.vde_vmnet.plist "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
29+
ifneq ($(BRIDGED),)
30+
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"
31+
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"
32+
endif
2633

2734
install.launchd: install.launchd.plist
2835
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
2936
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
37+
ifneq ($(BRIDGED),)
38+
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
39+
launchctl load -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
40+
endif
3041

3142
install: install.bin install.launchd
3243

@@ -38,10 +49,18 @@ uninstall.bin:
3849
uninstall.launchd:
3950
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
4051
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
52+
ifneq ($(BRIDGED),)
53+
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
54+
launchctl unload -w "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
55+
endif
4156

4257
uninstall.launchd.plist: uninstall.launchd
4358
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.plist"
4459
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.plist"
60+
ifneq ($(BRIDGED),)
61+
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.$(BRIDGED).plist"
62+
rm -f "$(DESTDIR)/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.$(BRIDGED).plist"
63+
endif
4564

4665
uninstall: uninstall.launchd.plist uninstall.bin
4766

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,20 @@ Make sure to specify unique MAC addresses to VMs: `-device virtio-net-pci,netdev
4545
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.
4646
You do not need to configure (and you can't, currently) the MAC address of `vde_vmnet` itself.
4747

48+
### Bridged mode
49+
50+
Run `sudo make install BRIDGED=en0`.
51+
52+
The following additional files will be installed:
53+
- `/Library/LaunchDaemons/io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist`
54+
- `/Library/LaunchDaemons/io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist`
55+
56+
Use `/var/run/vde.bridged.en0.ctl` as the VDE socket path.
57+
58+
Needs macOS 10.15 or later.
59+
60+
## Advanced usage
61+
4862
### Testing without launchd
4963

5064
```console

cli.c

+48-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <getopt.h>
66

7+
#include <availability.h>
8+
79
#include "cli.h"
810

911
#ifndef VERSION
@@ -16,26 +18,38 @@ static void print_usage(const char *argv0) {
1618
printf("vde_vmnet does not require QEMU to run as the root user, but "
1719
"vde_vmnet itself has to run as the root, in most cases.\n");
1820
printf("\n");
19-
printf("--vde-group=GROUP VDE group name (default: \"staff\")\n");
20-
printf("-h, --help display this help and exit\n");
21-
printf("-v, --version display version information and exit\n");
21+
printf("--vde-group=GROUP VDE group name (default: "
22+
"\"staff\")\n");
23+
printf(
24+
"--vmnet-mode=(host|shared|bridged) vmnet mode (default: \"shared\")\n");
25+
printf("--vmnet-interface=INTERFACE interface used for "
26+
"--vmnet=bridged, e.g., \"en0\"\n");
27+
printf("-h, --help display this help and exit\n");
28+
printf("-v, --version display version information and "
29+
"exit\n");
2230
printf("\n");
2331
printf("version: " VERSION "\n");
2432
}
2533

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

2836
#define CLI_OPTIONS_ID_VDE_GROUP -42
37+
#define CLI_OPTIONS_ID_VMNET_MODE -43
38+
#define CLI_OPTIONS_ID_VMNET_INTERFACE -44
2939
struct cli_options *cli_options_parse(int argc, char *argv[]) {
3040
struct cli_options *res = malloc(sizeof(*res));
3141
if (res == NULL) {
3242
goto error;
3343
}
3444
memset(res, 0, sizeof(*res));
3545
res->vde_group = strdup("staff"); /* use strdup to make it freeable */
46+
res->vmnet_mode = VMNET_SHARED_MODE;
3647

3748
const struct option longopts[] = {
3849
{"vde-group", required_argument, NULL, CLI_OPTIONS_ID_VDE_GROUP},
50+
{"vmnet-mode", required_argument, NULL, CLI_OPTIONS_ID_VMNET_MODE},
51+
{"vmnet-interface", required_argument, NULL,
52+
CLI_OPTIONS_ID_VMNET_INTERFACE},
3953
{"help", no_argument, NULL, 'h'},
4054
{"version", no_argument, NULL, 'v'},
4155
{0, 0, 0, 0},
@@ -46,6 +60,27 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
4660
case CLI_OPTIONS_ID_VDE_GROUP:
4761
res->vde_group = strdup(optarg);
4862
break;
63+
case CLI_OPTIONS_ID_VMNET_MODE:
64+
if (strcmp(optarg, "host") == 0) {
65+
res->vmnet_mode = VMNET_HOST_MODE;
66+
} else if (strcmp(optarg, "shared") == 0) {
67+
res->vmnet_mode = VMNET_SHARED_MODE;
68+
} else if (strcmp(optarg, "bridged") == 0) {
69+
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
70+
res->vmnet_mode = VMNET_BRIDGED_MODE;
71+
#else
72+
fprintf(stderr,
73+
"vmnet mode \"bridged\" requires macOS 10.15 or later\n");
74+
goto error;
75+
#endif
76+
} else {
77+
fprintf(stderr, "Unknown vmnet mode \"%s\"\n", optarg);
78+
goto error;
79+
}
80+
break;
81+
case CLI_OPTIONS_ID_VMNET_INTERFACE:
82+
res->vmnet_interface = strdup(optarg);
83+
break;
4984
case 'h':
5085
print_usage(argv[0]);
5186
cli_options_destroy(res);
@@ -67,6 +102,14 @@ struct cli_options *cli_options_parse(int argc, char *argv[]) {
67102
goto error;
68103
}
69104
res->vde_switch = strdup(argv[optind]);
105+
#if __MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
106+
if (res->vmnet_mode == VMNET_BRIDGED_MODE && res->vmnet_interface == NULL) {
107+
fprintf(
108+
stderr,
109+
"vmnet mode \"bridged\" require --vmnet-interface to be specified\n");
110+
goto error;
111+
}
112+
#endif
70113
return res;
71114
error:
72115
print_usage(argv[0]);
@@ -82,5 +125,7 @@ void cli_options_destroy(struct cli_options *x) {
82125
free(x->vde_group);
83126
if (x->vde_switch != NULL)
84127
free(x->vde_switch);
128+
if (x->vmnet_interface != NULL)
129+
free(x->vmnet_interface);
85130
free(x);
86131
}

cli.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
#ifndef VDE_VMNET_CLI_H
22
#define VDE_VMNET_CLI_H
33

4+
#include <vmnet/vmnet.h>
5+
46
struct cli_options {
5-
char *vde_group; // --vde-group
6-
char *vde_switch; // arg
7+
char *vde_group; // --vde-group
8+
operating_modes_t vmnet_mode; // --vmnet-mode
9+
char *vmnet_interface; // --vmnet-interface
10+
char *vde_switch; // arg
711
};
812

913
struct cli_options *cli_options_parse(int argc, char *argv[]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>Label</key>
6+
<string>io.github.AkihiroSuda.vde_vmnet.bridged.en0.plist</string>
7+
<key>Program</key>
8+
<string>/usr/local/bin/vde_vmnet</string>
9+
<key>ProgramArguments</key>
10+
<array>
11+
<string>/usr/local/bin/vde_vmnet</string>
12+
<string>--vmnet-mode=bridged</string>
13+
<string>--vmnet-interface=en0</string>
14+
<string>/var/run/vde.bridged.en0.ctl</string>
15+
</array>
16+
<key>StandardErrorPath</key>
17+
<string>/var/run/vde_vmnet.bridged.en0.stderr</string>
18+
<key>StandardOutPath</key>
19+
<string>/var/run/vde_vmnet.bridged.en0.stdout</string>
20+
<key>RunAtLoad</key>
21+
<true />
22+
<key>UserName</key>
23+
<string>root</string>
24+
<key>KeepAlive</key>
25+
<dict>
26+
<key>PathState</key>
27+
<dict>
28+
<key>/var/run/vde.bridged.en0.pid</key>
29+
<true />
30+
</dict>
31+
</dict>
32+
</dict>
33+
</plist>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<!-- vde_switch itself is maintained at github.com/virtualsquare/vde-2 , but this plist file is maintained at github.com/AkihiroSuda/vde_vmnet -->
6+
<key>Label</key>
7+
<string>io.github.virtualsquare.vde-2.vde_switch.bridged.en0.plist</string>
8+
<key>Program</key>
9+
<string>/usr/local/bin/vde_switch</string>
10+
<key>ProgramArguments</key>
11+
<array>
12+
<string>/usr/local/bin/vde_switch</string>
13+
<string>--sock</string>
14+
<string>/var/run/vde.bridged.en0.ctl</string>
15+
<string>--pidfile</string>
16+
<string>/var/run/vde.bridged.en0.pid</string>
17+
<string>--group</string>
18+
<string>staff</string>
19+
<string>--dirmode</string>
20+
<string>0770</string>
21+
</array>
22+
<key>StandardErrorPath</key>
23+
<string>/var/run/vde.bridged.en0.stderr</string>
24+
<key>StandardOutPath</key>
25+
<string>/var/run/vde.bridged.en0.stdout</string>
26+
<key>RunAtLoad</key>
27+
<true />
28+
<key>UserName</key>
29+
<string>daemon</string>
30+
<key>GroupName</key>
31+
<string>staff</string>
32+
</dict>
33+
</plist>

main.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,16 @@ static void on_vmnet_packets_available(interface_ref iface, int64_t estim_count,
149149
_on_vmnet_packets_available(iface, r, max_bytes, vdeconn);
150150
}
151151

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

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

247-
iface = start(vdeconn);
251+
iface = start(vdeconn, cliopt);
248252
if (iface == NULL) {
249253
perror("start");
250254
goto done;

test/test.sh

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
set -eux -o pipefail
33
cd "$(dirname "$0")"
44

5+
if [ "$#" -ne 1 ]; then
6+
echo >&2 "Usage: $0 VDESOCK"
7+
exit 1
8+
fi
9+
10+
VDESOCK="$1"
11+
512
if [ ! -f ipxe.lkrn ]; then
613
curl -fSL -O https://boot.ipxe.org/ipxe.lkrn
714
fi
@@ -10,7 +17,7 @@ rm -f serial.log
1017
echo >&2 "===== QEMU BEGIN ====="
1118
qemu-system-x86_64 \
1219
-device virtio-net-pci,netdev=net0 \
13-
-netdev vde,id=net0,sock=/var/run/vde.ctl \
20+
-netdev vde,id=net0,sock=$VDESOCK \
1421
-kernel ipxe.lkrn \
1522
-initrd test.ipxe \
1623
-no-reboot \

0 commit comments

Comments
 (0)