Linux Bridge 增加和删除 VLAN 的代码流程是怎样的?

大家好,我是Q,QQ邮箱:1042484520@qq.com。
今天我们在上一讲的基础上再扩展下 Brideg 增加和删除 VLAN 的代码流程。
话不多说,我们先直接展示网络架构图,具体如下所示:
Linux Bridge 中,VLAN 标签的增加和删除是通过内核的网络栈、VLAN 支持模块以及桥接(Bridge)驱动来实现的。具体来说, VLAN 标签的处理 是由 bridge 模块VLAN 子系统 协同工作完成的。
要深入了解 VLAN 标签的增加和删除 的过程,我们可以分为以下几个部分:

1. VLAN 子系统概述

在 Linux 中, VLAN 子系统 通过 IEEE 802.1Q 标准来处理 VLAN 标签的插入和去除。VLAN 标签本质上是在 数据链路层 对以太网帧进行标记,使其可以被识别为属于特定 VLAN。
VLAN 标签的添加和删除主要通过以下几个组件完成:
  • vlan 驱动程序:负责将 VLAN 标签添加到以太网帧中。
  • bridge 驱动程序:负责在桥接接口之间转发数据,管理不同接口上的 VLAN 标签。

2. 增加和删除 VLAN 标签的工作原理

当桥接接口(br0)转发数据时,会根据接口是否支持 VLAN 来决定是否增加或删除 VLAN 标签。

(1)从 eth0.22 转发到 WLAN1(带 VLAN 标签的数据转发)

  • 数据从 eth0.22 发出:
    • 数据帧从 eth0.22 接口发出时,包含 VLAN 标签。eth0.22 是一个 VLAN 接口,数据帧会附带 VLAN ID。
    • 内核会处理数据帧,自动加上 VLAN 标签,标记数据帧为 VLAN 22。
  • 转发到 WLAN1:
    • 当桥接设备 (br0) 将数据帧转发到 WLAN1 接口时,发现 WLAN1 是普通的非 VLAN 接口。
    • 内核代码 会检查该数据帧,如果目标接口不支持 VLAN(如 WLAN1),则会 删除 VLAN 标签,并将数据帧作为普通帧传递。
  • 删除 VLAN 标签:
    • 在数据包的转发过程中,内核通过桥接表和 VLAN 配置,会自动移除 VLAN 标签,完成数据包的转发。

(2)从 wlan0 转发到 eth0.22(无 VLAN 标签的数据转发)

  • 数据从 WLAN1 发出:
    • 数据帧从 WLAN1 发出时,不带有 VLAN 标签,即普通的以太网帧。
    • 当桥接设备 (br0) 收到该帧时,检测到目标接口是 eth0.22(VLAN 接口)。
  • 添加 VLAN 标签:
    • 内核代码 会自动将 VLAN 标签添加到数据帧,使用 VLAN 22 标记该帧,以便正确地将其传递到 eth0.22。
    • 此过程通过 VLAN 驱动程序 实现,该驱动程序负责将 VLAN 标签插入到数据帧中,符合 IEEE 802.1Q 标准。

3. 具体的代码流程

假设我们在桥接中执行 VLAN 标签的添加和删除,相关的代码主要涉及以下几个部分:

(1)VLAN 标签的添加(增加)

在 Linux 内核中,VLAN 标签的添加通常是在数据帧被转发到 VLAN 接口时,由 VLAN 处理模块执行。相关代码可以在 net/bridge/br_vlan.cnet/8021q/vlan.c 文件中找到。
函数 vlan_insert_tag():用于将 VLAN 标签插入到数据帧中。
int vlan_insert_tag(struct sk_buff *skb, u16 vlan_id)
{
    struct vlan_ethhdr *veth;
    struct ethhdr *eth;

    eth = eth_hdr(skb);
    veth = (struct vlan_ethhdr *)eth;

    /* VLAN tag insertion */
    veth->h_vlan_proto = htons(ETH_P_8021Q);  /* VLAN protocol */
    veth->h_vlan_TCI = htons(vlan_id);  /* VLAN ID */
    skb->protocol = eth_type_trans(skb, skb->dev);
    return 0;
}
vlan_insert_tag() 函数会将 VLAN ID 插入到数据帧中,使数据帧符合 IEEE 802.1Q 标准。

(2)VLAN 标签的删除(移除)

当数据包从一个带 VLAN 标签的接口(如 eth0.22)转发到不支持 VLAN 的接口(如 WLAN1)时,内核会通过 vlan_hwaccel_receive_skb() 来删除 VLAN 标签。
函数 vlan_hwaccel_receive_skb():用于处理接收到的带 VLAN 标签的数据帧,并根据目标接口是否支持 VLAN 标签来决定是否删除标签。
int vlan_hwaccel_receive_skb(struct sk_buff *skb, struct net_device *dev)
{
    struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb);
    
    if (skb_vlan_tag_present(skb)) {
        /* Remove VLAN tag */
        skb->protocol = eth_type_trans(skb, dev);
        skb_pull(skb, VLAN_HLEN);  /* Remove the VLAN header */
    }
    
    return 0;
}

skb_pull(skb, VLAN_HLEN) 会去除 VLAN 标签(VLAN 头部的长度),确保数据包以普通帧的格式继续传输。

(3)桥接处理的关键代码

在桥接处理中,VLAN 标签的管理通常会在 net/bridge/br_input.cnet/bridge/br_forward.c 中完成,涉及到数据包的接收和转发。
函数 br_handle_frame():负责处理桥接设备接收到的帧,并根据目标接口的类型来决定是否需要加或去除 VLAN 标签。
int br_handle_frame(struct sk_buff *skb, struct net_device *dev)
{
    struct vlan_ethhdr *veth = (struct vlan_ethhdr *)eth_hdr(skb);

    if (dev->vlan_vid) {
        /* If the device is VLAN-aware, insert VLAN tag */
        vlan_insert_tag(skb, dev->vlan_vid);
    } else {
        /* If the device is not VLAN-aware, remove VLAN tag */
        if (skb_vlan_tag_present(skb)) {
            skb_pull(skb, VLAN_HLEN);
        }
    }
    return 0;
}

(4)总结

  • VLAN 标签的添加:通过调用类似 vlan_insert_tag() 的函数,数据帧会被标记为特定 VLAN。
  • VLAN 标签的删除:在不支持 VLAN 的接口(如 wlan0)上,数据帧的 VLAN 标签会被移除。
  • 桥接处理:桥接设备会根据接口的 VLAN 配置自动处理 VLAN 标签的插入和删除,保证数据帧能够正确转发。
这些操作是在 Linux 内核中通过 VLAN 子系统Bridge 驱动程序 完成的,基本上实现了 VLAN 标签的透明处理,无需额外的用户空间配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值