kata-container 的tap设备在哪里创建的?虚拟机内还是虚拟机外
现在我需要确认 setupTCFiltering 和 tapNetworkPair 被调用时是否在 netns 上下文内。让我回顾一下调用链。
从 VethEndpoint.Attach(veth_endpoint.go 第 109 行):
func (endpoint *VethEndpoint) Attach(ctx context.Context, s *Sandbox) error {
...
h := s.hypervisor
if err := xConnectVMNetwork(ctx, endpoint, h); err != nil { // ← 这里调用
...
}
return h.AddDevice(ctx, endpoint, NetDev)
}
Attach 是在 addSingleEndpoint 中被调用的。让我们看看 addSingleEndpoint 和 scanEndpointsInNs 中的调用上下文。前面看到 scanEndpointsInNs(第 455 行):
if err := doNetNS(nsPath, func(_ ns.NetNS) error {
ep, addErr := n.addSingleEndpoint(ctx, s, netInfo, hotplug)
...
});
所以 addSingleEndpoint(包括里面的 endpoint.Attach → xConnectVMNetwork → setupTCFiltering/tapNetworkPair)都是在 doNetNS(nsPath) 中执行的,即在容器的网络命名空间内。
同样,AddEndpoints 在传入 endpointsInfo 时也通过 doNetNS(n.netNSPath, ...) 包裹(第 643 行)。
现在我有完整的答案了。
答案:TAP 设备在虚拟机外部(宿主机的容器网络命名空间内)创建
明确结论
kata-containers 的 TAP 设备是在虚拟机外部创建的,具体位置是容器的网络命名空间(netns)内,创建者是运行在宿主机上的 shim-v2 运行时进程,而不是虚拟机内部的 agent。
详细分析
TAP 设备的创建逻辑位于 setupTCFiltering(TC Filter 默认模型)或 tapNetworkPair(MacVtap 模型)中,两者都调用 createLink:
// setupTCFiltering (network_linux.go 第 1096 行)
tapLink, fds, err := createLink(netHandle, netPair.TAPIface.Name, &netlink.Tuntap{}, queues)
而 createLink(第 729 行)最终执行的是 netHandle.LinkAdd(newLink)(第 775 行),通过 netlink 系统调用在当前所在的内核网络命名空间里创建 tapN_kata TAP 接口。
关键:调用发生在哪个 netns?
关键在于调用链的执行上下文:
scanEndpointsInNs (network_linux.go 第 455 行)
└─ doNetNS(nsPath, ...) ← 进入容器的 netns
└─ addSingleEndpoint
└─ endpoint.Attach
└─ xConnectVMNetwork
└─ setupTCFiltering
└─ createLink → netlink.LinkAdd ← TAP 在此创建
doNetNS(第 1359 行)会通过 targetNS.Set() 切换到目标网络命名空间(即容器的 netns,n.netNSPath),然后才执行回调。因此 createLink 里的 netlink.LinkAdd 是在容器的网络命名空间中执行的。
所以 TAP 设备创建在:
- 宿主机上(不是 VM 内)
- 容器的网络命名空间内(netns)
为什么在 VM 外创建 TAP?
kata-containers 的核心设计是:虚拟机(guest)不直接操作宿主机的 TAP 设备。TAP 的 fd 是在宿主机侧创建好之后,通过传文件描述符(fd passing)传给 hypervisor(QEMU/CLH),作为 VM 的虚拟网卡(virtio-net 后端)。具体:
- 宿主机侧
createLink创建 TAP,并把tapLink.Fds(fd)存入netPair.VMFds - 这些 fd 通过
h.AddDevice(ctx, endpoint, NetDev)传给 hypervisor - hypervisor(QEMU)用这个 fd 作为 virtio-net 设备的后端,实现 VM 内网卡与宿主 TAP 的数据交换
- TC 过滤器把容器 netns 内 CNI 创建的 veth(
eth0)流量重定向到 TAP,实现双向连通
虚拟机内部发生了什么?
VM 内部不需要也不存在 TAP 设备。VM 内的网络配置(kataAgent.setupNetworks)只是:
- 通过 agent 的
updateInterfaces配置 VM 内 virtio 网卡的 MAC/IP/MTU - 通过
updateRoutes配置路由 - 通过
addARPNeighbors配置 ARP 邻居
这些配置信息来自宿主机侧扫描时保存的 NetworkInfo(IP、路由、邻居),让 VM 内的 virtio 网卡(对应宿主的 TAP/veth)拥有正确的网络配置,实现容器与 VM 内进程的网络互通。
对比两种模型
| 模型 | TAP 设备 | 创建位置 | VM 内部 |
|---|---|---|---|
| TC Filter(默认) | tapN_kata(netlink.Tuntap) |
宿主机容器 netns 内 | virtio-net 网卡(对应 TAP fd) |
| MacVtap | tapN_kata(netlink.Macvtap) |
宿主机容器 netns 内(挂在父接口上) | virtio-net 网卡(对应 macvtap fd) |
总结:TAP 设备一律创建在宿主机的容器网络命名空间内(虚拟机外),由 shim-v2 运行时通过 netlink 创建,其 fd 传给 hypervisor 作为 VM 网卡的后端。VM 内部只有对应的 virtio-net 虚拟网卡,没有 TAP 设备。

浙公网安备 33010602011771号