【Linux网络】网络层 IP 协议:从网段划分到内核源码解析

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》

《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔

《Git深度解析》:版本管理实战全解 《Qt 极境架构》MySQL 核心技术与实战

🌟心向往之行必能


🎥Cx330🌸的简介:


目录

前言:

[一. 网段划分:IP 地址的 "身份证" 与 "家庭住址"](#一. 网段划分:IP 地址的 "身份证" 与 "家庭住址")

[1.1 IP 地址的本质:网络号 + 主机号](#1.1 IP 地址的本质:网络号 + 主机号)

[1.2 早期方案:分类划分法(A/B/C/D/E 类)](#1.2 早期方案:分类划分法(A/B/C/D/E 类))

[1.3 进化版:CIDR 无类别域间路由与子网掩码](#1.3 进化版:CIDR 无类别域间路由与子网掩码)

[1.4 懒人福音:DHCP 自动 IP 分配](#1.4 懒人福音:DHCP 自动 IP 分配)

[二. 为什么要划分子网?从 "大海捞针" 到 "精准定位"](#二. 为什么要划分子网?从 "大海捞针" 到 "精准定位")

[三. IP 协议的核心补充知识](#三. IP 协议的核心补充知识)

[3.1 那些特殊的 IP 地址](#3.1 那些特殊的 IP 地址)

[3.2 IPv4 地址危机与解决方案](#3.2 IPv4 地址危机与解决方案)

[3.3 私有 IP 与公网 IP:内网与外网的边界](#3.3 私有 IP 与公网 IP:内网与外网的边界)

[3.4 NAT 技术:拯救 IPv4 的 "幕后英雄"](#3.4 NAT 技术:拯救 IPv4 的 "幕后英雄")

[四. IP 协议头格式与源码解读](#四. IP 协议头格式与源码解读)

[4.1 IPv4 协议头完整解析](#4.1 IPv4 协议头完整解析)

[4.2 Linux 内核中的 iphdr 结构体详解](#4.2 Linux 内核中的 iphdr 结构体详解)

[五. 路由:数据包的 "导航系统"](#五. 路由:数据包的 "导航系统")

[1. 本地网段判断与 ARP](#1. 本地网段判断与 ARP)

[2. 路由表查找(最长前缀匹配原则)](#2. 路由表查找(最长前缀匹配原则))

[3. 数据包逐跳转发(Hop-by-Hop)](#3. 数据包逐跳转发(Hop-by-Hop))

结尾:


前言:

在互联网的庞大世界中,每天有数以千亿计的数据包在不同的设备之间穿梭。如果我们把互联网比作庞大的邮政物流网络,那么 IP 协议(Internet Protocol) 就是整个网络的基石,它为每一个连接进来的设备颁发"地址",并制定了数据包投递的基本法则。

无论你是正在学习计算机网络的学生,还是希望深入研究网络排错与高性能网络编程的开发者,深刻理解 IP 协议及其底层机制都是不可或缺的基本功。本文将严格按照网段划分、子网掩码、特殊地址、IPv4 协议头以及 Linux 内核源码等维度,全方位带你拆解 IP 协议的核心秘密。


一. 网段划分:IP 地址的 "身份证" 与 "家庭住址"

1.1 IP 地址的本质:网络号 + 主机号

在 IPv4 协议中,一个 IP 地址由 32 位二进制数(4 字节) 组成。为了方便人类阅读,通常采用 点分十进制(Dotted Decimal Notation) 表示,例如 192.168.1.1

从逻辑上看,一个 IP 地址被划分为两个核心部分:

  • 网络号(Network ID):标识该设备属于哪一个独立的物理或逻辑网络(类似于"省/市/小区")。

  • 主机号(Host ID):标识该设备在其所在的网络内部是哪一台具体的主机(类似于"门牌号")。

公式:网络号 + 主机号 = 子网(局域网)

例如192.168.128.10/24中,/24表示前 24 位是网络号(192.168.128),后 8 位是主机号(10)。

复制代码
+-----------------------------------+-----------------------------------+
|            网络号 (Network ID)      |           主机号 (Host ID)         |
+-----------------------------------+-----------------------------------+
|<------------------------------ 32 Bits ------------------------------->|

当源主机向目标主机发送数据包时,路由器首先根据目标 IP 的网络号 进行跨网路由,到达目标网络后,再根据主机号将数据精确送达对应的主机。

1.2 早期方案:分类划分法(A/B/C/D/E 类)

在互联网发展初期,RFC 791 提出了分类 IP 地址(Classful Addressing) 方案,将 32 位的地址空间划分为 5 大类:

类别 首位固定比特 网络号长度 主机号长度 网络号范围 默认子网掩码 单网络最大主机数 主要用途
A 类 0 8 bits 24 bits 1.0.0.0 ~ 126.0.0.0 255.0.0.0 2^24-2 = 16,777,214 超大型网络
B 类 10 16 bits 16 bits 128.0.0.0 ~ 191.255.0.0 255.255.0.0 2^16-2 = 65,534 中型网络/企业
C 类 110 24 bits 8 bits 192.0.0.0 ~ 223.255.255.0 255.255.255.0 2^8-2 = 254 小型局域网
D 类 1110 - - 224.0.0.0 ~ 239.255.255.255 - - 组播(Multicast)
E 类 1111 - - 240.0.0.0 ~ 255.255.255.255 - - 保留/科研测试

传统分类划分法的缺陷: 颗粒度过于粗糙。申请一个 B 类网络拥有 6.5 万个地址,对于中小型企业来说根本用不完;而申请 C 类网络仅有 254 个可用地址,又极易不够用。这导致了早期 IPv4 地址空间的严重浪费。

1.3 进化版:CIDR 无类别域间路由与子网掩码

为了彻底解决分类 IP 地址的浪费问题,1993 年推出了 CIDR(Classless Inter-Domain Routing,无类别域间路由)

CIDR 放弃了固定的 A/B/C 类界限,引入了 子网掩码(Subnet Mask) 。 子网掩码是一个 32 位的二进制数,其高位连续的 1 表示网络号,低位连续的 0 表示主机号

例如,对于 CIDR 记法 192.168.1.100/24

  • /24 表示前 24 位为网络号(子网掩码为 255.255.255.0)。

  • 计算网络地址的过程是:将 IP 地址与子网掩码进行按位与(AND)运算。

二进制计算示例:

复制代码
  IP 地址:   192.168.00000001.01100100  (192.168.1.100)
  子网掩码:  255.255.11111111.00000000  (255.255.255.0)
  ----------------------------------------------------
  网络地址:  192.168.00000001.00000000  (192.168.1.0)

通过 CIDR,网络管理者可以根据需要任意划分网段大小(例如 /27 可以提供2^32-27-2 = 30 个可用地址),大大提升了 IP 地址的利用效率。

1.4 懒人福音:DHCP 自动 IP 分配

手动配置 IP 地址、子网掩码、网关和 DNS 既繁琐又容易发生地址冲突。DHCP(Dynamic Host Configuration Protocol,动态主机配置协议) 应运而生。

DHCP 运行在 UDP 协议之上(服务端端口 67,客户端端口 68),采用 DORA 交互模型 自动给新接入的主机分配 IP 地址:

复制代码
 Client                                           DHCP Server
   |                                                   |
   | -------- 1. DHCP Discover (广播 255.255.255.255) -> |
   |                                                   |
   | <------- 2. DHCP Offer (单播/广播 提供 IP 建议) --- |
   |                                                   |
   | -------- 3. DHCP Request (广播 请求租用 IP) -------> |
   |                                                   |
   | <------- 4. DHCP ACK (单播/广播 确认配置) -------- |
   |                                                   |
  1. Discover(发现):客户端刚入网,不知道任何信息,发出广播包询问"网络中有 DHCP 协议服务器吗?"。

  2. Offer(提供):DHCP 服务器收到后,从预留地址池挑选一个未使用 IP,发出回应。

  3. Request(请求):客户端选择其中一个 Offer,发广播包确认"我打算租用这个 IP"。

  4. ACK(确认):服务器确认租期(Lease Time)及配置(子网掩码、网关、DNS 等),完成分配。


二. 为什么要划分子网?从 "大海捞针" 到 "精准定位"

我们用一个 "归还钱包" 的故事来理解子网划分的意义:

  • 学校分为多个学院,学号 = 院号(网络号)+ 个人编号(主机号)
  • 张三捡到李四的钱包,只看到学号06321
  • 张三首先判断院号06不是自己学院的,直接找本院学生会主席(路由器)
  • 主席将消息转发到校群(公网),找到机械学院主席(目标网段路由器)
  • 机械学院主席在本院群(目标子网)找到李四

核心结论 :划分子网的本质是提高路由查找效率。路由的本质是 "排除法",通过网络号可以一次性排除整个网段的设备,而不是逐个遍历所有主机。如果没有子网划分,全球几十亿设备在同一个网络中,路由查找将变成 "大海捞针",网络根本无法正常运行。


三. IP 协议的核心补充知识

3.1 那些特殊的 IP 地址

在 IPv4 地址空间中,有几类特殊的 IP 地址具有特殊用途,不能作为普通主机地址分配:

  • 0.0.0.0/8:代表"任意地址"或"本网络中的本主机"。在路由表中常用作默认路由(Default Route) 的目标网络。

  • 127.0.0.0/8(环回地址 Loopback) :最典型的是 127.0.0.1。发往该地址的数据包不会经过物理网卡传出,而是直接由内核环回驱动(lo)接收,常用于本机服务测试与进程间通信。

  • 广播地址

    • 受限广播地址255.255.255.255,代表当前局域网内的所有主机(路由器不转发此广播)。

    • 直接广播地址 :主机号全为 1 的地址(例如 192.168.1.255/24),发往特定网段的所有主机。

  • 网络地址 :主机号全为 0的地址(例如 192.168.1.0/24),代表该网段本身。

  • APIPA 地址(169.254.0.0/16):自动私有 IP 地址。当主机开启了 DHCP 却未能成功联系上 DHCP 服务器时,系统会自动从该网段随机挑选一个 IP 进行临时局域网通信。

3.2 IPv4 地址危机与解决方案

IPv4 总共只能提供 2^32 = 42.9 亿个地址。随着移动互联网和物联网的爆发,IPv4 地址早在 2011 年(IANA 正式耗尽)就已经告罄。

为了解决危机,网络工程界提出了"治标"与"治本"两类方案:

  • 短期/过渡方案(治标) :CIDR(减少浪费)、私有 IP + NAT 技术(极大提升单个公网 IP 的容纳能力)。

  • 终极方案(治本) :全面升级至 IPv6。IPv6 使用 128 位地址空间,可提供 2^128 = 3.4 * 10^38 个地址,号称能为地球上的"每一粒沙子都分配一个 IP"。

3.3 私有 IP 与公网 IP:内网与外网的边界

根据 RFC 1918 规范,IPv4 预留了三块地址空间专门用于局域网内部通信,即 私有 IP(Private IP)

Class 私有 IP 地址范围 网段段数/大小
A 类 10.0.0.0 ~ 10.255.255.255 10.0.0.0/8 (1 个 A 类)
B 类 172.16.0.0 ~ 172.31.255.255 172.16.0.0/12 (16 个连续 B 类)
C 类 192.168.0.0 ~ 192.168.255.255 192.168.0.0/16 (256 个连续 C 类)
  • 私有 IP :可以在全球不同的企业或家庭局域网内部重复使用 ,但在公网路由器上是不可路由的(公网路由器会直接丢弃源或目的为私有 IP 的数据包)。

  • 公网 IP :由运营商(ISP)统一分配,在全球范围内具有唯一性,可以直接在互联网上传输。

3.4 NAT 技术:拯救 IPv4 的 "幕后英雄"

NAT(Network Address Translation,网络地址转换) 是使得现代多台设备共享一个公网 IP 访问互联网的幕后功臣。最常用的是 NAPT(网络地址端口转换 / Port Address Translation)

  • 路由器有两个 IP:LAN 口 IP (内网网关,如192.168.1.1)和WAN 口 IP(运营商分配的公网 IP)

  • 内网设备访问外网时,路由器会将数据包的源 IP替换为自己的 WAN 口 IP

  • 响应数据包返回时,路由器再将目的 IP替换为对应的内网设备 IP

  • 多级 NAT:家用路由器→运营商路由器→公网,逐级替换 IP 地址

    [ 内网主机 ] [ 路由器 (NAT) ] [ 公网服务器 ]
    192.168.1.100:50001 公网 IP: 1.2.3.4 93.184.216.34:80
    | | |
    | ------ 1. 发送请求数据包 ------------------> | |
    | Src: 192.168.1.100:50001 | |
    | Dst: 93.184.216.34:80 | |
    | | -- 2. 转换源 IP 与端口并发送 --------------> |
    | | Src: 1.2.3.4:61001 |
    | | Dst: 93.184.216.34:80 |
    | | |
    | | <-- 3. 响应数据包 ----------------------- |
    | | Src: 93.184.216.34:80 |
    | | Dst: 1.2.3.4:61001 |
    | <----- 4. 根据 NAT 表项映射还原并转发 -------- | |
    | Src: 93.184.216.34:80 | |
    | Dst: 192.168.1.100:50001 | |

NAT 映射表结构示例如下:

内网 IP:端口 外网映射 IP:端口 目标 IP:端口
192.168.1.100:50001 1.2.3.4:61001 93.184.216.34:80
192.168.1.101:50001 1.2.3.4:61002 93.184.216.34:80

NAT 极大地延缓了 IPv4 地址枯竭的速度,但也破坏了 IP 的"端到端透明通信"原则,导致内网设备主动提供公网服务时需要进行"端口映射(Port Forwarding)"。


四. IP 协议头格式与源码解读

4.1 IPv4 协议头完整解析

IPv4 报文由 IP 报头(Header)数据载荷(Payload) 组成。一个不带选项的标准 IPv4 报头长度固定为 20 字节

复制代码
 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |        Header Checksum        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source IP Address                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination IP Address                     |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options (if IHL > 5)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

各字段功能详解:

  1. 版本号(Version, 4 bits) :对 IPv4 而言值为 4

  2. 首部长度(IHL - Internet Header Length, 4 bits) :以 4 字节(32 位 Word)为单位。最小值为 5(即 5 * 4 = 20 字节),最大值为 15(即 60 字节)。

  3. 服务类型(ToS / DiffServ, 8 bits):用于 QoS 服务质量控制,标记数据包的优先级与延迟要求。

  4. 总长度(Total Length, 16 bits):整个 IP 数据包(首部 + 数据)的总字节数。理论最大值为 2^16-1 = 65,35 字节。

  5. 标识(Identification, 16 bits):用于分片重组。属于同一个原始数据包的分片拥有相同的标识值。

  6. 标志位(Flags, 3 bits)

    • Bit 0: 保留,必须为 0。

    • Bit 1: DF (Don't Fragment):置 1 表示禁止路由器分片。

    • Bit 2: MF (More Fragments):置 1 表示后面还有分片,置 0 表示最后一个分片。

  7. 片偏移(Fragment Offset, 13 bits) :指示当前分片相对于原始数据载荷起始位置的偏移量,单位为 8 字节

  8. 生存时间(TTL - Time to Live, 8 bits):数据包能经过的最大路由器跳数(Hop)。每经过一个路由器该值减 1,减至 0 时被丢弃,并向源端发送 ICMP Time Exceeded 报文,防止路由环路死循环。

  9. 上层协议(Protocol, 8 bits) :标识 IP 载荷中传输的上层协议(例如:ICMP 为 1,TCP 为 6,UDP 为 17)。

  10. 首部校验和(Header Checksum, 16 bits):仅校验 IP 报头自身的完整性(数据部分由传输层校验)。

  11. 源 IP / 目的 IP(Source/Destination IP Address, 32 bits):数据包的发送方与接收方地址。

4.2 Linux 内核中的 iphdr 结构体详解

在 Linux 内核网络协议栈源码(如 <linux/ip.h>)中,IPv4 报头被直接定义为 struct iphdr

复制代码
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
    __u8    ihl:4,          /* 首部长度 (Internet Header Length) */
            version:4;      /* 版本号 (Version) */
#elif defined(__BIG_ENDIAN_BITFIELD)
    __u8    version:4,
            ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif
    __u8    tos;            /* 服务类型 (Type of Service) */
    __be16  tot_len;        /* 总长度 (Total Length) */
    __be16  id;             /* 标识 (Identification) */
    __be16  frag_off;       /* 标志位 (Flags) + 片偏移 (Fragment Offset) */
    __u8    ttl;            /* 生存时间 (Time to Live) */
    __u8    protocol;       /* 上层协议 (Protocol) */
    __sum16 check;          /* 首部校验和 (Header Checksum) */
    __be32  saddr;          /* 源地址 (Source Address) */
    __be32  daddr;          /* 目的地址 (Destination Address) */
    /* The options start here. */
};

源码中的技术细节解读

  1. 位域与字节序(Bitfield & Endianness) :C 语言结构体使用位域 :4划分高 4 位与低 4 位。由于网络字节序是大端模式,而主机可能为小端模式,内核必须根据 __LITTLE_ENDIAN_BITFIELD__BIG_ENDIAN_BITFIELD来颠倒 ihlversion的定义顺序。

  2. __be16__be32 类型 :前缀 __be 表示 Big Endian(大端位)。多字节字段在进入网络传输前必须使用 htons() / htonl() 转换位网络字节序,从网络接收后需使用 ntohs() / ntohl() 转为主机字节序。

  3. frag_off 组合字段 :高 3 位存储 Flags(如 IP_DFIP_MF),低 13 位存储偏移量。内核解析时常使用掩码进行提取:

    • flags = ntohs(iph->frag_off) & IP_OFFSET;

五. 路由:数据包的 "导航系统"

当一个 IP 数据包构造完毕后,它是如何一步步穿越万水千山到达终点的?这就需要依赖路由机制。

复制代码
[ 发送端主机 ] ──> [ 路由器 A ] ──> [ 路由器 B ] ──> [ 目标主机 ]

1. 本地网段判断与 ARP

发送端首先将目标 IP自身的子网掩码 进行 AND运算:

  • 若属于同一子网 :直接通过 ARP 协议 查询目标 IP 的 MAC 地址,在二层(以太网)直接投递。

  • 若属于异地网段 :必须将数据包发送给默认网关(Default Gateway) 处理。

2. 路由表查找(最长前缀匹配原则)

路由器收到数据包后,剥离二层帧头,取出 IP 头的目标地址,并检索路由表(Routing Table)。

典型的 Linux 路由表结构(通过 ip route show 输出):

复制代码
default via 192.168.1.1 dev eth0 proto dhcp metric 100 
10.0.0.0/8 via 10.1.1.1 dev eth1
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.100 

当多条路由规则都能匹配目标 IP 时,路由器遵循 最长前缀匹配(Longest Prefix Match) 原则------优先选择子网掩码最长(网络号最精确)的那条路由。

3. 数据包逐跳转发(Hop-by-Hop)

  1. 路由器将 IP 报头中的 TTL 减 1。若 TTL 减至 0,则直接丢弃包并向源地址发送 ICMP 错误响应。

  2. 重新计算 IP 首部的 CheckSum

  3. 查找下一跳(Next Hop)的 MAC 地址,重新封装二层以太网帧(源 MAC 改为当前路由器接口 MAC,目的 MAC 改为下一跳 MAC)。

  4. 将数据包从对应的物理网口发送出去。

在整个路由转发过程中,IP 报头中的源 IP 和目的 IP 始终保持不变 (除非经过 NAT 转换),而二层的源 MAC 和目的 MAC 则在每一跳之间不断重写


结尾:

IP 协议作为 TCP/IP 协议栈中网络层(Layer 3)的核心,通过逻辑地址划分(CIDR/子网掩码) 解决了海量设备的定位问题,通过 NAT 技术 极大延长了 IPv4 的使用寿命,并通过无连接、尽力而为(Best-Effort) 的简洁设计,实现了极高的转发效率。

从应用层的 HTTP/RPC 请求,到传输层的 TCP 三次握手,所有数据的骨架最终都需要封装在 IP 报文中穿梭于路由器之间。深刻理解 IP 协议的结构与路由逻辑,不仅能让我们对网络排错(如 pingtraceroutetcpdump)更加游刃有余,也为进一步探索 Linux 内核网络栈及高性能网络开发奠定了坚实的基础。

相关推荐
Data_Journal1 小时前
使用 AutoScraper 进行网页抓取:分步教程
大数据·开发语言·数据库·python·scrapy
chaoyuanl1 小时前
超元力主题乐园飞行影院:把景区文化做成可持续更新的沉浸体验
大数据·3d·xr·娱乐·mr
王国强20091 小时前
Deep Agents vs LangChain vs LangGraph
langchain
企鹅的蚂蚁1 小时前
LubanCat RK3588 实时 Linux 开发(七):YT6801 PCIe 网卡驱动移植与 vermagic 排查
linux·rk3588·linux驱动·yt6801·pcie网卡·vermagic
yume_sibai1 小时前
12-Rust 性能优化指南(性能分析 + 内存优化 + SIMD + 并发优化 + 编译器优化 + 基准测试)
开发语言·性能优化·rust
DYWorker0011 小时前
Linux驱动子系统:DMA子系统 —— Consumer和Provider(006)
linux·驱动开发
爱喝水的鱼丶1 小时前
SAP-ABAP:SAP MM 模块物料主数据批量导入与增强开发:字段扩展、校验逻辑与批量导入工具开发
开发语言·性能优化·sap·abap·增强·经验交流·mm
byte轻骑兵1 小时前
【BlueZ】 log 模块:日志系统的实现与自定义日志输出配置
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙
探索云原生2 小时前
KubeClipper 1.7.0 发布:Operation 优化与 Kubernetes 1.37 支持
linux·docker·云原生·kubernetes·go