基础介绍
Netfilter是Linux操作系统核心层内部的一个数据包处理模块,它具有如下功能:网络地址转换(Network Address Translate)数据包内容修改以及数据包过滤的防火墙功能。Netfliter框架不仅仅在ipv4中有应用,bridge,ipv4,ipv6,decnet,这四种协议中都有应用,其中ipv4中又分开了arp和ip的两种。其实netfliter是个大的框架,在ipv4中对应的应用层工具是iptables,在bridge中对应的应用层工具是ebtables,在arp中对应的应用层工具是arptables
- iptables 中有raw,filter,nat,mangle,4个table,
- ebtables 中有broute,filter,nat,3个table,
- arptables 中有filter,1个table
Netfilter框架被设计用来在网络协议栈的内核路径上过滤数据包,就像在一条路上的关卡一样,Netfilter在协议栈处理网络数据包的路径上的5个位置设置了这样的关卡,一个数据包在被处理的路径上经过这些关卡被检查,结果就是若干个动作:接受,丢弃,排队,导入其它路径等,框架只需针对一个数据包得出一个结果即可,关卡内部提供什么服务在Netfilter框架中并没有任何规定。
TC旨在对数据包或者数据流提供一种服务,比如限速,整形等,而这并不是一个类似Netfilter的结果可以表达的,提供这些服务需要执行一系列的动作,如何来规划和组织这些动作的执行是TC框架设计的关键,也就是说,TC框架关注的是如何执行而不是仅仅想要得到一个要执行的动作。换句话说,Netfilter框架关注做什么,而TC框架关注怎么做。
QoS的全称是Quality of Service,意即服务质量。是专门用于解决拥堵网络上的信号质量一视同仁的问题。Linux内核内置了一个Traffic Control框架,可以实现流量限速,流量整形,策略应用(丢弃,NAT等), 结合tc和netfilter可以实现基于IP或基于端口的限速需求。
关于iptables的使用可以参考博客:朱双印个人日志
TC基础介绍
大多数排队规则(qdisc)都是用于输出方向的,输入方向只有一个排队规则,即ingress qdisc。ingress qdisc本身的功能很有限。
TC操作原理
类(class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。某些qdisc (例如:CBQ和 HTB)允许在运行时动态添加类,而其它的qdisc(例如:PRIO)不允许动态建立类。允许动态添加类的qdisc可以有零个或者多个子类,由它们为数据包排队。此外,每个类都有一个叶子qdisc,默认情况下,这个也在qdisc有可分类,不过每个子类只能有一个叶子qdisc。当一个数据包进入一个分类qdisc,它会被归入某个子类。我们可以使用一下三种方式为数据包归类,不过不是所有的qdisc都能够使用这三种方式。
如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由ebtables或者iptables做的标记。树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以一直接用于其子类。如果数据包没有被成功归类,就会被排到这个类的叶子qdisc的队中。相关细节在各个qdisc的手册页中。
TC命名规则
所有的qdisc、类、和过滤器都有ID。ID可以手工设置,也可以由内核自动分配。ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。qdisc,一个qdisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄才有像1:0一样的表达方式。习惯上,需要为有子类的qdisc显式的分配一个句柄。类(Class),在同一个qdisc里面的类共享这个qdisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父qdisc有关,与父类无关。类的命名习惯和qdisc相同。过滤器(Filter),过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。
TC流量的处理由三种对象控制,它们是:qdisc(排队规则)、class(类别)和filter(过滤器)。
qdisc 分类:
- 1.CLASSLESS QDisc(不可分类QDisc)
[p|b]fifo
使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。
pfifo_fast
在编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。
red:
red是Random Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。
sfq:
sfq是Stochastic Fairness Queueing(随机公平排队)的简写。它按照会话(session–对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。
tbf
tbf是Token Bucket Filter的简写,适合于把流速降低到某个值。
- 2.Classful QDisc(分类QDisc)
可分类的qdisc:
CBQ
CBQ是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。
HTB等级令牌桶
HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,虽然它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级
PRIO
PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包FILTER(过滤器),Filter(过滤器)用于为数据包分类,决定它们按照何种QDisc进入队列
TC 中的 Filter 规则
filter 用来将用户划入到具体的控制策略中(即不同的 class 中).比如,现在,我们想对 xxa,xxb两个 IP 实行不同的控制策略(A,B),这时,我们可用 filter 将 xxa 划入到控制策略 A,将 xxb 划入到控制策略 B,filter 划分的标志位可用 u32 打标功能或 IPtables的 set-mark (大多使用iptables 来做标记)功能来实现。
目前,TC 可以使用的过滤器有:fwmark 分类器,u32 分类器,基于路由的分类器和 RSVP分类器(分别用于 IPV6、IPV4)等;其中,fwmark分类器允许我们使用 Linux netfilter 代码选择流量,而 u32 分类器允许我们选择基于 ANY 头的流量 .需要注意的是,filter (过滤器)是在 QDisc 内部,它们不能作为主体。
4、命名规则
所有的QDisc、类和过滤器都有ID。ID可以手工设置,也可以有内核自动分配。
ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。
关于TC,我们当前限速使用的有htb与sfq。
tc示例:
#增加ccinet0根队列,未标记数据默认走28
tc qdisc add dev ccinet0 root handle 1: htb default 28
#增加总流量规则
tc class add dev ccinet0 parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000
#增加子类
tc class add dev ccinet0 parent 1:1 classid 1:11 htb rate 6000kbit ceil 6000kbit prio 0
#为子类添加SFQ公平队列,每10秒重置
tc qdisc add dev ccinet0 parent 1:11 handle 11: sfq perturb 10
#子类过滤规则,匹配标记值为21的数据包
tc filter add dev ccinet0 parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:11
查看tc相关规则:
#查看网络状态信息
ifconfig
#查看网桥信息
brctl show
#查看所有网口的tc信息
tc qdisc
#查看ccinet0 tc信息
tc -s class ls dev ccinet0
#查看ccinet0 tc具体限速规则
tc -s filter ls dev ccinet0
关于tc快速上手可以参考:tc命令详解
需求分析
当前需要通过IP/Mac对特定设备或者ip段进行限速,或者通过固定端口(如USB,WIFI的某个ssid,或者通过LAN口接入的)进行限速。在当前情况下,只能从IP/MAC/端口三者中选一种模式(如果想要同时生效需要考虑冲突的情况以及兼容性处理,可自行实现)
明确网口结构
在正式开始前,需要明确一下要做限速的设备的interface结构,以我自身做过的项目为例,上行网口为ccinet0或者eth1(视具体项目而定),下行接口统一归到三层虚拟网桥br-lan上。
Linux中的QoS分为入口(ingress)部分和出口(egress)部分,ingress和egress是对router来说的,对于上行数据,设备数据进入到每个连接的网口是ingress方向,最后到ccinet0发出是egress方向,对于下行数据,进入ccinet0是ingress方向,从设备连接的网口发给设备是egress方向。
实现思路
整体的实现思路很简单:就是通过iptables或者ebtables等工具将数据包进行打标,在tc工具中根据打标值分流限速即可。
具体实现过程
一、基于端口限速的实现
主要思路是:
通过ebtables或者iptables对数据包打标,在tc规则中对打标数据进行管控从而进行速率限制。其中上行数据打标后统一放到ccinet0网口子类规则中进行处理,下行数据在每个网口子类规则中进行处理。
打标方法:
- 1.通过iptables来实现打标
iptables可以在mangle表中对数据包进行打标,使用physdev模块
模块来做,具体示例如下:
#需要该命令开启才能正常打标。
sysctl -w net.bridge.bridge-nf-call-iptables=1iptables -t mangle -N AUTOLANIN
iptables -t mangle -I PREROUTING -m physdev --physdev-in autolan -j AUTOLANIN
iptables -t mangle -A AUTOLANIN -s 0.0.0.0/0 -j MARK --set-mark 21iptables -t mangle -N AUTOLANOUT
iptables -t mangle -I PREROUTING -m physdev --physdev-out autolan -j AUTOLANOUT
iptables -t mangle -A AUTOLANOUT -s 0.0.0.0/0 -j MARK --set-mark 20
- 2.通过ebtables来实现打标。
打标也可以放到二层来做,由ebtables实现:
ebtables -t filter -I INPUT -i autolan -j mark --mark-set 21 --mark-target CONTINUE
ebtables -t filter -I OUTPUT -o autolan -j mark --mark-set 20 --mark-target CONTINUE
- 3.其他可能的思路:
ifb设备,根据tc相关文档描述,使用tc ingress限速,功能有限,似乎只能选择丢弃,并且也不支持分类。实际应用中,我们可以将业务流重定向到ifb设备上,业务流从这个ifb设备中出去,再又相应的端口接收,那我们就可以像正常使用tc对egress限速一样,来对ifb设备进行egress限速,就可以达到对接收方向的限速了(实际是将ingress方向重定向到虚拟设备ifb0,这样可以变相使用tc出口方向规则对流量进行控制,需要安装启用虚拟设备ifb,个人不采用此方式)
限速实现示例:
#需要关闭fastpath才能正常匹配数据包,否则匹配到数量非常少。之所以需要这个是因为当前设备采用的是ASR的芯片,其有一套内核加速机制,不关闭的话会导致无法打标
echo 1 > /sys/kernel/fastpath/fp_forward/bypass_fastpath
#打标
ebtables -t filter -I INPUT -i autolan -j mark --mark-set 21 --mark-target CONTINUE
ebtables -t filter -I OUTPUT -o autolan -j mark --mark-set 20 --mark-target CONTINUE
#上行速率限制
tc qdisc add dev ccinet0 root handle 1: htb default 28
tc class add dev ccinet0 parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000
tc class add dev ccinet0 parent 1:1 classid 1:11 htb rate 6000kbit ceil 6000kbit prio 0
tc qdisc add dev ccinet0 parent 1:11 handle 11: sfq perturb 10
tc filter add dev ccinet0 parent 1:0 prio 0 protocol ip handle 21 fw flowid 1:11
#下行速率限制
tc qdisc add dev autolan root handle 1: htb default 28
tc class add dev autolan parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000
tc class add dev autolan parent 1:1 classid 1:12 htb rate 8000kbit ceil 8000kbit prio 0
tc qdisc add dev autolan parent 1:12 handle 12: sfq perturb 10
tc filter add dev autolan parent 1:0 prio 0 protocol ip handle 20 fw flowid 1:12
参考实现:
#初始化tc队列(当前仅针对ccinet0,如果下行在br-lan中统一处理也放到此处)
qos_init_dev_tc_rule(){#增加根队列,未标记数据默认走28tc qdisc add dev ${UP_DEV} root handle 1: htb default 28#增加上行总流量限制规则tc class add dev ${UP_DEV} parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000
}
#清空接口tc规则
qos_clear_dev_limit_rule(){local dev=$1tc qdisc del dev $dev root
}
#删除ebtables打标规则
qos_dev_delete_mark(){ebtables -t filter -D INPUT -i $1 -j mark --mark-set $2 --mark-target CONTINUEebtables -t filter -D OUTPUT -o $1 -j mark --mark-set $3 --mark-target CONTINUE
}
#添加ebtables二层打标规则
qos_dev_set_mark(){ebtables -t filter -I INPUT -i $1 -j mark --mark-set $2 --mark-target CONTINUEebtables -t filter -I OUTPUT -o $1 -j mark --mark-set $3 --mark-target CONTINUE#也可以使用physdev模块进行iptables打标,示例如下:#sysctl -w net.bridge.bridge-nf-call-iptables=1#iptables -t mangle -N ETH02#iptables -t mangle -I PREROUTING -m physdev --physdev-out eth0.2 -j ETH02#iptables -t mangle -A ETH02 -s 0.0.0.0/0 -j MARK --set-mark 21
}
#端口限速设置
qos_set_dev_limit(){local config=$1local up_bwlocal down_bwlocal dev_namelocal real_namelocal pri_numlocal dw_classidlocal up_classidlocal dw_marklocal up_marklocal enableconfig_get enable $config enableconfig_get dev_name $config dev_nameconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwif [ "$dev_name" == "LAN1" ]; thenreal_name="autolan"pri_num=0classid=20dw_mark=20up_mark=30elif [ "$dev_name" == "SSID1_24G" ]; thenreal_name="wlan0"pri_num=0classid=21dw_mark=21up_mark=31elif [ "$dev_name" == "SSID2_24G" ]; thenreal_name="wlan0-va0"pri_num=0classid=22dw_mark=22up_mark=32elif [ "$dev_name" == "SSID3_24G" ]; thenreal_name="wlan0-va1"pri_num=0classid=23dw_mark=23up_mark=33elif [ "$dev_name" == "SSID1_5G" ]; thenreal_name="wlan1"pri_num=0classid=24dw_mark=24up_mark=34elif [ "$dev_name" == "SSID2_5G" ]; thenreal_name="wlan1-va0"pri_num=0classid=25dw_mark=25up_mark=35elif [ "$dev_name" == "SSID3_5G" ]; thenreal_name="wlan1-va1"pri_num=0classid=26dw_mark=26up_mark=36elseecho "dev_name is $dev_name" > /dev/kmsgreturn 0fiecho "real_name is $real_name" > /dev/kmsg#先清空一下针对该端口的规则qos_clear_dev_limit_rule ${real_name}qos_dev_delete_mark ${real_name} ${up_mark} ${dw_mark}if [ "$enable" == "0" ]; thenecho "$dev_name enable is 0" > /dev/kmsgreturn 0fiecho "dev_name is $dev_name, down_bw is $down_bw, up_bw is $up_bw" > /dev/kmsg#设置打标规则qos_dev_set_mark ${real_name} ${up_mark} ${dw_mark}#基于端口的上行限速设置
if [ "$up_bw" != "0" ]; then#增加子类tc class add dev ${UP_DEV} parent 1:1 classid 1:${classid} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit prio 0#为子类添加SFQ公平队列,每10秒重置tc qdisc add dev ${UP_DEV} parent 1:${classid} handle ${classid}: sfq perturb 10#根据打标值过滤tc filter add dev ${UP_DEV} parent 1:0 prio 0 protocol ip handle ${up_mark} fw flowid 1:${classid}
fi#基于端口的下行限速设置
if [ "$down_bw" != "0" ]; thentc qdisc add dev ${real_name} root handle 1: htb default 28tc class add dev ${real_name} parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000#添加子类tc class add dev ${real_name} parent 1:1 classid 1:${classid} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit prio 0#为子类添加SFQ公平队列tc qdisc add dev ${real_name} parent 1:${classid} handle ${classid}: sfq perturb 10#过滤规则tc filter add dev ${real_name} parent 1:0 prio 0 protocol ip handle ${dw_mark} fw flowid 1:${classid}
fi
}
qos_set_dev_rule(){qos_init_dev_tc_ruleconfig_foreach qos_set_dev_limit qos_dev_limit
}
二、基于MAC限速的实现
主要思路是:
- 1.老思路:通过mac查arp表,最后通过ip来限速
存在的问题及应对思路:
CPE重启后执行脚本时设备未连接,arp表中查找不到mac对应ip会导致规则设置失败,后续设备连接后出现速度不受限情况
应对:新连接进来设备时重新执行脚本(在代码中操作不修改shell脚本,当前已采用新思路,未使用该方法)
老思路参考实现:
#初始化基于ip和mac的tc规则
qos_init_tc_rule(){#新建限速队列tc qdisc add dev ${UP_DEV} root handle 100: htb default 100tc qdisc add dev ${DN_DEV} root handle 200: htb default 200#新建根分类tc class add dev ${UP_DEV} parent 100: classid 100:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev ${DN_DEV} parent 200: classid 200:1 htb rate 1000Mbit burst 15k quantum 60000
}
#删除旧链
qos_delete_mac_limit_chain(){iptables -t mangle -D FORWARD -j QOS_MAC_FORWARDiptables -t mangle -F QOS_MAC_FORWARDiptables -t mangle -X QOS_MAC_FORWARD
}
#创建qos链
qos_create_mac_limit_chain(){iptables -t mangle -N QOS_MAC_FORWARDiptables -t mangle -I FORWARD -j QOS_MAC_FORWARD
}
qos_set_mac_limit(){local config=$1local up_bwlocal down_bwlocal mac_addrlocal mac_addr_lowerlocal ip_addrlocal ip_taglocal enableconfig_get enable $config enableconfig_get mac_addr $config mac_addrconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwecho "mac_addr is $mac_addr" > /dev/kmsgif [ "$enable" == "0" ]; thenecho "$mac_addr enable is 0" > /dev/kmsgreturn 0fi#将mac地址转换为小写,不然大写的匹配不到ipmac_addr_lower=$(echo $mac_addr | tr '[A-Z]' '[a-z]')local ip_addr=`cat /proc/net/arp |grep $mac_addr_lower | awk -F ' ' '{print $1}'`if [ "$ip_addr" == "" ]; thenecho "the ip addr of $mac_addr is null" > /dev/kmsgreturn 0filocal ip_tag=`echo $ip_addr | awk -F '.' '{print $4}'`echo "ip_addr is $ip_addr, ip_tag is $ip_tag" > /dev/kmsgif [ "$up_bw" != "0" ]; then#创建子分类tc class add dev ${UP_DEV} parent 100:1 classid 100:${ip_tag} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit burst 15k prio 1#创建过滤器 tc filter add dev ${UP_DEV} protocol all parent 100: prio 1 handle $ip_tag fw classid 100:${ip_tag}#创建公平队列tc qdisc add dev ${UP_DEV} parent 100:${ip_tag} handle ${ip_tag}: sfq perturb 10iptables -t mangle -A QOS_MAC_FORWARD -s $ip_addr/32 -j MARK --set-mark ${ip_tag}
fiif [ "$down_bw" != "0" ]; thentc class add dev ${DN_DEV} parent 200:1 classid 200:${ip_tag} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev ${DN_DEV} protocol all parent 200: prio 2 handle $ip_tag fw classid 200:${ip_tag}tc qdisc add dev ${DN_DEV} parent 200:${ip_tag} handle ${ip_tag}: sfq perturb 10iptables -t mangle -A QOS_MAC_FORWARD -d $ip_addr/32 -j MARK --set-mark ${ip_tag}
fi
}
qos_set_mac_rule(){qos_init_tc_ruleqos_create_mac_limit_chainconfig_foreach qos_set_mac_limit qos_mac_limit
}
- 2.新思路:通过mac模块对mac打标直接进行限速
存在的问题及应对思路:
–mac-source 只能用于PREROUTING/INPUT/FORWARD这三个链,下行数据在nat转换前数据包目的mac非目标设备mac,如果直接在iptables中打标会不成功,所以采用ebtables进行打标,但是ebtables打标就无法在br-lan上做下行的限速
应对:在br-lan网桥下挂的所有网口都设定tc规则
#新思路参考实现qos_init_mac_tc_rule(){#新建限速队列tc qdisc add dev ${UP_DEV} root handle 100: htb default 100tc qdisc add dev autolan root handle 200: htb default 200tc qdisc add dev wlan0 root handle 300: htb default 300tc qdisc add dev wlan0-va0 root handle 400: htb default 400tc qdisc add dev wlan0-va1 root handle 500: htb default 500tc qdisc add dev wlan1 root handle 600: htb default 600tc qdisc add dev wlan1-va0 root handle 700: htb default 700tc qdisc add dev wlan1-va1 root handle 800: htb default 800#新建根分类tc class add dev ${UP_DEV} parent 100: classid 100:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev autolan parent 200: classid 200:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0 parent 300: classid 300:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0-va0 parent 400: classid 400:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0-va1 parent 500: classid 500:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1 parent 600: classid 600:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1-va0 parent 700: classid 700:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1-va1 parent 800: classid 800:1 htb rate 1000Mbit burst 15k quantum 60000
}
#删除ebtables旧链
qos_delete_mac_limit_chain(){ebtables -D INPUT -j QOS_MAC_CHAINebtables -D OUTPUT -j QOS_MAC_CHAINebtables -F QOS_MAC_CHAINebtables -X QOS_MAC_CHAIN
}
#创建qos链
qos_create_mac_limit_chain(){ebtables -t filter -N QOS_MAC_CHAINebtables -t filter -I INPUT -j QOS_MAC_CHAINebtables -t filter -I OUTPUT -j QOS_MAC_CHAIN
}
#基于mac的初始打标值
mac_mark_value=10
#mac限速设置
qos_set_mac_limit(){local mark_valuelocal config=$1local up_bwlocal down_bwlocal mac_addrlocal mac_addr_lowerlocal ip_addrlocal ip_taglocal enableconfig_get enable $config enableconfig_get mac_addr $config mac_addrconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwecho "mac_addr is $mac_addr" > /dev/kmsgif [ "$enable" == "0" ]; thenecho "$mac_addr enable is 0" > /dev/kmsgreturn 0fi#统一换成小写mac地址mac_addr_lower=$(echo $mac_addr | tr '[A-Z]' '[a-z]')if [ "$mac_addr_lower" == "" ]; thenecho "the mac addr is null" > /dev/kmsgreturn 0fimark_value=$mac_mark_value#打标值递增,区分下一mac打标值mac_mark_value=$(($mac_mark_value+1)) echo "mac_addr is $mac_addr_lower, mac_tag is $mark_value" > /dev/kmsg#上行统一在各个子类中处理
if [ "$up_bw" != "0" ]; then#创建子分类tc class add dev ${UP_DEV} parent 100:1 classid 100:${mark_value} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit burst 15k prio 1#创建过滤器 tc filter add dev ${UP_DEV} protocol all parent 100: prio 1 handle $mark_value fw classid 100:${mark_value}#创建公平队列tc qdisc add dev ${UP_DEV} parent 100:${mark_value} handle ${mark_value}: sfq perturb 10ebtables -t filter -A QOS_MAC_CHAIN -s "$mac_addr_lower" -j mark --mark-set ${mark_value} --mark-target CONTINUE
fiif [ "$down_bw" != "0" ]; thenebtables -t filter -A QOS_MAC_CHAIN -d "$mac_addr_lower" -j mark --mark-set ${mark_value} --mark-target CONTINUEtc class add dev autolan parent 200:1 classid 200:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev autolan protocol all parent 200: prio 2 handle $mark_value fw classid 200:${mark_value}tc qdisc add dev autolan parent 200:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0 parent 300:1 classid 300:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0 protocol all parent 300: prio 2 handle $mark_value fw classid 300:${mark_value}tc qdisc add dev wlan0 parent 300:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0-va0 parent 400:1 classid 400:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0-va0 protocol all parent 400: prio 2 handle $mark_value fw classid 400:${mark_value}tc qdisc add dev wlan0-va0 parent 400:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0-va1 parent 500:1 classid 500:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0-va1 protocol all parent 500: prio 2 handle $mark_value fw classid 500:${mark_value}tc qdisc add dev wlan0-va1 parent 500:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1 parent 600:1 classid 600:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1 protocol all parent 600: prio 2 handle $mark_value fw classid 600:${mark_value}tc qdisc add dev wlan1 parent 600:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1-va0 parent 700:1 classid 700:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1-va0 protocol all parent 700: prio 2 handle $mark_value fw classid 700:${mark_value}tc qdisc add dev wlan1-va0 parent 700:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1-va1 parent 800:1 classid 800:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1-va1 protocol all parent 800: prio 2 handle $mark_value fw classid 800:${mark_value}tc qdisc add dev wlan1-va1 parent 800:${mark_value} handle ${mark_value}: sfq perturb 10
fi
}
qos_set_mac_rule(){qos_init_mac_tc_ruleqos_create_mac_limit_chainconfig_foreach qos_set_mac_limit qos_mac_limit
}
三、基于IP限速的实现
主要思路是:
在mangle表中使用-s、-d参数或者使用iprange模块对数据进行打标,然后在ccinet0和br-lan上使用tc规则进行限速处理
参考实现:
#初始化基于ip和mac的tc规则
qos_init_tc_rule(){#新建限速队列tc qdisc add dev ${UP_DEV} root handle 100: htb default 100tc qdisc add dev ${DN_DEV} root handle 200: htb default 200#新建根分类tc class add dev ${UP_DEV} parent 100: classid 100:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev ${DN_DEV} parent 200: classid 200:1 htb rate 1000Mbit burst 15k quantum 60000
}
#删除旧链
qos_delete_ip_limit_chain(){iptables -t mangle -D FORWARD -j QOS_IP_FORWARDiptables -t mangle -F QOS_IP_FORWARDiptables -t mangle -X QOS_IP_FORWARD
}
#创建qos链
qos_create_ip_limit_chain(){iptables -t mangle -N QOS_IP_FORWARDiptables -t mangle -I FORWARD -j QOS_IP_FORWARD
}
qos_set_ip_limit(){local config=$1local up_bwlocal down_bwlocal start_iplocal end_iplocal enableconfig_get enable $config enableconfig_get start_ip $config start_ipconfig_get end_ip $config end_ipconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwif [ "$enable" == "0" ]; thenecho "$start_ip enable is 0" > /dev/kmsgreturn 0filocal start_last=`echo $start_ip | awk -F '.' '{print $4}'`local end_last=`echo $end_ip | awk -F '.' '{print $4}'`echo "start_last is $start_last, end_last is $end_last" > /dev/kmsgif [ "$up_bw" != "0" ]; then#创建子分类tc class add dev ${UP_DEV} parent 100:1 classid 100:${start_last} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit burst 15k prio 1#创建过滤器 tc filter add dev ${UP_DEV} protocol all parent 100: prio 1 handle $start_last fw classid 100:${start_last}#创建公平队列tc qdisc add dev ${UP_DEV} parent 100:${start_last} handle ${start_last}: sfq perturb 10
fiif [ "$down_bw" != "0" ]; thentc class add dev ${DN_DEV} parent 200:1 classid 200:${start_last} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev ${DN_DEV} protocol all parent 200: prio 2 handle $start_last fw classid 200:${start_last}tc qdisc add dev ${DN_DEV} parent 200:${start_last} handle ${start_last}: sfq perturb 10fiif [ "$start_ip" == "$end_ip" ]; theniptables -t mangle -A QOS_IP_FORWARD -s $start_ip/32 -j MARK --set-mark ${start_last}iptables -t mangle -A QOS_IP_FORWARD -d $start_ip/32 -j MARK --set-mark ${start_last}elseiptables -t mangle -A QOS_IP_FORWARD -m iprange --src-range ${start_ip}-${end_ip} -j MARK --set-mark ${start_last}iptables -t mangle -A QOS_IP_FORWARD -m iprange --dst-range ${start_ip}-${end_ip} -j MARK --set-mark ${start_last}
fi}
qos_set_ip_rule(){qos_init_tc_ruleqos_create_ip_limit_chainconfig_foreach qos_set_ip_limit qos_ip_limit
}
四、整体shell脚本
#!/bin/sh
. /lib/functions.sh
. /lib/config/uci.shQOS_FILE="qos"
g_qos_enable=""
g_limit_mode=""
UP_DEV="ccinet0"
DN_DEV="br-lan"LAN_NAME=""
DEVICE_LAN_SWITCH=""
#LAN_NAME="eth0.2" #with switch
#LAN_NAME="eth0" #without switch#######################################################start of qos based on dev
#初始化tc队列(当前仅针对ccinet0,如果下行在br-lan中统一处理也放到此处)
qos_init_dev_tc_rule(){#增加根队列,未标记数据默认走28tc qdisc add dev ${UP_DEV} root handle 1: htb default 28#增加上行总流量限制规则tc class add dev ${UP_DEV} parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000
}
#清空接口tc规则
qos_clear_dev_limit_rule(){local dev=$1tc qdisc del dev $dev root
}
#删除ebtables打标规则
qos_dev_delete_mark(){ebtables -t filter -D INPUT -i $1 -j mark --mark-set $2 --mark-target CONTINUEebtables -t filter -D OUTPUT -o $1 -j mark --mark-set $3 --mark-target CONTINUE
}
#添加ebtables二层打标规则
qos_dev_set_mark(){ebtables -t filter -I INPUT -i $1 -j mark --mark-set $2 --mark-target CONTINUEebtables -t filter -I OUTPUT -o $1 -j mark --mark-set $3 --mark-target CONTINUE#也可以使用physdev模块进行iptables打标,示例如下:#sysctl -w net.bridge.bridge-nf-call-iptables=1#iptables -w -t mangle -N ETH02#iptables -w -t mangle -I PREROUTING -m physdev --physdev-out eth0.2 -j ETH02#iptables -w -t mangle -A ETH02 -s 0.0.0.0/0 -j MARK --set-mark 21
}
#端口限速设置
qos_set_dev_limit(){local config=$1local up_bwlocal down_bwlocal dev_namelocal real_namelocal pri_numlocal dw_classidlocal up_classidlocal dw_marklocal up_marklocal enableconfig_get enable $config enableconfig_get dev_name $config dev_nameconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwif [ "$dev_name" == "LAN1" ]; thenreal_name="${LAN_NAME}"pri_num=0classid=20dw_mark=20up_mark=30elif [ "$dev_name" == "SSID1_24G" ]; thenreal_name="wlan0"pri_num=0classid=21dw_mark=21up_mark=31elif [ "$dev_name" == "SSID2_24G" ]; thenreal_name="wlan0-va0"pri_num=0classid=22dw_mark=22up_mark=32elif [ "$dev_name" == "SSID3_24G" ]; thenreal_name="wlan0-va1"pri_num=0classid=23dw_mark=23up_mark=33elif [ "$dev_name" == "SSID1_5G" ]; thenreal_name="wlan1"pri_num=0classid=24dw_mark=24up_mark=34elif [ "$dev_name" == "SSID2_5G" ]; thenreal_name="wlan1-va0"pri_num=0classid=25dw_mark=25up_mark=35elif [ "$dev_name" == "SSID3_5G" ]; thenreal_name="wlan1-va1"pri_num=0classid=26dw_mark=26up_mark=36elseecho "dev_name is $dev_name" > /dev/kmsgreturn 0fiecho "real_name is $real_name" > /dev/kmsg#先清空一下针对该端口的规则qos_clear_dev_limit_rule ${real_name}qos_dev_delete_mark ${real_name} ${up_mark} ${dw_mark}if [ "$enable" == "0" ]; thenecho "$dev_name enable is 0" > /dev/kmsgreturn 0fiecho "dev_name is $dev_name, down_bw is $down_bw, up_bw is $up_bw" > /dev/kmsg#设置打标规则qos_dev_set_mark ${real_name} ${up_mark} ${dw_mark}#基于端口的上行限速设置if [ "$up_bw" != "0" ]; then#增加子类tc class add dev ${UP_DEV} parent 1:1 classid 1:${classid} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit prio 0#为子类添加SFQ公平队列,每10秒重置tc qdisc add dev ${UP_DEV} parent 1:${classid} handle ${classid}: sfq perturb 10#根据打标值过滤tc filter add dev ${UP_DEV} parent 1:0 prio 0 protocol ip handle ${up_mark} fw flowid 1:${classid}fi#基于端口的下行限速设置if [ "$down_bw" != "0" ]; thentc qdisc add dev ${real_name} root handle 1: htb default 28tc class add dev ${real_name} parent 1: classid 1:1 htb rate 1000Mbit burst 15k quantum 60000#添加子类tc class add dev ${real_name} parent 1:1 classid 1:${classid} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit prio 0#为子类添加SFQ公平队列tc qdisc add dev ${real_name} parent 1:${classid} handle ${classid}: sfq perturb 10#过滤规则tc filter add dev ${real_name} parent 1:0 prio 0 protocol ip handle ${dw_mark} fw flowid 1:${classid}fi
}
qos_set_dev_rule(){#上行速率控制统一放到ccinet0子类中分开处理,下行速率控制放到每一个dev中处理(如果不生效考虑在br-lan中用子类进行处理)#`echo 1 > /sys/kernel/fastpath/fp_forward/bypass_fastpath`qos_init_dev_tc_ruleconfig_foreach qos_set_dev_limit qos_dev_limit
}
#######################################################end of qos based on dev#######################################################start of qos based on mac
#当前只能在ebtables上对特定mac打标,处理采用在每个dev上都做限制#初始化基于mac的tc规则
qos_init_mac_tc_rule(){#新建限速队列tc qdisc add dev ${UP_DEV} root handle 100: htb default 100tc qdisc add dev ${LAN_NAME} root handle 200: htb default 200tc qdisc add dev wlan0 root handle 300: htb default 300tc qdisc add dev wlan0-va0 root handle 400: htb default 400tc qdisc add dev wlan0-va1 root handle 500: htb default 500tc qdisc add dev wlan1 root handle 600: htb default 600tc qdisc add dev wlan1-va0 root handle 700: htb default 700tc qdisc add dev wlan1-va1 root handle 800: htb default 800#新建根分类tc class add dev ${UP_DEV} parent 100: classid 100:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev ${LAN_NAME} parent 200: classid 200:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0 parent 300: classid 300:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0-va0 parent 400: classid 400:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan0-va1 parent 500: classid 500:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1 parent 600: classid 600:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1-va0 parent 700: classid 700:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev wlan1-va1 parent 800: classid 800:1 htb rate 1000Mbit burst 15k quantum 60000
}
#删除ebtables旧链
qos_delete_mac_limit_chain(){#iptables -w -t mangle -D FORWARD -j QOS_MAC_FORWARD#iptables -w -t mangle -F QOS_MAC_FORWARD#iptables -w -t mangle -X QOS_MAC_FORWARDebtables -D INPUT -j QOS_MAC_CHAINebtables -D OUTPUT -j QOS_MAC_CHAINebtables -F QOS_MAC_CHAINebtables -X QOS_MAC_CHAIN
}
#创建qos链
qos_create_mac_limit_chain(){#iptables -w -t mangle -N QOS_MAC_FORWARD#iptables -w -t mangle -I FORWARD -j QOS_MAC_FORWARDebtables -t filter -N QOS_MAC_CHAINebtables -t filter -I INPUT -j QOS_MAC_CHAINebtables -t filter -I OUTPUT -j QOS_MAC_CHAIN
}
#基于mac的初始打标值
mac_mark_value=10
#mac限速设置
qos_set_mac_limit(){local mark_valuelocal config=$1local up_bwlocal down_bwlocal mac_addrlocal mac_addr_lowerlocal ip_addrlocal ip_taglocal enableconfig_get enable $config enableconfig_get mac_addr $config mac_addrconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwecho "mac_addr is $mac_addr" > /dev/kmsgif [ "$enable" == "0" ]; thenecho "$mac_addr enable is 0" > /dev/kmsgreturn 0fi#统一换成小写mac地址mac_addr_lower=$(echo $mac_addr | tr '[A-Z]' '[a-z]')if [ "$mac_addr_lower" == "" ]; thenecho "the mac addr is null" > /dev/kmsgreturn 0fimark_value=$mac_mark_value#打标值递增,区分下一mac打标值mac_mark_value=$(($mac_mark_value+1)) echo "mac_addr is $mac_addr_lower, mac_tag is $mark_value" > /dev/kmsg#上行统一在各个子类中处理if [ "$up_bw" != "0" ]; then#创建子分类tc class add dev ${UP_DEV} parent 100:1 classid 100:${mark_value} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit burst 15k prio 1#创建过滤器 tc filter add dev ${UP_DEV} protocol all parent 100: prio 1 handle $mark_value fw classid 100:${mark_value}#创建公平队列tc qdisc add dev ${UP_DEV} parent 100:${mark_value} handle ${mark_value}: sfq perturb 10ebtables -t filter -A QOS_MAC_CHAIN -s "$mac_addr_lower" -j mark --mark-set ${mark_value} --mark-target CONTINUEfiif [ "$down_bw" != "0" ]; then#iptables mac模块--mac-source只能在PREROUTING/INPUT/FORWARD中使用,nat转换之前的目的mac非设备mac无法正确匹配#针对真实mac地址无法在nat修改mac后打标,只能在ebtables上打标,br-lan无法处理所以在br-lan下每一个端口都加上tc规则(另一种方式:接入设备重新加载脚本,未采用)ebtables -t filter -A QOS_MAC_CHAIN -d "$mac_addr_lower" -j mark --mark-set ${mark_value} --mark-target CONTINUEtc class add dev ${LAN_NAME} parent 200:1 classid 200:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev ${LAN_NAME} protocol all parent 200: prio 2 handle $mark_value fw classid 200:${mark_value}tc qdisc add dev ${LAN_NAME} parent 200:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0 parent 300:1 classid 300:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0 protocol all parent 300: prio 2 handle $mark_value fw classid 300:${mark_value}tc qdisc add dev wlan0 parent 300:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0-va0 parent 400:1 classid 400:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0-va0 protocol all parent 400: prio 2 handle $mark_value fw classid 400:${mark_value}tc qdisc add dev wlan0-va0 parent 400:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan0-va1 parent 500:1 classid 500:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan0-va1 protocol all parent 500: prio 2 handle $mark_value fw classid 500:${mark_value}tc qdisc add dev wlan0-va1 parent 500:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1 parent 600:1 classid 600:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1 protocol all parent 600: prio 2 handle $mark_value fw classid 600:${mark_value}tc qdisc add dev wlan1 parent 600:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1-va0 parent 700:1 classid 700:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1-va0 protocol all parent 700: prio 2 handle $mark_value fw classid 700:${mark_value}tc qdisc add dev wlan1-va0 parent 700:${mark_value} handle ${mark_value}: sfq perturb 10tc class add dev wlan1-va1 parent 800:1 classid 800:${mark_value} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev wlan1-va1 protocol all parent 800: prio 2 handle $mark_value fw classid 800:${mark_value}tc qdisc add dev wlan1-va1 parent 800:${mark_value} handle ${mark_value}: sfq perturb 10fi
}
qos_set_mac_rule(){qos_init_mac_tc_ruleqos_create_mac_limit_chainconfig_foreach qos_set_mac_limit qos_mac_limit
}
#######################################################end of qos based on mac#######################################################start of qos based on ip
#初始化基于ip的tc规则
qos_init_ip_tc_rule(){#新建限速队列tc qdisc add dev ${UP_DEV} root handle 100: htb default 100tc qdisc add dev ${DN_DEV} root handle 200: htb default 200#新建根分类tc class add dev ${UP_DEV} parent 100: classid 100:1 htb rate 1000Mbit burst 15k quantum 60000tc class add dev ${DN_DEV} parent 200: classid 200:1 htb rate 1000Mbit burst 15k quantum 60000
}
#删除旧链
qos_delete_ip_limit_chain(){iptables -w -t mangle -D FORWARD -j QOS_IP_FORWARDiptables -w -t mangle -F QOS_IP_FORWARDiptables -w -t mangle -X QOS_IP_FORWARD
}
#创建qos链
qos_create_ip_limit_chain(){iptables -w -t mangle -N QOS_IP_FORWARDiptables -w -t mangle -I FORWARD -j QOS_IP_FORWARD
}
qos_set_ip_limit(){local config=$1local up_bwlocal down_bwlocal start_iplocal end_iplocal enableconfig_get enable $config enableconfig_get start_ip $config start_ipconfig_get end_ip $config end_ipconfig_get down_bw $config down_bwconfig_get up_bw $config up_bwif [ "$enable" == "0" ]; thenecho "$start_ip enable is 0" > /dev/kmsgreturn 0filocal start_last=`echo $start_ip | awk -F '.' '{print $4}'`local end_last=`echo $end_ip | awk -F '.' '{print $4}'`echo "start_last is $start_last, end_last is $end_last" > /dev/kmsgif [ "$up_bw" != "0" ]; then#创建子分类tc class add dev ${UP_DEV} parent 100:1 classid 100:${start_last} htb rate ${up_bw}Mbit ceil ${up_bw}Mbit burst 15k prio 1#创建过滤器 tc filter add dev ${UP_DEV} protocol all parent 100: prio 1 handle $start_last fw classid 100:${start_last}#创建公平队列tc qdisc add dev ${UP_DEV} parent 100:${start_last} handle ${start_last}: sfq perturb 10fiif [ "$down_bw" != "0" ]; thentc class add dev ${DN_DEV} parent 200:1 classid 200:${start_last} htb rate ${down_bw}Mbit ceil ${down_bw}Mbit burst 15k prio 2tc filter add dev ${DN_DEV} protocol all parent 200: prio 2 handle $start_last fw classid 200:${start_last}tc qdisc add dev ${DN_DEV} parent 200:${start_last} handle ${start_last}: sfq perturb 10fiif [ "$start_ip" == "$end_ip" ]; theniptables -w -t mangle -A QOS_IP_FORWARD -s $start_ip/32 -j MARK --set-mark ${start_last}iptables -w -t mangle -A QOS_IP_FORWARD -d $start_ip/32 -j MARK --set-mark ${start_last}elseiptables -w -t mangle -A QOS_IP_FORWARD -m iprange --src-range ${start_ip}-${end_ip} -j MARK --set-mark ${start_last}iptables -w -t mangle -A QOS_IP_FORWARD -m iprange --dst-range ${start_ip}-${end_ip} -j MARK --set-mark ${start_last}fi}
qos_set_ip_rule(){qos_init_ip_tc_ruleqos_create_ip_limit_chainconfig_foreach qos_set_ip_limit qos_ip_limit
}
#######################################################end of qos based on ipqos_del_all_rule(){tc qdisc del dev ${UP_DEV} roottc qdisc del dev ${DN_DEV} roottc qdisc del dev ${LAN_NAME} roottc qdisc del dev wlan0 roottc qdisc del dev wlan0-va0 roottc qdisc del dev wlan0-va1 roottc qdisc del dev wlan1 roottc qdisc del dev wlan1-va0 roottc qdisc del dev wlan1-va1 root#qos_delete_dev_limit_chainqos_delete_mac_limit_chainqos_delete_ip_limit_chain}#qos_init
qos_init(){config_load "$QOS_FILE"config_get g_qos_enable qos_ctrl qos_enableconfig_get g_limit_mode qos_ctrl current_mode#config_get LAN_NAME qos_ctrl lan_nameDEVICE_LAN_SWITCH=$(uci get properties.DEVICE_LAN_SWITCH)if [ "$DEVICE_LAN_SWITCH" == "1" ];thenLAN_NAME="eth0.2"elseLAN_NAME="eth0"fiecho "DEVICE_LAN_SWITCH: $DEVICE_LAN_SWITCH" > /dev/kmsgqos_del_all_ruleecho "g_qos_enable=$g_qos_enable g_limit_mode=$g_limit_mode" > /dev/kmsgecho "modified on 2023.8.1" > /dev/kmsgif [ -z "$g_qos_enable" ]; thenecho "g_qos_enable is null" > /dev/kmsgexit 0fiif [ "$g_qos_enable" = "1" ] ; then`echo 1 > /sys/kernel/fastpath/fp_forward/bypass_fastpath`echo "qos_enable is 1, start config!" > /dev/kmsgif [ "$g_limit_mode" == "dev" ]; thenqos_set_dev_ruleelif [ "$g_limit_mode" == "mac" ]; thenqos_set_mac_ruleelif [ "$g_limit_mode" == "ip" ]; thenqos_set_ip_ruleelseecho "g_limit_mode is error, qos exit!" > /dev/kmsgfielif [ "$g_qos_enable" = "0" ] ; then echo "qos_enable is 0, exit!" > /dev/kmsg`echo 0 > /sys/kernel/fastpath/fp_forward/bypass_fastpath`exit 0elseecho "g_qos_enable value is error" > /dev/kmsgfi
}input_type=$1
case $input_type in"init")qos_init ;;
esac
五、注意事项
- 1.确认上行网口名称,当前上行为UP_DEV="ccinet0"下行为DN_DEV=“br-lan”
- 2.确认LAN口和wifi的实际名称,该信息在基于端口和基于MAC的限速中会用到
- 3.手动测试时需要将fastpath关闭否则打标匹配存在问题
echo 1 > /sys/kernel/fastpath/fp_forward/bypass_fastpath
- 4.如果需要对WAN接入做限制,需要对应修改相关内容
六、其他补充信息
常用的一些命令:
#显示信息
ebtables -L --Lc
iptables -t mangle -nvL
tc qdisc
tc qdisc show dev ccinet0
tc -s class ls dev ccinet0
tc -s filter ls dev ccinet0
#清空tc规则
tc qdisc del dev ${UP_DEV} root
tc qdisc del dev ${DN_DEV} root
tc qdisc del dev autolan root
tc qdisc del dev wlan0 root
tc qdisc del dev wlan0-va0 root
tc qdisc del dev wlan0-va1 root
tc qdisc del dev wlan1 root
tc qdisc del dev wlan1-va0 root
tc qdisc del dev wlan1-va1 root
#调用函数清空打标规则
qos_delete_mac_limit_chain
qos_delete_ip_limit_chain
常用限速单位
kbps 千字节/秒
mbps 兆字节/秒
kbit KBits/秒
mbit MBits/秒
bps或者一个无单位数字 字节数/秒
Ref:
https://blog.51cto.com/u_15065849/3803690
http://doc.aiwaly.com/docs/arm/arm-1ek8uo3rs27s1
https://blog.csdn.net/Van_male/article/details/98938160
https://www.cnblogs.com/yxwkf/p/5424383.html