"Linux Driver" Netfilter/iptables (vii) kernel protocol stack SKB Encapsulation analysis (continued VI)

Source: Internet
Author: User
Tags reserved iptables

The above describes the NetFilter mechanism, how to re-build and send a SKB, involving kernel protocol stack programming, rather than what we usually call the user layer socket network programming.

Let's begin by introducing several functions that are involved in the SKB refactoring program above:
First of all, it is necessary to say, but also in each of the following procedures are said, is the development of the source tree version is 3.13, this version of the Skb_buff and our common 2.4, 2.6 are very different.

One, the main look at four fields:

typedef unsigned int sk_buff_data_t;
    sk_buff_data_t      tail;
    sk_buff_data_t end      ;
    unsigned char       *head,
                *data;

It means "deep understanding of Linux network Technology" as shown in the following figure

head and end point to the header and tail of the buffer, while data and tail point to the head and tail of the actual data, each layer fills the protocol header between the head and data, or adds new protocol data between tail and end.

So according to the above analysis, head and data is the protocol header and payload, such as transport layer, network layer, Ethernet frame head.

emphasis: The data section in Sk_buff contains the protocol layer header and payload.

The following is the length field of each head in the Sk_buff:

Local
    __u16           Transport_header;
    __u16           Network_header;
    __u16           Mac_header;

Sk_buff canceled the Union field in the data structure,
//So when programming can not directly call the consortium members in Sk_buff to the corresponding transport layer head, network layer head, etc.
//But it provides us with a more convenient way:

//Lift network layer For example
static inline struct IPHDR *ip_hdr (const struct Sk_buff)
{
    return (struct IPHDR *) Skb_network_header (SKB);
}

Static inline unsigned char *skb_network_header (const struct Sk_buff *skb)
{return
    Skb->head + skb-> Network_header;
}
And we are in the Linux network protocol stack analysis is the same, by first locating the entire buffer of the head end,
/and then according to the protocol layer offset to locate the protocol layer, as to the order of the Protocol headers. All know

ii. ALLOC_SKB and Skb_reserve

Also, for ALLOC_SKB (), we just need to specify the size of its data part (Application Layer Data + protocol layer header), the function will be the extra space in the Skb_buff to allocate , this does not need us to worry about.

Skb_reserve (), is a positioning function, is the front alloc a SKB, use this function to adjust the data and tail pointer

static inline void Skb_reserve (struct sk_buff *skb, int len)
{
    skb->data = len;
    Skb->tail = len;
How much Len takes depends on how you fill up the data later.

Skb_reserve () This function is to reserve the SKB protocol head and the space of the valid data part in the buffer, the space can be large and small.

After the previous ALLOC_SKB and Skb_reserve, the two pointers (data and tail) have now changed:
ALLOC_SKB ():

The fields before tail and tail are initialized to 0
    memset (SKB, 0, offsetof (struct sk_buff, tail));
    /* account for allocated MEMORY:SKB + Skb->head * ...
    Skb->head = data;
    Skb->data = data;
...
    Skb->end = skb->tail + size;

Head and data point to the first address position of the allocated SKB data portion (protocol header + payload),
//end to the end position, and the tail value is 0

after Skb_reserve (SKB, Len), the pointer to data and tail is changed, in other words, the Len size is reserved between head and data to populate the protocol header and payload.

The above reserved the whole space, below we also want to subdivide the space, the above whole space includes each protocol layer head and payload part, we also have to according to each layer agreement Head's Prevention Order reasonable Division space:

iii. Skb_push and Skb_put

How to score, we used the Skb_push ()

unsigned char *skb_push (struct sk_buff *skb, unsigned int len)
{
    skb->data = len;
    Skb->len  = len;
    if (unlikely (skb->data<skb->head))
        skb_under_panic (SKB, Len, __builtin_return_address (0));
    Return skb->data;
}

See the implementation, we know, call this function to subdivide space, must be in strict accordance with the format of the data frame to divide
//Ethernet Frame Head | Network Layer Header | Transport Layer Header | Application layer data
//So first you have to subdivide the application layer data, and finally the Ethernet frame head
//eg ,
 pdata = Skb_push (SKB, Pkt_len);
 UDPH = (struct udphdr*) skb_push (SKB, sizeof (struct UDPHDR));
 Iph = (struct iphdr*) skb_push (SKB, sizeof (struct IPHDR));
 ETHDR = (struct ethhdr*) skb_push (SKB, sizeof (struct ETHHDR));

If the front you understand, know the sk_buff of the data space layout, this function a look at the know. Well, there are several Len in the Sk_buff, representing the length of the payload, the length of each protocol head, and the length.

And look at skb_put ()

unsigned char *skb_put (struct sk_buff *skb, unsigned int len)
{
    unsigned char *tmp = Skb_tail_pointer (SKB);
    Skb_linear_assert (SKB);
    Skb->tail = len;
    Skb->len  = len;
    if (Unlikely (Skb->tail > Skb->end))
        skb_over_panic (SKB, Len, __builtin_return_address (0));
    return tmp;
}
Looking at the code, here is the tail (the tail pointer to the data), so here is the append data to the tail of the data area,
//And Skb_push () is exactly the reverse

So call Skb_put (), the front skb_reserve () only need to reserve the space of the Ethernet frame head, then call Skb_put (), followed by the subdivision of the network layer Head, protocol layer Head and Payload section.

Two functions are used to subdivide the space, returning the first address pointer after the subdivision space to facilitate subsequent protocol headers and payload data filling.

After the space subdivision is a simple protocol layer field fill and payload fill.

As you can see, several important functional interfaces for creating SKB are:
ALLOC_SKB, Skb_reserver, Skb_push, Skb_put
The following three functions are actually simple to modify the pointer operation.

The previous and this article is to create a skb ourselves, in fact we can also copy (Skb_copy ()) received the SKB, and then targeted changes sent out. Or directly modify the received SKB. due to the received SKB, the space has been subdivided, we do not need the above three functions, directly call the following functions to navigate to the various protocol layer head:

Static inline struct ETHHDR *eth_hdr (const struct sk_buff);
Static inline struct IPHDR *ip_hdr (const struct sk_buff);
Static inline struct TCPHDR *tcp_hdr (const struct sk_buff);
Static inline struct UDPHDR *udp_hdr (const struct sk_buff);
...

Then the specific changes can be, the rest of the principle is similar, here is not an additional introduction.

Resources:
"Deep understanding of Linux network technology inside"
Http://www.2cto.com/os/201502/376226.html

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.