资源描述:
《linux_qos实现框架分析》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、LinuxQOS实现框架分析作者:徐晓东(joyxxd@163.com)Linux中的QOS分为入口(Ingress)部分和出口(Egress)部分,入口部分主要用于进行入口流量限速(policing),出口部分的QOS用于队列调度(queuingscheduling)。以下分析所参考的linux内核版本为2.6.21。1.IngressQOSIngressQOS在内核的入口点有两个,但是不能同时启用,这取决于内核编译选项。当打开了CONFIG_NET_CLS_ACT时,入口点在src/net/core/dev.c的netif_receive
2、_skb函数中,代码片段如下:#ifdefCONFIG_NET_CLS_ACTif(pt_prev){ret=deliver_skb(skb,pt_prev,orig_dev);pt_prev=NULL;/*nooneelseshouldprocessthisafter*/}else{skb->tc_verd=SET_TC_OK2MUNGE(skb->tc_verd);}ret=ing_filter(skb);if(ret==TC_ACT_SHOT
3、
4、(ret==TC_ACT_STOLEN)){kfree_skb(skb);gotoout;}
5、skb->tc_verd=0;ncls:#endif进入ing_filter后,代码片段如下:if((q=dev->qdisc_ingress)!=NULL)result=q->enqueue(skb,q);我们可以看到,在这里判断了是否在设备上配置了ingress调度规则,如果配置了则调用其enqueue函数进行处理。在这里实际上调用的是src/net/core/sched/sch_ingress.c中的ingress_enqueue函数。当没有打开CONFIG_NET_CLS_ACT,而是打开了CONFIG_NET_CLS_POLICE和
6、CONFIG_NETFILTER时,就会在netfilter的PREROUTING钩子点处调用ing_hook函数,该函数的代码片段如下:if(dev->qdisc_ingress){spin_lock(&dev->queue_lock);if((q=dev->qdisc_ingress)!=NULL)fwres=q->enqueue(skb,q);spin_unlock(&dev->queue_lock);}可以看出与ing_filter的处理部分类似,最终都是调用了ingressqdisc的enqueue函数(即ingress_enque
7、ue函数)。ing_hook函数是在src/net/sched/sch_ingress.c文件中进行注册的,在sch_ingress文件中定义了一个结构实例ingress_qdisc_ops,如下所示:staticstructQdisc_opsingress_qdisc_ops={.next=NULL,.cl_ops=&ingress_class_ops,.id="ingress",.priv_size=sizeof(structingress_qdisc_data),.enqueue=ingress_enqueue,.dequeue=ing
8、ress_dequeue,.requeue=ingress_requeue,.drop=ingress_drop,.init=ingress_init,.reset=ingress_reset,.destroy=ingress_destroy,.change=NULL,.dump=ingress_dump,.owner=THIS_MODULE,};所有的qdisc都会有这样的一个对象实例,在模块初始化时会调用register_qdisc函数将自己的structQdisc_ops结构实例注册到链表中,该链表头是qdisc_base,定义在sch
9、_api.c文件中,staticstructQdisc_ops*qdisc_base。当通过tcqdisc命令配置了ingressqdisc规则时,会调用到ingress_init函数,进入ingress_init函数代码片段如下:#ifndefCONFIG_NET_CLS_ACT#ifdefCONFIG_NETFILTERif(!nf_registered){if(nf_register_hook(&ing_ops)<0){printk("ingressqdiscregistrationerror");return-EINVAL;}nf
10、_registered++;if(nf_register_hook(&ing6_ops)<0){printk("IPv6ingressqdiscregistrati