Linux VLAN 实现原理技术笔记

一、引言

 

VLAN(虚拟局域网)在整车网络架构中起着至关重要的作用,它能够在物理网络基础设施上创建逻辑隔离的网络区域,提高车内网络的安全性、灵活性和性能。Linux 内核通过一系列复杂的机制实现了 VLAN 功能,本技术笔记将从源码分析的角度深入梳理 Linux VLAN 的实现原理,包括其数据结构和数据包的收发流程。

 

二、数据结构

 

(一) struct vlan_group 

 

// 定义 VLAN 组结构体

struct vlan_group {

    // 指向真实的网络设备,如物理网卡对应的设备结构体

    struct net_device *real_dev; 

    // 用于组织该 VLAN 组内的 VLAN 设备的哈希链表头

    struct hlist_head vlan_devices; 

    // 用于 RCU(读 - 拷贝更新)机制的结构体成员,用于并发控制

    struct rcu_head rcu; 

    // 指向 VLAN 组的 RCU 相关数据结构,用于高效的内存管理和并发访问

    struct vlan_group_rcu *vgr; 

};

 

 

(二) struct vlan_dev_info 

 

// 定义 VLAN 设备信息结构体

struct vlan_dev_info {

    // 指向该 VLAN 设备对应的网络设备结构体

    struct net_device *dev; 

    // 指向该 VLAN 设备所属的 VLAN 组结构体

    struct vlan_group *vlan_group; 

    // 该 VLAN 设备的 VLAN ID

    u16 vlan_id; 

    // 标志位,用于表示 VLAN 设备的一些属性或状态

    u16 flags; 

    // 指向该 VLAN 设备对应的真实网络设备

    struct net_device *real_dev; 

    // 用于入站数据包过滤的链表头,可设置过滤规则

    struct list_head ingress_filter; 

    // 用于出站数据包过滤的哈希链表头,可设置过滤规则

    struct hlist_head egress_filter; 

    // 用于 RCU 机制的结构体成员

    struct rcu_head rcu; 

};

 

 

这些数据结构是 Linux 实现 VLAN 功能的基础,通过它们可以有效地组织和管理 VLAN 设备以及 VLAN 组之间的关系。

 

三、接收流程

 

(一)入口函数 netif_receive_skb 

 

// 网络数据包接收的关键入口函数

int netif_receive_skb(struct sk_buff *skb)

{

    //... 其他代码省略

    // 判断数据包的协议是否为 802.1Q(VLAN 协议)或 802.1AD(QinQ 协议)

    if (skb->protocol == htons(ETH_P_8021Q) ||

        skb->protocol == htons(ETH_P_8021AD)) {

        // 如果是 VLAN 数据包,则调用 vlan_skb_recv 函数进行处理

        return vlan_skb_recv(skb, skb->dev);

    }

    //... 其他代码省略

    // 如果不是 VLAN 数据包,则返回接收成功的标识

    return NET_RX_SUCCESS;

}

 

 

(二) vlan_skb_recv 函数

 

// 处理 VLAN 数据包接收的函数

int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev)

{

    struct vlan_group *vg;

    struct vlan_dev_info *vlan;

    u16 vid;

    // 从数据包中获取 VLAN ID

    vid = vlan_get_VID(skb);

    // 通过 RCU 机制获取设备对应的 VLAN 组结构体

    vg = rcu_dereference(dev->vlgrp);

    // 如果没有对应的 VLAN 组,则丢弃该数据包

    if (!vg)

        return NET_RX_DROP;

    // 根据 VLAN ID 在 VLAN 组中查找对应的 VLAN 设备信息结构体

    vlan = vlan_group_get_device(vg, vid);

    // 如果没有找到对应的 VLAN 设备,则丢弃该数据包

    if (!vlan)

        return NET_RX_DROP;

    // 将数据包的接收设备设置为找到的 VLAN 设备

    skb->dev = vlan->dev;

    // 将数据包送入网络栈进行后续的接收处理

    netif_receive_skb_internal(skb);

    // 返回接收成功的标识

    return NET_RX_SUCCESS;

}

 

 

在接收流程中,当带有 VLAN 标签的数据包到达网络接口时,首先在 netif_receive_skb 函数中被识别为 VLAN 数据包,然后交由 vlan_skb_recv 函数处理。 vlan_skb_recv 函数会解析数据包中的 VLAN ID,在对应的 VLAN 组中查找匹配的 VLAN 设备,并将数据包的接收设备设置为该 VLAN 设备后,继续进行后续的网络栈处理,就如同该数据包是直接从该 VLAN 设备对应的虚拟接口接收的一样。

 

四、发送流程

 

(一) dev_hard_start_xmit 函数及相关

 

在发送数据包时, dev_hard_start_xmit 函数(在 net/core/dev.c )会被调用,它是网络设备发送数据包的关键函数。对于 VLAN 设备,最终会调用到 vlan_dev_hard_start_xmit 函数。

 

(二) vlan_dev_hard_start_xmit 函数

 

// VLAN 设备发送数据包的函数

int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)

{

    struct vlan_dev_info *vlan = netdev_priv(dev);

    struct net_device *real_dev = vlan->real_dev;

    u16 vlan_tci = vlan->vlan_id | VLAN_TAG_PRESENT;

    // 将数据包指针向前移动 VLAN 头部长度,为添加 VLAN 标签腾出空间

    skb_push(skb, VLAN_HLEN);

    // 将 VLAN 标签(包含 VLAN ID 等信息)添加到数据包中

    __vlan_put_tag(skb, htons(vlan_tci));

    // 将数据包发送到真实设备的发送队列中进行发送

    return dev_queue_xmit(skb);

}

 

 

在发送流程中,当应用程序通过系统调用将数据包发送到对应的 VLAN 设备(如 eth0.10 这样的 VLAN 接口)时, vlan_dev_hard_start_xmit 函数会被调用。它首先获取 VLAN 设备的配置信息,然后将 VLAN 标签添加到数据包中,最后通过底层的网络设备驱动将带有 VLAN 标签的数据包发送到物理网络中。

 

五、总结

 

Linux 通过精心设计的数据结构 struct vlan_group 和 struct vlan_dev_info ,以及在数据包收发流程中的关键函数 netif_receive_skb 、 vlan_skb_recv 、 dev_hard_start_xmit 和 vlan_dev_hard_start_xmit 等的协同工作,实现了 VLAN 功能。在接收时,能够根据 VLAN 标签将数据包正确地分发到对应的 VLAN 设备;在发送时,能够为数据包添加正确的 VLAN 标签并发送到物理网络。这种实现方式使得 Linux 系统在网络虚拟化和 VLAN 应用场景中具有很强的适应性和扩展性,为构建复杂的企业网络和云计算网络环境提供了坚实的基础。同时,由于涉及到内核代码和网络协议栈的底层操作,对于开发者来说,深入理解这些原理有助于进行网络性能优化、故障排查以及定制化的网络功能开发等工作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

车联网安全杂货铺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值