网络驱动移植之sk_buff结构体及其相关操作函数(上)

来源:互联网 发布:拯救与逍遥 知乎 编辑:程序博客网 时间:2024/05/17 23:55

    开发平台:Ubuntu11.04

    编译器:gcc version 4.5.2 (Ubuntu/Linaro 4.5.2-8ubuntu4)

    内核源码:linux-2.6.38.8.tar.bz2

 

    struct sk_buff是Linux操作系统网络相关代码中最重要的结构体之一,用于管理已接收或正要传输的网络数据包。此结构体定义在include/linux/skbuff.h头文件中。

    1、结构体成员 

struct sk_buff*next;struct sk_buff*prev;

    内核通过一个双向链表来维护所有的sk_buff结构体,所以每个sk_buff结构体都使用next和prev这两个成员来实现与这个双向链表的联系。 

ktime_ttstamp;

    时间戳记,常用于表示数据包何时被接收。 

struct sock*sk;

    当数据在本地产生或者正由本地进程接收时,TCP或UDP以及用户程序就会使用sk这个指针。 

struct net_device*dev;

    当接收数据包时,驱动程序使用接收设备的结构体变量更新此成员;当发送一个数据包时,此成员代表的是发送数据包的设备。 

charcb[48] __aligned(8);

    控制缓冲区(controlbuffer),每一层都可以使用它来存储私有数据。 

unsigned long_skb_refdst;

    dst引用计数。 

#ifdef CONFIG_XFRMstructsec_path*sp;#endif

    由IPsec协议组使用,以记录转换信息。 

unsigned intlen,data_len;__u16mac_len,hdr_len;

    len是缓冲区以及一些片段的总长度,data_len只是一些片段的长度,mac_len是MAC报头的长度,hdr_len是克隆skb时可写报头的长度。 

union {__wsumcsum;struct {__u16csum_start;__u16csum_offset;};};

    校验和以及相关的状态标识。 

__u32priority;

    此成员表示正被传输或转发的数据包QoS等级。 

kmemcheck_bitfield_begin(flags1);__u8local_df:1,cloned:1,ip_summed:2,nohdr:1,nfctinfo:3;__u8pkt_type:3,fclone:2,ipvs_property:1,peeked:1,nf_trace:1;kmemcheck_bitfield_end(flags1);kmemcheck_bitfield_begin(flags2);__u16queue_mapping:16;#ifdef CONFIG_IPV6_NDISC_NODETYPE__u8ndisc_nodetype:2,deliver_no_wcard:1;#else__u8deliver_no_wcard:1;#endif__u8ooo_okay:1;kmemcheck_bitfield_end(flags2);

    各种标识(至于这些标识的用法,在以后用到时再加以说明)。

    kmemcheck_bitfield_begin和kmemcheck_bitfield_end分别用于定义零长数组,以确定这些成员的起始和终止的位置。 它们的源代码如下所示:

/* linux-2.6.38.8/include/linux/kmemcheck.h */#define kmemcheck_bitfield_begin(name)\int name##_begin[0];#define kmemcheck_bitfield_end(name)\int name##_end[0];

    使用零长数组实现此功能的类似代码如下: 

#include <stdio.h>struct test {    int len1;    char ch_start[0];    char ch1;    char ch2;    char ch_end[0];    int len2;};int main(void){    char *p;    int i;    struct test test_value = {.ch1 = 'a',.len1 = 1,.len2 = 2,.ch2 = 'b',    };    for (p = test_value.ch_start, i = 0;     p < test_value.ch_end; p++, i++)printf("*(p + %d) = %c\n", i, *p);    return 0;}

    例子输出结果:

*(p + 0) = a*(p + 1) = b
__be16protocol;

    由于每种协议都有自己处理接收数据包的处理函数,因此,驱动程序使用此成员来通知其上层该使用哪个处理函数。 

void(*destructor)(struct sk_buff *skb);

    当此缓冲区被删除时,用它来完成某些工作。 

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)struct nf_conntrack*nfct;#endif#ifdef NET_SKBUFF_NF_DEFRAG_NEEDEDstruct sk_buff*nfct_reasm;#endif#ifdef CONFIG_BRIDGE_NETFILTERstruct nf_bridge_info*nf_bridge;#endif

    这些成员由netfilter相关代码所使用。 

intskb_iif;

    目的地网络设备的ifindex。 

#ifdef CONFIG_NET_SCHED__u16tc_index;/* traffic control index */#ifdef CONFIG_NET_CLS_ACT__u16tc_verd;/* traffic control verdict */#endif#endif

    这些成员由流量控制功能所使用。 

__u32rxhash;

    所接收的数据包的哈希表。 

#ifdef CONFIG_NET_DMAdma_cookie_tdma_cookie;#endif

    a cookie to one of several possible DMAoperations done by skb DMA functions. 

#ifdef CONFIG_NETWORK_SECMARK__u32secmark;#endif

     数据包安全等级标记。 

union {__u32mark;__u32dropcount;};

    通用数据包标记。 

__u16vlan_tci;

    VLAN控制信息。 

sk_buff_data_ttransport_header;sk_buff_data_tnetwork_header;sk_buff_data_tmac_header;

    指向TCP/IP协议栈各协议报头的指针:transport_header指向传输层,network_header指向网络层,mac_header指向链路层。 

sk_buff_data_ttail;sk_buff_data_tend;unsigned char*head,*data;

    这些成员代表缓冲区的边界以及其中的数据,head和end指向已分配缓冲区空间的开端和尾端,而data和tail则指向实际数据的开端和尾端,如下图(图片来自《Understanding Linux Network Internals》):

 

    其中,headroom可插入一个协议报头,tailroom可填入其他新的数据。 

unsigned inttruesize;

    此成员代表缓冲区总的大小,包括sk_buff结构本身。 

atomic_tusers;

    引用计数,避免正在使用时被其它用户所释放掉。

原创粉丝点击