1. 背景
过去传统的网络聚合方案是使用交换机堆叠技术,两台交换机之间需要堆叠线缆连接,这种使用方式一直沿用。随着互联网规模越来越大,交换机数量成倍增加,质量问题也越来越严重,传统的堆叠技术也面临着诸多挑战,其中成员交换机故障风险、交换机系统bug、软件版本升级问题等都会对网络可用性造成影响,因此网络技术发展出了去堆叠的方案,这种方案在物理形态上去掉了传统的堆叠线缆,两台交换机独立工作,同时服务器依然采用双上联bond模式,提高了网络可靠性。
2. 方案
关于去堆叠技术的设计方案,网上有很多介绍,这里我们选择了去堆叠技术中的ARP转主机路由的方式,这种方式服务器侧的网络配置不变,但是需要修改linux内核支持ARP双发。
网络架构
3. 实现
目前我们使用的操作系统是ubuntu22.04,内核使用的是5.15.0操作系统标配内核未做任何修改,之前我们基于3.10的内核做过ARP收发的分析:
#内核在发送arp请求时函数调用栈为:
arp_solicit
|
arp_send_dst -> arp_create
|
arp_xmit
|
dev_queue_xmit
|
dev_hard_start_xmit:此时网卡为虚拟网卡bond0,不存在队列queue,因此没有通过队列直接发送数据,而进入到此函数
|
netdev_start_xmit:根据bond的模式,会进入不同的net_device_ops,对于mode4模式,外出流量的slave选举是基于传输hash策略实现的,该策略能够经过xmit_hash_policy选项从缺省的XOR策略改变到其余策略,因此实际需要关注的是XOR模式,实现函数是bond_3ad_xor_xmit
|
bond_3ad_xor_xmit -> bond_xmit_hash:选择bond的一个slave网卡
#了解一下bond的7种模式
通过之前的分析,套用到此次ubuntu22.04的系统上,同样需要关注bond_3ad_xor_xmit函数,来修改和配置ARP报文的发送。在原本的发送过程中:根据流量HASH原理,ARP报文会按照算法选择BOND成员网卡中的一个进行发送。
#通过hash选择其中一个绑定的网卡成员
slave = bond->arr[bond_xmit_hash(bond, skb) % count];
因此,为了广播ARP包,我们在bond_3ad_xor_xmit中,检查数据包的类型,如果是ARP报文,则进行广播发送,广播发送的实现函数bond_xmit_broadcast,相关修改代码
#切换到源码目录
vim ./drivers/net/bonding/bond_main.c
#改变内容如下
#static netdev_tx_t bond_xmit_broadcast本来存在,不要动,但是需要在bond_3ad_xor_xmit之前再定义一次,避免编译器无法找到bond_xmit_broadcast函数的声明,防止编译过程报错
static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev);
static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
struct bond_up_slave *slaves;
struct slave *slave;
**//判断数据包的类型是否为ARP包
if (skb->protocol == htons(ETH_P_ARP)){
//ARP包进行广播发送
return bond_xmit_broadcast(skb, dev);
}**
slaves = rcu_dereference(bond->usable_slaves);
slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves);
if (likely(slave))
return bond_dev_queue_xmit(bond, skb, slave->dev);
return bond_tx_drop(dev, skb);
}
修改完代码以后,测试效果如下:
通过tcpdump any arp 我们可以看到bond模式下的eth0、eth1都在发送ARP广播,最终实现ARP双发的能力,支持去堆叠方案。
4. 扩展
记录整体实现过程
#下载源码
apt install linux-source
#安装必要软件
apt install openssl flex bison ncurses* libelf-dev libssl-dev libffi-dev build-essential dwarves
#配置
make menuconfig
vim .config
CONFIG_DEBUG_INFO_BTF=n
CONFIG_SYSTEM_TRUSTED_KEYSEYS=""
CONFIG_SYSTEM_REVOCATION_KEYS=""
#修改内核源码
vim ./drivers/net/bonding/bond_main.c
static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev);
static netdev_tx_t bond_3ad_xor_xmit(struct sk_buff *skb,
struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
struct bond_up_slave *slaves;
struct slave *slave;
//判断数据包的类型是否为ARP包
if (skb->protocol == htons(ETH_P_ARP)){
//ARP包进行广播发送
return bond_xmit_broadcast(skb, dev);
}
slaves = rcu_dereference(bond->usable_slaves);
slave = bond_xmit_3ad_xor_slave_get(bond, skb, slaves);
if (likely(slave))
return bond_dev_queue_xmit(bond, skb, slave->dev);
return bond_tx_drop(dev, skb);
}
#编译,64为CPU核心数
make -j 64 CFLAGS_MODULE=-fno-strict-aliasing
#安装模块
make modules_install
#安装内核,注意安装内核完毕后的系统启动问题
make install
#可选操作,制作deb内核文件,后续可以做内核升级使用,并推到线上
make bindeb-pkg -j 64 #64为CPU核心数
- 网络BGP模式下bond成员端口up/down后的路由收敛时间过长的问题,目前使用ifplugd进程监控物理连接,bond成员端口发生up/down时执行相应ARP Ping和路由修改操作。