802.1Q VLAN简介
1 VLAN
1.1 VLAN的定义
以太网是一种基于CSMA/CD(Carrier Sense Multiple Access/Collision Detection)的共享通讯介质的数据网络通讯技术。当主机数目较多时会导致冲突严重、广播泛滥、性能显著下降甚至造成网络不可用等问题。通过交换机实现LAN互连虽然可以解决冲突严重的问题,但仍然不能隔离广播报文和提升网络质量。
在这种情况下出现了VLAN技术,这种技术可以把一个LAN划分成多个逻辑的VLAN,每个VLAN是一个广播域,每个广播域都有一个编号(1-4096)。VLAN内的主机间通信就和在一个LAN内一样,而VLAN间则不能直接互通,这样广播报文就被限制在一个VLAN内。
图 1-1-1 VLAN的定义
1.2 VLAN的作用
- 限制广播域:广播域被限制在VLAN ID内,节省了带宽,提高了网络处理能力。
- 增强局域网的安全性:VLAN间的二层报文是相互隔离的,即一个VLAN内的用户不能和其它VLAN内的用户直接通信,如果不同VLAN要进行通信,则需通过路由器或三层交换机等三层设备。
- 灵活构建虚拟工作组:用VLAN可以划分不同的用户到不同的工作组,同一工作组的用户也不必局限于某个固定的物理范围,网络构建和维护更方便灵活。
1.3 VLAN数据帧格式
目前VLAN协议格式有两种: ISL 和 802.1Q。ISL是思科研发的Dot1Q标准,产生于802.1Q标准之前,只有思科的设备使用。802.1Q是IEEE标准的VLAN协议,也是现在的主流VLAN技术,本文以802.1Q标注介绍VLAN报文格式,如需了解ISL格式,可浏览思科网站相关介绍。
正常的802.3 报文头和带VLAN的报文对比如下:
Packet type | Preamble | Start frame delimiter | Destination MAC address | Source MAC address | dot1q identifier | tag type (4 bits) | vlan ID (12 bits) | packet type field | data | padding | FCS |
---|---|---|---|---|---|---|---|---|---|---|---|
Normal ethernet tcp packet | 10101010 (56 alternating bits) | 10101011 | 00:10:C6:C0:61:CD | 00:13:CE:47:06:86 | not present | not present | not present | 0x800 | |||
VLAN packet | 10101010 (56 alternating bits) | 10101011 | 00:10:C6:C0:61:CD | 00:13:CE:47:06:86 | 0x8100 | QOS bits | VLAN ID | 0x800 |
两种报文的主要差别是VLAN 报文在二层头的MAC地址后面加入了VLAN Tag,其它都是一致的,所以判别是否是VLAN报文,只要判断二层头里TYPE类型是否有TPID(默认0X8100)即可。
传统的以太网数据帧在目的MAC地址和源MAC地址之后封装的是上层协议的类型字段,就是untagged帧,如图1-3-1所示
图1-3-1 以太网帧结构
VLAN数据帧是在类型字段前加上802.1Q的tag,也就是tagged帧,如图1-3-2所示
图3 VLAN数据帧
802.1Q Tag中各字段的含义如下表所示:
字段 | 长度 | 含义 | 取值 |
---|---|---|---|
TPID | 2Byte | Tag Protocol Identifier(标签协议标识符),表示数据帧类型。 | 默认取值为0x8100时表示IEEE 802.1Q的VLAN数据帧。如果不支持802.1Q的设备收到这样的帧,会将其丢弃。 |
PRI | 3bit | Priority,表示数据帧的802.1p优先级。 | 取值范围为0~7,值越大优先级越高。当网络阻塞时,交换机优先发送优先级高的数据帧,主要在Qos的优先级中使用。 |
CFI | 1bit | Canonical Format Indicator(标准格式指示位),表示MAC地址在不同的传输介质中是否以标准格式进行封装,用于兼容以太网和令牌环网。 | CFI取值为0表示MAC地址以标准格式进行封装,为1表示以非标准格式封装。在以太网中,CFI的值为0。 |
VID | 12bit | VLAN ID,表示该数据帧所属VLAN的编号。 | 12bit的VID取值范围是0~4095。由于0和4095为协议保留取值,所以VID的有效取值范围是1~4094。 |
1.4 端口模式类型
根据端口连接对象及对收发数据帧处理的不同,以太网端口分为Access/Trunk/Hybrid三种模式。
-
Access 模式
Access模式仅允许唯一的 VID 通过本端口,即端口的PVID。Access模式一般用于和不能识别tag的用户终端(用户主机、服务器等)相连的端口,或者不需要区分不同VLAN成员时使用。
- ingress:没有tag报文,打上端口pvid;带tag报文,直接丢弃;
- egress: tag=VID,剥离tag发送;tag != VID, 直接丢弃;
-
Trunk 模式
Trunk接口一般用于连接交换机、路由器、AP以及可同时收发Tagged帧和Untagged帧的语音终端。它可以允许多个VLAN的帧带Tag通过,但只允许一个VLAN的帧从该类接口上发出时不带Tag(即剥除Tag)。
- ingress: 没有tag报文,打上端口pvid;带标签tag 匹配vlan id,不匹配的直接丢弃;
- egress:tag=pvid,剥离tag发送;tag 匹配端口的vlan id转发,不匹配的直接丢弃;
-
Hybrid 模式
Hybrid接口既可以用于连接不能识别Tag的用户终端(如用户主机、服务器等)和网络设备(如Hub),也可以用于连接交换机、路由器以及可同时收发Tagged帧和Untagged帧的语音终端、AP。它可以允许多个VLAN的帧带Tag通过,且允许从该类接口发出的帧根据需要配置某些VLAN的帧带Tag(即不剥除Tag)、某些VLAN的帧不带Tag(即剥除Tag)。
假设Hybrid口的配置,tag vlan N/ untag vlan M/ pvid vlan L。
- ingress:没有tag报文,打上端口pvid L,带tag报文匹配vlan N,不匹配的直接丢弃;
- egress:首先先匹配vlan N, 匹配直接转发;不是则匹配vlan M,匹配剥离tag转发;不是则匹配pvid L,匹配剥离tag转发;以上都不匹配直接丢弃;
Hybrid接口和Trunk接口在很多应用场景下可以通用,但在某些应用场景下,必须使用Hybrid接口。比如一个接口连接不同VLAN网段的场景中,因为一个接口需要给多个Untagged报文添加Tag,所以必须使用Hybrid接口。
1.5 Linux 内核的 802.1Q模块
1.5.1 vlan在协议层面是如何工作的
为了支持VLAN功能,创建了一种特别的以太网报文,该报文相比普通以太网报文新增了一个额外的报文头,用于识别vlan报文。对于access端口,switch会在ingress增加该报文头;对于trunk端口,进来的报文会直接带有vlan报文头,如果没有,会默认加上端口的PVID(native vlan)。
基本的以太网报文:
Ethernet/IP/tcp/
trunk/access端口ingress的以太网报文:
Ethernet/VLAN/IP/tcp/
1.5.2 vlan在linux kernel是如何工作的
1.5.2.1 vconfig 工具
通过使用vconfig 工具,你可以创建一个VLAN子端口。如果你配置连接到该端口的switch端口eth1是可用发送带vlan 810 和820的报文,配置如下:
vconfig add eth0 810
vconfig add eth0 820
配置后,“eth0.810” 和 “eth0.820” 两个虚拟端口将被创建,带有相应VLAN的报文将被送到对应的虚拟口处理,就像接到了不同的网络。所以,你需要给他们配上不同的IP地址区别两个端口。
使能不同vlan间的routing功能:
echo 1 > /proc/sys/net/ipv4/ip_forward
通过如下的路由配置,两台设备可以相互通信:
(on the client devices in an access port :)
route add <network on other vlan> netmask <the netmask of the network> gw <the ip of the vlan router on the correct vlan>
1.5.3 kernel的实现
1.5.3.1 收包处理流程
当一个NIC驱动收到一个报文,首先它将为收到的报文创建一个sk_buff 结构体(include/linux/skbuff.h), 然后将该结构体的dev成员指向NIC对应的接口,最后报文将会被送到netif_rx(net/core/dev.c)或者receive_skb(net/core/dev.c)处理。基本的收包处理流程如下:
struct sk_buff * skb;
skb = dev_alloc_skb();
/* fill in some data in the skb */
skb->dev = my interface struct
netif_rx(skb);
当一个端口接受一个带VLAN的报文(如果接口有vlan加速),调用将由vlan_hwaccel_rx替代netif_rx:
vlan_hwaccel_rx(skb, vlan_group, vlan_tag)
缩写
PVID(Port VLAN ID Default)
参考文档
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)