
file 提供了一套unix文件描述符操作管理接口。用于管理所有Linux文件操作和socket通信。并提供了相关的注册、更新、删除的api接口。
typedef struct clib_file
{
/* Unix file descriptor from open/socket. */
u32 file_descriptor;
u32 flags;
#define UNIX_FILE_DATA_AVAILABLE_TO_WRITE (1 << 0)
#define UNIX_FILE_EVENT_EDGE_TRIGGERED (1 << 1)
/* polling thread index */
u32 polling_thread_index;
/* Data available for function's use. */
uword private_data;
/* Functions to be called when read/write data becomes ready. */
clib_file_function_t *read_function, *write_function, *error_function;
/* Description 当前文件管理描述信息*/
u8 *description;
/* Stats 记录事件的统计*/
u64 read_events;
u64 write_events;
u64 error_events;
} clib_file_t;各个字段的描述看字面意思都比较清楚;我们主要关注一下flags字段:
UNIX_FILE_DATA_AVAILABLE_TO_WRITE :
当前描述符是否可写,告诉epool是否监听写事件。
UNIX_FILE_EVENT_EDGE_TRIGGERED :设置epool触发模式是边缘触发模式
epoll有两种模式,Edge Triggered(简称ET) 和 Level Triggered(简称LT).在采用这两种模式时要注意的是,如果采用ET模式,那么仅当状态发生变化时才会通知,而采用LT模式类似于原来的select/poll操作,只要还有没有处理的事件就会一直通知.
typedef enum
{
UNIX_FILE_UPDATE_ADD,
UNIX_FILE_UPDATE_MODIFY,
UNIX_FILE_UPDATE_DELETE,
} clib_file_update_type_t;
typedef struct
{
/* Pool of files to poll for input/output. */
clib_file_t *file_pool;
void (*file_update) (clib_file_t * file,
clib_file_update_type_t update_type);
} clib_file_main_t;file_pool:clib_file_t 文件单个实例的内存池;使用pool结构。
file_update:提供了三种操作类型,添加、修改、删除。
由用户自己指定函数指针。
always_inline uword
clib_file_add (clib_file_main_t * um, clib_file_t * template)2、删除当前clib_file_t实例。
always_inline void
clib_file_del (clib_file_main_t * um, clib_file_t * f)3、设置当前索引对应的clib_file_t实例的轮询线程
目前还未找到使用的地方,但是vpp已经支持worker核来轮询。应该memif接口有使用吧。待研究了。
always_inline void
clib_file_set_polling_thread (clib_file_main_t * um, uword index,
u32 thread_index)其他的操作函数也比较简单,也不介绍了。
在src/vlib/unix/main.c文件中定义了全局文件管理结构,在对应目录下的input.c文件中有相应的初始化接口。
下面是linux epoll input初始化接口,对应的node函数是linux_epoll_input_node;是为了处理api、命令行、及套接字链接 读请求接口等等。
clib_file_main_t file_main;
clib_error_t *
linux_epoll_input_init (vlib_main_t * vm)
{
linux_epoll_main_t *em;
clib_file_main_t *fm = &file_main;
vlib_thread_main_t *tm = vlib_get_thread_main ();
/*每个worker线程对应一个linux_epoll_mains,这里cache一致性问题,
使用64字节d对齐 */
vec_validate_aligned (linux_epoll_mains, tm->n_vlib_mains,
CLIB_CACHE_LINE_BYTES);
vec_foreach (em, linux_epoll_mains)
{
/* Allocate some events. */
vec_resize (em->epoll_events, VLIB_FRAME_SIZE);
if (linux_epoll_mains == em)
{
em->epoll_fd = epoll_create (1);
if (em->epoll_fd < 0)
return clib_error_return_unix (0, "epoll_create");
}
else
em->epoll_fd = -1;
}
/* 设置文件更新回调函数*/
fm->file_update = linux_epoll_file_update;
return 0;
}
VLIB_INIT_FUNCTION (linux_epoll_input_init);下面是linux_epoll_input_node node节点,目前实现已支持多线程。在vpp启动后show runtime 可以看到有这个节点等待事件处理。
static uword
linux_epoll_input (vlib_main_t * vm,
vlib_node_runtime_t * node, vlib_frame_t * frame)
{
u32 thread_index = vlib_get_thread_index ();
if (thread_index == 0)
return linux_epoll_input_inline (vm, node, frame, 0);
else
return linux_epoll_input_inline (vm, node, frame, thread_index);
}
/* *INDENT-OFF* */
VLIB_REGISTER_NODE (linux_epoll_input_node,static) = {
.function = linux_epoll_input,
.type = VLIB_NODE_TYPE_PRE_INPUT,
.name = "unix-epoll-input",
};本文分享自 DPDK VPP源码分析 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!