EIGRP在邻居关系建立后,如果某条路由丢失且没有可行后继,路由器会向邻居发送查询报文并进入活动状态。如果查询在指定时间内没有收到所有邻居的应答,该路由就会被标记为SIA(Stuck In Active),默认时间通常是三分钟。这个参数虽然看似简单,但直接影响网络在链路故障后的收敛行为。使用Ruby脚本批量调整查询超时时间,可以避免手动重复劳动,也能保证配置一致性。

理解EIGRP SIA查询超时的作用
在EIGRP拓扑表中,每条路由都有一个状态机。当路由进入Active状态后,路由器会向所有邻居发送查询,并启动一个活动计时器。如果在计时器到期前没有收到所有邻居的应答,路由就会进入SIA状态,邻居关系可能被重置,进而引发更严重的路由震荡。
默认的活动计时器在三分钟,这在低速广域网链路或大型网络中可能会过于宽松或者过于紧张。例如,当链路延迟较高时,三分钟可能不够,导致频繁SIA;而在小型园区网中,三分钟又太长,故障收敛被拖慢。因此,根据实际链路质量调整timers active-time是必要的。
需要注意的是,这个计时器只影响查询阶段,不会影响正常的路由更新周期。配置时应该结合hold-time和hello-interval一起评估,不能孤立修改。
使用Ruby通过SSH下发配置命令
Ruby的Net::SSH库提供了稳定的SSH连接能力,适合批量执行网络设备命令。下面先封装一个通用的命令执行函数,负责登录设备并进入配置模式。
require 'net/ssh'
def exec_commands(host, user, password, commands)
Net::SSH.start(host, user, password: password) do |ssh|
ssh.exec!('enable')
ssh.exec!('configure terminal')
commands.each do |cmd|
result = ssh.exec!(cmd)
puts "#{host} 执行 #{cmd}: #{result}"
end
ssh.exec!('end')
ssh.exec!('write memory')
end
end
上述代码只是一个示意,真实环境中还需要处理enable密码和分页输出。更稳妥的做法是使用Net::SSH::Telnet或者基于expect的交互,例如发送命令后等待提示符。为了保持简单,这里直接使用ssh.exec!串行执行命令。
在配置EIGRP时,命令序列通常为router eigrp 100、timers active-time 5、exit,最后保存配置。下面的函数将这一序列封装成数组,并支持传入AS号与超时分钟数。
def configure_eigrp_active_time(host, user, password, as_number, active_time)
commands = [
"router eigrp #{as_number}",
"timers active-time #{active_time}",
"exit"
]
exec_commands(host, user, password, commands)
end
这里把exec_commands作为通用命令执行入口,具体实现需要处理提示符检测。如果你管理的设备启用了SSH密钥认证,可以将密码参数设为nil并传入密钥文件。建议不要把明文密码写死在脚本里,使用环境变量或密钥管理工具。
参数校验与批量执行策略
超时时间并非越大越好。如果设置得过小,正常网络抖动就可能触发SIA;如果设置得过大,故障检测会被显著延迟。一般来说,5到10分钟是比较常见的调整范围,但必须根据网络规模和链路RTT来估算。脚本里应该加入参数校验,避免误输入负数或非整数。
def validate_active_time(value)
time = value.to_i
if time < 1 || time > 60
raise ArgumentError, "active-time 必须在1到60分钟之间"
end
time
end
批量执行时,建议先在一个低风险设备上测试,再逐步推广。设备清单可以用YAML或JSON存储,脚本逐台读取并执行。对于每台设备,记录成功或失败状态,最后汇总输出。失败时不要中断整个流程,而是捕获异常并继续处理下一个设备。
下面给出一个简单的批量执行示例,使用数组存设备信息:
devices = [
{ host: '10.1.1.1', user: 'admin', password: ENV['IOS_PASSWORD'], as_number: 100, active_time: 5 },
{ host: '10.1.1.2', user: 'admin', password: ENV['IOS_PASSWORD'], as_number: 100, active_time: 5 }
]
devices.each do |device|
begin
time = validate_active_time(device[:active_time])
configure_eigrp_active_time(device[:host], device[:user], device[:password], device[:as_number], time)
puts "成功:#{device[:host]} 已配置 active-time 为 #{time} 分钟"
rescue StandardError => e
warn "失败:#{device[:host]} - #{e.message}"
end
end
这段代码中使用了环境变量ENV['IOS_PASSWORD']来避免硬编码密码。注意在begin-rescue块中捕获的是StandardError,这样不会吞掉脚本本身的语法错误,只处理运行期连接或配置异常。
配置验证与回滚建议
修改EIGRP计时器后,应该确认命令是否真正生效。可以通过show running-config | include active-time或show ip protocols查看当前值。虽然write memory会保存配置,但如果验证发现异常,需要快速回滚。建议在修改前先备份当前配置,使用show running-config并保存到本地文件。
在Ruby脚本中,可以在执行修改命令前先下载一份running-config,这样即使配置出现问题,也能通过copy tftp://... running-config或手动粘贴恢复。对于高可用网络,建议将EIGRP SIA超时调整安排在维护窗口,并配合监控观察邻居抖动次数。
最后,关于Ruby自动化本身,如果想进一步简化,可以考虑使用Cisco的restconf或netconf接口。这些API方式不需要处理PTY和分页,返回结构化数据,但要求设备支持相应的Yang模型。对于传统IOS设备,基于SSH的命令行操作仍然是成本最低的方案。