Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 協議棧深度解析:網橋創建流程與核心數據結構初始化

編輯:Linux 教學

在 Linux 核心網路子系統中,網橋作為一種虛擬的第二層交換設備,其創建流程涉及從用戶空間到核心空間的多層交互。本文將深入剖析 br_add_bridge、new_bridge_dev 以及 br_dev_setup 等關鍵函數,揭示網橋 net_device 結構的初始化細節。

用戶空間觸發:ioctl 與 SIOCBRADDBR

當用戶執行 brctl addbr br0 時,工具程序會調用 ioctl(br_socket_fd, SIOCBRADDBR, brname),進入核心空間的 br_ioctl_deviceless_stub 函數。該函數根據命令類型分發處理邏輯:

int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg)
{
    switch (cmd) {
    case SIOCBRADDBR:  // 新建網橋
    case SIOCBRDELBR:  // 刪除網橋
        if (!capable(CAP_NET_ADMIN))
            return -EPERM;
        if (copy_from_user(buf, uarg, IFNAMSIZ))
            return -EFAULT;
        buf[IFNAMSIZ-1] = '\0';
        return (cmd == SIOCBRADDBR) ? br_add_bridge(buf) : br_del_bridge(buf);
    }
    return -EOPNOTSUPP;
}

此處會檢查 CAP_NET_ADMIN 權限,並通過 copy_from_user 將網橋名稱從用戶空間拷貝到核心緩衝區,隨後調用 br_add_bridge 正式開始創建流程。

核心創建邏輯:br_add_bridge

br_add_bridge 負責分配並註冊網橋對應的 net_device:

int br_add_bridge(const char *name)
{
    struct net_device *dev = new_bridge_dev(name);
    if (!dev) return -ENOMEM;

    rtnl_lock();
    if (strchr(dev->name, '%')) {
        int ret = dev_alloc_name(dev, dev->name);
        if (ret < 0) goto err1;
    }
    int ret = register_netdevice(dev);
    if (ret) goto err2;
    dev_hold(dev);
    rtnl_unlock();

    ret = br_sysfs_addbr(dev);
    dev_put(dev);
    if (ret) unregister_netdev(dev);
    return ret;

err2: free_netdev(dev);
err1: rtnl_unlock(); return ret;
}

關鍵步驟包括:

  • 調用 new_bridge_dev 分配並初始化 net_device 及其私有數據 net_bridge
  • 若名稱包含 % 則由核心自動分配名稱(如 br0)
  • 調用 register_netdevice 向核心註冊網絡設備
  • 通過 br_sysfs_addbr 在 sysfs 中創建相關屬性節點

私有結構初始化:new_bridge_dev

此函數分配 net_device 並初始化網橋私有結構 net_bridge:

static struct net_device *new_bridge_dev(const char *name)
{
    struct net_device *dev = alloc_netdev(sizeof(struct net_bridge), name, br_dev_setup);
    if (!dev) return NULL;

    struct net_bridge *br = netdev_priv(dev);
    br->dev = dev;
    br->lock = SPIN_LOCK_UNLOCKED;
    INIT_LIST_HEAD(&br->port_list);  // 端口列表初始化
    br->hash_lock = SPIN_LOCK_UNLOCKED;

    // STP 協議相關初始化(略)
    br->bridge_id.prio[0] = 0x80;
    br->stp_enabled = 0;
    br->ageing_time = 300 * HZ;
    INIT_LIST_HEAD(&br->age_list);
    br_stp_timer_init(br);

    return dev;
}

此處完成了自旋鎖初始化、端口列表(port_list)與老化列表(age_list)的鏈表頭初始化,以及 STP 定時器的設置。

設備操作函數綁定:br_dev_setup

br_dev_setup 為 net_device 綁定核心操作函數指針:

void br_dev_setup(struct net_device *dev)
{
    memset(dev->dev_addr, 0, ETH_ALEN);
    ether_setup(dev);  // 以太網基礎設置

    dev->do_ioctl         = br_dev_ioctl;
    dev->get_stats        = br_dev_get_stats;
    dev->hard_start_xmit  = br_dev_xmit;      // 數據發送入口
    dev->open             = br_dev_open;
    dev->set_multicast_list = br_dev_set_multicast_list;
    dev->change_mtu       = br_change_mtu;
    dev->destructor       = free_netdev;
    dev->stop             = br_dev_stop;
    dev->accept_fastpath  = br_dev_accept_fastpath;
    dev->tx_queue_len     = 0;
    dev->set_mac_address  = NULL;
    dev->priv_flags       = IFF_EBRIDGE;  // 標識為橋設備
}

值得注意的是,橋設備的 hard_start_xmit 指向 br_dev_xmit,這是數據包轉發的核心入口;priv_flags 設置為 IFF_EBRIDGE 以區分於普通網卡。

總結

網橋的創建過程本質上是一個虛擬 net_device 的註冊過程,核心在於私有結構 net_bridge 的精心初始化:端口管理列表、MAC 地址學習雜湊表、STP 狀態機以及定時器機制。理解這一流程,有助於深入掌握 Linux 虛擬網絡設備的設計哲學與實現細節。

Copyright © Windows教程網 All Rights Reserved