在二层交换网络中,冗余链路一方面提升了可用性,另一方面也可能在缺乏控制机制时构成环路。一旦广播帧进入环路,便会在各交换机间无限复制转发,迅速耗尽带宽与设备CPU资源,这就是典型的广播风暴。使用Ruby编写轻量探测程序,可以在不依赖专业网管软件的情况下,主动发现拓扑中的环路隐患并自动阻塞多余链路。

环路产生原理与为何需要主动检测
以太网交换机默认对广播、未知单播和组播帧执行泛洪操作。当两台交换机之间通过两条或更多物理链路互联,且这些链路同属一个广播域时,广播帧会从链路A发出,经对端交换机再从链路B发回,如此往复。由于二层帧没有生存时间字段,这种循环不会自然终止,最终形成广播风暴。传统解决办法是启用生成树协议(STP),让交换机自动阻塞部分端口,但在老旧设备、异构网络或临时组网中,STP可能未开启或配置不一致。
主动用Ruby检测的价值在于,它把网络状态拉到脚本层面集中判断。通过读取LLDP邻居通告、桥接转发表和端口运行状态,我们能够以软件方式复原出当前的物理连接图。当发现某台交换机的两个上行端口指向同一个邻居设备,或者同一广播域内出现多条等价路径时,即可判定存在冗余链路风险。相比等待STP收敛,脚本化检测更适配自动化运维流水线和自定义告警逻辑。
另外,有些场景下的环路并非长期存在,而是运维误插网线、无线桥接回连等偶发行为。这类瞬时环路往往STP来不及响应就已造成拥塞。Ruby脚本配合短周期轮询,能够在秒级发现异常端口状态跳变,并立即执行阻塞命令,从而将风暴影响控制在极小时间窗内。理解底层泛洪机制,是设计检测逻辑的前提。
基于Ruby的拓扑发现与冗余链路识别实现
要实现拓扑发现,第一步是获取设备邻居信息。多数支持LLDP的交换机可通过lldpctl或SNMP返回邻居MAC与端口。在Ruby中可以用Open3.capture2调用系统命令并解析文本。下面示例展示如何收集本地交换机各端口的LLDP邻居,并构建端口到邻居的映射关系。
require 'open3'
def collect_lldp_neighbors
ports = {}
stdout, _status = Open3.capture2('lldpctl -f keyvalue')
stdout.each_line do |line|
# 形如:lldp.eth0.neighbor.chassis.mac = "00:11:22:33:44:55"
if line =~ /lldp.(S+).neighbor.chassis.macs*=s*"([0-9a-f:]+)"/
port = $1
mac = $2
ports[port] = mac
end
end
ports
end
neighbors = collect_lldp_neighbors
puts neighbors.inspect
得到邻居映射后,需要判断冗余。若同一台邻居MAC出现在两个不同端口,且这两个端口均未处于STP阻塞态,则构成潜在环路。我们可以进一步读取bridge link或ovs-vsctl输出,确认这些端口是否属于同一网桥。以下代码演示了简单的冗余判定逻辑。
def find_redundant_ports(neighbors)
groups = {}
neighbors.each do |port, mac|
groups[mac] ||= []
groups[mac] << port
end
redundant = []
groups.each do |mac, ports|
redundant << ports if ports.length > 1
end
redundant
end
puts find_redundant_ports(neighbors).inspect
实际网络中还要排除合法聚合链路(如LACP),它们虽有多端口但逻辑为单链路。因此在脚本中应维护一个白名单,将已配置绑定的端口组跳过。只有那些既无STP阻塞、又不在聚合组中的重复邻居路径,才进入待阻塞队列。这种分层过滤能显著降低误判率。
自动阻塞冗余链路与运维注意事项
确认冗余端口后,Ruby可通过调用ip link set或厂商CLI来阻塞端口。对于Linux网桥或OVS环境,直接停掉端口是最快手段。以下示例将识别出的多余端口执行降级操作,并记录日志以备回滚。
def block_port(port)
cmd = "ip link set #{port} down"
system(cmd)
File.open('/var/log/loop_block.log', 'a') do |f|
f.puts("#{Time.now} blocked #{port}")
end
end
redundant_lists = find_redundant_ports(neighbors)
redundant_lists.each do |ports|
# 保留第一个端口,阻塞其余
ports[1..-1].each { |p| block_port(p) }
end
自动阻塞虽能快速止暴,但也带来误伤风险。例如邻居MAC可能因设备重启暂时变化,或无线网络漫游导致LLDP刷新延迟。为此脚本应引入确认机制:连续两个轮询周期都判定为冗余才执行阻塞,且阻塞前发送告警给运维通道。同时提供一键恢复命令,将ip link set up封装为恢复任务,避免人工登机操作。
从架构角度看,Ruby脚本适合作为边缘巡检代理,定期上报拓扑JSON给中心平台。中心端可做跨设备关联,识别横跨多交换机的三角环路,这是单设备视角看不到的。结合CMDB中的授权拓扑,就能区分“违规环路”与“规划内冗余”。只有违规部分才触发Ruby自动阻塞,从而在保障网络弹性的同时杜绝广播风暴。