struct sk_buff 学习

本文深入解析Linux内核中sk_buff数据结构,详细介绍了其成员变量的功能,并解释了sk_buff在链表中的布局及其管理函数。此外,还探讨了sk_buff在不同网络层中的应用及其实现细节。

struct sk_buff 学习
1.sk_buff是linux 网络内核里面最终要的数据结构了.存放要发送和接收的数据.头文件 linux/skbuff.h
2.主要成员以及相关结构函数分为以下几类
a.layout        
    struct sk_buff *next;
    struct sk_buff *prev;
    struct sk_buff_head* list;    方便找到表头
    __u32 qlen;            双链表里sk_buff结构的数量
    spinlock_t lock;        保证操作链表安全
    struct sock *sock;        指向tcp udp socket结构,如果数据被转发的话,该指针为NULL
    unsigned int len;        整个sk_buff链data_len的总和
    unsigned int data_len;        当前sk_buff的数据长度.包含协议头部内容.各层传输时大小会变化
    unsigned int mac_len;        mac头部大小
    atomic_t users;            引用计数.(skb_get kfree_skb改变)
    unsigned int truesize;        data大小 + sizeof(sk_buff)
    unsigned char *head;
    unsigned char *data;
    unsigned char *tail;
    unsigned char *end; 以上都是数据段的指针
    void (*destructor)(...)        当sk_buff某个socket的时候被初始化,通常执行sock_rfree或者sock_wfree
b.general
    struct timeval stamp;        接收到数据时时间
    struct net_device *dev;        网络设备,也很重要
    struct net_device *input_dev;    输入设备
    struct net_device *real_dev;    可用于虚拟设备
    /* application layer header */
    union
        {
                struct tcphdr *th;
                struct udphdr *uh;
                struct icmphdr *icmph;
                struct igmphdr *igmph;
                struct iphdr *ipiph;
                struct spxhdr *spxh;
                unsigned char *raw;
        } h;
 
        /* Network layer header */
        union
        {
                struct iphdr *iph;
                struct ipv6hdr *ipv6h;
                struct arphdr *arph;
                struct ipxhdr *ipxh;
                unsigned char *raw;
        } nh;
 
        /* Link layer header */
        union
        {
                struct ethhdr *ethernet;
                unsigned char *raw;
        } mac;
    struct dst_entry dst;        路由子系统使用,复杂
    char cb[40];            控制缓冲区或者存放隐私信息,例如tcp用它来存放一个struct_skb_cb的结构体
    struct tcp_skb_cb {
            ... ... ...
             _ _u32 seq; /* Starting sequence number */
          _ _u32 end_seq; /* SEQ + FIN + SYN + datalen*/
         _ _u32 when; /* used to compute rtt's */
         _ _u8 flags; /* TCP header flags. */
         ... ... ...
    };
    unsigned int csum;
    unsigned char ip_summed;
    unsigned char cloned;        该sk_buff是否克隆的
    unsigned char pkt_type;        根据L2层的目的地址判断,该数据包的类型,本机的,多播,广播,其他主机
    __u32 priority;            发送和转发的QoS
    unsigned short protocol;    L2层的协议类型.通常是ip ip6 arp rarp
    unsigned short security;    IPSec,未使用
c.feature-specific
    unsigned long nfmark;
    __u32 nfcache;
    __u32 nfctinfo;
    struct nf_conntrack *nfct;
    unsigned int nfdebug;
    struct nf_bridge_info *nf_bridge;
    以上字段netfilter模块使用.
    union {...} private         HIPPI使用
    __u32 tc_index;
    __u32 tc_verd;
    __u32 tc_classid;
    以上字段用于traffic control
    struct sec_path *sp;        用于IPSec跟踪传输
        
d.manegement functions
    sk_put                L2层接收数据时,将除了数据帧头部(已经拷贝)的内容包考到sk_buff数据缓冲区
    sk_push                发送数据时,高层->低层添加头部(data指针改变)
    sk_pull                接收数据时,低层->高层去掉头部(data指针改变)
    sk_reserve            L2层开始接收数据前,保持4字节对齐,data += 2

    alloc_skb dev_alloc_skb        分配空间函数,默认用dev_alloc_skb.分配的空间包括两次,第一个是struct sk_buff,第二个是data_size + sizeof(struct skb_shared_info)
    kfree_skb dev_kfree_skb        释放sk_buff内存
    struct skb_shared_info {    紧跟着data缓冲区后面,保存data缓冲区的相关信息的结构体
        atomic_t dataref;
        unsigned int nr_frags;
        unsigned short tso_size;
        unsigned short tso_seqs;
        unsigned sk_buff *frag_list;
        skb_frag_t frags[MAX_SKB_FRAGS];
    };
    clone和copy
    clone:数据需要给其他的使用者时候(不会改变数据内容),会采用clone.分配一个新的sk_buff,并且    cloned属性为1,users属性为1,保证不要的时候释放内存.head data等仍然指向以前的data缓冲区.但是    保存data缓冲区的
    struct skb_shared_info的dataref需要加一.
    copy:其他使用者需要改变data缓冲区的数据的时候使用.分配两块新的内存.不会设置clone位
    相关函数:skb_clone pskb_copy(拷贝当前data缓冲区) skb_copy(拷贝所有data缓冲区)

    skb_queue_head_init        初始化一个空链表    
    skb_queue_head skb_queue_tail    添加sk_buff到链表
    skb_dequeue skb_dequeue_tail    删除sk_buff从链表
    skb_queue_purge            清空sk_buff链表
    skb_queue_walk            循环链表
    进行这些函数的时候需要使用 :
    unsigned long flags;
    spin_lock_irqsave(...);
    function();
    spin_unlock_irqrestore(...);
    spin的作用在单处理器上,关中断.多处理器上, 通过一个原子变量,保证函数的执行安全.

 
### ### struct sk_buff 结构体定义及作用 `struct sk_buff` 是 Linux 内核中用于管理网络数据包的核心结构体之一,广泛应用于网络协议栈中。该结构体不仅包含了数据包的元信息,还负责管理数据包在内存中的存储和传输过程。 #### 结构体定义 `struct sk_buff` 的定义位于 Linux 内核源码中,通常位于 `<linux/skbuff.h>` 头文件内。其结构较为复杂,包含多个成员变量,用于描述数据包的属性和状态。以下是一个简化的定义示例: ```c struct sk_buff { struct sk_buff *next; struct sk_buff *prev; ktime_t tstamp; struct sock *sk; struct net_device *dev; unsigned int len, data_len; __u16 mac_len, hdr_len; __u16 queue_mapping; __u8 ip_summed; __be16 protocol; void (*destructor)(struct sk_buff *skb); char cb[48]; skb_data_end_t tail; skb_data_end_t end; unsigned char *head, *data; unsigned int truesize; atomic_t users; }; ``` 该结构体中的 `next` 和 `prev` 成员变量用于将 `sk_buff` 组织成双向链表[^2]。此外,`head` 和 `data` 指针分别指向数据包的起始地址和当前数据的起始地址,而 `len` 和 `data_len` 用于记录数据包的长度信息。 #### 作用 `struct sk_buff` 的主要作用是封装网络数据包,并在协议栈的不同层级之间传递。其设计目标包括: 1. **高效的数据包管理**:通过 `next` 和 `prev` 指针,`sk_buff` 可以被组织成双向链表,使得数据包在不同队列之间的移动无需复制整个缓冲区,只需修改指针即可[^1]。例如,在 USB 网络设备驱动中,`struct usbnet` 使用 `struct sk_buff_head` 管理接收队列 (`rxq`)、发送队列 (`txq`) 和已完成队列 (`done`) 等。 2. **支持线性与非线性数据区域**:`sk_buff` 的数据部分分为线性区域和非线性区域。线性区域直接存储在 `data` 指针指向的内存中,而非线性区域则由 `skb_shared_info` 结构体管理,用于支持分片和共享数据块[^3]。 3. **提供数据包元信息**:`sk_buff` 中包含多个成员变量,如 `tstamp`(时间戳)、`dev`(网络设备)、`protocol`(协议类型)等,用于记录数据包的传输状态和上下文信息。 4. **支持数据包的生命周期管理**:通过 `users` 引用计数器和 `destructor` 析构函数指针,`sk_buff` 可以安全地在多个模块之间共享,并在使用完成后释放资源。 #### 使用示例 以下是一个简单的示例,展示如何在内核模块中分配和释放 `sk_buff`: ```c #include <linux/skbuff.h> #include <linux/netdevice.h> struct sk_buff *skb = alloc_skb(1500, GFP_KERNEL); if (skb) { skb_put(skb, 100); // 假设数据长度为100字节 // 填充数据到 skb->data // ... kfree_skb(skb); // 释放 sk_buff } ``` 上述代码中,`alloc_skb` 用于分配一个 `sk_buff` 结构体及其关联的数据缓冲区,而 `skb_put` 用于扩展数据区域的长度。最后,`kfree_skb` 用于释放 `sk_buff` 资源。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值