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得出.
                        bandwidth: 物理网卡的带宽, 用于计算链路空闲时间.
                        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虚拟网卡上的队列规定中, 这样你就可对进入刚进入网卡的
                       数据包打上标记做入口整形,或把所有网卡当成一个个类来对待,做全局整形控制。
TC学习总结的更多相关文章
- 虚拟化原理到K8s实践经验路线总结
		
以下这些内容均为自行学习总结的内容,很多内容没有写概括介绍,看起来可能会有些突兀,但并不影响整体性,我自己的学习经验告诉我,这些内容还仅仅是最精简的核心部分,周边还有很多可扩展内容,主要是操作系统生态 ...
 - Linux学习日记-使用EF6 Code First(四)
		
一.在linux上使用EF 开发环境 VS2013+mono 3.10.0 +EF 6.1.0 先检测一下EF是不是6的 如果不是 请参阅 Linux学习日记-EF6的安装升级(三) 由于我的数据库 ...
 - HTML5移动开发学习笔记之CSS3基础学习
		
CSS回顾 在学CSS3之前首先巩固下CSS的基础知识. 1.CSS框模型 举例子: #box { width: 70px; margin: 10px; padding: 5px; } 这个代码将出现 ...
 - knockout学习笔记10:demo
		
前面已经介绍了ko的基本用法,结合官方文档,基本就可以实际应用了.本章作为ko学习的最后一篇,实现一个简单的demo.主要集中在ko,所以后台数据都是静态的.类似于博园,有一个个人文章的分类列表,一个 ...
 - 【HTML5&CSS3进阶学习02】Header的实现·CSS中的布局
		
前言 我们在手机上布局一般是这个样子的: 其中头部对整个mobile的设计至关重要,而且坑也很多: ① 一般来说整个header是以fixed布局,fixed这个产物在移动端来说本身坑就非常多 ② 在 ...
 - Python爬虫学习(10):Selenium的好基友PhantomJS
		
上一节中我们学习了selenium,用python来操作浏览器,在做网页自动化测试的时候最好不过了 .如果我们来做爬虫用一个带界面的浏览器似乎不太好吧,那可咋办呢?别着急,下来我们要介绍的就是一款不带 ...
 - Android学习——windows下搭建Cygwin环境
		
在上一篇博文<Android学习——windows下搭建NDK_r9环境>中,我们详细的讲解了在windows下进行Android NDK开发环境的配置,我们也讲到了在NDk r7以后,我 ...
 - Android学习——windows下搭建NDK_r9环境
		
1. NDK(Native Development Kit) 1.1 NDK简介 Android NDK是一套允许开发人员使用本地代码(如C/C++)进行Android APP功能开发的工具,通过这个 ...
 - Java学习笔记(04)
		
Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...
 
随机推荐
- HBase协处理器同步二级索引到Solr(续)
			
一. 已知的问题和不足二.解决思路三.代码3.1 读取config文件内容3.2 封装SolrServer的获取方式3.3 编写提交数据到Solr的代码3.4 拦截HBase的Put和Delete操作 ...
 - ios状态栏的一些操作
			
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES; //显示 [UIApplication sharedA ...
 - mysql优化-------Myisam与innodb引擎,索引文件的区别
			
Myisam与innodb引擎,索引文件的区别: innodb的次索引指向对主键的引用. myisam的次索引和主索引都指向物理行. myisam一行一行的插入,会产生一行一行的文件,磁盘上有数据文件 ...
 - PHP——巧用PHP函数array_merge()合并数组
			
前言 返回联系人列表,包含所有的字母,之前返回的是存在这个联系人才会返回对应的大写字母,后面更改了要求要返回所有的字母从A-Z.PHP内置的一些函数活用起来,真的很省劲! 步骤 一般这时候大家可能直接 ...
 - 设置Tomcat的jvm内存问题
			
tomcat的jvm大小设置与操作系统以及jdk有关:具体来说: 1.操作系统是32bit的,程序最大内存访问空间是4G, 2的32次方,这是硬件决定的,跟windows linux没有任何关系. 2 ...
 - Python机器视觉编程常用数据结构与示例
			
本文总结了使用Python进行机器视觉(图像处理)编程时常用的数据结构,主要包括以下内容: 数据结构 通用序列操作:索引(indexing).分片(slicing).加(adding).乘(multi ...
 - 【HDU 4819】Mosaic
			
[题目链接] 点击打开链接 [算法] 二维线段树(树套树) [代码] #include<bits/stdc++.h> using namespace std; #define MAXN 8 ...
 - Watir 能够为你做什么?
			
为了提高自己的工作效率,我曾经对Watir进行了系统性的学习,比起学习C++, Java等始终不得门,Watir还是学进去了,能够完整搭建出一个自己很容易理解的自动化架构. 之后我想继续在自动化测试方 ...
 - vs2008工程部署不成功,可能是远程文件路径出现问题
			
解决方法: 修改工程属性页的配置属性 调试中的远程可执行文件的路径 部署中的远程目录的路径
 - VS2008 视图资源.rc无法加载的问题及解决方法
			
VS2008 视图资源.rc无法加载 1.首先先把vs关闭,然后执行 开始>>所有程序>>Mircosoft visual studio 2008>>visual ...