Skip to content

Commit c3ceb87

Browse files
shemmingertmonjalo
authored andcommitted
pdump: forward callback enable to secondary process
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 <[email protected]> Acked-by: Bruce Richardson <[email protected]> Acked-by: Khadem Ullah <[email protected]>
1 parent 05326ef commit c3ceb87

File tree

2 files changed

+190
-28
lines changed

2 files changed

+190
-28
lines changed

doc/guides/rel_notes/release_25_11.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ New Features
202202
It is now possible to register an RCU QSBR object
203203
to handle graceful deletion of table groups.
204204

205+
* **Added packet capture (pdump) for secondary process.**
206+
207+
Added multi-process support to allow packets sent and received
208+
by secondary process to be visible in packet capture.
209+
205210
* **Allow overriding the automatic usage/help generation in argparse library.**
206211

207212
The argparse library now supports overriding the automatic help text generation,

lib/pdump/rte_pdump.c

Lines changed: 185 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <stdlib.h>
66

77
#include <eal_export.h>
8+
#include <rte_alarm.h>
89
#include <rte_mbuf.h>
910
#include <rte_ethdev.h>
1011
#include <rte_lcore.h>
@@ -26,11 +27,28 @@ RTE_LOG_REGISTER_DEFAULT(pdump_logtype, NOTICE);
2627
/* Used for the multi-process communication */
2728
#define PDUMP_MP "mp_pdump"
2829

30+
/* Overly generous timeout for secondary to respond */
31+
#define MP_TIMEOUT_S 5
32+
2933
enum pdump_operation {
3034
DISABLE = 1,
3135
ENABLE = 2
3236
};
3337

38+
static const char *
39+
pdump_opname(enum pdump_operation op)
40+
{
41+
static char buf[32];
42+
43+
if (op == DISABLE)
44+
return "disable";
45+
if (op == ENABLE)
46+
return "enable";
47+
48+
snprintf(buf, sizeof(buf), "op%u", op);
49+
return buf;
50+
}
51+
3452
/* Internal version number in request */
3553
enum pdump_version {
3654
V1 = 1, /* no filtering or snap */
@@ -56,6 +74,11 @@ struct pdump_response {
5674
int32_t err_value;
5775
};
5876

77+
struct pdump_bundle {
78+
struct rte_mp_msg msg;
79+
char peer[];
80+
};
81+
5982
static struct pdump_rxtx_cbs {
6083
struct rte_ring *ring;
6184
struct rte_mempool *mp;
@@ -432,34 +455,150 @@ set_pdump_rxtx_cbs(const struct pdump_request *p)
432455
return ret;
433456
}
434457

458+
static void
459+
pdump_request_to_secondary(const struct pdump_request *req)
460+
{
461+
struct rte_mp_msg mp_req = { };
462+
struct rte_mp_reply mp_reply;
463+
struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
464+
465+
PDUMP_LOG_LINE(DEBUG, "forward req %s to secondary", pdump_opname(req->op));
466+
467+
memcpy(mp_req.param, req, sizeof(*req));
468+
strlcpy(mp_req.name, PDUMP_MP, sizeof(mp_req.name));
469+
mp_req.len_param = sizeof(*req);
470+
471+
if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) != 0)
472+
PDUMP_LOG_LINE(ERR, "rte_mp_request_sync failed");
473+
474+
else if (mp_reply.nb_sent != mp_reply.nb_received)
475+
PDUMP_LOG_LINE(ERR, "not all secondary's replied (sent %u recv %u)",
476+
mp_reply.nb_sent, mp_reply.nb_received);
477+
478+
free(mp_reply.msgs);
479+
}
480+
481+
/* Allocate temporary storage for passing state to the alarm thread for deferred handling */
482+
static struct pdump_bundle *
483+
pdump_bundle_alloc(const struct rte_mp_msg *mp_msg, const char *peer)
484+
{
485+
struct pdump_bundle *bundle;
486+
size_t peer_len = strlen(peer) + 1;
487+
488+
/* peer is the unix domain socket path */
489+
bundle = malloc(sizeof(*bundle) + peer_len);
490+
if (bundle == NULL)
491+
return NULL;
492+
493+
bundle->msg = *mp_msg;
494+
memcpy(bundle->peer, peer, peer_len);
495+
return bundle;
496+
}
497+
498+
/* Send response to peer */
435499
static int
436-
pdump_server(const struct rte_mp_msg *mp_msg, const void *peer)
500+
pdump_send_response(const struct pdump_request *req, int result, const void *peer)
437501
{
438-
struct rte_mp_msg mp_resp;
439-
const struct pdump_request *cli_req;
440-
struct pdump_response *resp = (struct pdump_response *)&mp_resp.param;
502+
struct rte_mp_msg mp_resp = { };
503+
struct pdump_response *resp = (struct pdump_response *)mp_resp.param;
504+
int ret;
441505

442-
/* recv client requests */
443-
if (mp_msg->len_param != sizeof(*cli_req)) {
444-
PDUMP_LOG_LINE(ERR, "failed to recv from client");
445-
resp->err_value = -EINVAL;
446-
} else {
447-
cli_req = (const struct pdump_request *)mp_msg->param;
448-
resp->ver = cli_req->ver;
449-
resp->res_op = cli_req->op;
450-
resp->err_value = set_pdump_rxtx_cbs(cli_req);
506+
if (req) {
507+
resp->ver = req->ver;
508+
resp->res_op = req->op;
451509
}
510+
resp->err_value = result;
452511

453512
rte_strscpy(mp_resp.name, PDUMP_MP, RTE_MP_MAX_NAME_LEN);
454513
mp_resp.len_param = sizeof(*resp);
455-
mp_resp.num_fds = 0;
456-
if (rte_mp_reply(&mp_resp, peer) < 0) {
457-
PDUMP_LOG_LINE(ERR, "failed to send to client:%s",
514+
515+
ret = rte_mp_reply(&mp_resp, peer);
516+
if (ret != 0)
517+
PDUMP_LOG_LINE(ERR, "failed to send response: %s",
458518
strerror(rte_errno));
459-
return -1;
519+
return ret;
520+
}
521+
522+
/* Callback from MP request handler in secondary process */
523+
static int
524+
pdump_handle_primary_request(const struct rte_mp_msg *mp_msg, const void *peer)
525+
{
526+
const struct pdump_request *req = NULL;
527+
int ret;
528+
529+
if (mp_msg->len_param != sizeof(*req)) {
530+
PDUMP_LOG_LINE(ERR, "invalid request from primary");
531+
ret = -EINVAL;
532+
} else {
533+
req = (const struct pdump_request *)mp_msg->param;
534+
PDUMP_LOG_LINE(DEBUG, "secondary pdump %s", pdump_opname(req->op));
535+
536+
/* Can just do it now, no need for interrupt thread */
537+
ret = set_pdump_rxtx_cbs(req);
460538
}
461539

540+
return pdump_send_response(req, ret, peer);
541+
542+
}
543+
544+
/* Callback from the alarm handler (in interrupt thread) which does actual change */
545+
static void
546+
__pdump_request(void *param)
547+
{
548+
struct pdump_bundle *bundle = param;
549+
struct rte_mp_msg *msg = &bundle->msg;
550+
const struct pdump_request *req =
551+
(const struct pdump_request *)msg->param;
552+
int ret;
553+
554+
PDUMP_LOG_LINE(DEBUG, "primary pdump %s", pdump_opname(req->op));
555+
556+
ret = set_pdump_rxtx_cbs(req);
557+
ret = pdump_send_response(req, ret, bundle->peer);
558+
559+
/* Primary process is responsible for broadcasting request to all secondaries */
560+
if (ret == 0)
561+
pdump_request_to_secondary(req);
562+
563+
free(bundle);
564+
}
565+
566+
/* Callback from MP request handler in primary process */
567+
static int
568+
pdump_handle_secondary_request(const struct rte_mp_msg *mp_msg, const void *peer)
569+
{
570+
struct pdump_bundle *bundle = NULL;
571+
const struct pdump_request *req = NULL;
572+
int ret;
573+
574+
if (mp_msg->len_param != sizeof(*req)) {
575+
PDUMP_LOG_LINE(ERR, "invalid request from secondary");
576+
ret = -EINVAL;
577+
goto error;
578+
}
579+
580+
req = (const struct pdump_request *)mp_msg->param;
581+
582+
bundle = pdump_bundle_alloc(mp_msg, peer);
583+
if (bundle == NULL) {
584+
PDUMP_LOG_LINE(ERR, "not enough memory");
585+
ret = -ENOMEM;
586+
goto error;
587+
}
588+
589+
/*
590+
* We are in IPC callback thread, sync IPC is not possible
591+
* since sending to secondary would cause livelock.
592+
* Delegate the task to interrupt thread.
593+
*/
594+
ret = rte_eal_alarm_set(1, __pdump_request, bundle);
595+
if (ret != 0)
596+
goto error;
462597
return 0;
598+
599+
error:
600+
free(bundle);
601+
return pdump_send_response(req, ret, peer);
463602
}
464603

465604
RTE_EXPORT_SYMBOL(rte_pdump_init)
@@ -469,19 +608,36 @@ rte_pdump_init(void)
469608
const struct rte_memzone *mz;
470609
int ret;
471610

472-
mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
473-
SOCKET_ID_ANY, 0);
474-
if (mz == NULL) {
475-
PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics");
476-
rte_errno = ENOMEM;
477-
return -1;
611+
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
612+
ret = rte_mp_action_register(PDUMP_MP, pdump_handle_secondary_request);
613+
if (ret && rte_errno != ENOTSUP)
614+
return -1;
615+
616+
mz = rte_memzone_reserve(MZ_RTE_PDUMP_STATS, sizeof(*pdump_stats),
617+
SOCKET_ID_ANY, 0);
618+
if (mz == NULL) {
619+
PDUMP_LOG_LINE(ERR, "cannot allocate pdump statistics");
620+
rte_mp_action_unregister(PDUMP_MP);
621+
rte_errno = ENOMEM;
622+
return -1;
623+
}
624+
} else {
625+
ret = rte_mp_action_register(PDUMP_MP, pdump_handle_primary_request);
626+
if (ret && rte_errno != ENOTSUP)
627+
return -1;
628+
629+
mz = rte_memzone_lookup(MZ_RTE_PDUMP_STATS);
630+
if (mz == NULL) {
631+
PDUMP_LOG_LINE(ERR, "cannot find pdump statistics");
632+
rte_mp_action_unregister(PDUMP_MP);
633+
rte_errno = ENOENT;
634+
return -1;
635+
}
478636
}
637+
479638
pdump_stats = mz->addr;
480639
pdump_stats->mz = mz;
481640

482-
ret = rte_mp_action_register(PDUMP_MP, pdump_server);
483-
if (ret && rte_errno != ENOTSUP)
484-
return -1;
485641
return 0;
486642
}
487643

@@ -491,7 +647,7 @@ rte_pdump_uninit(void)
491647
{
492648
rte_mp_action_unregister(PDUMP_MP);
493649

494-
if (pdump_stats != NULL) {
650+
if (rte_eal_process_type() == RTE_PROC_PRIMARY && pdump_stats != NULL) {
495651
rte_memzone_free(pdump_stats->mz);
496652
pdump_stats = NULL;
497653
}
@@ -580,11 +736,12 @@ pdump_prepare_client_request(const char *device, uint16_t queue,
580736
int ret = -1;
581737
struct rte_mp_msg mp_req, *mp_rep;
582738
struct rte_mp_reply mp_reply;
583-
struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
739+
struct timespec ts = {.tv_sec = MP_TIMEOUT_S, .tv_nsec = 0};
584740
struct pdump_request *req = (struct pdump_request *)mp_req.param;
585741
struct pdump_response *resp;
586742

587743
if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
744+
/* FIXME */
588745
PDUMP_LOG_LINE(ERR,
589746
"pdump enable/disable not allowed in primary process");
590747
return -EINVAL;

0 commit comments

Comments
 (0)