Hi,

Thanks again for the patch,

As I said in the discussion of v2, I think we should keep the
condition variable, so that we can return from the datapath
functions when the port operations are effectively completed.

I also have a couple of minor coding style suggestions (inline).


Other than this the patch looks good to me

Thanks,

Daniele


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

>Current rx queue management model is buggy and will not work properly
>without additional barriers and other syncronization between PMD
>threads and main thread.
>
>Known BUGS of current model:
>       * While reloading, two PMD threads, one already reloaded and
>         one not yet reloaded, can poll same queue of the same port.
>         This behavior may lead to dpdk driver failure, because they
>         are not thread-safe.
>       * Same bug as fixed in commit e4e74c3a2b
>         ("dpif-netdev: Purge all ukeys when reconfigure pmd.") but
>         reproduced while only reconfiguring of pmd threads without
>         restarting, because addition may change the sequence of
>         other ports, which is important in time of reconfiguration.
>
>Introducing the new model, where distribution of queues made by main
>thread with minimal synchronizations and without data races between
>pmd threads. Also, this model should work faster, because only
>needed threads will be interrupted for reconfiguraition and total
>computational complexity of reconfiguration is less.
>
>Signed-off-by: Ilya Maximets <i.maxim...@samsung.com>
>---
> lib/dpif-netdev.c | 245
>++++++++++++++++++++++++++++++++----------------------
> 1 file changed, 147 insertions(+), 98 deletions(-)
>
>diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
>index cd72e62..f055c6e 100644
>--- a/lib/dpif-netdev.c
>+++ b/lib/dpif-netdev.c
>@@ -372,6 +372,13 @@ struct dp_netdev_pmd_cycles {
>     atomic_ullong n[PMD_N_CYCLES];
> };
> 
>+/* Contained by struct dp_netdev_pmd_thread's 'poll_list' member. */
>+struct rxq_poll {
>+    struct dp_netdev_port *port;
>+    struct netdev_rxq *rx;
>+    struct ovs_list node;
>+};
>+
> /* PMD: Poll modes drivers.  PMD accesses devices via polling to
>eliminate
>  * the performance overhead of interrupt processing.  Therefore netdev
>can
>  * not implement rx-wait for these devices.  dpif-netdev needs to poll
>@@ -393,9 +400,6 @@ struct dp_netdev_pmd_thread {
>     struct ovs_refcount ref_cnt;    /* Every reference must be
>refcount'ed. */
>     struct cmap_node node;          /* In 'dp->poll_threads'. */
> 
>-    pthread_cond_t cond;            /* For synchronizing pmd thread
>reload. */
>-    struct ovs_mutex cond_mutex;    /* Mutex for condition variable. */
>-
>     /* Per thread exact-match cache.  Note, the instance for cpu core
>      * NON_PMD_CORE_ID can be accessed by multiple threads, and thusly
>      * need to be protected (e.g. by 'dp_netdev_mutex').  All other
>@@ -430,6 +434,11 @@ struct dp_netdev_pmd_thread {
>     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. */
>+    /* List of rx queues to poll. */
>+    struct ovs_list poll_list OVS_GUARDED;
>+    int poll_cnt;                   /* Number of elemints in poll_list.
>*/
>+
>     /* Only a pmd thread can write on its own 'cycles' and 'stats'.
>      * The main thread keeps 'stats_zero' and 'cycles_zero' as base
>      * values and subtracts them from 'stats' and 'cycles' before
>@@ -469,7 +478,6 @@ static void dp_netdev_input(struct
>dp_netdev_pmd_thread *,
>                             struct dp_packet **, int cnt);
> 
> static void dp_netdev_disable_upcall(struct dp_netdev *);
>-void dp_netdev_pmd_reload_done(struct dp_netdev_pmd_thread *pmd);

Assuming we're keeping this function, I think it should be made static.
This wasn't introduced by this patch, but it would be nice to fix it
anyway.


> static void dp_netdev_configure_pmd(struct dp_netdev_pmd_thread *pmd,
>                                     struct dp_netdev *dp, int index,
>                                     unsigned core_id, int numa_id);
>@@ -482,6 +490,11 @@ dp_netdev_pmd_get_next(struct dp_netdev *dp, struct
>cmap_position *pos);
> static void dp_netdev_destroy_all_pmds(struct dp_netdev *dp);
> static void dp_netdev_del_pmds_on_numa(struct dp_netdev *dp, int
>numa_id);
> static void dp_netdev_set_pmds_on_numa(struct dp_netdev *dp, int
>numa_id);
>+static void
>+dp_netdev_add_rxq_to_pmd(struct dp_netdev_pmd_thread *pmd,
>+                         struct dp_netdev_port *port, struct netdev_rxq
>*rx);
>+static struct dp_netdev_pmd_thread *
>+dp_netdev_less_loaded_pmd_on_numa(struct dp_netdev *dp, int numa_id);
> static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp);
> static bool dp_netdev_pmd_try_ref(struct dp_netdev_pmd_thread *pmd);
> static void dp_netdev_pmd_unref(struct dp_netdev_pmd_thread *pmd);
>@@ -1019,22 +1032,7 @@ dp_netdev_reload_pmd__(struct dp_netdev_pmd_thread
>*pmd)
>         return;
>     }
> 
>-    ovs_mutex_lock(&pmd->cond_mutex);
>     atomic_add_relaxed(&pmd->change_seq, 1, &old_seq);
>-    ovs_mutex_cond_wait(&pmd->cond, &pmd->cond_mutex);
>-    ovs_mutex_unlock(&pmd->cond_mutex);
>-}
>-
>-/* Causes all pmd threads to reload its tx/rx devices.
>- * Must be called after adding/removing ports. */
>-static void
>-dp_netdev_reload_pmds(struct dp_netdev *dp)
>-{
>-    struct dp_netdev_pmd_thread *pmd;
>-
>-    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
>-        dp_netdev_reload_pmd__(pmd);
>-    }
> }
> 
> static uint32_t
>@@ -1128,8 +1126,26 @@ do_add_port(struct dp_netdev *dp, const char
>*devname, const char *type,
>     cmap_insert(&dp->ports, &port->node, hash_port_no(port_no));
> 
>     if (netdev_is_pmd(netdev)) {
>-        dp_netdev_set_pmds_on_numa(dp, netdev_get_numa_id(netdev));
>-        dp_netdev_reload_pmds(dp);
>+        int numa_id = netdev_get_numa_id(netdev);
>+        struct dp_netdev_pmd_thread *pmd;
>+
>+        /* Cannot create pmd threads for invalid numa node. */
>+        ovs_assert(ovs_numa_numa_id_is_valid(numa_id));
>+
>+        for (i = 0; i < netdev_n_rxq(netdev); i++) {
>+            pmd = dp_netdev_less_loaded_pmd_on_numa(dp, numa_id);
>+            if (!pmd) {
>+                /* There is no pmd threads on this numa node. */
>+                dp_netdev_set_pmds_on_numa(dp, numa_id);
>+                /* Assigning of rx queues done. */
>+                break;
>+            }
>+
>+            ovs_mutex_lock(&pmd->poll_mutex);
>+            dp_netdev_add_rxq_to_pmd(pmd, port, port->rxq[i]);
>+            ovs_mutex_unlock(&pmd->poll_mutex);
>+            dp_netdev_reload_pmd__(pmd);
>+        }
>     }
>     seq_change(dp->port_seq);
> 
>@@ -1226,16 +1242,6 @@ port_ref(struct dp_netdev_port *port)
>     }
> }
> 
>-static bool
>-port_try_ref(struct dp_netdev_port *port)
>-{
>-    if (port) {
>-        return ovs_refcount_try_ref_rcu(&port->ref_cnt);
>-    }
>-
>-    return false;
>-}
>-
> static void
> port_unref(struct dp_netdev_port *port)
> {
>@@ -1313,12 +1319,38 @@ do_del_port(struct dp_netdev *dp, struct
>dp_netdev_port *port)
>     if (netdev_is_pmd(port->netdev)) {
>         int numa_id = netdev_get_numa_id(port->netdev);
> 
>+        /* PMD threads can not be on invalid numa node. */
>+        ovs_assert(ovs_numa_numa_id_is_valid(numa_id));
>         /* If there is no netdev on the numa node, deletes the pmd
>threads
>-         * for that numa.  Else, just reloads the queues.  */
>+         * for that numa.  Else, deletes the queues from polling lists.
>*/
>         if (!has_pmd_port_for_numa(dp, numa_id)) {
>             dp_netdev_del_pmds_on_numa(dp, numa_id);
>         }
>-        dp_netdev_reload_pmds(dp);
>+        else {

This should be

} else {

on the same line


>+            struct dp_netdev_pmd_thread *pmd;
>+            struct rxq_poll *poll, *next;
>+
>+            CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
>+                if (pmd->numa_id == numa_id) {
>+                    bool found = false;
>+
>+                    ovs_mutex_lock(&pmd->poll_mutex);
>+                    LIST_FOR_EACH_SAFE (poll, next, node,
>&pmd->poll_list) {
>+                        if (poll->port == port) {
>+                            found = true;
>+                            port_unref(poll->port);
>+                            list_remove(&poll->node);
>+                            pmd->poll_cnt--;
>+                            free(poll);
>+                        }
>+                    }
>+                    ovs_mutex_unlock(&pmd->poll_mutex);
>+                    if (found) {
>+                        dp_netdev_reload_pmd__(pmd);
>+                    }
>+                }
>+            }
>+        }
>     }
> 
>     port_unref(port);

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

Reply via email to