收起左侧

在飞牛系统上限制虚拟机网速

0
回复
312
查看
[ 复制链接 ]

3

主题

23

回帖

0

牛值

江湖小虾

2025-4-20 09:37:11 显示全部楼层 阅读模式

目前飞牛官方并没有开发虚拟机的网络限速功能,但可以利用 OVS 原生 QoS 功能实现网络限速。(要求 OVS≥2.5 且支持 HTB )

查看 OVS 网络端口

# 查找虚拟机对应的 OVS 端口(如tap53eeb988-c7)
ovs-vsctl show

输出示例,可以看到 OVS 网桥(Bridge)名称、端口(Port)名称、接口(Interface )名称和 OVS 版本。在这里,虚拟机的接口是 vnet2,属于网桥 enp2s0-ovs,OVS 版本为 3.1.0。

19d20c10-43b1-4509-82d6-bcc1bf2cd08e
Bridge enp2s0-ovs
Port enp2s0
Interface enp2s0
Port enp2s0-ovs
Interface enp2s0-ovs
type: internal
Port vnet2
Interface vnet2
ovs_version: "3.1.0"

上传速率限制(基于 MAC地址)

ovs-vsctl -- set Port enp2s0 qos=@upload_qos \
-- --id=@upload_qos create QoS type=linux-htb other-config:max-rate=2500000000 queues=1=@vm_queue \
-- --id=@vm_queue create Queue other-config:min-rate=0 other-config:max-rate=20000000 other-config:burst=2000000
ovs-ofctl add-flow enp2s0-ovs "priority=500,dl_src=11:22:33:44:55:66,actions=set_queue:1,enp2s0" -O OpenFlow13

代码解释:

为网口 enp2s0 创建 QoS 策略,所有经过此端口的出口流量(egress)都会受 @upload_qos 控制,并加入限速队列 @vm_queue(队列 1);

在网桥上创建流表,处理特定的数据包,在队列 1 中加入 MAC 地址,根据虚拟机的 MAC 地址限速,并指定流量出口方向为物理网卡。

由于飞牛系统每次重启都会导致虚拟机的网络端口(vnetX)改变,因此不建议直接在 vnet 端口上进行 QoS 的配置。

参数说明:

  • type=linux-htb:使用 linux 网络流控的 HTB(分层令牌桶)算法。
  • QoS 策略中的 other-config:max-rate:指定该端口的最大速率(不可省略,若省略则会直接
  • 影响飞牛系统网速,这里设置为了 2.5Gbps ,并且所有队列最大速率总和不得超过该值)
  • HTB 队列中的 other-config:max-rate:限制最大速率(此处设置 20Mbps )
  • HTB 队列中的 other-config:burst:允许突发流量(此处设置 2Mbit )
  • HTB 队列中的 other-config:min-rate :设置为 0 表示允许其他队列借用带宽,但可能影响虚拟机的最低带宽保障
  • dl_src:匹配虚拟机源 MAC 地址
  • set_queue:将流量定向到限速队列 1
  • -O OpenFlow13:使用 OpenFlow 1.3 协议

流量控制示意图:

[虚拟机(vnetX)] --> OVS网桥(enp2s0-ovs)
|
|-- 流表引擎(基于MAC匹配队列)
|
[物理网卡(enp2s0)] --> 外部网络

下载速率限制

** **OVS 的 QoS 策略是针对出口方向(egress,针对端口而言)的,因此要限制虚拟机的下载速率,除了在虚拟机的网络端口(因为对于 vnetX 端口来说虚拟机下载的流量就相当于从端口传出的流量)设置 QoS 之外,也可以直接在物理网络端口上设置 ingress_policing_rate(不推荐,会直接限制物理机网速)。

ovs-vsctl set interface vnet2 ingress_policing_rate=20000 ingress_policing_burst=2000

ingress_policing_rate 使用简单令牌桶算法,相比HTB队列缺乏优先级控制和带宽借用机制,缺乏流量整形能力,可能造成虚拟机的大量丢包,也不支持流表这种操作,因此,如有下载速率限制需求,建议使用下方提供的自动脚本。

持久化部署

  1. 创建脚本 /usr/local/bin/ovs-dual-qos.sh
#!/bin/bash
# 配置参数
PHY_MAC="aa:bb:cc:dd:ee:ff"      # 物理端口网卡MAC(使用小写英文字母)
VM_MAC="a1:b2:c3:d4:e5:66"       # 虚拟机固定MAC(使用小写英文字母)
PHY_RATE="2500000000"            # 物理网口速率2.5Gbps(总带宽上限,需≥所有队列速率之和)
UPLOAD_RATE="20000000"           # 上传限速20Mbps
DOWNLOAD_RATE="20000000"         # 下载限速20Mbps
UPLOAD_BURST="2000000"           # 突发流量2Mbits
DOWNLOAD_BURST="2000000"

# 获取接口UUID
iface_uuid=$(ovs-vsctl --bare find interface \
    external_ids:attached-mac=\"$VM_MAC\" | head -1)
# 验证UUID有效性(若失败则说明虚拟机未启动)
if ! [[ $iface_uuid =~ ^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$ ]]; then
    echo "错误:接口UUID提取失败"
    exit 1
fi
# 获取虚拟机端口名称
VM_PORT=$(ovs-vsctl --bare get interface "$iface_uuid" name)

# 获取虚拟机端口所在网桥名称
VM_BRIDGE=$(ovs-vsctl port-to-br "$VM_PORT")

# 获取网桥所在物理端口名称
# 获取网桥下的所有端口
PORTS=$(ovs-vsctl list-ports $VM_BRIDGE)
# 遍历端口并匹配MAC地址
for port in $PORTS; do
    port_mac=$(ovs-vsctl --bare get interface "$port" mac-in-use 2>/dev/null)
    if [ "$port_mac" = "\"$PHY_MAC\"" ]; then
        PHY_PORT="$port"
        break
    fi
done

# 未匹配时的报错
if [ -z "$PHY_PORT" ]; then
    echo "错误:未找到MAC为 $PHY_MAC 的物理端口"
    exit 2
fi

echo "网桥:$VM_BRIDGE、虚拟机端口:$VM_PORT、物理端口:$PHY_PORT"

if [ "$PHY_RATE" -lt "$((UPLOAD_RATE + DOWNLOAD_RATE))" ]; then
    echo "错误:物理端口总带宽不足"
    exit 3
fi

# 清除旧配置
phy_qos_uuid=$(ovs-vsctl get Port "$PHY_PORT" qos)
if [ "$phy_qos_uuid" != '[]' ]; then
    ovs-vsctl -- destroy QoS "$phy_qos_uuid" -- clear Port "$PHY_PORT" qos
fi
vm_qos_uuid=$(ovs-vsctl get Port "$VM_PORT" qos)
if [ "$vm_qos_uuid" != '[]' ]; then
    ovs-vsctl -- destroy QoS "$vm_qos_uuid" -- clear Port "$VM_PORT" qos
fi
ovs-ofctl del-flows "$VM_BRIDGE" "dl_src=$VM_MAC"

#################### 上传限速配置 ####################
# 在物理端口配置出口QoS
ovs-vsctl -- \
set Port $PHY_PORT qos=@upload_qos \
-- --id=@upload_qos create QoS type=linux-htb \
other-config:max-rate=$PHY_RATE \
queues=1=@upload_queue \
-- --id=@upload_queue create Queue \
other-config:max-rate=$UPLOAD_RATE \
other-config:burst=$UPLOAD_BURST

# 流表规则:匹配源MAC→限速队列(注意!流表规则只能在网桥上添加,不可在端口上添加)
ovs-ofctl add-flow "$VM_BRIDGE" \
"priority=500,dl_src=$VM_MAC,actions=set_queue:1,output:$(ovs-vsctl get Interface "$PHY_PORT" ofport)"

#################### 下载限速配置 ####################
# 在虚拟机端口配置出口QoS
ovs-vsctl -- \
set Port $VM_PORT qos=@download_qos \
-- --id=@download_qos create QoS type=linux-htb \
other-config:max-rate=$PHY_RATE \
queues=2=@download_queue \
-- --id=@download_queue create Queue \
other-config:max-rate=$DOWNLOAD_RATE \
other-config:burst=$DOWNLOAD_BURST

ovs-ofctl add-flow "$VM_BRIDGE" \
"priority=500,dl_dst=$VM_MAC,actions=set_queue:2,output:$(ovs-vsctl get Interface "$VM_PORT" ofport)"
  1. 创建 systemd 服务 /etc/systemd/system/ovs-qos.service
[Unit]
Description=OVS QoS
After=network-online.target openvswitch.service libvirtd.service
Requires=libvirtd.service

[Service]
# 等待虚拟机启动
ExecStartPre=/bin/sh -c 'while ! virsh list | grep -q "running"; do sleep 2; done'
ExecStart=/usr/local/bin/ovs-dual-qos.sh
Restart=on-failure

# 增加超时配置避免无限等待
TimeoutStartSec=120s
RestartSec=10s

[Install]
WantedBy=multi-user.target
  1. 授权并启用服务:
chmod +x /usr/local/bin/ovs-dual-qos.sh
systemctl enable ovs-qos

查看流控配置

# 查看端口QoS绑定状态
ovs-vsctl list port vnet2 | grep qos

# 查看QoS策略详细信息
ovs-vsctl list qos

# 查看队列参数
ovs-vsctl list queue

# 查看端口统计(含突发包计数)
ovs-appctl dpctl/show -s

# 查看队列统计
watch -n 1 "ovs-ofctl queue-stats enp2s0-ovs"

# 查看流表规则
ovs-ofctl dump-flows enp2s0-ovs

# 查看ingress限速统计(Kbps单位)
ovs-vsctl list interface vnet2 | grep policing

 # 查看HTB队列状态
tc -s -d qdisc show dev enp2s0-ovs

预期输出:qos 字段应显示 UUID,且 other_config:max-rate 值为 35000000

(回滚)恢复默认状态

# 消除 QoS 策略
ovs-vsctl clear port enp2s0 qos
ovs-vsctl destroy qos <QoS_UUID>
ovs-vsctl destroy queue <Queue_UUID>

# 消除 ingress_policing_rate 规则
ovs-vsctl set interface vnet2 ingress_policing_rate=0 \
                      ingress_policing_burst=0

# 消除流表
ovs-ofctl del-flows enp2s0-ovs
收藏
送赞
分享
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则