物理网卡的 net_device_ops 背后是硬件寄存器和
DMA 引擎;虚拟网络设备的 net_device_ops
背后是纯软件逻辑。但对协议栈来说,它们是同一个接口——这就是
Linux 网络设备模型的抽象能力。
容器网络的绝大多数功能都建立在虚拟设备上:veth 做跨命名空间通信、bridge 做二层转发、macvlan 做轻量级隔离、tun/tap 做用户态网络。本文从内核源码拆解这四类设备的实现细节。
一、veth pair:跨命名空间的零拷贝通道
veth(virtual ethernet)是成对创建的虚拟网卡,一端发送的包直接出现在另一端的接收队列中。它是容器网络最常用的跨命名空间通信机制。
1.1 创建与数据结构
veth pair 通过 netlink 创建,内核入口是
veth_newlink()。两端设备共享同一个驱动,各自持有指向对端的
peer 指针:
// drivers/net/veth.c
struct veth_priv {
struct net_device __rcu *peer; // 对端设备(RCU 保护)
atomic64_t dropped; // 丢包计数
struct bpf_prog *_xdp_prog; // XDP 程序
struct veth_rq *rq; // 接收队列(NAPI 模式)
unsigned int requested_headroom;
};peer 是 RCU 指针——删除 veth pair
时,一端先将对端的 peer 设为 NULL,另一端通过
rcu_dereference() 检测到 NULL
后停止转发。这比加锁高效得多,因为 veth_xmit()
在发包热路径上。
1.2 veth_xmit:发送路径
veth 的发送不涉及任何硬件操作——它只是将 skb 从一端”搬运”到另一端:
// drivers/net/veth.c(简化)
static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct veth_priv *priv = netdev_priv(dev);
struct net_device *rcv;
rcu_read_lock();
rcv = rcu_dereference(priv->peer);
if (unlikely(!rcv)) {
kfree_skb(skb);
goto drop;
}
// 零拷贝:不复制数据,只切换 skb->dev
if (likely(veth_forward_skb(rcv, skb, rq, use_napi) == NET_RX_SUCCESS))
// 更新发送统计
else
atomic64_inc(&priv->dropped);
rcu_read_unlock();
return NETDEV_TX_OK;
}veth_forward_skb() 内部调用
dev_forward_skb() 或
__dev_forward_skb(),最终通过
netif_rx() 将 skb
注入对端设备的接收队列。关键操作:
skb->dev = rcv——将包的设备指针从发送端切换为接收端skb_scrub_packet()——清除发送端的路由缓存、conntrack 关联eth_type_trans()——重新解析以太网头netif_rx()或napi_gro_receive()——注入接收路径
这里没有 memcpy——skb 的数据缓冲区原封不动地从发送端传递到接收端。唯一的”代价”是接收端要走完整的收包路径,包括 netfilter 钩子。
1.3 双重 netfilter 遍历
veth 的一个重要性能特征是:一次跨命名空间通信,netfilter 钩子被遍历两次。
容器命名空间 宿主机命名空间
┌────────────────────┐ ┌────────────────────┐
│ 应用 send() │ │ │
│ ↓ │ │ │
│ OUTPUT 钩子 ① │ │ │
│ ↓ │ │ │
│ POSTROUTING 钩子 ② │ │ │
│ ↓ │ │ │
│ veth_xmit() │──skb 切换──→│ PREROUTING 钩子 ③ │
│ │ │ ↓ │
└────────────────────┘ │ 路由判定 │
│ ↓ │
│ FORWARD 钩子 ④ │
│ ↓ │
│ POSTROUTING 钩子 ⑤ │
│ ↓ │
│ 物理网卡发送 │
└────────────────────┘
五次 netfilter 钩子遍历是 veth 方案的固有开销。Cilium 通过在 veth 的 TC/XDP 钩子上挂载 BPF 程序,在 netfilter 之前就完成转发决策,绕过了大部分钩子遍历。
1.4 XDP native 模式
veth 支持 XDP native 模式。当对端挂载了 XDP 程序时,veth 切换到 NAPI 接收模式:
// drivers/net/veth.c
struct veth_rq {
struct napi_struct xdp_napi; // NAPI 实例
struct napi_struct *napi;
struct net_device *dev;
struct bpf_prog __rcu *xdp_prog; // 该接收队列的 XDP 程序
struct xdp_mem_info xdp_mem;
struct xdp_rxq_info xdp_rxq;
// ...
};在 NAPI 模式下,veth_xmit() 不再直接调用
netif_rx(),而是将 skb 放入对端的
veth_rq 队列,然后调度 NAPI
轮询。veth_poll() 在轮询时执行 XDP 程序:
// veth_poll() → veth_xdp_rcv()(简化)
static int veth_xdp_rcv(struct veth_rq *rq, int budget, ...)
{
// 对每个 skb 运行 XDP 程序
act = bpf_prog_run_xdp(xdp_prog, &xdp);
switch (act) {
case XDP_PASS: // 继续走协议栈
break;
case XDP_TX: // 从原端口发回
veth_xdp_tx(rq, &xdp, ...);
break;
case XDP_REDIRECT: // 重定向到其他设备/CPU
xdp_do_redirect(rq->dev, &xdp, xdp_prog);
break;
case XDP_DROP: // 丢弃
break;
}
}XDP native 模式让 veth 可以在
netif_receive_skb() 之前就处理包,避免了分配
sk_buff 的开销。这是 Cilium 在 Kubernetes
中实现高性能网络策略的关键路径。
1.5 GRO 支持
veth 实现了 veth_gro_receive() 和
veth_gro_complete() 回调,支持 GRO(Generic
Receive Offload)聚合。当大量小包从容器发出时,GRO
在宿主机侧将它们合并为大包,减少协议栈处理次数。
二、Linux bridge:软件二层交换机
Linux bridge 是内核实现的二层交换机。Docker 的
docker0、Kubernetes 的 cni0 都是
bridge 设备。
2.1 核心数据结构
// net/bridge/br_private.h(简化)
struct net_bridge {
struct net_device *dev; // bridge 设备本身
struct list_head port_list; // 端口链表
struct net_bridge_fdb_entry *fdb_hash; // FDB 哈希表
struct hlist_head fdb_list; // FDB 全量链表
unsigned long ageing_time; // FDB 老化时间(默认 300s)
u16 group_fwd_mask; // LLDP/STP 帧转发掩码
bridge_id bridge_id; // STP 网桥 ID
bridge_id designated_root;// STP 根网桥
struct br_stp_info stp_info; // STP 状态
// VLAN 过滤
struct net_bridge_vlan_group __rcu *vlgrp;
// ...
};
struct net_bridge_port {
struct net_bridge *br; // 所属网桥
struct net_device *dev; // 物理/虚拟端口设备
struct list_head list; // 链入 br->port_list
unsigned long flags; // BR_LEARNING, BR_FLOOD 等
u8 state; // STP 状态
u16 port_no; // 端口编号
port_id port_id; // STP 端口 ID
// ...
};
struct net_bridge_fdb_entry {
struct rhash_head rhnode; // 哈希表节点
unsigned char addr[ETH_ALEN]; // MAC 地址
unsigned char key[ETH_ALEN]; // 查找键
struct net_bridge_port *dst; // 目标端口
unsigned long updated; // 最后更新时间
unsigned long used; // 最后使用时间
u16 vlan_id; // VLAN ID
u16 flags; // 本地/静态标记
};2.2 br_handle_frame:入口处理
当一个帧到达 bridge 的端口设备时,收包路径中的
__netif_receive_skb_core() 通过
rx_handler 回调进入 bridge 处理:
// net/bridge/br_input.c(简化)
static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
{
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
// 1. STP BPDU 处理
if (is_link_local_ether_addr(dest)) {
// 根据 group_fwd_mask 决定转发还是本地处理
return br_handle_local_finish(...);
}
// 2. 检查端口 STP 状态
switch (p->state) {
case BR_STATE_FORWARDING:
case BR_STATE_LEARNING:
break;
default:
goto drop; // DISABLED/LISTENING/BLOCKING 状态丢弃
}
// 3. 源 MAC 学习(如果端口启用了 BR_LEARNING)
if (p->flags & BR_LEARNING)
br_fdb_update(p->br, p, eth_hdr(skb)->h_source, vid, ...);
// 4. 进入转发路径
if (p->state == BR_STATE_FORWARDING)
NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING, ...
br_handle_frame_finish);
}2.3 FDB 转发决策
br_handle_frame_finish() 根据目的 MAC 在 FDB
中查找转发端口:
// net/bridge/br_input.c(简化)
static int br_handle_frame_finish(struct sk_buff *skb)
{
struct net_bridge_fdb_entry *dst;
// 目的 MAC 查找
dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid);
if (dst) {
// 单播转发:发送到特定端口
br_forward(dst->dst, skb, ...);
} else {
// 未知单播/广播/组播:泛洪到所有端口(除入口端口)
br_flood(br, skb, BR_PKT_UNICAST, ...);
}
}FDB 查找使用 rhashtable(可调整大小的哈希表),键是
(MAC, VLAN_ID) 二元组。查找在 RCU
读临界区中进行,无需加锁。
2.4 FDB 学习与老化
学习:br_fdb_update()
在每个入帧时调用,记录源 MAC 与入口端口的映射。如果 MAC
已存在但端口不同(设备迁移),更新端口并刷新时间戳。
老化:br_fdb_cleanup()
定期扫描 FDB,删除超过 ageing_time(默认 300
秒)未被使用的条目:
// 老化判断
if (time_after(jiffies, fdb->updated + br->ageing_time)) {
// 删除过期条目
fdb_delete(br, fdb, ...);
}静态条目(通过 bridge fdb add
手动添加)和本地条目(bridge 自身 MAC)不参与老化。
2.5 STP 状态机
STP(Spanning Tree Protocol)防止二层环路。bridge 的每个端口维护一个 STP 状态:
| 状态 | 值 | 行为 |
|---|---|---|
| DISABLED | 0 | 端口关闭,不参与任何操作 |
| LISTENING | 1 | 处理 BPDU 帧,不学习、不转发 |
| LEARNING | 2 | 处理 BPDU,学习 MAC,不转发数据 |
| FORWARDING | 3 | 完全工作状态:学习 + 转发 |
| BLOCKING | 4 | 只处理 BPDU,阻止数据帧 |
状态转换由 BPDU 帧驱动。根选举完成后,冗余路径上的端口进入 BLOCKING 状态,保证无环路拓扑。
容器网络场景中通常关闭
STP(brctl stp docker0 off),因为 veth
拓扑是星型的,不存在环路。
2.6 VLAN 过滤
bridge 支持 per-port VLAN 过滤。每个端口可以配置允许通过的 VLAN ID 集合:
// include/uapi/linux/if_bridge.h
struct bridge_vlan_info {
__u16 flags; // BRIDGE_VLAN_INFO_MASTER, PVID, UNTAGGED
__u16 vid; // VLAN ID
};启用 VLAN
过滤后(echo 1 > /sys/class/net/br0/bridge/vlan_filtering),bridge
在转发前检查帧的 VLAN
标签是否在目标端口的允许列表中。PVID(Port VLAN
ID)为未标记帧添加默认 VLAN。
2.7 端口标志
bridge 端口通过 24 个二进制标志控制行为:
// include/linux/if_bridge.h
#define BR_HAIRPIN_MODE BIT(0) // 允许从入口端口发回(hairpin)
#define BR_BPDU_GUARD BIT(1) // 收到 BPDU 立即关闭端口
#define BR_ROOT_BLOCK BIT(2) // 阻止成为根端口
#define BR_MULTICAST_FAST_LEAVE BIT(3) // IGMP 快速离组
#define BR_LEARNING BIT(5) // 启用 FDB 源 MAC 学习
#define BR_FLOOD BIT(6) // 未知单播泛洪
#define BR_PROMISC BIT(7) // 混杂模式
#define BR_NEIGH_SUPPRESS BIT(15) // ARP/ND 代答(抑制广播)
#define BR_TX_FWD_OFFLOAD BIT(20) // 硬件卸载转发BR_HAIRPIN_MODE
在容器网络中有特殊作用:当容器需要通过 bridge
访问同一宿主机上的服务时,包从 veth 端口进入 bridge
后需要从同一端口发回。默认关闭,需要显式启用。
三、macvlan:轻量级 MAC 地址虚拟化
macvlan 在一个物理网卡上创建多个虚拟设备,每个设备有独立的 MAC 地址。与 bridge 相比,macvlan 没有 FDB 学习和 STP 的开销。
3.1 数据结构
// include/linux/if_macvlan.h
struct macvlan_dev {
struct net_device *dev; // 虚拟接口
struct macvlan_port *port; // 父端口(管理结构)
struct net_device *lowerdev; // 底层物理网卡
enum macvlan_mode mode; // 工作模式
u16 flags; // NOPROMISC, NODST
struct vlan_pcpu_stats __percpu *pcpu_stats; // per-CPU 统计
DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ);
unsigned int macaddr_count;
};
struct macvlan_port {
struct net_device *dev; // 底层物理网卡
struct hlist_head vlan_hash[MACVLAN_HASH_SIZE]; // MAC→macvlan 哈希
struct list_head vlans; // 所有 macvlan 设备链表
struct sk_buff_head bc_queue; // 广播队列
// ...
};macvlan_port 挂在物理网卡上,维护一个 MAC
地址哈希表。收到包时,通过目的 MAC 查找对应的
macvlan_dev,直接投递。
3.2 五种模式
// include/uapi/linux/if_link.h
enum macvlan_mode {
MACVLAN_MODE_PRIVATE = 1, // 完全隔离
MACVLAN_MODE_VEPA = 2, // 通过外部交换机转发
MACVLAN_MODE_BRIDGE = 4, // 本地二层桥接
MACVLAN_MODE_PASSTHRU = 8, // 独占物理网卡
MACVLAN_MODE_SOURCE = 16, // 基于源 MAC 过滤
};bridge 模式:macvlan 子接口之间可以直接通信,不需要经过外部交换机。发送时检查目的 MAC 是否属于本端口的其他 macvlan,如果是则直接本地转发。
VEPA 模式:所有流量都发往物理网卡,即使目的地是同一宿主机上的另一个 macvlan。要求外部交换机支持 hairpin(802.1Qbg VEPA)。
private 模式:最严格的隔离——macvlan 子接口之间完全不能通信,即使外部交换机做 hairpin 也被内核丢弃。
passthru 模式:物理网卡只能有一个 macvlan 子接口,该接口直接使用物理网卡的 MAC。常用于需要完全控制物理网卡但不想直接迁移设备到容器的场景。
source 模式:基于源 MAC 地址列表决定哪些帧可以被接收。用于安全过滤。
3.3 收包路径
macvlan 通过 rx_handler 注册在物理网卡上(和
bridge 一样的机制):
// drivers/net/macvlan.c(简化)
static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
{
struct macvlan_port *port = macvlan_port_get_rcu(skb->dev);
struct macvlan_dev *vlan;
if (is_multicast_ether_addr(dest)) {
// 广播/组播:复制到所有 macvlan 子接口
macvlan_broadcast(skb, port, ...);
} else {
// 单播:MAC 哈希查找
vlan = macvlan_hash_lookup(port, dest);
if (vlan) {
skb->dev = vlan->dev; // 切换到 macvlan 设备
// 投递到该 macvlan 的接收队列
}
}
}单播查找是 O(1) 哈希操作,比 bridge 的 FDB 更轻量——没有学习、没有老化、没有 STP。
3.4 macvlan 与 ipvlan 对比
ipvlan 与 macvlan 类似,但所有子接口共享同一个 MAC 地址,仅靠 IP 地址区分流量:
| 特性 | macvlan | ipvlan |
|---|---|---|
| MAC 地址 | 每个子接口独立 MAC | 共享父设备 MAC |
| 交换机影响 | 交换机看到多个 MAC | 交换机只看到一个 MAC |
| 广播处理 | 每个 MAC 独立接收 | 按 IP 过滤广播 |
| 模式 | L2 操作 | L2 模式和 L3 模式 |
| 性能 | 接近线速 | L3 模式更快(跳过 ARP) |
| 802.1x 兼容 | 不兼容(多 MAC) | 兼容(单 MAC) |
ipvlan L3 模式性能最优——它在三层路由级别分发包,完全跳过二层处理和 ARP 解析。
四、tun/tap:用户态网络的入口
tun 和 tap 是内核与用户态之间的数据通道。用户态程序打开
/dev/net/tun 字符设备,通过 read/write
收发网络包。
4.1 tun 与 tap 的区别
// include/uapi/linux/if_tun.h
#define IFF_TUN 0x0001 // L3 模式:用户态读写 IP 包
#define IFF_TAP 0x0002 // L2 模式:用户态读写以太网帧- tun:三层设备,用户态程序收到的是 IP 包(没有以太网头)。VPN 软件(OpenVPN、WireGuard 用户态版本)常用 tun。
- tap:二层设备,用户态程序收到的是完整以太网帧。虚拟机(QEMU/KVM)常用 tap 来模拟真实网卡。
4.2 内核到用户态(发送方向)
当协议栈向 tun/tap 设备发包时:
// drivers/net/tun.c(简化)
static netdev_tx_t tun_net_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct tun_file *tfile;
// 选择目标队列(多队列支持)
tfile = rcu_dereference(tun->tfiles[txq]);
// 将 skb 放入文件描述符的接收队列
if (skb_queue_len(&tfile->socket.sk->sk_receive_queue) >= dev->tx_queue_len)
goto drop; // 队列满则丢弃
skb_queue_tail(&tfile->socket.sk->sk_receive_queue, skb);
// 唤醒在 read()/poll() 上等待的用户态进程
wake_up_interruptible(&tfile->socket.wq.wait);
return NETDEV_TX_OK;
}用户态进程通过 read()
系统调用从文件描述符读取包。每次 read 返回一个完整的包。
4.3 用户态到内核(接收方向)
用户态程序通过 write() 系统调用注入包:
// drivers/net/tun.c(简化)
static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
const struct iov_iter *from, ...)
{
struct sk_buff *skb;
// 分配 skb 并从用户态缓冲区复制数据
skb = tun_alloc_skb(tfile, ...);
skb_copy_datagram_from_iter(skb, 0, from, len);
// 设置协议类型
if (tun->flags & IFF_TUN)
skb->protocol = pi.proto; // tun 模式从 tun_pi 头获取
else
skb->protocol = eth_type_trans(skb, tun->dev); // tap 模式解析以太网头
// 注入接收路径
netif_rx_ni(skb);
}注意这里有一次 copy_from_user()——这是
tun/tap
的主要性能瓶颈。每个包都要在内核态和用户态之间复制一次数据。
4.4 vhost-net 加速
QEMU/KVM 场景中,每个包经历两次上下文切换(内核→QEMU→内核)和一次数据复制。vhost-net 通过将数据路径下沉到内核态来消除这个开销:
标准路径:NIC → 内核 → QEMU(用户态) → write → 内核 → 虚拟机
vhost-net:NIC → 内核 → vhost worker(内核态) → 虚拟机
vhost-net 在内核中运行一个工作线程,直接操作 virtio 环形缓冲区,避免了用户态的上下文切换。
4.5 多队列支持
tun/tap
支持多队列(IFF_MULTI_QUEUE),允许多个用户态线程并行处理不同队列的包:
// 创建多队列 tun/tap
int fd = open("/dev/net/tun", O_RDWR);
struct ifreq ifr = { .ifr_flags = IFF_TAP | IFF_NO_PI | IFF_MULTI_QUEUE };
ioctl(fd, TUNSETIFF, &ifr);
// 每个线程打开一个新的 fd 并绑定到同一设备
int fd2 = open("/dev/net/tun", O_RDWR);
ioctl(fd2, TUNSETIFF, &ifr); // 自动分配到下一个队列多队列配合 RSS/RPS 可以显著提高虚拟机网络吞吐量。
4.6 offload 特性
tun/tap 支持多种卸载特性,通过 virtio 网络头传递给用户态:
// include/uapi/linux/if_tun.h
#define TUN_F_CSUM 0x01 // 校验和卸载
#define TUN_F_TSO4 0x02 // TCP 分段卸载(IPv4)
#define TUN_F_TSO6 0x04 // TCP 分段卸载(IPv6)
#define TUN_F_TSO_ECN 0x08 // TSO + ECN
#define TUN_F_UFO 0x10 // UDP 分片卸载
#define TUN_F_USO4 0x20 // UDP 分段卸载(IPv4)
#define TUN_F_USO6 0x40 // UDP 分段卸载(IPv6)启用 IFF_VNET_HDR 后,每个包前面附加
struct virtio_net_hdr,其中包含 GSO
类型和校验和偏移量。这让用户态程序(QEMU)可以处理大包而不需要内核先分段。
五、性能对比与选型指南
各类虚拟设备的吞吐量排序(从高到低):
ipvlan L3 ≥ macvlan bridge > ipvlan L2 > veth + bridge >> tun/tap
| 设备类型 | 每包开销 | 适用场景 |
|---|---|---|
| ipvlan L3 | 最低(纯路由) | 高性能容器,不需要独立 MAC |
| macvlan bridge | 低(MAC 哈希查找) | 需要独立 MAC 的容器 |
| veth + bridge | 中(双重协议栈 + FDB) | Docker 默认、K8s 通用方案 |
| veth + 路由 | 中(双重协议栈) | Calico 方案 |
| tun/tap | 高(用户态拷贝 + 上下文切换) | VPN、虚拟机 |
veth + bridge 是最通用的方案,牺牲一些性能换取最大的灵活性。macvlan 性能更好但不支持与宿主机通信(bridge 模式下 macvlan 无法访问父设备的 IP)。ipvlan L3 性能最优但对上层协议有限制(不支持 DHCP、不支持组播)。
六、可观测性
6.1 bpftrace 追踪虚拟设备
追踪 veth 转发:
bpftrace -e '
kprobe:veth_xmit {
$dev = (struct net_device *)arg1;
printf("veth_xmit: dev=%s len=%d\n", $dev->name,
((struct sk_buff *)arg0)->len);
}'追踪 bridge FDB 更新:
bpftrace -e '
kprobe:br_fdb_update {
$port = (struct net_bridge_port *)arg1;
printf("fdb_update: port=%s\n", $port->dev->name);
}'追踪 tun/tap 数据交换:
bpftrace -e '
kprobe:tun_net_xmit {
$dev = (struct net_device *)arg1;
printf("tun_xmit: dev=%s len=%d\n", $dev->name,
((struct sk_buff *)arg0)->len);
}
kprobe:tun_get_user {
printf("tun_rx: from userspace, pid=%d\n", pid);
}'6.2 bridge 状态查看
# 查看 FDB 表
bridge fdb show dev docker0
# 查看 STP 状态
brctl showstp docker0
# 查看 VLAN 过滤配置
bridge vlan show
# 查看端口统计
ip -s link show docker06.3 perf 性能分析
# 对比 veth 与 macvlan 的协议栈开销
perf record -g -e cycles -- iperf3 -c 10.0.0.2 -t 10
perf report --no-children
# 追踪 tun/tap 上下文切换
perf stat -e context-switches -p $(pidof qemu-system-x86_64) -- sleep 10七、参考文献
- Linux 6.6 内核源码
drivers/net/veth.c、net/bridge/br_input.c - Linux 6.6 内核源码
drivers/net/macvlan.c、drivers/net/tun.c - Linux 6.6 内核源码
include/linux/if_bridge.h、include/linux/if_macvlan.h - Thomas Graf,《Understanding and Configuring Linux Network Interfaces》
- vhost-net 架构文档
Documentation/vhost/vhost.rst
下一篇:隧道协议内核实现:VXLAN、IPIP、GRE 与 WireGuard
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【Kubernetes 网络深度系列】虚拟网络设备:veth / bridge / tun/tap / macvlan / ipvlan
五种 Linux 虚拟网络设备的内核实现原理、数据流路径、性能代价与适用场景,附手工实验验证。
【从零造容器】容器网络性能真相:veth vs macvlan vs eBPF 数据面
容器网络为什么比裸机慢?veth + bridge 每个包经过两次 netfilter,macvlan 跳过了 bridge,Cilium 用 eBPF 替掉了 iptables。到底慢多少?我们用 iperf3、wrk 和自定义 echo server 实测。
【Linux 网络子系统深度拆解】网络命名空间:内核级网络隔离的实现
容器网络的一切隔离能力,都建立在网络命名空间之上。本文从 Linux 6.6 内核源码拆解 struct net 的完整布局、possible_net_t 与 RCU 访问模式、pernet_operations 子系统注册与生命周期回调、copy_net_ns() 命名空间创建路径、per-netns 路由表/netfilter/socket 隔离机制,以及 veth pair 跨命名空间数据转发的 skb->dev 切换原理。
【Linux 网络子系统深度拆解】网络丢包定位:从 drop_monitor 到 kfree_skb 追踪
从内核源码拆解 Linux 网络丢包追踪的完整体系:kfree_skb tracepoint 与 80+ 种 drop_reason 枚举、drop_monitor netlink 子系统、dropwatch 工具、perf 丢包记录、bpftrace 丢包聚合脚本,以及生产环境常见丢包点速查表。