Linux SKB结构体中各个长度字段的含义(len, data_len, headlen, pagelen)

结构体sk_buff是Linux内核网络子系统的一个基本结构体,关于它的长度有很多定义和操作,非常容易弄混,这里给出一个简单的说明。

下面这幅图是《深入理解Linux网络技术内幕》里面的图,一个skb用于存储一个报文,如果一个报文特别大的话,线性存储区放不下就需要多个skb来存储,这就是下面frag_list的作用,保存连续的skb,但是如果内核支持分散聚集技术的话,并且报文长度刚好又不大于mtu,就不必重新分配一个skb来存储,可以使用一些内存碎片来存储,就是下面的frags数组表示的内存页面片段。举一个恰当的例子,一帮弟兄去凑份子,凑份子起点比较高,大哥钱不够,这时候如果有小弟(内核支持分散聚集)并且小弟有钱的话就拿上小弟的钱来凑,但是如果加上小弟的钱也不够的话,大哥就只好去找兄弟去了⊙﹏⊙‖∣。份子钱就好比报文大小,大哥不够小弟来凑,没有小弟(不支持分散聚集)或者小弟钱也不够就只好去找兄弟了,这里需要注意的一点是大哥和小弟的总钱数不能大于MTU,如果大于MTU的话,多出的部分就必须重新分配一个skb来存储(总不能一直找小弟吧)。

skb->len      //大哥、小弟和兄弟的总和,即data的总长度,线性和非线性的总和。
skb->data_len //小弟和兄弟的总和,即大哥缺少的份额,非线性数据长度。
skb_headlen() //即大哥长度,线性长度。和skb_headroom()不一样,这个是只头部空间剩余长度。
skb_pagelen() //大哥和小弟的总和,即线性数据长度和页面碎片的长度,不包括分片skb队列长度。

 

struct sk_buff 是 Linux 内核网络子系统的一个非常重要的数据结构,它代表了内核网络协议栈的一个网络数据包。在 Linux 内核,网络数据包都是封装在 sk_buff 进行传输和处理的,因此可以说 sk_buff 是 Linux 网络子系统最核心的数据结构之一。 下面是 struct sk_buff 结构体的详细说明: ```c struct sk_buff { struct sk_buff *next; /* 下一个 sk_buff */ struct sk_buff *prev; /* 上一个 sk_buff */ ktime_t tstamp; /* 时间戳 */ struct sock *sk; /* socket */ struct net_device *dev; /* 网络设备 */ unsigned long _skb_dst; /* 目标地址 */ unsigned long _skb_src; /* 源地址 */ struct skb_shared_info *shinfo; /* 共享数据 */ atomic_t users; /* 引用计数 */ unsigned int len, data_len; /* 总长度和数据长度 */ __u16 protocol; /* 协议类型 */ __u16 vlan_proto; /* VLAN 协议 */ __u16 vlan_tci; /* VLAN 标记 */ union { __be16 ip4_frag_id; /* IPv4 报文分片标识 */ __u8 hdr_len; /* 首部长度 */ __u16 mac_len; /* MAC 头长度 */ }; __u16 queue_mapping; /* 网络队列映射 */ __u16 tc_index; /* 网络流量控制 */ __u16 pkt_type; /* 数据包类型 */ __u32 priority; /* 优先级 */ __u32 skb_mstamp; /* 时间戳 */ u32 secmark; /* 安全标记 */ unsigned int mark; /* skb 标记 */ unsigned int nf_trace; /* 网络跟踪 */ __u32 hash; /* 哈希值 */ __u16 nfctinfo; /* nf_conntrack 信息 */ __u8 queue_bypass; /* 是否绕队列 */ __u8 protocol_was_802_3; /* 协议是否是 802.3 */ __u8 encapsulation; /* 封装类型 */ __u8 transport_header_was; /* 传输层首部是否有效 */ union { __wsum csum; /* 校验和 */ struct { __u16 csum_start; /* 校验和起始位置 */ __u16 csum_offset; /* 校验和偏移量 */ }; }; union { void *dst; /* 目标地址 */ struct { __be32 saddr; /* 源 IP 地址 */ __be32 daddr; /* 目标 IP 地址 */ } ip4; struct { const void *hdr; /* MAC 头指针 */ const void *payload; /* 数据负载指针 */ } mac; struct { unsigned char *tail; /* 尾部指针 */ unsigned char *end; /* 结束指针 */ }; }; }; ``` 下面是各个字段的详细说明: - next 和 prev 字段:这两个字段分别指向下一个和上一个 sk_buff,用于将 sk_buff 组织成链表。这样可以方便地进行遍历和管理多个 sk_buff。 - tstamp 字段:这个字段表示 sk_buff 的时间戳,记录了 sk_buff 的创建时间。 - sk 字段:这个字段指向一个 socket,表示这个 sk_buff 相关联的 socket。 - dev 字段:这个字段指向一个网络设备,表示这个 sk_buff 是从哪个网络设备接收到的,或者将要发送到哪个网络设备。 - \_skb_dst 和 \_skb_src 字段:这两个字段是目标地址和源地址的指针,分别指向目标地址和源地址的内存空间。 - shinfo 字段:这个字段指向一个 skb_shared_info 结构体,用于共享数据。 - users 字段:这个字段是一个引用计数器,用于记录当前有多少个指针指向这个 sk_buff。 - lendata_len 字段:这两个字段分别表示 sk_buff 的总长度和数据长度。 - protocol 字段:这个字段表示 sk_buff 数据的协议类型,例如 ETH_P_IP 表示 IPv4 协议,ETH_P_ARP 表示 ARP 协议等。 - vlan_proto 和 vlan_tci 字段:这两个字段用于处理 VLAN 标记。 - ip4_frag_id 字段:这个字段用于处理 IPv4 报文分片标识。 - queue_mapping 字段:这个字段表示网络队列映射。 - tc_index 字段:这个字段表示网络流量控制。 - pkt_type 字段:这个字段表示数据包的类型,例如数据包是从网络设备接收而来的、或者是要发送到网络设备的等。 - priority 字段:这个字段表示 sk_buff 的优先级。 - skb_mstamp 字段:这个字段表示 sk_buff 的时间戳,记录了 sk_buff 的最后修改时间。 - secmark 字段:这个字段用于安全标记。 - mark 字段:这个字段用于 skb 标记。 - nf_trace 字段:这个字段用于网络跟踪。 - hash 字段:这个字段用于哈希值。 - nfctinfo 字段:这个字段用于 nf_conntrack 信息。 - queue_bypass 字段:这个字段表示是否绕过队列。 - protocol_was_802_3 字段:这个字段表示协议是否是 802.3。 - encapsulation 字段:这个字段表示封装类型。 - transport_header_was 字段:这个字段表示传输层首部是否有效。 - csum 字段:这个字段用于校验和。 - csum_start 和 csum_offset 字段:这两个字段分别表示校验和的起始位置和偏移量。 - dst 字段:这个字段指向目标地址。 - ip4.saddr 和 ip4.daddr 字段:这两个字段分别表示 IPv4 报文的源 IP 地址和目标 IP 地址。 - mac.hdr 和 mac.payload 字段:这两个字段分别指向 MAC 头和数据负载的指针。 - tail 和 end 字段:这两个字段分别指向 sk_buff 数据的尾部和结束位置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值