4、OVS QoS配置命令:ovs-vsctl set port qos命令详解

好,咱们接着往下聊。上一节我把QoS的整体框架和限速原理讲清楚了,这一节咱们直接上手——敲命令。

在Open vSwitch里,配置QoS最核心的命令就是ovs-vsctl set port。说白了,就是把一个QoS策略绑定到某个端口上。我刚开始接触OVS时,总觉得这命令很简单,不就是set一下嘛。结果第一次在生产环境配限速,忘了清空旧策略,导致整个出口带宽被打满,差点背锅。嗯,从那以后我再也不敢小看这条命令了。

4.1 命令基本语法

先看最基础的写法:

ovs-vsctl set port <port_name> qos=<uuid>

这条命令的意思很直白:给名为<port_name>的端口,绑定一个UUID为<uuid>的QoS对象。你想想看,QoS对象就像一张限速规则表,端口就是执行这张表的出口。

但实际工作中,我们很少手动去查UUID。更常见的做法是直接内联创建:

ovs-vsctl set port eth0 qos=@newqos \
  -- --id=@newqos create qos type=linux-htb \
     other-config:max-rate=1000000000 \
     queues:0=@q0 \
     queues:1=@q1 \
  -- --id=@q0 create queue other-config:max-rate=500000000 \
  -- --id=@q1 create queue other-config:max-rate=300000000

这条命令一口气做了三件事:创建QoS对象、创建两个队列、把QoS绑定到端口。我个人习惯用这种内联写法,因为逻辑清晰,一条命令搞定,不容易漏掉关联关系。

4.2 参数详解

咱们拆开来看每个参数的含义。我整理了一张表,方便你对照:

参数 说明 必填/可选
type QoS类型,常用linux-htb(层次令牌桶)或linux-hfsc 必填
other-config:max-rate 端口总带宽上限,单位bps。例如1Gbps就是1000000000 可选(建议设置)
queues 队列映射表,格式queue_id=@queue_obj 必填(如果使用队列)
other-config:min-rate 队列保证带宽,单位bps。HTB模式下有效 可选
other-config:burst 突发流量大小,单位字节。控制瞬时峰值 可选
other-config:priority 队列优先级,数值越小优先级越高 可选

这里有个坑,我曾经踩过:max-rate的单位是bps,不是Bps。1Gbps = 1000000000,不是1073741824。如果你按字节去算,限速会偏小很多。嗯,这个细节很容易被忽略。

4.3 实战:给虚拟机网卡限速

假设你有一台虚拟机,它的虚拟网卡叫vnet0,你想给它限速到200Mbps。怎么做?

ovs-vsctl set port vnet0 qos=@qos \
  -- --id=@qos create qos type=linux-htb \
     other-config:max-rate=200000000 \
     queues:0=@queue \
  -- --id=@queue create queue other-config:max-rate=200000000

这条命令执行后,vnet0的出口带宽就被限制在200Mbps了。注意,我这里只创建了一个队列,队列ID是0。如果你不指定队列,OVS会使用默认行为,但那样就失去了精细控制的意义。

我个人建议,哪怕只做一个限速,也显式创建一个队列。为什么?因为后续你要加优先级、加突发控制时,直接改队列参数就行,不用重构整个QoS结构。

4.4 查看和验证配置

命令敲完了,怎么确认生效了?用ovs-vsctl list port

ovs-vsctl list port vnet0

输出里会有一行:

qos                : 8a2f3c1e-... (uuid)

有这个UUID就说明绑定成功了。再进一步查看QoS详情:

ovs-vsctl list qos 8a2f3c1e-...

你会看到类似这样的输出:

type               : linux-htb
other_config       : {max-rate="200000000"}
queues             : {0=3b7d9e2f-...}

嗯,到这里基本就确认配置没问题了。但我想提醒你一句:ovs-vsctl list看到的只是控制面的配置,数据面是否真的生效,还得用tc命令或者实际打流来验证。我遇到过配置写对了,但内核模块没加载的情况,结果限速根本没起作用。

4.5 修改和删除QoS

改配置很简单,重新set一次就行。比如把限速从200Mbps改成500Mbps:

ovs-vsctl set queue 3b7d9e2f-... other-config:max-rate=500000000

注意,这里改的是队列对象,不是端口。如果你要改端口的总带宽,就改QoS对象的max-rate

删除QoS呢?先把端口上的绑定清掉:

ovs-vsctl clear port vnet0 qos

然后再删QoS对象和队列:

ovs-vsctl destroy qos 8a2f3c1e-...
ovs-vsctl destroy queue 3b7d9e2f-...

顺序很重要。我曾经先删了QoS对象,结果端口还引用着它,导致OVS报错。正确的做法是:先解绑,再销毁。

⚠️ 避坑指南: 我曾经在生产环境上直接destroy了QoS对象,忘了先clear port。结果那个端口上的流量瞬间失控,所有虚拟机都跑满了带宽。所以请记住:先clear port,再destroy qos

4.6 常见错误与排查

最后列几个我遇到过的典型错误:

  • 错误1:ovs-vsctl: no row "qos" in table Port
    原因:端口名写错了,或者端口不存在。用ovs-vsctl list port确认一下。
  • 错误2:限速不生效,但配置看起来都对
    原因:可能是内核没加载sch_htb模块。执行modprobe sch_htb试试。
  • 错误3:队列优先级不生效
    原因:HTB模式下,优先级只在同一层级的队列间有效。如果你搞了多层嵌套,优先级逻辑会变复杂。
💡 我的小技巧: 每次配完QoS,我都会用tc -s qdisc show dev vnet0看一眼实际生效的队列规则。OVS的配置最终会映射到内核的tc规则上,所以tc的输出才是最真实的。如果tc里看不到你配的规则,那说明OVS的配置没推下去。

好了,这一节的内容就到这。ovs-vsctl set port qos这条命令,说白了就是给端口挂上一套限速规则。你只要记住:先建QoS对象,再建队列,最后绑定到端口。顺序别搞反,参数别写错,基本就不会出大问题。