You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 14:53:20