[<prev] [next>] [day] [month] [year] [list]
Message-ID: <22194.80.59.183.97.1167907351.squirrel@www.kernel-labs.org>
Date: Thu, 4 Jan 2007 05:42:31 -0500 (EST)
From: javiroman@...nel-labs.org
To: netdev@...r.kernel.org
Subject: egress path understanding
Hi all,
(sorry for newbie question)
I'm trying to learn the networking code of an ancient 2.4.18 vanilla kernel.
I understand that the egress path of network packet (socket buffer) as
general behaviour, goes through the method hard_start_xmit() within of
the driver layer. This method is the responsible of putting the
network packet into the output buffers of the network device. When the
physical transmmission is completed the device raises an interrupt and
the interrupt handler of the device is called.
The typical interrupt handler is a function running in interrupt
context, so needs to be as quick as possible, and because this
function has to free the skb buffer (to deallocate the sk_buff
structure associated with sucessfully transmitted buffer), the task is
delegated to softirq (NET_TX_SOFTIRQ) by means of function
dev_kfree_skb_irq():
static inline void dev_kfree_skb_irq(struct sk_buff *skb)
{
if (atomic_dec_and_test(&skb->users)) {
int cpu =smp_processor_id();
unsigned long flags;
#ifdef CONFIG_PROC_FS
softirq_stats.raise_from_kfree_skb_cont++;
#endif
local_irq_save(flags);
skb->next = softnet_data[cpu].completion_queue;
softnet_data[cpu].completion_queue = skb;
cpu_raise_softirq(cpu, NET_TX_SOFTIRQ);
local_irq_restore(flags);
}
}
When do_softirq() is called the funcion associated with
NET_TX_SOFTIRQ, net_tx_action() is called:
static void net_tx_action(struct softirq_action *h)
{
int cpu = smp_processor_id();
if (softnet_data[cpu].completion_queue) {
struct sk_buff *clist;
local_irq_disable();
clist = softnet_data[cpu].completion_queue;
softnet_data[cpu].completion_queue = NULL;
local_irq_enable();
while (clist != NULL) {
struct sk_buff *skb = clist;
clist = clist->next;
#ifdef CONFIG_PROC_FS
softirq_stats.tx_completion_cont++;
#endif
BUG_TRAP(atomic_read(&skb->users) == 0);
__kfree_skb(skb);
}
}
..... [snip]
}
How you can see, I have put some counters in order to trace the
execution of networking code by means of the file:
/proc/net/softirq_stat. The oputput of this file is the following when
I test the kernel:
# cat /proc/net/softirq_stat
raise_from_netif_cont: 0
raise_from_kfree_skb_cont: 0
(qdisc_restart) hard_start_xmit_cont: 5869
(qdisc_restart) xmit_lock_grabbed_cont: 0
tx_completion_cont: 5869
tx_output_cont: 142
OK, the important fields of this output are tx_completion_cont and
raise_from_kfree_skb_cont. We can see that every packet passed to
hard_start_xmit_cont (in qdisc_restart) is freed with net_tx_action,
so the counter hard_start_xmit_cont and tx_completion_cont show the
same values. But I cannot understand why the counter
raise_from_kfree_skb_cont is zero!!!
I guess the code path must pass through of dev_kfree_skb_irq() in
order to raise the softirq with cpu_raise_softirq(cpu,
NET_TX_SOFTIRQ), so it's possible to execute net_tx_action() later.
I don't know if I don't understand the therory or I have an error in
the code. Please can anybody advice me about this behaviour?
Thanks a lot, and sorry for my english.
--
Javi Roman
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists