lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Thu, 4 Jan 2007 05:42:31 -0500 (EST)
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

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;

                skb->next = softnet_data[cpu].completion_queue;
                softnet_data[cpu].completion_queue = skb;
                cpu_raise_softirq(cpu, NET_TX_SOFTIRQ);

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;

                clist = softnet_data[cpu].completion_queue;
                softnet_data[cpu].completion_queue = NULL;

                while (clist != NULL) {
                        struct sk_buff *skb = clist;
                        clist = clist->next;
                        BUG_TRAP(atomic_read(&skb->users) == 0);

..... [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
More majordomo info at

Powered by blists - more mailing lists