【2016-04-02】Linux网络通讯中传输队列初始化及其简单笔记

发布时间:2026/9/15 9:18:57
【2016-04-02】Linux网络通讯中传输队列初始化及其简单笔记 [历史归档]本文原发布于 cstriker1407.info 个人博客内容为历史存档仅供参考。发布时间2016-04-02 标题Linux网络通讯中传输队列初始化及其简单笔记分类操作系统 / linux / kernel 标签linux·kernelLinux网络通讯中传输队列初始化及其简单笔记Linux网络通讯中传输队列初始化及其简单笔记传送队列涉及到的内容非常多这里简单的笔记下最简单的初始化吧。哎。。心不稳啊~~看不下去当网络设备初始化时会初始化两个软中断分别用于发送队列和接收队列参考代码:/net/core/dev.cstaticint__initnet_dev_init(void){............/* 申请两个软中断分别用于发送和接收 */open_softirq(NET_TX_SOFTIRQ,net_tx_action,NULL);open_softirq(NET_RX_SOFTIRQ,net_rx_action,NULL);......}/* 发送软中断回调函数 */staticvoidnet_tx_action(structsoftirq_action*h){structsoftnet_data*sd__get_cpu_var(softnet_data);/* 首先看下是否有skb已经发送完成了 如果这些skb已经发送完了就把它们释放掉。 */if(sd-completion_queue){structsk_buff*clist;local_irq_disable();clistsd-completion_queue;sd-completion_queueNULL;local_irq_enable();/* 遍历完成链表把skb释放掉 */while(clist){structsk_buff*skbclist;clistclist-next;BUG_TRAP(!atomic_read(skb-users));__kfree_skb(skb);}}/* 如果外送链表不为空那么就唤醒这些skb对应的dev 进行发送 */if(sd-output_queue){structnet_device*head;local_irq_disable();headsd-output_queue;sd-output_queueNULL;local_irq_enable();while(head){structnet_device*devhead;headhead-next_sched;smp_mb__before_clear_bit();clear_bit(__LINK_STATE_SCHED,dev-state);/* 尝试对该dev加锁如果锁定成功那么就进行发送否则重新 触发发送软中断重新执行该流程 */if(spin_trylock(dev-queue_lock)){qdisc_run(dev);spin_unlock(dev-queue_lock);}else{netif_schedule(dev);}}}}/* 接受软中断回调函数 */staticvoidnet_rx_action(structsoftirq_action*h){structsoftnet_data*queue__get_cpu_var(softnet_data);unsignedlongstart_timejiffies;intbudgetnetdev_max_backlog;local_irq_disable();while(!list_empty(queue-poll_list)){structnet_device*dev;if(budget0||jiffies-start_time1)gotosoftnet_break;local_irq_enable();devlist_entry(queue-poll_list.next,structnet_device,poll_list);if(dev-quota0||dev-poll(dev,budget)){local_irq_disable();list_del(dev-poll_list);list_add_tail(dev-poll_list,queue-poll_list);if(dev-quota0)dev-quotadev-weight;elsedev-quotadev-weight;}else{dev_put(dev);local_irq_disable();}}out:local_irq_enable();return;softnet_break:__get_cpu_var(netdev_rx_stat).time_squeeze;__raise_softirq_irqoff(NET_RX_SOFTIRQ);gotoout;}那么该如何触发这些软中断在netdevice.h中有函数定义/* 触发一个发送队列软中断 */staticinlinevoid__netif_schedule(structnet_device*dev){/* 如果当前已经跑起来了就不用触发了 */if(!test_and_set_bit(__LINK_STATE_SCHED,dev-state)){unsignedlongflags;structsoftnet_data*sd;local_irq_save(flags);sd__get_cpu_var(softnet_data);dev-next_schedsd-output_queue;sd-output_queuedev;raise_softirq_irqoff(NET_TX_SOFTIRQ);/* 触发软中断 */local_irq_restore(flags);}}/* 在某个网络设备上发起发送流程 */staticinlinevoidnetif_schedule(structnet_device*dev){if(!test_bit(__LINK_STATE_XOFF,dev-state))/* 当前设备不能是OFF状态 */__netif_schedule(dev);}/* 在某个网络设备上开始传输队列 */staticinlinevoidnetif_start_queue(structnet_device*dev){clear_bit(__LINK_STATE_XOFF,dev-state);}/* 在某个网络设备上唤醒传输队列 */staticinlinevoidnetif_wake_queue(structnet_device*dev){#ifdefCONFIG_NETPOLL_TRAPif(netpoll_trap())return;#endifif(test_and_clear_bit(__LINK_STATE_XOFF,dev-state))__netif_schedule(dev);}/* 在某个网络设备上停止传输队列 */staticinlinevoidnetif_stop_queue(structnet_device*dev){#ifdefCONFIG_NETPOLL_TRAPif(netpoll_trap())return;#endifset_bit(__LINK_STATE_XOFF,dev-state);}/* 校验传输队列是否停止 */staticinlineintnetif_queue_stopped(conststructnet_device*dev){returntest_bit(__LINK_STATE_XOFF,dev-state);}/* 校验传输队列是否启动 */staticinlineintnetif_running(conststructnet_device*dev){returntest_bit(__LINK_STATE_START,dev-state);}/* 判断一个设备是否已经可以接收 */staticinlineintnetif_rx_schedule_prep(structnet_device*dev){returnnetif_running(dev)!test_and_set_bit(__LINK_STATE_RX_SCHED,dev-state);}/* Add interface to tail of rx poll list. This assumes that _prep has * already been called and returned 1. *//* 触发一个接收队列软中断 */staticinlinevoid__netif_rx_schedule(structnet_device*dev){unsignedlongflags;local_irq_save(flags);dev_hold(dev);list_add_tail(dev-poll_list,__get_cpu_var(softnet_data).poll_list);if(dev-quota0)dev-quotadev-weight;elsedev-quotadev-weight;__raise_softirq_irqoff(NET_RX_SOFTIRQ);local_irq_restore(flags);}/* Try to reschedule poll. Called by irq handler. *//* 在某个网络设备上发起接收流程 */staticinlinevoidnetif_rx_schedule(structnet_device*dev){if(netif_rx_schedule_prep(dev))__netif_rx_schedule(dev);}/* Try to reschedule poll. Called by dev-poll() after netif_rx_complete(). * Do not inline this? *//* 在某个网络设备上发起接收流程 */staticinlineintnetif_rx_reschedule(structnet_device*dev,intundo){if(netif_rx_schedule_prep(dev)){unsignedlongflags;dev-quotaundo;local_irq_save(flags);list_add_tail(dev-poll_list,__get_cpu_var(softnet_data).poll_list);__raise_softirq_irqoff(NET_RX_SOFTIRQ);local_irq_restore(flags);return1;}return0;}