Files
cs-note/hhs/NETWORK/02-链路层/05-VLAN与Trunk.md
T
2026-05-27 23:01:37 +08:00

290 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 的帧
```
┌──────────┬──────────┬──────┬──────┬──────────┬─────────────┬──────┐
│ 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
```
> [!important] TPID 替换了 EtherType
> TPID(0x8100)**占据**了原帧中 EtherType 的位置,原 EtherType(如 0x0800)被后移到 TCI 之后、Payload 之前。交换机通过识别 TPID=0x8100 来判断这是一帧 802.1Q 标记帧。
### TCI (Tag Control Information) 位图
```
Bit 15-13 Bit 12 Bit 11-0
─────────────────────────────────────────
PCP (优先级) | DEI/CFI | VID (VLAN ID)
(3 bits) | (1 bit) | (12 bits)
```
| 字段 | 大小 | 取值范围 | 说明 |
|------|------|---------|------|
| PCP | 3 bit | 0–7 | Priority Code Point,QoS 优先级(见下表) |
| 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 保留) |
### PCP 优先级对照
| PCP | 用途 | 典型场景 |
|-----|------|---------|
| 1 | Background | 后台低优先级的备份任务 |
| 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。
## 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
```
## 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 攻击的入口(见下一节)
## 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
> [!warning] Docker bridge 网络 ≠ VLAN
> `docker network create --driver bridge` 创建的是**隔离的 Linux 网桥**,不会在帧上打 802.1Q Tag。它在逻辑上类似"独立广播域",但不是真正的 VLAN。
> 要让容器接入真实 VLAN,需使用 `macvlan` 或 `ipvlan` 驱动:
```yaml
# docker-compose.yml — 容器直接接入物理 VLAN
services:
web-vlan10:
image: nginx
networks:
office_net:
ipv4_address: 192.168.10.10
app-vlan20:
image: app:latest
networks:
server_net:
ipv4_address: 192.168.20.10
networks:
office_net:
driver: macvlan
driver_opts:
parent: eth0.10 # 宿主机 VLAN 子接口
ipam:
config:
- subnet: 192.168.10.0/24
gateway: 192.168.10.1
server_net:
driver: macvlan
driver_opts:
parent: eth0.20
ipam:
config:
- subnet: 192.168.20.0/24
gateway: 192.168.20.1
```
容器通过 macvlan 驱动直接收发带 802.1Q 标签的帧,与物理网络中的 VLAN 设备无缝互通。
## 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 数据库独立处理。
## 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
```
## 最佳实践
| 项目 | 建议 |
|------|------|
| VLAN ID 分配 | 管理 VLAN=1(不建议,安全风险),业务 VLAN ≥ 10 |
| Native VLAN | 修改默认 native VLAN(避免用 1),防 VLAN Hopping |
| VLAN 数量 | 单台交换机支持最大 4094 个 VLAN |
| Inter-VLAN 路由 | >10 个 VLAN 用三层交换机而非单臂路由 |
| 安全 | 未使用的端口划入"黑洞 VLAN"(无 IP 段),**关闭 DTP**(Dynamic Trunking Protocol,Cisco 私有自动协商协议)|
## 关联笔记
- [[hhs/NETWORK/02-链路层/01-Ethernet帧结构]] — 802.1Q Tag 的 TPID 替换了原始帧的 EtherType 位置
- [[hhs/NETWORK/02-链路层/04-Switch与路由器]] — Switch 如何基于 VLAN 隔离广播域
- [[hhs/NETWORK/02-链路层/03-MAC地址与广播域]] — VLAN 缩小了广播域的规模