本文主要关注基于ip
命令的配置, 尽量避免使用ifconfig
, route
, brctl
等传统命令, 尽量避开使用systemd-network
等网络管理器.
本文基于 利用OSPF协议实现WireGuard高可用 并假设已存在一个由WireGuard安全点对点连接组成的网络, 且网络中运行一种IGP协议(例如OSPF).
网络拓扑如上图. 其中点对点链路均使用/30
网段, 各路由器均运行OSPF协议. 现在想利用Router 10.65.1.1
, 10.65.1.2
两台机器实现Router 10.65.2.2
和 10.65.2.1
流量最大化通信.
由于WireGuard本身运行在L3/IP层, 且官方版本不支持设置mac地址(有魔改版据说做到了), 我们无法利用Linux本身提供的Bonding功能来做原生负载均衡. 因此可以在 10.65.2.2
和 10.65.2.1
之间分别搭建两条经过不同路由的GRE隧道, 然后在两侧分别将两个GRE端口绑定起来.
需要注意的是, GRE隧道分为GRE和GRETAP, 其中GRE也是运行在L3的, GRETAP则是运行在L2的. 尽管GRE没有加密功能, 但由于外层隧道本身是加密的, 所以不会有安全问题, 也避免了多次加密带来的性能损耗.
首先加载必要的kernel module (不过这一步似乎可以省略, 因为新建gre设备的时候会自动加载)
1 | modprobe ip_gre |
创建GRE隧道
在Router 10.65.2.2
上:
1 | ip link add gre1 type gretap local 10.65.0.2 remote 10.65.0.6 ttl 255 |
在Router 10.65.2.1
上:
1 | ip link add gre1 type gretap local 10.65.0.6 remote 10.65.0.2 |
此时两侧应该可以通过gre隧道ping通:
1 | PING 10.66.0.2 (10.66.0.2) 56(84) bytes of data. |
创建Bonding
注意: 向bonding添加slave时, 对应的设备状态不能为up.
在Router 10.65.2.2
上:
1 | ip link add bond0 type bond |
这里, 由于需求是尽量使用带宽, 这里采用了balance-rr
模式, 即平均分配入流量到两个接口上. 此外还有 active-backup
, balance-xor
, broadcase
, 802.3ad
, balance-tlb
, balance-alb
等模式.
在Router 10.65.2.1
上:
1 | ip link add bond0 type bond |
此时两侧应该可以通过bond0
的地址ping通:
1 | PING 10.67.0.1 (10.67.0.1) 56(84) bytes of data. |
不知道为什么, 在两侧bond0
都启动完成后, 如果只从一侧开始ping刚开始并不能ping通, 如果此时从另一侧也开始ping, 那么两侧从此都可以互相ping通. 推测可能是没有给bond0
设置miimon
等参数导致的. (MIIMON是Media Independent Interface Monitoring的缩写)
bonding的状态可以通过 /proc/net/bonding/bond0
获取:
1 | Ethernet Channel Bonding Driver: v3.7.1 (April 27, 2011) |
至此已基本搭建完毕. 在两侧通过bond0
的地址使用iperf3
进行测速, 实测可以达到几乎双倍的速度.
另外, 由于底层网络基于WG+OSPF, 当网络中有节点掉线的时, bond接口会有短暂的丢包(实际观测看要>50%, 几乎65%) 经过一段时间OSPF完成收敛后(默认配置下大约45秒), bond接口就会恢复正常. 推测如果bond接口本身配置了miimon可能在bond层会先剔除掉超时的slave.
最后我们来计算一下开销:
只考虑IPv4的情况下, 从外到内分别是:
- 外层IPv4, 20 bytes
- UDP, 8 bytes
- WireGuard, 32 bytes
- 内层IPv4, 20 bytes
- GRE, 4 bytes
- 以太网帧头部, 14 bytes (因为用的是L2 GRETAP)
最终在基础MTU=1500
的前提下, 最内层MTU还剩下1402
. 如果外层内层均更换为IPv6, 由于IPv6 header为40 bytes, 那么最后留给最内层的MTU还剩下1362
, 距离IPv6要求的最低1280
还有一点空间.
最开始给gre隧道挂到bridge下面了, 结果两边bridge一开直接回环网络风暴… = =||
参考资料
GRE bridging, IPsec and NFQUEUE
SETUP GRE TUNNEL ON UBUNTU 20 LINUX SERVER
Syntax for changing the bond mode of an interface
ip-link(8) — Linux manual page
10.5 Configuring Network Interface Bonding
Switch flooding when bonding interfaces in Linux