




数据包从应用层发出时依次经过socket层→TCP/UDP层→IP层→邻居子系统→网络设备驱动→物理介质,每层仅处理自身头部并传递净荷。
Linux 中一个 send() 系统调用发出的数据,并不会直接变成网线上的电信号。它要依次穿过 socket 层 → TCP/UDP 层 → IP 层 → 邻居子系统(ARP)→ 网络设备驱动 → 物理介质。
关键点在于:每一层只处理自己关心的字段,添加或校验对应头部,然后把净荷交给下一层。比如 TCP 层加 tcp_header,IP 层加 ip_header,而以太网帧头(eth_header)是在邻居子系统确认目的 MAC 后才补上的。
arp_table 或触发 ARP 请求获取 MAC;netstat -rn 和 ip route get 可验证路由决策结果;tcpdump -i any host 能在任意接口抓到未加密的原始包,但注意 loopback 接口(lo)上看到的是 IP 层以上,不含以太网头。ping 通但 curl 不通?常见链路断裂点定位ICMP(ping)走的是内核的 icmp_rcv() 路径,而 HTTP 请求依赖完整的四层栈(TCP 连接 + 应用层交互),任一环节异常都会失败。
ss -tn state syn-sent 是否堆积,说明 SYN 发出但没收到 SYN-ACK,可能是防火墙丢包、目标端口未监听、或中间设备限速;tcpdump -i eth0 port 80 看是否有 ACK 流量,若 client 发了请求但 server 没回包,重点查 server 的 iptables -L -n -v 和 sysctl net.ipv4.tcp_tw_reuse 设置;
:某些发行版默认启用 nf_conntrack,大量短连接可能耗尽连接跟踪表,表现为随机超时,可通过 cat /proc/sys/net/netfilter/nf_conntrack_count 查看当前用量;curl 默认先走 DNS,再建 TCP,建议用 curl -v --resolve example.com:80:192.168.1.100 http://example.com 绕过 DNS 直连测试。tcpdump 抓不到包?三个最常被忽略的过滤与接口问题tcpdump 默认只监听第一个非 loopback 接口,且无法捕获被内核丢弃前的包(如被 iptables -j DROP 丢弃的包,除非用 nflog 配合)。
ip link show up 列出所有 UP 状态接口,明确指定 -i eth0 或 -i any(后者可捕获所有接口,但 loopback 上的包不含以太网帧头);port 22 会同时匹配源和目的,应写 dst port 22;ip link show eth0 | grep PROMISC,若无输出且需抓其他主机流量,得联系管理员开启;tcpdump 的缓冲区丢弃,建议加 -B 4096 扩大缓冲,或用 -w file.pcap 先保存再分析。容器本质是独立 network namespace,其网络栈与宿主机隔离。不理解命名空间边界,就容易在错误位置排查。
readlink /proc//ns/net ,对比宿主机的 /proc/1/ns/net;nsenter -t -n ip addr 看是否有正确配置的 veth 接口和 IP;ethtool -S | grep peer (部分内核版本支持),或通过 ip link 输出中 interface 名称规律(如 vethabc123 ↔ vethdef456)人工匹配;ip link set dev vethxxx up,否则即使容器内 ifconfig 显示 UP,也无法收发;DOCKER-USER 链,但自建 namespace 若未显式允许转发,需加规则 iptables -I FORWARD -i cni0 -o eth0 -j ACCEPT(假设 cni0 是桥接接口)。网络路径不是一条直线,而是由多个松耦合模块拼接而成。每层都有自己的缓存、队列、策略和错误码,跳过某一层的日志或状态检查,就可能把问题归因到完全错误的方向。