转载博客连接地址
套接字缓存之skb_put、skb_push、skb_pull、skb_reserve
skb操作中的预留和对齐操作主要由skb_put、skb_push、skb_pull、skb_reserve完成;这几个函数的区别通过下面图(图片来自:深入理解linux网络技术内幕)可以清晰的区分;另外,需要注意的是skb_reserve只能操作空skb,即在分配了空间,尚未填充数据时调用;
以下为四个函数的源码分析;
1 /**
2 * skb_put - add data to a buffer
3 * @skb: buffer to use
4 * @len: amount of data to add
5 *
6 * This function extends the used data area of the buffer. If this would
7 * exceed the total buffer size the kernel will panic. A pointer to the
8 * first byte of the extra data is returned.
9 */
10 /*
11 向skb尾部添加数据
12 */
13 unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
14 {
15 /* 获取当前skb->tail */
16 unsigned char *tmp = skb_tail_pointer(skb);
17
18 /* 要求skb数据区必须为线性 */
19 SKB_LINEAR_ASSERT(skb);
20
21 /* skb尾部增加len字节 */
22 skb->tail += len;
23 /* skb数据总长度增加len字节 */
24 skb->len += len;
25
26 /* 如果增加之后的tail > end ,则panic */
27 if (unlikely(skb->tail > skb->end))
28 skb_over_panic(skb, len, __builtin_return_address(0));
29
30 //返回添加数据的第一个字节位置
31 return tmp;
32 }
1 /**
2 * skb_push - add data to the start of a buffer
3 * @skb: buffer to use
4 * @len: amount of data to add
5 *
6 * This function extends the used data area of the buffer at the buffer
7 * start. If this would exceed the total buffer headroom the kernel will
8 * panic. A pointer to the first byte of the extra data is returned.
9 */
10 /*
11 向skb数据区头部添加数据
12 */
13 unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
14 {
15 /* 数据区data指针前移len字节 */
16 skb->data -= len;
17 /* 数据总长度增加len字节 */
18 skb->len += len;
19
20 /* 添加数据长度溢出过header ,panic*/
21 if (unlikely(skb->data<skb->head))
22 skb_under_panic(skb, len, __builtin_return_address(0));
23
24 /* 返回新的data指针 */
25 return skb->data;
26 }
1 /**
2 * skb_pull - remove data from the start of a buffer
3 * @skb: buffer to use
4 * @len: amount of data to remove
5 *
6 * This function removes data from the start of a buffer, returning
7 * the memory to the headroom. A pointer to the next data in the buffer
8 * is returned. Once the data has been pulled future pushes will overwrite
9 * the old data.
10 */
11 /*
12 从数据区头部移除数据
13 */
14 unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
15 {
16 return skb_pull_inline(skb, len);
17 }
```c
1 /* 根据移除数据长度判断函数调用 */
2 static inline unsigned char *skb_pull_inline(struct sk_buff *skb, unsigned int len)
3 {
4 /*
5 移除长度> skb数据总长度,返回NULL
6 否则,继续调用_skb_pull函数
7 */
8 return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len);
9 }
```c
1 /* 从skb数据区头部移除数据 */
2 static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len)
3 {
4 /* 数据总长度减去len字节 */
5 skb->len -= len;
6 /* 数据总长度是否有异常 */
7 BUG_ON(skb->len < skb->data_len);
8
9 /*
10 data指针移动len字节
11 返回移除之后新的data指针
12 */
13 return skb->data += len;
14 }
1 /*
2 保留头部空间,只能对空的skb使用
3 */
4 static inline void skb_reserve(struct sk_buff *skb, int len)
5 {
6 /* 数据区data指针增加len字节*/
7 skb->data += len;
8 /* 数据区tail指针增加len字节 */
9 skb->tail += len;
10 }