You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
An alternative to multi-process: each worker thread runs its own FreeBSD stack instance (`vnet_i`, `thread0_i`) within one process. The kernel view is SMP-aware (`-DSMP`): each thread gets a dense pcpu slot `[0, nb_threads-1]` with per-thread `curcpu`, disjoint UMA/SMR per-CPU cache slots, and its own callout callwheel. The `uma_crit_lock` global spinlock has been removed (slot isolation is the sole protection). `thread_mode=0` preserves the original single-thread/multi-process behavior with zero regression. See `docs/native_mt_spec/`.
An optional mode (compile-time macro `FF_KERNEL_COEXIST` + runtime `config.ini [stack] kernel_coexist`, both default off) lets one process serve traffic over **both** the F-Stack stack and the host Linux kernel stack from the **same `ff_epoll_wait` loop**:
In `thread_mode=1`, each worker thread gets its own dense pcpu slot with per-thread `curcpu`, disjoint UMA/SMR per-CPU cache slots, and its own callout callwheel (`timeout_cpu` is `__thread`). The `uma_crit_lock` global spinlock has been removed (slot isolation is the sole protection). `ff_pthread_create()`-created application threads do **not** get a pcpu slot and must not call `ff_*` stack APIs (fail-fast by design). See `docs/native_mt_spec/`.
Since v1.26, F-Stack supports an optional **single-process multi-thread** mode (`thread_mode=1` in `config.ini`), where each worker thread runs its own FreeBSD stack instance (independent `vnet_i`, `thread0_i`) within one process. This complements the multi-process model for use cases where shared address space is needed.
481
+
482
+
Key design points (spec: `docs/native_mt_spec/`):
483
+
- **SMP-aware kernel view** (`-DSMP`, `lib/Makefile:221`): `MAXCPU=1024`, `UMA_ZONE_PCPU` preserved, each thread gets a dense pcpu slot `[0, nb_threads-1]` with per-thread `curcpu` (`lib/include/sys/pcpu.h:34`).
484
+
- **Per-thread UMA/SMR slot isolation**: `mp_ncpus`/`mp_maxid`/`all_cpus` set from `nb_threads` before `uma_startup1()`; each thread exclusively owns its `uz_cpu[curcpu]` and SMR `c_seq` slot.
485
+
- **Global `uma_crit_lock` removed** (commit `57b612d16`): the band-aid spinlock that serialized UMA per-CPU cache access is now a no-op, since slot isolation is the sole protection.
486
+
- **Per-thread callwheel** (`ff_kern_timeout.c:190` `static __thread int timeout_cpu`).
487
+
- **`thread_mode=0` zero regression**: all paths gated by `thread_mode ?` ternary; values identical to pre-change.
Since v1.26, F-Stack supports `thread_mode=1` in `config.ini` for single-process multi-thread operation. Each worker thread gets its own dense pcpu slot with per-thread `curcpu`, UMA/SMR per-CPU cache slot, and callout callwheel. The `uma_crit_lock` global spinlock that previously serialized UMA access has been removed (slot isolation is the sole protection). See `docs/native_mt_spec/` for the full design and runtime test data.
812
+
813
+
> **Note**: `ff_pthread_create()`-created application threads do **not** get a pcpu slot (they have `pcpup == NULL`). Calling any `ff_*` stack API from such threads is unsupported and will crash (fail-fast by design). Only threads created via the `ff_stack_thread_init()` path (i.e., `main_loop` workers in `thread_mode=1`) have valid pcpu slots.
-**Fix**: intercept `IPPROTO_IP + LINUX_IP_BIND_ADDRESS_NO_PORT` in `ff_setsockopt`/`ff_getsockopt` before `linux2freebsd_opt`, return success no-op. FreeBSD already defers ephemeral port selection to connect; F-Stack RSS reverse path (`ff_rss_adjust_sport/6`) picks the source port at connect. Covers both v4 and v6 (nginx calls setsockopt at IPPROTO_IP level for both).
95
95
-**Complements R-E (§6 of ff_rss 10)**: R-E fixed the kernel-side bind gate (`in_pcb.c`/`in6_pcb.c`); this patch fixes the setsockopt option wiring so nginx can actually request the delayed-port behavior without EINVAL.
96
96
97
+
---
98
+
99
+
## 2D. Post-index code delta: MTU/jumbo-frame configuration support
100
+
101
+
> **Manual addendum (not yet re-indexed)**: documented against current source (2026-07). Covers the MTU change feature set (`mtu_change_spec/`): jumbo-frame enablement, KNI/MTU mutual-exclusion removal, IPv6 `nd_ifinfo.maxmtu` sync, and SIOCSIFMTU ioctl dedup. Re-index with `npx gitnexus analyze` to fold into the graph.
102
+
103
+
The feature allows runtime MTU changes on DPDK-backed veth interfaces, including jumbo frames up to the NIC's hardware limit. The KNI/MTU mutual exclusion that previously blocked `mtu_enable` when KNI was enabled has been removed; IPv6 `nd_ifinfo.maxmtu` is now synced via `if_notifymtu` so IPv6 path MTU discovery tracks the configured MTU.
104
+
105
+
| Area | Where in source |
106
+
|------|-----------------|
107
+
| MTU capability query |`lib/ff_dpdk_if.c`: `ff_mtu_capability()` queries `rte_eth_dev_info` for `max_mtu`/`min_mtu`; uses `uint8_t` (not `bool`) for the jumbo-capable flag (commit `4c30d118f` clean-build fix). Magic numbers replaced with named macros `FF_MTU_DEFAULT`, `FF_MTU_JUMBO_THRESHOLD` etc. (commit `0f8f6991e`). |
108
+
| SIOCSIFMTU ioctl handler |`lib/ff_veth.c`: dedup'd via fall-through so v4 and v6 share one code path (commit `332abf997`); validates against `if_getmtu` + hw capability, calls `rte_eth_dev_set_mtu` for DPDK-backed NICs. |
109
+
| KNI/MTU mutex removal |`lib/ff_dpdk_if.c` / `lib/ff_config.c`: removed the `mtu_enable`/`kni.enable` mutual-exclusion check (commit `989f1d2da`); both can now be enabled simultaneously. |
110
+
| IPv6 nd_ifinfo maxmtu sync |`lib/ff_veth.c`: `if_notifymtu` called on MTU change to propagate to `nd_ifinfo.maxmtu` (commit `0f25ac495`), ensuring IPv6 path MTU discovery and neighbor discovery use the updated MTU. |
111
+
| config.ini `[portN]`| New per-port `mtu` configuration item (default 1500); parsed in `ff_config.c`. |
112
+
| IPv6 fragmentation |`freebsd/netinet6/`: IPv6 fragment reassembly respects the updated `maxmtu` (FreeBSD 15.0 `ip6_input` path). |
> **Manual addendum (not yet re-indexed)**: documented against current source (2026-08). Covers the `native_mt_spec/` spec 17 work: making the FreeBSD kernel view SMP-aware for `thread_mode=1`, giving each stack thread a dense pcpu slot with per-thread `curcpu`, and removing the `uma_crit_lock` global spinlock that was serializing the UMA per-CPU cache fast path. Re-index with `npx gitnexus analyze` to fold into the graph.
121
+
122
+
Before this change, all stack threads shared pcpu slot 0 (because `ff_pcpu_thread_init` ignored its `cpuid` parameter, `mp_ncpus=1`, `mp_maxid=0`, `MAXCPU=1`, and `curcpu` was hardcoded to 0). This caused SMR read-side sequence numbers to be overwritten across threads, creating a UAF window. A global spinlock `uma_crit_lock` was introduced as a band-aid to serialize UMA per-CPU cache access, but it was a dataplane bottleneck. This work (G1+G2) makes each thread own a distinct dense pcpu slot and removes the lock.
123
+
124
+
| Area | Where in source |
125
+
|------|-----------------|
126
+
|`-DSMP` build flag |`lib/Makefile:221-223`: `CFLAGS+= -DSMP` — activates `MAXCPU=1024`, `UMA_ZONE_PCPU` not stripped, per-cpu `M_ZERO` full-slot zeroing, `smp_topo()` call site in `tcp_hpts.c`. |
127
+
|`smp_topo()` stub |`lib/ff_glue.c:171-177`: returns `NULL` (safe: `tcp_hpts.c:1890 if (cpu_top == NULL) grp_cnt = 1`; `grps[]` never `malloc`'d). |
128
+
| Triple `mp_ncpus`/`mp_maxid`/`all_cpus`|`lib/ff_freebsd_init.c:314-317`: `nb_cpus = thread_mode ? nb_threads : 1; mp_ncpus = nb_cpus; mp_maxid = nb_cpus - 1; for (i...) CPU_SET(i, &all_cpus);` — set **before**`uma_startup1()` (`:331`) and `mi_startup()` (`:339`); never modified after. |
129
+
|`uma_page_slab_hash` advance |`lib/ff_freebsd_init.c:379-387`: moved hash init **before**`uma_startup1()` — when `mp_maxid ≥ 2`, zone-of-zones item size exceeds 1 page → `UMA_ZFLAG_VTOSLAB` set → `keg_alloc_slab()` calls `vsetzoneslab()` during `uma_startup1()` → NULL deref crash without this fix. |
130
+
|`ff_pcpu_thread_init(cpuid)` uses parameter |`lib/ff_freebsd_init.c:106-112`: now `pcpu_init(pcpup, cpuid, ...)` (was hardcoded `0`); upper-bound `panic` if `cpuid > mp_maxid` (because `subr_pcpu.c:88 KASSERT` is compiled out without `INVARIANTS`). |
0 commit comments