首页 > 其他分享 >tc端口流量控制(带宽限速)

tc端口流量控制(带宽限速)

时间:2023-06-05 22:48:06浏览次数:40  
标签:enp8s0 ip 端口 带宽 网卡 12345 tc

tc qdisc add dev ens192 root handle 1: htb
tc class add dev ens192 parent 1: classid 1:1 htb rate 80mbit
tc filter add dev ens192 protocol ip parent 1:0 prio 1 u32 match ip dst 0.0.0.0/0 flowid 1:1

 


sudo tc qdisc del root dev ens192

 

 

 

tc端口流量控制
tc真的是个巨坑,搞了一天才明白问题出在哪,记录一下。

tc前置
首先强调一下,tc只管发包,不管收包的事。tc只管发包,不管收包的事。tc只管发包,不管收包的事。重要的事说三遍,坑就出在这里,很容易给绕晕过去。换言之,tc只管出站(出网卡)的流量,不管进来的流量,当然这句话也不完全是,因为即使是本地回环lo,也是这么一回事。

更具体地说,我们将包简单的解构为:[source-ip] | [source-port] | [other-data] | [destination-ip] | [destination-port]

这对后面的说明和理解会有较大的帮助。这个包显然是由 source-ip 机器的 source-port 发送出去的,经由的是 source 机器的网卡。因此如果要做限流,在 destination 机器上的网卡设置规则是没有意义的,只能在 source 机器的网卡上限制规则。

具体操作
首先简单了解一下tc的三大功能,其他可以忽略,当然要想深入可以去看参考资料的demo。这三个就可以简单完成端口流量控制的目标了,重点其实是后两个。

tc-qdisc:队列规则。后面用的是htb层次令牌桶的队列。队列是用来管理消息进出和分发的。
tc-class:定义队列规则类。每个类可以简单理解成一个子队列,有着独立的规则。
tc-filter:定义过滤器。端口控流就用得到了,如果和iptables配合还可以专门过滤出带有特殊标志的包。实际上就是将包过滤到特定class的队列去。
来一遍实操就懂了,这里默认对外的网卡是enp8s0,本地回环是lo,这两个都可以实现端口控流。

先删除root已有的队列规则(del是delete,root是根队列,dev是device,enp8s0是网卡名,可以通过ip addr查看):

sudo tc qdisc del root dev enp8s0

重建root队列规则(handle可以简单理解为处理句柄,类似C那种,1:其实是1:0,即缺省是0,所以这个队列的‘名字’就是1:0了,htb是层次令牌桶,即所用的队列类型,default 3指的是如果进来的包没有指定要去的子类,就默认去1:3子类的队列,显然,这里的1是一个大类的公共前缀,而0和3就是小类或者称父类、子类的专属后缀):

sudo tc qdisc add root dev enp8s0 handle 1: htb default 3

在这个队列的基础上建一个子类,设置带宽上限实现该子类的控流(parent用于指定父类,classid与上面的handle类似,用于指定这个子类的名字,rate用于控流,由于ceil和rate默认是一致的,所以如果只是控制流量稳定在一个值,可以不用额外再写ceil,这里控制带宽上限为20mbps):

sudo tc class add dev enp8s0 parent 1: classid 1:1 htb rate 20mbit

接着可以在这个子类上再建两个子类(注意带宽不能超过父类1:1的20mbps):

sudo tc class add dev enp8s0 parent 1:1 classid 1:2 htb rate 10mbit

sudo tc class add dev enp8s0 parent 1:1 classid 1:3 htb rate 5mbit

到这里就可以知道,包如果分发给了1:2的子类队列,带宽最高是10mbps,如果没有分发给特定的子类队列,那就会按照默认设置的3,分发给1:3的子类队列,带宽最高是5mbps。

如何分发就涉及到了过滤器了(protocol是协议类别,ip就可以了,其他还有指定tcp,udp等。prio是优先级别。sport是source port的意思,也可以设定dport,即destination port。0xffff是用于设置端口范围的,或者说偏移量,这里的效果是单个端口。flowid就是满足过滤器条件的包分发到哪个流,这里将包分发到1:2的子类队列):

sudo tc filter add dev enp8s0 protocol ip parent 1:0 prio 1 u32 match ip sport 12345 0xffff flowid 1:2

到这里就完成了12345端口的限流,不过注意是发出的包限流,而不是收到的包限流。如果要将收到的包限流,只有两种方式,1)一个是做一个中转网卡,让那个网卡收到的包再发给enp8s0这个网卡,然后将规则设定到那个中转网卡上,那么本质上控制的就是中转网卡的发包,进而影响到enp8s0的收包。2)在对接的服务端的网卡上设置规则,本地客户端收到的包自然也就是限流后的了。

至于过滤器的sport和dport的意义,我们还是拿之前提到的包的结构来说明。比如sport 12345指的是这个包是从本地的12345端口发出的包,满足这类条件的包就能通过这个过滤器。而dport 12345指的是这个包是本地发出的包(不管是哪个端口的),且包发往的目的端口是12345,满足这类条件的包可通过过滤器,而不是本地收到的发到12345端口的包,即使是本地发到本地12345端口的包,也是在发送的时候就限流了。此外过滤器还能设置目的ip,只要是发往那个ip地址的包就会通过过滤器,这里就不细说了。可以发现这里提到的全部都是发包,这也就是为什么前面一直在强调tc影响的是发包而不是收包了。

测试结果
前置环境装个iperf3就可以了:sudo apt-get install iperf3

我们假定有两个机器,ip地址分别是192.168.1.101和192.168.1.102。

将上述tc规则设置在101机器的enp8s0网卡上。

接着在101机器上的12345端口设置服务端(s是server,p是port):

pc101: iperf3 -s -p 12345

在102机器上设置客户端,并从服务端收取数据(c是client,后接对接服务端的ip。R代表反向,即从服务端接收数据,不加-R选项则是客户端往服务端发数据。i是interval,代表发送间隔,t是time,代表测试时长):

pc102: iperf3 -c 192.168.1.101 -p 12345 -R -i 1 -t 3

可以发现从192.168.1.101的12345端口发出的包被限流到10mbps了。iperf3不能设置client的端口,所以这里用了-R来间接完成从12345端口发包。

当然也可以把12345端口设为目的端口,即之前tc的filter的条件设为(将sport改成dport,还是在101机器上设置,记得先用tc filter delete删掉原有条件):

pc101: sudo tc filter add dev enp8s0 protocol ip parent 1:0 prio 1 u32 match ip dport 12345 0xffff flowid 1:2

不过这时候反过来,让102机器作为服务端,并设置端口为12345。

pc102: iperf3 -s -p 12345

然后用101机器作为客户端发送数据到服务端,测试带宽(不用带-R选项了!):

pc101: iperf3 -c 192.168.1.102 -p 12345 -i 1 -t 3

可以发现发包带宽也是被限制在10mbps左右(肯定是会有波动的,但会在10mbps附近一个小范围内)。

不管是哪种方式,tc限流最终都是落在发包上。

在一台机器上做tc限流
跟之前提到的具体操作几乎没有任何区别,只需要把设备名从enp8s0改成lo即可,因为本地端口之间的通信走的都是lo回环。

设置完tc规则和filter条件后,用两个终端或者tmux开启多窗口的方式来用iperf3分别开服务端和客户端。

后续操作和原理与之前在两台机器上的完全一致,就不多说了。

查看网卡的规则
再给一些查看网卡规则的指令,有时候也可以确认规则是否生效,以及流量是否被分配到某一个子类规则队列中,流量和包数有多少等等。

简单查看(设备可以换成lo等等,查看的除了qdisc也可以换成class,filter等):

tc qdisc ls dev enp8s0

详细查看(还可以看class的流量和包数等):

tc -s qdisc ls dev enp8s0

其他-利用iptables完成相同工作
也可以用iptables完成分发,前面步骤还是一样的,只有最后的filter不太一样(这里的handle 10以及后续的参数指的是将标志为10的包分发给classid为1:2的flow):

tc filter add dev enp8s0 parent 1:0 protocol ip prio 1 handle 10 fw classid 1:2

然后用iptables对指定端口的包设置特殊的标志,完成端口绑定tc队列(只要保证--set-mark的值和handle的值一致就可以了)。

iptables -A OUTPUT -t mangle -p tcp --sport 12345 -j MARK --set-mark 10

由于这些规则还是基于本机的tc设置的,因此控制的还是发包(sport指定的是本机发包的source端口,即使改成dport也是这个包发往的目的端口号)。

参考资料
tc控制端口带宽
tc高级控流demo
tc参数/manpage

 

标签:enp8s0,ip,端口,带宽,网卡,12345,tc
From: https://www.cnblogs.com/exmyth/p/17459136.html

相关文章

  • leetcode-图论总结
    此文总结一下常见图论算法,代码可以为后续遇见类似题目提供参考:1.图的表示:邻接矩阵:可通过创建数组得到邻接表:我个人喜欢通过LinkedList<int[]>[]graph=newLinkedList[n];得到。EdgeList:同样可以通过LinkedList<int[]>[]graph=newLinkedList[n];得到。2.图遍历:DF......
  • 【网络基础】用了 TCP 协议,数据一定不会丢吗?
    1  前言TCP是一个可靠的传输协议,那它一定能保证数据不丢失吗?这次,就跟大家探讨这个问题。2  数据包的发送流程首先,我们两个手机的绿皮聊天软件客户端,要通信,中间会通过它们家服务器。大概长这样。但为了简化模型,我们把中间的服务器给省略掉,假设这是个端到端的通信。且为了......
  • 手把手教你AspNetCore WebApi:Swagger(Api文档)
    前言小明已经实现“待办事项”的增删改查,并美滋滋向负责前端的小红介绍Api接口,小红很忙,暂时没有时间听小明介绍,希望小明能给个Api文档。对于码农小明来说能不写文档就尽量不要写,不过这也难不倒小明,他知道Swagger不仅可以自动生成Api文档,并还可以用Swagger进行接口测试。Swagger是什......
  • 手把手教你AspNetCore WebApi:数据验证
    前言小明最近又遇到麻烦了,小红希望对接接口传送的数据进行验证,既然是小红要求,那小明说什么都得满足呀,这还不简单嘛。传统验证[HttpPost]publicasyncTask<ActionResult<Todo>>PostTodo(Todotodo){if(string.IsNullOrEmpty(todo.Name)){returnOk("名称不......
  • 手把手教你AspNetCore WebApi:Serilog(日志)
    前言小明目前已经把“待办事项”功能实现了,API文档也搞定了,但是马老板说过,绝对不能让没有任何监控的项目上线的。Serilog是什么?在.NET使用日志框架第一时间会想到NLog或是Log4Net,Serilog是这几年快速崛起的Log框架之一,Serilog是以Structuredlogging为基础进行设计,透过loggingAP......
  • 手把手教你AspNetCore WebApi:缓存(MemoryCache和Redis)
    前言这几天小明又有烦恼了,系统上线一段时间后,系统性能出现了问题,马老板很生气,叫小明一定要解决这个问题。性能问题一般用什么来解决呢?小明第一时间想到了缓存。什么是缓存缓存是实际工作中非常常用的一种提高性能的方法。缓存可以减少生成内容所需的工作,从而显著提高应用程序的性能......
  • 手把手教你AspNetCore WebApi:增删改查
    前言小明已经创建与运行了WebApi项目,了解项目结构有哪些组成,并学会了怎么发布到IIS。基础已经建好,从现在开始要真正实现待办事项的功能了。新建表CREATETABLE[dbo].[Todo]( [Id][uniqueidentifier]NOTNULL, [Name][nvarchar](100)NULL,CONSTRAINT[PK_Todo]PRIMARYKEY......
  • 手把手教你AspNetCore WebApi:认证与授权
    前言这几天小明又有烦恼了,之前给小红的接口没有做认证授权,直接裸奔在线上,被马老板发现后狠狠的骂了一顿,赶紧让小明把授权加上。赶紧Baidu一下,发现大家都在用JWT认证授权,这个倒是挺适合自己的。什么是TokenToken是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后......
  • Ubuntu系统开放指定端口
    今天在一台Ubuntu服务器里面配置了一个Nginx服务,监听的8080端口。本机可以访问,但是局域网就是访问不到。首先怀疑防火墙没有开放8080端口,设置ufw防火墙开放8080端口$sudoufwallow80然后局域网依然不能访问,接下来应该还要配置一下iptables,开放8080端口$sudoiptables-IINPUT......
  • AtCoder Beginner Contest 281 Ex Alchemy
    洛谷传送门AtCoder传送门考虑设\(f_i\)为\(i\)的答案,那么:\[f_i=[x_i](1+x)^A\prod\limits_{j=2}^{i-1}(1+f_jx)\]这个东西其实是可以分治FFT的。具体地,设分治区间为\([l,r]\),要求一个\(r-l+1\)次多项式\(\prod\limits_{i=l}^r(1+f_ix)\)。......