<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css" style="display:none;"> P {margin-top:0;margin-bottom:0;} </style>
</head>
<body dir="ltr">
<div style="font-family: Calibri, Arial, Helvetica, sans-serif; font-size: 12pt; color: rgb(0, 0, 0);">
<br>
</div>
<div id="appendonsend"></div>
<div style="font-family:Calibri,Arial,Helvetica,sans-serif; font-size:12pt; color:rgb(0,0,0)">
<br>
</div>
<hr tabindex="-1" style="display:inline-block; width:98%">
<div id="divRplyFwdMsg" dir="ltr"><font face="Calibri, sans-serif" color="#000000" style="font-size:11pt"><b>From:</b> Ferruh Yigit <ferruh.yigit@intel.com><br>
<b>Sent:</b> 17 January 2022 23:52<br>
<b>To:</b> Kumara Parameshwaran <kumaraparamesh92@gmail.com>; keith.wiles@intel.com <keith.wiles@intel.com><br>
<b>Cc:</b> dev@dpdk.org <dev@dpdk.org>; Kumara Parameshwaran <kparameshwar@vmware.com>; Raslan Darawsheh <rasland@nvidia.com><br>
<b>Subject:</b> Re: [PATCH] net/tap: Bug fix to populate fds in secondary process</font>
<div> </div>
</div>
<div class="BodyFragment"><font size="2"><span style="font-size:11pt">
<div class="PlainText">On 11/26/2021 4:15 AM, Kumara Parameshwaran wrote:<br>
> From: Kumara Parameshwaran <kparameshwar@vmware.com><br>
> <br>
> When a tap device is hotplugged to primary process which in turn<br>
> adds the device to all secondary process, the secondary process<br>
> does a tap_mp_attach_queues, but the fds are not populated in<br>
> the primary during the probe they are populated during the queue_setup,<br>
> added a fix to sync the queues during rte_eth_dev_start<br>
> <br>
<br>
Hi Kumara,<br>
<br>
Original intention seems first running primary application, later secondary,<br>
so yes it doesn't looks like covering the hotplug case.</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​Thanks. The issue is when we use the vdev_netvsc driver which uses TAP interface,  in multiprocess and RSS mode things are broken. We encountered this issue while using Azure DPDK PMD. </span><br>
<br>
I have a few questions below, can you please check?<br>
<br>
> Signed-off-by: Kumara Parameshwaran <kparameshwar@vmware.com><br>
> ---<br>
>   drivers/net/tap/rte_eth_tap.c | 80 +++++++++++++++++++++++++++++++++++<br>
>   1 file changed, 80 insertions(+)<br>
> <br>
> diff --git a/drivers/net/tap/rte_eth_tap.c b/drivers/net/tap/rte_eth_tap.c<br>
> index f1b48cae82..8e7915656b 100644<br>
> --- a/drivers/net/tap/rte_eth_tap.c<br>
> +++ b/drivers/net/tap/rte_eth_tap.c<br>
> @@ -67,6 +67,7 @@<br>
>   <br>
>   /* IPC key for queue fds sync */<br>
>   #define TAP_MP_KEY "tap_mp_sync_queues"<br>
> +#define TAP_MP_REQ_START_RXTX "tap_mp_req_start_rxtx"<br>
>   <br>
>   #define TAP_IOV_DEFAULT_MAX 1024<br>
>   <br>
> @@ -880,11 +881,51 @@ tap_link_set_up(struct rte_eth_dev *dev)<br>
>        return tap_ioctl(pmd, SIOCSIFFLAGS, &ifr, 1, LOCAL_AND_REMOTE);<br>
>   }<br>
>   <br>
> +static int tap_mp_req_on_rxtx(struct rte_eth_dev *dev)<br>
> +{<br>
> +     struct rte_mp_msg msg;<br>
> +     struct ipc_queues *request_param = (struct ipc_queues *)msg.param;<br>
> +     int err;<br>
> +     int fd_iterator = 0;<br>
> +     struct pmd_process_private *process_private = dev->process_private;<br>
> +     int i;<br>
> +<br>
> +     memset(&msg, 0, sizeof(msg));<br>
> +     strcpy(msg.name, TAP_MP_REQ_START_RXTX);<br>
> +     strlcpy(request_param->port_name, dev->data->name,<br>
> +             sizeof(request_param->port_name));<br>
<br>
Why one use 'strcpy' and other 'strlcpy', can you please unify both to 'strlcpy'?</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​Sure, will unify it. </span><br>
<br>
> +     msg.len_param = sizeof(*request_param);<br>
> +     for (i = 0; i < dev->data->nb_tx_queues; i++) {<br>
> +             msg.fds[fd_iterator++] = process_private->txq_fds[i];<br>
> +             msg.num_fds++;<br>
> +             request_param->txq_count++;<br>
> +     }<br>
> +     for (i = 0; i < dev->data->nb_rx_queues; i++) {<br>
> +             msg.fds[fd_iterator++] = process_private->rxq_fds[i];<br>
> +             msg.num_fds++;<br>
> +             request_param->rxq_count++;<br>
> +     }<br>
> +<br>
> +     RTE_ASSERT(request_param->txq_count == dev->data->nb_tx_queues);<br>
> +     RTE_ASSERT(request_param->rxq_count == dev->data->nb_rx_queues);<br>
> +<br>
<br>
Are these assertions really useful?<br>
Asserts are good to verify the external assumptions, but for this case<br>
the values are all related to above logic already.</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​I agree, will remove it. </span><br>
<br>
> +     err = rte_mp_sendmsg(&msg);<br>
> +     if (err < 0) {<br>
> +             TAP_LOG(ERR, "Failed to send start req to secondary %d",<br>
> +                     rte_errno);<br>
> +             return -1;<br>
> +     }<br>
> +<br>
> +     return 0;<br>
> +}<br>
> +<br>
>   static int<br>
>   tap_dev_start(struct rte_eth_dev *dev)<br>
>   {<br>
>        int err, i;<br>
>   <br>
> +     tap_mp_req_on_rxtx(dev);<br>
> +<br>
<br>
As for as I understand your logic is primary sends the message to the secondar(y|ies),<br>
so what happens first secondary is started?<br>
<span style="color: rgb(81, 167, 249);">​In case of TAP PMD looks like there is an assumption where primary should be started first. There is an existing check below during the probe function call. </span></div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">if (!rte_eal_primary_proc_alive(NULL)) {
<div>     TAP_LOG(ERR, "Primary process is missing");</div>
<div>      return -1;</div>
}<br>
</span></div>
<div class="PlainText"><font color="#51a7f9"><br>
</font>What about secondary sends the message when they are started?</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​IMHO, since primary process setups the queue it should be sufficient for the primary processes to the send the message and secondary need not send anything. </span><br>
<br>
Also above functions is called by both primary and secondary, what happens when it is<br>
called by secondary? And the logic is not clear, it can be good to add a process type<br>
check to clarify.</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​Sure, these are for tap_intr_handle_set and tap_dev_start functions? </span><br>
<br>
>        err = tap_intr_handle_set(dev, 1);<br>
>        if (err)<br>
>                return err;<br>
> @@ -901,6 +942,39 @@ tap_dev_start(struct rte_eth_dev *dev)<br>
>        return err;<br>
>   }<br>
>   <br>
> +static int<br>
> +tap_mp_req_start_rxtx(const struct rte_mp_msg *request, __rte_unused const void *peer)<br>
> +{<br>
> +     struct rte_eth_dev *dev;<br>
> +     int ret;<br>
> +     uint16_t port_id;<br>
> +     const struct ipc_queues *request_param =<br>
> +             (const struct ipc_queues *)request->param;<br>
> +     int fd_iterator;<br>
> +     int queue;<br>
> +     struct pmd_process_private *process_private;<br>
> +<br>
> +     ret = rte_eth_dev_get_port_by_name(request_param->port_name, &port_id);<br>
> +     if (ret) {<br>
> +             TAP_LOG(ERR, "Failed to get port id for %s",<br>
> +                     request_param->port_name);<br>
> +             return -1;<br>
> +     }<br>
> +     dev = &rte_eth_devices[port_id];> +     process_private = dev->process_private;<br>
> +     dev->data->nb_rx_queues = request_param->rxq_count;<br>
> +     dev->data->nb_tx_queues = request_param->txq_count;<br>
> +     fd_iterator = 0;<br>
> +     RTE_LOG(DEBUG, PMD, "tap_attach rx_q:%d tx_q:%d\n", request_param->rxq_count,<br>
> +             request_param->txq_count);<br>
> +     for (queue = 0; queue < request_param->txq_count; queue++)<br>
> +             process_private->txq_fds[queue] = request->fds[fd_iterator++];<br>
> +     for (queue = 0; queue < request_param->rxq_count; queue++)<br>
> +             process_private->rxq_fds[queue] = request->fds[fd_iterator++];<br>
> +<br>
> +     return 0;<br>
> +}<br>
> +<br>
>   /* This function gets called when the current port gets stopped.<br>
>    */<br>
>   static int<br>
> @@ -2445,6 +2519,12 @@ rte_pmd_tap_probe(struct rte_vdev_device *dev)<br>
>                ret = tap_mp_attach_queues(name, eth_dev);<br>
>                if (ret != 0)<br>
>                        return -1;<br>
> +<br>
> +             ret = rte_mp_action_register(TAP_MP_REQ_START_RXTX, tap_mp_req_start_rxtx);<br>
> +             if (ret < 0 && rte_errno != ENOTSUP)<br>
> +                     TAP_LOG(ERR, "tap: Failed to register IPC callback: %s",<br>
> +                             strerror(rte_errno));<br>
> +<br>
<br>
While this update fds in start logic is added, do we still need the 'tap_mp_attach_queues()'?<br>
Can't we remove the 'tap_mp_sync_queues()' after this change?<br>
<span style="color: rgb(81, 167, 249);">​Agreed, will remove the old tap_mp_attach_queues and tap_mp_sync_queues. </span><br>
<br>
And need to unregister the mp_action, possibly in the 'tap_dev_close()'?<br>
</div>
<div class="PlainText"><span style="color: rgb(81, 167, 249);">​Yes, will do it. </span><br>
</div>
</span></font></div>
</body>
</html>