路由和路由规则

你的问题核心是:**“Pod 访问宿主机 IP 时,如果宿主机 IP 的路由未指向 `local` 表,会有什么影响?”**  

以下是关键结论和详细分析:

---

## **1. 路由表 `local` 的作用**
Linux 的 `local` 路由表(`ip route show table local`)用于管理 **本机 IP 地址的流量**。  
- **如果目标 IP 在 `local` 表中**:  
  内核会直接将流量交给 `lo`(环回接口),**不触发 ARP**,也不经过物理网卡或网桥(如 `eth0`、`cni0`)。  
  ```bash
  # 示例:宿主机 IP 10.252.176.253 在 local 表中
  ip route show table local
  # 输出:local 10.252.176.253 dev lo scope host
  ```

- **如果目标 IP 不在 `local` 表中**:  
  内核会尝试通过普通路由表(如 `main` 表)转发,可能触发 ARP 或走网关。

---

## **2. 你的场景分析**
### **(1)当前路由表的问题**
从你的 `ip route` 输出看:
```bash
10.252.176.0/22 dev eth0  proto kernel  scope link  src 10.252.176.253
```
- **宿主机 IP `10.252.176.253` 未绑定到 `local` 表**,而是通过 `eth0` 设备关联。  
- 当 Pod 访问 `10.252.176.253` 时:  
  1. Pod 查路由表,发现目标 IP 不在 `246.255.0.0/24`,走默认网关 `246.255.0.1`(即 `cni0`)。  
  2. 宿主机收到流量后,发现目标 IP 是自己的,但 **未在 `local` 表中**,因此可能尝试通过 `eth0` 响应,而非直接走 `lo`。  
  3. **如果 `eth0` 未启用 ARP 代理或防火墙阻止**,则 ARP 请求无响应。

### **(2)关键结论**
- **未绑定 `local` 表** → 宿主机 IP 的流量可能被错误地导向物理网卡(如 `eth0`),而非 `lo`。  
- **绑定 `local` 表** → 强制宿主机 IP 的流量走 `lo`,避免 ARP 和物理网络干扰。

---

## **3. 解决方案**
### **✅ 方法 1:将宿主机 IP 加入 `local` 表**
```bash
sudo ip addr add 10.252.176.253/32 dev lo
```
**验证**:
```bash
ip route show table local | grep 10.252.176.253
# 应输出:local 10.252.176.253 dev lo scope host
```
**效果**:  
- Pod 访问 `10.252.176.253` 时,宿主机直接通过 `lo` 处理,**不触发 ARP**。  
- 无需依赖 `proxy_arp` 或防火墙规则。

### **✅ 方法 2:启用 `proxy_arp`(备用方案)**
如果无法修改 `local` 表,可临时启用 ARP 代理:
```bash
echo 1 | sudo tee /proc/sys/net/ipv4/conf/cni0/proxy_arp
```
**缺点**:  
- 扩大 ARP 响应范围,可能影响网络安全。  
- 仍需确保流量能正确路由到宿主机。

---

## **4. 实验验证**
### **(1)未修复时**
在 Pod 内执行:
```bash
ping 10.252.176.253
```
- **抓包观察**:
  ```bash
  sudo tcpdump -i cni0 arp -nn
  ```
  - 会看到 ARP 请求,但宿主机不响应。

### **(2)修复后**
- **绑定 `local` 表后**:  
  - `ping` 直接成功,无 ARP 请求。  
  - 流量通过 `lo` 环回,不经过物理网络。

---

## **5. 总结**
| 问题根源 | 现象 | 修复方法 |
|----------|------|----------|
| 宿主机 IP 未绑定 `local` 表 | Pod 访问宿主机 IP 触发 ARP 但无响应 | **`ip addr add <host-ip>/32 dev lo`** |
| `cni0` 未启用 ARP 代理 | ARP 请求被丢弃 | **`echo 1 > /proc/sys/net/ipv4/conf/cni0/proxy_arp`** |
| 防火墙/NetworkPolicy 拦截 | 流量被丢弃 | 检查 `iptables`/`calico` 规则 |

**最终建议**:  
- **优先绑定 `local` 表**(一劳永逸,避免 ARP 问题)。  
- 如果需跨节点访问宿主机服务,改用 `NodePort` 或 `hostNetwork`。

### **1. `ip rule` 和 `ip route` 的区别**
`ip rule` 和 `ip route` 是 Linux 网络栈的两个不同部分,分别管理 **路由策略** 和 **具体路由表**。  

| **功能**       | **`ip rule`(路由策略)** | **`ip route`(路由表)** |
|--------------|----------------------|----------------------|
| **作用**      | 决定 **如何选择路由表** | 存储 **具体的路由规则** |
| **管理对象**  | 策略规则(优先级、匹配条件) | 路由条目(目标网络、下一跳) |
| **典型用途**  | 多路由表、策略路由(如 VPN、多网卡) | 普通路由(默认网关、子网路由) |
| **查看命令**  | `ip rule show` | `ip route show` 或 `ip route show table main` |

---

### **2. 你的 `ip rule` 输出解析**
```bash
0:	from all lookup local 
32766:	from all lookup main 
32767:	from all lookup default
```
- **`0: from all lookup local`**  
  - **最高优先级(0)**,所有流量先查 `local` 路由表。  
  - `local` 表存储 **本机 IP 和广播地址**(如 `127.0.0.1`、`10.252.176.253`)。  
  - 如果目标 IP 在 `local` 表中,直接走 `lo` 设备,**不触发 ARP**。  

- **`32766: from all lookup main`**  
  - 如果 `local` 表未匹配,查 `main` 表(普通路由表)。  
  - 你的 `ip route show` 输出实际是 `main` 表的内容。  

- **`32767: from all lookup default`**  
  - 最低优先级,通常为空,仅作后备。  

---

### **3. 关键区别:`local` 表 vs. `main` 表**
#### **(1)`local` 表**
- **内容**:本机 IP、广播地址、多播地址。  
  ```bash
  ip route show table local
  # 示例输出:
  # local 10.252.176.253 dev lo scope host
  # broadcast 10.252.179.255 dev eth0 proto kernel scope link src 10.252.176.253
  ```
- **作用**:  
  - 确保发往本机 IP 的流量直接走 `lo`,**不经过物理网卡**。  
  - **避免 ARP 请求**(因为 `lo` 是虚拟设备,无需 MAC 地址)。  

#### **(2)`main` 表**
- **内容**:普通路由(默认网关、子网路由、CNI 网桥等)。  
  ```bash
  ip route show  # 默认显示 main 表
  # 示例输出:
  # default via 10.252.176.1 dev eth0
  # 10.252.176.0/22 dev eth0 proto kernel scope link src 10.252.176.253
  # 246.255.0.0/24 dev cni0 proto kernel scope link src 246.255.0.1
  ```
- **作用**:  
  - 决定非本机流量的下一跳(如 Pod 访问外部 IP 时走默认网关)。  

---

### **4. 为什么 `local` 表影响 ARP?**
- **如果宿主机 IP 在 `local` 表中**:  
  - Pod 访问宿主机 IP 时,内核直接匹配 `local` 表,走 `lo` 设备,**不触发 ARP**。  

- **如果宿主机 IP 不在 `local` 表中**:  
  - 内核会查 `main` 表,发现目标 IP 属于 `eth0` 的子网(`10.252.176.0/22`)。  
  - 尝试通过 `eth0` 发送 ARP 请求,但宿主机可能不响应(因为目标 IP 是自己,但未绑定 `lo`)。  

---

### **5. 修复方案回顾**
#### **(1)将宿主机 IP 加入 `local` 表(推荐)**
```bash
sudo ip addr add 10.252.176.253/32 dev lo
```
**效果**:  
- 强制宿主机 IP 的流量走 `lo`,**跳过 ARP**。  
- 无需修改 `proxy_arp` 或防火墙。  

#### **(2)验证 `local` 表**
```bash
ip route show table local | grep 10.252.176.253
# 正确输出:
# local 10.252.176.253 dev lo scope host
```

---

### **6. 总结**
| **问题**                | **原因**                          | **解决方案**                     |
|-------------------------|----------------------------------|----------------------------------|
| Pod 访问宿主机 IP 无响应 | 宿主机 IP 未绑定 `local` 表,触发 ARP 但无应答 | **`ip addr add <host-ip>/32 dev lo`** |
| 路由优先级混乱          | `main` 表优先于 `local` 表(实际不会发生) | 依赖默认的 `ip rule` 优先级(0 > 32766) |
| 流量误走物理网卡        | 未匹配 `local` 表,走到 `main` 表的 `eth0` 路由 | 确保关键 IP 在 `local` 表中       |

**最终建议**:  
- **始终将宿主机管理 IP 绑定到 `lo`**,避免依赖 ARP。  
- 如需跨节点访问,使用 `NodePort` 或 `hostNetwork`,而非直接依赖宿主机 IP。

 

在 Linux 中,可以通过以下方法查看系统中定义的所有路由表(Routing Tables)及其内容:

---

### **1. 查看所有路由表名称**
```bash
cat /etc/iproute2/rt_tables
```
输出示例:
```
#
# reserved values
#
255	local
254	main
253	default
0	unspec
#
# custom tables (if any)
#
100	my_custom_table
```
- **系统保留表**:
  - `local`(255):存储本机地址和广播路由(`lo` 设备)。
  - `main`(254):默认路由表(`ip route show` 实际显示此表)。
  - `default`(253):通常为空,备用表。
  - `unspec`(0):未指定用途。

- **自定义表**:  
  管理员可以添加自定义表(如 `my_custom_table`)。

---

### **2. 查看所有路由表的内容**
#### **方法 1:遍历所有表**
```bash
ip route show table all
```
这会列出所有已配置的路由表内容(包括 `local`、`main` 和自定义表)。

#### **方法 2:查看特定表**
```bash
ip route show table <table_name_or_id>
```
示例:
```bash
ip route show table local  # 查看 local 表
ip route show table main  # 查看 main 表
ip route show table 100   # 查看 ID 为 100 的表
```

---

### **3. 查看路由策略规则(决定如何选择表)**
```bash
ip rule show
```
输出示例:
```
0:	from all lookup local
32766:	from all lookup main
32767:	from all lookup default
```
- **解读**:  
  - 优先级 `0` 的规则:所有流量先查 `local` 表。  
  - 优先级 `32766`:未匹配则查 `main` 表。  
  - 优先级 `32767`:最后查 `default` 表。

---

### **4. 统计路由表的数量**
```bash
# 统计已配置的非空路由表数量
ip route show table all | grep -o "table [0-9]\+" | sort -u | wc -l
```
输出示例:
```
4
```
表示系统中有 4 个路由表被使用。

---

### **5. 关键路由表说明**
| **表名/ID** | **用途**                                                                 |
|-------------|--------------------------------------------------------------------------|
| `local` (255) | 本机 IP、广播地址、多播地址(如 `127.0.0.1`、`10.0.0.1`)。流量直接走 `lo`。 |
| `main` (254)  | 默认路由表(普通路由规则,如默认网关、子网路由)。                          |
| `default` (253) | 通常为空,备用表。                                                       |
| 自定义表 (1-252) | 用户自定义策略路由(如多网卡分流、VPN 专用路由)。                        |

---

### **6. 实际示例**
#### **场景:检查 Kubernetes 节点的路由表**
```bash
# 查看所有路由表
ip route show table all

# 检查 local 表(宿主机 IP 是否绑定?)
ip route show table local | grep 10.252.176.253

# 检查 main 表(Pod 和 Service 路由)
ip route show table main
```

#### **输出示例**
```bash
# ip route show table local
local 127.0.0.0/8 dev lo scope host
local 10.252.176.253 dev lo scope host  # 宿主机 IP 绑定到 lo

# ip route show table main
default via 10.252.176.1 dev eth0
10.252.176.0/22 dev eth0 proto kernel scope link src 10.252.176.253
246.255.0.0/24 dev cni0 proto kernel scope link src 246.255.0.1
```

---

### **7. 总结**
| **操作**                     | **命令**                                |
|------------------------------|----------------------------------------|
| 查看所有路由表名称           | `cat /etc/iproute2/rt_tables`          |
| 查看所有路由表内容           | `ip route show table all`              |
| 查看特定表内容               | `ip route show table <name_or_id>`     |
| 查看路由策略规则(`ip rule`)| `ip rule show`                         |
| 统计路由表数量               | `ip route show table all \| grep -o "table [0-9]\+" \| sort -u \| wc -l` |

通过以上方法,可以全面掌握系统中的路由表结构和策略规则。  
对于 Kubernetes 网络问题,重点关注 `local` 和 `main` 表是否包含关键路由(如宿主机 IP 和 Pod CIDR)。

  

 

posted on 2025-06-21 00:31  吃草的青蛙  阅读(46)  评论(0)    收藏  举报

导航