Donation from Maigurs Stalidzans. Thanks!
[ikiwiki.git] / docs / docs / howtos / nvmm / index.mdwn
1 [[!meta title="Virtualization: NVMM Hypervisor"]]
2
3 **Table of Contents:**
4
5 [[!toc startlevel=2 levels=3]]
6
7 ## Introduction
8
9 NVMM is a Type-2 hypervisor, and hypervisor platform, that provides support for hardware-accelerated virtualization.
10 A virtualization API is shipped in libnvmm(3), and allows existing emulators (e.g., QEMU) to easily create and manage virtual machines via NVMM.
11
12 NVMM can support up to 128 virtual machines, each having a maximum of 128 vCPUs and 127TB RAM.
13 It works with both x86 AMD CPUs (SVM/AMD-V) and x86 Intel CPUs (VMX/VT-x).
14
15 NVMM was designed and written by Maxime Villard (m00nbsd.net), first appeared in NetBSD 9, and was ported to DragonFly 6.1 by Aaron LI (aly@) with significant help from Matt Dillon (dillon@) and Maxime.
16
17 ## Design
18
19 In order to achieve hardware-accelerated virtualization, two components need to interact together:
20
21 * A kernel driver that will switch machine's CPU to a mode where it will be able to safely execute guest instructions.
22 * A userland emulator, which talks to the kernel driver to run virtual machines.
23
24 NVMM provides the infrastructure needed for both the kernel driver and the userland emulators.
25
26 The kernel NVMM driver comes as a kernel module.
27 It is made of a generic machine-independent frontend, and of several machine-dependent backends (currently only x86 AMD SVM and x86 Intel VMX backends).
28 During initialization, NVMM selects the appropriate backend for the system.
29 The frontend handles everything that is not CPU-specific: the virtual machines, the virtual CPUs, the guest physical address spaces, and so forth.
30 The frontend also provides an IOCTL interface for userland emulators.
31
32 When it comes to the userland emulators, NVMM does not provide one.
33 In other words, it does not re-implement a QEMU, a VirtualBox, a Bhyve (FreeBSD) or a VMD (OpenBSD).
34 Rather, it provides a virtualization API via the libnvmm(3) library, which allows to effortlessly add NVMM support in already existing emulators.
35 This API is meant to be simple and straightforward, and is fully documented.
36 It has some similarities with WHPX on Windows and HVF on macOS.
37 The idea is to provide an easy way for applications to use NVMM to implement services, which can go from small sandboxing systems to advanced system emulators.
38
39 An overview of NVMM's unique design:<br>
40 [[!img NvmmDesign.png alt="NVMM Design" size=400x]]
41 <br>
42 (Credit: [https://m00nbsd.net/NvmmDesign.png](https://m00nbsd.net/NvmmDesign.png))
43
44 Read blog [From Zero to NVMM (by Maxime Villard)](https://blog.netbsd.org/tnf/entry/from_zero_to_nvmm) for a detailed analysis of the design.
45
46 ## Usage Guide
47
48 ### Requirements
49
50 * AMD CPU with SVM and RVI/NPT support, or Intel CPU with VT-x/VMX and EPT support
51 * DragonFly master (6.1) at/after [commit 11755db6](https://gitweb.dragonflybsd.org/dragonfly.git/commit/11755db6b4ad8e01f32f277b591496121e03fc5d)
52
53 ### Setup
54
55 1. Add yourself to the `nvmm` group (so you can later run examples and QEMU without using `root`):
56
57         # pw groupmod nvmm -m $USER
58
59 2. Re-login to make it effective.
60
61 3. Load the `nvmm` kernel module:
62
63         # kldload nvmm
64
65 4. Check NVMM status:
66
67         $ nvmmctl identify
68
69    On my AMD Ryzen 3700X, it shows:
70
71         nvmm: Kernel API version 3
72         nvmm: State size 1008
73         nvmm: Comm size 4096
74         nvmm: Max machines 128
75         nvmm: Max VCPUs per machine 128
76         nvmm: Max RAM per machine 127T
77         nvmm: Arch Mach conf 0
78         nvmm: Arch VCPU conf 0x1<CPUID>
79         nvmm: Guest FPU states 0x3<x87,SSE>
80
81 ### Examples
82
83 * calc-vm:
84
85         $ cd /usr/src/test/nvmm
86         $ make
87         $ /tmp/calc-vm <integer1> <integer2>
88         $ ./looprun.sh
89
90 * demo:
91
92         $ cd /usr/src/test/nvmm/demo
93         $ make
94         $ /tmp/toyvirt /tmp/smallkern
95
96 * libnvmm tests:
97
98         $ cd /usr/src/test/testcases/libnvmm
99         $ make test
100
101 ### QEMU
102
103 #### Basic setup
104
105 1. Install QEMU:
106
107         # pkg install qemu
108
109 2. Create a disk:
110
111         $ qemu-img create -f qcow2 dfly.qcow2 50G
112
113 3. Boot an ISO with NVMM acceleration:
114
115         $ qemu-system-x86_64 \
116           -machine type=q35,accel=nvmm \
117           -smp cpus=2 -m 4G \
118           -cdrom dfly.iso -boot d \
119           -drive file=dfly.qcow2,if=none,id=disk0 \
120           -device virtio-blk-pci,drive=disk0 \
121           -netdev user,id=net0,hostfwd=tcp:127.0.0.1:6022-:22 \
122           -device virtio-net-pci,netdev=net0 \
123           -object rng-random,id=rng0,filename=/dev/urandom \
124           -device virtio-rng-pci,rng=rng0 \
125           -display curses \
126           -vga qxl \
127           -spice addr=127.0.0.1,port=5900,ipv4=on,disable-ticketing=on,seamless-migration=on
128
129 This setup creates a VM of settings:
130
131 * Modern machine (Q35) with NVMM hardware acceleration
132 * Emulate the host processor with 2 vCPUs
133 * 4GB RAM
134 * VirtIO-BLK hard disk
135 * VirtIO-NET network card
136 * VirtIO-RNG random number generator
137 * Display video output via curses
138 * User-mode networking (TCP/UDP pass-through; no ICMP), with port-forwarding (host `127.0.0.1:6022` to guest `22` port)
139 * [SPICE](https://www.spice-space.org/) remote desktop support (use `qxl` for more powerful graphics support), accessible via `127.0.0.1:5900`
140
141 To connect to guest via SSH:
142
143         $ ssh -p 6022 user@127.0.0.1
144
145 To connect to guest via SPICE (install package `spice-gtk` to get the `spicy` utility):
146
147         $ spicy -p 5900
148
149 By the way, the created VMs can be shown with:
150
151         # nvmmctl list
152         Machine ID VCPUs RAM  Owner PID Creation Time           
153         ---------- ----- ---- --------- ------------------------
154         0          2     4.1G 91101     Sat Jul 24 17:55:22 2021
155
156 #### TAP networking
157
158 The above setup uses user-mode networking, which has limitations in both performance and functionalities.  A more advanced network can be achieved by using the TAP device.
159
160 1. Create a bridge (`bridge0`) and configure it:
161
162         # ifconfig bridge0 create
163         # ifconfig bridge0 inet 10.66.6.1/24
164         # ifconfig bridge0 up
165
166 2. Create a TAP device (`tap666`) and add it to the bridge:
167
168         # ifconfig tap666 create
169         # ifconfig tap666 up
170         # ifconfig bridge0 addm tap666
171
172 3. Adjust TAP sysctls:
173
174         # sysctl net.link.tap.up_on_open=1
175         # sysctl net.link.tap.user_open=1
176
177 4. Make the TAP device can be opened by yourself:
178
179         # chown $USER /dev/tap666
180
181    **NOTE**:
182    Should have a better way to do this; devd(8) could be used.
183
184 5. Start QEMU with option `-netdev tap,ifname=tap666,id=net0,script=no,downscript=no`, i.e.,
185
186         $ qemu-system-x86_64 \
187           ... \
188           -netdev tap,ifname=tap666,id=net0,script=no,downscript=no \
189           -device virtio-net-pci,netdev=net0,mac=52:54:00:34:56:66
190
191    **NOTE**:
192    QEMU by default assigns the link-level address `52:54:00:12:34:56` to guest.
193    If unspecified, all guests would have the **same** MAC address.
194    Specify the MAC address with `-device xxx,netdev=xxx,mac=52:54:xx:xx:xx:xx`.
195
196 6. Configure guest IP address:
197
198         guest# ifconfig vtnet0 inet 10.66.6.2/24 up
199         guest# route add default 10.66.6.1
200
201    And then the guest can communicate with host and vice versa.
202
203         guest# ping 10.66.6.1
204         host$ ping 10.66.6.2
205
206 #### Bridged Network
207
208 With the above setup, guests can only talk to each other and the host, but can't access the external network.
209 One way to make VM access the external work is configuring a **bridged network**:
210 the host machine is acting as a switch, and the VM appears as another machine (similar to the host machine)
211 in the LAN.
212
213 1. Create the bridge interface in the same way as above, but no need to configure its address:
214
215         # ifconfig bridge0 create
216         # ifconfig bridge0 up
217
218 2. Create the TAP interface and configure it the same way as above:
219
220         # ifconfig tap666 create
221         # ifconfig tap666 up
222         # sysctl net.link.tap.up_on_open=1
223         # sysctl net.link.tap.user_open=1
224         # chown $USER /dev/tap666
225
226 3. Add both the TAP interface and the **host network interface** (e.g., `re0` in my case) to the bridge:
227
228         # ifconfig bridge0 addm re0
229         # ifconfig bridge0 addm tap666
230
231    **NOTE**:
232    Adding an interface to the bridge will auto enable *promiscuous mode* for it.
233
234 4. Start the VM the same as before, and run DHCP inside the VM, e.g.:
235
236         vm# dhclient vtnet0
237
238    Now the VM can obtain IP configuration from the LAN router and can access the Internet, e.g.,:
239
240         vm# ifconfig
241         vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
242                 options=28<VLAN_MTU,JUMBO_MTU>
243                 ether 52:54:00:12:34:56
244                 inet6 fe80::5054:ff:fe12:3456%vtnet0 prefixlen 64 scopeid 0x1
245                 inet 10.6.20.34 netmask 0xffffff00 broadcast 10.6.20.255
246                 media: Ethernet 1000baseT <full-duplex>
247                 status: active
248
249 **WARNING**:
250 This method exposes the VM to the LAN and makes it accessible to all other LAN machines
251 besides the host machine.
252 This can render the VM in risk and also may reveal sensitive information from VM!!
253
254 #### NAT
255
256 Another way to allow VM access the Internet is to configure the NAT on the host side.
257 This method doesn't expose the VM beyond the host machine, and thus is regarded more secure.
258
259 1. Enable IP forwarding:
260
261         # sysctl net.inet.ip.forwarding=1
262
263 2. Configure NAT with PF(4) by adding the follow snippet to `/etc/pf.conf`:
264
265         ext_if = "re0"
266         br_if = "bridge0"
267         nat on $ext_if inet from $br_if:network to !$br_if:network -> ($ext_if:0)
268
269 3. Enable and start PF:
270
271         # echo 'pf_enable=YES' >> /etc/rc.conf
272         # service pf start
273
274 Now, the guest can access the external network.
275
276 #### DHCP & DNS
277
278 A DHCP server can be run on the bridge interface to provide guests with auto IP address configuration.
279 Similarly, a DNS service can be provided to guests.
280
281 TODO: `dnsmasq`
282
283 #### IPv6
284
285 TODO...
286
287 #### Graphics
288
289 TODO...
290
291 #### Audio
292
293 TODO...
294
295 #### USB
296
297 TODO...
298
299 #### PCI Passthrough
300
301 TODO...
302
303 ### Issues
304
305 * QEMU `-cpu host` doesn't work.  Need to investigate the root cause.
306
307 ## Resources
308
309 * NVMM kernel code: [machine-independent frontend](https://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/sys/dev/virtual/nvmm), [machine-dependent x86 backends](https://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/sys/dev/virtual/nvmm/x86)
310 * [libnvmm API code](https://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/lib/libnvmm)
311 * [libnvmm test cases](https://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/test/testcases/libnvmm)
312 * [nvmmctl utility code](https://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/usr.sbin/nvmmctl)
313 * Examples: [calc-vm](https://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/test/nvmm/calc-vm.c), [demo](https://gitweb.dragonflybsd.org/dragonfly.git/blob/HEAD:/test/nvmm/deomo)
314 * [nvmm(4) man page](https://man.dragonflybsd.org/?command=nvmm&section=4)
315 * [libnvmm(3) man page](https://man.dragonflybsd.org/?command=libnvmm&section=3)
316 * [nvmmctl(8) man page](https://man.dragonflybsd.org/?command=nvmmctl&section=8)
317
318 ## References
319
320 * [m00nbsd: NVMM](https://m00nbsd.net/4e0798b7f2620c965d0dd9d6a7a2f296.html)
321 * [NetBSD: From Zero to NVMM](https://blog.netbsd.org/tnf/entry/from_zero_to_nvmm)
322 * [NetBSD: Chapter 30. Using virtualization: QEMU and NVMM](https://netbsd.org/docs/guide/en/chap-virt.html)
323 * [QEMU: Networking](https://wiki.qemu.org/Documentation/Networking)
324 * [Gentoo: QEMU/Options](https://wiki.gentoo.org/wiki/QEMU/Options)
325 * [ArchWiki: QEMU](https://wiki.archlinux.org/title/QEMU)
326 * [SPICE: Simple Protocol for Independent Computing Environments](https://www.spice-space.org/)