2026-05-24 11:42:38 +08:00
|
|
|
|
---
|
|
|
|
|
|
tags: [计算机网络, VLAN, 802.1Q, Trunk, Access端口]
|
|
|
|
|
|
create time: 2026-05-17 23:30
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
# VLAN 与 Trunk
|
|
|
|
|
|
|
|
|
|
|
|
## 概述
|
|
|
|
|
|
|
|
|
|
|
|
VLAN(Virtual Local Area Network,虚拟局域网)允许在一台物理交换机上创建多个逻辑隔离的广播域。它是现代数据中心和办公网络的基本组织单元。
|
|
|
|
|
|
|
|
|
|
|
|
> [!QUESTION] 为什么需要 VLAN?
|
|
|
|
|
|
> 一台万兆交换机的 MAC 表通常限制在几万条以内,加上广播泛洪带来的开销,单广播域超过 2000 台主机会显著降低性能。VLAN 将大网络划分为多个小广播域,就像在一栋大楼里用防火墙隔出多个独立办公室——同一楼层但互不干扰。
|
|
|
|
|
|
|
|
|
|
|
|
## IEEE 802.1Q Tag 结构
|
|
|
|
|
|
|
|
|
|
|
|
### 不带 VLAN 的 Ethernet II 帧
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌──────────┬──────────┬──────┬─────────────┬──────┐
|
|
|
|
|
|
│ Dest MAC │ Src MAC │Type │ Payload │ FCS │
|
|
|
|
|
|
│ 6 bytes │ 6 bytes │ 2B │ 46-1500 B │ 4 B │
|
|
|
|
|
|
│ │ │0x0800│ │ │
|
|
|
|
|
|
└──────────┴──────────┴──────┴─────────────┴──────┘
|
|
|
|
|
|
←── 14 ──→ ←──MTU──→ ←── 4 ──→
|
|
|
|
|
|
Header Payload Tail
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 带 802.1Q Tag 的帧
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-05-27 23:01:37 +08:00
|
|
|
|
┌──────────┬──────────┬──────┬──────┬──────────┬─────────────┬──────┐
|
|
|
|
|
|
│ Dest MAC │ Src MAC │ TPID │ TCI │Org.EType │ Payload │ FCS │
|
|
|
|
|
|
│ 6 bytes │ 6 bytes │ 2B │ 2B │ 2B │ 46-1500 B │ 4 B │
|
|
|
|
|
|
│ │ │0x8100│ VID │ 0x0800 │ │ │
|
|
|
|
|
|
└──────────┴──────────┴──────┴──────┴──────────┴─────────────┴──────┘
|
|
|
|
|
|
←── 14 ──→ │←4 Tag→│ ←───── 4+MTU ─────→ ←── 4 ──→
|
|
|
|
|
|
↑ 新增 4-byte Tag
|
2026-05-24 11:42:38 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
> [!important] TPID 替换了 EtherType
|
|
|
|
|
|
> TPID(0x8100)**占据**了原帧中 EtherType 的位置,原 EtherType(如 0x0800)被后移到 TCI 之后、Payload 之前。交换机通过识别 TPID=0x8100 来判断这是一帧 802.1Q 标记帧。
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
### TCI (Tag Control Information) 位图
|
|
|
|
|
|
|
|
|
|
|
|
```
|
2026-05-27 23:01:37 +08:00
|
|
|
|
Bit 15-13 Bit 12 Bit 11-0
|
|
|
|
|
|
─────────────────────────────────────────
|
|
|
|
|
|
PCP (优先级) | DEI/CFI | VID (VLAN ID)
|
|
|
|
|
|
(3 bits) | (1 bit) | (12 bits)
|
2026-05-24 11:42:38 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 字段 | 大小 | 取值范围 | 说明 |
|
|
|
|
|
|
|------|------|---------|------|
|
|
|
|
|
|
| PCP | 3 bit | 0–7 | Priority Code Point,QoS 优先级(见下表) |
|
2026-05-27 23:01:37 +08:00
|
|
|
|
| DEI | 1 bit | 0 或 1 | Drop Eligible Indicator,指示该帧在拥塞时可被丢弃。在 802.1Q-2011 前称为 CFI(Canonical Format Indicator),传统以太网固定为 0 |
|
|
|
|
|
|
| VID | 12 bit | 0–4095 | VLAN Identifier,**实际可用 1–4094**(0 仅用于优先级帧,4095 保留) |
|
2026-05-24 11:42:38 +08:00
|
|
|
|
|
|
|
|
|
|
### PCP 优先级对照
|
|
|
|
|
|
|
|
|
|
|
|
| PCP | 用途 | 典型场景 |
|
|
|
|
|
|
|-----|------|---------|
|
|
|
|
|
|
| 1 | Background | 后台低优先级的备份任务 |
|
2026-05-27 23:01:37 +08:00
|
|
|
|
| 0 | Best Effort(默认) | 普通数据流量,**大多数业务的默认值** |
|
|
|
|
|
|
| 2 | Spare | 预留,可用于自定义业务 |
|
|
|
|
|
|
| 3 | Excellent Effort | 关键业务数据(如 ERP、数据库同步) |
|
|
|
|
|
|
| 4 | Video | 视频流(≤100ms 延迟要求) |
|
|
|
|
|
|
| 5 | Voice | 语音通话 VoIP(≤10ms 延迟,**流控标记**) |
|
|
|
|
|
|
| 6 | Internetwork Control | 路由协议等网络控制报文 |
|
|
|
|
|
|
| 7 | Network Control | STP、LLDP 等二层协议,**不能被丢弃** |
|
|
|
|
|
|
|
|
|
|
|
|
> [!question] 为什么 PCP 0(Best Effort)不是最低优先级?
|
|
|
|
|
|
> 这是 IEEE 802.1Q 历史遗留设计。PCP 1 的 "Background" 比默认更"低",用于非紧急的大块传输(如备份),避免抢占默认业务的带宽。实际部署中 PCP 0 和 1 的区别不大,重点应关注 PCP 4–7。
|
2026-05-24 11:42:38 +08:00
|
|
|
|
|
|
|
|
|
|
## VLAN 端口类型
|
|
|
|
|
|
|
|
|
|
|
|
| 端口类型 | Access | Trunk | Hybrid(Huawei/H3C) |
|
|
|
|
|
|
|----------|--------|-------|---------------------|
|
|
|
|
|
|
| 允许 VLAN | 1 个(PVID) | 多个 | 多个(可配置) |
|
|
|
|
|
|
| 入栈标签 | 接收不带标签 → 打上 PVID | 所有到达的帧保持标签 | 根据配置决定 |
|
|
|
|
|
|
| 出栈标签 | 发送时剥离标签 | 发送时保留标签(除 PVID) | 按每 VLAN 配置 |
|
|
|
|
|
|
| 使用场景 | 接 PC/打印机/AP | 交换机互联、接路由器 | 灵活混合 |
|
|
|
|
|
|
|
|
|
|
|
|
### Access 端口示例
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
PC["PC (无标签帧)"] -->|"发裸帧"| A["Access Port<br/>PVID = 10"]
|
|
|
|
|
|
A -->|"打上 Tag 10"| S["Switch 内部 VLAN 10 域"]
|
|
|
|
|
|
S -->|"移除 Tag"| B["Access Port<br/>PVID = 10"]
|
|
|
|
|
|
B -->|"发裸帧"| GW["网关 Router"]
|
|
|
|
|
|
|
|
|
|
|
|
style A fill:#DDA0DD,color:#000
|
|
|
|
|
|
style B fill:#DDA0DD,color:#000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> Access 端口对主机透明——主机看到的仍是普通以太网帧,完全不知道 VLAN 的存在。
|
|
|
|
|
|
|
|
|
|
|
|
### Trunk 端口示例
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
SW1["Switch A"] -->|"Trunk<br/>携带多个 VID"| SW2["Switch B"]
|
|
|
|
|
|
|
|
|
|
|
|
Note over SW1,SW2: VLAN 10 流量: EtherType=0x8100, VID=10<br/>VLAN 20 流量: EtherType=0x8100, VID=20
|
|
|
|
|
|
|
|
|
|
|
|
style SW1 fill:#98FB98,color:#000
|
|
|
|
|
|
style SW2 fill:#98FB98,color:#000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
## Native VLAN(本征 VLAN)
|
|
|
|
|
|
|
|
|
|
|
|
Trunk 端口上有一个特殊概念:**Native VLAN**,默认为 VLAN 1。
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
flowchart LR
|
|
|
|
|
|
UH["不带标签的主机"] -->|"裸帧(无 Tag)"| TR["Trunk 端口"]
|
|
|
|
|
|
TH["带 Tag 的主机"] -->|"Tag 帧(VID=10)"| TR
|
|
|
|
|
|
TR -->|"识别为 Native VLAN"| NV["VLAN 1 域"]
|
|
|
|
|
|
TR -->|"按 VID 转发"| V10["VLAN 10 域"]
|
|
|
|
|
|
|
|
|
|
|
|
style NV fill:#FFD700,color:#000
|
|
|
|
|
|
style V10 fill:#87CEEB,color:#000
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**工作规则:**
|
|
|
|
|
|
- **入方向**:Trunk 端口收到**不带标签的帧**时,自动归入 Native VLAN
|
|
|
|
|
|
- **出方向**:属于 Native VLAN 的帧在发出时**剥离标签**(对端看到的是裸帧)
|
|
|
|
|
|
|
|
|
|
|
|
> [!warning] Native VLAN 必须两端一致
|
|
|
|
|
|
> 如果 Trunk 两端交换机的 Native VLAN 设置不一致(一端是 VLAN 1,另一端是 VLAN 2),会导致:
|
|
|
|
|
|
> 1. 流量被错误转发到非预期 VLAN
|
|
|
|
|
|
> 2. 成为 VLAN Hopping 攻击的入口(见下一节)
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
## Router-on-a-Stick(单臂路由)
|
|
|
|
|
|
|
|
|
|
|
|
当路由器只有一个物理接口时,可以通过子接口 + VLAN 实现多个 VLAN 间路由:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
VLAN 10 VLAN 20
|
|
|
|
|
|
┌──────────┐ ┌──────────┐
|
|
|
|
|
|
│ 192.168.10.x /24 │ │ 192.168.20.x /24 │
|
|
|
|
|
|
└──────┬───┘ └──────┬───┘
|
|
|
|
|
|
│ │
|
|
|
|
|
|
Access Access
|
|
|
|
|
|
│ │
|
|
|
|
|
|
┌──────┴───────────────────┴───┐
|
|
|
|
|
|
│ Switch │
|
|
|
|
|
|
│ Trunk Port (eth0.10 & .20) │
|
|
|
|
|
|
└──────┬───────────────────┬───┘
|
|
|
|
|
|
│ 子接口 eth0.10 │ 子接口 eth0.20
|
|
|
|
|
|
▼ ▼
|
|
|
|
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
|
|
|
|
│ Router │ │ Router │
|
|
|
|
|
|
│ eth0.10: 192.168.10.1/24 │ │ eth0.20: 192.168.20.1/24 │
|
|
|
|
|
|
└─────────────────┘ └─────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
> [!warning] 单臂路由的性能瓶颈
|
|
|
|
|
|
> 所有 VLAN 间的流量都经过同一个物理接口进出(先入后出),相当于**双倍带宽占用**。对于万兆环境,建议使用三层交换机做硬件 VLAN 间路由。
|
|
|
|
|
|
|
|
|
|
|
|
## 配置示例
|
|
|
|
|
|
|
|
|
|
|
|
### Linux Bridge 上的 VLAN
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 创建 vlan interface
|
|
|
|
|
|
ip link add link eth0 name eth0.10 type vlan id 10
|
|
|
|
|
|
ip link add link eth0 name eth0.20 type vlan id 20
|
|
|
|
|
|
|
|
|
|
|
|
# 设置 IP 并启用
|
|
|
|
|
|
ip addr add 192.168.10.1/24 dev eth0.10
|
|
|
|
|
|
ip addr add 192.168.20.1/24 dev eth0.20
|
|
|
|
|
|
ip link set eth0.10 up
|
|
|
|
|
|
ip link set eth0.20 up
|
|
|
|
|
|
|
|
|
|
|
|
# 查看
|
|
|
|
|
|
$ ip -d link show type vlan
|
|
|
|
|
|
4: eth0.10@eth0: <BROADCAST,MULTICAST,UP> mtu 1500 ...
|
|
|
|
|
|
link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff promiscuity 0
|
|
|
|
|
|
vlan protocol 802.1Q id 10 reassemble 0
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Docker 中利用 VLAN
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
> [!warning] Docker bridge 网络 ≠ VLAN
|
|
|
|
|
|
> `docker network create --driver bridge` 创建的是**隔离的 Linux 网桥**,不会在帧上打 802.1Q Tag。它在逻辑上类似"独立广播域",但不是真正的 VLAN。
|
|
|
|
|
|
> 要让容器接入真实 VLAN,需使用 `macvlan` 或 `ipvlan` 驱动:
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
```yaml
|
2026-05-27 23:01:37 +08:00
|
|
|
|
# docker-compose.yml — 容器直接接入物理 VLAN
|
2026-05-24 11:42:38 +08:00
|
|
|
|
services:
|
2026-05-27 23:01:37 +08:00
|
|
|
|
web-vlan10:
|
|
|
|
|
|
image: nginx
|
2026-05-24 11:42:38 +08:00
|
|
|
|
networks:
|
2026-05-27 23:01:37 +08:00
|
|
|
|
office_net:
|
2026-05-24 11:42:38 +08:00
|
|
|
|
ipv4_address: 192.168.10.10
|
2026-05-27 23:01:37 +08:00
|
|
|
|
|
|
|
|
|
|
app-vlan20:
|
|
|
|
|
|
image: app:latest
|
|
|
|
|
|
networks:
|
|
|
|
|
|
server_net:
|
2026-05-24 11:42:38 +08:00
|
|
|
|
ipv4_address: 192.168.20.10
|
|
|
|
|
|
|
|
|
|
|
|
networks:
|
2026-05-27 23:01:37 +08:00
|
|
|
|
office_net:
|
|
|
|
|
|
driver: macvlan
|
|
|
|
|
|
driver_opts:
|
|
|
|
|
|
parent: eth0.10 # 宿主机 VLAN 子接口
|
2026-05-24 11:42:38 +08:00
|
|
|
|
ipam:
|
|
|
|
|
|
config:
|
|
|
|
|
|
- subnet: 192.168.10.0/24
|
2026-05-27 23:01:37 +08:00
|
|
|
|
gateway: 192.168.10.1
|
|
|
|
|
|
server_net:
|
|
|
|
|
|
driver: macvlan
|
|
|
|
|
|
driver_opts:
|
|
|
|
|
|
parent: eth0.20
|
2026-05-24 11:42:38 +08:00
|
|
|
|
ipam:
|
|
|
|
|
|
config:
|
|
|
|
|
|
- subnet: 192.168.20.0/24
|
2026-05-27 23:01:37 +08:00
|
|
|
|
gateway: 192.168.20.1
|
2026-05-24 11:42:38 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
容器通过 macvlan 驱动直接收发带 802.1Q 标签的帧,与物理网络中的 VLAN 设备无缝互通。
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
## VLAN 边界与跨 Switch
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant SW1 as Switch-A
|
|
|
|
|
|
participant Link as 交换机间链路
|
|
|
|
|
|
participant SW2 as Switch-B
|
|
|
|
|
|
|
|
|
|
|
|
SW1->>Link: Frame {EtherType:0x8100, VID:10}
|
|
|
|
|
|
Note over Link: Trunk 链路保持 802.1Q Tag
|
|
|
|
|
|
SW2->>SW2: 收到 → 识别 VID=10 → 在 VLAN 10 内转发
|
|
|
|
|
|
SW2->>SW2: 查 MAC 表 → 仅从同 VLAN 端口发出
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**核心要点:** VLAN 信息随 802.1Q Tag 穿过 Trunk 链路传递到下一台交换机。每台交换机根据自己的 VLAN 数据库独立处理。
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
## VLAN Hopping 攻击与防御
|
|
|
|
|
|
|
|
|
|
|
|
VLAN Hopping 是通过协议漏洞非法访问其他 VLAN 的二层攻击,主要有两种方式:
|
|
|
|
|
|
|
|
|
|
|
|
### 攻击一:Double Tagging(双标签攻击)
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
|
participant A as 攻击者 (VLAN 10)
|
|
|
|
|
|
participant S as Switch
|
|
|
|
|
|
participant V as VLAN 20 目标主机
|
|
|
|
|
|
|
|
|
|
|
|
A->>S: 外层 Tag VID=1 (Native VLAN)<br/>内层 Tag VID=20 (目标 VLAN)
|
|
|
|
|
|
S->>S: 剥离外层 Tag (Native VLAN=1)
|
|
|
|
|
|
S->>V: 帧到达 VLAN 20!(内层 Tag 未被检查)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**原理**:攻击者发送双标签帧,外层使用 Native VLAN ID。Switch 剥离外层 Tag 后,内层 Tag 暴露,帧被转发到目标 VLAN。此攻击**单向**,且需要攻击者在 Native VLAN 中。
|
|
|
|
|
|
|
|
|
|
|
|
> [!important] 防御:将 Native VLAN 设为未使用的 VLAN(如 VLAN 999),并确认所有 Trunk 端口都显式允许所需的 VLAN(不要用 `allowed vlan all`)
|
|
|
|
|
|
|
|
|
|
|
|
### 攻击二:DTP 欺骗
|
|
|
|
|
|
|
|
|
|
|
|
若端口启用了 DTP(Dynamic Trunking Protocol),攻击者可伪装成交换机,诱使端口切换为 Trunk 模式,从而访问所有 VLAN。
|
|
|
|
|
|
|
|
|
|
|
|
**防御**:在所有接入端口上关闭 DTP 自动协商:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Cisco: 关闭 DTP
|
|
|
|
|
|
switchport nonegotiate
|
|
|
|
|
|
# Huawei: 关闭自动协商
|
|
|
|
|
|
undo negotiation auto
|
|
|
|
|
|
```
|
|
|
|
|
|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
## 最佳实践
|
|
|
|
|
|
|
|
|
|
|
|
| 项目 | 建议 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| VLAN ID 分配 | 管理 VLAN=1(不建议,安全风险),业务 VLAN ≥ 10 |
|
|
|
|
|
|
| Native VLAN | 修改默认 native VLAN(避免用 1),防 VLAN Hopping |
|
|
|
|
|
|
| VLAN 数量 | 单台交换机支持最大 4094 个 VLAN |
|
|
|
|
|
|
| Inter-VLAN 路由 | >10 个 VLAN 用三层交换机而非单臂路由 |
|
2026-05-27 23:01:37 +08:00
|
|
|
|
| 安全 | 未使用的端口划入"黑洞 VLAN"(无 IP 段),**关闭 DTP**(Dynamic Trunking Protocol,Cisco 私有自动协商协议)|
|
2026-05-24 11:42:38 +08:00
|
|
|
|
|
|
|
|
|
|
## 关联笔记
|
|
|
|
|
|
|
2026-05-27 23:01:37 +08:00
|
|
|
|
- [[hhs/NETWORK/02-链路层/01-Ethernet帧结构]] — 802.1Q Tag 的 TPID 替换了原始帧的 EtherType 位置
|
|
|
|
|
|
- [[hhs/NETWORK/02-链路层/04-Switch与路由器]] — Switch 如何基于 VLAN 隔离广播域
|
|
|
|
|
|
- [[hhs/NETWORK/02-链路层/03-MAC地址与广播域]] — VLAN 缩小了广播域的规模
|