Linux内核网络源码解析2——sk_buff操作
Linux内核源码学习,套接字缓存sk_buff的操作函数
前言
上一篇解析了sk_buff的结构体成员,这一篇就来解析sk_buff的操作函数。
分配sk_buff:alloc_skb()
函数声明:
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
int fclone, int node)
- size,待分配sk_buff的线性存储区的长度
- gfp_mask,分配内存的方式
- fclone,预测是否会克隆,用于确定从哪个高速缓存中分配
- node,当支持NUMA(非均匀质存储结构)时,用于确定何种区域中分配sk_buff
图中padding是为了对齐而填充的区域,填充区域上面区域的大小为size
释放sk_buff:kfree_skb()
函数声明:
void kfree_skb(struct sk_buff *skb)
只在 skb->users 为1的情况下才释放内存,否则只是简单的递减
为协议首部预留空间:skb_reserve()
在数据缓存区头部预留一定的空间,只能用于空的sk_buff
只是简单地更新了分别指向负载起始和结尾的data和tail指针
添加用户之前调用:skb_put()
例子:
unsigned char *data = skb_put(skb, user_data_len);
memcpy(data, 0x11, user_data_len);
修改tail指针,下移len字节,同时更新数据区长度len
添加首部:skb_push()
例子:
unsigned char *tcp_header = skb->push(skb, sizeof(struct udphdr));
struct tcphdr *tcp;
tcp = tcp_header;
tcp->source = htons(1025);
tcp->dest = htons(2095);
tcp->len = htons(user_data_len);
tcp->check = 0;
忽略其他层的头部:skb_pull()
将data指针往下移动,在数据区首部忽略len字节长度的数据,通常用于接收的数据包后在各层由下往上传递时,上层忽略下层的首部
小结
克隆sk_buff:skb_clone()
只复制sk_buff描述符,同时增加数据缓存区的引用计数
拷贝sk_buff及其数据:pskb_copy() & skb_copy()
- 修改的数据在skb->head和skb->end之间,可使用pskb_copy()来复制这部分数据
- 如果同时需要修改聚合分散IO存储区中的数据,就必须使用skb_copy()
添加尾部数据:skb_add_data()
将指定用户空间的数据添加到skb_buff的数据缓存区的尾部
删除尾部数据:skb_trim()
与skb_add_data()操作相反
拆分数据:skb_split()
根据指定长度拆分sk_buff,使得原sk_buff中的数据长度为指定长度,剩下的数据保存到拆分得到的sk_buff中
LEN:拆分长度,hlen:线性数据长度 + 当拆分数据的长度小于线性数据长度时,直接拆分线性数据区即可
- 拆分数据的长度大于线性数据长度时,则需要拆分非线性区域中的数据,拆分长度LEN大于hlen并且LEN小于hlen+S1
其它函数
There are a bunch of skb support functions provided by the sk_buff layer.
allocation / free / copy / clone and expansion functions
struct sk_buff *alloc_skb(unsigned int size, int gfp_mask) +This function allocates a new skb. This is provided by the skb layer to initialize some privat data and do memory statistics. The returned buffer has no headroom and a tailroom of /size/ bytes.
void kfree_skb(struct sk_buff *skb) +Decrement the skb’s usage count by one and free the skb if no references left.
struct sk_buff *skb_get(struct sk_buff *skb) +Increments the skb’s usage count by one and returns a pointer to it.
struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) +This function clones a skb. Both copies share the packet data but have their own struct sk_buff. The new copy is not owned by any socket, reference count is 1.
struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
- Makes a real copy of the skb, including packet data. This is needed, if You wish to modify the packet data. Reference count of the new skb is 1.
struct skb_copy_expand(const struct sk_buff *skb, int new_headroom, int new_tailroom, int gfp_mask)
- Make a copy of the skb, including packet data. Additionally the new skb has a haedroom of /new_headroom/ bytes size and a tailroom of /new_tailroom/ bytes.
anciliary functions
int skb_cloned(struct sk_buff *skb)
- Is the skb a clone?
int skb_shared(struct sk_Buff *skb)
- Is this skb shared? (is the reference count > 1)?
operations on lists of skb’s
struct sk_buff *skb_peek(struct sk_buffhead *list)
- peek a skb from front of the list; does not remove skb from the list
struct sk_buff *skb_peek_tail(struct sk_buffhead *list)
- peek a skb from tail of the list; does not remove sk from the list
__u32 skb_queue_len(sk_buffhead *list)
- return the length of the given skb list
void skb_queue_head(struct sk_buffhead *list, struct sk_buff *newsk)
- enqueue a skb at the head of a given list
void skb_queue_tail(struct sk_buffhead *list, struct sk_buff *newsk)
- enqueue a skb at the end of a given list.
int skb_headroom(struct sk_buff *skb)
- return the amount of bytes of free space at the head of skb
int skb_tailroom(struct sk_buff *skb)
- return the amount of bytes of free space at the end of skb
struct sk_buff *skb_cow(struct sk_buff *skb, int headroom)
- if the buffer passed lacks sufficient headroom or is a clone it is copied and additional headroom made available.
void struct sk_buff *skb_dequeue(struct sk_buffhead *list)
- skb_dequeue() takes the first buffer from a list (dequeue a skb from the head of the given list) If the list is empty a NULL pointer is returned. This is used to pull buffers off queues. The buffers are added with the routines skb_queue_head() andskb_queue_tail().
struct sk_buff *sbk_dequeue_tail(struct sk_buffhead *list)
- dequeue a skb from the tail of the given list
总结
这篇笔记包括了大部分sk_buff的操作函数,为以后使用打下基础