@@ -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