前言
最近有一个需求,需要限制网卡速度进行一些测试。在朋友推荐下阅读了这篇文章 TC简单粗暴限制网速。
经过尝试,简单有效,整理成脚本放在正文,留作参考。
正文
-
指令解析(chatgpt 分析)
您提供的命令序列是用于在Linux系统中使用tc
(traffic control)工具对网络流量进行管理和控制的示例。下面是每个命令的作用和一些解释: -
modprobe ifb numifbs=1
- 加载
ifb
(Intermediate Functional Block)模块,创建一个新的ifb设备实例。numifbs=1
参数表示创建一个虚拟的网络接口,用于流量控制。
- 加载
-
ip link set dev ifb0 up
- 激活(启用)名为
ifb0
的网络接口。
- 激活(启用)名为
-
tc qdisc add dev ens18 handle ffff: ingress
- 在网络接口
ens18
上添加一个ingress队列规则,处理进入的流量。
- 在网络接口
-
tc filter add dev ens18 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
- 在
ens18
接口上添加一个过滤器,匹配所有进入的IPv4流量并将其镜像(重定向)到ifb0
设备。
- 在
-
tc qdisc add dev ifb0 root handle 1: htb default 10
- 在
ifb0
上添加一个根队列规则,使用HTB(Hierarchical Token Bucket)算法来管理和限制流量。
- 在
-
tc class add dev ifb0 parent 1:0 classid 1:1 htb rate 1Mbps
- 添加一个限制类,将
ifb0
的流量限制到1Mbps。
- 添加一个限制类,将
-
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate 1Mbps
- 在前面创建的类
1:1
下添加一个子类1:10
,限制率同样是1Mbps。
- 在前面创建的类
以下是修改类的命令,用于变更流量限制:
-
tc class change dev ifb0 parent 1:0 classid 1:1 htb rate 2Mbps
- 将类
1:1
的速率改为2Mbps。注意这里最后的单位使用的是大写的B,代表Bytes,这可能是个错误,因为通常限制速率使用的是小写的b,代表bits。
- 将类
-
tc class change dev ifb0 parent 1:1 classid 1:10 htb rate 2Mbps
- 将子类
1:10
的速率改为2Mbps。同样的单位问题。
- 将子类
-
tc class change dev ifb0 parent 1:0 classid 1:1 htb rate 20Mbit
- 将类
1:1
的速率改为20Mbps。
- 将类
-
tc class change dev ifb0 parent 1:1 classid 1:10 htb rate 20Mbit
- 将子类
1:10
的速率改为20Mbps。
- 将子类
-
tc class show dev ifb0
- 显示
ifb0
接口上的类信息。
- 显示
最后,以下命令用于清理前面创建的队列规则:
-
tc qdisc del dev ens18 ingress
- 删除
eth0
接口上的ingress队列规则。
- 删除
-
tc qdisc del dev ifb0 root
- 删除
ifb0
接口上的根队列规则。
- 删除
-
modprobe -r ifb
- 卸载
ifb
模块。
- 卸载
请注意,使用tc进行流量控制时,确保你使用正确的流量单位非常重要。通常流量速率以bit为单位(即Mbit或Mbps),而不是Byte(即MBps)。这里的速率控制指令中的"B"应该是小写的"b",除非实际环境有特别规定使用了Bytes作为单位。
脚本:limit_net_speed.sh, 这个脚本实现了简单增删改查,但细节方面还需要打磨,还有一定局限性。
#!/bin/bash
action=$1
network_card=$2
limit=$3
function Usage()
{
echo -e "${0} [action] [network_card] [speed_limit]"
echo -e "------"
echo -e "action: show/add/change/delete"
echo -e "network_card: you network card name"
echo -e "speed_limit: network speed limit num (Mbps), only number, default 100"
echo -e "------"
exit 0
}
function show_network_cards()
{
echo -e "------ NETWORK ------\n"
echo -e "NAME IPADDRESS"
ip -o -4 addr show | awk '{print $2, $4}' | column -t
echo -e "---------------------\n"
}
function show_ip_ifb_info()
{
echo -e "------ IP IFPS ------\n"
ip link show type ifb
echo -e "---------------------\n"
}
function show_tc_info()
{
echo -e "------ TC INFO ------\n"
tc class show dev ifb0
echo -e "---------------------\n"
}
if [[ ${action} == "show" ]];then
echo -e "start show all info"
show_network_cards
show_ip_ifb_info
show_tc_info
elif [[ ${action} == "add" ]];then
echo -e "start add"
if [[ ${network_card} == "" ]];then
echo -e "Error: network_card is None, select one from below:"
show_network_cards
Usage
fi
ip -o -4 addr show | grep -qw "${network_card}"
if [[ $? == 1 ]];then
echo "Error:${network_card} not in below:"
show_network_cards
Usage
fi
has_ip_ifp=`ip link show type ifb`
if [[ ${has_ip_ifp} != "" ]];then
echo -e "ifp has exists:"
echo ${has_ip_ifp}
Usage
fi
modprobe ifb numifbs=1
ip link set dev ifb0 up
tc qdisc add dev ${network_card} handle ffff: ingress
tc filter add dev ${network_card} parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev ifb0
tc qdisc add dev ifb0 root handle 1: htb default 10
limit_speed=100
if [[ ${limit} != "" ]];then
limit_speed=${limit}
fi
echo -e "add ${network_card} limit:${limit_speed}Mbps"
tc class add dev ifb0 parent 1:0 classid 1:1 htb rate ${limit_speed}Mbit
tc class add dev ifb0 parent 1:1 classid 1:10 htb rate ${limit_speed}Mbit
show_ip_ifb_info
show_tc_info
echo "finished"
elif [[ ${action} == "change" ]];then
echo -e "start change"
if [[ ${network_card} == "" ]];then
echo -e "Error: network_card is None, select one from below:"
show_network_cards
Usage
fi
ip -o -4 addr show | grep -qw "${network_card}"
if [[ $? == 1 ]];then
echo "Error:${network_card} not in below:"
show_network_cards
Usage
fi
has_ip_ifp=`ip link show type ifb`
if [[ ${has_ip_ifp} == "" ]];then
echo -e "ifp not exists:"
Usage
fi
if [[ ${limit} == "" ]];then
echo -e "Error: limit is None"
Usage
fi
echo -e "change ${network_card} speed:${limit}Mbps"
tc class change dev ifb0 parent 1:0 classid 1:1 htb rate ${limit}Mbit
tc class change dev ifb0 parent 1:1 classid 1:10 htb rate ${limit}Mbit
show_ip_ifb_info
show_tc_info
echo "finished"
elif [[ ${action} == "delete" ]];then
echo -e "start delete"
if [[ ${network_card} == "" ]];then
echo -e "Error: network_card is None, select one from below:"
show_network_cards
Usage
fi
ip -o -4 addr show | grep -qw "${network_card}"
if [[ $? == 1 ]];then
echo "Error:${network_card} not in below:"
show_network_cards
Usage
fi
has_ip_ifp=`ip link show type ifb`
if [[ ${has_ip_ifp} == "" ]];then
echo -e "ifp not exists:"
Usage
fi
echo "delete ${network_card} speed limit"
tc qdisc del dev ${network_card} ingress
tc qdisc del dev ifb0 root
modprobe -r ifb
show_ip_ifb_info
show_tc_info
echo "finished"
else
echo -e "Error:action: ${action} not supported"
show_network_cards
Usage
fi
参考
[1]. TC简单粗暴限制网速
[2]. chatgpt