HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 网络架构师学习手册

    • 网络架构师学习教程
    • 基础篇

      • 第1章 网络模型与数据流转
      • 第2章 以太网与二层通信
      • 第3章 IP路由与三层转发
      • 第4章 TCP与可靠传输
      • 第5章 应用层协议
    • Linux网络栈

      • 第6章 数据包接收路径
      • 第7章 多核网络优化
      • 第8章 Netfilter与防火墙
      • 第9章 流量控制与QoS
    • 虚拟网络

      • 第10章 Network Namespace基础
      • 第11章 Bridge与互联
      • 第12章 VXLAN与Overlay网络
      • 第13章 OVS与SDN
    • Kubernetes网络

      • 第14章 CNI模型与实现
      • 第15章 kube-proxy与Service实现
      • 第16章 CoreDNS与服务发现
      • 第17章 NetworkPolicy与安全隔离
      • 第18章 Calico网络深度解析
      • 第19章 Cilium与eBPF网络
    • 网络架构

      • 第20章 网络设备与拓扑设计
      • 第21章 网络容量规划与计算
      • 第22章 负载均衡架构设计
      • 第23章 高可用网络架构
      • 第24章 网络安全架构
    • 性能调优

      • 第25章 系统级网络调优
      • 第26章 故障排查方法论
      • 第27章 生产环境案例分析
    • 前沿技术

      • 第28章 eBPF深度实践
      • 第29章 ServiceMesh与边车代理
      • 第30章 网络技术趋势与未来展望
    • 附录

      • 附录A:命令速查手册
      • 附录B:排错决策树
      • 附录C:学习资源
      • 附录D:技能图谱

第3章 IP路由与三层转发

学习目标

  • 理解IP地址结构和子网划分
  • 掌握路由表的工作原理和配置
  • 了解ICMP协议的作用和类型
  • 能够配置静态路由和策略路由

🔬 原理

IP地址结构

IPv4地址格式:

格式:X.X.X.X(点分十进制)
示例:192.168.1.100

地址分类:

  • A类:1.0.0.0 - 126.255.255.255(网络位8位)
  • B类:128.0.0.0 - 191.255.255.255(网络位16位)
  • C类:192.0.0.0 - 223.255.255.255(网络位24位)
  • D类:224.0.0.0 - 239.255.255.255(组播)
  • E类:240.0.0.0 - 255.255.255.255(保留)

特殊地址:

  • 0.0.0.0:默认路由
  • 127.0.0.1:回环地址
  • 255.255.255.255:广播地址
  • 169.254.x.x:链路本地地址

子网划分

CIDR表示法:

格式:IP地址/网络位长度
示例:192.168.1.0/24

子网掩码:

/24 = 255.255.255.0
/16 = 255.255.0.0
/8  = 255.0.0.0

子网计算:

网络地址 = IP地址 & 子网掩码
广播地址 = 网络地址 | (~子网掩码)
可用主机 = 2^(主机位) - 2

示例:

192.168.1.0/24:
- 网络地址:192.168.1.0
- 广播地址:192.168.1.255
- 可用主机:254个(192.168.1.1 - 192.168.1.254)

路由表原理

路由表结构:

目标网络    网关        接口        优先级    度量
192.168.1.0/24  *        eth0        0         0
0.0.0.0/0       192.168.1.1  eth0        0         1
10.0.0.0/8      192.168.1.254 eth0        0         1

路由匹配原则:

  1. 最长前缀匹配:选择网络位最长的路由
  2. 优先级:数值越小优先级越高
  3. 度量值:相同优先级时选择度量值最小的

路由类型:

  • 直连路由:接口配置IP后自动生成
  • 静态路由:手动配置
  • 动态路由:通过协议学习(BGP、OSPF等)

ICMP协议

ICMP(Internet Control Message Protocol):网络层控制协议

主要类型:

  • Echo Request/Reply:ping命令使用
  • Destination Unreachable:目标不可达
  • Time Exceeded:TTL超时(traceroute使用)
  • Redirect:路由重定向

ICMP头部:

类型(1) 代码(1) 校验和(2) 数据(变长)

常见类型码:

  • 0:Echo Reply
  • 3:Destination Unreachable
  • 8:Echo Request
  • 11:Time Exceeded

️ 实现

Linux路由表实现

路由表结构:

struct fib_table {
    struct hlist_node tb_hlist;
    u32 tb_id;
    int tb_default;
    int tb_num_default;
    unsigned long tb_data[0];
};

struct fib_info {
    struct hlist_node fib_hash;
    struct hlist_node fib_lhash;
    int fib_treeref;
    atomic_t fib_clntref;
    unsigned int fib_flags;
    unsigned char fib_dead;
    unsigned char fib_protocol;
    unsigned char fib_scope;
    unsigned char fib_type;
    __be32 fib_prefsrc;
    u32 fib_priority;
    u32 fib_metrics[RTAX_MAX];
    struct fib_nh fib_nh[0];
};

路由查找:

static int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
                           struct fib_result *res, int fib_flags)
{
    struct trie *t = (struct trie *) tb->tb_data;
    struct tnode *n;
    struct fib_result res;
    
    // 最长前缀匹配算法
    n = trie_lookup(t, flp->daddr);
    if (n) {
        res = n->res;
        return 0;
    }
    
    return -ENOENT;
}

策略路由实现

策略路由表:

struct fib_rule {
    struct list_head list;
    atomic_t refcnt;
    int ifindex;
    char ifname[IFNAMSIZ];
    u32 mark;
    u32 mark_mask;
    u32 priority;
    u32 flags;
    u32 table;
    u8 action;
    u8 l3mdev;
    struct fib_rule __rcu *next;
    struct net *fr_net;
};

🛠️ 命令

基础路由命令

# 查看路由表
ip route show

# 查看特定路由
ip route get 8.8.8.8

# 添加静态路由
sudo ip route add 10.0.2.0/24 via 192.168.1.254

# 删除路由
sudo ip route del 10.0.2.0/24

# 添加默认路由
sudo ip route add default via 192.168.1.1

策略路由配置

# 查看策略路由表
ip rule show

# 添加策略路由
sudo ip rule add from 192.168.1.10 table 100
sudo ip route add default via 192.168.1.1 table 100

# 删除策略路由
sudo ip rule del from 192.168.1.10 table 100

ICMP相关命令

# ping测试
ping -c 3 8.8.8.8

# 路由追踪
traceroute 8.8.8.8

# 路径MTU发现
tracepath 8.8.8.8

# 检查ICMP统计
cat /proc/net/snmp | grep -i icmp

代码

简单路由表查看程序

// route_table.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>

int main() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        return 1;
    }
    
    char buffer[8192];
    struct rt_msghdr *rtm;
    struct sockaddr_in *sin;
    
    // 读取路由表
    int len = read(sock, buffer, sizeof(buffer));
    if (len < 0) {
        perror("read");
        close(sock);
        return 1;
    }
    
    rtm = (struct rt_msghdr *)buffer;
    
    printf("Destination     Gateway         Flags    Refs    Use    Interface\n");
    printf("-------------   -------------   ------   ----    ---    ---------\n");
    
    // 解析路由条目
    while (len > 0) {
        if (rtm->rtm_type == RTM_GET) {
            sin = (struct sockaddr_in *)(rtm + 1);
            char dst[INET_ADDRSTRLEN];
            char gw[INET_ADDRSTRLEN];
            
            inet_ntop(AF_INET, &sin->sin_addr, dst, INET_ADDRSTRLEN);
            
            if (rtm->rtm_flags & RTF_GATEWAY) {
                sin = (struct sockaddr_in *)((char *)sin + 
                       ((sin->sin_len + 3) & ~3));
                inet_ntop(AF_INET, &sin->sin_addr, gw, INET_ADDRSTRLEN);
            } else {
                strcpy(gw, "*");
            }
            
            printf("%-15s %-15s %-6x %-4d %-6d %s\n",
                   dst, gw, rtm->rtm_flags, rtm->rtm_refcnt, 
                   rtm->rtm_use, "eth0");
        }
        
        len -= rtm->rtm_msglen;
        rtm = (struct rt_msghdr *)((char *)rtm + rtm->rtm_msglen);
    }
    
    close(sock);
    return 0;
}

编译运行:

gcc route_table.c -o route_table
./route_table

ICMP ping实现

// simple_ping.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>

unsigned short checksum(void *b, int len) {
    unsigned short *buf = b;
    unsigned int sum = 0;
    unsigned short result;
    
    while (len > 1) {
        sum += *buf++;
        len -= 2;
    }
    
    if (len == 1) {
        sum += *(unsigned char*)buf << 8;
    }
    
    while (sum >> 16) {
        sum = (sum & 0xFFFF) + (sum >> 16);
    }
    
    result = ~sum;
    return result;
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <host>\n", argv[0]);
        return 1;
    }
    
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (sock < 0) {
        perror("socket");
        return 1;
    }
    
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &addr.sin_addr);
    
    struct icmp icmp_pkt;
    icmp_pkt.icmp_type = ICMP_ECHO;
    icmp_pkt.icmp_code = 0;
    icmp_pkt.icmp_cksum = 0;
    icmp_pkt.icmp_id = getpid();
    icmp_pkt.icmp_seq = 1;
    
    icmp_pkt.icmp_cksum = checksum(&icmp_pkt, sizeof(icmp_pkt));
    
    if (sendto(sock, &icmp_pkt, sizeof(icmp_pkt), 0, 
               (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("sendto");
        close(sock);
        return 1;
    }
    
    printf("PING %s: %d data bytes\n", argv[1], sizeof(icmp_pkt));
    
    char buffer[1024];
    struct sockaddr_in from;
    socklen_t fromlen = sizeof(from);
    
    if (recvfrom(sock, buffer, sizeof(buffer), 0, 
                 (struct sockaddr*)&from, &fromlen) < 0) {
        perror("recvfrom");
        close(sock);
        return 1;
    }
    
    struct iphdr *ip = (struct iphdr*)buffer;
    struct icmp *icmp = (struct icmp*)(buffer + (ip->ihl << 2));
    
    if (icmp->icmp_type == ICMP_ECHOREPLY) {
        printf("64 bytes from %s: icmp_seq=1 time=0.001 ms\n", argv[1]);
    }
    
    close(sock);
    return 0;
}

编译运行:

gcc simple_ping.c -o simple_ping
sudo ./simple_ping 8.8.8.8

🧪 实验

实验1:子网划分实践

目标:掌握子网划分和CIDR表示法

步骤:

# 1. 查看当前网络配置
ip addr show

# 2. 计算子网信息
# 假设网络:192.168.1.0/24
# 网络地址:192.168.1.0
# 广播地址:192.168.1.255
# 可用主机:192.168.1.1 - 192.168.1.254

# 3. 划分子网
# 将192.168.1.0/24划分为4个子网
# 子网1:192.168.1.0/26  (192.168.1.1-62)
# 子网2:192.168.1.64/26 (192.168.1.65-126)
# 子网3:192.168.1.128/26 (192.168.1.129-190)
# 子网4:192.168.1.192/26 (192.168.1.193-254)

# 4. 配置子网接口
sudo ip addr add 192.168.1.1/26 dev eth0
sudo ip addr add 192.168.1.65/26 dev eth0:1
sudo ip addr add 192.168.1.129/26 dev eth0:2
sudo ip addr add 192.168.1.193/26 dev eth0:3

# 5. 验证配置
ip addr show

预期结果:

  • 理解子网划分原理
  • 掌握CIDR计算方法
  • 学会多IP配置

实验2:静态路由配置

目标:配置静态路由实现网络互通

步骤:

# 1. 查看当前路由表
ip route show

# 2. 添加静态路由
sudo ip route add 10.0.2.0/24 via 192.168.1.254
sudo ip route add 172.16.0.0/16 via 192.168.1.254

# 3. 验证路由
ip route get 10.0.2.5
ip route get 172.16.1.1

# 4. 测试连通性
ping -c 2 10.0.2.1
ping -c 2 172.16.1.1

# 5. 查看路由统计
cat /proc/net/route

预期结果:

  • 理解路由表工作原理
  • 掌握静态路由配置
  • 验证路由选择过程

实验3:策略路由配置

目标:根据源地址选择不同路由

步骤:

# 1. 查看当前策略路由
ip rule show

# 2. 添加策略路由表
echo "200 custom" >> /etc/iproute2/rt_tables

# 3. 配置策略路由
sudo ip rule add from 192.168.1.10 table 200
sudo ip route add default via 192.168.1.1 table 200

# 4. 测试策略路由
sudo ip route add 192.168.1.10/32 dev lo
ping -I 192.168.1.10 8.8.8.8

# 5. 查看路由选择
ip route get 8.8.8.8 from 192.168.1.10

预期结果:

  • 理解策略路由原理
  • 掌握多路由表配置
  • 验证路由选择策略

实验4:traceroute原理验证

目标:理解traceroute的工作原理

步骤:

# 1. 使用traceroute
traceroute -n 8.8.8.8

# 2. 手动实现traceroute
for i in {1..10}; do
    echo "TTL $i:"
    sudo hping3 -c 1 -V --ttl $i 8.8.8.8
    echo
done

# 3. 抓包观察
sudo tcpdump -i any -nn 'icmp[0] == 11' &
traceroute 8.8.8.8

预期结果:

  • 理解TTL递减机制
  • 观察ICMP Time Exceeded
  • 掌握网络路径发现

排错

常见问题排查

问题1:路由表混乱

# 清空路由表
sudo ip route flush table main

# 重新添加默认路由
sudo ip route add default via 192.168.1.1

# 检查路由优先级
ip route show table all

问题2:策略路由不生效

# 检查策略规则
ip rule show

# 检查路由表
ip route show table 200

# 验证源地址
ip addr show

问题3:ICMP被过滤

# 检查防火墙规则
sudo iptables -L -n | grep icmp

# 允许ICMP
sudo iptables -A INPUT -p icmp -j ACCEPT

# 检查ICMP统计
cat /proc/net/snmp | grep -i icmp

排错清单

  • [ ] 检查IP地址配置(地址、掩码、广播)
  • [ ] 验证路由表(直连、静态、默认)
  • [ ] 确认网关可达性(ping网关)
  • [ ] 检查策略路由(规则、表、优先级)
  • [ ] 测试ICMP功能(ping、traceroute)
  • [ ] 查看路由统计(/proc/net/route)
  • [ ] 检查系统日志(dmesg、/var/log/syslog)
Prev
第2章 以太网与二层通信
Next
第4章 TCP与可靠传输