Sorry for the delayed reply,

I tested this patch yesterday, found that this is not right fix,

Turns out, dp_netdev_reset_pmd_threads() just creates (or restores) pmd
threads...  and we call dp_netdev_destroy_all_pmds() at the beginning of the
function.  So, when purge_cb() is called, the flows in each 'pmd' have
already
gone...  So, we did not harvest the last bit of stats,

Instead, I think the right place to call purge_cb() is between pmd thread
stop
and deletion in dp_netdev_del_pmd().  Please see the V2 patch for details,

Thanks,
Alex Wang,

On Mon, Aug 17, 2015 at 11:09 PM, Ilya Maximets <i.maxim...@samsung.com>
wrote:

>
> On 17.08.2015 20:35, Alex Wang wrote:
> >
> >
> > On Mon, Aug 17, 2015 at 10:22 AM, Daniele Di Proietto <
> diproiet...@vmware.com <mailto:diproiet...@vmware.com>> wrote:
> >
> >     The patch looks good to me.
> >
> >     I think that losing some packets when the thread are reconfigured
> >     is unavoidable, considering that often the NIC must be stopped
> >     to change the number of rxqs.  Does this make sense?
> >
> >
> > Thx, Daniele,
> >
> > Ilya, if you are also okay, I'll push this to master.
>
> Ok. I think, it's good.
>
> Acked-by: Ilya Maximets <i.maxim...@samsung.com>
>
> >
> >
> >
> >     Related to this, I've had an offline discussion with Ethan
> >     and we realized that ukeys are never deleted if the datapath
> >     flow disappear for other reasons (e.g. ovs-dpctl del-flows).
> >     Should we address these issues toghether?
> >
> >
> > For this issue, to be more specific, the ukeys are never deleted if:
> > 1. datapath flow disappears,
> > 2. && there is no userspace changes which causes increments of reval_seq.
> >
> > In other words, once 'need_revalidate' is true, the obsolete ukeys
> should be
> > deleted at revaidator_sweep() stage.  Right?
> >
> > This sounds to me like a different issue and may require more thinking,
> so I'd
> > like to keep it a separate issue,
> >
> > Thanks,
> > Alex Wang,
> >
> >
> >     Thanks
> >
> >     On 11/08/2015 03:47, "Alex Wang" <al...@nicira.com <mailto:
> al...@nicira.com>> wrote:
> >
> >     >When dpdk configuration changes, all pmd threads are recreated
> >     >and rx queues of each port are reloaded.  After this process,
> >     >rx queue could be mapped to a different pmd thread other than
> >     >the one before reconfiguration.  However, this is totally
> >     >transparent to ofproto layer modules.  So, if the
> ofproto-dpif-upcall
> >     >module still holds ukeys generated before pmd thread recreation,
> >     >this old ukey will collide with the ukey for the new upcalls
> >     >from same traffic flow, causing flow installation failure.
> >     >
> >     >To fix the bug, this commit adds a new call-back function
> >     >in dpif layer for notifying upper layer the purging of datapath
> >     >(e.g. pmd threads recreation in dpif-netdev).  So, the
> >     >ofproto-dpif-upcall module can react properly with deleting
> >     >all the ukeys and with collecting all flows' last stats.
> >     >
> >     >Reported-by: Ilya Maximets <i.maxim...@samsung.com <mailto:
> i.maxim...@samsung.com>>
> >     >Signed-off-by: Alex Wang <al...@nicira.com <mailto:al...@nicira.com
> >>
> >     >---
> >     > lib/dpif-netdev.c             |   25 +++++++++++++++++++++++++
> >     > lib/dpif-netlink.c            |    1 +
> >     > lib/dpif-provider.h           |   11 ++++++++++-
> >     > lib/dpif.c                    |    8 ++++++++
> >     > lib/dpif.h                    |   12 ++++++++++++
> >     > ofproto/ofproto-dpif-upcall.c |   16 ++++++++++++++++
> >     > 6 files changed, 72 insertions(+), 1 deletion(-)
> >     >
> >     >diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> >     >index c144352..a54853f 100644
> >     >--- a/lib/dpif-netdev.c
> >     >+++ b/lib/dpif-netdev.c
> >     >@@ -203,6 +203,11 @@ struct dp_netdev {
> >     >     upcall_callback *upcall_cb;  /* Callback function for executing
> >     >upcalls. */
> >     >     void *upcall_aux;
> >     >
> >     >+    /* Callback function for notifying the purging of dp flows
> (during
> >     >+     * reseting pmd threads). */
> >     >+    dp_purge_callback *dp_purge_cb;
> >     >+    void *dp_purge_aux;
> >     >+
> >     >     /* Stores all 'struct dp_netdev_pmd_thread's. */
> >     >     struct cmap poll_threads;
> >     >
> >     >@@ -223,6 +228,8 @@ struct dp_netdev {
> >     >
> >     > static struct dp_netdev_port *dp_netdev_lookup_port(const struct
> >     >dp_netdev *dp,
> >     >                                                     odp_port_t);
> >     >+static void dp_netdev_disable_upcall(struct dp_netdev *);
> >     >+static void dp_netdev_enable_upcall(struct dp_netdev *);
> >     >
> >     > enum dp_stat_type {
> >     >     DP_STAT_EXACT_HIT,          /* Packets that had an exact match
> >     >(emc). */
> >     >@@ -2440,10 +2447,18 @@ dpif_netdev_pmd_set(struct dpif *dpif,
> unsigned
> >     >int n_rxqs, const char *cmask)
> >     >         free(dp->pmd_cmask);
> >     >         dp->pmd_cmask = cmask ? xstrdup(cmask) : NULL;
> >     >
> >     >+        /* Disables upcall and notifies higher layer about the
> incoming
> >     >+         * datapath purging. */
> >     >+        dp_netdev_disable_upcall(dp);
> >     >+        dp->dp_purge_cb(dp->dp_purge_aux);
> >     >+
> >     >         /* Restores the non-pmd. */
> >     >         dp_netdev_set_nonpmd(dp);
> >     >         /* Restores all pmd threads. */
> >     >         dp_netdev_reset_pmd_threads(dp);
> >     >+
> >     >+        /* Enables upcall after pmd reconfiguration. */
> >     >+        dp_netdev_enable_upcall(dp);
> >     >     }
> >     >
> >     >     return 0;
> >     >@@ -3419,6 +3434,15 @@ struct dp_netdev_execute_aux {
> >     > };
> >     >
> >     > static void
> >     >+dpif_netdev_register_dp_purge_cb(struct dpif *dpif,
> dp_purge_callback
> >     >*cb,
> >     >+                                 void *aux)
> >     >+{
> >     >+    struct dp_netdev *dp = get_dp_netdev(dpif);
> >     >+    dp->dp_purge_aux = aux;
> >     >+    dp->dp_purge_cb = cb;
> >     >+}
> >     >+
> >     >+static void
> >     > dpif_netdev_register_upcall_cb(struct dpif *dpif, upcall_callback
> *cb,
> >     >                                void *aux)
> >     > {
> >     >@@ -3665,6 +3689,7 @@ const struct dpif_class dpif_netdev_class = {
> >     >     NULL,                       /* recv */
> >     >     NULL,                       /* recv_wait */
> >     >     NULL,                       /* recv_purge */
> >     >+    dpif_netdev_register_dp_purge_cb,
> >     >     dpif_netdev_register_upcall_cb,
> >     >     dpif_netdev_enable_upcall,
> >     >     dpif_netdev_disable_upcall,
> >     >diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
> >     >index 8884a9f..f8f3092 100644
> >     >--- a/lib/dpif-netlink.c
> >     >+++ b/lib/dpif-netlink.c
> >     >@@ -2314,6 +2314,7 @@ const struct dpif_class dpif_netlink_class = {
> >     >     dpif_netlink_recv,
> >     >     dpif_netlink_recv_wait,
> >     >     dpif_netlink_recv_purge,
> >     >+    NULL,                       /* register_dp_purge_cb */
> >     >     NULL,                       /* register_upcall_cb */
> >     >     NULL,                       /* enable_upcall */
> >     >     NULL,                       /* disable_upcall */
> >     >diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
> >     >index 28ea86f..8f2690f 100644
> >     >--- a/lib/dpif-provider.h
> >     >+++ b/lib/dpif-provider.h
> >     >@@ -361,13 +361,22 @@ struct dpif_class {
> >     >      * return. */
> >     >     void (*recv_purge)(struct dpif *dpif);
> >     >
> >     >+    /* When 'dpif' is about to purge the datapath, the higher
> layer may
> >     >want
> >     >+     * to be notified so that it could try reacting accordingly
> (e.g.
> >     >grabbing
> >     >+     * all flow stats before they are gone).
> >     >+     *
> >     >+     * Registers an upcall callback function with 'dpif'.  This is
> only
> >     >used if
> >     >+     * if 'dpif' needs to notify the purging of datapath.  'aux' is
> >     >passed to
> >     >+     * the callback on invocation. */
> >     >+    void (*register_dp_purge_cb)(struct dpif *, dp_purge_callback
> *,
> >     >void *aux);
> >     >+
> >     >     /* For datapaths that run in userspace (i.e. dpif-netdev),
> threads
> >     >polling
> >     >      * for incoming packets can directly call upcall functions
> instead of
> >     >      * offloading packet processing to separate handler threads.
> >     >Datapaths
> >     >      * that directly call upcall functions should use the functions
> >     >below to
> >     >      * to register an upcall function and enable / disable upcalls.
> >     >      *
> >     >-     * Registers an upcall callback function with 'dpif'. This is
> only
> >     >used if
> >     >+     * Registers an upcall callback function with 'dpif'. This is
> only
> >     >used
> >     >      * if 'dpif' directly executes upcall functions. 'aux' is
> passed to
> >     >the
> >     >      * callback on invocation. */
> >     >     void (*register_upcall_cb)(struct dpif *, upcall_callback *,
> void
> >     >*aux);
> >     >diff --git a/lib/dpif.c b/lib/dpif.c
> >     >index 6e26f30..9a67a24 100644
> >     >--- a/lib/dpif.c
> >     >+++ b/lib/dpif.c
> >     >@@ -1346,6 +1346,14 @@ dpif_handlers_set(struct dpif *dpif, uint32_t
> >     >n_handlers)
> >     > }
> >     >
> >     > void
> >     >+dpif_register_dp_purge_cb(struct dpif *dpif, dp_purge_callback
> *cb, void
> >     >*aux)
> >     >+{
> >     >+    if (dpif->dpif_class->register_dp_purge_cb) {
> >     >+        dpif->dpif_class->register_dp_purge_cb(dpif, cb, aux);
> >     >+    }
> >     >+}
> >     >+
> >     >+void
> >     > dpif_register_upcall_cb(struct dpif *dpif, upcall_callback *cb,
> void
> >     >*aux)
> >     > {
> >     >     if (dpif->dpif_class->register_upcall_cb) {
> >     >diff --git a/lib/dpif.h b/lib/dpif.h
> >     >index ea9caf8..dca5d00 100644
> >     >--- a/lib/dpif.h
> >     >+++ b/lib/dpif.h
> >     >@@ -787,6 +787,18 @@ struct dpif_upcall {
> >     >     struct nlattr *actions;    /* Argument to
> OVS_ACTION_ATTR_USERSPACE.
> >     >*/
> >     > };
> >     >
> >     >+/* A callback to notify higher layer of dpif about to be purged,
> so that
> >     >+ * higher layer could try reacting to this (e.g. grabbing all flow
> stats
> >     >+ * before they are gone).  This function is currently implemented
> only by
> >     >+ * dpif-netdev.
> >     >+ *
> >     >+ * The caller only needs to provide the 'aux' pointer passed down
> by
> >     >higher
> >     >+ * layer from the dpif_register_notify_cb() function.
> >     >+ */
> >     >+typedef void dp_purge_callback(void *aux);
> >     >+
> >     >+void dpif_register_dp_purge_cb(struct dpif *, dp_purge_callback *,
> void
> >     >*aux);
> >     >+
> >     > /* A callback to process an upcall, currently implemented only by
> >     >dpif-netdev.
> >     >  *
> >     >  * The caller provides the 'packet' and 'flow' to process, the
> >     >corresponding
> >     >diff --git a/ofproto/ofproto-dpif-upcall.c
> b/ofproto/ofproto-dpif-upcall.c
> >     >index 0f2e186..6385abc 100644
> >     >--- a/ofproto/ofproto-dpif-upcall.c
> >     >+++ b/ofproto/ofproto-dpif-upcall.c
> >     >@@ -306,6 +306,7 @@ static int upcall_receive(struct upcall *, const
> >     >struct dpif_backer *,
> >     > static void upcall_uninit(struct upcall *);
> >     >
> >     > static upcall_callback upcall_cb;
> >     >+static dp_purge_callback dp_purge_cb;
> >     >
> >     > static atomic_bool enable_megaflows = ATOMIC_VAR_INIT(true);
> >     > static atomic_bool enable_ufid = ATOMIC_VAR_INIT(true);
> >     >@@ -358,6 +359,7 @@ udpif_create(struct dpif_backer *backer, struct
> dpif
> >     >*dpif)
> >     >     }
> >     >
> >     >     dpif_register_upcall_cb(dpif, upcall_cb, udpif);
> >     >+    dpif_register_dp_purge_cb(dpif, dp_purge_cb, udpif);
> >     >
> >     >     return udpif;
> >     > }
> >     >@@ -1110,6 +1112,20 @@ out:
> >     >     return error;
> >     > }
> >     >
> >     >+/* In reaction to dpif purge, purges all 'ukey's. */
> >     >+static void
> >     >+dp_purge_cb(void *aux)
> >     >+{
> >     >+    struct udpif *udpif = aux;
> >     >+    size_t i;
> >     >+
> >     >+    for (i = 0; i < udpif->n_revalidators; i++) {
> >     >+        struct revalidator *revalidator = &udpif->revalidators[i];
> >     >+
> >     >+        revalidator_purge(revalidator);
> >     >+    }
> >     >+}
> >     >+
> >     > static int
> >     > process_upcall(struct udpif *udpif, struct upcall *upcall,
> >     >                struct ofpbuf *odp_actions, struct flow_wildcards
> *wc)
> >     >--
> >     >1.7.9.5
> >     >
> >
> >
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to