将流量路由到同一网络上的两个 NIC

Vad*_*imo 5 networking routing ip-routing linux-networking iproute

我在 Scaleway 上有几个 linux 测试盒,每个都有 2 个 NIC,它们都连接到同一个网络,10.0.0.0/8但每个都有自己的网关。

我希望能够同时使用 NIC(eth0/eth1)及其 IP 进行通信。因此,如果应用程序绑定到 IP .187,则应使用 dev eth0。如果应用程序绑定到 IP .189,则应使用 eth1。

现在只有 IP 为 .187 的接口 eth0 正在响应请求。任何请求。(这就是我使用 ping 和 ssh 进行测试的原因)。但是,如果我将默认路由从 eth0 更改为 eth1(ip .189),则传出流量将通过 eth1 正确路由,在这种情况下,eth0 将不可用。

那么如何配置盒子,这样两个接口都可以使用。

给定的

Box 1:
eth0_ip = 10.5.68.187/31
eth0_gw = 10.5.68.186

eth1_ip = 10.5.68.189/31
eth1_gw = 10.5.68.188
Run Code Online (Sandbox Code Playgroud)

方法

根据我的研究,herehere我创建了一个 bash 脚本,该脚本应该添加带有表的静态路由,以便可以同时使用两个网卡。

#/bin/bash
# My Vars with IP and GW for eth0
eth0_ip=$(ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
eth0_gw=$(ip route list dev eth0 | awk '{print $1}' | tail -1 | cut -d'/' -f1)

eth1_ip=$(ip -o -4 addr list eth1 | awk '{print $4}' | cut -d/ -f1)
eth1_gw=$(ip route list dev eth1 | awk '{print $1}' | tail -1 | cut -d'/' -f1)

#ip route add 10.0.0.0/8 dev eth0 table 1 priority 100
#ip route add ${eth0_ip} dev eth0 table 1
ip route add default via ${eth0_gw} dev eth0 table 1
ip rule add from ${eth0_ip}/32 table 1

#ip route add 10.0.0.0/8 dev eth1 table 2 priority 110
#ip route add ${eth1_ip} dev eth1 table 2
ip route add default via ${eth1_gw} dev eth1 table 2
ip rule add from ${eth1_ip}/32 table 2
Run Code Online (Sandbox Code Playgroud)

ip 路由刷新缓存

我对脚本做了一些变体,但没有一个起作用

输出

[node]# ip route
default via 10.1.229.186 dev eth0 
10.1.229.186/31 dev eth0 proto kernel scope link src 10.1.229.187 
10.1.229.188/31 dev eth1 proto kernel scope link src 10.1.229.189 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.18.0.0/16 dev docker_gwbridge proto kernel scope link src 172.18.0.1 

[node]# ip route show table 1
10.1.229.187 dev eth0 scope link 

[node]# ip route show table 2
10.1.229.189 dev eth1 scope link 
Run Code Online (Sandbox Code Playgroud)

测试

[]]# ip route get 10.5.68.187 from 10.1.229.187
10.5.68.187 from 10.1.229.187 via 10.1.229.186 dev eth0 
    cache 
[]# ip route get 10.5.68.187 from 10.1.229.189
10.5.68.187 from 10.1.229.189 via 10.1.229.188 dev eth1 
    cache 
Run Code Online (Sandbox Code Playgroud)

从另一台机器。

ping 10.1.229.187   # OK
ping 10.1.229.189   # NOK

nmap 10.1.229.187 -p 22   # OK
nmap 10.1.229.189 -p 22   # NOK
Run Code Online (Sandbox Code Playgroud)

那么我如何设置路由才能正常工作,同时与 .187 和 .189 通信。

更新 2:

通过这种设置,我能够取得某种成功。

eth0_ip=$(ip -o -4 addr list eth0 | awk '{print $4}' | cut -d/ -f1)
eth0_gw=$(ip route list dev eth0 | awk '{print $1}' | tail -1 | cut -d'/' -f1)

eth1_ip=$(ip -o -4 addr list eth1 | awk '{print $4}' | cut -d/ -f1)
eth1_gw=$(ip route list dev eth1 | awk '{print $1}' | tail -1 | cut -d'/' -f1)

ip route add default via ${eth0_gw} dev eth0 table 1
ip rule add from ${eth0_ip} table 1

ip route add default via ${eth1_gw} dev eth1 table 2
ip rule add from ${eth1_ip} table 2
Run Code Online (Sandbox Code Playgroud)

应用上述脚本后,我修改了默认路由,切换到 eth1 然后返回,之后我可以 ping 到 .187 和 .189。(在另一个例子中,我也完全删除了它)我不确定这里的问题是什么。

# remove and add route 
ip route change default via ${eth1_gw} dev eth1
ip route change default via ${eth0_gw} dev eth0

ip route flush cache
Run Code Online (Sandbox Code Playgroud)

更新 3:

从各种试验来看,在我看来,表 2 完全被忽略了。由于 ISP 有自定义内核,是否可以禁用内核中的路由表?我该如何测试?

更新 4:

我再一次取得了一点进展,但离一个可行的解决方案还很远。尝试不同的选择,我偶然发现了这种奇怪的情况。为了看到 eth1 工作,我需要先使用有问题的接口一次,例如

我需要从 IP .189(node1) ping 到网络上的另一个节点,例如:示例:节点 1-> 节点 2: ping -I 10.1.229.189 10.5.68.187这有效,然后突然返回来自节点 2 的 ping -> 节点 1ping 10.1.229.189正在工作。如果我不从(节点 1 -> 节点 2)进行初始连接/ping,那么(节点 2 -> 节点 1)将无法工作。

然而,这里的问题是,如果我重新启动机器或等待一段时间(10-60 分钟),它会回到初始状态。

部分工作的最小设置是这样的,(我随后删除了所有内容,没有任何区别)

eth1_ip=$(ip -o -4 addr list eth1 | awk '{print $4}' | cut -d/ -f1)
eth1_gw=$(ip route list dev eth1 | awk '{print $1}' | tail -1 | cut -d'/' -f1)

ip route add default via ${eth1_gw} dev eth1 table 2
ip rule add from ${eth1_ip} lookup 2
Run Code Online (Sandbox Code Playgroud)

这是@Anton Danilov 要求的输出

[root@cluser-node-1 ~]# ip -4 r ls table all
default via 10.1.229.188 dev eth1 table 2 
default via 10.1.229.186 dev eth0 
10.1.229.186/31 dev eth0 proto kernel scope link src 10.1.229.187 
10.1.229.188/31 dev eth1 proto kernel scope link src 10.1.229.189 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
172.18.0.0/16 dev docker_gwbridge proto kernel scope link src 172.18.0.1 
local 10.1.229.187 dev eth0 table local proto kernel scope host src 10.1.229.187 
broadcast 10.1.229.187 dev eth0 table local proto kernel scope link src 10.1.229.187 
local 10.1.229.189 dev eth1 table local proto kernel scope host src 10.1.229.189 
broadcast 10.1.229.189 dev eth1 table local proto kernel scope link src 10.1.229.189 
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1 
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1 
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1 
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1 
broadcast 172.17.0.0 dev docker0 table local proto kernel scope link src 172.17.0.1 
local 172.17.0.1 dev docker0 table local proto kernel scope host src 172.17.0.1 
broadcast 172.17.255.255 dev docker0 table local proto kernel scope link src 172.17.0.1 
broadcast 172.18.0.0 dev docker_gwbridge table local proto kernel scope link src 172.18.0.1 
local 172.18.0.1 dev docker_gwbridge table local proto kernel scope host src 172.18.0.1 
broadcast 172.18.255.255 dev docker_gwbridge table local proto kernel scope link src 172.18.0.1 



[root@cluser-node-1 ~]# ip rule list
0:  from all lookup local 
32765:  from 10.1.229.189 lookup 2 
32766:  from all lookup main 
32767:  from all lookup default 

[root@cluser-node-1 ~]# ip n ls dev eth1
10.1.229.188 lladdr 00:07:cb:0b:0d:93 REACHABLE

[root@cluser-node-1 ~]# tcpdump -ni eth1 arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
16:36:17.237182 ARP, Request who-has 10.1.229.188 tell 10.1.229.189, length 28
16:36:17.237369 ARP, Reply 10.1.229.188 is-at 00:07:cb:0b:0d:93, length 46

2 packets captured
4 packets received by filter
0 packets dropped by kernel
Run Code Online (Sandbox Code Playgroud)

这是系统重新启动后或 15-30 分钟超时后的另一个输出。

[root@cluser-node-1 ~]# tcpdump -ni eth1 arp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

[root@cluser-node-1 ~]# ip n ls dev eth1
10.1.229.188 lladdr 00:07:cb:0b:0d:93 REACHABLE
Run Code Online (Sandbox Code Playgroud)

Ant*_*lov 1

检查是否有回复(可能回复是通过其他接口发出的)或者回复丢失。

检查反向路径过滤器的设置(检查“nstat -az”或“netstat -S”输出中的计数器 - 对于 rp_filter 丢弃的数据包有 TcpExtIPReversePathFilter)。禁用它或设置为松散模式(请参阅sysctl 设置说明)。查找传入数据包的反向路由以确认假设。

我认为您应该将直连网络的路由添加到路由表中,因为相应网关的 arp 解析以及与直连网络中其他主机的通信需要它。这些设置应该足以解决您的情况:

ip 路由添加 10.5.68.186/31 dev eth0 表 1
ip 路由 0/0 通过 10.5.68.186 dev eth0 表 1

ip 路由添加 10.5.68.188/31 dev eth1 表 2
ip 路由 0/0 通过 10.5.68.188 dev eth1 表 2

从 10.5.68.187 查找 1 添加 ip 规则
从 10.5.68.189 查找 2 添加 ip 规则

另外,您应该知道,此设置仅适用于这些具有重叠寻址的接口上的 IP 地址不同的情况。否则,您应该使用更复杂的方案,通过防火墙标记使用 CONNMARK 和 pbr。

如果您尝试从主机本身 ping 主机,则应使用以下命令:

ip 路由添加本地 10.5.68.187 dev eth0 表 1
ip 路由添加 10.5.68.186/31 dev eth0 表 1
ip 路由 0/0 通过 10.5.68.186 dev eth0 表 1

ip 路由添加本地 10.5.68.189 dev eth1 表 2
ip 路由添加 10.5.68.188/31 dev eth1 表 2
ip 路由 0/0 通过 10.5.68.188 dev eth1 表 2

ip 规则添加 iif eth0 查找 1 pref 101
ip 规则添加 iif eth1 查找 2 pref 102

ip 规则从 10.5.68.187 添加查找 1 pref 201
ip 规则从 10.5.68.189 添加查找 2 pref 202

从所有查找本地首选项 300 添加 ip 规则
IP 规则 del pref 0