• TC学习总结


      带宽管理:
      TC中规定描述带宽:
      mbps = 1024 kbps = 1024 * 1024 bps => byte/s
      mbit = 1024 kbit => kilo bit/s
      mb = 1024 kb = 1024 * 1024 b =>byte
      mbit = 1024kbit => kilo bit.
      默认: 数字使用bps和 b方式存储.

    无类队列规则: 它能够接受数据和重新编排、延时或丢弃数据包,默认使用pfifo_fast队列规则.

    pfifo_fast:
      特点: 对任何数据包都使用FIFO(先进先出)队列,来存放入队。但它有3个所谓的"频道",对
        每一个频道都使用FIFO规则,内核会优先将TCP的TOS标志位(“最小延迟”)置位的数据包
        放入0频道,其它的放入1和2频道中,当然这是默认行为. 三个频道按照0,1,2的顺序,依次
        等待处理,即0频道有数据包等待发送,1频道的包就不会发送,若1频道有包等待发送,则
        2频道的包将不会被发送。
      

      txqueuelen
        #关于网卡设备的缓冲队列长度,可通过ip 或 ifconfig来修改.
        ifconfig eth0 txqueuelen 10

      priomap:
        内核对会根据数据包的优先权将其对应到不同的频道.
        TCP报文中TOS字段如下:

          

        TOS值的含义 和 其对应的频道:

          

        对于以下服务推荐TOS设置:

          

      TBF(令牌桶过滤器):
        TBF是一个简单队列,它只允许数据包按照事先设定的速率通过,支持设置峰值流量,它很精确,
        且对网络和处理器的影响较小,因此比较常用.
      TBF的原理:
        它实现了一个缓冲器(即令牌桶),在这个桶里面会不断以特定速率往里面填充“令牌",token rate
          (令牌速率)是令牌桶比较重要的参数,它是桶的大小,也就是能存储令牌的数量.
        如:
        rate 200kbps:   它指 令牌桶最多存储200kbit个令牌,一个令牌1bit, 因为要通过1bit的数据,
              就需要一个令牌,因此发送速率若为200k bit每秒,则桶里面始终会有令牌,若超过
              则没有可用令牌,就会产生丢包,这也就是TBF对流量整型的过程; 若低于此速率
              则令牌桶可能会被装满,多余的令牌将丢失。
              另外它也隐含说明了,缓存队列的长度,即它最多能缓存多少bit的数据.
              理解: 因为令牌的产生是按照系统的时间解析度来产生的,系统时间解析度指
               多久为1个时间单位 或 多少HZ(赫兹)一个时间单位, 假如10ms为一个时间单位,
               那就是每隔10毫秒系统会生产一个令牌放到令牌桶中。
               假如在初始时 桶中当前只有1个令牌,按照200kbit/s的速率, 第一个bit进入,桶中
              有令牌取走,该bit通过,接下来的bit,就要等10ms(一个时间单位)后,才能得到下一个
              令牌,而第二个bit在等待时,第三个bit已经到了,依次类推,缓存队列最多能存200kbit
              数据,若超过了,后续的数据就丢失了,若不超过设定速率,这个队列始终不会被填满.

      TBF可用参数:
        limit 和 latency:
        limit: 允许最多有多少数据(字节数)在队列中等待可用令牌。
        latency: 设定一个数据包在缓存队列中等待发送的最长等待时间,若设置它,就相当于
          决定了桶的大小、速率和峰值速率,因为数据包大小范围:64~MTU kbit 。

        burst/buffer/maxburst:
          设置最多一次允许多少个令牌能被立即使用,即峰值速率。
        buffer: 设置令牌桶的大小,通常是管理的带宽越大,buffer就需要的越大.

        mpu: Minimum Packet Unit:最小分组单位, 它决定了令牌的最低消耗。
        rate:设置速率(缺省不限速)
        peakrate:设置峰值速率,即: 一个包通过后,下一个包要等多久才允许通过.
          如: Unix的时间解析度是10ms(2004年左右的参考值), 若平均包长为10kbit,
            则峰值速率最大为1Mbps,即 1秒=1000ms, 按10ms的解析度, 即100个
            时间单位,每个时间单位发送10kbit,就是100 X 10kbit = 1Mbps.
        mtu/minburst:
          mtu: 峰值速率 = mtu X 时间解析度.

          例:
            tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540

      SFQ(Stochastic Fairness Queueing:随机公平队列):
        SFQ的精确度不如上面的算法,但它确能以很小的计算量,实现较高的公平数据发送。
        SFQ实现的公平是随机的, 因为它是针对一个TCP会话或UDP流,将它们通过散列的
        方式平均分配到有限的几个FIFO队列中,所以它们实际上是共享发包机会的,但为了
        让尽量公平,SFQ会每隔指定时间改变一次散列算法,以便让这种机制能让所有包都
        在几秒内发送出去。
       注:
        SFQ仅在网卡确实已经被挤满时,才会生效, 来创建队列并散列TCP或UDP数据包到不同
        队列中,进行公平调度。

      SFQ可用参数:
        perturb: 每隔多久改变一次散列算法,10秒是比较合适的值.
        quantum: 设置一个流至少传输多少字节后,切换到下一个队列中发送其中的数据包。
            建议使用默认值,即最大包长度(MTU). 此值不能设置数值小于MTU!!

        例:
        # tc qdisc add dev ppp0 root sfq perturb 10
        # tc -s -d qdisc ls
         qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec
         Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)
        注:
          “ 800c:”这个号码是系统自动分配的句柄号
          “ limit”: 是这个队列中可以有 128 个数据包排队等待。
          “flows 128/1024”: 一共可以有 1024 个散列目标可以用于速率审计,
                  而其中 128 个可以同时激活。
          perturb 10: 每隔 10 秒散列算法更换一次。

      以上队列何时使用最合适:
        1. 仅想限速,使用令牌桶过滤器(TBF):调整桶的配置后可用于控制很高的带宽。
        2. 若链路已被塞满, 使用SFQ,可避免某一会话独占出口带宽.
        3. 若你仅想看看网卡是否有较高的负载,可使用pfifo,而非pfifo_fast,因为pfifo内部
          频道可进行backlog统计。
        4.最后记住: 技术不能解决一切问题,社交还是需要的!

        TC的实现流量控制的大致框架流程如下:

        

       注:
        图中Ingress处就根据策略避免超过规定的数据包进入内核,这样可以
        减少CPU处理时间。 若数据包顺利进入内核,若它是进入本地进程的,
        就转给IP协议栈, 否则就交给egress分类器. 经过审查后,最终被放入
        若干队列规定中进行排队,此过程叫入队。如不进行任何配置,默认
        只有一个egress队列规定,即pfifo_fast. 当数据包入队后,等待内核处理
        并通过某网卡发出,这过程叫出队。

      队列规定: 即管理设备输入(ingress)或输出(egress)的算法.根据否能包含子类,
          它被分为无类和分类两种:
          无类队列规定: 一个内部不包含可配置子类的队列规定.
          分类队列规定: 一个分类的队列规定内可包含更多class(类),其中每个子类又
                进一步地包含一个分类 或 无类的队列规定。

      整形(策略):在数据包被发送前,跟据设定进行适当延迟,避免超过设定的最大速率.
          通常采用丢包来实现, 因为TCP的滑动窗口机制可以根据丢包来自动调整
          其发送数据包的速率,而UDP只能通过丢包来限制其速率。
        Work-Conserving: 对于work-conserving队列规定,若得到一个数据包,就立刻
          发送。即:只要网卡(egress队列规定)允许,它就不会延迟数据包发送.
      non-Work-Conserving: 有些队列,如TBF(令牌桶过滤器),可能需要暂时停止发包,
          以实现限制带宽,也就是说它们有时即时有数据包需要处理,也可能拒绝发送.

      过滤器: 对流量进行分类,如:网页流量,视频流量,游戏流量等进行过滤条件匹配,
        匹配出来后,交给分类器处理。
      分类器: 分类器可将不同的流量分发给 分类队列规定 中不同的子类来处理。 

    TC的队列规定家族:
      root, 句柄(handle), 兄弟节点 和 父节点

        

       注:
        句柄(handle): 节点引用标识,它的格式: MajorNumber:MinorNumber,其中父节点的次号码始终为0.
            root节点的handle为1:0(可简写为:"1:"), 它有一个子节点 1:1
            1:1这个子队列规定有两个父级的子队列规定分别是 10: 和 11:
            内核 仅和root qdisc 进行通信, 与物理网卡的通信也是有root qdisc来完成的,它们对应整体
            的队列规定家族是透明的,所有对外的接口只有root qdisc一个。
        在队列规定内部(我的理解如下):
          当内核发来入队请求时, root qdisc 会先调用过滤器来匹配数据包,若没有匹配就直接由分类器
            将其下发至子队列规定,它也是先过滤器匹配,然后分类器分发,假如过滤器发现数据包为游戏流量
         就将其送入11: 这个父级的子队列规定,接着11: 过滤器继续判断,发现是boos的游戏流量,就将其
            分发到11:1,在继续到11:1的过滤器,然后是分类器,完后入队等待发送。
          当内核发来出队请求时,root qdisc会向1:1发查询,1:1会分别向10: 和 11:发查询,接着10:会向
            其下的10:1 和 10:2发查询,直到11:1发现了要出队的数据包,它将数据包出队发给root qdisc,接着
         在内核的指引下,root qdisc将数据包发给网卡。【注: 出队要遍历全队列,所以队列不要太多哦~】


      队列规定:
        PRIO:它不对流量进行整形,它仅根据配置的过滤器将流量细分到不同的类中,若需要对流量进行整形处理,
          可以在这些子类中包含相应的队列,由它们来做整形。默认PRIO队列规定包含3个类,每个类下面包含
          一个FIFO队列。

         PRIO可以参数:
        bands : 指定创建的频道个数,一个频道就是一个类, 默认是3个频道.
        priomap: 为PRIO队列规定绑定一个过滤器,默认:根据TOS字段来匹配分类规则与pfifo_fast根据TOS
          字段分类一样。

        例:
         创建如下树:

          

             命令:
           #这个命令创建了三个类,1:1, 1:2, 1:3,因为默认bands为3.
              tc qdisc add dev eth0 root handle 1: prio
          #为第一个子类1:1创建了一个父级子类10:, 并制定内部队列为SFQ(随机公平队列)
              tc qdisc add dev eth0 parent 1:1 handle 10: sfq 
            

             tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000
             tc qdisc add dev eth0 parent 1:3 handle 30: sfq

               tc -s qdisc ls dev eth0
            qdisc sfq 30: quantum 1514b
            Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
            qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
            Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
            qdisc sfq 10: quantum 1514b
            Sent 132 bytes 2 pkts (dropped 0, overlimits 0)
            qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
            Sent 174 bytes 3 pkts (dropped 0, overlimits 0)

        测试:
        1. 尝试使用scp 复制文件到其它主机. 然后查看 队列统计信息。
        2. 书中说 10: 它的优先权最高,交互流量会优先选它, 30:的优先权最低,大量数据流量会优先走它.
            需要测试参考 TOS 标志位含义。

      CBQ(Class Based Queueing:基于类的队列):
        CBQ是根据链路平均空闲时间,来判断链路负载是否需要进行管制(即:整形),它有三种情况:
          avgidle = 0 : 则说明当前连路负载最佳,数据包能够精确按照预计时间间隔到达.
          avgidle < 0 : 则说明当前链路过载了, 若负值逐渐增大,则说明负载超限(Overlimit),
              CBQ将启动整形,开始丢包以禁止发包,禁止发包时长为 超限前计算
              出来的数据包平均发送间隔。
          avgidle > 0 : 则说明当前链路太空闲了, 若空闲超过几个小时,若此时有流量过来,CBQ
              将允许无限制的流量转发, 但这通常不是我期望的,因此需要设置maxidle,
              来限制avgidle的值不能太大.
          avgidle = 两个数据包平均发送间隔时长 减去 EWMA
              EWMA:Exponential Weighted Moving Average:指数加权移动均值,此算法是根据最近
                处理的数据包的权值比以前的数据包按指数增加。 【算法具体含义不清楚】
          简单理解: 最近数据包权值 = 前一个数据包权值^n+1
          另注: UNIX 的平均负载也是这样算出来的

      CBQ整形的参数:
        avpkt: 平均数据包大小,单位:字节. 它是计算maxidle的参数, maxidle从maxburst得出.
        band 物理网卡的带宽, 用于计算链路空闲时间.
        cell: 它用于设置时间解析度(即:时间精度), 通常设为8,它必须是2的整数次幂。
        maxburst: 最大突发数据包的个数(原文: 在avgidle=0前,可允许有maxburst个数据包突发传输出去。)
            此值决定了maxidle计算使用的数据包个数【不是很理解】.
        minburst: 它是设置超限后CBQ进入禁止发包延时状态后,根据之前计算的空闲时间延迟值,
            结合系统调度处理程序离开CPU到下次调度它到CPU上执行的间隔,来适当设置禁止发包的
            时长,当处理程序调度到CPU上执行时,一次突发传输 minburst 个数据包.
            注: 大尺度时间上, minburst值越大,整形越精确;
             从毫秒级时间尺度上,就会有更多突发传输.
               禁止发包的等待时间叫: offtime
          minidle: 当avgidle < 0,发送越限后,CBQ进入禁止发包的等待状态,但为了避免解禁后,再次
            出现突发传输,导致avgidle超限更多,负值越大,导致更长的禁止状态,所以需要设置
            一个 minidle 来限制负值无限增大.
            注: minidle 10 : 表示avgidle被限制其越限最大值为 -10us (负10微秒)
          mpu: 数据包的最小大小.用于CBQ精确计算链路空闲时间
          rate: 预期想限制的最大传输速率.

        CBQ在数据包分类方面的参数:
          注: 这些参数是控制那些队列要参与计算,如:已知该队列中无数据包,就不让其参与调度计算,
            及那些队列要被惩罚性的降低优先级等。
          CBQ使用prio参数来设定每个类的优先级,值越小越优先; 数据包出队是按照WRR(Weighted
            Round Robin:加权轮询) 对root qdisc下每个子类进行轮询,优先级高的子类先被调度,从
            该子类中的队列中取数据,接着是次高的,直到全部子类遍历一遍,当然对于没有数据的
            子类将自动跳过. 每次从子类中取多少数据是根据 allot * weight 来决定的。

      WRR的相关参数:
        prio: 设置类的优先级,值越小越优先.
        allot: 设置一次发送多少数据量.
        weight: 允许多发多少数据的权重数(注: 建议weight=rate/10);假如有如下图:

          

       注:
        对于这个图, 1:0这个根类下有两个子类1:1和1:2, 1:1的prio值更小,因此它
        更优先被WRR调度;
          一级子类1:1它的发送数据的权重=0.2+0.5
          一级子类1:2它的发送数据的权重=0.3
          而对于1:1的子类来说:
           二级1:1发送数据的权重=0.2
             二级1:2发送数据的权重=0.5
             而2:1与此一样.

      CBQ兄弟类之间是否可以互相借用带宽:
        isolated / sharing:
        isolated: 不会和兄弟类出借暂时多余的带宽。
        sharing: 允许借用暂时多余的带宽.
        bounded / borrow:
        bounded: 不允许借
        borrow: 允许借

       例:
        这个配置把 WEB 服务器的流量控制为 5Mbps、 SMTP 流量控制在 3Mbps , 而且
        二者一共不得超过 6Mbps,互相之间允许借用带宽。我们的网卡是 100Mbps的。
        # tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8
        # tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit
          rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
        注:
            子类1:1物理网卡的最大带宽为100Mbit,设置最大速率为6Mbit,允许发送数据量的权重为0.6Mbit.
           一次发送数据量为1514(单位:不清楚),允许的最大突发20个数据包,平均包大小为1000字节,时间解析度为8,
           不借出带宽给兄弟节点,本例子类1:1没有同级兄弟节点,因此设置或不设置一样.

       # tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit
        rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000
         # tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit
        rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000
          注:
          在子类1:1下有两个子类,它们是可以互相借用空闲带宽的,但他俩最大能使用的总带宽是6Mbit.
        Web能占用的带宽 = 6 X (0.5/(0.5+0.3)) Mbps
        SMTP能占用的带宽 = 6 X (0.3/(0.5+0.3)) Mbps

      # tc qdisc add dev eth0 parent 1:3 handle 30: sfq
      # tc qdisc add dev eth0 parent 1:4 handle 40: sfq

      # tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 80 0xffff flowid 1:3
      # tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 25 0xffff flowid 1:4
      注:
           这是添加了两个过滤器,用于匹配Web和SMTP的流量,并将它们分别送入1:3和1:4中.
      对于没有匹配到的流量,1:0 即root队列规定将直接处理,它采用FIFO队列,不限制直接转发.

      注: 以上命令创建的结构如下图:

        

      
      CBQ的过滤器选项:
        split节点: 当你需要使用CBQ自带的过滤器 defmap时,定义defmap的类的父类就称为split节点.
        defmap: 它是通过与TCP的TOS(服务类型标志位) 做或运算来匹配特定TOS置位的数据包,并将
          这些数据包接入到匹配类中. 0:表示不匹配.

          例:
        # 1:1就是split节点
        # tc qdisc add dev eth1 root handle 1: cbq bandwidth 10Mbit allot 1514 cell 8 avpkt 1000 mpu 64
        # tc class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit
          rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 avpkt 1000

        # c0: 1100 0000, 它是匹配TOS的第7和6位,即交互和控制位 置位的数据包.
        # tc class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit
         rate 1Mbit allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 avpkt 1000 split 1:0 defmap c0

        # 3f:0011 1111, 它是匹配TOS的1~5位,也就是将剩余的所有数据包都匹配到本子类中.
        # tc class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit
         rate 8Mbit allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 avpkt 1000 split 1:0 defmap 3f

        root节点1:0接收到的数据包将被分配到1:3 和 1:2子类中的情况为:

          

          补充:
          # tc class change dev eth1 classid 1:2 cbq defmap 01/01
          # 这个change 可以给defmap提供一个mask(掩码),但是暂时不理解它是什么意思.
          # 这是原作者提供的 经过掩码计算后, 优先权值的变化:

          

        HTB(Hierarchical Token Bucket : 分层令牌桶)
       有一个固定速率的链路,希望分割给多种不同的用途使用,为每种用途做出带宽承诺并实现定量的带宽借用,
       这时你就需要使用HTB队列规则了,它配置相比于CBQ简单.

      HTB参数解释:
        rate: 设定期望的最大限制速率.
        burst: 设置突发流量在现有基础上,可以增大多少.
        ceil: 设置速率最高可达到多少. 此参数表明该子类可借用其兄弟类的空闲带宽。

        # tc qdisc add dev eth0 root handle 1: htb default 30
          注:
          default 30: 表明若过滤器没有匹配到的流量都将被分配到root qdisc的1:30这个子类中.
        # tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k
        # tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k
          注:
          1:10这个子类,它的最大速率为5Mbps,它不可用借用其兄弟类的带宽.
          但下面两个设置ceil ,表明它们可借用兄弟类空闲带宽,最大速率可达到6Mbps.
        # tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k
        # tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k

        # tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
        # tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
        # tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
        注:
        perturb: 设定SFQ(随机公平队列)每隔10秒更新一次随机散列算法,以便入队数据包有机会被排在前面,
            最终达到它们都能在可接受的时间内被发送.

      添加过滤器,直接把流量导向相应的类:
        # U32="tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32"
        # $U32 match ip dport 80 0xffff flowid 1:10
        # $U32 match ip sport 25 0xffff flowid 1:20

        以上命令创建的TC结构图:

          

         TC过滤器创建:
        # tc filter add dev 网卡名  parent  父类句柄  protocol  ip  prio   优先级值   u32
          [match [ip [[src |dst [IPAddr/CIDR Mask]] [sport |dport 端口号 Mask] | protocol 协议号 Mask]] |
          handle FirewallMark fw]
          flowid 前面父类的子类句柄
          注:
           protocol: 支持/etc/protocols中定义的协议号.

      创建基于端口的过滤器:
        # tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip dport 22 0xffff flowid 10:1
        # tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip sport 80 0xffff flowid 10:1
          注:
           上面两个是精确匹配80, 即: 80和0xffff或运算的值 必须与 目标端口 匹配.
             u32: 是一种根据协议内容做数据提取,与指定参数做匹配的参数.
        # tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2 #默认所有流量都匹配.

      创建基于地址的过滤器:
        # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip dst 4.3.2.1/32 flowid 10:1
        # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 1.2.3.4/32 flowid 10:1
        注:
            IP/32: 这是精确匹配主机IP. 若需要匹配网络地址,可使用指定CIDR值,如:192.168.0.0/24
        # tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2

      基于源地址 和 源端口的过滤器:
        # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 4.3.2.1/32 match ip sport 80 0xffff flowid 10:1

      基于协议号的过滤器:
        # tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip protocol 1 0xff flowid 10:1

      基于防火墙标记的过滤器:
        # tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1
        # iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6

      基于TOS字段的过滤器:
        # tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:4

      高级过滤器:
        基于路由的过滤器:
        目的地址匹配:
        # ip route add 192.168.10.0/24 via 192.168.10.1 dev eth1 realm 10
        注:
         realm :用于定义一个realm号码,用于表示网络或主机路由.
        # tc filter add dev eth1 parent 1:0 protocol ip prio 100 route to 10 classid 1:10
         注:
          此命令定义节点 1:0 里添加了一个优先级是 100 的路由过滤器(或加分类器),
          当来自192.168.10.0/24网络的数据包到达这个节点时,就会查询路由表,
          若它要从eth1接口被路由出去,则匹配此路由,进而被发送到类1:10,并赋予优先级值为 100。

      源地址匹配:
        # ip route add 192.168.2.0/24 dev eth2 realm 2
        # tc filter add dev eth1 parent 1:0 protocol ip prio 100 route from 2 classid 1:2
         注:
          若匹配到从192.168.2.0/24网络过来的数据包,则将其送到1:2节点,并赋予优先级值为100.


      管理大量过滤器:
        注: 不建议使用,若真的有这类需求,可尝试使用ipset 和 mark结合
          当你需要管理大量过滤器时,为了避免大量过滤器对每一个数据包都做匹配,带来严重的系统性能问题,
          这里提供一种通过散列表来构建 多个链表,每个链表中仅有几条规则过滤器,以便高效匹配过滤器.
          下面的例子是对IP做散列表的示例:
            假如说你有 1024 个用户使用一个 Cable MODEM,IP 地址范围是 1.2.0.0 到 1.2.3.255,
            每个 IP 都需要不同过滤器来对待,最佳的做法如下:
          

          1. 首先创建一个root过滤器
           # tc filter add dev eth1 parent 1:0 prio 5 protocol ip u32

          2. 然后构建出一个256项的散列表
           # tc filter add dev eth1 parent 1:0 prio 5 handle 2: protocol ip u32 divisor 256

          3.然后我们向表项中添加一些规则:利用IP地址的后半段做为
             # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: match ip src 1.2.0.123 flowid 1:1
             # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: match ip src 1.2.1.123 flowid 1:2
             # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: match ip src 1.2.3.123 flowid 1:3
             # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 2:7b: match ip src 1.2.4.123 flowid 1:2
            注:
            这是第 123 项,包含了为 1.2.0.123、1.2.1.123、1.2.2.123 和 1.2.3.123 准备的匹配
            规则,分别把它们发给 1:1、1:2、1:3 和 1:2。注意,我们必须用 16 进制来表示
            散列表项,0x7b 就是 123

            4.然后创建一个“散列过滤器”,直接把数据包发给散列表中的合适表项:
          # tc filter add dev eth1 protocol ip parent 1:0 prio 5 u32 ht 800::
            match ip src 1.2.0.0/16
            hashkey mask 0x000000ff at 12
            link 2:
          注:
           “800::” 这表示创建一个散列表,所有的过滤都将从这里开始.
           at 12: 表示从IP头的第12位开始匹配 mask的长度, IP头的第12~15字节为源IP地址位.
           ”link 2:“ 表示匹配后,发送数据包发送到前面创建的第2个散列表项,即: 2:


      IMQ(Intermediate queueing device: 中介队列设备)
        若需要使用IMQ,需要对内核,netfilter,iptables打补丁后才能使用:
          https://blog.csdn.net/dayancn/article/details/45871523
        这篇文章详细讲解了如何给Linux-kernel2.6.18的内核打上IMQ补丁的详细步骤.
        在Linux中由于队列规定只能附加到网卡上,因此有两个局限:
        1. 虽可在入口做队列规定,但在上面实现分类队列规定可能性很小,所以相当于只支持出口整形.
        2. 一个队列规定只能处理一个网卡流量,无法全局限速.
        IMQ就是为解决这两个问题而诞生的,简单说: 你可往一个队列规定中放任何方向的流量, 我们可通过
        iptables将打了特定标记的数据包在netfilter的NF_IP_PRE_ROUTING和NF_IP_POST_ROUTING两个
        钩子函数处被拦截,并被送到附加在IMQ虚拟网卡上的队列规定中, 这样你就可对进入刚进入网卡的
        数据包打上标记做入口整形,或把所有网卡当成一个个类来对待,做全局整形控制。

  • 相关阅读:
    2018.5.17 memcached
    2018.5.11 B树总结
    2018.5.8 排序总结
    2018.5.8 python操纵sqlite数据库
    2018.5.4 Unix的五种IO模型
    2018.5.3 maven
    2018.5.3 docker
    Mybatis学习笔记,挺全的!
    这么强大的Mybatis插件机制原来就是这?
    Swagger API Spec + Swagger Codegen + YAPI管理接口文档
  • 原文地址:https://www.cnblogs.com/wn1m/p/10919797.html
Copyright © 2020-2023  润新知