> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/handbook/di-17-zhang-jail-yu-rong-qi/17.6.-vnet-jail.md).

# 17.6.VNET jail

FreeBSD 的 VNET jail 拥有独立的网络栈，包括接口、IP 地址、路由表和防火墙规则。

创建 VNET jail 的第一步是创建 [bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=bridge\&sektion=4\&format=html)，执行以下命令：

```sh
# ifconfig bridge create
```

输出应该类似于以下内容：

```sh
bridge0
```

> **警告**
>
> 将 IP 地址分配给作为网桥成员的接口已被弃用。应将宿主地址分配给 `bridge0` 本身，而非 `em0`，正如下面的 **/etc/rc.conf** 配置块所做的那样。此类配置目前仍然可用：FreeBSD 15.0 在将携带地址的接口添加到网桥时会记录内核警告，只有当 `net.link.bridge.member_ifaddrs` sysctl 从默认值 `1` 改为 `0` 时才会以 `EINVAL` 拒绝。[bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=bridge\&sektion=4\&format=html) 宣布在 FreeBSD 16.0 中移除该 sysctl，届时网桥成员上的地址将不再被允许。

创建好 `bridge` 后，接下来需要将其附加到 `em0` 接口，并启动它们，执行以下命令：

```sh
# ifconfig bridge0 addm em0 up
# ifconfig em0 up
```

为了使此设置在重启后生效，将以下行添加到 **/etc/rc.conf** 中：

```sh
defaultrouter="192.168.1.1"
cloned_interfaces="bridge0"
ifconfig_bridge0="inet 192.168.1.150/24 addm em0 up"
ifconfig_em0="up"
```

有关桥接的更多信息，请参阅 [网络桥接](/handbook/di-35-zhang-gao-ji-wang-luo/35.8.-qiao-jie.md)。

接下来，根据上述内容创建 jail。

可使用 [传统 jail（厚 jail）](/handbook/di-17-zhang-jail-yu-rong-qi/17.4.-chuan-tong-jail-hou-jail.md) 或 [瘦 jail](/handbook/di-17-zhang-jail-yu-rong-qi/17.5.-shou-jail.md) 的方法。唯一不同的是 **/etc/jail.conf** 文件中的配置。

在本示例中，将使用路径 **/usr/local/jails/containers/vnet** 来表示创建的 jail。

以下是 VNET jail 的示例配置：

```sh
vnet {
  # 启动/日志记录
  exec.consolelog = "/var/log/jail_console_${name}.log";

  # 权限
  allow.raw_sockets;
  exec.clean;
  mount.devfs;
  devfs_ruleset = 5;

  # 路径/主机名
  path = "/usr/local/jails/containers/${name}";
  host.hostname = "${name}";

  # VNET/VIMAGE
  vnet;
  vnet.interface = "${epair}b";

  # 网络/接口
  $id = "154"; ①
  $ip = "192.168.1.${id}/24";
  $gateway = "192.168.1.1";
  $bridge = "bridge0"; ②
  $epair = "epair${id}";

  # 添加到 bridge 接口
  exec.prestart  = "/sbin/ifconfig ${epair} create up";
  exec.prestart += "/sbin/ifconfig ${epair}a up descr jail:${name}";
  exec.prestart += "/sbin/ifconfig ${bridge} addm ${epair}a up";
  exec.start    += "/sbin/ifconfig ${epair}b ${ip} up";
  exec.start    += "/sbin/route add default ${gateway}";
  exec.start    += "/bin/sh /etc/rc";
  exec.stop      = "/bin/sh /etc/rc.shutdown";
  exec.poststop = "/sbin/ifconfig ${bridge} deletem ${epair}a";
  exec.poststop += "/sbin/ifconfig ${epair}a destroy";
}
```

* ① 每个 jail **唯一** 的编号，用于派生 epair 设备名（`epair${id}`）和 jail 地址的最后一个八位组（`192.168.1.${id}`）；为网桥上的每个 jail 分配不同的值。
* ② 指代先前创建的 bridge。

`vnet.interface` 参数指定 [jail(8)](https://man.freebsd.org/cgi/man.cgi?query=jail\&sektion=8\&format=html) 在 jail 创建后移入 jail 网络栈的接口，此处为 epair 的 jail 端，即 `${epair}b`。该接口在 jail 运行时会从宿主消失，并在 jail 停止时自动释放回宿主。物理网卡或 SR-IOV 虚拟功能也可以同样的方式交给 jail，使其无需网桥或 epair 即可获得专用网络。

`devfs_ruleset = 5` 行应用 **/etc/defaults/devfs.rules** 中的 `devfsrules_jail_vnet` 规则集，该规则集通过暴露 **/dev/pf** 扩展了默认的 jail 规则集。因此，VNET jail 可使用 `pf_enable="YES"` 和私有的 **pf.conf** 运行自己的 [pf(4)](https://man.freebsd.org/cgi/man.cgi?query=pf\&sektion=4\&format=html) 防火墙，独立于宿主。关于规则集的定义方式请参见 [devfs 规则集](/handbook/di-17-zhang-jail-yu-rong-qi/17.3.-zhu-ji-pei-zhi-jail.md)，关于 pf 本身请参见 [防火墙](/handbook/di-34-zhang-fang-huo-qiang/34.1.-gai-shu.md) 一章。

## 17.6.1. 使用 jib 自动化 VNET 网络

如上所示，在 `exec.prestart` 和 `exec.poststop` 中手动连接 epair 并将其附加到网桥，在多个 jail 中会变得繁琐。基本系统附带了辅助脚本 **/usr/share/examples/jails/jib**，可自动执行相同的管道工作。

在 jail 的钩子中引用该脚本，而非五行手写的 [ifconfig(8)](https://man.freebsd.org/cgi/man.cgi?query=ifconfig\&sektion=8\&format=html) 命令：

```sh
  exec.prestart += "jib addm ${name} em0";
  exec.poststop += "jib destroy ${name}";

  vnet.interface = "e0b_${name}";
```

`jib addm` 创建一个 epair，其宿主端命名为 `e0a_<name>`，jail 端命名为 `e0b_<name>`，然后将宿主端附加到它自动创建的网桥上，该网桥以成员接口命名（对于 `em0`，网桥名为 `em0bridge`）。在 `vnet.interface` 中指定该 jail 端。当 jail 停止时，`jib destroy` 会移除该 epair。该脚本还提供了 `jib show` 子命令来列出其管理的接口。

## 17.6.2. 使用 jng 的 netgraph VNET 网络

[网络](/handbook/di-17-zhang-jail-yu-rong-qi/17.3.-zhu-ji-pei-zhi-jail.md) 概述中提到的第三种网络模式使用 [netgraph(4)](https://man.freebsd.org/cgi/man.cgi?query=netgraph\&sektion=4\&format=html) 而非 [bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=bridge\&sektion=4\&format=html) 和 epair。基本系统附带了第二个辅助脚本 **/usr/share/examples/jails/jng**，可为每个 jail 构建一个连接到 `ng_eiface` 的 `ng_bridge`：

```sh
  exec.prestart += "jng bridge ${name} em0";
  exec.poststop += "jng shutdown ${name}";

  vnet.interface = "ng0_${name}";
```

`jng bridge` 创建 netgraph 节点和一个名为 `ng0_<name>` 的 jail 端接口，后者在 `vnet.interface` 中指定；`jng shutdown` 在 jail 停止时拆除该拓扑。结果在功能上等同于 epair-and-bridge 设置，但构建在 netgraph 节点而非 [bridge(4)](https://man.freebsd.org/cgi/man.cgi?query=bridge\&sektion=4\&format=html) 之上。

## 17.6.3. 在 VNET jail 中运行防火墙和 DHCP

由于 `devfs_ruleset = 5` 暴露了 **/dev/pf**，VNET jail 可运行自己的防火墙。在 jail 内启用它，方式与任何宿主相同，即在 jail 的 **/etc/rc.conf** 中设置 `pf_enable="YES"`，并使用自己的 **/etc/pf.conf**。

但规则集 5 不暴露 **/dev/bpf**。通过 DHCP 获取地址的 VNET jail（例如在其 **/etc/rc.conf** 中设置 `ifconfig_e0b_myjail="SYNCDHCP"`）会运行 [dhclient(8)](https://man.freebsd.org/cgi/man.cgi?query=dhclient\&sektion=8\&format=html)，该程序需要 bpf，因此在规则集 5 下会失败。按照 [devfs 规则集](/handbook/di-17-zhang-jail-yu-rong-qi/17.3.-zhu-ji-pei-zhi-jail.md) 中的方法，在 **/etc/devfs.rules** 中定义一个自定义规则集，从 `devfsrules_jail_vnet` 开始，并额外取消隐藏 bpf 设备：

```sh
[devfsrules_jail_vnet_dhcp=101]
add include $devfsrules_jail_vnet
add path 'bpf*' unhide
```

在宿主上运行 `service devfs restart` 后，使用 `devfs_ruleset = 101;` 将 jail 指向新规则集。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://book.bsdcn.org/handbook/di-17-zhang-jail-yu-rong-qi/17.6.-vnet-jail.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
