# 12.4 在 FreeBSD 上安装 VirtualBox

VirtualBox 是甲骨文（Oracle）公司开发的跨平台 Type-2 虚拟化平台。Type-2 虚拟化运行在宿主操作系统之上，通过宿主机内核访问硬件资源，与 Type-1 虚拟化（裸机运行）不同。

VirtualBox 采用 GNU 通用公共许可证（GNU General Public License，GPL）协议开源发布，支持 x86 与 AMD64 架构的硬件辅助虚拟化（Intel VT-x 与 AMD-V）。硬件辅助虚拟化技术使虚拟机可以直接访问部分硬件资源，显著提升虚拟化性能。

闭源的 VirtualBox 扩展包（VirtualBox Extension Pack）尚未在 FreeBSD 上完全支持，该扩展包提供 USB 2.0/3.0 支持、NVMe 磁盘加密等附加功能。

## 安装 VirtualBox

VirtualBox 在 FreeBSD 上有多个版本可供选择。不同版本的主要差异在于功能更新和兼容性：legacy 版本（5.X）适用于旧系统，6.X 版本提供稳定支持，70 和 71 版本包含最新功能。各版本均提供无 X11 的 `-nox11` 变体（例如 `emulators/virtualbox-ose-71-nox11`），适用于无图形界面的服务器环境，仅可通过命令行工具 `VBoxManage` 操作。

本文安装最新的 `emulators/virtualbox-ose-71`。

使用 pkg 安装可能会出现内核模块与当前内核版本不匹配的报错，这是因为 pkg 安装的预编译内核模块可能与运行中的内核版本不一致。而通过 Ports 编译安装可以确保生成的内核模块与当前系统内核完全匹配，因此推荐使用 Ports 安装：

```sh
# cd /usr/ports/emulators/virtualbox-ose-71/ 
# make install clean
```

> **注意**
>
> 编译过程需要在 `/usr/src/` 目录下存在内核源码。

## 安装后说明

VirtualBox 安装完成后，可以通过以下命令查看详细的安装说明和配置指导：

```sh
# pkg info -D virtualbox-ose-71
virtualbox-ose-71-7.1.10:
On install:
VirtualBox was installed.  
VirtualBox 已安装。

You need to load the vboxdrv kernel module via /boot/loader.conf:  
你需要通过 `/boot/loader.conf` 加载 vboxdrv 内核模块：

vboxdrv_load="YES"

You also have to add all users to your vboxusers group in order to use vbox.  
你还需要将使用 VirtualBox 的用户加入 vboxusers 组：

% pw groupmod vboxusers -m jerry

Reboot the machine to load the needed kernel modules.  
重启系统以加载所需的内核模块。


Bridging Support:  
=================  
桥接支持：

For bridged networking please add the following line to your /etc/rc.conf:  
要启用桥接网络，请将以下行添加到 `/etc/rc.conf`：

vboxnet_enable="YES"


USB Support:  
============  
USB 支持：

For USB support your user needs to be in the operator group and needs read  
and write permissions to the USB device.  
要启用 USB 支持，用户需要属于 operator 组，并具有对 USB 设备的读写权限。

% pw groupmod operator -m jerry

Add the following to /etc/devfs.rules (create if it doesn't exist):  
将以下内容添加到 `/etc/devfs.rules`（如文件不存在，请创建）：

[system=10]  
add path 'usb/*' mode 0660 group operator

To load these new rule add the following to /etc/rc.conf:  
要加载这些新规则，请在 /etc/rc.conf 中添加以下行：

devfs_system_ruleset="system"

Then restart devfs to load the new rules:  
然后重启 devfs 以使新规则生效：

% /etc/rc.d/devfs restart


Troubleshooting:  
================  
故障排查：

Running VirtualBox as non-root user may fail with a fatal error  
NS_ERROR_FACTORY_NOT_REGISTERED. In this case delete /tmp/.vbox-*-ipc file.  
以非 root 用户运行 VirtualBox 时可能会因致命错误 NS_ERROR_FACTORY_NOT_REGISTERED 而失败。此时请删除 /tmp/.vbox-*-ipc 文件。

If you experience "Network: write Failed: Cannot allocate memory" errors  
try to increase net.graph.maxdata in /boot/loader.conf  
如果遇到“Network: write Failed: Cannot allocate memory”错误，请尝试在 /boot/loader.conf 中增加 net.graph.maxdata 的值。

If you are using AIO, then increase these limits (https://bugs.freebsd.org/168298):  
如果你正在使用 AIO，请提高以下限制值（详见 https://bugs.freebsd.org/168298）：
vfs.aio.max_buf_aio=8192  
vfs.aio.max_aio_queue_per_proc=65536  
vfs.aio.max_aio_per_proc=8192  
vfs.aio.max_aio_queue=65536  
To check if AIO is used use: kldstat -v | grep aio  
要检查是否启用了 AIO，可运行：`kldstat -v | grep aio`

If you are experiencing VMs freezes with an error in VBox.log such as:  
如果你的虚拟机出现冻结，并在 VBox.log 中出现如下错误信息：

"
00:01:29.590192 AssertLogRel /usr/ports/emulators/virtualbox-ose/work/VirtualBox-6.1.44
/src/VBox/VMM/VMMR3/PGMPhys.cpp(5148) int PGMR3PhysAllocateHandyPages(PVM): RT_SUCCESS(rc)
00:01:29.590221 87/128: idPage=0x3d400 HCPhysGCPhys=000000027eaed000 rc=VERR_NO_MEMORY
00:01:29.590247 Changing the VM state from 'RUNNING' to 'GURU_MEDITATION'
00:01:29.590261 Console: Machine state changed to 'GuruMeditation'
00:01:29.590695 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00:01:29.590696 !!
00:01:29.590697 !!         VCPU0: Guru Meditation -8 (VERR_NO_MEMORY)
"

and see a lot of free RAM, then increase sysctl vm.max_user_wired  
(https://bugs.freebsd.org/252227).  
如果系统存在大量空闲内存，但仍出现问题，请增加 sysctl vm.max_user_wired 的值（详见 https://bugs.freebsd.org/252227）。

For dedicated VM servers, a good start is:  
对于专用虚拟机服务器，可以按以下公式设置初始值：
（“内存容量（GB）” − max(1, “内存容量（GB） / 32”)） × 1024 × 1024 × 1024 ÷ PAGE_SIZE
x86 架构下 PAGE_SIZE 为 4096。

Examples with different RAM sizes in GB:  
不同内存容量的示例（单位：GB）：
 16: ( 16-max(1, 16/32)*1024*1024*1024/4096 ) = 3932160  =>  15GB  
 32: ( 32-max(1, 32/32)*1024*1024*1024/4096 ) = 8126464  =>  31GB  
 48: ( 48-max(1, 48/32)*1024*1024*1024/4096 ) = 12189696 =>  46.5GB  
 64: ( 64-max(1, 64/32)*1024*1024*1024/4096 ) = 16252928 =>  62GB  
128: (128-max(1,128/32)*1024*1024*1024/4096 ) = 32505856 => 124GB  
256: (256-max(1,256/32)*1024*1024*1024/4096 ) = 65011712 => 248GB

When assigning IP addresses in host-only mode from ranges outside  
of VirtualBox's defaults, the respective ranges need to be listed  
in /usr/local/etc/vbox/networks.conf (https://bugs.freebsd.org/259399).  
如果你在 host-only 模式下分配的 IP 地址超出 VirtualBox 默认范围，请将对应的地址范围写入 /usr/local/etc/vbox/networks.conf（详见 https://bugs.freebsd.org/259399）。

Check the wiki page for known issues and troubleshooting:  
查看官方 Wiki 页面获取已知问题和故障排查信息：  
https://wiki.freebsd.org/VirtualBox

Please report any problems to emulation@. Thanks!  
如遇问题，请发送邮件报告至 emulation@，谢谢！


On upgrade from virtualbox-ose-71<6.1.22:  
从 virtualbox-ose-71 小于 6.1.22 的版本升级时：

The PULSEAUDIO option has been forcibly disabled since VirtualBox  
version 6.1.24 due to a bug in it preventing virtual machines  
configured to use it from starting.  
从 VirtualBox 6.1.24 起，PULSEAUDIO 选项已被强制禁用，因为其存在导致配置使用它的虚拟机无法启动的错误。

When upgrading from a previous version please reconfigure any virtual  
machines using the Pulseaudio host audio driver to use another  
supported one.  
升级后，请将所有使用 Pulseaudio 主机音频驱动的虚拟机改为使用其他受支持的音频驱动。


On upgrade from virtualbox-ose-71>6.1.26<6.1.32_1:  
从 virtualbox-ose-71 版本大于 6.1.26 且小于 6.1.32_1 的版本升级时：

To comply to hier(7) requirements, networks.conf's location changed  
to /usr/local/etc/vbox/networks.conf.  
为符合 hier(7) 要求，`networks.conf` 的位置已更改为 `/usr/local/etc/vbox/networks.conf`。

In case /etc/vbox/networks.conf exists, it needs to be moved to  
/usr/local/etc/vbox and /etc/vbox should be deleted.  
如果 `/etc/vbox/networks.conf` 存在，请将其移动到 `/usr/local/etc/vbox`，并删除 `/etc/vbox` 目录。
```

## 相关文件结构

```sh
/
├── boot/
│   └── loader.conf # 内核模块加载配置
├── etc/
│   ├── rc.conf # 系统启动配置
│   ├── devfs.rules # DevFS 规则文件
│   └── vbox/
│       └── networks.conf # 旧版 VirtualBox 网络配置位置
├── tmp/
│   └── .vbox-*-ipc # VirtualBox IPC 临时文件
└── usr/
    ├── local/
    │   └── etc/
    │       └── vbox/
    │           └── networks.conf # VirtualBox 网络配置
    ├── ports/
    │   └── emulators/
    │       └── virtualbox-ose-71/ # VirtualBox Ports 目录
    └── src/ # 内核源码目录
```

## 配置

完成 VirtualBox 安装后，需要进行一些必要的配置才能正常使用。首先加载 vboxdrv 内核模块，该模块为 VirtualBox 提供核心虚拟化功能。

1. **加载内核模块**：将以下行写入 `/boot/loader.conf` 文件，设置系统在启动时加载 VirtualBox 内核模块

   ```ini
   vboxdrv_load="YES"
   ```
2. **启用桥接网络支持**：允许虚拟机直接连接物理网络

   ```sh
   # service vboxnet enable # 设置 VirtualBox 网络服务开机自启
   ```

默认的 `net.graph.maxdata` 值应该足够，不需要修改。

### 普通用户所需

为了让普通用户能够使用 VirtualBox，需要将用户加入相应的用户组以获得必要权限：

需要分别加入 `vboxusers`、`operator`（USB 支持）组：

```sh
# 将当前用户添加到 operator 用户组
# pw groupmod operator -m 你的用户名

# 将当前用户添加到 vboxusers 用户组
# pw groupmod vboxusers -m 你的用户名
```

将以下内容添加到 `/etc/devfs.rules`（如果不存在请创建）：

```ini
[system=10]  
add path 'usb/*' mode 0660 group operator
```

为 USB 设备添加访问权限，设置文件模式为 `0660`，所属组为 `operator`。

要加载这些新规则，请在 `/etc/rc.conf` 中添加以下行：

```ini
devfs_system_ruleset="system" # 设置 DevFS 使用名为 “system” 的规则集
```

重启 DevFS 服务以应用新的规则集：

```sh
$ /etc/rc.d/devfs restart
```

以非 root 用户运行 VirtualBox 时可能会报错 `NS_ERROR_FACTORY_NOT_REGISTERED`。此时请删除匹配该模式的临时文件：

```sh
# rm /tmp/.vbox-*-ipc
```

## 测试

完成所有配置后，可以启动 VirtualBox 并创建虚拟机进行测试，如图所示：

![VirtualBox 界面](https://338876981-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FCJR3FQGH1PkdRtOljuxb%2Fuploads%2Fgit-blob-6878f7744d80f44ee69010c8569b80ca22171da9%2Fvb-vm-1.png?alt=media)

## 故障排除与未竟事项

本节提供 VirtualBox 使用过程中可能遇到的问题及其解决方法。

### TPM 不支持

虽然在设置中可见该选项，但虚拟机无法启动。

## 课后习题

1. 使用 VBoxManage 命令行工具创建一个虚拟机并启动，对比图形界面与命令行操作的差异，理解这种双模式设计如何在易用性与可控性之间做权衡。
2. 查找 FreeBSD 内核中 vboxdrv 模块的源代码，理解它如何与宿主机内核交互，思考这种第三方内核模块如何扩展系统能力的同时是否也带来了安全风险。
