使用Ryu控制器实现QoS遇AttributeError问题求助
问题原因
你遇到的AttributeError: module 'ovs.db.idl' has no attribute '_uuid_to_row'是由于RYU的ryu/lib/ovs/vsctl.py依赖了OVS IDL的私有内部函数_uuid_to_row,而新版本的OVS已经移除了这个未公开的API,导致两者兼容性断裂。
解决方案
以下是几种可行的修改方案,按推荐优先级排序:
方案1:改用OpenFlow Meter表实现控制器端QoS(推荐)
这是SDN控制器原生的QoS实现方式,不依赖OVSDB,完全通过OpenFlow协议下发规则,避免OVS版本兼容问题。
修改你的代码如下:
from ryu.base import app_manager from ryu.ofproto import ofproto_v1_3 from ryu.controller.handler import (MAIN_DISPATCHER, CONFIG_DISPATCHER, set_ev_cls) from ryu.controller import ofp_event from ryu.lib.packet import ether_types class SimpleApp(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] @set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): datapath = ev.msg.datapath ofproto = datapath.ofproto parser = datapath.ofproto_parser # 创建Meter表:限制速率为500Mbps(单位:kbps) meter_mod = parser.OFPMeterMod( datapath, ofproto.OFPMC_ADD, ofproto.OFPMF_KBPS, # 按千比特每秒计量 meter_id=1, bands=[parser.OFPMeterBandDrop(rate=500000)] # 500000 kbps = 500 Mbps ) datapath.send_msg(meter_mod) self.logger.info(f"Meter 1 created for datapath {datapath.id}") # 下发流表:将IP流量绑定到该Meter match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP) actions = [parser.OFPActionOutput(ofproto.OFPP_NORMAL)] inst = [ parser.OFPInstructionMeter(1, ofproto.OFPIT_METER), parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions) ] flow_mod = parser.OFPFlowMod( datapath=datapath, match=match, cookie=0, command=ofproto.OFPFC_ADD, idle_timeout=0, hard_timeout=0, priority=10, instructions=inst ) datapath.send_msg(flow_mod) self.logger.info(f"Flow rule bound to Meter 1 for datapath {datapath.id}")
方案2:直接调用ovs-vsctl命令配置QoS
绕过RYU的OVSBridge封装,直接执行系统命令配置OVS QoS,兼容性更好:
修改你的代码如下:
from ryu.base import app_manager from ryu.ofproto import ofproto_v1_3 from ryu.controller.handler import set_ev_cls from ryu.topology import event import subprocess class SimpleApp(app_manager.RyuApp): OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] @set_ev_cls(event.EventSwitchEnter) def mymethod(self, ev): self.logger.info(f'Called mymethod') port_name = 'enp0s8' max_rate = '500000000' # 单位:bps # 直接执行ovs-vsctl命令创建QoS并绑定到端口 try: subprocess.run([ 'ovs-vsctl', 'set', 'port', port_name, 'qos=@newqos', '--', '--id=@newqos', 'create', 'qos', 'type=linux-htb', f'other_config:max-rate={max_rate}' ], check=True, capture_output=True, text=True) self.logger.info(f"QoS configured for port {port_name} with max rate {max_rate} bps") except subprocess.CalledProcessError as e: self.logger.error(f"Failed to configure QoS: {e.stderr}")
方案3:修复RYU的vsctl.py代码
如果必须使用RYU的OVSBridge,可以修改ryu/lib/ovs/vsctl.py中的代码,替换私有API:
找到_pre_mod_column方法中的这一行:
return datum.to_python(ovs.db.idl._uuid_to_row)
替换为:
# 自定义uuid转row的函数,替代私有API def _uuid_to_row(uuid): return self.idl.rows_by_uuid.get(uuid) return datum.to_python(_uuid_to_row)
方案4:降级OVS到兼容版本
如果不想修改代码,可以将OVS降级到2.13.x或更早版本,这些版本仍保留_uuid_to_row私有函数。
内容的提问来源于stack exchange,提问作者Astrophe
相关产品推荐
相关产品推荐

