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+
2933enum 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 */
3553enum 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+
5982static 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 */
435499static 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
465604RTE_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