当前位置: 首页 > news >正文

Rocky9.0去堆叠双发arp(支持“ARP 广播双发”)

摘要

在去堆叠/MLAG 场景下,默认 bonding 只会以单口回复 ARP,另一台交换机收不到 ARP Reply。本文在 Linux bonding 驱动中增加参数 arp_broadcast_mode,当开启时对 ARP 包临时切换到 广播模式,实现双口同时发 ARP Reply。文内提供可直接套用的补丁与完整编译、替换、验证流程,并覆盖常见坑位(Module.symvers 不匹配、Secure Boot、NetworkManager/ifcfg、sshd OpenSSL 版本错配等)。


基础信息

  • OS:Rocky Linux 9.0(RHEL 9 系列适用)

  • 内核:5.14.0-70.13.1.el9_0.x86_64

  • bonding 模式:mode=6(balance-alb,其他模式同理)

  • 构建工具:gcc make bison flex elfutils-libelf-devel openssl-devel perl kernel-devel kernel-headers

关键点:运行内核版本必须与kernel-devel 版本一致,否则会出现 Module.symvers missing / undefined symbol 等问题。


一、环境准备

1. 确认内核版本

uname -r

例如:5.14.0-70.13.1.el9_0.x86_64

2. 安装依赖工具链

dnf install -y gcc make bison flex elfutils-libelf-devel \openssl-devel perl

注:依据实际情况,如有其他依赖正常安装即可。 PS:最好直接报报错给大模型,输出命令执行就行。 

3. 安装内核开发包(必须和 uname -r 一致)

dnf download --source kernel-$(uname -r) rpm -ivh kernel-*.src.rpm

如果下载的不对dnf,你就要手动安装如下三个包。 

rpm -ivh kernel-5.14.0-70.13.1.el9_0.src.rpm  
rpm -ivh kernel-devel-5.14.0-70.13.1.el9_0.x86_64.rpm  
rpm -ivh kernel-headers-5.14.0-70.13.1.el9_0.x86_64.rpm

 源码安装后会解压到:

ls ~/rpmbuild/BUILD/kernel-<version>/

其实就是安装这三个包,如果你看到安装的不是, 那你就自己下载就行。 

https://dl.rockylinux.org/stg/rocky/9.0-sources-only/tree/Packages/k/kernel-5.14.0-70.13.1.el9.src.rpm

https://downloads.rockylinux.org/vault/rocky/9.0/devel/x86_64/kickstart/Packages/k/kernel-devel-5.14.0-70.13.1.el9_0.x86_64.rpm

https://downloads.rockylinux.org/vault/rocky/9.0/devel/x86_64/kickstart/Packages/k/kernel-headers-5.14.0-70.13.1.el9_0.x86_64.rpm

验证:

ls -ld /lib/modules/$(uname -r)/build 
ls /usr/src/kernels/$(uname -r)/

正常会看到对应源码目录存在。

二、补丁说明(新增模块参数 + 仅对 ARP 强制临时广播)

思路:

  1. bond_main.c 中新增可控参数:

/* ---- ARP broadcast extension ---- */
static int arp_broadcast_mode = 0;
module_param(arp_broadcast_mode, int, 0644);
MODULE_PARM_DESC(arp_broadcast_mode,"broadcast ARP packet to all slaves, 0=off(default), 1=on.");

2.在 __bond_start_xmit() 函数里,仅当是 ARP 且开关=1 时,将 switch (BOND_MODE(bond)) 动态替换为 BOND_MODE_BROADCAST,从而实现仅对 ARP双发。对其他报文不影响原有模式。


    三、开始打补丁(适配 RHEL9 5.14 源码)

    文件路径:~/rpmbuild/BUILD/kernel-<version>/drivers/net/bonding/bond_main.c
    说明:上下文行适配 RHEL9 5.14;若行号有偏差,可采用“手工改动”或下文“一键 sed”方案。

    我测试的路径:/root/rpmbuild/BUILD/kernel-5.14.0-70.13.1.el9_0/linux-5.14.0-70.13.1.el9.x86_64/drivers/net/bonding

    增加1:打开之后放在include部分第一行就行

    #include <linux/moduleparam.h>

    增加2:放在#include部分最后就行。 

    /* ---- ARP broadcast extension ---- */
    static int arp_broadcast_mode = 0;
    module_param(arp_broadcast_mode, int, 0644);
    MODULE_PARM_DESC(arp_broadcast_mode,"broadcast ARP packet to all slaves, 0=off(default), 1=on.");
    

    在我的测试里, 我把#include <linux/moduleparam.h> 放在了首行,如图:

    增加3:检索 __bond_start_xmit部分,

    注意,+号是增加的内容, +号不用复制。-号部分是删除的。 

    static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev){struct bonding *bond = netdev_priv(dev);
    +
    +       /* ARP-only broadcast trigger */
    +       bool is_arp = (vlan_get_protocol(skb) == cpu_to_be16(ETH_P_ARP));
    +       bool do_bcast = arp_broadcast_mode && is_arp;if (bond_should_override_tx_queue(bond) &&!bond_slave_override(bond, skb))return NETDEV_TX_OK;#if IS_ENABLED(CONFIG_TLS_DEVICE)if (skb->sk && tls_is_sk_tx_device_offloaded(skb->sk))return bond_tls_device_xmit(bond, skb, dev);#endif
    -       switch (BOND_MODE(bond)) {
    +       switch (do_bcast ? BOND_MODE_BROADCAST : BOND_MODE(bond)) {case BOND_MODE_ROUNDROBIN:return bond_xmit_roundrobin(skb, dev);case BOND_MODE_ACTIVEBACKUP:

    如果补丁由于上下文差异无法直接打入,建议手工按“三处改动”完成:①在 include 区增加 #include <linux/moduleparam.h>;②在全局参数区增加 arp_broadcast_mode 参数;③在 __bond_start_xmit() 里加 is_arp/do_bcast 并替换 switch


    四、(可选)一键 sed 注入脚本

    在源码根目录Makefile 所在处)执行:

    # 1) 确保引入 moduleparam 头(若已有不会重复)
    grep -q 'linux/moduleparam.h' drivers/net/bonding/bond_main.c || \sed -i '/#include <linux\/preempt.h>/a #include <linux/moduleparam.h>' drivers/net/bonding/bond_main.c# 2) 在 "bonding_priv.h" 之后插入参数块(若已存在请忽略)
    awk '
    /#include "bonding_priv.h"/ && !done {print;print "";print "/* ---- ARP broadcast extension ---- */";print "static int arp_broadcast_mode = 0;";print "module_param(arp_broadcast_mode, int, 0644);";print "MODULE_PARM_DESC(arp_broadcast_mode,";print "        \"broadcast ARP packet to all slaves, 0=off(default), 1=on.\");";print "";done=1; next
    }1' drivers/net/bonding/bond_main.c > .bond_main.c.new && mv .bond_main.c.new drivers/net/bonding/bond_main.c# 3) 在 __bond_start_xmit() 中插入 is_arp/do_bcast(若已插过会失败,忽略即可)
    sed -i '/struct bonding \*bond = netdev_priv(dev);/a \ \ \ \ bool is_arp = (vlan_get_protocol(skb) == cpu_to_be16(ETH_P_ARP));\n\ \ \ \ bool do_bcast = arp_broadcast_mode && is_arp;' drivers/net/bonding/bond_main.c# 4) 仅替换 __bond_start_xmit() 中的第一个 switch
    awk 'BEGIN{infunc=0; depth=0}/static netdev_tx_t __bond_start_xmit\(struct sk_buff \*skb, struct net_device \*dev\)/{infunc=1}{if(infunc && $0 ~ /switch \(BOND_MODE\(bond\)\) \{/ && !done){sub(/switch \(BOND_MODE\(bond\)\) \{/, "switch (do_bcast ? BOND_MODE_BROADCAST : BOND_MODE(bond)) {"); done=1}print}/{/{if(infunc) depth++}/}/{if(infunc){depth--; if(depth==0) infunc=0}}
    ' drivers/net/bonding/bond_main.c > .bond_main.c.new && mv .bond_main.c.new drivers/net/bonding/bond_main.c
    

    五、编译 bonding 模块

    1)我们在第一步环境准备时已经安装好相关源码包了

    2)进入源码目录并构建(外部构建,确保符号版本匹配)

    cd ~/rpmbuild/BUILD/kernel-5.14.0-70.13.1.el9_0/linux-5.14.0-70.13.1.el9.x86_64# 使用当前运行内核的配置
    cp -v /boot/config-$(uname -r) .config
    yes "" | make olddefconfig# 准备头文件(只有第一次需要)
    make prepare && make modules_prepare# 用匹配内核的 build 来编译指定子目录模块(推荐)
    make -C /lib/modules/$(uname -r)/build M=$PWD/drivers/net/bonding clean
    make -C /lib/modules/$(uname -r)/build M=$PWD/drivers/net/bonding modules -j"$(nproc)"
    

    产物:drivers/net/bonding/bonding.ko

    提示 “Skipping BTF generation … vmlinux 不在” 不影响加载。


    六、部署并让系统优先用自编译模块

    方案 A(推荐):放到 weak-updates 并覆盖 modprobe 安装行为

    # 放置新模块
    mkdir -p /lib/modules/$(uname -r)/weak-updates/bonding/
    cp -v drivers/net/bonding/bonding.ko /lib/modules/$(uname -r)/weak-updates/bonding/
    depmod -a# 持久化默认参数(开启双发)
    echo 'options bonding arp_broadcast_mode=1' > /etc/modprobe.d/bonding.conf# 强制 modprobe 始终加载我们这份(避免回退到内置 .xz)
    cat >/etc/modprobe.d/override-bonding.conf <<'EOF'
    install bonding /sbin/insmod /lib/modules/$(uname -r)/weak-updates/bonding/bonding.ko $CMDLINE_OPTS
    EOF
    

    之后 modprobe bonding 会优先加载我们放在 weak-updates 的模块。

    Secure Boot 提醒:若启用 Secure Boot,加载未签名模块会报 Required key not available。需关闭 Secure Boot 或对 bonding.ko 本地签名并导入 MOK。

    重新加载

    modprobe -r bonding 2>/dev/null || true modprobe bonding

    验证参数存在:

    modinfo bonding | egrep 'filename|vermagic|parm'
    # filename 应指向 weak-updates/bonding/bonding.ko
    # parm 应含 arp_broadcast_modecat /sys/module/bonding/parameters/arp_broadcast_mode   # 应=1
    

    注意:有可能你编译的内核和使用的内核一样, 所以加载的bonding需要注意一下,使用的是新编译的内核, 还是老内核。 


    七、网络脚本参考(ifcfg)

    /etc/sysconfig/network-scripts/ifcfg-bond0

    DEVICE=bond0
    NAME=bond0
    TYPE=Bond
    ONBOOT=yes
    BOOTPROTO=none
    IPADDR=10.10.10.11
    NETWORK=24
    GATEWAY=10.10.10.1
    NM_CONTROLLED=yes
    BONDING_OPTS="mode=6 miimon=100"
    

    /etc/sysconfig/network-scripts/ifcfg-eth0

    DEVICE=eth0
    TYPE=Ethernet
    BOOTPROTO=none
    ONBOOT=yes
    MASTER=bond0
    SLAVE=yes
    NM_CONTROLLED=yes
    

    /etc/sysconfig/network-scripts/ifcfg-eth1

    DEVICE=eth1
    TYPE=Ethernet
    BOOTPROTO=none
    ONBOOT=yes
    MASTER=bond0
    SLAVE=yes
    NM_CONTROLLED=yes
    

    启用:

    nmcli con reload
    nmcli con up bond0
    cat /proc/net/bonding/bond0
    

    八、功能验证(ARP 双发)

    方法一:远端 ping 触发 ARP

    # 终端A
    tcpdump -ni eth0 arp -vv
    # 终端B
    tcpdump -ni eth1 arp -vv
    

    在另一台同网段机器 ping bond0_IP,你应看到同一时间两个口都有 ARP Reply。

    方法二:本机主动 arping

    arping -c 3 -I bond0 <对端IP或网关IP>
    # 同时在 eth0/eth1 抓包观察
    

    九、常见坑位与排障速查

    1. Module.symvers 缺失/符号未定义

    • 现象:Module.symvers missingundefined symbol …

    • 处理:确保 kernel-develuname -r 一致;使用
      make -C /lib/modules/$(uname -r)/build M=... 外部构建。

    1. 加载到旧模块(.xz)

    • 现象:modinfo bonding | grep filename 显示 .xz

    • 处理:modprobe -r bondingdepmod -a → 用 override-bonding.conf 强制 insmod 我们的 weak-updates 版本。

    1. Secure Boot 导致无法加载

    • 报错:Required key not available

    • 处理:关闭 Secure Boot 或签名模块并导入 MOK。

    1. bond0 为 DOWN 或无 IP

    • 检查:cat /proc/net/bonding/bond0,确认 slave 绑定与 MII Status

    • 给 bond0 配置 IP/PREFIX,BONDING_OPTS 中设置 miimon=100

    • nmcli con up bond0 后再 ip a show bond0

    1. sshd 起不来(OpenSSL 版本错配)

    • 错误:OpenSSL version mismatch. Built against 30000010, you have 30200020

    • 处理:升级 openssh-server 到与系统 OpenSSL 对齐的版本(Rocky 有 8.7p1-45.el9.rocky.0.1 等),或降级 OpenSSL(不推荐)。


    十、结语

    本文通过极小的代码改动,为 bonding 增加了 arp_broadcast_mode 参数,实现仅对 ARP 报文的“临时广播”,从而满足去堆叠/MLAG 场景下的“双发 ARP”需求。方案对非 ARP 流量无侵入,并保留原有模式行为。生产环境上线前,建议在维护时段配合交换机侧做充分验证。


    附:最小操作清单(懒人版)

    # 0) 安装匹配的 kernel-devel
    rpm -ivh --oldpackage /opt/kernel-devel-$(uname -r).x86_64.rpm# 1) 修改源码 (按上文补丁三处改动)
    cd ~/rpmbuild/BUILD/kernel-*/linux-*/   # 进入源码根
    # (可用上文 sed 快捷脚本)# 2) 构建
    cp -v /boot/config-$(uname -r) .config
    yes "" | make olddefconfig
    make prepare && make modules_prepare
    make -C /lib/modules/$(uname -r)/build M=$PWD/drivers/net/bonding clean
    make -C /lib/modules/$(uname -r)/build M=$PWD/drivers/net/bonding modules -j"$(nproc)"# 3) 部署 + 持久化参数
    mkdir -p /lib/modules/$(uname -r)/weak-updates/bonding/
    cp -v drivers/net/bonding/bonding.ko /lib/modules/$(uname -r)/weak-updates/bonding/
    depmod -a
    echo 'options bonding arp_broadcast_mode=1' > /etc/modprobe.d/bonding.conf
    cat >/etc/modprobe.d/override-bonding.conf <<'EOF'
    install bonding /sbin/insmod /lib/modules/$(uname -r)/weak-updates/bonding/bonding.ko $CMDLINE_OPTS
    EOF# 4) 重载并验证
    modprobe -r bonding 2>/dev/null || true
    modprobe bonding
    modinfo bonding | egrep 'filename|parm'
    cat /sys/module/bonding/parameters/arp_broadcast_mode# 5) 抓包验证
    tcpdump -ni eth0 arp -vv &
    tcpdump -ni eth1 arp -vv &
    # 在另一台同网段 ping bond0_IP,观察两口同时 ARP Reply
    


    文章转载自:

    http://h5bM6YRS.qcwck.cn
    http://quut1Ahv.qcwck.cn
    http://xtaKxS8d.qcwck.cn
    http://lxZJRKtg.qcwck.cn
    http://I5XvDfLX.qcwck.cn
    http://GjJH8qTm.qcwck.cn
    http://DSdr50rF.qcwck.cn
    http://hGGfWPib.qcwck.cn
    http://2IX3dacP.qcwck.cn
    http://iVjqo3Jy.qcwck.cn
    http://aXIV5c8G.qcwck.cn
    http://mFkWe3W8.qcwck.cn
    http://q7g5LwvF.qcwck.cn
    http://3xh97ADg.qcwck.cn
    http://pTnwFMH0.qcwck.cn
    http://dAhhuLWp.qcwck.cn
    http://rsH6NSDq.qcwck.cn
    http://aO3S9Okd.qcwck.cn
    http://sJTIbw4K.qcwck.cn
    http://UdlKed0d.qcwck.cn
    http://Quu2th9o.qcwck.cn
    http://UCvxeQaO.qcwck.cn
    http://cPwvJvHw.qcwck.cn
    http://p64WNlG9.qcwck.cn
    http://7WqHvM3i.qcwck.cn
    http://ubH0uZv0.qcwck.cn
    http://GMyvC7yd.qcwck.cn
    http://Z9HEDA3h.qcwck.cn
    http://rBaN0Vix.qcwck.cn
    http://MwONGMOF.qcwck.cn
    http://www.dtcms.com/a/378904.html

    相关文章:

  1. 「京墨」1.15.0 诗词、成语、对联、句子、诗歌…
  2. AWS TechFest 2025: 风险模型的转变、流程设计的转型、生成式 AI 从实验走向实施的三大关键要素、评估生成式 AI 用例的适配度
  3. 【Blender】二次元人物制作【二】:五官的制作
  4. MinIO集群部署详细步骤(高性能的分布式对象存储系统)
  5. 带地图的 RAG:多模态 + 地理空间 在 Elasticsearch 中
  6. 使用 Spring AI Alibaba Graph 实现工作流
  7. 【Debug日志 | DDP 下 BatchNorm 统计失真】
  8. linux C 语言开发 (六) 程序的编辑和编译(vim、gcc)
  9. 综合文化信息管理系统|基于java和小程序的综合文化信息管理系统设计与实现(源码+数据库+文档)
  10. 20250911_10.1.11.46车辆定位aidata-01_Apache Doris分布式数据库全量备份(本地+异地)Python脚本
  11. DenseNet网络
  12. 2025胶水分装机服务商技术解析:聚焦高精度、智能化应用
  13. Drawnix白板本地部署指南:cpolar实现远程创意协作
  14. leetcode189.轮转数组
  15. SPI设备驱动
  16. 第七节,探索 ​​CSS 的高级特性、复杂布局技巧、性能优化以及与现代前端工作流的整合(二)
  17. O3.2 opencv高阶
  18. c语言,识别到黑色就自动开枪,4399单击游戏狙击战场,源码分享,豆包ai出品
  19. Spring Boot 原理与性能优化实战
  20. PHP 性能优化实战 OPcache + FPM 极限优化配置
  21. solidity的高阶语法(完结篇)
  22. 端–边–云一体的实时音视频转发:多路RTSP转RTMP推送技术深度剖析
  23. OPC Client第10讲:实现主界面;获取初始界面传来的所有配置信息config【C++读写Excel:xlnx;ODBC;缓冲区】
  24. git的使用命令
  25. uniapp | 实现微信小程序端的分包处理
  26. C/C++项目练习:命令行记账本
  27. mes之生产管理
  28. 【51单片机】【protues仿真】基于51单片机多功能电子秤系统
  29. VSCode 下 PlatformIO 的使用
  30. Shell编程:生成10个随机数,并判断最大值和最小值