在Linux网络代码中,struct sk_buff 代表已接收或正要传输的数据的报头。
Defined in <include/linux/skbuff.h>, <net/core/skbuff.c>
- used by every network layer (except physical layer)
- field of the structure change as it is passed from one layer to another, i.e., fields are layer dependent.
当sk_buff从协议栈的一层传到下一层时,会附加一个该层协议的报头:附加报头比把数据从一层copy到另一层更有效率。
后续可以看到,内核中使用skb_reserve
函数来保证sk_buff在传到下层时有足够的预留空间以保存后续的报头。
sk_buffer结构中的字段很多,但大致可分为几种类型:
- 布局(Layout)
- 通用(General)
- 功能专用(Feature-specific)
- 管理函数(Management functions)
Layout of sk buffer :
The kernel maintains all sk_buff structures in a doubly linked list.
struct sk_buff_head {
struct sk_buff *next;
struct sk_buff *prev;
__u32 qlen; //表中元素的数目
spinlock_t lock; //防止对表的并发访问
}
sk_buff_head结构之所以存在,是因为sk_buff双向链表的一项要求:sk_buff结构必需能够迅速找出整个表的头。
sk_buff_head本身也是双向链表中的一个node。
每个sk_buff结构都包含一个指针,指向sk_buff_head结构,此指针名为list
。
struct sk_buff {
struct sk_buff *next;
struct sk_buff *prev;
/* represents the Rx/Tx device interface corresponding
to the packet. */
struct net_device *dev;
/* structure of the socket that owns this buffer. */
struct sock *sk;
/* This is the control buffer, or storage for private
information, maintained by each layer for internal use. */
char cb[48] __aligned(8);
/* include both the data in the main buffer(i.e. the one
pointed to by head) and the data in the fragments. */
unsigned int len;
/* unlike len, data_len accounts only for the size of the
data in the fragments. */
unsigned int data_len;
/* size of mac header. */
unsigned int mac_len;
/* pointers to protocol headers. */
__u16 transport_header;
__u16 network_header;
__u16 mac_header;
sk_buff_data_t tail;
sk_buff_data_t end;
unsigned char *head, *data;
/* total size of this buffer (including sk_buff itself) */
unsigned int truesize;
/* the number of entities using this sk_buff buffer. */
refcount_t users;
}
Control block example:
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 */
...
}
Management functions :
Each of the above 4 memory management functions return the data pointer.
Memory allocation :
Initializing buffer :
Clone && Copy of buffer
当同一个buffer需要由不同消费者个别处理时,那些消费者可能需要修改sk_buff descriptor的内容,但内核不需要完全copy sk_buff结构和其关联的数据缓冲区。
相反,为了效率,内核可以clone原始值,即值copy sk_buff结构,然后使用引用计数,以避免过早释放共享的数据块。
缓冲区的clone由skb_clone
函数实现。

Walkthrough Reception :
网友评论