/* * \brief 虚拟设备管理器 * * 虚拟设备,用于驱动与应用进行数据通信。驱动程序将从物理设备 * 收取的报文,经过交换逻辑送入虚拟设备中,从而分发到各应用进行处理。 * * \author Lu Qiuwen * \date 2017-02-17 * */ #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; } /* 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); mr_pdump_tx(vdev->port_id, qid, pkts, nr_pkts); return vdev_data_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); unsigned int rx_nr_mbufs = vdev_data_collect(_vdev, qid, pkts, nr_pkts, flags); mr_pdump_rx(vdev->port_id, qid, pkts, rx_nr_mbufs); return (int)rx_nr_mbufs; } int vdev_rt_pkts_retrieve(struct vdev * vdev, queue_id_t qid, struct rte_mbuf * pkts[], unsigned int nr_pkts) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return vdev_data_rt_pkts_retrieve(_vdev, qid, pkts, nr_pkts); } int vdev_idle_poll(struct vdev * vdev, queue_id_t qid) { struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); return vdev_data_idle_poll(_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_data_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; } static int vdev_instance_create_handler(const struct rte_mp_msg * msg, const void * peer) { assert(msg->len_param == sizeof(struct ctrl_msg_vdev_open_request)); struct ctrl_msg_vdev_open_request * msg_req = (struct ctrl_msg_vdev_open_request *)msg->param; /* prepare the response message */ struct rte_mp_msg msg_rep = {}; snprintf(msg_rep.name, sizeof(msg_rep.name), "%s", msg->name); msg_rep.len_param = sizeof(struct ctrl_msg_vdev_open_response); struct ctrl_msg_vdev_open_response * vdev_open_rep = (struct ctrl_msg_vdev_open_response *)msg_rep.param; /* app object and other handlers */ struct app * app_object = app_lookup_by_symbol(sc_main_get(), (const char *)msg_req->appsym); assert(app_object != NULL); struct vdev_main * vdev_main = sc_main_get()->vdev_main; assert(vdev_main != NULL); struct vdev * vdev = vdev_lookup(vdev_main, (char *)msg_req->devsym); if (vdev == NULL) { MR_WARNING("invalid vdi request: from %s, device %s is not existed", app_object->symbol, (char *)msg_req->devsym); vdev_open_rep->errcode = ENODEV; goto out; } /* Verify the vdev usage status */ if (vdev->in_use == VDEV_IN_USE) { MR_WARNING("invalid vdi request: from %s, device %s is already in use", app_object->symbol, (char *)msg_req->devsym); vdev_open_rep->errcode = EBUSY; goto out; } struct _vdev * _vdev = container_of(vdev, struct _vdev, vdev); struct vdev_instance * vdi = vdev_data_instance_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); vdev_open_rep->errcode = ENOMEM; goto out; } /* get the notify structure, and transfer the eventfd used in app */ struct vnode_cons_notify * notify_ctx = vnode_mirror_notify_ctx_cons(vdi->vnode_rx_cons); msg_rep.num_fds = msg_req->nr_rxstream; for (unsigned int i = 0; i < msg_req->nr_rxstream; i++) { msg_rep.fds[i] = notify_ctx[i].cons_notify_eventfd; } /* VDI申请成功 */ vdev_open_rep->ptr_vdi = (uint64_t)vdi; vdev_open_rep->nr_rxstream = msg_req->nr_rxstream; vdev_open_rep->nr_txstream = msg_req->nr_txstream; snprintf((char *)vdev_open_rep->devsym, sizeof(vdev_open_rep->devsym) - 1, "%s", vdev->symbol); if (vdev->link_status == LINK_DOWN) { vdev->link_status = LINK_UP; MR_INFO("shmdev %s link status is up. ", vdev->symbol); } /* Mark the vdev as in use */ vdev->in_use = VDEV_IN_USE; struct vdev_main_pme * vdev_main_pme = (struct vdev_main_pme *)app_object->pme_vdev_main; TAILQ_INSERT_TAIL(&vdev_main_pme->vdi_list, vdi, next); out: rte_mp_reply(&msg_rep, peer); return 0; } static void shmdev_event_handler_app_register(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); } static void shmdev_event_handler_app_unregister(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); if (vdi->vdev->link_status == LINK_UP) { vdi->vdev->link_status = LINK_DOWN; MR_INFO("shmdev %s link status is down. ", vdi->vdev->symbol); } /* Mark the vdev as not in use */ vdi->vdev->in_use = VDEV_NOT_IN_USE; vdev_data_instance_destory(vdi); } FREE(vdev_main_pme); } int vdev_main_init(struct sc_main * sc) { sc->vdev_main = ZMALLOC(sizeof(struct vdev_main)); MR_VERIFY_MALLOC(sc->vdev_main); rte_mp_action_register("vdev_instance_request", vdev_instance_create_handler); /* 注册应用注册、反注册处理函数,主要用于释放资源 */ app_event_handler_register(sc->app_main, APP_EV_TYPE_REGISTER, shmdev_event_handler_app_register, sc->vdev_main); app_event_handler_register(sc->app_main, APP_EV_TYPE_UNREGISTER, shmdev_event_handler_app_unregister, sc->vdev_main); return RT_SUCCESS; } int vdev_dump(struct sc_main * sc) { MR_INFO("\n"); for (int i = 0; i < sc->vdev_main->vdev_max_idx; i++) { struct _vdev * _vdev_iter = sc->vdev_main->_vdev_array[i]; char str_vdev_info[2048]; int len = snprintf(str_vdev_info, sizeof(str_vdev_info), "virtual device, name=%s, rx_thread_count=%d, tx_thread_count=%d, rx_ring_size=%d, " "tx_ring_size=%d, max_inflight=%d", _vdev_iter->vdev.symbol, _vdev_iter->nr_rxstream, _vdev_iter->nr_txstream, _vdev_iter->sz_rx_tunnel, _vdev_iter->sz_tx_tunnel, _vdev_iter->sz_max_inflight); /* IP地址没有配置,忽略IP类信息的输出 */ if (_vdev_iter->vdev.in_addr.s_addr != 0) { snprintf(str_vdev_info + len, sizeof(str_vdev_info) - len, ", ip_addr=%s, subnet_mask=%s, gateway=%s", inet_ntoa(_vdev_iter->vdev.in_addr), inet_ntoa(_vdev_iter->vdev.in_addr), inet_ntoa(_vdev_iter->vdev.in_gateway)); } MR_INFO("%s", str_vdev_info); } return 0; }