LWIP学习笔记(3)LWIP数据包管理结构pbuf
pbuf结构体
协议栈本质是对数据包进⾏管理,lwip中⽤pbuf来描述和管理数据包,相关实现在pbuf.c/h,pbuf.h中定义结构体如下
pbuf类型
pbuf.h中定义类型如下
PBUF_RAM
pbuf描述的数据在pbuf结构之后的连续内存堆中,就是说他们是在⼀块连续的内存堆中,申请⽅式如下:
mem_malloc说明是在内存堆中申请,
SIZEOF_STRUCT_PBUF是如下宏定义,表⽰struct pbuf的⼤⼩
length是数据需要的空间
offest⽤来存储数据包各种⾸部,如TCP⾸部、IP⾸部、以太⽹⾸部等,也可以是0
PBUF_POOL
是通过内存池⽅式申请来的,pbuf结构与数据在同⼀内存池中,申请⽅式如下
可以看到参数是MEMP_PBUF_POOL,回忆前⾯讲的内存池管理,他是memp_t的枚举变量,是由memp_std.h宏定义来的,如下
后⾯的描述字段也说明了这是PBUF_POOL,再宏定义到下⾯,可以看到这种类型每个pool⼤⼩是 struct pbuf的⼤⼩加payload⼤⼩
payload⼤⼩是如下宏定义,
TCP_MSS+TCP头(20)+IP头(20)+以太⽹头(20),
ETH_PAD_SIZE默认是0,TCP_MSS默认是536,
祝自己生日快乐PBUF_ROM/PBUF_REF
PBUF_ROM :pbuf描述的数据在ROM中,PBUF_REF:pbuf描述的数据在RAM中,但位置与pbuf结构所在位置⽆关,申请⽅式都如下
对于参数MEMP_PBUF和上⾯原理⼀样,再贴⼀遍,从描述符可能看出这种池是PBUF_REF/ROM,不同的是他的payload是0,那么这种池的⼤⼩就是struct pbuf的⼤⼩,则他就只分配struct pbuf的⼤⼩
4种类型如下图
pbuf层次
由于lwip各层禁⽌数据拷贝,所以存在不同层次对数据包pbuf的alloc,前⾯的offest就是为不同层预留的头部字段,下⾯枚举了4种层次,分配时除了要知道⼤⼩、类型还要传⼊这个层次,在pbuf.h
古典爱情
数据包分配函数pbuf_alloc
/**
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
*
* The actual memory allocated for the pbuf is determined by the
* layer at which the pbuf is allocated and the requested size
* (from the size parameter).
*
* @param layer flag to define header size
* @param length size of the pbuf's payload
* @param type this parameter decides how and where the pbuf
* should be allocated as follows:
*
* - PBUF_RAM: buffer memory for pbuf is allocated as one large
* chunk. This includes protocol headers as well.
* - PBUF_ROM: no buffer memory is allocated for the pbuf, even for
* protocol headers. Additional headers must be prepended
* by allocating another pbuf and chain in to the front of
* the ROM pbuf. It is assumed that the memory ud is really
* similar to ROM in that it is immutable and will not be
* changed. Memory which is dynamic should generally not西藏风景图
* be attached to PBUF_ROM pbufs. U PBUF_REF instead.
* - PBUF_REF: no buffer memory is allocated for the pbuf, even for
* protocol headers. It is assumed that the pbuf is only
* being ud in a single thread. If the pbuf gets queued,
* then pbuf_take should be called to copy the buffer.
* - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from
* the pbuf pool that is allocated during pbuf_init().
*
* @return the allocated pbuf. If multiple pbufs where allocated, this
* is the first pbuf of a pbuf chain.
*/
struct pbuf *pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
{
struct pbuf *p,*q,*r;
u16_t offt;/**///预留⾸部长度
s32_t rem_len;/* remaining length */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,("pbuf_alloc(length=%"U16_F")\n", length));
/* determine header offt *///根据不同层次计算预留长度offest
switch(layer){
ca PBUF_TRANSPORT:/**///传输层,预留以太⾸部+IP⾸部+TCP⾸部
/* add room for transport (often TCP) layer header */
offt = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
ca PBUF_IP:/**///⽹络层,预留以太⾸部+IP⾸部
/* add room for IP layer header */
offt = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
ca PBUF_LINK:/**///链路层,预留以太⾸部
/* add room for link layer header */
offt = PBUF_LINK_HLEN;
break;
ca PBUF_RAW:/**///原始层,不预留
offt =0;
break;
default:
LWIP_ASSERT("pbuf_alloc: bad pbuf layer",0);
return NULL;
}
switch(type){/**///根据类型来分配pbuf
ca PBUF_POOL:/**///PBUF_POOL类型可能需要分配⼏个pool串起来
/* allocate head of pbuf chain into p */
p =(struct pbuf *)memp_malloc(MEMP_PBUF_POOL);
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,("pbuf_alloc: allocated pbuf %p\n",(void*)p)); if(p ==NULL){
PBUF_POOL_IS_EMPTY();
return NULL;
}
p->type = type;
p->next =NULL;
/* make the payload pointer point 'offt' bytes into pbuf data memory *///p->payload指向数据
桂圆枸杞茶p->payload =LWIP_MEM_ALIGN((void*)((u8_t *)p +(SIZEOF_STRUCT_PBUF + offt)));
LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",
帕朱丸
((mem_ptr_t)p->payload % MEM_ALIGNMENT)==0);
/* the total length of the pbuf chain is the requested size *///填写总长度
p->tot_len = length;
/* t the length of the first pbuf in the chain *///len是pool的剩余空间和length的最⼩值
p->len =LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED -LWIP_MEM_ALIGN_SIZE(offt)); LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
((u8_t*)p->payload + p->len <=
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
(PBUF_POOL_BUFSIZE_ALIGNED -LWIP_MEM_ALIGN_SIZE(offt))>0);
/* t reference count (needed here in ca we fail) */
p->ref =1;
/**///下⾯判断已分配的pool能否装满length,不够则继续分配
/* now allocate the tail of the pbuf chain */
/* remember first pbuf for linkage in next iteration */
r = p;
/* remaining length to be allocated */
rem_len = length - p->len;/**///还需要分配的长度
/* any remaining pbufs to be allocated? */
while(rem_len >0){/**///只要不够则继续分配
q =(struct pbuf *)memp_malloc(MEMP_PBUF_POOL);/**///再分配⼀个pool
if(q ==NULL){
PBUF_POOL_IS_EMPTY();
/* free chain so far allocated */
pbuf_free(p);
/* bail out unsuccesfully */
return NULL;
}
q->type = type;
q->flags =0;
q->next =NULL;
/* make previous pbuf point to this pbuf */
r->next = q;/**///新分配的连接到之前的尾部
/* t total length of this pbuf and next in chain */
LWIP_ASSERT("rem_len < max_u16_t", rem_len <0xffff);
q->tot_len =(u16_t)rem_len;
/* this pbuf length is pool size, unless smaller sized tail */
q->len =LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);
q->payload =(void*)((u8_t *)q + SIZEOF_STRUCT_PBUF);
LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",
((mem_ptr_t)q->payload % MEM_ALIGNMENT)==0);
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
((u8_t*)p->payload + p->len <=
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));鹅鹅鹅古诗作者
q->ref =1;
/* calculate remaining length to be allocated */
rem_len -= q->len;/**///更新rem_len
/* remember this pbuf for linkage in next iteration */
r = q;
}
/* end of chain */
/*r->next = NULL;*/
break;
ca PBUF_RAM:
/* If pbuf is to be allocated in RAM, allocate memory for it. */
p =(struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offt)+LWIP_MEM_ALIGN_SIZE(length));
if(p ==NULL){
return NULL;
}
/* Set up internal structure of the pbuf. */
p->payload =LWIP_MEM_ALIGN((void*)((u8_t *)p + SIZEOF_STRUCT_PBUF + offt));
p->len = p->tot_len = length;
p->next =NULL;
p->type = type;
LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",
((mem_ptr_t)p->payload % MEM_ALIGNMENT)==0);
break;
/* pbuf references existing (non-volatile static constant) ROM payload? */
ca PBUF_ROM:
/* pbuf references existing (externally allocated) RAM payload? */
ca PBUF_REF:
/* only allocate memory for the pbuf structure */
p =(struct pbuf *)memp_malloc(MEMP_PBUF);//⼀个struct pbuf⼤⼩的pool
if(p ==NULL){
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
(type == PBUF_ROM)?"ROM":"REF"));
return NULL;
}
/
* caller must t this field properly, afterwards */
p->payload =NULL;//payload需要⽤户⾃⼰根据实际位置设置
p->len = p->tot_len = length;
p->next =NULL;
p->type = type;
break;
default:
LWIP_ASSERT("pbuf_alloc: erroneous type",0);
return NULL;
}
/* t reference count */
手机恢复出厂设置怎么弄
p->ref =1;
/* t flags */
p->flags =0;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,("pbuf_alloc(length=%"U16_F") == %p\n", length,(void*)p));
return p;
}
数据包释放函数pbuf_free
注意只有当pbuf的引⽤次数为0,即ref字段为0时才能释放pbuf,因为此时没有指针指向这个数据包了,代表他被处理完了当pbuf链表的⾸节点, 被释放后还有检查他后⾯的节点是否能被释放,因为⾸节点释放会影响后续节点的ref字段
还有只能释放pbuf链表的⾸节点,不能释放中间节点,会导致⾮法指针
/
**
* Dereference a pbuf chain or queue and deallocate any no-longer-ud
* pbufs at the head of this chain or queue.
*
慌急* Decrements the pbuf reference count. If it reaches zero, the pbuf is
* deallocated.
*
* For a pbuf chain, this is repeated for each pbuf in the chain,
* up to the first pbuf which has a non-zero reference count after
* decrementing. So, when all reference counts are one, the whole
* chain is free'd.