Thanks for the patch, I applied this to master and branch-2.5 with
a minor change: since tx_qid is accessed concurrently by multiple
threads, it seems that it should be atomic.

This is just a formality: I've used relaxed semantics so there should
be no change to the compiled code.

Here's the incremental:

diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 24946b7..ad6b202 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -434,7 +434,7 @@ struct dp_netdev_pmd_thread {
                                     /* threads on same numa node. */
     unsigned core_id;               /* CPU core id of this pmd thread. */
     int numa_id;                    /* numa node id of this pmd thread. */
-    int tx_qid;                     /* Queue id used by this pmd thread to
+    atomic_int tx_qid;              /* Queue id used by this pmd thread to
                                      * send packets on all netdevs */

     struct ovs_mutex poll_mutex;    /* Mutex for poll_list. */
@@ -2838,8 +2838,11 @@ dp_netdev_configure_pmd(struct dp_netdev_pmd_thread
*pmd, struct dp_netdev *dp,
     pmd->numa_id = numa_id;
     pmd->poll_cnt = 0;

-    pmd->tx_qid = (core_id == NON_PMD_CORE_ID) ? ovs_numa_get_n_cores()
-                                               : get_n_pmd_threads(dp);
+    atomic_init(&pmd->tx_qid,
+                (core_id == NON_PMD_CORE_ID)
+                ? ovs_numa_get_n_cores()
+                : get_n_pmd_threads(dp));
+
     ovs_refcount_init(&pmd->ref_cnt);
     latch_init(&pmd->exit_latch);
     atomic_init(&pmd->change_seq, PMD_INITIAL_SEQ);
@@ -2931,15 +2934,22 @@ dp_netdev_del_pmds_on_numa(struct dp_netdev *dp,
int numa_id)

     CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
         if (pmd->numa_id == numa_id) {
-            free_idx[k++] = pmd->tx_qid;
+            atomic_read_relaxed(&pmd->tx_qid, &free_idx[k]);
+            k++;
             dp_netdev_del_pmd(dp, pmd);
         }
     }

     n_pmds = get_n_pmd_threads(dp);
     CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
-        if (pmd->tx_qid >= n_pmds) {
-            pmd->tx_qid = free_idx[--k];
+        int old_tx_qid;
+
+        atomic_read_relaxed(&pmd->tx_qid, &old_tx_qid);
+
+        if (old_tx_qid >= n_pmds) {
+            int new_tx_qid = free_idx[--k];
+
+            atomic_store_relaxed(&pmd->tx_qid, new_tx_qid);
         }
     }

@@ -3585,7 +3595,11 @@ dp_execute_cb(void *aux_, struct dp_packet
**packets, int cnt,
     case OVS_ACTION_ATTR_OUTPUT:
         p = dp_netdev_lookup_port(dp, u32_to_odp(nl_attr_get_u32(a)));
         if (OVS_LIKELY(p)) {
-            netdev_send(p->netdev, pmd->tx_qid, packets, cnt, may_steal);
+            int tx_qid;
+
+            atomic_read_relaxed(&pmd->tx_qid, &tx_qid);
+
+            netdev_send(p->netdev, tx_qid, packets, cnt, may_steal);
             return;
         }
         break;


On 25/01/2016 22:12, "Ilya Maximets" <i.maxim...@samsung.com> wrote:

>Currently tx_qid is equal to pmd->core_id. This leads to unexpected
>behavior if pmd-cpu-mask different from '/(0*)(1|3|7)?(f*)/',
>e.g. if core_ids are not sequential, or doesn't start from 0, or both.
>
>Example:
>       starting 2 pmd threads with 1 port, 2 rxqs per port,
>       pmd-cpu-mask = 00000014 and let dev->real_n_txq = 2
>
>       It that case pmd_1->tx_qid = 2, pmd_2->tx_qid = 4 and
>       txq_needs_locking = true (if device hasn't ovs_numa_get_n_cores()+1
>       queues).
>
>       In that case, after truncating in netdev_dpdk_send__():
>               'qid = qid % dev->real_n_txq;'
>       pmd_1: qid = 2 % 2 = 0
>       pmd_2: qid = 4 % 2 = 0
>
>       So, both threads will call dpdk_queue_pkts() with same qid = 0.
>       This is unexpected behavior if there is 2 tx queues in device.
>       Queue #1 will not be used and both threads will lock queue #0
>       on each send.
>
>Fix that by using sequential tx_qids.
>
>Signed-off-by: Ilya Maximets <i.maxim...@samsung.com>
>---
> lib/dpif-netdev.c | 38 ++++++++++++++++++++++++++------------
> 1 file changed, 26 insertions(+), 12 deletions(-)
>
>diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>index 8c87c05..24946b7 100644
>--- a/lib/dpif-netdev.c
>+++ b/lib/dpif-netdev.c
>@@ -1285,6 +1285,13 @@ get_port_by_name(struct dp_netdev *dp,
> }
> 
> static int
>+get_n_pmd_threads(struct dp_netdev *dp)
>+{
>+    /* There is one non pmd thread in dp->poll_threads */
>+    return cmap_count(&dp->poll_threads) - 1;
>+}
>+
>+static int
> get_n_pmd_threads_on_numa(struct dp_netdev *dp, int numa_id)
> {
>     struct dp_netdev_pmd_thread *pmd;
>@@ -2820,16 +2827,6 @@ dp_netdev_pmd_get_next(struct dp_netdev *dp,
>struct cmap_position *pos)
>     return next;
> }
> 
>-static int
>-core_id_to_qid(unsigned core_id)
>-{
>-    if (core_id != NON_PMD_CORE_ID) {
>-        return core_id;
>-    } else {
>-        return ovs_numa_get_n_cores();
>-    }
>-}
>-
> /* Configures the 'pmd' based on the input argument. */
> static void
> dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd, struct
>dp_netdev *dp,
>@@ -2838,10 +2835,11 @@ dp_netdev_configure_pmd(struct
>dp_netdev_pmd_thread *pmd, struct dp_netdev *dp,
>     pmd->dp = dp;
>     pmd->index = index;
>     pmd->core_id = core_id;
>-    pmd->tx_qid = core_id_to_qid(core_id);
>     pmd->numa_id = numa_id;
>     pmd->poll_cnt = 0;
> 
>+    pmd->tx_qid = (core_id == NON_PMD_CORE_ID) ? ovs_numa_get_n_cores()
>+                                               : get_n_pmd_threads(dp);
>     ovs_refcount_init(&pmd->ref_cnt);
>     latch_init(&pmd->exit_latch);
>     atomic_init(&pmd->change_seq, PMD_INITIAL_SEQ);
>@@ -2919,17 +2917,33 @@ dp_netdev_destroy_all_pmds(struct dp_netdev *dp)
>     }
> }
> 
>-/* Deletes all pmd threads on numa node 'numa_id'. */
>+/* Deletes all pmd threads on numa node 'numa_id' and
>+ * fixes tx_qids of other threads to keep them sequential. */
> static void
> dp_netdev_del_pmds_on_numa(struct dp_netdev *dp, int numa_id)
> {
>     struct dp_netdev_pmd_thread *pmd;
>+    int n_pmds_on_numa, n_pmds;
>+    int *free_idx, k = 0;
>+
>+    n_pmds_on_numa = get_n_pmd_threads_on_numa(dp, numa_id);
>+    free_idx = xmalloc(n_pmds_on_numa * sizeof *free_idx);
> 
>     CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
>         if (pmd->numa_id == numa_id) {
>+            free_idx[k++] = pmd->tx_qid;
>             dp_netdev_del_pmd(dp, pmd);
>         }
>     }
>+
>+    n_pmds = get_n_pmd_threads(dp);
>+    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
>+        if (pmd->tx_qid >= n_pmds) {
>+            pmd->tx_qid = free_idx[--k];
>+        }
>+    }
>+
>+    free(free_idx);
> }
> 
> /* Returns PMD thread from this numa node with fewer rx queues to poll.
>-- 
>2.5.0
>

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to