Linux网络通讯中传输队列初始化及其简单笔记
传送队列涉及到的内容非常多,这里简单的笔记下最简单的初始化吧。哎。。心不稳啊~~看不下去
当网络设备初始化时,会初始化两个软中断,分别用于发送队列和接收队列,参考代码:
/net/core/dev.c
static int __init net_dev_init(void) { ...... ...... /* 申请两个软中断,分别用于发送和接收 */ open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL); open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL); ...... } /* 发送软中断回调函数 */ static void net_tx_action(struct softirq_action *h) { struct softnet_data *sd = &__get_cpu_var(softnet_data); /* 首先看下是否有skb已经发送完成了, 如果这些skb已经发送完了,就把它们释放掉。 */ if (sd->completion_queue) { struct sk_buff *clist; local_irq_disable(); clist = sd->completion_queue; sd->completion_queue = NULL; local_irq_enable(); /* 遍历完成链表,把skb释放掉 */ while (clist) { struct sk_buff *skb = clist; clist = clist->next; BUG_TRAP(!atomic_read(&skb->users)); __kfree_skb(skb); } } /* 如果外送链表不为空,那么就唤醒这些skb对应的dev, 进行发送 */ if (sd->output_queue) { struct net_device *head; local_irq_disable(); head = sd->output_queue; sd->output_queue = NULL; local_irq_enable(); while (head) { struct net_device *dev = head; head = head->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); } } } } /* 接受软中断回调函数 */ static void net_rx_action(struct softirq_action *h) { struct softnet_data *queue = &__get_cpu_var(softnet_data); unsigned long start_time = jiffies; int budget = netdev_max_backlog; local_irq_disable(); while (!list_empty(&queue->poll_list)) { struct net_device *dev; if (budget <= 0 || jiffies - start_time > 1) goto softnet_break; local_irq_enable(); dev = list_entry(queue->poll_list.next, struct net_device, poll_list); if (dev->quota <= 0 || dev->poll(dev, &budget)) { local_irq_disable(); list_del(&dev->poll_list); list_add_tail(&dev->poll_list, &queue->poll_list); if (dev->quota < 0) dev->quota += dev->weight; else dev->quota = dev->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); goto out; }
那么该如何触发这些软中断,在netdevice.h中有函数定义:
/* 触发一个发送队列软中断 */ static inline void __netif_schedule(struct net_device *dev) { /* 如果当前已经跑起来了,就不用触发了 */ if (!test_and_set_bit(__LINK_STATE_SCHED, &dev->state)) { unsigned long flags; struct softnet_data *sd; local_irq_save(flags); sd = &__get_cpu_var(softnet_data); dev->next_sched = sd->output_queue; sd->output_queue = dev; raise_softirq_irqoff(NET_TX_SOFTIRQ); /* 触发软中断 */ local_irq_restore(flags); } } /* 在某个网络设备上发起发送流程 */ static inline void netif_schedule(struct net_device *dev) { if (!test_bit(__LINK_STATE_XOFF, &dev->state))/* 当前设备不能是OFF状态 */ __netif_schedule(dev); } /* 在某个网络设备上开始传输队列 */ static inline void netif_start_queue(struct net_device *dev) { clear_bit(__LINK_STATE_XOFF, &dev->state); } /* 在某个网络设备上唤醒传输队列 */ static inline void netif_wake_queue(struct net_device *dev) { #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) return; #endif if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) __netif_schedule(dev); } /* 在某个网络设备上停止传输队列 */ static inline void netif_stop_queue(struct net_device *dev) { #ifdef CONFIG_NETPOLL_TRAP if (netpoll_trap()) return; #endif set_bit(__LINK_STATE_XOFF, &dev->state); } /* 校验传输队列是否停止 */ static inline int netif_queue_stopped(const struct net_device *dev) { return test_bit(__LINK_STATE_XOFF, &dev->state); } /* 校验传输队列是否启动 */ static inline int netif_running(const struct net_device *dev) { return test_bit(__LINK_STATE_START, &dev->state); } /* 判断一个设备是否已经可以接收 */ static inline int netif_rx_schedule_prep(struct net_device *dev) { return netif_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. */ /* 触发一个接收队列软中断 */ static inline void __netif_rx_schedule(struct net_device *dev) { unsigned long flags; local_irq_save(flags); dev_hold(dev); list_add_tail(&dev->poll_list, &__get_cpu_var(softnet_data).poll_list); if (dev->quota < 0) dev->quota += dev->weight; else dev->quota = dev->weight; __raise_softirq_irqoff(NET_RX_SOFTIRQ); local_irq_restore(flags); } /* Try to reschedule poll. Called by irq handler. */ /* 在某个网络设备上发起接收流程 */ static inline void netif_rx_schedule(struct net_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? */ /* 在某个网络设备上发起接收流程 */ static inline int netif_rx_reschedule(struct net_device *dev, int undo) { if (netif_rx_schedule_prep(dev)) { unsigned long flags; dev->quota += undo; 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); return 1; } return 0; }
发表评论