送信キューのスケジューリング

スケジューリングが必要になるか、送信パケットが一定数を超えるまで、送信(qdisc_restart())し続ける。

[net/core/dev.c]
dev_queue_xmit
__dev_xmit_skb

[net/sched/sch_generic.c]
void __qdisc_run(struct Qdisc *q)
{
int quota = weight_p;

while (qdisc_restart(q)) {
/*
* Ordered by possible occurrence: Postpone processing if
* 1. we've exceeded packet quota
* 2. another process needs the CPU;
*/
if (--quota <= 0 || need_resched()) {
__netif_schedule(q);
break;
}
}

qdisc_run_end(q);
}


qdisc_restart(q)内で実際にパケット(skb)を送信(sch_direct_xmit)してる。
static inline int qdisc_restart(struct Qdisc *q)
{
struct netdev_queue *txq;
struct net_device *dev;
spinlock_t *root_lock;
struct sk_buff *skb;

/* Dequeue packet */
skb = dequeue_skb(q);
if (unlikely(!skb))
return 0;
WARN_ON_ONCE(skb_dst_is_noref(skb));
root_lock = qdisc_lock(q);
dev = qdisc_dev(q);
txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));

return sch_direct_xmit(skb, q, dev, txq, root_lock);
}



__netif_schedule()は
[net/core/dev.c]
__netif_schedule
static inline void __netif_reschedule(struct Qdisc *q)
{
struct softnet_data *sd;
unsigned long flags;

local_irq_save(flags);
sd = &__get_cpu_var(softnet_data);
q->next_sched = NULL;
*sd->output_queue_tailp = q;
sd->output_queue_tailp = &q->next_sched;
raise_softirq_irqoff(NET_TX_SOFTIRQ);
local_irq_restore(flags);
}

ここで送信処理を行うソフトウェア割り込みを登録(スケジュール)している
参考:http://wiki.bit-hive.com/linuxkernelmemo/pg/%C1%F7%BC%F5%BF%AE