Skip to content

Commit 35aa958

Browse files
committed
docs: add R-E (IP_BIND_ADDRESS_NO_PORT) spec and gap-scan checklist
Two spec deliverables (docs only, no code changes): 1. ff_rss_check_opt_spec: add requirement 0.5 / milestone R-E for porting upstream commit cb9b4d4 (IP_BIND_ADDRESS_NO_PORT) to FreeBSD 15.0. 15.0 already has the connect-time RSS path (in_pcb_lport_dest with INPLOOKUP_LPORT_RSS_CHECK), so only the bind-side gates are needed: hunk1 in in_pcbbind to skip in_pcbinshash when inp_lport==0, hunk2 in in_pcbbind_setup to skip the early in_pcb_lport call. IPv6 sync is added as recommended (in6_pcbbind delayed allocation + in6_pcbconnect L515 condition relaxation). Covers 10 chapters: overview, requirement, current-state-gap, external-research, design, interface, milestone, test, baseline, review-gate. 2. freebsd_13_to_15_upgrade_spec/04 §11: add gap-scan checklist of 13.0 FSTACK customizations vs current 15.0 tree (10 items, evidence-based with file:line). Final classification: (a) port: #1 IP_BIND v4, #2 v6 sync, #6 ng_socket kldload; (b) already ported via stub: #7/#8 ipfw; (c) not applicable: #3/#4 mcast (15.0 two trees strictly layered, no out-of-bound), #5 require_unique_port (path removed), #9 if_spppsubr.c (file does not exist), #10 namei.h NDFREE (macros refactored). All line numbers verified by grep/read_file.
1 parent f7fd3b6 commit 35aa958

12 files changed

Lines changed: 719 additions & 17 deletions

docs/ff_rss_check_opt_spec/zh_cn/00-总览索引.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
| 0.1 | `ff_rss_tbl_get_portrange` 内核侧选端口对接在 13.0→15.0 升级中未移植,需在 15.0 回迁并测试 | 回迁上游能力 |
1010
| 0.2 | `ff_rss_check` / `ff_rss_tbl_get_portrange` 支持 IPv6 hash(当前仅 IPv4) | 全新增(上游亦无 IPv6) |
1111
| 0.3 | 保留静态 `ff_rss_tbl` 前提下用 `rte_thash_adjust_tuple()` 优化动态计算场景,并与 FreeBSD 选源端口流程兼容对接 | 超越上游(上游未用 adjust_tuple) |
12+
| 0.4 | `ff_rss_check` / `ff_rss_check6` 反算后二次软算复核默认关闭,作为 debug 选项可开启(运行时开关) | 增量优化(运行时开关) |
13+
| 0.5 | `IP_BIND_ADDRESS_NO_PORT` bind-then-connect RSS 端口选择移植(对齐 Linux 语义 + RSS 队列亲和):让 `bind(local_addr, port=0)` 后 connect 时延迟端口分配,使 connect 期 `ff_rss_check` 的 RSS 感知端口选择生效 | 回迁上游能力(上游 commit `cb9b4d462`,IPv4;v6 为 15.0 全新增同步) |
1214

1315
## 文档地图
1416
| 文件 | 里程碑 | 内容 |
@@ -31,6 +33,8 @@
3133
| 0.1 回迁 | R-A | TC-U-RSS-01-01~06、IT-RSS-01/02、RT-RSS-01/02 |
3234
| 0.3 thash | R-B | TC-U-RSS-03-01~05、IT-RSS-03/05、RT-RSS-03 |
3335
| 0.2 IPv6 | R-C | TC-U-RSS-02-01~05、IT-RSS-04、RT-RSS-04 |
36+
| 0.4 recheck 开关 | R-D | TC-U-RSS-04-01~06、IT-RSS-03/05、RT-RSS-03 |
37+
| 0.5 bind no port | R-E | TC-U-RSS-05-01~05、IT-RSS-06、RT-RSS-05/06 |
3438

3539
## 关键设计决策(速查)
3640
1. **IPv6 用 v6 独立表/函数(方案A)**,不用联合体 —— 保 IPv4 零回归、不改 v4 接口签名。

docs/ff_rss_check_opt_spec/zh_cn/01-需求规格.md

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,88 @@ R-B/R-C(0.3 + 0.2)落地后,`ff_rss_adjust_sport`(`lib/ff_dpdk_if.c:3053
153153

154154
---
155155

156-
## 4. 四项需求关系小结
156+
## 3-ter. 需求 0.5:`IP_BIND_ADDRESS_NO_PORT` bind-then-connect RSS 端口选择移植
157+
158+
### 3-ter.1 背景
159+
160+
- 参考上游 commit `cb9b4d462a0cd8c47b6f514e2af0111cd26597b3`(f-stack 上游,基于 13.0,仅改 `freebsd/netinet/in_pcb.c`,+9/-2,3 hunk),release note「Support bind no port like linux's IP_BIND_ADDRESS_NO_PORT」,与本批 `ff_rss_check` 优化同源(详见 03 §5 调研)。
161+
- **典型用法/故障链**:应用 `bind(local_addr, port=0)` 后再 `connect(remote)`
162+
- 原生 FreeBSD 路径:`bind` 阶段即为 socket 分配一个匿名本地端口(`in_pcbbind``in_pcbbind_setup``in_pcb_lport`),此端口选择**不感知 RSS**(不带 `INPLOOKUP_LPORT_RSS_CHECK`)。
163+
- 随后 `connect` 时,因 `inp->inp_lport` 已非 0,connect 走「已分配端口」分支(`in_pcbconnect:1377` else / `in_pcb.c` anonport=false),**绕过** R-A 回迁的 `in_pcb_lport_dest(... INPLOOKUP_LPORT_RSS_CHECK)` RSS 感知选端口(`in_pcb.c:1363-1366`)。
164+
- 结果:该四元组报文经网卡 RSS 后**可能落非本 worker 队列**,破坏 F-Stack 多进程 share-nothing 的「回包落本核」前提(与 0.1 的目标场景同源,但触发路径在 bind 而非 connect)。
165+
- **上游修法语义**(commit `cb9b4d462` 三 hunk,基于 13.0,证据见 02 §6-ter):
166+
- hunk1(`in_pcbbind`):用 `#ifdef FSTACK if (inp->inp_lport != 0) { ... } #endif` 包裹 `in_pcbinshash` 入 hash 块——bind local addr(port=0)时**不入 hash**(即不固化端口)。
167+
- hunk2(`in_pcbbind_setup`):用 `#ifndef FSTACK` 包裹 `if (lport==0) { in_pcb_lport(...); }`——FSTACK 下 bind(port=0) 时**不在 bind 阶段分配端口**,使 `inp->inp_lport` 保持 0。
168+
- hunk3(13.0 `in_pcbconnect_setup`):`in_pcbbind_setup(...)` 改为 `in_pcb_lport(inp, &laddr, &lport, cred, INPLOOKUP_WILDCARD)`——connect 期重选端口。
169+
- **语义对齐**:与 Linux `IP_BIND_ADDRESS_NO_PORT`(Linux 4.2 引入,`bind(addr,0)` 不预留端口、推迟到 connect 按完整四元组选端口)一致;但 F-Stack 在此基础上**多了 RSS 队列亲和约束**——connect 期延迟选端口走的是 R-A 的 `INPLOOKUP_LPORT_RSS_CHECK` 路径,选出的端口须落本 worker 队列。
170+
- **部署约束**:local addr(vip)须配置在 DPDK 接管的 nic(`f-stack-x`,config.ini `[portN]` 默认值),**不能配在 `lo`**(lo 走内核栈不经 DPDK RSS)。
171+
172+
### 3-ter.2 15.0 落点结论(核心,已实证,行号以当前代码为准)
173+
174+
15.0 当前 `freebsd/netinet/in_pcb.c`(已实证,见 02 §6-ter):
175+
176+
- `in_pcbbind`(L720):L739-745 的 `in_pcbinshash` 块(含 `__predict_false` + `MPASS(SO_REUSEPORT_LB)` + 清 `INADDR_ANY`/`inp_lport`/`INP_BOUNDFIB`**无 FSTACK 守卫****hunk1 丢失点**
177+
- `in_pcbbind_setup`:L1273 `if (*lportp != 0) lport = *lportp;`、L1275-1279 `if (lport == 0) { in_pcb_lport(... lookupflags); }` **`#ifndef FSTACK`****hunk2 丢失点**
178+
- connect 路径:15.0 已无独立 `in_pcbconnect_setup`(重构进 `in_pcbconnect` L1294);L1313 `anonport = (inp->inp_lport == 0)`;L1363-1366 anonport 分支已用 `in_pcb_lport_dest(... INPLOOKUP_WILDCARD | INPLOOKUP_LPORT_RSS_CHECK)`(FSTACK 守卫 L1365-1366);L1377 else 用已分配端口。**hunk3 在 15.0 已等价具备,无需改动**
179+
- **故障链**:bind 期分配端口 → `inp_lport ≠ 0` → connect L1313 `anonport = false` → 走 L1377 else 绕过 RSS。
180+
181+
**落点结论**:15.0 只需补 **hunk1**`in_pcbbind` L739-745 入 hash 块套 `if (inp->inp_lport != 0)`)+ **hunk2**`in_pcbbind_setup` L1275-1279 套 `#ifndef FSTACK`),使 `bind(addr, 0)``inp_lport = 0` → connect 天然进 anonport=true → `INPLOOKUP_LPORT_RSS_CHECK` 分支。预估 v4 `+8` 行。
182+
183+
### 3-ter.3 IPv6 对称性(重要,已实证)
184+
185+
- 13.0 baseline `in6_pcb.c` 无 FSTACK,v6 此能力 13.0 本就**没有**;参考 commit 也只改 v4。
186+
- 15.0 `in6_pcb.c` 已新增 FSTACK:`in6_pcbconnect` RSS 分支 L515-527(条件 `IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) && inp->inp_lport == 0`,用 `INPLOOKUP_LPORT_RSS_CHECK` L521);但 `in6_pcbbind`(L306)的 L354 `if (lport == 0) { in6_pcbsetport(...); }` 提前分配端口(`in6_pcbsetport``in_pcb_lport` 无 RSS_CHECK),L361-369 else 直接 `in_pcbinshash` 入 hash。
187+
- **v6 故障链**:bind 一个 v6 local addr 后 `in6p_laddr` 非 unspec **** `inp_lport ≠ 0` → connect L515 两条件均破 → 绕过 RSS。**v6 bind-then-connect 同样未闭合**,需同步移植(`in6_pcbbind` 延迟分配 + 入 hash 门控),属 15.0 全新增范畴(无 13.0 diff 可照搬),预估 `in6_pcb.c` `+6~10` 行。
188+
189+
### 3-ter.4 目标
190+
191+
1. **v4(必做)**:补 15.0 `in_pcb.c` 的 hunk1 + hunk2(`#ifdef FSTACK`/`#ifndef FSTACK` 门控),使 `bind(v4_addr, 0)` 后 connect 进入 RSS 感知选端口路径,选出的源端口落本 worker 队列;语义对齐 Linux `IP_BIND_ADDRESS_NO_PORT` + RSS 亲和。
192+
2. **v6(建议同步,全新设计)**:对称改造 15.0 `in6_pcb.c``in6_pcbbind`(延迟端口分配 + 入 hash 门控),使 `bind(v6_addr, 0)` 后 connect 进入 L515 RSS 分支。**标明为 15.0 全新设计(无 13.0 diff 照搬)**
193+
194+
### 3-ter.5 范围(In Scope)
195+
196+
- `freebsd/netinet/in_pcb.c``in_pcbbind`(L720,入 hash 块门控)+ `in_pcbbind_setup`(L1275-1279,端口分配门控)。
197+
- `freebsd/netinet6/in6_pcb.c``in6_pcbbind`(L306,L354 端口分配 + L361-369 入 hash 门控)——v6 同步项。
198+
- 全部 `#ifdef FSTACK`/`#ifndef FSTACK` 门控,最小侵入;复用 R-A 已具备的 connect 期 `INPLOOKUP_LPORT_RSS_CHECK` 路径(不新增用户态接口)。
199+
- bind-then-connect 功能/回归测试(v4 必做、v6 建议同步)。
200+
201+
### 3-ter.6 非目标(Out of Scope)
202+
203+
- 不改用户态 `ff_rss_*` 接口签名(本特性纯内核 `in_pcbbind`/`in6_pcbbind` 内部门控调整,复用 R-A 的 connect 期 RSS 路径)。
204+
- 不改 connect 路径(hunk3 在 15.0 已等价具备,L1363-1366 / in6 L515-527)。
205+
- 不引入新的 socket option 解析(F-Stack 复用现有 RSS 开关,行为对所有 bind(addr,0) 生效;是否需 per-socket `IP_BIND_ADDRESS_NO_PORT` setsockopt 语义见 §3-ter.8 待确认)。
206+
- 不在本需求内做 0.1~0.4 已覆盖的 connect 直连场景(本需求只补 bind-then-connect 这一漏闭合路径)。
207+
208+
### 3-ter.7 验收标准
209+
210+
- **AC-05-1(v4 bind 不预分配端口)**:开 FSTACK + `rss_check` 多队列下,`bind(v4_addr, 0)` 返回成功后 `inp->inp_lport == 0`(未在 bind 阶段固化端口);socket 未入 hash(不占端口空间)。
211+
- **AC-05-2(v4 connect 走 RSS 路径)**:上述 socket `connect``anonport == true`(L1313)→ 走 `in_pcb_lport_dest(... INPLOOKUP_LPORT_RSS_CHECK)`(L1363-1366)→ 选出的源端口经独立 `ff_rss_check` 复核**落本 worker 队列**
212+
- **AC-05-3(v6 同步)**`bind(v6_addr, 0)``inp->inp_lport == 0``in6p_laddr` 仍按 bind 设置;connect 时进入 L515 RSS 分支(`IN6_IS_ADDR_UNSPECIFIED``inp_lport==0` 的实际条件以编码核实为准,见 §3-ter.8)→ 源端口经 `ff_rss_check6` 复核落本队列。
213+
- **AC-05-4(bind 指定端口零回归)**`bind(addr, port=N)`(N≠0)行为**完全不变**——端口仍在 bind 阶段固化、socket 仍正常入 hash(hunk1/hunk2 门控仅作用于 `lport == 0` 分支)。
214+
- **AC-05-5(关闭 FSTACK / 单队列零回归)**:关闭 FSTACK 编译通过且 bind/connect 退回原生 FreeBSD 行为;`rss_check` enable=0 或单队列时,connect 期 RSS 分支自动退化(`ff_rss_check` nb_queues<=1 返回 1)。
215+
- **AC-05-6(REUSEPORT_LB 兼容)**:开启 `SO_REUSEPORT_LB` 的 socket bind(addr,0) 行为正确(hunk1 门控不破坏 L740 `MPASS(SO_REUSEPORT_LB)` 既有语义,见 §3-ter.8 待确认)。
216+
- **AC-05-7(local addr 配置约束)**:vip(local addr)配在 DPDK nic(`f-stack-x`)时落队列生效;配在 `lo` 时走内核栈不经 RSS(属预期,文档明示)。
217+
218+
### 3-ter.8 待确认项(编码阶段核实,不臆测)
219+
220+
- 【待确认】hunk1 门控 `if (inp->inp_lport != 0)` 包裹 L739-745 入 hash 块后,与 L740 `MPASS(inp->inp_socket->so_options & SO_REUSEPORT_LB)` 的交互——上游 13.0 此块结构与 15.0 不同(15.0 含 `in_pcbinshash` 失败回滚),门控位置须精确到「`lport==0` 时跳过 inshash,`lport!=0` 时维持现状」,编码期复核 hunk 适配(02 §6-ter)。
221+
- 【待确认】hunk2 在 15.0 `in_pcbbind_setup`(L1275-1279)的 `#ifndef FSTACK` 包裹后,FSTACK 下 `lport` 保持 0 是否影响 L1280-1281 `*laddrp = laddr.s_addr; *lportp = lport;`(lport=0 回写 inp_lport)的下游使用,以及 `in_pcbbind`(L735-748)对 `inp->inp_lport==0 + anonport` 的处理(L746-747 `INP_ANONPORT`)。
222+
- 【待确认】v6 `in6_pcbbind`(L354/L361-369)延迟分配的精确改法——v6 无 13.0 diff 照搬,须仿 v4 hunk1/hunk2 设计「lport==0 时跳过 in6_pcbsetport + 跳过 in_pcbinshash」,并保证 connect L515 条件(`in6p_laddr` 非 unspec 但 `inp_lport==0`)能进 RSS 分支(即 bind 仍设置 in6p_laddr 但不设 lport)。
223+
- 【待确认】是否需要 per-socket `IP_BIND_ADDRESS_NO_PORT` setsockopt(Linux 是 per-socket 显式开启)vs F-Stack 对所有 `bind(addr,0)` 隐式生效——上游 commit 是隐式(FSTACK 下所有 bind(addr,0) 都延迟),本项目倾向沿用上游隐式语义,是否需显式 option 留编码/产品决策。
224+
225+
---
226+
227+
## 4. 五项需求关系小结
157228

158229
| 需求 | 性质 | 用户态改动 | 内核态改动 | IPv6 |
159230
|------|------|------------|------------|------|
160231
| 0.1 | 回迁(13.0 已有、15.0 缺失) | 无(接口已存在保留) | `in_pcb.c` 回迁 FSTACK RSS 钩子 | 否(IPv4) |
161232
| 0.2 | 全新增(13.0 也无) | hash/表结构/接口 IPv6 化 | `in6_pcb.c` 新建对接 ||
162233
| 0.3 | 优化(动态路径) | `ff_rss_check` 动态路径引入 `rte_thash` | 与 0.1 对接协同 | 随 0.2 扩展 |
163234
| 0.4 | 增量优化(运行时开关) | `ff_rss_check_cfg``recheck`;reverse 函数门控 `ff_rss_check[6]` 复核 || v4/v6 对称 |
235+
| 0.5 | 回迁(13.0 已有 v4、15.0 缺;v6 全新增) | 无(复用 R-A connect 期 RSS 路径,不改用户态接口) | `in_pcbbind`/`in_pcbbind_setup` 延迟分配门控;`in6_pcbbind` 同步(v6 全新设计) | v4 必做 + v6 建议同步 |
236+
237+
> 0.5 与 0.1 关系:0.1(R-A)补的是 **connect 直连**期的 RSS 选端口;0.5(R-E)补的是 **bind(addr,0)-then-connect** 这条因 bind 提前分配端口而绕过 0.1 路径的漏闭合分支。0.5 复用 0.1 已落地的 connect 期 `INPLOOKUP_LPORT_RSS_CHECK` 路径,只需让 bind 阶段「不抢先分配端口」即可使 connect 天然走 RSS。
164238
165239
---
166240

0 commit comments

Comments
 (0)