首页
关于
Search
1
PacketForge 博客部署文档
16 阅读
2
深入 SONiC 与 SAI:从命令行到芯片的完整数据之旅
14 阅读
3
DPU 与 CPO:AI 时代的网络基础设施革命
11 阅读
4
Broadcom芯片
10 阅读
5
DPDK高性能网络
10 阅读
默认分类
交换芯片
高性能网络
AI算力网络
WebSocket高性能项目
DPDK 成长路线
①性能工程基础
②DPDK 源码深读
③用户态协议栈
④软件交换与 SONiC
⑤PCIe、虚拟化与 DPU
⑥面试与复盘
登录
Search
标签搜索
DPDK→DPU 学习路线
P0
P1
P2
P3
P5
PCIe
P4
P6
libmtcp
NUMA
mTCP
OVS
SONiC
SAI
DPU
perf
gdb
EAL
mempool
PacketForge
累计撰写
53
篇文章
累计收到
3
条评论
首页
栏目
页面
关于
最新文章
热门文章
评论最多
点赞最多
2026-08-18
P2-03 · 🐧 对照:mTCP 与内核 TCP 状态机逐状态对比
对应路线图:Phase 2 (Day 50-91) | DPDK 24.11.6 LTS | 内核对照 v6.6.143代码出处:source/mtcp/mtcp/src/tcp_in.c vs source/linux-stable/net/ipv4/tcp_input.c,引用均标 文件:行号上一篇:P2-02 mTCP 源码架构 | 下一篇:P2-04 libmtcp-v3 设计一句话定位同一份 RFC 793 状态机,mTCP 用 65 行 switch 写完,内核用一个 switch + 一条快路径 + 半连接队列 + TW 子机写完。逐状态对照一遍,用户态栈"简化了什么、为什么敢简化"就全清楚了。两个分发器先摆一起mTCP 的 switch(tcp_in.c:1298-1363,节选): switch (cur_stream->state) { case TCP_ST_LISTEN: Handle_TCP_ST_LISTEN(mtcp, cur_ts, cur_stream, tcph); break; case TCP_ST_SYN_SENT: Handle_TCP_ST_SYN_SENT(mtcp, cur_ts, cur_stream, iph, tcph, seq, ack_seq, payloadlen, window); break; case TCP_ST_SYN_RCVD: /* SYN retransmit implies our SYN/ACK was lost. Resend */ if (tcph->syn && seq == cur_stream->rcvvar->irs) Handle_TCP_ST_LISTEN(mtcp, cur_ts, cur_stream, tcph); else { Handle_TCP_ST_SYN_RCVD(mtcp, cur_ts, cur_stream, tcph, ack_seq); if (payloadlen > 0 && cur_stream->state == TCP_ST_ESTABLISHED) { Handle_TCP_ST_ESTABLISHED(mtcp, cur_ts, cur_stream, tcph, seq, ack_seq, payload, payloadlen, window); } } break; // ... ESTABLISHED / CLOSE_WAIT / LAST_ACK / FIN_WAIT_1 / FIN_WAIT_2 // ... CLOSING / TIME_WAIT / CLOSED,共 11 个分支 }内核的 switch(tcp_input.c:6637-6684 + 6725 起,节选): switch (sk->sk_state) { case TCP_CLOSE: SKB_DR_SET(reason, TCP_CLOSE); goto discard; case TCP_LISTEN: if (th->ack) return 1; if (th->rst) { /* ... */ goto discard; } if (th->syn) { // ... acceptable = icsk->icsk_af_ops->conn_request(sk, skb) >= 0; // ... consume_skb(skb); return 0; } // ... case TCP_SYN_SENT: tp->rx_opt.saw_tstamp = 0; tcp_mstamp_refresh(tp); queued = tcp_rcv_synsent_state_process(sk, skb, th); if (queued >= 0) return queued; // ... }最关键的架构差:内核 ESTABLISHED 之后根本不进这个 switch——普通数据包走 tcp_rcv_established 快路径(tcp_input.c:6009),只有 SYN/FIN/异常才落到 tcp_rcv_state_process(tcp_input.c:6627)慢路径。mTCP 每包都过同一个 switch,靠 static inline 的 handler 把分支成本压到可接受。逐状态对比(只看有料的三组)LISTEN:mTCP 直接转态 vs 内核建 request_sockmTCP 的 Handle_TCP_ST_LISTEN(tcp_in.c:750-764)收 SYN 直接 state = TCP_ST_SYN_RCVD 并 AddtoControlList 回 SYN/ACK——没有半连接队列,没有 SYN cookie。内核在 LISTEN 收 SYN 调 icsk_af_ops->conn_request(tcp_input.c:6660)建 request_sock 挂半连接队列,由 tcp_check_req(tcp_minisocks.c:602)在三路握手最后校验。半连接队列 + cookie 是防 SYN flood 的,mTCP 的假设是"信任内网/测试环境流量"——这就是简化权。SYN_SENT:主动打开路径mTCP(tcp_in.c:767-812)三步走:① ACK 不可接受(TCP_SEQ_LEQ(ack_seq, iss))直接回 RST(:774-782);② RST 则进 CLOSE_WAIT 报错(:787-798);③ SYN+ACK 则 HandleActiveOpen 后置 ESTABLISHED、清 RTO(RemoveFromRTOList,:810)、RaiseWriteEvent 通知应用可写(:815)。内核把同时打开等边角情况交给 tcp_rcv_synsent_state_process(tcp_input.c:6675)单独处理,主 switch 只做收尾(tcp_input.c:6672-6683)。ESTABLISHED:mTCP 一个函数 vs 内核快慢双路径mTCP 的 Handle_TCP_ST_ESTABLISHED(tcp_in.c:906-953)顺序:SYN 异常回 ACK → payload 进 ProcessTCPPayload 并攒 ACK(ACK_OPT_AGGREGATE 延迟 / ACK_OPT_NOW 立即,:921-928)→ ACK 进 ProcessACK(:932)→ FIN 序号合法则转 CLOSE_WAIT 并 RaiseReadEvent(:937-947)。内核快路径 tcp_rcv_established(tcp_input.c:6009)只处理"序号连续、无标志异常"的段:校验 header pred、更新 ACK、直接进接收队列,全程不锁用户态锁、不做状态判断;一旦 tcp_validate_incoming(tcp_input.c:5862)判异常就跌回慢路径。TIME_WAIT:链表批查 vs TW 子机mTCP 收 FIN 转 TIME_WAIT 时挂进 timewait_list(tcp_in.c:1139),由主循环 CheckTimewaitExpire 每轮批查过期销毁(timer.c:444-487,ts_tw_expire 到期 → CLOSED + DestroyTCPStream)。TIME_WAIT 里再收到 FIN 重传就 re-arm 定时并补 ACK(tcp_in.c:1352-1360)。内核的 TW 是独立生命周期:tcp_time_wait(tcp_minisocks.c:280)把 sock 转成 inet_timewait_sock,由 tw_timer 定时回收,迟到的包走 tcp_timewait_state_process 专门处理。mTCP 一个链表搞定,内核一个子状态机搞定——复杂度差一个数量级。🐧 差异总表状态mTCP(tcp_in.c)Linux v6.6(tcp_input.c)差异本质LISTEN:750-764,SYN 直接转 SYN_RCVD:6642-6667,conn_request 建 request_sock无半连接队列/cookieSYN_SENT:767-812,ACK/RST/SYN+ACK 三分支:6672-6683,交 synsent_state_process内核单列同时打开SYN_RCVD:1308-1320,ACK 转 ESTABLISHED 且同包数据顺带处理:6726-6768,tcp_init_transfer + tcp_set_statemTCP 顺带处理是亮点ESTABLISHED:906-953,单函数全处理:6009 快路径 + 慢路径兜底快慢路径分离是内核最大工程FIN_WAIT_1:1033 起:6770-6779,先验 snd_una != write_seq内核多一层 FIN 序号防护TIME_WAITtimer.c:444 链表批查tcp_minisocks.c:280 TW 子机链表 vs 子状态机面试 3 问内核为什么需要 tcp_rcv_established 快路径? → ESTABLISHED 占 99% 包量;快路径省掉状态 switch、锁与校验分支,只做 header pred + ACK 处理(tcp_input.c:6009);异常段经 tcp_validate_incoming 跌回慢路径(tcp_input.c:5862)。mTCP SYN_RCVD 转 ESTABLISHED 时"顺带处理 payload"体现在哪? → tcp_in.c:1314-1318:ACK 完成后若 state == TCP_ST_ESTABLISHED 且 payloadlen>0,直接再调一次 ESTABLISHED handler——同一轮循环把三次握手和数据都吃掉,省一轮事件。mTCP 为什么敢不要半连接队列? → 定位是单机多核的 Web/LB 场景,SYN flood 交给前面的硬件/网关防;省掉 request_sock 结构、队列和定时器(对照 tcp_input.c:6660 与 tcp_minisocks.c:602)。🔧 动手实验用 tcpdump 抓一次完整的三次握手 + 四次挥手,对照本文行号逐包标出"哪个包触发了哪一行"。再做一个改动实验:把 mTCP tcp_timewait 配成 0(sample_mtcp.conf:71 默认就是 0)观察短连接压测下 TIME_WAIT 立即回收的吞吐差。数据落点 perf-data/P2/03-fsm.md。下一篇:P2-04 · libmtcp-v3 设计:RFC、模块图、内存模型
2026年08月18日
1 阅读
0 评论
0 点赞
第 1/1 页 · 本页 1 条 · 共 1 条