🚀 学习向复刻操作系统网络层:从零实现 IP/ARP/ICMP 核心机制

一、项目背景与核心定位

1.1 项目背景

在完整TCP/IP协议栈体系里,网络层是串联传输层与链路层的跨网段调度中枢。绝大多数开发者日常仅调用Socket接口、使用应用层协议,完全不清楚内核底层IP寻址、路由决策、分片重组、ARP地址解析、网络差错反馈整套底层逻辑。
本项目配套自研Socket抽象层、自研传输层TCP/UDP同步学习,通过手写基础网络层代码,同时吃透生产环境工业级拓展能力原理,打通整套协议栈底层知识链条。

1.2 核心目标

本项目仅用于底层网络原理学习,不完整手写工业级高并发、高安全复杂模块,采用「基础机制手写吃透、工业拓展仅懂原理、高难度组件复用成熟开源实现」的学习策略,两大核心目标:

  1. 手写ARP、IPv4、基础ICMP全套核心基础逻辑,吃透IP寻址、路由转发、分片重组、二层地址映射、网络差错处理底层原生实现;
  2. 完整梳理操作系统网络层为上层传输层屏蔽的海量底层工作,同时掌握NAT、防火墙钩子、策略路由等工业内核拓展能力,补齐网络层知识盲区,与Socket层、传输层形成完整协议栈知识闭环。

1.3 整体分层架构

┌─────────────────────────────────────────────────────────────┐
│                   应用层 (Application Layer)                  │
│  HTTP/FTP/SMTP/DNS... 基于Socket API进行网络通信            │
└──────────────────────────────┬──────────────────────────────┘
                               │
┌──────────────────────────────▼──────────────────────────────┐
│                  🖥️ 传输层 (Transport Layer)                 │
│  TCP/UDP 协议实现 · 端口管理 · 连接状态机 · 可靠传输机制      │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  TCP:三次握手/四次挥手 · 序列号/确认号 · 滑动窗口    │  │
│  │  超时重传 · 流量控制 · 拥塞控制基础算法              │  │
│  └──────────────────────────────────────────────────────┘  │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  UDP:无连接 · 无状态 · 尽力交付 · 端口多路复用       │  │
│  └──────────────────────────────────────────────────────┘  │
└──────────────────────────────┬──────────────────────────────┘
                               │
┌──────────────────────────────▼──────────────────────────────┐
│                  🌐 网络层 (Network Layer)                   │
│  IP/ARP/ICMP 协议 · 路由寻址 · 分片重组 · NAT/防火墙        │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  IP寻址与转发 · ARP地址解析 · ICMP差错控制            │  │
│  │  静态路由表 · IP分片与重组 · TTL生存周期              │  │
│  │  NAT地址转换 · Netfilter防火墙钩子 · 策略路由拓展     │  │
│  └──────────────────────────────────────────────────────┘  │
└──────────────────────────────┬──────────────────────────────┘
                               │
┌──────────────────────────────▼──────────────────────────────┐
│                  🔗 链路层 (Link Layer)                     │
│  以太网帧封装 · MAC地址寻址 · 网卡驱动接口                  │
└─────────────────────────────────────────────────────────────┘

核心设计原则

  • 分层解耦:每层只关心本层职责,通过标准接口与上下层交互,完全贴合真实操作系统协议栈分层设计;
  • 学习导向:重点手写基础协议核心机制,NAT、防火墙、动态路由等高复杂度工业特性仅了解原理,开发复用现成组件;
  • 可观测性:内置完整报文日志、状态统计、流转打印,可视化追踪IP分片、ARP交互、路由转发全流程;
  • 可测试性:支持单机互通、跨网段转发、ping连通性、分片异常等多场景集成测试,验证网络层功能正确性。

二、网络层完整全域职责

网络层是跨网段通信总调度中枢,分为基础刚需能力商用运维管控能力

(一)基础核心能力

  1. IP寻址:源/目的32位IPv4地址解析、本机多IP绑定;
  2. ARP地址解析:IP-MAC映射、缓存生命周期、请求应答;
  3. 路由决策(静态路由):最长前缀匹配、本机交付/跨网段转发判断;
  4. IP分片与重组:MTU适配、分片拆分、分片缓存拼接、重组超时回收;
  5. ICMP基础控制:ping探测、TTL超时、主机不可达基础差错上报;
  6. IP头部校验、TTL递减、上层协议分发(TCP=6/UDP=17/ICMP=1)。

(二)工业级拓展能力

  1. NAT地址转换:源NAT、目的NAT、端口映射、五元组会话跟踪表;
  2. 防火墙过滤钩子(Linux Netfilter / Windows WFP):报文五阶段拦截、修改、丢弃、限流;
  3. 高级路由:策略路由、多链路负载均衡、动态路由协议OSPF/RIP/BGP;
  4. 全链路PMTU探测、DF位精细化管控、TCP MSS自动适配;
  5. 多网卡管理、VLAN标签处理、IP隧道(GRE/VXLAN/WireGuard);
  6. 流量管控:QoS队列、带宽限速、报文优先级标记DSCP;
  7. 安全加固:IP源地址校验、防分片攻击、ARP防广播风暴、IP分片攻击防护。

三、网络层公共支撑底座

1. 完整路由表模块

手写基础部分
  1. 路由条目结构体:目标网段、子网掩码、下一跳IP、出口网卡ID;
  2. 匹配规则:最长掩码优先(主机路由 > 子网路由 > 默认网关);
  3. 基础接口:add_static_routedel_routelookup_route
  4. 转发决策分支:
    • 目标IP属于本机网卡地址 → 上交传输层;
    • 匹配跨网段路由 → 取对应下一跳IP,走ARP解析MAC转

伪代码示例:路由表最长前缀匹配

// 路由表条目结构
struct RouteEntry {
    uint32_t dest_network;  // 目标网络地址
    uint32_t netmask;       // 子网掩码
    uint32_t next_hop;      // 下一跳IP(0表示直连)
    int interface_id;       // 出口网卡ID
    int metric;             // 路由度量值(优先级)
};

// 最长前缀匹配算法
RouteEntry* lookup_route(uint32_t dest_ip, RouteEntry* table, int table_size) {
    RouteEntry* best_match = NULL;
    int longest_prefix = -1;
    
    for (int i = 0; i < table_size; i++) {
        RouteEntry* entry = &table[i];
        
        // 检查目标IP是否属于该路由条目
        if ((dest_ip & entry->netmask) == entry->dest_network) {
            // 计算前缀长度(掩码中1的个数)
            int prefix_len = count_ones(entry->netmask);
            
            // 选择最长前缀匹配
            if (prefix_len > longest_prefix) {
                longest_prefix = prefix_len;
                best_match = entry;
            }
        }
    }
    
    return best_match;  // 返回最佳匹配路由,可能为NULL(无默认路由时)
}

// 辅助函数:计算掩码中1的个数
int count_ones(uint32_t mask) {
    int count = 0;
    while (mask) {
        count += mask & 1;
        mask >>= 1;
    }
    return count;
}

发。

工业级拓展知识点
  1. 策略路由:不单纯依据目的IP匹配,可基于源IP、端口、协议、报文长度选择路由出口;多用于多宽带、多专线服务器;
  2. 动态路由:OSPF/RIP/BGP,设备之间自动交换路由表,无需手动配置静态路由;网关、云服务器必备;
  3. 路由缓存:内核缓存高频五元组路由结果,避免每次报文全表遍历,提升并发转发性能;
  4. 多链路负载均衡:多条网关分摊流量,故障自动切换链路。

2. ARP缓存哈希表

手写基础逻辑
  1. 缓存条目:目标IP、MAC地址、剩余超时、状态(未解析/已解析);
  2. 哈希存储+链表冲突解决,全局自旋锁并发保护;
  3. 定时器自动清理过期条目,避免缓存无限膨胀;
  4. 待发送报文队列:ARP未解析时缓存IP报文,收到应答后批量发

伪代码示例:ARP缓存哈希表操作

// ARP缓存条目
struct ARPCacheEntry {
    uint32_t ip_addr;           // 目标IP地址
    uint8_t mac_addr[6];        // 对应的MAC地址
    time_t timestamp;           // 最后更新时间
    int state;                  // 状态:0-未解析, 1-已解析, 2-过期
    struct list_head pending_packets;  // 等待发送的报文队列
};

// ARP缓存哈希表查找
ARPCacheEntry* arp_lookup(uint32_t target_ip) {
    int hash_index = hash_function(target_ip) % ARP_CACHE_SIZE;
    ARPCacheEntry* entry = arp_cache[hash_index];
    
    // 遍历链表处理哈希冲突
    while (entry != NULL) {
        if (entry->ip_addr == target_ip) {
            // 检查是否过期
            if (time(NULL) - entry->timestamp > ARP_TIMEOUT) {
                entry->state = 2;  // 标记为过期
                return NULL;
            }
            return entry;  // 找到有效条目
        }
        entry = entry->next;
    }
    
    return NULL;  // 未找到
}

// ARP请求发送
void arp_request(uint32_t target_ip) {
    // 创建ARP请求报文
    ARPPacket request;
    request.opcode = ARP_REQUEST;
    request.sender_ip = local_ip;
    memcpy(request.sender_mac, local_mac, 6);
    request.target_ip = target_ip;
    memset(request.target_mac, 0xFF, 6);  // 广播MAC
    
    // 发送到链路层
    link_send(broadcast_mac, ETH_TYPE_ARP, (uint8_t*)&request, sizeof(request));
}

// ARP响应处理
void arp_reply_process(ARPPacket* reply) {
    ARPCacheEntry* entry = arp_lookup(reply->sender_ip);
    if (entry == NULL) {
        // 创建新缓存条目
        entry = create_arp_entry(reply->sender_ip);
    }
    
    // 更新MAC地址和状态
    memcpy(entry->mac_addr, reply->sender_mac, 6);
    entry->state = 1;  // 已解析
    entry->timestamp = time(NULL);
    
    // 发送缓存的等待报文
    send_pending_packets(entry);
}

送。

工业级拓展优化
  1. ARP请求限流:同一IP短时间多次请求合并,杜绝广播风暴;
  2. 免费ARP:网卡上线主动广播自身IP-MAC,快速更新全网缓存;
  3. ARP代理:跨网段转发ARP应答,适配三层网关;
  4. 防ARP欺骗:静态ARP绑定、ARP报文校验过滤,防火墙联动拦截伪造ARP。

3. 全局定时器底座

手写复用统一定时器,承载:

  • ARP缓存过期回收;
  • IP分片重组超时释放缓存;
    工业拓展:NAT会话超时定时器、防火墙连接跟踪定时器。

4. 通用IP报文缓冲区

手写:malloc/free临时分配释放报文,满足学习调试;
工业内核优化(不手写):skb内存缓冲区、分片复合内存、内存池预分配,减少内存碎片、零拷贝支持。

四、手写子系统1:ARP 完整底层实现

发送流程

  1. IP路由查表得到下一跳IP;
  2. 查询ARP缓存:
    • 有效缓存:直接取出MAC封装以太网帧;
    • 无缓存:创建未解析条目,缓存待发IP报文,广播ARP请求;
  3. ARP请求报文封装:源IP、源MAC、目标IP,广播MAC FF:FF:FF:FF:FF:FF。

接收流程

  1. 区分ARP请求 / ARP应答;
  2. 应答报文:刷新ARP缓存,唤醒阻塞发送队列,发送缓存报文;
  3. 请求报文:若目标IP为本机IP,组装ARP应答原路回复;
  4. 刷新缓存超时计时器。

五、手写子系统2:IPv4 核心模块

1. IP头部结构与校验和

基础20字节IP头,舍弃可选Options字段(工业拓展才用到)
关键字段:版本、IHL、总长度、标识、分片标志+片偏移、TTL、上层协议、源IP、目的IP、头部校验和
校验和规则:仅计算IP头部,16bit累加取反,接收校验失败直接丢弃报文。

2. IP分片与重组

发送分片逻辑
  1. 以太网MTU=1500,IP总长度超过MTU自动拆分;
  2. 所有分片共用同一个标识ID,片偏移标记分段位置(单位8字节);
  3. MF标志位:最后一片MF=0,其余分片MF=1;
  4. DF不分片标记置1时,禁止分片,返回ICMP不可达报

伪代码示例:IP分片发送逻辑

// IP分片结构
struct IPFragment {
    uint16_t id;           // 分片标识符
    uint16_t offset;       // 片偏移(单位:8字节)
    uint16_t total_len;    // 原始IP报文总长度
    uint8_t mf_flag;       // 更多分片标志
    uint8_t* data;         // 分片数据
    size_t data_len;       // 分片数据长度
};

// IP分片发送函数
void ip_fragment_and_send(uint32_t src_ip, uint32_t dst_ip, uint8_t proto, 
                          uint8_t* payload, uint16_t total_len) {
    uint16_t mtu = 1500;      // 以太网MTU
    uint16_t ip_header_len = 20;  // IP头部长度
    uint16_t max_data_per_fragment = mtu - ip_header_len;
    uint16_t fragment_id = generate_fragment_id();
    
    // 计算需要多少分片
    int num_fragments = (total_len + max_data_per_fragment - 1) / max_data_per_fragment;
    
    for (int i = 0; i < num_fragments; i++) {
        uint16_t offset = i * (max_data_per_fragment / 8);  // 转换为8字节单位
        uint16_t fragment_len;
        uint8_t mf_flag = (i < num_fragments - 1) ? 1 : 0;  // 最后一片MF=0
        
        // 计算当前分片的数据长度
        if (i == num_fragments - 1) {
            fragment_len = total_len - i * max_data_per_fragment;
        } else {
            fragment_len = max_data_per_fragment;
        }
        
        // 创建IP头部
        IPHeader ip_header;
        ip_header.version_ihl = 0x45;      // IPv4, 头部长度5*4=20字节
        ip_header.total_length = htons(ip_header_len + fragment_len);
        ip_header.id = htons(fragment_id);
        ip_header.frag_offset = htons((offset & 0x1FFF) | (mf_flag << 13));
        ip_header.ttl = 64;
        ip_header.protocol = proto;
        ip_header.src_addr = src_ip;
        ip_header.dst_addr = dst_ip;
        ip_header.checksum = ip_checksum(&ip_header);
        
        // 发送分片
        send_fragment(&ip_header, payload + i * max_data_per_fragment, fragment_len);
    }
}

文。

接收重组逻辑
  1. 重组唯一Key:源IP+目的IP+IP标识+上层协议;
  2. 独立重组缓冲区,按片偏移填充分段;
  3. 全部分片抵达且MF=0,拼接完整IP报文上交上层;
  4. 重组定时器超时缺失分片,释放缓冲区丢弃全部分段

伪代码示例:IP分片重组逻辑

// 分片重组缓冲区条目
struct ReassemblyBuffer {
    uint32_t src_ip;
    uint32_t dst_ip;
    uint16_t id;
    uint8_t protocol;
    time_t last_update;      // 最后更新时间
    uint8_t* data_buffer;    // 重组缓冲区
    uint16_t total_len;      // 完整报文总长度
    uint16_t received_len;   // 已接收数据长度
    uint8_t fragment_map[8192];  // 分片到达位图
};

// 分片重组处理
int ip_reassemble_fragment(IPHeader* ip_header, uint8_t* fragment_data) {
    // 生成重组键值
    uint32_t key = hash_function(ip_header->src_addr, ip_header->dst_addr, 
                                 ip_header->id, ip_header->protocol);
    
    // 查找或创建重组缓冲区
    ReassemblyBuffer* buffer = find_reassembly_buffer(key);
    if (buffer == NULL) {
        buffer = create_reassembly_buffer(ip_header);
    }
    
    // 计算分片偏移和数据长度
    uint16_t fragment_offset = (ntohs(ip_header->frag_offset) & 0x1FFF) * 8;
    uint16_t fragment_len = ntohs(ip_header->total_length) - IP_HEADER_LEN;
    
    // 检查分片是否重叠或超出范围
    if (!validate_fragment(buffer, fragment_offset, fragment_len)) {
        return -1;  // 无效分片
    }
    
    // 复制分片数据到缓冲区
    memcpy(buffer->data_buffer + fragment_offset, fragment_data, fragment_len);
    
    // 更新接收状态
    update_fragment_map(buffer, fragment_offset, fragment_len);
    buffer->received_len += fragment_len;
    buffer->last_update = time(NULL);
    
    // 检查是否所有分片都已到达
    uint8_t mf_flag = (ntohs(ip_header->frag_offset) >> 13) & 0x01;
    if (mf_flag == 0 && is_complete(buffer)) {
        // 所有分片已到达,提交完整报文给上层
        deliver_reassembled_packet(buffer);
        free_reassembly_buffer(buffer);
        return 1;  // 重组完成
    }
    
    return 0;  // 等待更多分片
}

// 重组超时清理
void cleanup_timeout_reassembly() {
    time_t now = time(NULL);
    for (each buffer in reassembly_table) {
        if (now - buffer->last_update > REASSEMBLY_TIMEOUT) {
            free_reassembly_buffer(buffer);  // 超时释放
        }
    }
}
工业级拓展分片管控
  1. 分片攻击防护:限制单IP最大分片缓存数量,防止内存耗尽;
  2. PMTU完整探测:持续ICMP反馈,同步通知TCP调整MSS,全程避免分片;
  3. 超大报文分片队列限速,高并发网关必备。

3. IP完整收发链路

发送链路:传输层TCP/UDP → IP → ARP → 链路层
  1. 接收传输层载荷、源目IP、协议号;
  2. 组装IP头部,计算头部校验和;
  3. 判断报文长度,执行分片;
  4. 路由查表匹配下一跳IP;
  5. ARP解析目标MAC;
  6. 封装以太网帧下发链路层

伪代码示例:IP发送链路完整流程

// IP层发送主函数
int ip_send(uint32_t src_ip, uint32_t dst_ip, uint8_t proto, 
            uint8_t* payload, uint16_t payload_len) {
    
    // 1. 组装IP头部
    IPHeader ip_header;
    ip_header.version_ihl = 0x45;  // IPv4, 头部长度20字节
    ip_header.tos = 0;
    ip_header.total_length = htons(IP_HEADER_LEN + payload_len);
    ip_header.id = htons(generate_packet_id());
    ip_header.frag_offset = htons(0x4000);  // DF=1, MF=0, offset=0
    ip_header.ttl = DEFAULT_TTL;
    ip_header.protocol = proto;
    ip_header.src_addr = src_ip;
    ip_header.dst_addr = dst_ip;
    ip_header.checksum = 0;
    ip_header.checksum = ip_checksum(&ip_header);
    
    // 2. 检查是否需要分片
    uint16_t mtu = get_interface_mtu(src_ip);
    if (IP_HEADER_LEN + payload_len > mtu) {
        if (ip_header.frag_offset & 0x4000) {  // DF位被设置
            // 发送ICMP不可达报文(需要分片但DF置位)
            send_icmp_frag_needed(src_ip, dst_ip, mtu);
            return -1;
        }
        // 执行分片
        return ip_fragment_and_send(&ip_header, payload, payload_len);
    }
    
    // 3. 路由查找
    RouteEntry* route = lookup_route(dst_ip);
    if (route == NULL) {
        // 无路由,发送ICMP主机不可达
        send_icmp_dest_unreachable(src_ip, dst_ip);
        return -1;
    }
    
    // 4. ARP解析下一跳MAC
    uint8_t next_hop_mac[6];
    if (route->next_hop == 0) {  // 直连网络
        next_hop_ip = dst_ip;
    } else {
        next_hop_ip = route->next_hop;
    }
    
    int arp_result = arp_resolve(next_hop_ip, next_hop_mac);
    if (arp_result != 0) {
        // ARP解析失败,报文进入等待队列
        queue_packet_for_arp(next_hop_ip, &ip_header, payload, payload_len);
        return 0;  // 异步等待ARP响应
    }
    
    // 5. 封装以太网帧并发送
    uint8_t packet[mtu];
    memcpy(packet, &ip_header, IP_HEADER_LEN);
    memcpy(packet + IP_HEADER_LEN, payload, payload_len);
    
    return link_send(next_hop_mac, ETH_TYPE_IP, packet, IP_HEADER_LEN + payload_len);
}
接收链路:链路层帧 → IP解析 → 分片重组 → 分发上层
  1. 剥离以太网头部,提取IP报文;
  2. 校验IP头部校验和,损坏丢弃;
  3. 判断分片,存入重组缓冲区等待补齐;
  4. 完整报文执行路由判断:
    • 本机IP:根据协议号分发给TCP/UDP/ICMP;
    • 跨网段转发:TTL-1,TTL=0则丢弃并发送ICMP超时报文,重新路由转发。

4. TTL生存周期处理

报文每经过一台路由设备,TTL数值减1;TTL归零直接丢弃,生成ICMP超时差错报文回源,防止报文无限循环全网广播。

六、手写子系统3:ICMP基础模块

手写实现两类核心报文

  1. ECHO请求/应答(ping连通性探测);收到本机ping请求,自动回复应答;
  2. 基础差错报文:目标主机不可达、TTL超时。

工业级ICMP拓展

  1. PMTU探测报文(DF置位分片失败反馈,联动TCP动态调整MSS);
  2. 源抑制报文、重定向路由报文;
  3. ICMP速率限制,防止恶意ICMP洪水攻击。

七、工业级网络层拓展模块详细原理

拓展1:NAT 地址转换(网关、容器、家庭路由核心)

核心原理

内网私有IP无法公网路由,NAT维护五元组会话表,转换IP/端口实现多主机共用单一公网IP上网。

  1. SNAT源NAT:内网主机出网,替换源IP/端口为公网地址,记录会话;回程报文查表还原源IP;
  2. DNAT目的NAT:公网访问公网端口,转发至内网指定主机端口(端口映射);
  3. FULL NAT:同时转换源、目的IP,多用于云负载均衡;
  4. 配套机制:会话超时自动回收、端口池管理、连接跟踪表conntrack;
学习方案:不用手写,直接复用开源lwIP NAT模块、Linux iptables conntrack。

拓展2:防火墙钩子框架(Linux Netfilter / Windows WFP)

设计原理:报文五阶段预埋拦截点,全链路管控所有IP报文

Linux Netfilter 五大钩子点:

  1. PREROUTING:报文刚进入网卡,路由决策前;DNAT、报文修改;
  2. INPUT:目标为本机的报文,过滤本机入站流量;
  3. FORWARD:跨网段转发报文,网关核心过滤;
  4. OUTPUT:本机程序向外发送的报文;
  5. POSTROUTING:报文即将离开网卡,SNAT、QoS标记;
    可实现能力:报文丢弃/放行、修改IP头部、限速、日志记录、端口转发、封禁IP。
学习方案:仅梳理钩子流转逻辑,底层过滤代码复用成熟内核组件,无需自研。

拓展3:多网卡、VLAN、隧道协议

  1. VLAN:二层标签隔离多网段,IP层识别VLAN接口区分路由;
  2. 隧道GRE/VXLAN:把IP报文封装在另一个IP载荷中,实现跨公网内网互通;
  3. 多网卡地址绑定:多IP、多网关、故障切换;
    学习仅理解封装解封装流程,驱动与隧道复用开源实现。

拓展4:QoS与DSCP流量调度

IP头部DSCP字段标记报文优先级,网卡出口队列按优先级调度带宽,音视频、业务流量优先转发,拥塞时丢弃低优先级报文;工业网关、云服务器必备,无需手写队列调度。

八、网络层 ↔ 上下层标准解耦接口

向上对接传输层(TCP/UDP调用)

// 传输层下发载荷,交由IP层发送
int ip_send(uint32_t src_ip, uint32_t dst_ip, uint8_t proto, uint8_t *payload, uint16_t len);
// IP层完整报文回调分发给传输层
void ip_recv_callback(uint8_t proto, uint8_t *payload, uint16_t len, uint32_t src_ip, uint32_t dst_ip);

传输层完全不感知路由、ARP、分片、NAT、防火墙,仅传入基础参数。

向下对接链路层

int link_send(uint8_t *dst_mac, uint16_t eth_type, uint8_t *data, uint16_t len);
void link_recv_callback(uint8_t *eth_frame, uint16_t frame_len);

网络层屏蔽硬件网卡、二层帧细节。

工业拓展挂载接口(预留钩子)

  1. 报文入栈钩子:PREROUTING 过滤/NAT;
  2. 转发钩子:FORWARD 防火墙限流;
  3. 报文出栈钩子:POSTROUTING SNAT、DSCP标记;
    分层解耦设计:基础IP/ARP逻辑不变,工业管控模块以插件钩子形式挂载,符合真实操作系统内核模块化设计。

九、完整端到端全链路

  1. 上层Socket send写入数据 → TCP传输层封装头部;
  2. TCP调用ip_send下发网络层;
  3. 网络层基础流程:IP头封装 → 分片 → 静态路由查表;
  4. 【工业拓展钩子】PREROUTING 钩子:NAT转换、防火墙过滤丢弃非法报文;
  5. ARP解析下一跳MAC;
  6. 【工业拓展钩子】POSTROUTING:SNAT、DSCP流量标记;
  7. 封装以太网帧下发链路层;
  8. 对端接收帧 → IP解析重组分片 → 【INPUT钩子】本机入站防火墙校验 → 分发给TCP;
  9. TCP回复ACK报文反向完整走一遍网络层、钩子、NAT流程。

十、网络层分层难点拆分

(一)手写必攻克难点

  1. IP分片重组:片偏移、标识匹配、超时内存回收,数值换算极易出错;
  2. ARP并发竞争:多连接同时请求同一IP,缓存链表无锁直接崩溃;
  3. 路由最长掩码匹配算法,匹配错误导致跨网段不通;
  4. IP头部校验和、分片偏移8字节单位换算细节易错。

(二)工业拓展模块高难度点

  1. NAT会话跟踪:海量五元组会话表并发读写、超时回收、端口池管理;
  2. Netfilter多钩子并发锁:多阶段过滤共享连接跟踪表,锁粒度设计复杂;
  3. 动态路由协议状态机、路由收敛算法;
  4. QoS多级队列调度、带宽公平限流算法;
  5. 防攻击体系:分片洪水、ARP欺骗、ICMP洪水、SYN洪水联动拦截。

十一、三层网络架构职责对照表

分层 手写实现内容 工业级拓展能力(复用组件) 屏蔽上层的全部复杂工作
Socket抽象层 阻塞bind/connect/send/recv/close、缓冲区、句柄管理 IOCP/epoll多路复用、setsockopt全量配置 文件描述符、IO阻塞、连接资源回收
传输层TCP/UDP 状态机、序列号、滑动窗口、基础重传、五元组哈希 SACK、BBR拥塞控制、TCP Fast Open、保活高级配置 可靠传输、丢包修复、流量控制、连接生命周期
网络层IP/ARP/ICMP 寻址、静态路由、ARP缓存、IP分片重组、基础ICMP NAT、防火墙钩子、策略路由、动态路由、VLAN/隧道、QoS 跨网段转发、二层地址映射、分片、流量管控、安全过滤

十二、学习复刻实操建议

  1. 手写范围锁定:ARP、基础IPv4、静态路由、分片重组、ping基础ICMP,完整跑通单机、跨网段互通,吃透分层底层逻辑;
  2. 工业级模块学习方案
    • NAT、Netfilter防火墙、策略路由、动态路由只梳理工作流程、报文流转、核心数据结构;
    • 开发时直接复用lwIP、DPDK、Linux内核成熟网络组件,不从零手写高并发高复杂度逻辑;
  3. 分层严格解耦,预留钩子扩展接口,模拟真实操作系统内核插件化设计,既能满足底层原理学习,又完整掌握工业生产环境网络层全套管控能力;
  4. 结合传输层、Socket层全套复刻内容,完整贯通从用户态读写字节到网卡二层帧收发的全栈网络底层逻辑。

十三、整体总结

  1. 网络层是TCP/IP栈跨网段通信调度核心,由ARP(二层地址映射)、IPv4(寻址分片转发)、ICMP(差错探测)三大子系统构成,独立介于传输层与链路层中间;
  2. 复刻网络层可以亲手实现路由匹配、ARP缓存、IP分片重组、ICMP差错反馈全套底层逻辑,直观看到操作系统内核替传输层屏蔽了寻址、分片、二层映射等大量底层操作;
  3. 分层接口严格解耦,传输层仅需调用极简ip_send接口,完全不感知路由、ARP、MTU分片细节,完美体现TCP/IP分层设计“下层实现变更,上层无感知”的核心思想;
  4. 区分学习手写模块工业级拓展模块,既吃透底层原理、能从零写核心代码,又掌握生产环境必备的高级网络能力,不重复造轮子、不缺失工业认知;
  5. 结合Socket层、传输层复刻内容,完整打通「用户态Socket → 传输层TCP/UDP → 网络层IP/ARP → 链路层」完整协议栈底层逻辑,彻底补齐操作系统网络子系统全栈知识盲区。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐