本文深入讲解VLAN过滤失败处理、描述符差异、数据比对验证、多通道分配、优先级配置以及VLAN与组播广播的关系,所有内容基于官方Databook。
一、VLAN过滤失败的完整处理机制
1.1 过滤失败后的处理流程
当VLAN过滤失败时,DWC_ether_qos MAC提供多种处理方式:
VLAN过滤失败处理流程:
VLAN过滤
↓
┌──────────┴──────────┐
│ │
过滤通过 过滤失败
│ │
↓ ↓
基于优先级路由 检查RA和VTFE位
(PSRQ映射) │
┌─────┴─────┐
│ │
RA=0/VTFE=1 RA=1/VTFE=0
│ │
↓ ↓
丢弃帧 检查VFFQE位
│
┌────┴────┐
│ │
VFFQE=0 VFFQE=1
│ │
↓ ↓
PSRQ路由 VFFQ路由
1.2 寄存器配置详解
1.2.1 MAC_Packet_Filter寄存器
Bit 31: RA (Receive All)
0 = 仅接收过滤通过的帧
1 = 接收所有帧(包括过滤失败的帧)
Bit 16: VTFE (VLAN Tag Filter Enable)
0 = 禁用VLAN过滤
1 = 启用VLAN过滤
1.2.2 MAC_RxQ_Ctrl4寄存器
Bit 17: VFFQE (VLAN Filter Fail Queue Enable)
0 = 过滤失败帧使用PSRQ路由
1 = 过滤失败帧路由到VFFQ队列
Bit 16-19: VFFQ (VLAN Filter Fail Queue)
指定VLAN过滤失败帧的目标队列编号(0-7)
1.3 完整的路由表
1.3.1 单播Tagged帧的路由表
| SA/DA过滤 | VLAN过滤 | RA | VTFE | 过滤结果 | VFFQE | 队列路由 | 说明 |
|---|---|---|---|---|---|---|---|
| PASS | PASS | X | X | X | PSRQ | 基于优先级路由 | 正常处理 |
| PASS | FAIL | 0 | 0 | 0 | PSRQ | 基于优先级路由 | VTFE=0,不过滤 |
| PASS | FAIL | 0 | 0 | 1 | VFFQ | 路由到VFFQ | 特殊队列处理 |
| FAIL | X | 0 | X | X | DROPPED | 丢弃 | SA/DA过滤失败 |
| PASS | FAIL | 0 | 1 | X | DROPPED | 丢弃 | VLAN过滤失败 |
| FAIL | X | 1 | X | 0 | UFFQ/PSRQ | SA失败队列 | RA=1接收所有 |
| FAIL | X | 1 | X | 1 | UFFQ/VFFQ | 失败队列 | 使用失败队列 |
| PASS | FAIL | 1 | X | 0 | PSRQ | 基于优先级路由 | RA=1接收所有 |
| PASS | FAIL | 1 | X | 1 | VFFQ | 路由到VFFQ | VLAN失败队列 |
注:X表示任意值,UFFQ为Unicast Filter Fail Queue
1.4 配置示例
场景1:监控所有VLAN流量
c
void monitor_all_vlan_traffic() {
// 1. 启用VLAN过滤
MAC_Packet_Filter.VTFE = 1;
// 2. 接收所有帧(包括过滤失败的)
MAC_Packet_Filter.RA = 1;
// 3. 配置VLAN过滤表(仅允许VLAN 10)
config_vlan_filter_table(10);
// 4. 启用VLAN过滤失败队列
MAC_RxQ_Ctrl4.VFFQE = 1;
MAC_RxQ_Ctrl4.VFFQ = 7; // 失败帧路由到队列7
// 结果:
// - VLAN 10的帧 → 队列0-6(基于优先级)
// - 其他VLAN的帧 → 队列7(监控队列)
}
场景2:严格VLAN过滤
c
void strict_vlan_filtering() {
// 1. 启用VLAN过滤
MAC_Packet_Filter.VTFE = 1;
// 2. 不接收过滤失败的帧
MAC_Packet_Filter.RA = 0;
// 3. 配置允许的VLAN
config_vlan_filter_table(10, 20, 30);
// 结果:
// - VLAN 10/20/30的帧 → 正常接收
// - 其他VLAN的帧 → 丢弃
}
二、VLAN操作后的IP状态和描述符差异
2.1 发送路径(Tx)描述符
2.1.1 Context描述符结构
+-------------------+-------------------+-------------------+
| TSO Context | VLAN Context | SA Context |
+-------------------+-------------------+-------------------+
VLAN Context描述符字段:
Bit 31: OWN - 描述符所有权
0 = 软件所有
1 = 硬件所有
Bit 30: CTXT - Context类型
1 = Context描述符
Bit 29: OWNRS - Owner Request
请求所有权转移
Bit 28: Reserved
Bit 27-16: Reserved
Bit 15: VLTI - VLAN Tag Insert
0 = 从寄存器获取VLAN标签
1 = 从控制字获取VLAN标签
Bit 14-13: Reserved
Bit 12-0: VLAN Tag - 13位VLAN标签值
[12-10]: Priority (PCP)
[9]: CFI/DEI
[8-0]: VID (低9位)
2.1.2 Normal描述符结构
+-------------------+-------------------+-------------------+
| Buffer Address | Buffer Length | Control Bits |
+-------------------+-------------------+-------------------+
Normal描述符字段:
Bit 31: OWN - 描述符所有权
Bit 30: LD - Last Descriptor
1 = 帧的最后一个描述符
Bit 29: FD - First Descriptor
1 = 帧的第一个描述符
Bit 28-24: Reserved
Bit 23-0: Buffer1 Length - 缓冲区长度
2.2 接收路径(Rx)描述符
2.2.1 Write-back描述符结构
+-------------------+-------------------+-------------------+
| Status Word 0 | Status Word 1 | Status Word 2 |
+-------------------+-------------------+-------------------+
Status Word 0:
Bit 31: OWN - 描述符所有权
0 = 软件所有(DMA已写回)
1 = 硬件所有
Bit 30: CTXT - Context类型
0 = Normal描述符
Bit 29: LD - Last Descriptor
Bit 28: FD - First Descriptor
Status Word 1:
Bit 15: DE - Descriptor End
Bit 14-0: Frame Length - 帧长度
Status Word 2 (VLAN信息):
Bit 31-16: Outer VLAN Tag - 外层VLAN标签
[31-29]: Priority
[28]: CFI/DEI
[27-16]: VID
Bit 15-0: Inner VLAN Tag - 内层VLAN标签
[15-13]: Priority
[12]: CFI/DEI
[11-0]: VID
2.3 VLAN操作后的状态变化
2.3.1 插入VLAN标签
发送前:
帧结构:
[DA][SA][Type][Payload][FCS]
发送后(插入VLAN):
帧结构:
[DA][SA][TPID][TCI][Type][Payload][FCS]
描述符状态:
- Tx Context描述符:VLTI=0, VLAN Tag=配置值
- Tx Normal描述符:正常数据
- Rx Write-back描述符:包含插入的VLAN标签
2.3.2 替换VLAN标签
发送前:
帧结构:
[DA][SA][0x8100][Old_TCI][Type][Payload][FCS]
发送后(替换VLAN):
帧结构:
[DA][SA][0x8100][New_TCI][Type][Payload][FCS]
描述符状态:
- Tx Context描述符:VLC=11(替换), VLAN Tag=新值
- Rx Write-back描述符:包含新的VLAN标签
2.3.3 剥离VLAN标签
接收前:
帧结构:
[DA][SA][0x8100][TCI][Type][Payload][FCS]
接收后(剥离VLAN):
帧结构:
[DA][SA][Type][Payload][FCS]
描述符状态:
- Rx Write-back描述符:
* Status Word 2包含原始VLAN标签
* Frame Length减少4字节
* DE位指示描述符结束
2.4 IP状态检查
2.4.1 IP校验和影响
重要:VLAN标签的插入/删除/替换会影响IP校验和!
处理方式:
-
硬件自动计算:
- MAC可以自动重新计算IP校验和
- 配置:
MAC_Config.CPS = 1(Checksum Offload)
-
软件手动计算:
- 在VLAN操作后重新计算IP校验和
- 适用于不支持硬件offload的情况
2.4.2 IP状态字段
c
typedef struct {
uint32_t ip_checksum; // IP校验和
uint16_t ip_length; // IP总长度
uint8_t ip_ttl; // TTL
uint8_t ip_protocol; // 协议类型
uint32_t src_ip; // 源IP
uint32_t dst_ip; // 目的IP
} ip_state_t;
void check_ip_state_after_vlan(ip_state_t *ip) {
// VLAN操作后,IP长度不变
// 但校验和可能需要重新计算
if(vlan_operation == INSERT || vlan_operation == DELETE) {
// 帧长度变化,但IP长度不变
// IP校验和不变
}
if(vlan_operation == REPLACE) {
// 帧长度不变
// IP校验和不变
}
}
三、VLAN数据比对和验证方法
3.1 发送端验证
3.1.1 构造期望帧
systemverilog
class expected_frame;
bit [47:0] da;
bit [47:0] sa;
bit [15:0] tpid;
bit [15:0] tci;
bit [15:0] ether_type;
byte payload[];
// 构造期望的VLAN帧
function void construct_expected_vlan_frame(
input bit [47:0] exp_da,
input bit [47:0] exp_sa,
input bit [15:0] exp_vid,
input bit [2:0] exp_priority,
input byte exp_payload[]
);
da = exp_da;
sa = exp_sa;
tpid = 16'h8100;
tci = (exp_priority << 13) | exp_vid;
ether_type = 16'h0800; // IPv4
payload = exp_payload;
endfunction
endclass
3.1.2 比对逻辑
systemverilog
class vlan_checker;
// 比对发送的帧
function bit compare_tx_frame(
input svt_ethernet_transaction actual,
input expected_frame expected
);
bit match = 1;
// 比对MAC地址
if(actual.address != expected.da) begin
`uvm_error("VLAN_CHECK", $sformatf(
"DA mismatch: actual=%h, expected=%h",
actual.address, expected.da))
match = 0;
end
if(actual.source != expected.sa) begin
`uvm_error("VLAN_CHECK", $sformatf(
"SA mismatch: actual=%h, expected=%h",
actual.source, expected.sa))
match = 0;
end
// 比对VLAN标签
if(actual.vlan_tpid != expected.tpid) begin
`uvm_error("VLAN_CHECK", $sformatf(
"TPID mismatch: actual=%h, expected=%h",
actual.vlan_tpid, expected.tpid))
match = 0;
end
if(actual.vlan_tci != expected.tci) begin
`uvm_error("VLAN_CHECK", $sformatf(
"TCI mismatch: actual=%h, expected=%h",
actual.vlan_tci, expected.tci))
match = 0;
end
// 比对载荷
if(actual.payload.size() != expected.payload.size()) begin
`uvm_error("VLAN_CHECK", "Payload length mismatch")
match = 0;
end
else begin
foreach(actual.payload[i]) begin
if(actual.payload[i] != expected.payload[i]) begin
`uvm_error("VLAN_CHECK", $sformatf(
"Payload mismatch at byte %0d", i))
match = 0;
end
end
end
return match;
endfunction
endclass
3.2 接收端验证
3.2.1 描述符检查
systemverilog
class rx_descriptor_checker;
// 检查Rx描述符中的VLAN信息
function void check_rx_descriptor_vlan(
input rx_descriptor_t desc,
input bit [15:0] exp_vlan_tag
);
// 检查描述符类型
if(desc.CTXT != 0) begin
`uvm_error("DESC_CHECK", "Not a normal descriptor")
end
// 检查VLAN标签
if(desc.outer_vlan_tag != exp_vlan_tag) begin
`uvm_error("VLAN_CHECK", $sformatf(
"VLAN tag mismatch: actual=%h, expected=%h",
desc.outer_vlan_tag, exp_vlan_tag))
end
// 检查帧长度(考虑VLAN剥离)
if(vlan_stripped) begin
uint32_t expected_length = original_length - 4;
if(desc.frame_length != expected_length) begin
`uvm_error("VLAN_CHECK", $sformatf(
"Frame length mismatch: actual=%0d, expected=%0d",
desc.frame_length, expected_length))
end
end
endfunction
endclass
3.2.2 完整的验证流程
systemverilog
class vlan_verification_sequence extends uvm_sequence;
`uvm_object_utils(vlan_verification_sequence)
task body();
svt_ethernet_transaction tx_frame, rx_frame;
expected_frame exp_frame;
vlan_checker checker;
rx_descriptor_checker desc_checker;
// 1. 构造并发送帧
tx_frame = construct_test_frame();
send_frame(tx_frame);
// 2. 构造期望帧
exp_frame = new();
exp_frame.construct_expected_vlan_frame(
tx_frame.address,
tx_frame.source,
tx_frame.vlan_id,
tx_frame.vlan_priority,
tx_frame.payload
);
// 3. 接收帧
receive_frame(rx_frame);
// 4. 比对帧内容
if(!checker.compare_tx_frame(rx_frame, exp_frame)) begin
`uvm_error("VLAN_VERIFY", "Frame verification failed")
end
// 5. 检查描述符
desc_checker.check_rx_descriptor_vlan(
rx_frame.descriptor,
exp_frame.tci
);
`uvm_info("VLAN_VERIFY", "VLAN verification passed", UVM_LOW)
endtask
endclass
3.3 比对检查点
3.3.1 VLAN插入验证
| 检查项 | 期望值 | 验证方法 |
|---|---|---|
| TPID | 0x8100/0x88A8 | 比对帧的第13-14字节 |
| TCI | 配置值 | 比对帧的第15-16字节 |
| 帧长度 | 原长度+4 | 比对描述符中的长度 |
| FCS | 重新计算 | 比对帧的最后4字节 |
| 描述符VLAN | 配置值 | 比对Status Word 2 |
3.3.2 VLAN剥离验证
| 检查项 | 期望值 | 验证方法 |
|---|---|---|
| 帧结构 | 无VLAN标签 | 检查第13-14字节是否为Type |
| 帧长度 | 原长度-4 | 比对描述符中的长度 |
| 描述符VLAN | 原始VLAN | 比对Status Word 2 |
| FCS | 重新计算 | 比对帧的最后4字节 |
3.3.3 VLAN替换验证
| 检查项 | 期望值 | 验证方法 |
|---|---|---|
| TPID | 不变 | 比对帧的第13-14字节 |
| TCI | 新配置值 | 比对帧的第15-16字节 |
| 帧长度 | 不变 | 比对描述符中的长度 |
| FCS | 重新计算 | 比对帧的最后4字节 |
四、多通道VLAN分配
4.1 多通道架构
DWC_ether_qos支持多个DMA通道,每个通道可以独立配置VLAN处理:
┌─────────────┐
│ DMA │
│ Controller │
└──────┬──────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ Channel │ │ Channel │ │ Channel │
│ 0 │ │ 1 │ │ N │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐
│ Queue │ │ Queue │ │ Queue │
│ 0-7 │ │ 0-7 │ │ 0-7 │
└─────────┘ └─────────┘ └─────────┘
4.2 通道VLAN配置
4.2.1 寄存器映射
每个通道有独立的VLAN配置寄存器:
Channel 0:
- MAC_CH0_VLAN_Tag
- MAC_CH0_VLAN_Incl
Channel 1:
- MAC_CH1_VLAN_Tag
- MAC_CH1_VLAN_Incl
...
Channel N:
- MAC_CHN_VLAN_Tag
- MAC_CHN_VLAN_Incl
4.2.2 配置示例
c
void config_multi_channel_vlan() {
// Channel 0: VLAN 10 (研发部)
MAC_CH0_VLAN_Tag = (5 << 13) | 10;
MAC_CH0_VLAN_Incl = (0x8100 << 16) | (0 << 15) | (2 << 13);
// Channel 1: VLAN 20 (市场部)
MAC_CH1_VLAN_Tag = (6 << 13) | 20;
MAC_CH1_VLAN_Incl = (0x8100 << 16) | (0 << 15) | (2 << 13);
// Channel 2: VLAN 30 (财务部)
MAC_CH2_VLAN_Tag = (7 << 13) | 30;
MAC_CH2_VLAN_Incl = (0x8100 << 16) | (0 << 15) | (2 << 13);
}
4.3 队列到通道的映射
4.3.1 映射规则
Queue 0-1 → Channel 0 (VLAN 10)
Queue 2-3 → Channel 1 (VLAN 20)
Queue 4-5 → Channel 2 (VLAN 30)
Queue 6-7 → Channel 3 (VLAN 40)
4.3.2 配置方法
c
void config_queue_channel_mapping() {
// 配置队列到通道的映射
DMA_CH_Rx_Q_Map[0] = 0x00; // Queue 0 → Channel 0
DMA_CH_Rx_Q_Map[1] = 0x00; // Queue 1 → Channel 0
DMA_CH_Rx_Q_Map[2] = 0x01; // Queue 2 → Channel 1
DMA_CH_Rx_Q_Map[3] = 0x01; // Queue 3 → Channel 1
DMA_CH_Rx_Q_Map[4] = 0x02; // Queue 4 → Channel 2
DMA_CH_Rx_Q_Map[5] = 0x02; // Queue 5 → Channel 2
DMA_CH_Rx_Q_Map[6] = 0x03; // Queue 6 → Channel 3
DMA_CH_Rx_Q_Map[7] = 0x03; // Queue 7 → Channel 3
}
4.4 应用场景
场景:多租户数据中心
租户A (Channel 0):
- Queue 0-1: 数据流量 (VLAN 100)
- Queue 2-3: 管理流量 (VLAN 101)
租户B (Channel 1):
- Queue 0-1: 数据流量 (VLAN 200)
- Queue 2-3: 管理流量 (VLAN 201)
租户C (Channel 2):
- Queue 0-1: 数据流量 (VLAN 300)
- Queue 2-3: 管理流量 (VLAN 301)
五、VLAN优先级配置详解
5.1 优先级到队列的映射
5.1.1 PSRQ字段配置
MAC_RxQ_Ctrl2寄存器:
Bit 0-7: PSRQ0 - Priority 0映射的队列
Bit 8-15: PSRQ1 - Priority 1映射的队列
Bit 16-23: PSRQ2 - Priority 2映射的队列
Bit 24-31: PSRQ3 - Priority 3映射的队列
MAC_RxQ_Ctrl3寄存器:
Bit 0-7: PSRQ4 - Priority 4映射的队列
Bit 8-15: PSRQ5 - Priority 5映射的队列
Bit 16-23: PSRQ6 - Priority 6映射的队列
Bit 24-31: PSRQ7 - Priority 7映射的队列
5.1.2 标准QoS映射
c
void config_standard_qos_mapping() {
// IEEE 802.1Q推荐的优先级映射
// Priority 0: Best Effort (尽力而为)
// Priority 1: Background (后台)
// Priority 2: Spare (保留)
// Priority 3: Excellent Effort (优秀尽力)
// Priority 4: Controlled Load (受控负载)
// Priority 5: Video (视频)
// Priority 6: Voice (语音)
// Priority 7: Network Control (网络控制)
MAC_RxQ_Ctrl2 = 0x00000000; // Priority 0-3 → Queue 0
MAC_RxQ_Ctrl3 = 0x01010101; // Priority 4-7 → Queue 1
}
5.1.3 自定义映射示例
c
void config_custom_priority_mapping() {
// 8个优先级映射到4个队列
MAC_RxQ_Ctrl2 = 0x00010000; // P0→Q0, P1→Q0, P2→Q0, P3→Q1
MAC_RxQ_Ctrl3 = 0x03020202; // P4→Q2, P5→Q2, P6→Q2, P7→Q3
}
5.2 优先级调度
5.2.1 严格优先级调度
c
void config_strict_priority_scheduling() {
// 配置队列优先级
DMA_Rx_Q_Ctrl[0].PR = 0; // Queue 0: 最低优先级
DMA_Rx_Q_Ctrl[1].PR = 1;
DMA_Rx_Q_Ctrl[2].PR = 2;
DMA_Rx_Q_Ctrl[3].PR = 3; // Queue 3: 最高优先级
// 启用严格优先级调度
DMA_Rx_Ctrl_Mode.SP = 1;
}
5.2.2 加权轮询调度
c
void config_weighted_round_robin() {
// 配置队列权重
DMA_Rx_Q_Ctrl[0].Weight = 1; // Queue 0: 权重1
DMA_Rx_Q_Ctrl[1].Weight = 2; // Queue 1: 权重2
DMA_Rx_Q_Ctrl[2].Weight = 4; // Queue 2: 权重4
DMA_Rx_Q_Ctrl[3].Weight = 8; // Queue 3: 权重8
// 启用WRR调度
DMA_Rx_Ctrl_Mode.WRR = 1;
}
5.3 优先级重写
5.3.1 接收端优先级重写
c
void config_rx_priority_rewrite() {
// 启用优先级重写
MAC_VLAN_Tag.EPR = 1; // Enable Priority Rewrite
// 配置优先级重写表
MAC_Priority_Rewrite[0] = 1; // Priority 0 → 1
MAC_Priority_Rewrite[1] = 1; // Priority 1 → 1
MAC_Priority_Rewrite[2] = 2; // Priority 2 → 2
MAC_Priority_Rewrite[3] = 2; // Priority 3 → 2
MAC_Priority_Rewrite[4] = 3; // Priority 4 → 3
MAC_Priority_Rewrite[5] = 3; // Priority 5 → 3
MAC_Priority_Rewrite[6] = 4; // Priority 6 → 4
MAC_Priority_Rewrite[7] = 4; // Priority 7 → 4
}
六、VLAN与组播、广播的关系
6.1 组播地址与VLAN
6.1.1 组播MAC地址格式
组播MAC地址格式:01:00:5E:XX:XX:XX
特点:
- 第一个字节的最低位为1(组播标识)
- 前24位为
01:00:5E(IANA分配) - 后24位映射IP组播地址
6.1.2 VLAN组播处理
规则:
- 组播帧可以携带VLAN标签
- 组播帧的VLAN过滤与单播相同
- 组播帧可以路由到多个队列
配置示例:
c
void config_vlan_multicast() {
// 启用组播过滤
MAC_Packet_Filter.HPF = 1; // Hash Perfect Filtering
// 添加组播地址到过滤表
// 组播组: 01:00:5E:00:00:01, VLAN 10
add_multicast_entry(0x01005E000001, 10);
// 组播组: 01:00:5E:00:00:02, VLAN 20
add_multicast_entry(0x01005E000002, 20);
}
6.2 广播地址与VLAN
6.2.1 广播MAC地址
广播MAC地址:FF:FF:FF:FF:FF:FF
特点:
- 所有位为1
- 发送给同一VLAN内的所有设备
- 受VLAN隔离限制
6.2.2 VLAN广播处理
规则:
- 广播帧仅在同一个VLAN内传播
- 不同VLAN的广播域相互隔离
- 广播帧可以携带VLAN标签
配置示例:
c
void config_vlan_broadcast() {
// 启用广播过滤
MAC_Packet_Filter.RA = 1; // Receive All
// 配置广播队列
MAC_RxQ_Ctrl0.BQ = 7; // Broadcast Queue = 7
// 广播帧路由到队列7
// 无论VLAN ID如何,所有广播帧都路由到队列7
}
6.3 广播/组播包复制
6.3.1 功能描述
DWC_ether_qos支持广播/组播包复制功能,可以将一个包复制到多个队列。
6.3.2 配置方法
c
void config_broadcast_duplication() {
// 启用广播包复制
MAC_RxQ_Ctrl0.BDC = 1; // Broadcast Duplication Control
// 配置复制目标队列
MAC_RxQ_Ctrl0.BDQ = 0x8F; // 复制到Queue 0, 1, 2, 3, 7
// 结果:
// 广播帧会被复制到Queue 0, 1, 2, 3, 7
// 每个队列收到一份拷贝
}
6.4 VLAN与组播/广播的隔离
6.4.1 VLAN隔离原理
VLAN 10:
- 单播: 仅VLAN 10内的设备可见
- 组播: 仅VLAN 10内的组成员可见
- 广播: 仅VLAN 10内的设备可见
VLAN 20:
- 单播: 仅VLAN 20内的设备可见
- 组播: 仅VLAN 20内的组成员可见
- 广播: 仅VLAN 20内的设备可见
VLAN 10和VLAN 20完全隔离
6.4.2 跨VLAN组播
场景:某些组播组需要跨VLAN传播
解决方案:
- 使用VLAN标签剥离/插入:
c
// 接收时剥离VLAN标签
MAC_VLAN_Tag.EVLS = 1;
// 发送时插入新的VLAN标签
MAC_VLAN_Incl.VLC = 2; // 插入
- 使用路由器 :
- 三层路由器处理跨VLAN组播
- IGMP Snooping管理组播组
6.5 组播/组播过滤与VLAN
6.5.1 组播VLAN过滤表
c
typedef struct {
bit [47:0] mac_address; // 组播MAC地址
bit [11:0] vlan_id; // VLAN ID
bit valid; // 有效位
bit [2:0] queue; // 目标队列
} multicast_vlan_entry_t;
void config_multicast_vlan_filter() {
multicast_vlan_entry_t entries[4];
// 组播组1: 01:00:5E:00:00:01, VLAN 10 → Queue 0
entries[0] = '{0x01005E000001, 10, 1, 0};
// 组播组2: 01:00:5E:00:00:02, VLAN 10 → Queue 1
entries[1] = '{0x01005E000002, 10, 1, 1};
// 组播组3: 01:00:5E:00:00:01, VLAN 20 → Queue 2
entries[2] = '{0x01005E000001, 20, 1, 2};
// 组播组4: 01:00:5E:00:00:02, VLAN 20 → Queue 3
entries[3] = '{0x01005E000002, 20, 1, 3};
// 写入过滤表
for(int i = 0; i < 4; i++) {
write_multicast_table(i, entries[i]);
}
}
七、完整验证示例
7.1 综合测试场景
systemverilog
class comprehensive_vlan_test extends uvm_test;
`uvm_component_utils(comprehensive_vlan_test)
task run_phase(uvm_phase phase);
phase.raise_objection(this);
// 测试1: VLAN插入验证
test_vlan_insertion();
// 测试2: VLAN剥离验证
test_vlan_stripping();
// 测试3: VLAN替换验证
test_vlan_replacement();
// 测试4: VLAN过滤失败处理
test_vlan_filter_fail();
// 测试5: 多通道VLAN
test_multi_channel_vlan();
// 测试6: 优先级映射
test_priority_mapping();
// 测试7: 组播VLAN
test_multicast_vlan();
// 测试8: 广播VLAN
test_broadcast_vlan();
phase.drop_objection(this);
endtask
task test_vlan_insertion();
`uvm_info("TEST", "Testing VLAN insertion...", UVM_LOW)
// 配置VLAN插入
config_vlan_insert(10, 5);
// 发送无VLAN的帧
send_frame_without_vlan();
// 接收并验证
receive_and_verify_vlan(10, 5);
endtask
task test_vlan_filter_fail();
`uvm_info("TEST", "Testing VLAN filter fail...", UVM_LOW)
// 配置VLAN过滤(仅允许VLAN 10)
config_vlan_filter(10);
// 启用过滤失败队列
enable_filter_fail_queue(7);
// 发送VLAN 20的帧
send_vlan_frame(20);
// 验证帧路由到队列7
verify_frame_in_queue(7);
endtask
endclass
八、总结
核心要点
- 过滤失败处理:可路由到特定队列或丢弃,灵活配置
- 描述符差异:Tx Context描述符配置VLAN操作,Rx Write-back描述符包含VLAN信息
- 数据比对:比对帧内容、描述符状态、长度变化
- 多通道分配:每个通道独立配置VLAN,支持多租户
- 优先级配置:PSRQ映射、严格优先级/WRR调度
- 组播广播:VLAN隔离组播/广播域,支持包复制
最佳实践
- 验证方法:构造期望帧,比对所有字段
- 调试技巧:使用过滤失败队列捕获异常帧
- 性能优化:合理配置多通道和队列映射
- 安全考虑:严格VLAN过滤,防止VLAN跳跃
参考资料
- Synopsys DesignWare Cores Ethernet Quality-of-Service Databook
- IEEE 802.1Q - VLAN Standard
- IEEE 802.1p - Priority Classification
- IANA IPv4 Multicast Address Registry
关键词:VLAN过滤失败、描述符、数据比对、多通道、优先级、组播、广播