关键词不能为空

当前您在: 主页 > 英语 >

linux内核IMQ源码实现分析

作者:高考题库网
来源:https://www.bjmy2z.cn/gaokao
2021-02-12 09:17
tags:

-

2021年2月12日发(作者:大赦天下)


本文档的


Copyleft


< br>wwwlkk


所有,使用


GPL


发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁


用于任何商业用途。




E-mail:


wwwlkk@



来源


:


/?business&aid=6&un=wwwlkk#7



linux2.6.35


内核


IMQ< /p>


源码实现分析




1


)数据包截留并重新注入协议栈技术


......... .................................................. ......................................


1




2


)及时处理数据包技术


................... .................................................. .................................................. ..


2




3



IMQ


设备数据包重新注入协议栈 流程



.


............. .................................................. ............................


4




4



IMQ


截留数据包流程

< br>


.


....................... .................................................. ..............................................


4




5



IMQ


在软中断中及时将数据包重新注入 协议栈



.


............ .................................................. .............


7




6


)结束语


.................................................. .................................................. .............................................


9



前言:


I MQ


用于入口流量整形和全局的流量控制,


IMQ


的配置是很简单的,但很少人分析过


IMQ


的内核实 现,网络上也没有


IMQ


的源码分析文档,为了搞清楚


IMQ


的性能,稳定性,以及


借鉴


IMQ


的技术,本文分析了


IMQ

< br>的内核实现机制。



首先揭示


I MQ


的核心技术:



1.



如何从协议栈中截留数据包,并能把数据包重新注入协议栈。



2.



如何做到及时的将数据包重新注入协议栈。


< br>实际上


linux


的标准内核已经解决了以上

< p>
2


个技术难点,第


1


个技 术可以在


NF_QUEUE


机制


中看到 ,第二个技术可以在发包软中断中看到。下面先介绍这


2


个技术 。




1


)数 据包截留并重新注入协议栈技术



okfn


参数:



int


ip_rcv


(struct


sk_buff


*skb,


struct


net_device


*dev,


struct


packet_type


*pt,


struct


net_device


*orig_dev){







< p>
















。< /p>









< p>









return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING


, skb, dev, NULL,











ip_rcv_finish


);< /p>


//


下一流程是进入函数


ip_rcv_ finish




}


static inline int


NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb,



struct net_device *in, struct net_device *out,



int (*okfn)(struct sk_buff *))


//



ip_rcv_fini sh


地址作为参数传入。



{



return


NF_HOOK_THRESH


(pf, hook, skb, in, out,


okfn


, INT_MIN);


}


static inline int


NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb,










struct net_device *in, struct net_device *out,










int (*okfn)(struct sk_buff *), int thresh)


{



int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh);



if (ret == 1)




ret = okfn(skb) ;//


根据函数地址进入之前的


ip_rcv_finish< /p>


函数。



linux-2.6.35


内核


IMQ


源码实现分析

< br>





2011-8-23




1 /


9



}


return ret;


okf n


应该是下一个流程函数,不应该是本流程函数,这样做就很稳定了。

< br>


IMQ


设备的做法就是使用到了这个

< br>okfn



IMQ


设备发送数据 包不是调用网卡驱动,而是根据


okfn


,将数据包发给下一个 流程函数。



这里函数的概念和模块的概念是一样的,


一个函数就是一个模块,


一个模块处理完就将数据扔

给下一个模块处理,各个模块间的数据处理是互补干扰的。从这个概念看使用


okf n


是很合理的。



< br>2


)及时处理数据包技术



Qo S


有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的 数


据包被及时的发送出去呢?


linux


有一套机制来解决这个问题,下面先了解这套机制:



int dev_queue_xmit(struct sk_buff *skb)


{ < /p>









< p>
















。< /p>




txq = dev_pick_tx(dev, skb);



q = rcu_dereference_bh(txq->qdisc);


获得设备上的发送 队列





















< br>。










if (q->enqueue) {




rc = __dev_xmit_skb(skb, q, dev, txq);




goto out;


数据包入队后,整个入队流程就结束了




}


}


以 上是入队过程,那么需要保证入队的数据包被及时的发送出去。



static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,







struct net_device *dev,







struct netdev_queue *txq)


{



spinlock_t *root_lock = qdisc_lock(q);



int rc;



spin_lock(root_lock);



if (unlikely(test_bit(

< p>
__QDISC_STATE_DEACTIV


ATED

< br>, &q->state))) {




kfree_skb(skb);


如果这个队列是未运行的,那么释放这个数 据包





rc = NET_XMIT_DROP;



} else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) &&







!test_and_set_bit(


__QDISC_STAT E_RUNNING


, &q->state)) {


如果已经 有


CPU


在运行这


个队列,那么字节返 回,因为一个队列只能由一个


CPU


运行。




/*





* This is a work-conserving queue; there are no old skbs





* waiting to be sent out; and the qdisc is not running -





* xmit the skb directly.





*/< /p>


如果一个队列是位运行的,说明这个队列里面没有数据包,此时可以直接发送这个包





if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE))





skb_dst_force(skb);




__qdisc_update_bstats(q, skb->len);




if (


sch_direct_xmit


(skb, q, dev, txq, root_lock))


试图直接发送数据包,

< br>如果没有发送成功,



linux-2.6.35


内核


IMQ


源码实现分析





2011-8-23




2 /


9


者队列中还有待发数据包, 返回值会大于


0


,那么,此时需要激活这个队列。





< br>__qdisc_run(q);


激活运行队列





else





cle ar_bit(__QDISC_STATE_RUNNING


, &q->state);





rc = NET_XMIT_SUCCESS;



} else {




skb_dst_force(skb);




rc = qdisc_enqueue_root(skb, q);




qdisc_run(q);



}



spin_unlock(root_lock);




return rc;


}



上面看到了,发送队列被激活了, 只要队列中有数据包待发送,队列总是处于激活状态,那么


激活状态的队列是否能保证队 列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的


特点。



void __qdisc_run(struct Qdisc *q)


{



unsigned long start_time = jiffies;




while (qdisc_restart(q)) {


队列会一直发送数据包,





/*






* Postpone processing if





* 1. another process needs the CPU;





* 2. we've been doing it for too long.





*/




if (need_resched() || jiffies != start_time) {


如果占用的


CPU


的时间太长了,


有其他的路径需要

占用


CPU


,此时暂时停止队列的发包。

< br>





__netif_schedule(q);


将队列加入发送 软中断


NET_TX_SOFTIRQ


的处理队列,

< p>
当软中


断被执行时,队列又会继续发送数据包。






break;




}



}




clear_bit(__QDISC_STATE_RUN NING


, &q->state);


}



由于软中断被激活,软中断的优先 级仅次于硬中断,


这样就保证了队列会被及时的运行,


即保


证了数据包会被及时的发送。




这是


linux


内核发送软中断的机制,


IMQ


就是利用了这个机制,不同点在于:正


常的发送队列是将数据包发送给网卡驱动,而


IMQ


队列是将数 据包发送给


okfn






linux-2.6.35

内核


IMQ


源码实现分析






2011-8-23




3 /


9


以上


2


个技术点就是


IMQ


的关键技术, 下面是


IMQ


的具体流程。




3



IMQ


设备数据包重新注入协议栈流程



IMQ


网络设备:



static const struct net_device_ops


imq_netdev_ops


= {




.ndo_open



= imq_open,




.ndo_stop



= imq_close,




.ndo_start_xmit



=


imq_dev_xmit


,




.ndo_get_stats



= imq_get_stats,



};



static netdev_tx_t


imq_dev_xmit


(struct sk_buff *skb, struct net_device *dev)


-->


nf_reinject(entry, NF_ACCEPT);





-->



struct sk_buff *skb = entry->skb;





-->



entry->okfn(skb);


IMQ


网络设备来说,发送一个数据包,实际上就是将数据包重新注入到协议栈中。





4



IMQ


截留数据包流程

< br>


那么协议栈如何将数据包注入到


IMQ


设备中:



static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff *pskb,






const struct net_device *indev,






const struct net_device *outdev,






int (*okfn)(struct sk_buff *))


{



return (pskb->imq_flags & IMQ_F_ENQUEUE) ? NF_IMQ_QUEUE : NF_ACCEPT;


}


static struct nf_hook_ops


imq_ops


[] = {



{



/* imq_ingress_ipv4 */




.hook



= imq_nf_hook,




.owner



= THIS_MODULE,




.pf



= PF_INET,




.hooknum


= NF_INET_PRE_ROUTING


,


#if defined(CONFIG_IMQ_BEHA


VIOR_BA) || defined(CONFIG_IMQ_BEHA


VIOR_BB)




.priority = NF_IP_PRI_MANGLE + 1,


#else




.priority = NF_IP_PRI_NAT_DST + 1,


#endif



},



{



/* imq_egress_ipv4 */




.hook



= imq_nf_hook,


l inux-2.6.35


内核


IMQ


源 码实现分析






2011-8-23




4 /


9

-


-


-


-


-


-


-


-



本文更新与2021-02-12 09:17,由作者提供,不代表本网站立场,转载请注明出处:https://www.bjmy2z.cn/gaokao/642483.html

linux内核IMQ源码实现分析的相关文章