How to understand the function of pskb_may_pull()?

Alberto Leiva ydahhrk at gmail.com
Fri Jan 9 13:25:27 EST 2015


The code that handles the reception of a packet, before reaching the
IP stack, runs in interrupt context (page 180 of
http://it-ebooks.info/book/2195/).

Interrupt context is a magical world where you work under serious
pressure (http://www.makelinux.net/books/lkd2/ch06lev1sec5).
Allocating memory under such circumstances might be difficult because
you are not allowed to sleep. And maybe other reasons.
It is also generally understood that, because of memory fragmentation,
allocating several small pieces of memory is a lot easier than a
single & continuous chunk of equivalent aggregated length.
Therefore, a driver might find itself on a situation where it cannot
allocate a massive array of bytes for the packet it just received, but
can allocate several equivalent but small and separated chunks of
memory.
In this case, the driver can choose to page the skb. And it might just
so happen that the first page might not be large enough to fully
contain the IP header (since you don't know; maybe the driver is
running on an artifact with like 2kb total or something).

Keep in mind I'm no guru and I have never coded a really tight driver.
I'm just stacking some of my reading together and could be raving
lunacy :).

On Thu, Jan 8, 2015 at 12:29 AM, lx <lxlenovostar at gmail.com> wrote:
> hi Alberto:
>         I'm confused with " paging skbs is a technique meant to ease the
> work
> of drivers.A driver might choose to page "too much" data.", please give more
> explain.
>
> Thank you.
>
> 2015-01-07 23:35 GMT+08:00 Alberto Leiva <ydahhrk at gmail.com>:
>>
>> I think in theory whatever random driver for whatever random hardware
>> might create this situation. It's not illegal. Anyone can create a
>> driver outside of the kernel tree, after all. In practice, of course,
>> this is not the case, because anyone can tell it creates a significant
>> amount of overhead when the inevitable pskb_may_pull() come into play,
>> but you don't know what constrictive environments a driver out there
>> might be operating on.
>>
>> As I understand it, paging skbs is a technique meant to ease the work
>> of drivers.
>> A driver might choose to page "too much" data.
>> The kernel is prepared for this situation ('Be conservative in what
>> you do, be liberal in what you accept from others' -
>> http://en.wikipedia.org/wiki/Robustness_principle).
>> That's all there is to it, I think.
>>
>> PS: From your sorta definition, you seem to be assuming
>> pskb_may_pull() is only used to ensure the IP header is not paged. I
>> understand this might not be the case, but just to make things clear:
>> pskb_may_pull() can be used to copy *any* amount of bytes from the
>> paged part to the head room of the packet (it's not tied to the IP
>> header's length). For example, you could use it to also guarantee a
>> TCP header by doing this:
>> if (!pskb_may_pull(skb, sizeof(struct iphdr) + sizeof(struct tcphdr)))
>>         goto inhdr_error;
>>
>>
>> On Wed, Jan 7, 2015 at 2:28 AM, lx <lxlenovostar at gmail.com> wrote:
>> > hi all:
>> >       The job of pskb_may_pull is to make sure that the area pointed to
>> > by
>> > skb->data contains a block of
>> > data at least as big as the IP header, since each IP packet (fragments
>> > included) must include a complete IP
>> > header.When we receive a packet , the kernel will call the
>> > pkb_may_pull(),
>> > it looks like the following in line 395:
>> >
>> > 373 /*
>> > 374  *  Main IP Receive routine.
>> > 375  */
>> > 376 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct
>> > packet_type *pt, struct net_device *orig_dev)
>> > 377 {
>> > 378     const struct iphdr *iph;
>> > 379     u32 len;
>> > 380
>> > 381     /* When the interface is in promisc. mode, drop all the crap
>> > 382      * that it receives, do not try to analyse it.
>> > 383      */
>> > 384     if (skb->pkt_type == PACKET_OTHERHOST)
>> > 385         goto drop;
>> > 386
>> > 387
>> > 388     IP_UPD_PO_STATS_BH(dev_net(dev), IPSTATS_MIB_IN, skb->len);
>> > 389
>> > 390     if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
>> > 391         IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
>> > 392         goto out;
>> > 393     }
>> > 394
>> > 395     if (!pskb_may_pull(skb, sizeof(struct iphdr)))
>> > 396         goto inhdr_error;
>> > 397
>> > 398     iph = ip_hdr(skb);
>> > 399
>> >
>> > And the definition of pkb_may_pull() looks like the following:
>> >
>> > 1708 static inline int pskb_may_pull(struct sk_buff *skb, unsigned int
>> > len)
>> > 1709 {
>> > 1710     if (likely(len <= skb_headlen(skb)))
>> > 1711         return 1;
>> > 1712     if (unlikely(len > skb->len))
>> > 1713         return 0;
>> > 1714     return __pskb_pull_tail(skb, len - skb_headlen(skb)) != NULL;
>> > 1715 }
>> >
>> > I just want to know which situation make the skb->data contains a block
>> > of
>> > data less than the IP header?
>> > I think this packet can't send by kernel at all.
>> > Thank you.
>> >
>> > _______________________________________________
>> > Kernelnewbies mailing list
>> > Kernelnewbies at kernelnewbies.org
>> > http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
>> >
>
>



More information about the Kernelnewbies mailing list