Compare commits
4
Commits
master
..
bde2b24a4c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bde2b24a4c | ||
|
|
b481d8abab | ||
|
|
fa4c4ab9ce | ||
|
|
6d8c994dde |
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
| Day | 主题 | 日期 |
|
||||
|-----|------|------|
|
||||
| [Day 01](/notes/phase0/day01-pcie-topology) | PCIe 拓扑结构 | Sep 2026(重启后 Day 1) |
|
||||
| [Day 01](/notes/phase0/day01-pcie-topology) | PCIe 拓扑结构 | Jun 2026 |
|
||||
| [Day 02](/notes/phase0/day02-kernel-rx-path) | 内核收包路径分析 | Jun 2026 |
|
||||
| [Day 03](/notes/phase0/day03-kernel-memory) | 内核内存管理 | Jun 2026 |
|
||||
| [Day 04](/notes/phase0/day04-rcu-lockfree) | RCU & Lock-free 编程 | Jun 2026 |
|
||||
|
||||
@@ -1,64 +1,127 @@
|
||||
# Phase 0 · Day 01: PCIe 总线拓扑与 Config Space
|
||||
# Phase 0 · Day 1: PCIe 总线拓扑与 Config Space
|
||||
|
||||
> 2026-09-09(主线 Day 1 · 重启后) | 讲义: `Day01-lecture.md` | 融合锚点: uNOS M0 + X540-T2
|
||||
---
|
||||
|
||||
## 一、核心图景:软件怎么碰到硬件
|
||||
|
||||
DPDK/uNOS 的第一行代码 `rte_eal_init()` 返回之前要完成:扫 PCIe 树 → 按 Vendor/Device ID 认出 X540 → 读 Config Space 拿 BAR → 映射成用户态可写地址(MMIO)→ 之后 PMD 写寄存器 = 收发包。**PCIe 就是"软件碰到硬件"的那条路**,也是 P4 手写驱动的同一块知识。
|
||||
|
||||
## 二、拓扑:一条树,三个角色
|
||||
## 一、BDF 地址:每个设备的唯一身份
|
||||
|
||||
```
|
||||
CPU(Root Complex) → Root Port(桥, 引出新总线) → X540(Endpoint)
|
||||
0000 : 02 : 01 . 0
|
||||
│ │ │ └── Function (0~7) — 一个物理芯片可以有多个功能
|
||||
│ │ └────── Device (0~31) — 同一总线上最多 32 个设备
|
||||
│ └─────────── Bus (0~255) — 256 条总线
|
||||
└───────────────── Domain (0~65535) — 多 CPU socket 系统有多个 domain
|
||||
|
||||
单 CPU 系统 domain=0000。多路服务器每个 socket 一个 domain。
|
||||
```
|
||||
|
||||
- Root Complex = CPU 访问 PCIe 的唯一入口;Bridge 扩展总线;Endpoint = 设备本身
|
||||
- 类比: 机框/板卡/端口 三级编号 = Bus/Device/Function
|
||||
DPDK 通过 BDF 地址接管网卡:`dpdk-devbind.py -b vfio-pci 02:01.0`
|
||||
|
||||
## 三、BDF:设备的身份证
|
||||
### 为什么需要三级?
|
||||
|
||||
| 字段 | 位数/范围 | 含义 |
|
||||
PCI 是树形拓扑。每个 Bridge 引入一条新 bus。256 条 bus × 32 设备 × 8 功能 = 65536 个可寻址功能。如果没有 bus 层级,只靠 5-bit device 最多 32 个设备——一张显卡+一张网卡就满了。
|
||||
|
||||
## 二、拓扑中的四种角色
|
||||
|
||||
| 角色 | 你的实例 | 职责 |
|
||||
|------|---------|------|
|
||||
| **Root Complex** | `00:00.0` | CPU 和 PCIe 世界的桥梁,把 load/store 翻译成 TLP |
|
||||
| **PCI Bridge** | `00:11.0` → Bus 02 | 传统 PCI 桥,用 subtractive decode 转发未认领的访问 |
|
||||
| **PCIe Root Port** | `00:15.0` → Bus 03 | PCIe 原生桥,点对点链路,支持更高带宽 |
|
||||
| **Endpoint** | `02:01.0` `03:00.0` | 叶子节点,实际的网卡设备 |
|
||||
|
||||
关键差异:`02:01.0` (e1000) 是挂在传统 PCI Bridge 后面的老式设备,多条设备共享 Bus 02。`03:00.0` (VMXNET3) 是 PCIe Endpoint,独享 Bus 03 的整条链路(5GT/s × x32)。
|
||||
|
||||
## 二、PCIe 拓扑
|
||||
|
||||
```
|
||||
[0000:00] ← Root Complex (Host Bridge)
|
||||
│ CPU 访问 PCIe 设备的唯一入口
|
||||
│
|
||||
├── 11.0 → [02] ← PCI Bridge (老式总线)
|
||||
│ ├── 01.0 e1000 (Endpoint)
|
||||
│ └── 04.0 e1000 (Endpoint)
|
||||
│
|
||||
└── 15.0 → [03] ← PCIe Root Port (真正的 PCI Express)
|
||||
└── 00.0 VMXNET3 (Endpoint)
|
||||
```
|
||||
|
||||
数据流:CPU → Root Complex → TLP 封装 → PCIe 链路 → Endpoint。
|
||||
|
||||
## 三、Config Space 完整解码
|
||||
|
||||
e1000 (02:01.0) 的 256 字节 Config Space,逐字段解码:
|
||||
|
||||
| Offset | 字段 | Hex 值 | 含义 |
|
||||
|--------|------|--------|------|
|
||||
| 0x00-01 | Vendor ID | 0x8086 | Intel |
|
||||
| 0x02-03 | Device ID | 0x100f | 82545EM |
|
||||
| 0x04-05 | Command | 0x0113 | IO+Mem enable, BusMaster OFF |
|
||||
| 0x0a-0b | Class Code | 0x020000 | Network Controller |
|
||||
| 0x0e | Header Type | 0x00 | Endpoint |
|
||||
| 0x10-13 | BAR0 | 0xfd5c0004 | Memory@0xfd5c0000, 64bit, 128KB, Non-Prefetchable |
|
||||
| 0x18-1b | BAR2 | 0xfdff0004 | Memory@0xfdff0000, 64KB |
|
||||
| 0x20-23 | BAR4 | 0x00002001 | IO Port@0x2000 |
|
||||
| 0x34 | Capability Ptr | 0xdc | 链表起点 |
|
||||
| 0x3c | Interrupt Line | 0x07 | IRQ 7 |
|
||||
| 0x3d | Interrupt Pin | 0x01 | INTA# |
|
||||
|
||||
BAR flag bit 解码: bit0=Memory/IO, bit[2:1]=32b/64b, bit3=Prefetchable。`0xfd5c0004` 中的 `4` = 0100₂ → 64-bit Memory, Non-Prefetchable。真实基址 = 0xfd5c0004 & ~0xF = 0xfd5c0000。
|
||||
|
||||
Capability 链表: 0xdc→PM(ID=1)→0xe4→PCI-X(ID=7)→0x00(End)。
|
||||
|
||||
## 四、VMXNET3 对比 (真正的 PCIe 设备)
|
||||
|
||||
| | e1000 | VMXNET3 |
|
||||
|---|---|---|
|
||||
| Bus | 0~255 | 第几条总线 |
|
||||
| Device | 0~31 | 同总线第几个设备 |
|
||||
| Function | 0~7 | 芯片的独立功能 |
|
||||
| 总线 | PCI-X (老) | PCIe v2.0 |
|
||||
| Capability | PM + PCI-X | PM + PCIe Express + MSI + MSI-X + Serial# |
|
||||
| MSI-X | 无 | 25 向量, BAR2 offset 0, PBA offset 0x1000 |
|
||||
|
||||
全系统最多 65536 个功能。DPDK 绑卡 `dpdk-devbind.py -b vfio-pci 03:00.0` 报的就是 BDF。
|
||||
## 五、实战踩坑
|
||||
|
||||
## 四、Config Space:出厂说明书(256B)
|
||||
### 坑 1: Bus Master 没开
|
||||
- **现象**: DPDK 启动后一个包都收不到
|
||||
- **根因**: Command bit2=0 → 网卡不能 DMA
|
||||
- **定位**: `lspci -vvv | grep "BusMaster"`
|
||||
- **修复**: `pci_set_master(pdev)` 或 `setpci -s XX:XX.X COMMAND=0x117`
|
||||
|
||||
| Byte | 字段 | 含义 |
|
||||
|---|---|---|
|
||||
| 0-1 | Vendor ID | 0x8086 = Intel |
|
||||
| 2-3 | Device ID | **驱动匹配第一依据** |
|
||||
| 9-11 | Class Code | 0x020000 = 网络控制器 |
|
||||
| 14 | Header Type | 0x00 = Endpoint |
|
||||
### 坑 2: 64-bit BAR 误读
|
||||
- **现象**: 物理地址 >4GB 时 MMIO 地址错误
|
||||
- **根因**: 只用 uint32_t 读 BAR0 低 32 位
|
||||
- **修复**: 用 `resource_size_t pci_resource_start(pdev, 0)`
|
||||
|
||||
## 五、BAR + MMIO:CPU 碰网卡的物理通道
|
||||
### 坑 3: MSI-X 向量不够
|
||||
- **现象**: 多队列网卡性能不增长
|
||||
- **根因**: pci_alloc_irq_vectors 返回数 < RX 队列数
|
||||
- **定位**: `cat /proc/interrupts | grep PCI-MSI | wc -l`
|
||||
- **修复**: 增大内核 MSI-X 限制或 BIOS 调整
|
||||
|
||||
- BAR = 网卡向 OS 要的一段物理地址,映射自己的寄存器;CPU 读写 = 操作网卡
|
||||
- 本质即交换机 SDK 的 `asic_write_register(addr, val)` 同款操作
|
||||
- MSI-X 32 向量 = 多队列并行的硬件基础(uNOS 单核现在用 1,扩核复用)
|
||||
### 坑 4: PCIe 链路降速
|
||||
- **现象**: 100Gbps 网卡只能跑 25Gbps
|
||||
- **定位**: `lspci -vvv | grep -E "LnkCap:|LnkSta:"` → Speed 2.5GT/s
|
||||
- **修复**: 检查物理槽位宽度、PCIe 延长线、BIOS 设置
|
||||
|
||||
## 六、算法穿插:哈希表 + LC1
|
||||
### 坑 5: AER 静默数据损坏
|
||||
- **现象**: 偶尔出现 mbuf 数据乱码但不 crash
|
||||
- **定位**: `dmesg | grep AER` → Uncorrectable Error
|
||||
- **修复**: 必须换硬件,链路已不可靠
|
||||
|
||||
- 哈希 = 把"值"换算成"下标",借数组 O(1) 给查找;三组件:哈希函数/桶数组/冲突处理
|
||||
- LC1 两数之和:一趟遍历,每步问"补数出现过吗"(存在性查询 O(1)),先查后存保证"只向过去提问"
|
||||
- **评级 🔴**:要求参考实现,未独立完成 → **09-11 重做**
|
||||
- 产品锚点: conntrack 表(M2)/ flow cache(M1, rte_hash)就是哈希表的工业形态
|
||||
## 六、核心认知
|
||||
|
||||
## 七、冲刺穿插:RDMA 开篇
|
||||
CPU 操作网卡的全路径:
|
||||
|
||||
- RDMA = 网卡直接搬数据,CPU 不参与(QP/verbs、注册内存零拷贝、硬件可靠传输)
|
||||
- RoCEv2 = 以太网上的 RDMA → 对丢包零容忍 → 无损以太网成为 Week 1 主题
|
||||
- **丢包 vs 暂停的代价账**:丢包 = 全局/传染/触发 ≥1 RTT 硬件重传 + AllReduce 木桶放大;PFC 暂停 = 局部/可恢复 → 宁可暂停不可丢包
|
||||
```
|
||||
读 Config Space → 匹配 Vendor/Device ID → 确定驱动
|
||||
→ pci_enable_device → ioremap(BAR0) → 拿到虚拟地址
|
||||
→ ioread32/iowrite32 操作寄存器 → 网卡开始工作
|
||||
```
|
||||
|
||||
## 检验标准
|
||||
BAR 是 MMIO 的入口,Config Space 是身份证,Capability 链表是扩展机制。
|
||||
|
||||
- [ ] 能画出 CPU → RC → Root Port → X540 拓扑并解释三角色
|
||||
- [ ] 能解释 BDF 三字段与 65536 上限
|
||||
- [ ] 能说出驱动匹配靠 Config Space 哪两个字段
|
||||
- [ ] 能解释 BAR+MMIO 并联系 asic_write_register
|
||||
- [ ] 能讲清 rte_eal_init 找 X540 的五步
|
||||
- [ ] 能口述哈希表"先查后存"为什么防自我匹配
|
||||
- [ ] 能说出 RDMA 丢包三层代价(重传 RTT/木桶/传染)
|
||||
## 七、检验标准
|
||||
- [ ] 能解释 BDF 地址含义
|
||||
- [ ] 能手写 Config Space 前 16 字节字段
|
||||
- [ ] 能从 hex 值解码 BAR 的基址和大小
|
||||
- [ ] 能画 Capability 链表结构
|
||||
- [ ] 能对比 e1000(PCI-X) vs VMXNET3(PCIe v2)
|
||||
- [ ] 能解释为什么 Bus Master bit 不置位就没 DMA
|
||||
|
||||
@@ -60,11 +60,6 @@
|
||||
|
||||
## 三、硬件 BOM(最低成本,支持 VFIO)
|
||||
|
||||
> **研发机 vs 量产 BOM 的分工(2026-10-03)**:本节是**量产** BOM——目标是 ¥299 售价下的最低成本 + 低功耗(常开设备)。
|
||||
> **研发/验证机**已就绪:jb3455b = J3455 四核 + **X540-AT2 10G × 2** + 8GB DDR3。
|
||||
> 两者**不要混**:X540 单价/功耗都高于 82576,对 1 Gbps 产品是过度设计;研发机上的价值是能跑通代码 + 压实测数字,不是出货配置。
|
||||
> X540 在 jb3455b 上实测 PCIe 2.0 **x2**(≈8 Gbps),对 1G 产品 8 倍余量,不构成约束。
|
||||
|
||||
### 选型理由
|
||||
|
||||
- **J3355B-ITX**: Apollo Lake 起全系支持 VT-d,这是 Intel 平台最便宜的 VT-d 方案
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
### 1.2 产品矩阵
|
||||
|
||||
> ⚠ 2026-09-07 更新: Cloud Edge 硬件(T140)已售,该产品线**暂缓**;Home CPE 为唯一在研产品,硬件已升级(X540-AT2 10G × 2,8GB RAM)。模块拆解与路线对齐见 `dpdk_study/docs/uNOS_PRODUCT_FUSION_ROADMAP.md`(附录含 M0-M7 模块清单)。
|
||||
> ⚠ 2026-09-07 更新: Cloud Edge 硬件(T140)已售,该产品线**暂缓**;Home CPE 为唯一在研产品,硬件已升级(X540-T2 10G × 2,8GB RAM)。模块拆解与路线对齐见 `dpdk_study/uNOS_MODULE_ROADMAP.md`。
|
||||
|
||||
| | uNOS Cloud Edge ⏸ | uNOS Home CPE ▶ |
|
||||
|---|---|---|
|
||||
@@ -161,19 +161,17 @@ Core 0 ─→ lcore 0: Control Plane (main thread)
|
||||
├── ARP Manager / DHCP Client / Health Monitor
|
||||
└── CLI (Unix socket)
|
||||
|
||||
Core 1 ─→ lcore 1: Data Plane Worker (纯转发单核;叠加 NAT/ACL/QoS 后按实测决定是否用 core2)
|
||||
└── 物理口 (X540-T2 10G × 2, 绑 vfio-pci) RSS queue 0
|
||||
Core 1 ─→ lcore 1: Data Plane Worker (单核,1G 线速足够)
|
||||
└── 物理口 (82576 × 2) RSS queue 0
|
||||
Graph Pipeline: L2/L3/NAT/ACL/QoS
|
||||
Per-core Flow Cache + Connection Track Table
|
||||
(不包含 TCP 栈 — Home CPE 不跑应用层服务)
|
||||
|
||||
Core 2 ─→ 数据面备用核 (状态化/流控压不住时启用) ;否则 (非 DPDK) FRR ospfd
|
||||
Core 2 ─→ (非 DPDK) FRR ospfd
|
||||
|
||||
Core 3 ─→ 空闲 / Prometheus 轻量 exporter
|
||||
```
|
||||
|
||||
> **2026-10-03 勘误**:① 原来写 "单核,1G 线速足够" 只在**纯转发**成立——64B 小包打满即 1 Gbps 线速(=1.488 Mpps,算术恒等),叠加 conntrack/NAT/ACL/QoS 后单核无余量,故 core2 预留为第二数据面核;② 物理口笔误 `82576 × 2` 更正为实机 **X540-T2 10G × 2**;③ 管理口用板载 RTL8111(无上游 DPDK PMD,固定归 Linux)。
|
||||
|
||||
### 2.3 模块依赖图
|
||||
|
||||
```
|
||||
@@ -322,8 +320,6 @@ void unos_launch_lcores(void) {
|
||||
✅ 对标 VPP (FD.io) 的 Graph Node 架构,业界验证过
|
||||
```
|
||||
|
||||
> **边界说明(2026-10-03)**:上面 "❌ 单核转发" 针对的是 **Cloud Edge / 多 Gbps 目标**;Home CPE 的 1 Gbps 定位下单核可作为基线(见 §2.2 的 lcore 划分),但这是**性能余量换成本**的取舍,不是"单核更好"——所以 Home CPE 仍保留 core2 作为第二数据面核的退路。
|
||||
|
||||
### 4.1 Graph Pipeline 核心数据结构
|
||||
|
||||
```c
|
||||
|
||||
Reference in New Issue
Block a user