2017年04月26日 18:21:12 abcLinux 阅读数 799
 

This first diagram illustrates the layoutof the SKB data area and where in that area the various pointers in 'structsk_buff' point.

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

Also, we will discuss how page non-lineardata 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 rightafter you allocate it using alloc_skb()

As you can see, the head, data, and tailpointers all point to the beginning of the data buffer. And the end pointerpoints to the end of it. Note that all of the data area is considered tailroom.

The length of this SKB is zero, it isn'tvery interesting since it doesn't contain any packet data at all. Let's reservesome space for protocol headers using skb_reserve()


skb_reserve(skb,header_len);


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

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

When setting up receive packets that anethernet 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 theethernet header, the protocol header will be aligned on at least a 4-byteboundary. Nearly all of the IPV4 and IPV6 protocol processing assumes that theheaders are properly aligned.

Let's now add some user data to thepacket.


unsignedchar *data = skb_put(skb, user_data_len);

interr = 0;

skb->csum= csum_and_copy_from_user(user_pointer, data,

user_data_len, 0, &err);

if(err)

gotouser_fault;


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

skb_put() advances 'skb->tail' by the specified number of bytes, it alsoincrements 'skb->len' by that number of bytes as well. This routine must notbe called on a SKB that has any paged data. You must also be sure that there isenough tail room in the SKB for the amount of bytes you are trying to put. Bothof 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 UDPheader, then one for IPV4.


structinet_sock *inet = inet_sk(sk);

structflowi *fl = &inet->cork.fl;

structudphdr *uh;

skb->h.raw= skb_push(skb, sizeof(struct udphdr));

uh= skb->h.uh

uh->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 wepush the UDP header to the front of the SKB.

skb_push() will decrement the 'skb->data' pointer by the specified number ofbytes. 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 beingperformed. 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.


structrtable *rt = inet->cork.rt;

structiphdr *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 SKBlooks like after we push the IPv4 header to the front of the SKB.

Just as above for UDP, skb_push() decrements 'skb->data' andincrements 'skb->len'. We update the 'skb->nh.raw' pointer to the beginningof the new space, and build the IPv4 header.

This packet is basically ready to bepushed out to the device once we have the necessary information to build theethernet header (from the generic neighbour layer and ARP).


Things start to get a little bit morecomplicated once paged data begins to be used. For the most part the ability touse [page, offset, len] tuples for SKB data came about sothat file system file contents could be directly sent over a socket. But, as itturns out, it is sometimes beneficial to use this for nomal buffering ofprocess sendmsg() data.

It must be understood that once paged datastarts to be used on an SKB, this puts a specific restriction on all future SKBdata area operations. In particular, it is no longer possible to do skb_put() operations.

We will now mention that there areactually two length variables assosciated with an SKB, len and data_len. The latter onlycomes into play when there is paged data in the SKB. skb->data_len tells how many bytes of paged datathere are in the SKB. From this we can derive a few more things:

  • The existence of paged data in an SKB is indicated by skb->data_len being non-zero. This is codified in the helper routine skb_is_nonlinear() so that it the function you should use to test this.
  • The amount of non-paged data at skb->data can be calculated as skb->len - skb->data_len. Again, there is a helper routine already defined for this called skb_headlen() so please use that.

The main abstraction isthat, when there is paged data, the packet begins at skb->data for skb_headlen(skb) bytes, thencontinues on into the paged data area for skb->data_len bytes. That is why it is illogicalto try and do an skb_put(skb) when there is pageddata. You have to add data onto the end of the paged data area instead.

Each chunk of paged data in an SKB isdescribed by the following structure:

struct skb_frag_struct {

structpage *page;

__u16page_offset;

__u16size;

};

There is a pointer to thepage (which you must hold a proper reference to), the offset within the pagewhere this chunk of paged data starts, and how many bytes are there.

The paged frags are organized into anarray in the shared SKB area, defined by this structure:

#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2)

struct skb_shared_info {

atomic_tdataref;

unsignedint   nr_frags;

unsignedshort tso_size;

unsignedshort tso_segs;

structsk_buff *frag_list;

skb_frag_t     frags[MAX_SKB_FRAGS];

};

The nr_frags member states howmany frags there are active in the frags[] array. The tso_size and tso_segs is used to convey information to the devicedriver for TCP segmentation offload. The frag_list is used to maintain a chain of SKBs organizedfor fragmentation purposes, it is _not_ used for maintaining paged data. Andfinally the frags[] holds the frag descriptorsthemselves.

A helper routine is available to help youfill in page descriptors.


void skb_fill_page_desc(struct sk_buff *skb,int i,

structpage *page,

intoff, int size)


This fills the i'th page vector to point to page at offset off of size size. It also updates the nr_frags member to be onepast i.

If you wish to simply extend an existingfrag entry by some number of bytes, increment the size member by that amount.


With all of the complications imposed bynon-linear SKBs, it may seem difficult to inspect areas of a packet in astraightforward way, or to copy data out from a packet into another buffer.This is not the case. There are two helper routines available which make thispretty easy.

First, we have:


void*skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer)


You give it the SKB, theoffset (in bytes) to the piece of data you are interested in, the number ofbytes you want, and a local buffer which is to be used _only_ if the data youare interested in resides in the non-linear data area.

You are returned a pointer to the dataitem, or NULL if you asked for an invalid offset and len parameter. Thispointer could be one of two things. First, if what you asked for is directly inthe skb->data linear data area, you are given a directpointer into there. Else, you are given the buffer pointer you passed in.

Code inspecting packet headers on theoutput path, especially, should use this routine to read and interpret protocolheaders. The netfilter layer uses this function heavily.

For larger pieces of data other thanprotocol headers, it may be more appropriate to use the following helperroutine instead.


int skb_copy_bits(const struct sk_buff *skb,int offset,

void *to, int len);


This will copy thespecified number of bytes, and the specified offset, of the given SKB into the 'to'buffer. This is used for copies of SKBdata into kernel buffers, and therefore it is not to be used for copying SKBdata into userspace. There is another helper routine for that:


int skb_copy_datagram_iovec(const structsk_buff *from,

int offset, struct iovec *to,

int size);


Here,the user's data area is described by the given IOVEC. The other parameters arenearly identical to those passed in to skb_copy_bits() above.

http://vger.kernel.org/~davem/skb_data.html

skb head/data/tail/end/介绍的更多相关文章

  1. JS魔法堂:Data URI Scheme介绍

    一.前言 上周五公司内部的Any Topic Conf.上我和同事们分享了这个主题,有同事说这个有用,有同事说这个没啥用,后来还延伸到网站性能的话题上,大家讨论的激烈程度让我觉得这次选题还不错.本篇先 ...

  2. Python pandas 0.19.1 Intro to Data Structures 数据结构介绍 文档翻译

    官方文档链接http://pandas.pydata.org/pandas-docs/stable/dsintro.html 数据结构介绍 我们将以一个快速的.非全面的pandas的基础数据结构概述来 ...

  3. 二维码Data Matrix简单介绍及在VS2010中的编译

    Data Matrix 二维条码原名Datacode,由美国国际资料公司(International Data Matrix, 简称ID Matrix)于1989年发明.Data-Matrix二维条码 ...

  4. C++数据类型(data type)介绍

    在编写程序时,数据类型(data type)定义了使用存储空间的(内存)的方式. 程序员通过定义数据类型(data type),告诉特定存储空间这里要存储的数据类型是什么,以及你即将操作他的方式.(注 ...

  5. Spring整合Hibernate实现Spring Data JPA (介绍和使用)

    Spring Data JPA是Spring基于Hibernate开发的一个JPA框架.如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便. 但是Sprin ...

  6. UiPath数据抓取Data Scraping的介绍和使用

    一.数据抓取(Data Scraping)的介绍 使用截据抓取使您可以将浏览器,应用程序或文档中的结构化数据提取到数据库,.csv文件甚至Excel电子表格中. 二.Data Scraping在UiP ...

  7. Spring Data Redis整体介绍 (一)

    为什么使用Spring Data Redis 首先Spring Data Redis 是Spring 框架提供的用于操作Redis的客户端. Spring框架是一个全栈Java程序框架,通过DI.AO ...

  8. Landsat 现有 Analysis Ready Data (ARD) 数据介绍

    Global Web-Enabled Landsat Data (GWELD)[1] NASA 原先的 Web-Enabled Landsat Data Conterminous U.S. Seaso ...

  9. 【转】 关于data factory的介绍——即如何快速生成大批量数据

    上次在我的博客中讲述了quest公司的spotlight系列软件,这次来扯淡一下quest公司的另一测试辅助软件 datafactory(数据工厂),顾名思义,数据工厂是生产数据的,主要应用领域是性能 ...

随机推荐

  1. java实现工程配置文件敏感字段加解密

    以下引自他人博客: 1. 需求背景我们在开发应用时,需要连接数据库,一般把数据库信息放在一个属性配置文件中,比如***.properties,具体的内容 #mysql的配置文件jdbc.url=jdb ...

  2. (二十三)JSP指令

    一.JSP指令 1.1 JSP指令 JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分 1.2 在JSP 2.0规范中共 ...

  3. CCF 201803-1 跳一跳

    题目: 问题描述 近来,跳一跳这款小游戏风靡全国,受到不少玩家的喜爱. 简化后的跳一跳规则如下:玩家每次从当前方块跳到下一个方块,如果没有跳到下一个方块上则游戏结束. 如果跳到了方块上,但没有跳到方块 ...

  4. JavaScript检测浏览器

    Detect Browser <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> ...

  5. Go 代码风格和规范

    Go 语言写起来类似于C语言,因此熟悉C语言及其派生语言(C++.C#.Objective-C 等)的人都会迅速熟悉这门语言 编码风格 标识符命名规范 在习惯上,Go语言程序员推荐使用驼峰式命名,当名 ...

  6. 基于【 centos7】一 || 安装ELK

    一.安装jdk 上传安装包并解压:tar -zxvf ... 配置环境变量: 在配置文件中添加如下配置信息:vi /etc/profile export JAVA_HOME=/usr/local/jd ...

  7. <script> 为什么不再使用 type="text/javascript" 【问题】

    1.为什么在 <script> 标签中不需要使用 type="text/javascript" 就可以写jQuery代码 ? <head> <scri ...

  8. 4.Java集合-ArrayList实现原理及源码分析

    一.ArrayList概述: ArrayList 是基于数组实现的,是一个动态数组,其容量能自动增长,类似于C语言中的动态申请内存,动态增长内存 ArrayList不是线程安全的,只能用在单线程的情况 ...

  9. SpringDataJPA第三天讲义

    第1章     Specifications动态查询 有时我们在查询某个实体的时候,给定的条件是不固定的,这时就需要动态构建相应的查询语句,在Spring Data JPA中可以通过JpaSpecif ...

  10. Vue.js面试题整理(转载)

    一.什么是MVVM? MVVM是Model-View-ViewModel的缩写.MVVM是一种设计思想.Model 层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑:View 代表UI ...