From: Stephen Hemminger <stephen@networkplumber.org>
To: dev@dpdk.org
Cc: Stephen Hemminger <stephen@networkplumber.org>
Subject: [RFC 6/6] pdump: forward callback enable to secondary
Date: Mon, 11 Aug 2025 14:35:04 -0700 [thread overview]
Message-ID: <20250811213632.16023-7-stephen@networkplumber.org> (raw)
In-Reply-To: <20250811213632.16023-1-stephen@networkplumber.org>
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 <stephen@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
prev parent reply other threads:[~2025-08-11 21:37 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-11 21:34 [RFC 0/6] Packet capture fixes Stephen Hemminger
2025-08-11 21:34 ` [RFC 1/6] dumpcap: handle primary process exit Stephen Hemminger
2025-08-11 21:35 ` [RFC 2/6] pdump: " Stephen Hemminger
2025-08-11 21:35 ` [RFC 3/6] pdump: fix races in callbacks Stephen Hemminger
2025-08-11 21:35 ` [RFC 4/6] dumpcap: handle pdump requests from primary Stephen Hemminger
2025-08-11 21:35 ` [RFC 5/6] pdump: " Stephen Hemminger
2025-08-11 21:35 ` Stephen Hemminger [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250811213632.16023-7-stephen@networkplumber.org \
--to=stephen@networkplumber.org \
--cc=dev@dpdk.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).