Packet buffer 由sk_buff結構描述, Packet buffer Data由其head和end成員界定, 而Packet Data則由Packet Data內data和tail界定的子區域來描述, 採用這種結構可以使添加或去除Packet 頭的操作變得非常方便.
skb_put(skb,len) 在Packet 尾部擴展長度為len的Data block, 返回擴展塊的地址, __skb_put()為未校驗版本
skb_push(skb,len) 在Packet 前部擴展長度為len的Data block, 返回擴展塊的地址, __skb_push()為未校驗版本
skb_pull(skb,len) 去除Packet 前部長度為len的Data block, 返回新Packet 的起始地址, __skb_pull()為未校驗版本
skb_headroom(skb) 返回Packet 前部距離Packet 區開始的長度
skb_tailroom(skb) 返回Packet 尾部距離Packet 區結束的長度
skb_reserve(skb,len) 設置Packet 起始位置為Packet 區開始的len字節
skb_trim(skb,len) 將Packet 截斷為len字節, __skb_trim()為未校驗版本
; include/linux/skbuff.h:
struct sk_buff {
...
unsigned int
len;
/* Length of actual data
*/
unsigned char
*head;
/* Head of buffer
*/
unsigned char
*data;
/* Data head pointer
*/
unsigned char
*tail;
/* Tail pointer
*/
unsigned char
*end;
/* End pointer
*/
...
}
/*
*
Add data to an sk_buff
*/
static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
skb->tail+=len;
skb->len+=len;
return tmp;
}
/**
*
skb_put - add data to a buffer
*
@skb: buffer to use
*
@len: amount of data to add
*
*
This function extends the used data area of the buffer. If this would
*
exceed the total buffer size the kernel will panic. A pointer to the
*
first byte of the extra data is returned.
*/
static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
{
unsigned char *tmp=skb->tail;
skb->tail+=len;
skb->len+=len;
if(skb->tail>skb->end) {
skb_over_panic(skb, len, current_text_addr());
}
return tmp;
}
static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len)
{
skb->data-=len;
skb->len+=len;
return skb->data;
}
/**
*
skb_push - add data to the start of a buffer
*
@skb: buffer to use
*
@len: amount of data to add
*
*
This function extends the used data area of the buffer at the buffer
*
start. If this would exceed the total buffer headroom the kernel will
*
panic. A pointer to the first byte of the extra data is returned.
*/
static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
{
skb->data-=len;
skb->len+=len;
if(skb->datahead) {
skb_under_panic(skb, len, current_text_addr());
}
return skb->data;
}
static inline char *__skb_pull(struct sk_buff *skb, unsigned int len)
{
skb->len-=len;
return
skb->data+=len;
}
/**
*
skb_pull - remove data from the start of a buffer
*
@skb: buffer to use
*
@len: amount of data to remove
*
*
This function removes data from the start of a buffer, returning
*
the memory to the headroom. A pointer to the next data in the buffer
*
is returned. Once the data has been pulled future pushes will overwrite
*
the old data.
*/
static inline unsigned char * skb_pull(struct sk_buff *skb, unsigned int len)
{
if (len > skb->len)
return NULL;
return __skb_pull(skb,len);
}
/**
*
skb_headroom - bytes at buffer head
*
@skb: buffer to check
*
*
Return the number of bytes of free space at the head of an &sk_buff.
*/
static inline int skb_headroom(const struct sk_buff *skb)
{
return skb->data-skb->head;
}
/**
*
skb_tailroom - bytes at buffer end
*
@skb: buffer to check
*
*
Return the number of bytes of free space at the tail of an sk_buff
*/
static inline int skb_tailroom(const struct sk_buff *skb)
{
return skb->end-skb->tail;
}
/**
*
skb_reserve - adjust headroom
*
@skb: buffer to alter
*
@len: bytes to move
*
*
Increase the headroom of an empty &sk_buff by reducing the tail
*
room. This is only allowed for an empty buffer.
*/
static inline void skb_reserve(struct sk_buff *skb, unsigned int len)
{
skb->data+=len;
skb->tail+=len;
}
static inline void __skb_trim(struct sk_buff *skb, unsigned int len)
{
skb->len = len;
skb->tail = skb->data+len;
}
/**
*
skb_trim - remove end from a buffer
*
@skb: buffer to alter
*
@len: new length
*
*
Cut the length of a buffer down by removing data from the tail. If
*
the buffer is already under the length specified it is not modified.
*/
static inline void skb_trim(struct sk_buff *skb, unsigned int len)
{
if (skb->len > len) {
__skb_trim(skb, len);
}
}
1. socket buffer : struct sk_buff
(1) 宣告在 include/linux/skbuff.h
(2) 重要欄位有
|
unsigned char *head; // 配置空間起點
unsigned char *data; // 有效資料起點
unsigned char *tail; // 有效資料的最後一個 Octet
unsigned char *end; // 配置空間終點 |
2. 配置 sk_buff
|
(1) struct sk_buff *alloc_skb(unsigned int len, int priority);
比較原始. 配置完成會將 skb-> data 和 skb->tail 指向 skb->head |
(2) struct sk_buff *dev_alloc_skb(unsigned int len);
供ISR使用而設計, 以GFP_ATOMIC優先度來配置, 並在 skb->head 和 skb->data 之間保留空間, 用以存放協定標頭.
|
3. void skb_reserve(struct sk_buff *skb, int len);
保留前頭空間.
大多數的Ethernet 介面在封包之前會保留 2-bytes空間,
這樣可使得 IP header 對齊 16-bytes 邊緣
( 因為 IP header 之前的 Ethernet header 有 14-bytes ) |
|
4. unsigned char * skb_put(struct sk_buff *skb, int len);
unsigned char * __skb_put(struct sk_buff *skb, int len);
將資料加到tail room 區, 並將 skb->tail 往後移
skb_put() : 會檢查是否有足夠空間
__skb_put() : 會省略檢查 |