# FreeBSD 接口 API（IfAPI）

* 原文链接：[FreeBSD Interface API (IfAPI)](https://freebsdfoundation.org/our-work/journal/browser-based-edition/networking-10th-anniversary/freebsd-interface-api-ifapi/)
* 作者：Justin Hibbits

如某些人所知，瞻博（Juniper）使用自己定制的网络栈，该网络栈基于 FreeBSD 开发的长期分支，因此在表面上它看起来与当前的 FreeBSD 网络栈相似，但实际上存在诸多差异。当前 FreeBSD 网络栈中的某些状态在 Junos 中并不存在，反之亦然。

## 为什么以及如何实现

Junos 非常庞大。同步 FreeBSD 是一项艰巨的任务。为简化这个过程，Juniper 将 FreeBSD 组件拆分成了独立的仓库，将瞻博的增强功能保留在独立的仓库中。这就带来了一个难题——我们如何在 FreeBSD 中保留驱动程序，而将网络栈放在其他地方？作为分拆 FreeBSD 项目的一部分，提出了原始的 DrvAPI。通过这个 API，驱动程序可以存在于 FreeBSD 仓库中，同时把 Junos 网络栈保持为独立部分。

但什么是网络栈？我们在哪里划定网络栈与其他部分的界限？最初的方法是“sys/ 目录下所有以 `net` 开头的目录”，这种方法有效。然而，最近添加了组件 `netlink` ，从概念上来说，它并不属于网络栈的一部分，所以这一方法被抛弃了。现在，网络栈有 `net`、`net80211`、`netgraph`、`netinet`、`netinet6` 和 `netpfil`。保持网络栈的细节只关乎网络栈本身，也让核心内核的细节得以遮蔽。某些内核的其他部分也需要做出调整，以适应 IfAPI，包括 NFS 无根（boot）和 mbuf 处理。

## 设计

当前 IfAPI 的设计主要是访问器和迭代器。这种方法被认为是将驱动程序转化并遮蔽 `struct ifnet` 的最便捷方式，尽管它并非最理想的方式。转化过程大多是自动化的，Juniper 提供了一个 shell 脚本 `tools/ifnet/convert_ifapi.sh` 来解决大部分转化。显然，这可能会漏掉一些转化，例如当 `ifp` 是另一个结构体的成员，或者其名称是其他形式（如 `foo_ifp`）时，但它能处理大多数情况。

至于迭代器，最初的实现基于 Gleb Smirnoff 的 `if_foreach_lladdr()`，在迭代给定类型时使用回调函数。这被应用于 `if_addr` 和 `if_t`，在迭代接口时只会遍历当前的 VNET。最近，增加了一种新的迭代器 API，能使用更传统的循环进行迭代；要求是你必须调用 `if_iter_finish()`/`ifa_iter_finish()` 来清理迭代所设置的任何状态，包括释放实现可能分配的任何内存（FreeBSD 网络栈未做此处理，但其他栈可以做到）。

## 好处

将设备驱动程序与网络栈细节解耦，不仅对瞻博的源代码管理有益，还带来了一些额外的好处。通过稳定的 ABI，单个设备驱动程序能与多个不同的网络栈一起使用。例如，在数据中心的所有计算机上，在启动时，某款镜像能选择不同的网络栈，依据执行配置选择一款高性能的有限网络栈用于某些设备，而为其他设备使用完整的网络栈，所有设备仍使用相同的网络驱动程序。

另一个较小的好处是，驱动程序更改和网络栈更改可以同时发生，而不会互相干涉。在 IfAPI 出现之前，对 `struct ifnet` 的任何更改都需要重新构建所有设备驱动程序。现在，由于 `struct ifnet` 是完全私有的，任何对该结构的更改只需要重新构建那些直接引用它的文件，从而缩短了调试周期。

## 接下来会做什么？

IfAPI 只是第一步，仍然有很多工作要做，以便真正地抽象化网络栈。Gleb Smirnoff 提出了使用 KOBJ 接口来允许一个更加可插拔的网络栈，并完全解耦网络栈与其他部分。这甚至可以允许在运行时替换网络栈（`kldunload/kldload`）。进一步来说，我们甚至可以允许多个网络栈，并将不同的设备分配到不同的网络栈中。如此一来，甚至可能实现动态地在网络栈之间移动接口。

## 结论

IfAPI 只是解耦网络驱动程序与网络栈内部实现之间关系的第一阶段。随着进一步的工作，多个网络栈可以同时使用——甚至是可重新加载的网络栈。

***

**Justin Hibbits** 于 2011 年因其对 PowerPC 的执着被愚蠢地授予了 FreeBSD 提交权限。从那时起，他专注于 PowerPC 和其他嵌入式架构的工作。目前他在瞻博 Networks 工作，负责所有与 FreeBSD 内核相关的事务，并继续他对底层开发和异构架构的热情。


---

# Agent Instructions: 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:

```
GET https://freebsd-journal-cn.bsdcn.org/20240102-wang-luo-shi-zhou-nian/freebsd-jie-kou-apiifapi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
