netdev_pbuf_alloc是网卡驱动中的内存申请函数,申请一块缓冲区用于存放网络报文数据。
netdev_pbuf_alloc函数以pbuf结构申请内存空间,如程序清单 2.1所示。
程序清单 2.1 pbuf结构
struct pbuf { struct pbuf *next; void *payload; u16_t tot_len; u16_t len; u8_t type; u8_t flags; u16_t ref; };
netdev_pbuf_alloc函数是pbuf_alloc函数的函数封装,对外提供的函数接口只带有一个参数用于指定申请的缓冲区大小。而pbuf_alloc函数有三个参数,分别是申请的pbuf数据缓冲区是否带有偏移,数据缓冲区大小及缓冲区类型。在netdev_pbuf_alloc函数中,申请的pbuf结构缓冲区数据偏移固定为0,缓冲区类型为PBUF_POOL。netdev_pbuf_alloc函数传入的第二个参数缓冲区大小在调用pbuf_alloc函数申请pbuf结构时会被增加一个reserve长度,用于协议栈中的部分特殊操作。
在网络中通信的数据报文,除了真正的数据段外,还包括了TCP/IP各层协议的报文头。如用户有特殊需求,要在应用层构建报文并直接通过网卡驱动发送,则需要申请pbuf结构的数据缓冲区带有各层偏移,如程序清单 3.1所示。
程序清单 3.1 pbuf_alloc第一个参数分析
typedef enum { PBUF_TRANSPORT, /* 传输层报文头偏移 */ PBUF_IP, /* IP层报文头偏移 */ PBUF_LINK, /* 链路层报文头偏移 */ PBUF_RAW_TX, /* 封装链路层偏移 */ PBUF_RAW /* 无偏移 */ } pbuf_layer;
申请pbuf结构需要指定pbuf类型,原因是不同类型的pbuf申请内存的方式不同,如程序清单 3.2所示。
程序清单 3.2 pbuf_alloc第三个参数分析
typedef enum { PBUF_RAM, /* 内存堆分配 */ PBUF_ROM, /* 指向ROM空间内数据 */ PBUF_REF, /* 指向RAM空间内数据 */ PBUF_POOL /* 内存池分配 */ } pbuf_type;
PBUF_RAM类型的pbuf主要通过内存堆分配得到,协议栈划分了一块空间用于申请PBUF_RAM类型的pbuf,划分的空间大小通过“libsylixos/SylixOS/config/net/net_perf_cfg.h”中的“LW_CFG_LWIP_MEM_SIZE”宏配置。
PBUF_REF和PBUF_ROM类型的pbuf基本相同,前者指向ROM空间内的某段数据,而后者指向RAM空间内的某段数据。PBUF_REF和PBUF_ROM类型的pbuf通过“libsylixos/SylixOS/config/net/net_perf_cfg.h”中的“LW_CFG_LWIP_NUM_PBUFS”宏配置在内存池中预分配pbuf的最大数量。
PBUF_POOL类型的pbuf通过内存池分配,这种类型的pbuf可以在极短时间内得到分配,在网卡驱动接收数据时,一般采用这种方式。协议栈会在内存池中预先分配适当数量和大小的内存空间,通过“libsylixos/SylixOS/config/net/net_perf_cfg.h”中的“LW_CFG_LWIP_POOL_SIZE和LW_CFG_LWIP_NUM_POOLS”宏配置。
netdev_pbuf_alloc函数申请PBUF_POOL类型pbuf,若申请的缓冲区大于PBUF_POOL池中单个pbuf缓冲区长度,系统会分配多个固定大小的PBUF_POOL类型pbuf,并把这些pbuf链成一个链表,以满足用户的分配空间请求,如图 3.1所示。
图 3.1 PBUF_POOL类型pbuf申请流程
网卡驱动收到数据后,会调用netdev_pbuf_alloc函数申请pbuf结构,并将数据拷贝至pbuf。当有大量数据被网卡驱动接收时,可能会造成申请pbuf结构失败,原因是系统预分配的内存池中的pbuf结构已经全部被申请,还未被释放。可以尝试通过“libsylixos/SylixOS/config/net/net_perf_cfg.h”中的“LW_CFG_LWIP_POOL_SIZE和LW_CFG_LWIP_NUM_POOLS”宏配置增大pbuf缓冲区大小和数量解决pbuf结构申请失败问题。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。