When packet capture is enabled, need to also notify secondary processes to force them to do the callbacks.
Requires that all secondary processes also call rte_pdump_init() or there will be warning about not responding secondary. Signed-off-by: Stephen Hemminger <step...@networkplumber.org> --- lib/pdump/rte_pdump.c | 213 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 185 insertions(+), 28 deletions(-) diff --git a/lib/pdump/rte_pdump.c b/lib/pdump/rte_pdump.c index bfd63fa8c2..b95f7f863d 100644 --- a/lib/pdump/rte_pdump.c +++ b/lib/pdump/rte_pdump.c @@ -5,6 +5,7 @@ #include <stdlib.h> #include <eal_export.h> +#include <rte_alarm.h> #include <rte_mbuf.h> #include <rte_ethdev.h> #include <rte_lcore.h> @@ -26,11 +27,28 @@ RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE); /* Used for the multi-process communication */ #define PDUMP_MP "mp_pdump" +/* Overly generous timeout for secondary to respond */ +#define MP_TIMEOUT_S 5 + enum pdump_operation { DISABLE = 1, ENABLE = 2 }; +static inline const char * +pdump_opname(enum pdump_operation op) +{ + static char buf[32]; + + if (op == DISABLE) + return "disable"; + if (op == ENABLE) + return "enable"; + + snprintf(buf, sizeof(buf), "op%u", op); + return buf; +} + /* Internal version number in request */ enum pdump_version { V1 = 1, /* no filtering or snap */ @@ -56,6 +74,11 @@ struct pdump_response { int32_t err_value; }; +struct pdump_bundle { + struct rte_mp_msg msg; + char peer[]; +}; + static struct pdump_rxtx_cbs { struct rte_ring *ring; struct rte_mempool *mp; @@ -432,34 +455,150 @@ set_pdump_rxtx_cbs(const struct pdump_request *p) return ret; } +static void +pdump_request_to_secondary(const struct pdump_request *req) +{ + struct rte_mp_msg mp_req = { }; + struct rte_mp_reply mp_reply; + struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0}; + + PDUMP_LOG_LINE(DEBUG, "forward req %s to secondary", pdump_opname(req->op)); + + memcpy(mp_req.param, req, sizeof(*req)); + strlcpy(mp_req.name, PDUMP_MP, sizeof(mp_req.name)); + mp_req.len_param = sizeof(*req); + + if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) != 0) + PDUMP_LOG_LINE(ERR, "rte_mp_request_sync failed"); + + else if (mp_reply.nb_sent != mp_reply.nb_received) + PDUMP_LOG_LINE(ERR, "not all secondary's replied (sent %u recv %u)", + mp_reply.nb_sent, mp_reply.nb_received); + + free(mp_reply.msgs); +} + +/* Allocate temporary storage for passing state to the alarm thread for deferred handling */ +static struct pdump_bundle * +pdump_bundle_alloc(const struct rte_mp_msg *mp_msg, const char *peer) +{ + struct pdump_bundle *bundle; + size_t peer_len = strlen(peer) + 1; + + /* peer is the unix domain socket path */ + bundle = malloc(sizeof(*bundle) + peer_len); + if (bundle == NULL) + return NULL; + + bundle->msg = *mp_msg; + memcpy(bundle->peer, peer, peer_len); + return bundle; +} + +/* Send response to peer */ static int -pdump_server(const struct rte_mp_msg *mp_msg, const void *peer) +pdump_send_response(const struct pdump_request *req, int result, const void *peer) { - struct rte_mp_msg mp_resp; - const struct pdump_request *cli_req; - struct pdump_response *resp = (struct pdump_response *)&mp_resp.param; + struct rte_mp_msg mp_resp = { }; + struct pdump_response *resp = (struct pdump_response *)mp_resp.param; + int ret; - /* recv client requests */ - if (mp_msg->len_param != sizeof(*cli_req)) { - PDUMP_LOG_LINE(ERR, "failed to recv from client"); - resp->err_value = -EINVAL; - } else { - cli_req = (const struct pdump_request *)mp_msg->param; - resp->ver = cli_req->ver; - resp->res_op = cli_req->op; - resp->err_value = set_pdump_rxtx_cbs(cli_req); + if (req) { + resp->ver = req->ver; + resp->res_op = req->op; } + resp->err_value = result; rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN); mp_resp.len_param = sizeof(*resp); - mp_resp.num_fds = 0; - if (rte_mp_reply(&mp_resp, peer) < 0) { - PDUMP_LOG_LINE(ERR, "failed to send to client:%s", + + ret = rte_mp_reply(&mp_resp, peer); + if (ret != 0) + PDUMP_LOG_LINE(ERR, "failed to send response: %s", strerror(rte_errno)); - return -1; + return ret; +} + +/* Callback from MP request handler in secondary process */ +static int +pdump_handle_primary_request(const struct rte_mp_msg *mp_msg, const void *peer) +{ + const struct pdump_request *req = NULL; + int ret; + + if (mp_msg->len_param != sizeof(*req)) { + PDUMP_LOG_LINE(ERR, "invalid request from primary"); + ret = -EINVAL; + } else { + req = (const struct pdump_request *)mp_msg->param; + PDUMP_LOG_LINE(DEBUG, "secondary pdump %s", pdump_opname(req->op)); + + /* Can just do it now, no need for interrupt thread */ + ret = set_pdump_rxtx_cbs(req); } + return pdump_send_response(req, ret, peer); + +} + +/* Callback from the alarm handler (in interrupt thread) which does actual change */ +static void +__pdump_request(void *param) +{ + struct pdump_bundle *bundle = param; + struct rte_mp_msg *msg = &bundle->msg; + const struct pdump_request *req = + (const struct pdump_request *)msg->param; + int ret; + + PDUMP_LOG_LINE(DEBUG, "primary pdump %s", pdump_opname(req->op)); + + ret = set_pdump_rxtx_cbs(req); + ret = pdump_send_response(req, ret, bundle->peer); + + /* Primary process is responsible for broadcasting request to all secondaries */ + if (ret == 0) + pdump_request_to_secondary(req); + + free(bundle); +} + +/* Callback from MP request handler in primary process */ +static int +pdump_handle_secondary_request(const struct rte_mp_msg *mp_msg, const void *peer) +{ + struct pdump_bundle *bundle = NULL; + const struct pdump_request *req = NULL; + int ret; + + if (mp_msg->len_param != sizeof(*req)) { + PDUMP_LOG_LINE(ERR, "invalid request from secondary"); + ret = -EINVAL; + goto error; + } + + req = (const struct pdump_request *)mp_msg->param; + + bundle = pdump_bundle_alloc(mp_msg, peer); + if (bundle == NULL) { + PDUMP_LOG_LINE(ERR, "not enough memory"); + ret = -ENOMEM; + goto error; + } + + /* + * We are in IPC callback thread, sync IPC is not possible + * since sending to secondary would cause livelock. + * Delegate the task to interrupt thread. + */ + ret = rte_eal_alarm_set(1, __pdump_request, bundle); + if (ret != 0) + goto error; return 0; + +error: + free(bundle); + return pdump_send_response(req, ret, peer); } RTE_EXPORT_SYMBOL(rte_pdump_init) @@ -469,19 +608,36 @@ rte_pdump_init(void) const struct rte_memzone *mz; int ret; - mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats), - SOCKET_ID_ANY, 0); - if (mz == NULL) { - PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics"); - rte_errno = ENOMEM; - return -1; + if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + ret = rte_mp_action_register(PDUMP_MP, pdump_handle_secondary_request); + if (ret && rte_errno != ENOTSUP) + return -1; + + mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats), + SOCKET_ID_ANY, 0); + if (mz == NULL) { + PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics"); + rte_mp_action_unregister(PDUMP_MP); + rte_errno = ENOMEM; + return -1; + } + } else { + ret = rte_mp_action_register(PDUMP_MP, pdump_handle_primary_request); + if (ret && rte_errno != ENOTSUP) + return -1; + + mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS); + if (mz == NULL) { + PDUMP_LOG_LINE(ERR, "cannot find pdump statistics"); + rte_mp_action_unregister(PDUMP_MP); + rte_errno = ENOENT; + return -1; + } } + pdump_stats = mz->addr; pdump_stats->mz = mz; - ret = rte_mp_action_register(PDUMP_MP, pdump_server); - if (ret && rte_errno != ENOTSUP) - return -1; return 0; } @@ -491,7 +647,7 @@ rte_pdump_uninit(void) { rte_mp_action_unregister(PDUMP_MP); - if (pdump_stats != NULL) { + if (rte_eal_process_type() == RTE_PROC_PRIMARY && pdump_stats != NULL) { rte_memzone_free(pdump_stats->mz); pdump_stats = NULL; } @@ -580,11 +736,12 @@ pdump_prepare_client_request(const char *device, uint16_t queue, int ret = -1; struct rte_mp_msg mp_req, *mp_rep; struct rte_mp_reply mp_reply; - struct timespec ts = {.tv_sec = 5, .tv_nsec = 0}; + struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0}; struct pdump_request *req = (struct pdump_request *)mp_req.param; struct pdump_response *resp; if (rte_eal_process_type() == RTE_PROC_PRIMARY) { + /* FIXME */ PDUMP_LOG_LINE(ERR, "pdump enable/disable not allowed in primary process"); return -EINVAL; -- 2.47.2