Sk_buffer detailed analysis (below)

Source: Internet
Author: User

6. sk_buffer secret
When alloc_skb () is called to construct SKB and data buffer, the buffer size is calculated as follows:

Data = kmalloc (size + sizeof (struct skb_shared_info), gfp_mask );

In addition to the specified size, it also contains the space size of a struct skb_shared_info structure. That is to say, when alloc_skb (size) is called to allocate the buffer of the size, a skb_shared_info is also created.

The structure is defined as follows:

Struct skb_shared_info {
Atomic_t dataref;
Unsigned int nr_frags;
Unsigned short tso_size;
Unsigned short tso_segs;
Struct sk_buff * frag_list;
Skb_frag_t frags [max_skb_frags];
};

We only need to convert the end from char * To skb_shared_info * to access this structure.
Linux provides a macro for this conversion:

# Define skb_shinfo (SKB) (struct skb_shared_info *) (SKB)-> end ))

So what is the purpose of this hidden structure?
It has at least two purposes:
1. Used to manage paged data
2. Used to manage parts

Next, we will study how sk_buffer processes paged data and fragments respectively.

7. Processing paged data

In some cases, you want to directly send the data stored in the file through the socket, which avoids copying the data from the file to the buffer, thus improving the efficiency.

Linux uses a "paged data" technology to provide such support. This technology maps data in files to multiple pages.
In Linux, struct skb_frag_strut is used to manage such pages:

Typedef struct skb_frag_struct skb_frag_t;

Struct skb_frag_struct {

Struct page * page;

_ 2010page_offset;

_ 2010size;

};

In shared info, use the array frags [] to manage these structures.
As a result, sk_buffer not only manages data in a buffer space, but also manages a group of data stored on the page through the share info structure.
When "paged data" is used, the data_len member comes in handy, indicating how much data is stored in the page. Therefore,
If data_len is not 0, the data managed by this sk_buffer is "non-linear.
SKB-> len-SKB-> data_len is the length of non-paged data.

In the case of "paged data", skb_put () cannot be used. pskb_put () must be used ()...

8. processing parts

9. SKB management functions

9.1. Basic management functions of Data Buffer

· Unsigned char * skb_put (struct sk_buff * SKB, unsigned int Len)

Push data
Add data at the end of the buffer. Len is the length to be increased.
This function has two restrictions, which must be noticed by the caller. Otherwise, the caller is responsible for the consequences.
1) It cannot be used in the case of "paged data ".
This requires the caller to determine whether it is "paged data ".
2) After adding new data, the length cannot exceed the actual size of the buffer.
This requires the caller to calculate the data size that can be increased by himself.

· Unsigned char * skb_push (struct sk_buff * SKB, unsigned int Len)
"Pressure" incoming data
Increase data from the starting position of the buffer. Len is the length to be increased.
Actually, the new data is "pressed" into the head room.

· Unsigned char * skb_pull (struct sk_buff * SKB, unsigned int Len)
Pull data
Remove Data from the buffer starting position. Len is the length to be removed.
If Len is greater than SKB-> Len, nothing is done.
In the process of processing the received packet, the protocol header of the outermost layer is usually removed through skb_pull (). For example, after the network layer is processed, the header of the network layer needs to be removed, it is further handed over to the transport layer for processing.

· Void skb_trim (struct sk_buff * SKB, unsigned int Len)
Adjust the buffer size. Len is the adjusted size.
If Len is smaller than buffer, no adjustment is made.
Therefore, the data at the bottom of the buffer is removed.
It is easy to handle the absence of paged data;
However, when paged data exists, _ pskb_trim () needs to be called for processing.

9.2. "paged data" and shard management functions

· Char * pskb_pull (struct sk_buff * SKB, unsigned int Len)

"Pull" Data
If Len is longer than the data length in the linear buffer, call _ pskb_pull_tail () for processing.
(Q: At last, return SKB-> Data + = Len; will it cause SKB-> data to be out of the chain head range ?)

· Int pskb_may_pull (struct sk_buff * SKB, unsigned int Len)
Before you call skb_pull () to remove the outer protocol header, you usually call this function to determine whether there is sufficient data for "pull ".
If the linear buffer is pull enough, 1 is returned;
If pull data exceeds SKB-> Len, 0 is returned;
Finally, call _ pskb_pull_tail () to check whether the page buffer has enough data for pull.

· Int pskb_trim (struct sk_buff * SKB, unsigned int Len)
Adjust the Data Length of data buffer to Len
Without page buffer, it is equivalent to skb_trim ();
In the case of page buffer, ___ pskb_trim () needs to be called for further processing.

· Int skb_linearize (struct sk_buff * SKB, gfp_t green)

· Struct sk_buff * skb_clone (struct sk_buff * SKB, gfp_t gfp_mask)
'Clone 'a new SKB. The structure of the new SKB is basically the same as that of the original SKB. The difference is:
1) they share the same data buffer.
2) their cloned flag is set to 1
3) the sk of the new SKB is set to null.
(Q: When will the cloning technology be used ?)

· Struct sk_buff * skb_copy (const struct sk_buff * SKB, gfp_t gfp_mask)

· Struct sk_buff * pskb_copy (struct sk_buff * SKB, gfp_t gfp_mask)

· Struct sk_buff * skb_pad (struct sk_buff * SKB, int pad)

· Void skb_clone_fraglist (struct sk_buff * SKB)

· Void skb_drop_fraglist (struct sk_buff * SKB)

· Void copy_skb_header (struct sk_buff * New, const struct sk_buff * old)

· Pskb_expand_head (struct sk_buff * SKB, int nhead, int ntail, gfp_t gfp_mask)

· Int skb_copy_bits (const struct sk_buff * SKB, int offset, void * To, int Len)

· Int skb_store_bits (const struct sk_buff * SKB, int offset, void * From, int Len)

· Struct sk_buff * skb_dequeue (struct sk_buff_head * List)

· Struct sk_buff * skb_dequeue (struct sk_buff_head * List)

· Void skb_queue_purge (struct sk_buff_head * List)

· Void skb_queue_purge (struct sk_buff_head * List)

· Void skb_queue_tail (struct sk_buff_head * List, struct sk_buff * newsk)

· Void skb_unlink (struct sk_buff * SKB, struct sk_buff_head * List)

· Void skb_append (struct sk_buff * Old, struct sk_buff * newsk, struct sk_buff_head * List)

· Void skb_insert (struct sk_buff * Old, struct sk_buff * newsk, struct sk_buff_head * List)

· Int skb_add_data (struct sk_buff * SKB, char _ User * From, int copy)

· Struct sk_buff * skb_padto (struct sk_buff * SKB, unsigned int Len)

· Int skb_cow (struct sk_buff * SKB, unsigned int headroom)

This function needs to adjust the header room of SKB. The size of the adjusted header room is headroom.
If the headroom length exceeds the size of the current header room, or the SKB is cloned, you need to adjust it:
Allocate a new data buffer space, SKB uses the new data buffer space, and the reference count of the original space is reduced by 1. The original space is released without other users.

· Struct sk_buff * dev_alloc_skb (unsigned int length)

· Void skb_orphan (struct sk_buff * SKB)

· Void skb_reserve (struct sk_buff * SKB, unsigned int Len)

· Int skb_tailroom (const struct sk_buff * SKB)

· Int skb_headroom (const struct sk_buff * SKB)

· Int skb_pagelen (const struct sk_buff * SKB)

· Int skb_headlen (const struct sk_buff * SKB)

· Int skb_is_nonlinear (const struct sk_buff * SKB)

· Struct sk_buff * skb_0000_check (struct sk_buff * SKB, gfp_t PRI)

If SKB has only one quote, directly return SKB; otherwise, clone one SKB and subtract 1 from the original SKB-> users. to return a new SKB, pay special attention to pskb_pull () and pskb_may_pull () how is it used:

1) when receiving data, a large amount of pskb_may_pull () is used to determine whether there is sufficient data in SKB. For example, in ip_rcv:

If (! Pskb_may_pull (SKB, sizeof (struct iphdr )))
Goto inhdr_error;

IPH = SKB-> NH. iph;

It aims to get the IP header, but before obtaining the header, it first uses pskb_may_pull () to determine whether there is enough data for an IP header.
2) When we construct an IP group, we can use put to expand the space for the data section (if a sk_buffer is not enough, how can we split it ?); For the transport layer, network layer, and link layer headers, expand the space by pushing up;
3) When we resolve the IP Group, we use pull () to compress the space from the beginning to the end.

Therefore, put and push are mainly used to send data packets, while pull is mainly used to receive data packets.

10. Various Headers

Union {
Struct tcphdr * th;
Struct udphdr * uh;
Struct icmphdr * icmph;
Struct igmphdr * igmph;
Struct iphdr * ipiph;
Struct listen 6hdr * Listen 6 h;
Unsigned char * Raw;
} H;

Union {
Struct iphdr * IPH;
Struct listen 6hdr * Listen 6 h;
Struct arphdr * arph;
Unsigned char * Raw;
} NH;

Union {
Unsigned char * Raw;
} MAC;

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.