netif_start_queue()
clears __QUEUE_STATE_DRV_XOFF flags of TX queue 0. __QUEUE_STATE_DRV_XOFF is used by drivers to stop the queue. __QUEUE_STATE_STACK_XOFF is used by stack to stop the transmit queue independently.
Input Packet Queues, the Softnet_data Structure
packet qeueing structure contains an internal data structure called softnet_data.
a) struct sk_buff_head input_pkt_queue :
b) struct list_head poll_list; Poll_list is a list of network interfaces to be processed. It is used by backlog processing.
Queuing Layer Initialization
struct softnet_data *sd = &per_cpu(softnet_data, i);
skb_queue_head_init(&sd->input_pkt_queue);
skb_queue_head_init(&sd->process_queue);
INIT_LIST_HEAD(&sd->poll_list);
sd->output_queue_tailp = &sd->output_queue;
spin_lock_init(&sd->defer_lock);
gro_init(&sd->backlog.gro);
sd->backlog.poll = process_backlog;
sd->backlog.weight = weight_p;
INIT_LIST_HEAD(&sd->backlog.poll_list);
}
{
local_irq_disable();
list_splice_init(&sd->poll_list, &list);
local_irq_enable();
budget -= napi_poll(n, &repoll);
process_backlog()
struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
if (sd->rps_ipi_list) {
// send IPI
}
raise_softirq_irqoff
__raise_softirq_irqoff(nr);
/*
* If we're in an interrupt or softirq, we're done
* (this also catches softirq-disabled code). We will
* actually run the softirq once we return from
* the irq or softirq.
*
* Otherwise we wake up ksoftirqd to make sure we
* schedule the softirq soon.
*/
if (!in_interrupt() && should_wake_ksoftirqd())
wakeup_softirqd();
}
napi_schedule()
{
}
__raise_softirq_irqoff
set local_softirq_pending_ref 's corresponding BH flag.
{
handle_softirqs()
while ((softirq_bit = ffs(pending))) {
h->action(); // action is set when open_softirq() is called
}
enqueue_to_backlog()
enqueue_to_backlog is called to queue an skb to a per CPU backlog queue of a CPU.
backlog_lock_irq_save(sd, &flags);
qlen = skb_queue_len(&sd->input_pkt_queue);
if (qlen <= max_backlog) {
if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state))
napi_schedule_rps(sd);
__skb_queue_tail(&sd->input_pkt_queue, skb);
backlog_unlock_irq_restore(sd, &flags);
netif_rx()
netif_rx() receives packet from driver driver and enqueues to stack to process via backlog NAPI. This function can be invoked from interrupt and process context. This function calls local_bh_disable() if not interrupt context.
netif_rx() --> netif_rx_internal()
if (rps) enabled, get_rps_cpu() and enqueue_to_backlog()
else case enqueue_to_backlog() of this cpu
|
Please see enqueue_to_backlog() and process_backlog()
netif_receive_skb
|
if (rps) enabled, enqueue_to_backlog of get_rps_cpu()