Linux 3.10 引入 netdev_rx_handler_register,允許為 net_device 動態註冊接收處理函數,替代 2.6 時代硬編碼的協議棧入口。橋接、Bonding、Open vSwitch 均通過此機制掛載處理邏輯。
int netdev_rx_handler_register(struct net_device *dev,
rx_handler_func_t *rx_handler,
void *rx_handler_data) {
ASSERT_RTNL();
if (dev->rx_handler) return -EBUSY;
rcu_assign_pointer(dev->rx_handler_data, rx_handler_data);
rcu_assign_pointer(dev->rx_handler, rx_handler);
return 0;
}
static struct vport *netdev_create(const struct vport_parms *parms) {
// ...
err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, vport);
// ...
}
2.6 內核需替換 br_handle_frame_hook,3.10 直接註冊獨立 handler,模塊化解耦。
rx_handler = rcu_dereference(skb->dev->rx_handler);
if (rx_handler) {
switch (rx_handler(&skb)) {
case RX_HANDLER_CONSUMED: return NET_RX_SUCCESS;
case RX_HANDLER_ANOTHER: goto another_round;
case RX_HANDLER_EXACT: deliver_exact = true;
case RX_HANDLER_PASS: break;
}
}
橋接端口註冊 br_handle_frame,進入橋接邏輯。
rx_handler_result_t br_handle_frame(struct sk_buff **pskb) {
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
// 1. 回環包/無效 MAC 直接丟棄
// 2. 本地鏈路多播地址特殊處理(STP、LLDP 等)
// 3. NF_BR_LOCAL_IN hook → br_handle_local_finish
// 4. 轉發邏輯:FORWARDING/LEARNING 狀態
// - 目的 MAC 是橋設備 → PACKET_HOST → 協議棧
// - NF_BR_PRE_ROUTING hook → br_handle_frame_finish
}
int br_handle_frame_finish(struct sk_buff *skb) {
// 1. VLAN 入向檢查 br_allowed_ingress
// 2. 更新 FDB(MAC 表),含 VLAN 維度
// 3. 多播處理 br_multicast_rcv
// 4. LEARNING 狀態僅學習不轉發
// 5. 決策:
// - 廣播/多播/未知單播 → 泛洪 br_flood_forward
// - 已知單播 → br_forward 到目標端口
// - 本地 MAC → br_pass_frame_up 送協議棧
}
static int br_pass_frame_up(struct sk_buff *skb) {
// VLAN 出向處理 br_handle_vlan
skb->dev = brdev; // 關鍵:修改設備為橋設備
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, netif_receive_skb);
}
再次進入 netif_receive_skb,因橋設備無 rx_handler,直接上送協議棧。
static void __br_forward(const struct net_bridge_port *to, struct sk_buff *skb) {
skb = br_handle_vlan(to->br, nbp_get_vlan_info(to), skb); // VLAN 處理
skb->dev = to->dev; // 設置出口設備
NF_HOOK(NFPROTO_BRIDGE, NF_BR_FORWARD, ..., br_forward_finish);
}
int br_forward_finish(struct sk_buff *skb) {
return NF_HOOK(NFPROTO_BRIDGE, NF_BR_POST_ROUTING, ..., br_dev_queue_push_xmit);
}
int br_dev_queue_push_xmit(struct sk_buff *skb) {
if (nf_bridge_maybe_copy_header(skb) || need_fragment) kfree_skb(skb);
else {
skb_push(skb, ETH_HLEN);
br_drop_fake_rtable(skb);
dev_queue_xmit(skb); // 驅動發送
}
return 0;
}

| 特性 | 2.6 Kernel | 3.10 Kernel |
|---|---|---|
| 接收入口 | 硬編碼 br_handle_frame_hook | netdev_rx_handler_register 動態註冊 |
| VLAN 支持 | 無原生支持 | 完整 VLAN 過濾、獨立 FDB、標簽處理 |
| Hook 點 | 基礎 | NF_BR_LOCAL_IN/PRE_ROUTING/FORWARD/POST_ROUTING 完整 |
| 多播 | 基礎 IGMP Snooping | 增強 MDB、路由器端口檢測 |