——此【主机路由】指主机上的路由规则,非全网络位的前缀路由条目。

主机双网卡使用说明

写这篇文章的原因就是一些云主机客户在添加双网卡之后,网络出现连通性问题,这里先直接给出最优解,后文会详细阐述涉及的原理和其它一些相关性技术。

Windows——保证双网卡配置正确启用即可

使用 DHCP 获取地址

win1

这是最推荐的方式,简单不容易出错,若网络连通性还有问题,请检查地址的获取情况和路由表状态

  • 检查地址的获取情况

    configlink
    1
    2
    3
    4

    - 路由表状态

    ```route print

手动配置

win2

注意保证网卡对应地址和网关配置的正确性。

Linux——策略路由

网卡信息

1
2
eth0 192.168.10.100 (gw)192.168.10.1
eth1 192.168.20.100 (gw)192.168.20.1

新建路由表并添加默认路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
### eth0
# echo "101 net_100" >> /etc/iproute2/rt_tables
# ip route add default via 192.168.10.1 dev eth0 table net_100

### eth1
# echo "101 net_101" >> /etc/iproute2/rt_tables
# ip route add default via 192.168.20.1 dev eth1 table net_101

### 持久化
### 使用 -p 参数,或者在 /etc/rc.local 中添加 route 命令来保证该路由设置永久有效
### /etc/rc.local 文件不生效,尝试
# cat /etc/sysconfig/network-scripts/route-eth0
default via 192.168.10.1 dev eth1 table net_101
# cat /etc/sysconfig/network-scripts/route-eth1
default via 192.168.20.1 dev eth2 table net_102

### PS:可以只新建一张路由表,另一张使用系统的

添加策略路由

1
2
3
4
5
6
7
8
9
### eth0
# ip rule add from 192.168.10.100 table net_100

### eth1
# ip rule add from 192.168.20.100 table net_101

### 持久化
# echo "ip rule add from 192.168.3.0/24 table storage" >> /etc/rc.local
# chmod +x /etc/rc.d/rc.local

技术原理详解

路由简介

路由判断位置

其实在系统内有两处判断路由的地方,以 Linux 为例,一处是 prerouting,另一处是 output:

iptables数据处理流程

主机系统一般只有 output,开启路由功能后 prerouting 才会判断不丢弃,简单理解一个为主机自身选路,另一个为转发非自身产生的报文。

路由三要素

  • 网络前缀:匹配的唯一条件(最长匹配原则)

  • 逃出接口:发包的出口

  • 下一跳:数据包的下一站,一般为网关地址

ps:逃出接口和下一跳可二选一,缺少逃出接口会递归查询直到得到逃出接口,缺少下一跳会导致 ARP 请求(一般为末梢网络,否则下一目的设备必须有 ARP 代答)

ext:路由类型,有直连路由、静态路由、动态路由(很多子类)等;路由管理距离,不同的路由类型具有不同的管理距离,可以简单理解为优先级;metric,路由条目的代价值,可以理解为当管理距离和路由前缀一致时使用的优先级

为什么 Windows 双网卡配置那么简单

在正式讲解通用的解决方案前,需要把 Windows 的情况单独拿出来说,因为它的路由机制做了一定的优化处理。

前文有提到两点,一是对于主机来说一般是不需要开启路由功能的,二是路由的唯一匹配条件是网络前缀。基于此,Windows 当系统未开启路由功能时,路由判断的时候把逃出接口改为了逃出接口的 IP 地址并做了校验。

下图是不同子网的双网卡生成的路由表:

Win 路由表

我们看到有俩条优先级不同的默认路由(其实还有一条高优先级的没有逃出接口的未活动默认路由),当使用次网卡的时候,虽然匹配了高优先级默认路由,但是此时对源地址做了校验(注意这不是常规操作),所以最后走了低优先级路由。

经过测试,当 Windows 开启路由功能后,路由规则就符合常理了,不会进行这个校验,因为这个校验会所有的转发报文被丢弃。此时,Windows 的双网卡使用自然也有问题了。

在补充个知识点——源地址是如何决定的?
- 当存在 bind 时:
此时一般是被动建立的连接,或者主动发起时指定源地址,自然使用的 bind 地址
- 当不存在 bind 时:
此时只有不指定源时主动发起访问,源地址来源于逃出接口的地址

附:
Windows 开启路由功能
Linux 开启路由功能

接下来,我们来看看常规的解决办法吧(据笔者所知,Windows无法使用关闭反向路由检查和策略路由):

  • 明细路由
  • 关闭反向路由检查
  • 策略路由

明细路由

我们已经知道双网卡造成连通性的根因是主机无法根据路由判断数据包往哪发了,那我们就根据业务需求和规划,写明哪个网段走哪个出口就好了。

缺点:既然写了规矩,自然是哪些网段走哪个口整的明明白白的,不能两个网口同时向所有网段提供服务了,明细网段二选一。

根据业务需求,分为同子网接入和不同子网接入两种情况,一般明细路由的使用情况建议采用不同子网模式。

双网卡使用情形

其实,两种情况就只是下一跳的值不一样,便于管理和逻辑清晰推荐不同子网。

附:
Windows 详细配置明细路由可参见链接的第三部分:Windows 路由表详解
Linux 详细配置明细路由:关于Linux路由表的route命令

关闭反向路由检查

rp_filter 本身会过滤反向路由不通的数据包。用通俗的话解释一下,就是NIC1 有 incoming 数据包,Reverse Path Filtering 模块会将数据包的源地址和目的地址(srcIP->dstIP)调转过来成为(dstIP->srcIP),然后在路由表中查找这个(dstIP->srcIP) 的路由,如果出口恰好是 NIC1 那么 rp_filter 测试通过,否则不通过/丢弃。

0:不开启源地址校验。
1:开启严格的反向路径校验。对每个进来的数据包,校验其反向路径是否是最佳路径。如果反向路径不是最佳路径,则直接丢弃该数据包。
2:开启松散的反向路径校验。对每个进来的数据包,校验其源地址是否可达,即反向路径是否能通(通过任意网口),如果反向路径不同,则直接丢弃该数据包。

基于此,我们可以把它关闭,然后保证只有一条默认路由(优先级也好,不指定网关也罢,都是可以采取的措施)。此时主动访问时主机已经明确知道走默认路由的那张网卡了,而对于被动访问的次网卡,egress 流量其实走的还是主网卡,我们只是关闭掉反向路由检查放行了。

此种方式并不推荐,原因如下:

  • egress 流量还是占用主网卡的带宽
  • 一般云平台都会对 IP 和 Mac 的映射关系进行检查

附:Linux 关闭 rpf

策略路由

路由选路的唯一匹配条件就是网络前缀,策略路由可以基于报文的其它信息,比如来源端口和五元组其它信息等。

路由因只能使用网络前缀匹配导致无法分别两个接口的流量,我们这里就基于不同的源地址使数据包从不同的接口出去,实现原进原出。

这里顺便提一下路由策略,其是路由收敛时采取的机制,这里就不展开介绍了,注意不要混淆即可。

附:策略路由配置参考