包括 tc qdisc add dev eth0 root sfq的内核流程 sch_sfq.c文件分析 tbf的原理 sch_tbf.c的分析
桌面.rar
rogerhl 回复于:2006-11-13 14:32:18
看不太懂!
liuzhuan23 回复于:2006-11-13 15:12:42
谢谢 qtdszws,干的不错;
qtdszws 回复于:2006-11-13 15:42:07
其实我前段时间才真正开始研究网络。以前看过情景分析,把socket层基本搞清楚。往下是inet socket层,也不是很难。再往下就是传输层,TCP/UDP,虽然看过TCP/IP详解的一,二卷本,但仍一头雾水,看不懂(原因估计是太庞大,又盘根错节)。决定再从下往上。
先看了net/core/*.c,许多都看不同,但总算有了一些认识。然后看drivers/net/ne.c,loopback.c驱动,知道了驱动大概情况。
再往上就是qos了,也就是net/sched/*.c.从最简单的看起,sch_generic.c(其中有noop_disc,noqueue_qdisc,pfifo_fast_qdisc),sch_fifo.c。这些基本内容之后就看sch_sfq.c,sch_tbf.c,这两个稍微复杂一点,但是和别的东西独立(只是牵涉到af_netlink,sch_api.c),因此也比较容易理解.
再往后看了sch_prio.c,这是一个可分类的规则,很简单,但也很重要。因为能够分类(能够挂接其他队列规则),因此又涉及到分类器。于是从前天到昨天花了两天时间集中研究了u32分类器(cls_u32.c),这个分类器功能很强大,因此结构异常复杂。然后附带研究了一下fw分类器,这个分类器原理很简单。
分析的时候我同时进行试验,先在在virtual pc上,然后实战。我们学校的网关是我装的,redhat 7.2(2.4.7-10smp).以前照葫芦画瓢建了两个简单tc规则. tc qidsc add dev eth0 root sfq perturb 10 tc qidsc add dev eth1 root sfq perturb 10 eth0接外网,eth1接内网,iptables做nat和过滤包。
现在稍微懂了一些qos后,修改了一下规则 #!/bin/bash -x
for i in 0 1 do /sbin/tc qdisc del dev eth$i root /sbin/tc qdisc add dev eth$i handle 1: root prio bands 3 priomap 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 /sbin/tc qdisc add dev eth$i parent 1:1 sfq perturb 10 /sbin/tc qdisc add dev eth$i parent 1:2 sfq perturb 10 /sbin/tc qdisc add dev eth$i parent 1:3 sfq perturb 10 if [ $i -eq 0 ];then port="dport";addr="16";else port="sport";addr="12";fi /sbin/tc filter add dev eth$i parent 1: pref 10 protocol ip u32 match ip protocol 6 0xff match ip $port 80 0xffff flowid 1:1 /sbin/tc filter add dev eth$i parent 1: pref 10 protocol ip u32 match u32 0xaabbccdd 0xffffffe0 at $addr flowid 1:2 done
这样可以对校内的流量进行象样的qos了,保证http流量优先,其次是访问我们自己的公网服务器的流量,最后是其他流量,这些流量都是通过u32分类器进行分类.当然也可以使用fw分类器来完成这些任务。试验的时候有些命令不会用就看Linux的高级路由和流量控制HOWTO.pdf,然后在对照iproute2中tc的源代码,可以起到事半功倍的效果,而不是以前的抓瞎了(tc比较难用,有没有正规的手册)。
接下来我准备继续把其他的几个算法看完,包括cls_route,cls_tcindex,sch_red,sch_gred,sch_teql,sch_dsmask,sch_cbq(这个最麻烦了),sch_ingress.等等。
把这些看完就了后,往上到邻居子系统层(arp),再到ip层(包括路由子系统,netfilter子系统,icmp,igmp,ipip,等等),最后再猛攻UDP/TCP.
路还很长,但我有信心走下去。
[ 本帖最后由 qtdszws 于 2006-11-13 15:45 编辑 ]
qtdszws 回复于:2006-11-13 15:51:54
sch_prio队列规则的分析 cls_u332分类器的分析 cls_fw分类器的分析
桌面2.rar
liuzhuan23 回复于:2006-11-13 16:03:42
“试验的时候有些命令不会用就看Linux的高级路由和流量控制HOWTO.pdf,然后在对照iproute2中tc的源代码,可以起到事半功倍的效果“
呵呵,的确,有些时候看代码得到答案的速度会快一些,正如 Torvalds 所说:Use the Source, Luke!
独孤九贱 回复于:2006-11-14 09:17:50
引用:原帖由 qtdszws 于 2006-11-11 20:36 发表 包括 tc qdisc add dev eth0 root sfq的内核流程 sch_sfq.c文件分析 tbf的原理 sch_tbf.c的分析
要分析Linux 的QoS框架,明白内核的队列层是很重要的,楼主有没有这方面的资料??最近看这个,似懂非懂,呵呵!
qtdszws 回复于:2006-11-15 10:04:11
这方面的资料比较匮乏,我只有Linux的高级路由和流量控制HOWTO.pdf,其实源代码才是最宝贵的第一手资料(包括tc的)
修正发现的错误: 1.令牌桶过滤器的原理中 “如果令牌不够,数据需要等待一定的时间才被发送,这个时间是由latency参数控制。”这句话有误,这个时间不是由latency参数控制的,而是根据还需要多少令牌来计算延迟的时间,然后启动看门狗定时器。
2.u32分类器的数据结构的组织理解有误,修改过的文件在附件中
u32分类器比较复杂(非常容易写错),而fw却很简单(非常容易写),建议大家用fw.
tc filter add u32.rar
net_starter 回复于:2006-11-29 23:06:25
我需要
DanKnight 回复于:2006-11-30 16:50:10
学习了。我最近也在学linux内核编程, 写了一个大概,希望能坚持下去。
qtdszws 回复于:2006-12-14 15:07:26
关于sch_ingress.c
http://bbs./viewthread.php?tid=849145&highlight=qtdszws
使用ingress的内核处理流程 tc qdisc add dev eth0 handle ffff: ingress tc filter add dev eth0 parent ffff: pref 10 protocol ip u32
1.init_module->nf_register_hook 注册ingress的钩子到 static struct nf_hook_ops ing_ops = { { NULL, NULL}, ing_hook, PF_INET,// 2 NF_IP_PRE_ROUTING,//注册到PRE_ROUTING NF_IP_PRI_FILTER + 1 };
2.网卡接收到一个ip数据包后调用ip_input.c中的ip_rcv NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish) NF_HOOK定义如下 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) \ (list_empty(&nf_hooks[(pf)][(hook)]) \ (okfn)(skb) \ : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn))) 因此将调用nf_hook_slow,在core/netfilter.c中 nf_hook_slow->nf_iterate-> hook-> ing_hook(ingress的钩子函数)-> ingress_enqueue(入队)-> tc_classify(分类)
3.根据分类结果决定继续处理该包,还是丢弃(例如被管制器管制)
qtdszws 回复于:2006-12-14 16:02:50
sch_teql.c
teql原理
1.在Linux的高级路由和流量控制HOWTO.pdf有一些说明,可以参照
2.teql实现了一个简单的多网卡负载均衡.简单,是因为它不考虑实际的硬件情况,只是在关联的实际设备之间轮转转发包,即使是一个千兆网卡和MODEM被关联在一起.可以称做发包数负载均衡吧.
3.insmod sch_teql.o时, init_module会注册一个名为teql0的虚网络接口和一个名为teql0的队列规程,他们被集成在struct teql_master结构中,彼此分不开. 可以使用一下命令绑定实设备到队列规程teql0 tc qdisc add dev eth0 root teql0 tc qdisc add dev eth1 root teql0 然后用命令ip link set dev teql0 up激活虚设备teql0 这样一个teql设备就配置完成了 接下来可以再配置另一个teql设备 insmod –o sch_teql1 sch_teql.o 我这是RED HAT 7.2,由于已经加载了sch_teql.o模块,只能重命名加载了. 新版本内核已经实现一次insmod就可指定若干个teql tc qdisc add dev eth2 root teql1 tc qdisc add dev eth3 root teql1 ip link set dev teql1 up
4.当有数据包到达teql0时先进入自己的队列,缺省为pfifo_fast,然后内核就调用teql_master_xmit来在从设备中循环轮转选择一个设备eth*发包.如果teql*是该实设备的根队列规程,就直接调用eth*的hard_start_xmit函数发包.如果不是就选择下一个设备,只至成功或失败.而配置在该设备上的teql*规程,它的行为就类似于pfifo规程.这是给那些直接通过该设备发送的包准备的规程.
teql.rar
qtdszws 回复于:2006-12-14 18:03:02
sch_red.c random early detection 随机早期探测
参考http://www./floyd/papers/red/red.html 中的early.pdf
说明 1.qlen 为当前队列长度 2.qave 平均队列长度,它的计算公式是qave=qave*(1-W)+qlen*W,W为权重,W一般选得很小 ,这可以使突发包对qave不会产生太大波动 3.qmin,qmax 当qmin<=qave<=qmax时,开始随机标记/丢包,标记/丢包的概率为 max_P * (qave- qmin)/(qmax-qmin),,随着qave增长,概率逼近max_P 标记包是希望客户端知道目前网络已经开始拥挤,放慢发包速度吧 如果qave>=qmax,标记/丢弃所有的包 4.如果网络空闲了一段时间,就应该相应地减少qave的大小,qave=qave*(1-W)^m,m为空闲时间段长度
sch_red.rar
qtdszws 回复于:2006-12-15 09:30:50
路由分类器cls_route.c 路由分类器的原理很简单,就是在路由的时候由路由规则对数据包打标记.路由分类器就用这个标记来对数据包分类. 路由规则语法如下 ip route add Host/Network via Gateway dev Device realm RealmNumber 例 ip route add 192.168.10.0/24 via 192.168.10.1 dev eth1 realm 10 至于如何打标记,我现在还不了解 在设置了路由规则以后,就可以使用路由分类器分类数据了 tc filter add dev eth0 protocol ip prio 100 route to 10 classid :2 tc filter add dev eth0 protocol ip prio 100 route from 10 classid :1 路由分类器参考的参数有fromdev/from,to,fromdev和from互斥,只能使用其中一个,由他们在分类器的二层hash表中索引和查找.
资源预留协议分类器cls_rsvp.h 资源预留协议分类器的原理也很简单,就是用ip协议(也支持ipv6,此处不涉及)的目的地址,可能的目的端口,源地址,可能的源端口来索引和查找一个二层hash表. "可能的"意思是不一定使用,由用户决定.也就是它是基于session(会话)的. tc filter add dev eth0 pref 10 protocol ip rsvp ipproto tcp session 10.1.1.1/80 classid :1 这条规则的意思就是,到10.1.1.1:80的数据流分类到:1的队列 还可以加入sender,指定发送者,或者不指定端口,而指定一个GPI,也就是在offset处的值&mask==key方式更加灵活地指定一个匹配.
route_rsvp.rar
qtdszws 回复于:2006-12-15 10:11:05
sch_dsmark.c和cls_tcindex.c
diffserv是一个体系,需要一个有若干个路由和一定规模的网络来协作实现,就单个主机来说用处不大.在这个网络中,大家都遵守同样的diffserv协定,例如哪个dsfield的优先级高,哪个低,以及怎样处理等.
这里引入了域的概念,就是遵守某一diffserv协定的网络组成一个ds域.剩下的就是非ds域.一台域中的主机要发的包,可以在自己的出口队列分类,或在接入的路由上分类. 1.在本机分类,出口绑定dsmark队列规程和u32等分类器 2.在路由分类,路由入口绑定ingress队列规程和u32等分类器 注:上面的分类器一般不用tcindex分类器,因为是从非ds域到ds域的转换,而tcindex实用于使用已有ds field来分类流(见3)和不同ds域之间的转换,不同域之间的转换一般发生在入口上,例如上面的2,如果数据是从另外一个ds域来的话. 这样所有的流就被区分开了. 3.然后路由器就可以在自己的出口绑定dsmark队列规程(和一些内部队列,例如cbq)和tcindex分类器,让tcidnex分类来对不同级别的流(只根据ds field)进行整形和qos.
上面都是我的理解,化了我很长时间,不对之处,请大家指正.大家参考lartc上的说明. 下面的例子也是摘之lartc tc qdisc add dev eth0 handle 1:0 root dsmark indices 64 set_tc_index#绑定dsmark队列规程 tc filter add dev eth0 parent 1:0 protocol ip prio 1 tcindex mask 0xfc shift 2#建立tcindex分类器 tc qdisc add dev eth0 parent 1:0 handle 2:0 cbq bandwidth 10Mbit cell 8 avpkt 1000 mpu 64 # EF traffic class内部队列 tc class add dev eth0 parent 2:0 classid 2:1 cbq bandwidth 10Mbit rate 1500Kbit avpkt 1000 prio 1 bounded isolated allot 1514 weight 1 maxburst 10 # Packet fifo qdisc for EF traffic子类 tc qdisc add dev eth0 parent 2:1 pfifo limit 5 #子类的队列规程 tc filter add dev eth0 parent 1:0 protocol ip prio 1 handle 0x2e tcindex classid 2:1 pass_on #例子中是parent 2:0,我认为是parent 1:0,把EF流分类到2:1子类,不懂EF流是怎么回事,半桶水^_^
dsmark_tcindex.rar
qtdszws 回复于:2006-12-15 10:48:16
sch_gred.c Generic Random Early Detection
这个算法是在red的基础上扩展引入virtual queue的概念形成的. 在gred中最多可以引入16个vq,其中至少有一个缺省vq. 每个vq都基本按red算法来操作(有区别),但所有的这些vq都公用一个实际的队列 sch->q.
gred算法有四种模式,由参数eqp和grio控制(不知道是什么的缩写) (注意是否开始随机丢包由qave+q->qave<q->qth_min控制) eqp grio 0 0 每个vq一个独立red (qave=0),但共享一个实队列 0 1 每个vq和比它优先级高的vq构成一个部分相关red,保证优先级高的vq优先发包 qave+q->qave的值是按照相关的每个vq自己计算的ave的总和 1 0 每个vq一个部分相关red,和sch->backlog相关 (qave=0) q->qave的值是把sch->backlog按本vq的方式计算ave的值 1 1 每个vq一个全部相关red (qave=0) q->qave的值是把sch->backlog按本vq的方式计算ave的累计总和
我认为比较有用的是(0,0)(有点类似于sfq)和(0,1)(有点类似于prio) gred实际上和red一样都比较难配置,主要应用于路由器上 因为它是采用skb->tc_index来选择vq的,可以和dsmark规程和tcindex分类器协作
gred.rar
guotie 回复于:2006-12-15 12:56:17
楼主能不能整理一个all in one的包?
谢谢!
qtdszws 回复于:2006-12-15 14:32:16
不好意思,我也是一点点的分析的,不可能一下子给出所有的学习结果,等我把csz和cbq等看完后,会给出总结和all in one的包.
qtdszws 回复于:2006-12-16 11:52:35
estimator.c和police.c
-------------------------------------------------------------- estimator用于估计包的速度,包括bps(每秒字节数)和pps(每秒包数). estimator的调用独立于qos架构,每个estimator一个内核定时器,可以每1/4s,1/2s,1s,2s,4s,8s被调用一次,定时计算
它可以应用在队列规程上和分类器上. 1.在队列规程上,它把计算结果放在qdisc->stats中,到目前为止我还没有看到谁在使用这个结果,不过这可以让用户监视和评估该规程上的流量 2.在分类器上,在分类器的每个策略中都有一个tcf_police结构,估计结果就放入该结构的stats成员中.在策略被命中后,将调用tcf_police,如果使用了估计器,tc_police就根据估计结果决定通过该策略的数据流量是否超限,是的话就执行规定的动作,ok,drop,reclassify,unspec.
Usage: ... estimator INTERVAL TIME-CONST interval为定时间隔,time-const的计算方法是w=interval/time-const,w为加权比,例est 1s 8s,则定时间隔为1s,w=1/8=0.125
------------------------------------------------------------------ police用于分类器上,前面已经提到,策略被命中就会调用tcf_police,对通过该策略数据的进行管制
除了使用可选的estimator的结果进行管制以外,police主要使用tbf(令牌桶过滤器)对流进行管制操作.tbf的理论在前面已经叙述过了.tbf使用常规桶和峰值桶来控制流量.对于超限的包执行规定的动作.
Usage: ... police rate BPS burst BYTES[/BYTES] [ mtu BYTES[/BYTES] ] [ peakrate BPS ] [ avrate BPS ] [ ACTION ] Where: ACTION := reclassify | drop | continue avrate用于estimator,判断流量是否超限 lartc上有一个"防护SYN洪水攻击例子"用到police iptables -A PREROUTING -i $INDEV -t mangle -p tcp --syn -j MARK --set-mark 1 $TC qdisc add dev $INDEV handle ffff: ingress $TC filter add dev $INDEV parent ffff: protocol ip prio 50 handle 1 fw police rate 1kbit burst 40 mtu 9k drop flowid :1
lcl-cgy 回复于:2006-12-17 23:23:43
GOOD
fafeymao 回复于:2007-03-27 15:21:36
感谢楼主,你的资料给了我不少帮助,:lol: 继续加油:mrgreen:
funix_zjx 回复于:2007-04-01 23:48:34
推荐楼主看《OReilly.Understanding.Linux.Network.Internals》
kobefly 回复于:2007-04-06 11:22:43
感谢感谢, 非常感谢,
积极学习消化中
fengdream 回复于:2007-06-25 17:42:27
看不懂,先留名了。。。 向大虾学习。。。
honckly 回复于:2007-06-25 17:47:34
看不太懂 不过,能把个人心得共享出来,非常的感谢楼主。
flw2 回复于:2007-06-26 21:59:00
不错,还没看,这个东西太复杂了,加上对内核有不了解,也不知道代码能不能看懂点
wghuan 回复于:2007-08-17 17:52:31
谢谢!对我帮助很大
tent8 回复于:2007-08-20 15:26:40
最近在搞带宽控制 正需要....
sunny96 回复于:2008-05-04 23:07:52
最近用的Tc,非常感谢
|
|
|