-1)2023-01-08 21:23
0)学习使用nftable+tc来做简单流控,系统是openwrt。nftable是openwrt自带的(22.03之后自带),tc安装opkg update tc-full
1)ssh登录路由器,下方命令只需要输一次,以后都不需要变动
2)注意网口名称,iifname是指进入接口,它匹配的数据包对于客户端来说是上行流量,oifname反之。
3)nftable可以代替tc filter来把数据分配到tc class中对应的classid。meta priority关键词就是这功能,后面带有set关键词代表的是设置,没有set代表的是匹配
4)maps和sets很像,好像翻译为字典还是集,下方命令的第三第四行就是分别创建一个map
4)map里也可以执行动作,type里冒号后面的classid就是动作,和规则里的priority是一个意思,就是分配到tc class上对应的classid
5)tc qdisc中,wlan0-1出口的流量是发给客户端的,对于客户端来说是下行流量。wan口反之。
6)关于htb的参数中的ceil和rate,我发现当parent指定的qdisc没有限速的话就只有rate生效,所以在父类中我将两个值设为一样的。没有设置突发参数,有兴趣时再百度。
nft 'add table inet mytable' #新增加名字为mytable的表
nft 'add chain inet mytable forward {type filter hook forward priority 0;}' #新增加名字为forward的基本链
nft 'add map inet mytable ipsaddrmap {type ipv4_addr : classid;counter;flags interval;}' #新增加名字为ipsaddrmap的字典
nft 'add map inet mytable ipdaddrmap {type ipv4_addr : classid;counter;flags interval;}' #新增加名字为ipdaddrmap的字典
nft 'add rule inet mytable forward iifname "wlan0-1" meta priority set ip saddr map @ipsaddrmap counter' #新增加规则,使wlan0-1网口进来的流量的源IP信息转到ipsaddrmap去匹配
nft 'add rule inet mytable forward oifname "wlan0-1" meta priority set ip daddr map @ipdaddrmap counter' #新增加规则,使wlan0-1网口出去的流量的源IP信息转到ipdaddrmap去匹配
nft 'add rule inet mytable forward iifname "wlan0-1" meta priority none meta priority set 2:256 counter' #新增加规则,使wlan0-1网口进来的还没有被标记priority的流量,标记为2:256
nft 'add rule inet mytable forward oifname "wlan0-1" meta priority none meta priority set 1:256 counter' #新增加规则,使wlan0-1网口出去的还没有被标记priority的流量,标记为1:256
tc qdisc replace dev wlan0-1 root handle 1: htb #在wlan0-1出口上增加qdisc,使用的qdisc是htb,但没有指定速率,应该加上速率限制比较好。
tc qdisc replace dev wan root handle 2: htb #在wan出口上增加qdisc,使用的qdisc是htb,但没有指定速率,应该加上速率限制比较好。
tc class replace dev wlan0-1 parent 1: classid 1:1 htb ceil 20mbit rate 20mbit #在tc class中增加类并指定使用htb,这个类将是父类,parent要指向tc qdisc中的handle,classid是给这条规则设置id。ceil是htb的参数,代表该类最大可达到的速率,rate也是htb的参数,代表该类保证可以达到的速率,这两参数见上方第六条说明。
tc class replace dev wan parent 2: classid 2:1 htb ceil 16mbit rate 16mbit #在tc class中增加类并指定使用htb,这个类将是父类,parent要指向tc qdisc中的handle,classid是给这条规则设置id。ceil是htb的参数,代表该类最大可达到的速率,rate也是htb的参数,代表该类保证可以达到的速率,这两参数见上方第六条说明。
tc class replace dev wlan0-1 parent 1:1 classid 1:256 htb ceil 14mbit rate 600kbit #在tc class中增加子类,它的父类是1:1,该类用来限速所有未被标记的流量,限速的数值最大为父类的0.7,凭喜好设置。
tc class replace dev wan parent 2:1 classid 2:256 htb ceil 11200kbit rate 480kbit #在tc class中增加子类,它的父类是2:1,该类用来限速所有未被标记的流量,限速的数值最大为父类的0.7,凭喜好设置。
0)接下来创建一个sh脚本,用于通过arp表获取当前在线客户端,将增加相应的nft规则和tc规则,下方内容为脚本文件内容。
1)我将没有在sh脚本开头加上#说明,我不清楚它有什么用,但很明显文档的第一个#会有特殊意义,所以文件内容中不会加注释了。
2)第一行,首先是获取arp信息,然后通过grep分类出想要的信息,其中0x2代表的是在线,wlan0-1代表的是接口,最后192.168.3是网段(有时会有奇怪的IP出现,所以才加的)。然后就是while循环读每一行
3)读取到的每一行的信息中,只需用到IP地址,所以使用字符串操作获取,并且也使用IP地址最后一位来当classid(下行数据的id前缀为1:,上行的为2:)。
4)最后的nft命令和tc命令都是增加对应规则的。这里nft命令没有加单引号,因为会导致变量失效,但是没有使用单引号,就要用反斜杆来反义冒号。
5)这文件应该存在闪存里,不应该存临时目录,很明显要一直用啊。使用crontab每三十秒执行一次这脚本就好。
cat /proc/net/arp | grep wlan0-1 | grep 0x2 | grep 192.168.3 | while read line
do
echo $line
ipaddr=${line%0x1*}
echo $ipaddr
classidDown=$(echo -e "1:${ipaddr##*.}")
echo $classidDown
classidUp=$(echo -e "2:${ipaddr##*.}")
echo $classUp
nft add element inet mytable ipsaddrmap {$ipaddr\:$classidUp}
nft add element inet mytable ipdaddrmap {$ipaddr\:$classidDown}
tc class replace dev wlan0-1 parent 1:1 classid $classidDown htb ceil 14mbit rate 600kbit
tc class replace dev wan parent 2:1 classid $classidUp htb ceil 11200kbit rate 480kbit
done
0)上面的脚本是给在线客户端增加对应的限速规则,但是已经下线了的客户端也要清除对应的规则,才能使程序快一些。
1)将增加规则和删除规则分为两个脚本是因为增加需要频繁执行来确实及时限速,但对于已下线了的客户端就没必须及时删除对应规则了,在crontab中,设为每一小时执行一次就差不多了。
2)脚本基本与增加规则一样,只是将replace修改为del或delete。对于nft命令来说,有个IP地址就可以了,后面的classid缺失也是没问题的。tc命令也一样可以少一些参数。
cat /proc/net/arp | grep wlan0-1 | grep 0x0 | grep 192.168.3 | while read line
do
echo $line
ipaddr=${line%0x1*}
echo $ipaddr
classidDown=$(echo -e "1:${ipaddr##*.}")
echo $classidDown
classidUp=$(echo -e "2:${ipaddr##*.}")
echo $classUp
nft delete element inet mytable ipsaddrmap {$ipaddr}
nft delete element inet mytable ipdaddrmap {$ipaddr}
tc class del dev wlan0-1 classid $classidDown
tc class del dev br-lan.1002 classid $classidUp
done
0)关于crontab,openwrt的web界面中就有,或者用crontab -e。
1)第一行是每分钟都执行一下的意思,
2)第二行和第一行很像,只是多了个sleep 30,因为我想要每30秒执行一次,所以有这第二行,它将比第一行晚30秒执行一次。
3)第三行的意思就是每个小时的第30分钟执行一次
*/1 * * * * sh /tmp/tmp/updateQos.sh
*/1 * * * * sleep 30;sh /tmp/tmp/updateQos.sh
30 * * * * sh /tmp/tmp/cleanQos.sh
----------------------------------------------------------------------