通过Linux的tc指令实现软路由上的速度控制
现在很多使用软路由不管是做研究或者家庭使用,大部分基于Linux系统的Hostapd的方案较多,下面通过使用Ubuntu或者RaspOS操作系统为例,在安装了Hostapd的树莓派软路由上实现流量整形
的功能。
内容为原创,转载请标注,另外参考自已发表的学术论文,详情见参考文献
Traffic shaping
Traffic shaping 是一种网络流量管理技术,用于控制计算机网络中数据包的传输速度和带宽使用。这种方法可以用于优化、管理或限制网络资源的使用。通过对网络流量进行监控和调整,网络管理员可以确保关键任务的流量优先级最高,同时限制不太重要的数据流量。
在网络中应用的比较多,由于我并不是学习网络工程的,所以就不献丑介绍了。本文主要讲一下如何实际使用shell脚本,在一个局域网中,对不同的设备实现吞吐量控制的功能。
- 设备列表:
设备 | 描述 |
---|---|
树莓派4B | 作为软路由的本体 |
Raspbian OS | 树莓派的Linux操作系统 |
tc command | traffic control 指令,在iproute2包里 |
板载NIC | 比较垃圾,不建议用 |
external NIC | 这里使用的是tp-link的T4UH,除了要装驱动之外没有别的缺点 |
- 资料介绍参考网址:
- tc介绍:https://man7.org/linux/man-pages/man8/tc.8.html
- RedHat的介绍:https://access.redhat.com/documentation/zh-cn/red_hat_enterprise_linux/8/html-single/configuring_and_managing_networking/index#linux-traffic-control_configuring-and-managing-networking
- CSDN上找大佬们的帖子
Shell脚本实现TC控制
- 需要输入的地方:自己想要控制的设备ip地址和想要给吞吐量大小
- 运行,即可实现
先放一下完整的代码:
#!/bin/bash
#This scripts control incomming and outcomming bandwight in a linux router box
dir=/home/pi/Dual_tc
unit=mbit
# Interface connect to out lan
int1="wlan0"
# Interface virtual for incomming traffic
tin1="ifb0"
totalDatarate=$(< $dir/set_target_throughput24.tmp wc -l)
w=1
while [ $w -le $totalDatarate ]
do
IP[$w]=$(awk -v var=$w 'FNR==var{print $1}' $dir/set_target_throughput.tmp)
datarate[$w]=$(awk -v var=$w 'FNR==var{print $2}' $dir/set_target_throughput.tmp)
w=$(( w+1 ))
done
w=1
total_th=0
while [ $w -le $totalDatarate ]
do
total_th=$(echo "scale=10; $total_th + ${datarate[$w]};" | bc -l) # add the total datarate for parent class
w=$(( w+1 ))
done
# It's necessary load this module in the kernel for do it
modprobe ifb numifbs=1
sudo ip link set dev $tin1 up
## Limit incomming traffic ( to localhost)
# Clean interface
sudo tc qdisc del dev $int1 handle ffff: ingress
#modprobe -r ifb
sudo tc qdisc del root dev $tin1
sudo tc qdisc add dev $int1 handle ffff: ingress
# Redirect ingress wlan0 to egress ifb0
sudo tc filter add dev $int1 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $tin1
# Add classes per ip
sudo tc qdisc add dev $tin1 root handle 2: htb default 80
sudo tc class add dev $tin1 parent 2: classid 2:1 htb rate $total_th$unit
# distribute data rate to the host (child class)
w=1
class_id=10
while [ $w -le $totalDatarate ]
do
sudo tc class add dev $tin1 parent 2:1 classid 2:$class_id htb rate ${datarate[$w]}$unit ceil ${datarate[$w]}$unit
w=$(( w+1 ))
class_id=$(( class_id+10 ))
done
# Match ip and put it into the respective class
# host filter
w=1
class_id=10
while [ $w -le $totalDatarate ]
do
sudo tc filter add dev $tin1 parent 2: protocol ip prio 1 u32 match ip src ${IP[$w]} flowid 2:$class_id
w=$(( w+1 ))
class_id=$(( class_id+10 ))
done
简单讲一下上面的脚本内容:
-
首先
#!/bin/bash
这段别忘了加上,因为考虑到不是所有人都熟悉bash或者shell,还是要说一下的。当然这段脚本用的是bash。shell脚本和bash之间类似于包含和被包含的关系,具体的请自己查阅资料吧。#!/bin/bash
这行代码出现在脚本文件的第一行,用来指示系统如何执行该文件中的脚本。 -
因为需要方便修改ip地址和吞吐量,所以代码中对另外一个文件
set_target_throughput.tmp
进行了访问,在这文件中可以更加方便的设置,注意,需要修改你自己的文件夹路径和你自己的文件名字,或者你也可以用这个名字。 -
wlan0
是我们需要控制的接口,一般来说wlan0是板载的无线接口,但是如果你的名字不是这个,也没关系,可以修改。例如wlp3s0
或类似的格式。下面的方法查看你的接口名字:- 如果安装了net-tools 包,使用:
ifconfig
- 如果没安装,建议装一个 : )
- 一般来说改接口名字没啥问题,但也可能会有问题,如果你想改可以阅读下面的链接中的方法:https://askubuntu.com/questions/1303099/how-to-change-the-name-of-wireless-interface
-
ifb0
是 Linux 中的一个虚拟网络接口,主要用于处理进入系统的流量(入口流量)。在 Linux 的流量控制(tc)工具中,对出口流量(从本地系统发出的流量)进行限制和控制相对简单,但对入口流量的控制则更为复杂。ifb
接口的引入正是为了解决这个问题。通过将入口流量重定向到ifb
接口,可以使用tc
工具对其进行精细控制,就像处理出口流量一样。 -
outcoming的流量就是控制
wlan0
接口,进站通过ifb0
来实现:# 将进站重新定向到ifb0 sudo tc filter add dev $int1 parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $tin1 # 在 ifb0上应用HTB(分层令牌桶)流量控制 sudo tc qdisc add dev $tin1 root handle 2: htb default 80 sudo tc class add dev $tin1 parent 2: classid 2:1 htb rate $total_th$unit
-
上述情况适用于:
- 做实验,不联网,验证拓扑结构或者啥都可以
- 带宽公平共享,希望确保所有连接到路由器的设备都能公平地共享可用带宽
- 希望为某些类型的流量设置高优先级,而将其他流量降低优先级
如果是对于上传速度等需求的控制,入站流量可以选择性忽略。
可能有些绕,但是让我们慢慢来详细说明一下:
现在,有一个linux系统的设备,开启这Hostapd作为软路由,eth0也就是设备的网线口连着你家光猫或者什么都可以,总之就是连着互联网。然后你的这个软路由上有一个无线接口wlan0,这个接口作为wifi共享给你的设备。
你有一台手机,连着这个软路由的wifi,想要下载一部电影,通过控制软路由上的ifb0
实际上就是控制下载电影的速度。
当然,除了控制流量之外还可以设置优先级,上面的脚本中只用了HTB来控制流量,并没有涉及到优先级排序。
实际操作
下面来讲一下实际的操作。
-
首先,检查你的网络接口。
# 查看网络接口名称 ifconfig
出现错误,例如这样:
Command 'ifconfig' not found, but can be installed with: sudo apt install net-tools # 速速下载net-tools
你需要按照他的提示运行:
sudo apt install net-tools # 然后再次运行 ifconfig
出现的信息大概是下面这样:(我演示用的是wsl所以可能信息不一样,按照你自己的情况去找)
eth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.73.1 netmask 255.255.255.0 broadcast 192.168.73.255 inet6 fe80::dc3f:9673:5809:7c97 prefixlen 64 scopeid 0xfd<compat,link,site,host> ether 00:50:56:c0:00:01 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth3: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.136.1 netmask 255.255.255.0 broadcast 192.168.136.255 inet6 fe80::6091:2a00:3739:ff14 prefixlen 64 scopeid 0xfd<compat,link,site,host> ether 00:50:56:c0:00:08 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.29.96.1 netmask 255.255.240.0 broadcast 172.29.111.255 inet6 fe80::c148:abe:7a41:1e43 prefixlen 64 scopeid 0xfd<compat,link,site,host> ether 00:15:5d:64:2d:90 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 1500 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0xfe<compat,link,site,host> loop (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 # !!!这里,找到你的wifi接口名字 wifi0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.10.112 netmask 255.255.255.0 broadcast 192.168.10.255 inet6 fe80::4800:f260:8634:78ba prefixlen 64 scopeid 0xfd<compat,link,site,host> ether a8:64:f1:d6:08:67 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
-
在你想要的位置创建你的脚本和用于控制ip和速率的文件:
-
例如
/path to/home/your name/
,在你的home文件夹中创建一个例如名为traffic_control.sh
的脚本文件,里面粘贴上面的代码 -
在同一路径(推荐)创建一个名为
set_target_throughput.tmp
的文件,里面内容如下:# 你想要控制的设备ip | 以及速率(单位mbit) 192.168.10.1 50
-
修改代码中的路径:
# 这里放上你的set_target_throughput.tmp所在位置 dir=/home/pi/Dual_tc # 这里修改速率单位 unit=mbit # 这里修改你的无线接口名称 # 注意,如果使用的是Hostapd的话,注意和你Hostapd的conf文件中配置的软路由接口名字一致 # Interface connect to out lan int1="wlan0"
-
检查ifb模块是否加载:
# 通过ifconfig检查 ifconfig # 如果ifconfig找不到,运行 sudo modprobe ifb # 然后运行 sudo ip link add name ifb0 type ifb sudo ip link set dev ifb0 up # 再次检查 ifconfig # 或者使用 ip link show ifb0
拓展一下,如果你的软路由是双接口,比如现在常见的2.4Ghz和5Ghz的那种,一个80211n一个80211ac,你想控制双接口的流量的话,就需要两个ifb接口:
sudo modprobe ifb numifbs=2 sudo ip link add name ifb0 type ifb sudo ip link add name ifb1 type ifb sudo ip link set dev ifb0 up sudo ip link set dev ifb1 up
-
-
运行刚刚创建的脚本文件:
sudo ./traffic_control.sh
实用工具
可以使用iperf
或者iftop
等网络监测工具去查看目前的流量控制是否成功。
参考文献
- Rahman, M.M.; Funabiki, N.; Munene, K.I.; Roy, S.C.; Kuribayashi, M.; Gulo, M.M.; Kao, W.-C. A Throughput Request Satisfaction Method for Concurrently Communicating Multiple Hosts in Wireless Local Area Network. Sensors 2022, 22, 8823. https://doi.org/10.3390/s22228823
- Rahman M M, Funabiki N, Munene K I, et al. A Throughput Fairness Control Method for Concurrent Communications in Wireless Local-Area Network with Multiple Access-Points[J]. J. Commun., 2022, 17(8): 592-599.