IS-IS作为经典的链路状态路由协议,在运营商和大型企业网络中应用广泛。在广播型网络中,IS-IS需要选举一个指定中间系统(DIS)来负责生成伪节点LSP,而DIS的选举结果完全由接口优先级决定。传统的手工配置方式在设备数量多、接口规模大的场景下效率低下,且容易出现遗漏。本文将以Ruby脚本为工具,讲解如何批量完成IS-IS DIS优先级的配置下发与优化。
一、IS-IS DIS选举机制与优先级的作用
在IS-IS的广播网络(如以太网)中,DIS的角色类似于OSPF中的DR,负责代表网段生成伪节点LSP,减少网络中LSP的数量和泛洪开销。与OSPF不同的是,IS-IS的DIS选举没有BDIS的概念,也没有备用设备,一旦DIS失效会立即重新选举。
DIS的选举规则比较简单:比较接口的DIS优先级,数值越大越优先;优先级相同时,比较SNPA地址(以太网中即MAC地址),MAC地址最大者当选。值得注意的是,IS-IS的DIS优先级取值范围是0到127,其中0并不代表不参与选举,这与OSPF中优先级0不参与DR选举的规则完全不同,是配置时最容易踩的坑之一。
另一个重要特性是DIS支持抢占。也就是说,如果后续接入了一台优先级更高的设备,原有DIS会被立即替代。这在网络扩容或设备替换时可能引发LSP的重新泛洪,因此合理规划优先级取值比单纯设置一个高数值更有意义。通常的做法是将核心或性能更强的设备设置为较高优先级,比如100以上,接入设备保持在默认值64左右,从而让DIS稳定落在期望的设备上。
二、用Ruby实现配置批量下发的基础框架
Ruby拥有成熟的Net::SSH库,可以方便地建立SSH会话并向网络设备逐条发送配置命令。相比手工登录每台设备敲命令,脚本化下发能够保证配置的一致性,并且可以配合日志记录实现完整的操作审计。下面先看一个基础的下发框架。
require 'net/ssh'
# 设备清单,可以从文件或数据库中读取
devices = [
{ host: '192.168.0.1', user: 'admin', password: 'password' },
{ host: '192.168.0.2', user: 'admin', password: 'password' }
]
# 需要下发的IS-IS DIS优先级配置命令
commands = [
'interface GigabitEthernet0/0/1',
'isis dis-priority 100'
]
devices.each do |dev|
Net::SSH.start(dev[:host], dev[:user], password: dev[:password]) do |ssh|
channel = ssh.open_channel do |ch|
ch.request_pty do |pty, success|
raise 'Failed to request pty' unless success
end
ch.send_channel_request('shell') do |sh, success|
raise 'Failed to open shell' unless success
end
ch.on_data do |c, data|
puts "#{dev[:host]}: #{data}"
end
# 逐条发送命令,注意每条命令后需要回车
commands.each { |cmd| ch.send_data(cmd + "\n") }
# 进入系统视图并发送退出命令
ch.send_data("system-view\n")
ch.send_data("commit\n")
ch.send_data("quit\n")
ch.send_data("quit\n")
end
channel.wait
end
rescue => e
puts "连接 #{dev[:host]} 失败: #{e.message}"
end
上面的脚本展示了核心流程:建立SSH连接、请求伪终端、打开shell通道、依次发送命令。实际使用时需要注意不同厂商设备的命令差异,例如有些设备需要先进入系统视图再配置接口,有些设备在配置后需要执行保存命令。同时建议为每台设备添加超时控制和异常捕获,避免一台设备故障导致整个批量任务中断。
为了提升脚本的可维护性,可以把设备清单和配置命令拆分到独立的YAML文件中,脚本启动时加载即可。这样当网络拓扑调整时,只需要修改配置文件而不必改动代码逻辑,符合配置与代码分离的工程化实践。
三、动态计算优先级的优化策略
简单地下发固定优先级只是第一步,更进阶的做法是让脚本根据接口属性自动计算合理的优先级。例如,可以依据接口带宽、设备角色(核心、汇聚、接入)以及是否为冗余组主设备来动态赋值,让DIS始终落在转发能力最强的节点上。
一种常见的策略是分层赋值:核心设备接口优先级设为120,汇聚设备设为100,接入设备保持默认64。同时为了避免同一网段两台同角色设备优先级相同导致依赖MAC地址裁决,可以在脚本中为同组设备分配一个微小的差值,比如主设备120、备设备115,这样既保证了主设备长期担任DIS,又能在主设备故障时备设备快速接管。
require 'yaml'
# 从YAML文件加载拓扑信息
topology = YAML.load_file('topology.yml')
def calculate_priority(node)
base = { 'core' => 120, 'aggregation' => 100, 'access' => 64 }
prio = base[node['role']] || 64
# 冗余组中主设备额外加5,保证确定性选举
prio += 5 if node['redundancy_role'] == 'primary'
prio
end
topology['nodes'].each do |node|
priority = calculate_priority(node)
puts "#{node['hostname']} (#{node['role']}) => DIS优先级: #{priority}"
# 这里调用第二节的下发逻辑,将计算结果推送到设备
end
除了角色分级,还可以结合带宽因子做细化。例如在1000M接口和100M接口共存的网段中,将带宽作为次要权重加到基础优先级上,让大带宽接口优先承担DIS职责,从而减少伪节点LSP同步对窄带宽链路的压力。这种计算逻辑完全由Ruby代码实现,规则集中、易于调整,是脚本方案相对手工配置的显著优势。
四、配置验证与回滚机制
配置下发后必须验证生效情况。验证通常分两步:一是通过display isis interface或类似命令查看接口当前的DIS优先级;二是在网段内任一设备上执行display isis packet或查看邻居详细信息,确认DIS的实际选举结果与规划一致。Ruby脚本可以将验证命令的回显捕获下来,与预期值做字符串比对,自动生成核对报告。
expected = { 'GE0/0/1' => 120, 'GE0/0/2' => 100 }
def verify_dis_priority(ssh, expected)
output = ''
ssh.exec!('display isis interface') { |_, _, data| output << data }
expected.each do |intf, prio|
if output.include?(intf) && output.include?(prio.to_s)
puts "[PASS] #{intf} 优先级 #{prio} 已生效"
else
puts "[FAIL] #{intf} 期望优先级 #{prio},请人工检查"
end
end
end
对于生产环境,建议在脚本中加入回滚机制:下发前先执行命令采集当前配置并保存到本地文件,一旦验证失败,自动使用备份配置恢复原状。回滚逻辑可以用一个简单的状态标记实现,验证全部通过才标记本次任务成功,否则触发恢复流程。这样即使脚本存在缺陷,也不会让网络长时间处于错误配置状态。
最后提醒两点:一是修改DIS优先级会触发抢占,建议在业务低峰期执行批量操作;二是脚本中的设备凭据不要硬编码,可通过环境变量或专用的凭据管理工具注入,保证安全性。通过Ruby脚本配合合理的优先级规划策略,IS-IS DIS的配置管理可以从重复劳动转变为一次性的自动化任务,大幅降低人为失误的风险。