How SKB works

Link From :~davem/skb_data.html

This first diagram illustrates the layout of the SKB data area and where in that area the various pointers in ‘struct sk_buff’ point.

The rest of this page will walk through what the SKB data area looks like in a newly allocated SKB. How to modify those pointers to add headers, add user data, and pop headers.

Also, we will discuss how page non-linear data areas are implemented. We will also discuss how to work with them. skb = alloc_skb(len, GFP_KERNEL);

This is what a new SKB looks like right after you allocate it using alloc_skb()

As you can see, the head, data, and tail pointers all point to the beginning of the data buffer. And the end pointer points to the end of it. Note that all of the data area is considered tail room.

The length of this SKB is zero, it isn’t very interesting since it doesn’t contain any packet data at all. Let’s reserve some space for protocol headers using skb_reserve() skb_reserve(skb, header_len);

This is what a new SKB looks like right after the skb_reserve() call.

Typically, when building output packets, we reserve enough bytes for the maximum amount of header space we think we’ll need. Most IPV4 protocols can do this by using the socket value sk->sk_prot->max_header.

When setting up receive packets that an ethernet device will DMA into, we typically call skb_reserve(skb, NET_IP_ALIGN). By default NET_IP_ALIGN is defined to ‘2’. This makes it so that, after the ethernet header, the protocol header will be aligned on at least a 4-byte boundary. Nearly all of the IPV4 and IPV6 protocol processing assumes that the headers are properly aligned.

Let’s now add some user data to the packet. unsigned char *data = skb_put(skb, user_data_len);int err = 0;skb->csum = csum_and_copy_from_user(user_pointer, data,user_data_len, 0, &err);if (err)goto user_fault;

This is what a new SKB looks like right after the user data is added.

skb_put() advances ‘skb->tail’ by the specified number of bytes, it also increments ‘skb->len’ by that number of bytes as well. This routine must not be called on a SKB that has any paged data. You must also be sure that there is enough tail room in the SKB for the amount of bytes you are trying to put. Both of these conditions are checked for by skb_put() and an assertion failure will trigger if either rule is violated.

The computed checksum is remembered in ‘skb->csum’. Now, it’s time to build the protocol headers. We’ll build a UDP header, then one for IPV4. struct inet_sock *inet = inet_sk(sk);struct flowi *fl = &inet->cork.fl;struct udphdr *uh;skb->h.raw = skb_push(skb, sizeof(struct udphdr));uh = skb->h.uhuh->source = fl->fl_ip_sport;uh->dest = fl->fl_ip_dport;uh->len = htons(user_data_len);uh->check = 0;skb->csum = csum_partial((char *)uh,sizeof(struct udphdr), skb->csum);uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst,user_data_len, IPPROTO_UDP, skb->csum);if (uh->check == 0)uh->check = -1;

This is what a new SKB looks like after we push the UDP header to the front of the SKB.

skb_push() will decrement the ‘skb->data’ pointer by the specified number of bytes. It will also increment ‘skb->len’ by that number of bytes as well. The caller must make sure there is enough head room for the push being performed. This condition is checked for by skb_push() and an assertion failure will trigger if this rule is violated.

Now, it’s time to tack on an IPV4 header. struct rtable *rt = inet->cork.rt;struct iphdr *iph;skb->nh.raw = skb_push(skb, sizeof(struct iphdr));iph = skb->nh.iph;iph->version = 4;iph->ihl = 5;iph->tos = inet->tos;iph->tot_len = htons(skb->len);iph->frag_off = 0;iph->id = htons(inet->id++);iph->ttl = ip_select_ttl(inet, &rt->u.dst);iph->protocol = sk->sk_protocol; /* IPPROTO_UDP in this case */iph->saddr = rt->rt_src;iph->daddr = rt->rt_dst;ip_send_check(iph);skb->priority = sk->sk_priority;skb->dst = dst_clone(&rt->u.dst);

This is what a new SKB looks like after we push the IPv4 header to the front of the SKB.

Just as above for UDP, skb_push() decrements ‘skb->data’ and increments ‘skb->len’. We update the ‘skb->nh.raw’ pointer to the beginning of the new space, and build the IPv4 header.

This packet is basically ready to be pushed out to the device once we have the necessary information to build the ethernet header (from the generic neighbour layer and ARP). 慢慢学会了长大。流转的时光,

How SKB works

相关文章:

你感兴趣的文章:

标签云: