// Layer 2 模式 (macvlan.go:364-380)
if isLayer3 {
// ... Layer 3 配置
} else {
// Layer 2 模式:只设置接口 UP
err = netns.Do(func(_ ns.NetNS) error {
macvlanInterfaceLink, err := netlinksafe.LinkByName(args.IfName)
if err != nil {
return fmt.Errorf("failed to find interface name %q: %v", macvlanInterface.Name, err)
}
// 只做这一件事:设置 UP
if err := netlink.LinkSetUp(macvlanInterfaceLink); err != nil {
return fmt.Errorf("failed to set %q UP: %v", args.IfName, err)
}
return nil
})
}
// Layer 3 模式 (macvlan.go:323-363)
if isLayer3 {
// 调用 IPAM 获取 IP 配置
r, err := ipam.ExecAdd(n.IPAM.Type, args.StdinData)
// 检查必须有 IP
if len(ipamResult.IPs) == 0 {
return errors.New("IPAM plugin returned missing IP config")
}
// 保存 IP 和路由
result.IPs = ipamResult.IPs
result.Routes = ipamResult.Routes
// 配置 IP 和路由到接口
err = netns.Do(func(_ ns.NetNS) error {
return ipam.ConfigureIface(args.IfName, result)
})
}
Layer 2 配置(无 IPAM):
{
"cniVersion": "1.0.0",
"name": "mynet",
"type": "macvlan",
"master": "eth0",
"mode": "bridge"
}
结果:容器内有 eth0 接口,但没有 IP 地址
Layer 3 配置(有 IPAM):
{
"cniVersion": "1.0.0",
"name": "mynet",
"type": "macvlan",
"master": "eth0",
"mode": "bridge",
"ipam": {
"type": "host-local",
"subnet": "10.1.2.0/24",
"routes": [
{ "dst": "0.0.0.0/0" }
]
}
}
在 macvlan 的实现中, Layer 2 模式 和 Layer 3 模式 的 macvlan 的网卡有不同之处么? 除了 ip 和路由这些可以后续配置上的东西
⏺ 非常好的问题!让我仔细分析代码中 macvlan 网卡本身的创建过程。
⏺ Read(plugins/main/macvlan/macvlan.go)
⎿ Read 100 lines
⏺ 答案:网卡本身完全一样,只有一个配置上的细微差异
看代码执行顺序:
- 第 295 行:判断是否是 Layer 3 模式
- 第 303 行:创建 macvlan 网卡(在判断 isLayer3 之前!)
- 第 323-381 行:根据模式做不同的后续配置
macvlan 网卡本身:完全一样
createMacvlan() 函数(macvlan.go:202-287)创建的 macvlan 设备完全一样,不管是否配置了 IPAM。
创建时只依赖这些参数:
- Master: 父接口
- Mode: macvlan 模式(bridge/private/vepa/passthru)
- MTU: 最大传输单元
- Mac: MAC 地址(可选)
- BCQueueLen: 广播队列长度
网卡的内核属性(device type, mode, parent 等)完全相同。
唯一的差异:sysctl 内核参数
虽然网卡本身一样,但 Layer 3 模式会设置额外的内核参数:
Layer 3 模式(macvlan.go:355-360):
err = netns.Do(func(_ ns.NetNS) error {
// 📌 设置 ARP 和 NDP 通知
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv4/conf/%s/arp_notify", args.IfName), "1")
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv6/conf/%s/ndisc_notify", args.IfName), "1")
return ipam.ConfigureIface(args.IfName, result) // 这里也会设置 UP
})
Layer 2 模式(macvlan.go:366-377):
err = netns.Do(func(_ ns.NetNS) error {
macvlanInterfaceLink, err := netlinksafe.LinkByName(args.IfName)
if err != nil {
return fmt.Errorf("failed to find interface name %q: %v", macvlanInterface.Name, err)
}
// 只设置 UP,没有 sysctl 设置
if err := netlink.LinkSetUp(macvlanInterfaceLink); err != nil {
return fmt.Errorf("failed to set %q UP: %v", args.IfName, err)
}
return nil
})
这两个 sysctl 参数的作用
net/ipv4/conf//arp_notify = 1:
- 当 IP 地址配置到接口时,自动发送 Gratuitous ARP(免费 ARP)
- 让同网段的设备快速更新 ARP 缓存,学习新的 MAC-IP 映射
- 避免通信延迟(否则需要等待 ARP 超时)
net/ipv6/conf//ndisc_notify = 1:
- IPv6 的等价功能
- 发送 Unsolicited Neighbor Advertisement(主动邻居通告)
- 让 IPv6 网络快速学习新的 MAC-IP 映射
实际影响
你可以验证这个差异:
Layer 2 模式(无 IPAM):
# 容器内查看
$ sysctl net.ipv4.conf.eth1.arp_notify
net.ipv4.conf.eth1.arp_notify = 0 # 默认值
Layer 3 模式(有 IPAM):
容器内查看
$ sysctl net.ipv4.conf.eth1.arp_notify
net.ipv4.conf.eth1.arp_notify = 1 # 已设置
但这个差异可以手动补齐
即使是 Layer 2 模式创建的网卡,你后续也可以:
# 手动设置这些参数
sysctl -w net.ipv4.conf.eth1.arp_notify=1
sysctl -w net.ipv6.conf.eth1.ndisc_notify=1
手动配置 IP 和路由
ip addr add 192.168.1.10/24 dev eth1
ip route add default via 192.168.1.1 dev eth1
ip link set eth1 up
最终效果和 Layer 3 模式完全一样。
总结
| 项目 | Layer 2 模式 | Layer 3 模式 |
|---|---|---|
| macvlan 设备本身 | ✅ 完全相同 | ✅ 完全相同 |
| device type | macvlan | macvlan |
| mode/parent/MTU | ✅ 相同 | ✅ 相同 |
| arp_notify | 0(默认) | 1 |
| ndisc_notify | 0(默认) | 1 |
| IP 地址 | 无 | 有(IPAM 分配) |
| 路由 | 无 | 有(IPAM 提供) |
| 接口状态 | UP | UP |
结论:除了两个 sysctl 内核参数(arp_notify 和 ndisc_notify),macvlan 网卡设备本身没有任何区别。这两个参数也只是配置层面的优化,可以后续手动设置。