/* * \brief 虚拟设备管理器 * * 虚拟设备,用于驱动与应用进行数据通信。驱动程序将从物理设备 * 收取的报文,经过交换逻辑送入虚拟设备中,从而分发到各应用进行处理。 * * \author Lu Qiuwen * \date 2017-02-17 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef VDEV_DEFAULT_SZ_BUFFER #define VDEV_DEFAULT_SZ_BUFFER 32 #endif #ifndef VDEV_DEFAULT_SZ_TUNNEL #define VDEV_DEFAULT_SZ_TUNNEL 512 #endif /* =========================================================================================== */ int vdev_iterate(struct vdev_main * v_main, struct vdev ** vdev_result, unsigned int * next) { if (*next >= v_main->vdev_max_idx) return -ENOENT; else *vdev_result = &v_main->_vdev_array[(*next)++]->vdev; return 0; } struct vdev * vdev_lookup(struct vdev_main * v_main, const char * symbol) { struct vdev * vdev = NULL; unsigned int next = 0; while(vdev_iterate(v_main, &vdev, &next) >= 0) { if (strncmp(vdev->symbol, symbol, sizeof(vdev->symbol)) != 0) continue; return vdev; } return NULL; } // 设置虚设备的IP地址 int vdev_set_inaddr(struct vdev * vdev, struct in_addr in_addr, struct in_addr in_mask, struct in_addr gateway) { vdev->in_addr = in_addr; vdev->in_mask = in_mask; vdev->in_gateway = gateway; return 0; } // 读取虚设备的IP地址 int vdev_get_inaddr(struct vdev * vdev, struct in_addr * in_addr, struct in_addr * in_mask, struct in_addr * gateway) { *in_addr = vdev->in_addr; *in_mask = vdev->in_mask; *gateway = vdev->in_gateway; return 0; } int vdev_set_ether_addr(struct vdev * vdev, struct ether_addr * ether_addr) { vdev->ether_addr = *ether_addr; return 0; } // 设置虚设备的MTU int vdev_set_mtu(struct vdev * vdev, unsigned int mtu) { vdev->mtu = mtu; return 0; } // 读取虚设备的MTU int vdev_get_mtu(struct vdev * vdev) { return vdev->mtu; } // 启动设备 int vdev_enable(struct vdev * vdev) { vdev->enable = 1; return 0; } // 禁用设备 int vdev_disable(struct vdev * vdev) { vdev->enable = 0; return 0; } /* Datapath Functions */ int vdev_dispatch(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts, int flags) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return _vdev->dispatch(_vdev, qid, pkts, nr_pkts, flags); } int vdev_collect(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts, int flags) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return _vdev->collect(_vdev, qid, pkts, nr_pkts, flags); } int vdev_idle_poll(struct vdev * vdev, queue_id_t qid) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return _vdev->idle_pool(_vdev, qid); } int vdev_stats_get(struct vdev * vdev, struct vdev_stat_info * stat_info) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return _vdev->stats_get(_vdev, stat_info); } void vdev_stats_last_save(struct vdev * vdev, struct vdev_stat_info * stat_info_last) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); _vdev->stat_info_last = *stat_info_last; } void vdev_stats_last_get(struct vdev * vdev, struct vdev_stat_info * stat_info_last) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); *stat_info_last = _vdev->stat_info_last; } /* 虚设备用户配置查询 */ int vdev_usercfg_query_vdev_list(struct sc_main * sc, const char * str_vdev_type, char vdevsyms[MR_SYMBOL_MAX][MR_VDEV_MAX], unsigned int * nr_vdevsyms) { char str_direct_devices[MR_STRING_MAX] = { 0 }; int ret = MESA_load_profile_string_nodef(sc->local_cfgfile, "device", str_vdev_type, str_direct_devices, sizeof(str_direct_devices)); if (ret < 0) { *nr_vdevsyms = 0; return RT_SUCCESS; } char * str_vdev_symbol[MR_TOKENS_MAX]; int nr_str_tokens = rte_strsplit(str_direct_devices, sizeof(str_direct_devices), str_vdev_symbol, MR_TOKENS_MAX, ','); for (int i = 0; i < nr_str_tokens; i++) { MR_VERIFY(i < MR_VDEV_MAX); snprintf(vdevsyms[i], sizeof(vdevsyms[i]), "%s", str_vdev_symbol[i]); } *nr_vdevsyms = nr_str_tokens; return RT_SUCCESS; } int vdev_usercfg_query_vdev_in_addr(struct sc_main * sc, const char * devsym, struct in_addr * addr, struct in_addr * mask, struct in_addr * gateway) { // 生成配置文件节名称,例如[device:mr0] char str_section[MR_SYMBOL_MAX]; snprintf(str_section, sizeof(str_section), "device:%s", devsym); // 读IP地址(必要) char str_in_addr[MR_SYMBOL_MAX]; if (MESA_load_profile_string_nodef(sc->local_cfgfile, str_section, "in_addr", str_in_addr, sizeof(str_in_addr)) < 0) return 0; // 地址转换 int ret = inet_pton(AF_INET, str_in_addr, addr); if (ret < 0) { MR_CFGERR_INVALID_FORMAT(sc->local_cfgfile, str_section, "in_addr"); return RT_ERR; } // 读掩码(必要) char str_in_mask[MR_SYMBOL_MAX]; if (MESA_load_profile_string_nodef(sc->local_cfgfile, str_section, "in_mask", str_in_mask, sizeof(str_in_mask)) < 0) return RT_ERR; // 掩码转换 ret = inet_pton(AF_INET, str_in_mask, mask); if (ret < 0) { MR_CFGERR_INVALID_FORMAT(sc->local_cfgfile, str_section, "in_mask"); return RT_ERR; } // 读默认网关(可选项) char str_gateway[MR_SYMBOL_MAX]; if (MESA_load_profile_string_nodef(sc->local_cfgfile, str_section, "gateway", str_gateway, sizeof(str_gateway)) >= 0) { ret = inet_pton(AF_INET, str_gateway, gateway); if (ret < 0) { MR_CFGERR_INVALID_FORMAT(sc->local_cfgfile, str_section, "gateway"); return RT_ERR; } } return RT_SUCCESS; } int vdev_usercfg_query_vdev_setup(struct sc_main * sc, const char * devsym, unsigned int * sz_tunnel, unsigned int * sz_buffer) { unsigned int default_sz_tunnel; unsigned int default_sz_buffer; MESA_load_profile_uint_def(sc->local_cfgfile, "device", "sz_tunnel", &default_sz_tunnel, VDEV_DEFAULT_SZ_TUNNEL); MESA_load_profile_uint_def(sc->local_cfgfile, "device", "sz_buffer", &default_sz_buffer, VDEV_DEFAULT_SZ_BUFFER); char str_dev_section[MR_SYMBOL_MAX]; snprintf(str_dev_section, sizeof(str_dev_section), "device:%s", devsym); MESA_load_profile_uint_def(sc->local_cfgfile, str_dev_section, "sz_tunnel", sz_tunnel, default_sz_tunnel); MESA_load_profile_uint_def(sc->local_cfgfile, str_dev_section, "sz_buffer", sz_buffer, default_sz_buffer); return RT_SUCCESS; } int vdev_usercfg_query_mempool(struct sc_main * sc, const char * devsym, char mempool_direct_pool[MR_SYMBOL_MAX], char mempool_indirect_pool[MR_SYMBOL_MAX]) { char str_dev_section[MR_SYMBOL_MAX] = { 0 }; snprintf(str_dev_section, sizeof(str_dev_section), "device:%s", devsym); /* 没有定义直接内存池名称,使用设备名 */ MESA_load_profile_string_def(sc->local_cfgfile, str_dev_section, "direct-pool", mempool_direct_pool, MR_SYMBOL_MAX, devsym); /* 没有定义间接内存池名称,使用直接内存池名称 */ MESA_load_profile_string_def(sc->local_cfgfile, str_dev_section, "indirect-pool", mempool_indirect_pool, MR_SYMBOL_MAX, mempool_direct_pool); return RT_SUCCESS; } /* 处理应用打开设备的请求。为应用创建请求设备的VDI结构 */ static int __vdev_open_request_handler(struct ctrlmsg_handler * ct_hand, struct ctrlmsg_conn * ct_conn, struct ctrl_msg_header * msg, void * arg) { struct app * app_object = (struct app *)ct_conn->pme; struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app_object->pme_vdev_main; struct vdev_main * vdev_main = (struct vdev_main *)arg; struct ctrl_msg_vdev_open_request * msg_req = (struct ctrl_msg_vdev_open_request *)msg; /* 构造应答头部 */ struct ctrl_msg_vdev_open_response msg_rep; memset(&msg_rep, 0, sizeof(msg_rep)); ctrl_msg_header_construct(&msg_rep.msg_header, sizeof(msg_rep), CTRL_MSG_TYPE_RESPONSE, (char *)msg->msg_topic); /* 查找应用请求打开的VDEV的句柄,检查是否存在 */ struct vdev * vdev = vdev_lookup(vdev_main, (char *)msg_req->devsym); if (vdev == NULL) { MR_WARNING("Wrong Request: from %s, device %s is not existed", app_object->symbol, (char *)msg_req->devsym); ctrl_msg_error_construct(&msg_rep.msg_err, ENODEV, "device %s is not existed.", (char *)msg_req->devsym); ctrlmsg_msg_send(ct_hand, ct_conn, &msg_rep.msg_header); return 0; } struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); /* 申请VDI */ struct vdev_instance * vdi = _vdev->vdi_create(_vdev, app_object->symbol, msg_req->nr_rxstream, msg_req->nr_txstream); if (vdi == NULL) { MR_ERROR("Create vdev instance %s for app %s failed. ", (char *)msg_req->devsym, app_object->symbol); ctrl_msg_error_construct(&msg_rep.msg_err, ENOMEM, "Create vdev instance failed."); ctrlmsg_msg_send(ct_hand, ct_conn, &msg_rep.msg_header); return 0; } /* VDI申请成功 */ msg_rep.ptr_vdi = (uint64_t)vdi; msg_rep.nr_rxstream = msg_req->nr_rxstream; msg_rep.nr_txstream = msg_req->nr_txstream; snprintf((char *)msg_rep.devsym, sizeof(msg_rep.devsym), "%s", vdev->symbol); ctrlmsg_msg_send(ct_hand, ct_conn, &msg_rep.msg_header); TAILQ_INSERT_TAIL(&vdev_main_pme->vdi_list, vdi, next); return 0; } static void __vdev_app_register_handler(struct app_main * app_main, struct app * app, void * arg) { app->pme_vdev_main = ZMALLOC(sizeof(struct vdev_main_pme)); MR_VERIFY_MALLOC(app->pme_vdev_main); struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app->pme_vdev_main; TAILQ_INIT(&vdev_main_pme->vdi_list); return; } static void __vdev_app_unregister_handler(struct app_main * app_main, struct app * app, void * arg) { struct vdev_instance * vdi; struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app->pme_vdev_main; if (vdev_main_pme == NULL) return; while (!TAILQ_EMPTY(&vdev_main_pme->vdi_list)) { vdi = TAILQ_FIRST(&vdev_main_pme->vdi_list); TAILQ_REMOVE(&vdev_main_pme->vdi_list, vdi, next); struct _vdev * _vdev = container_of(vdi->vdev, struct _vdev, vdev); _vdev->vdi_destory(vdi); } FREE(vdev_main_pme); return; } /* 根据配置文件创建回环虚设备 */ static int vdev_loop_usercfg_setup(struct sc_main * sc) { /* 加载虚设备配置,虚设备和物理设备一一对应 */ char vdevsyms[MR_SYMBOL_MAX][MR_VDEV_MAX] = { { 0 } }; unsigned int nr_vdevsyms = 0; vdev_usercfg_query_vdev_list(sc, "loop", vdevsyms, &nr_vdevsyms); for (int i = 0; i < nr_vdevsyms; i++) { const char * vdevsym = vdevsyms[i]; struct rte_mempool * direct_pool = NULL; struct rte_mempool * indirect_pool = NULL; char sym_direct_mempool[MR_SYMBOL_MAX] = { 0 }; char sym_indirect_mempool[MR_SYMBOL_MAX] = { 0 }; vdev_usercfg_query_mempool(sc, vdevsym, sym_direct_mempool, sym_indirect_mempool); /* 查询Indirect Pool,使用与物理设备对应的Indirect Pool */ direct_pool = mrb_direct_mempool_locate(sc->mrb_pool_main, sym_direct_mempool, 0, 0); if (direct_pool == NULL) { MR_ERROR("Direct mempool %s for device %s is not existed. ", sym_direct_mempool, vdevsym); goto err; } indirect_pool = mrb_indirect_mempool_locate(sc->mrb_pool_main, sym_indirect_mempool, 0, 0); if (indirect_pool == NULL) { MR_ERROR("Indirect mempool %s for device %s is not existed. ", sym_indirect_mempool, vdevsym); goto err; } /* 查询队列缓冲区大小 */ unsigned int sz_tunnel, sz_buffer; vdev_usercfg_query_vdev_setup(sc, vdevsym, &sz_tunnel, &sz_buffer); /* 创建回环虚设备 */ int ret = vdev_loop_create(sc->vdev_main, vdevsym, sz_tunnel, sz_buffer, direct_pool, indirect_pool); if (ret < 0) goto err; struct vdev * vdev = vdev_lookup(sc->vdev_main, vdevsym); MR_VERIFY_2(vdev != NULL, "vdev_lookup() returns NULL."); } return RT_SUCCESS; err: MR_ERROR("Loop devices defined by user setup failed. "); return RT_ERR; } static int __vdev_data_setup_one_device(struct sc_main * sc, const char * vdevsym, unsigned int nr_rxstream, unsigned int nr_txstream) { struct rte_mempool * direct_pool = NULL; struct rte_mempool * indirect_pool = NULL; char sym_direct_mempool[MR_SYMBOL_MAX] = { 0 }; char sym_indirect_mempool[MR_SYMBOL_MAX] = { 0 }; vdev_usercfg_query_mempool(sc, vdevsym, sym_direct_mempool, sym_indirect_mempool); /* 查询Indirect Pool,使用与物理设备对应的Indirect Pool */ direct_pool = mrb_direct_mempool_locate(sc->mrb_pool_main, sym_direct_mempool, 0, 0); if (direct_pool == NULL) { MR_ERROR("Direct mempool %s for virtual device %s is not existed. ", sym_direct_mempool, vdevsym); goto err; } indirect_pool = mrb_indirect_mempool_locate(sc->mrb_pool_main, sym_indirect_mempool, 0, 0); if (indirect_pool == NULL) { MR_ERROR("Indirect mempool %s for virtual device %s is not existed. ", sym_indirect_mempool, vdevsym); goto err; } /* 查询队列缓冲区大小 */ unsigned int sz_tunnel, sz_buffer; vdev_usercfg_query_vdev_setup(sc, vdevsym, &sz_tunnel, &sz_buffer); /* 创建对应的虚拟设备 */ int ret = vdev_data_create(sc->vdev_main, vdevsym, nr_rxstream, nr_txstream, sz_tunnel, sz_buffer, direct_pool, indirect_pool); if (ret < 0) goto err; struct vdev * vdev = vdev_lookup(sc->vdev_main, vdevsym); MR_VERIFY_2(vdev != NULL, "vdev_lookup() returns NULL."); /* 读IP地址、掩码、网关设置 */ struct in_addr addr = { 0 }; struct in_addr mask = { 0 }; struct in_addr gateway = { 0 }; vdev_usercfg_query_vdev_in_addr(sc, vdevsym, &addr, &mask, &gateway); vdev_set_inaddr(vdev, addr, mask, gateway); vdev_enable(vdev); /* 查询物理设备,如果有对应的物理设备,复制对应的MAC地址、MTU等参数 */ struct phydev * phydev = phydev_lookup(sc->phydev_main, vdevsym); if (phydev == NULL) return RT_SUCCESS; vdev_set_ether_addr(vdev, &phydev->ether_addr); vdev_set_mtu(vdev, phydev->mtu); return RT_SUCCESS; err: return RT_ERR; } /* 根据配置文件创建虚设备 */ static int vdev_data_usercfg_setup(struct sc_main * sc) { /* 加载虚设备配置,虚设备和物理设备一一对应 */ char vdevsyms[MR_SYMBOL_MAX][MR_VDEV_MAX] = { { 0 } }; unsigned int nr_vdevsyms = 0; vdev_usercfg_query_vdev_list(sc, "device", vdevsyms, &nr_vdevsyms); /* 计算队列数 */ unsigned int nr_rxstream = sc->nr_serv_thread; unsigned int nr_txstream = sc->nr_serv_thread; for (int i = 0; i < nr_vdevsyms; i++) { const char * vdevsym = vdevsyms[i]; int ret = __vdev_data_setup_one_device(sc, vdevsym, nr_rxstream, nr_txstream); if (ret < 0) goto err; } /* 原始设备套接字 */ memset(vdevsyms, 0, sizeof(vdevsyms)); vdev_usercfg_query_vdev_list(sc, "rawsocket", vdevsyms, &nr_vdevsyms); for (int i = 0; i < nr_vdevsyms; i++) { const char * vdevsym = vdevsyms[i]; int ret = __vdev_data_setup_one_device(sc, vdevsym, nr_rxstream, nr_txstream); if (ret < 0) goto err; } return RT_SUCCESS; err: MR_ERROR("Virtual devices defined by user setup failed. "); return RT_ERR; } int vdev_main_init(struct sc_main * sc) { sc->vdev_main = ZMALLOC(sizeof(struct vdev_main)); MR_VERIFY_MALLOC(sc->vdev_main); /* 加载公共参数配置 */ MESA_load_profile_uint_def(sc->local_cfgfile, "device", "default_sz_tunnel", &sc->vdev_main->sz_tunnel, VDEV_DEFAULT_SZ_TUNNEL); MESA_load_profile_uint_def(sc->local_cfgfile, "device", "default_sz_buffer", &sc->vdev_main->sz_buffer, VDEV_DEFAULT_SZ_BUFFER); /* 数据分发虚拟设备创建 */ if (vdev_data_usercfg_setup(sc) == RT_ERR) return RT_ERR; /* 本地回环虚拟设备创建 */ if (vdev_loop_usercfg_setup(sc) == RT_ERR) return RT_ERR; /* 注册消息处理函数 */ ctrlmsg_msg_reciver_register(sc->ctrlmsg_handler, CTRLMSG_TOPIC_VDEV_OPEN, CTRL_MSG_TYPE_REQUEST, __vdev_open_request_handler, sc->vdev_main); /* 注册应用注册、反注册处理函数,主要用于释放资源 */ app_event_handler_register(sc->app_main, APP_EV_TYPE_REGISTER, __vdev_app_register_handler, sc->vdev_main); app_event_handler_register(sc->app_main, APP_EV_TYPE_UNREGISTER, __vdev_app_unregister_handler, sc->vdev_main); return RT_SUCCESS; } int vdev_dump(struct sc_main * sc) { MR_INFO(" "); for (int i = 0; i < sc->vdev_main->vdev_max_idx; i++) { struct _vdev * _vdev_iter = sc->vdev_main->_vdev_array[i]; MR_INFO("Virtual Device %s:", _vdev_iter->vdev.symbol); MR_INFO(" RX thread count : %d", _vdev_iter->nr_rxstream); MR_INFO(" TX thread count : %d", _vdev_iter->nr_txstream); MR_INFO(" Packet deliver ring size : %d", _vdev_iter->sz_tunnel); MR_INFO(" Packet deliver buffer size : %d", _vdev_iter->sz_buffer); /* IP地址没有配置,忽略IP类信息的输出 */ if (_vdev_iter->vdev.in_addr.s_addr != 0) { MR_INFO(" IP Address : %s", inet_ntoa(_vdev_iter->vdev.in_addr)); MR_INFO(" Subnet mask : %s", inet_ntoa(_vdev_iter->vdev.in_mask)); MR_INFO(" Gateway : %s", inet_ntoa(_vdev_iter->vdev.in_gateway)); } MR_INFO(" "); } return 0; }