[ovs-dev] [PATCH] ofproto-dpif-upcall: Replace ukeys for deleted flows.
Thadeu Lima de Souza Cascardo
cascardo at redhat.com
Thu Aug 25 20:15:29 UTC 2016
On Tue, Aug 23, 2016 at 07:18:50PM -0700, Joe Stringer wrote:
> If a revalidator dumps/revalidates a flow during the 'dump' phase,
> resulting in the deletion of the flow, then ukey->flow_exists is set to
> false, and the ukey is kept around until the 'sweep' phase. The ukey is
> kept around to ensure that cases like duplicated dumps from the
> datapaths do not result in multiple attribution of the same stats.
>
> However, if an upcall for this flow comes for a handler between the
> revalidator 'dump' and 'sweep' phases, the handler will lookup the ukey
> and find that the ukey exists, then skip installing a new flow entirely.
> As a result, for this period all traffic for the flow is slowpathed.
> If there is a lot of traffic hitting this flow, then it will all be
> handled in userspace until the 'sweep' phase. Eventually the
> revalidators will reach the sweep phase and delete the ukey, and
> subsequently the handlers should install a new flow.
>
> To reduce the slowpathing of this traffic during flow table transitions,
> allow the handler to identify this case during miss upcall handling and
> replace the existing ukey with a new ukey. The handler will then be able
> to install a flow for this traffic, allowing the traffic flow to return
> to the fastpath.
>
> There are three situations where the existing ukey has "flow_exists" set
> to false:
>
> * Firstly, the flow for the ukey might not yet have been installed. In
> this case, the other handler that set up this ukey will be holding the
> lock for the ukey. So, if we attempt to grab the lock and fail then
> another handler is already setting up the flow and we can safely skip
> flow install.
> * Secondly, a revalidator could be currently deleting the flow. In this
> case, the revalidator holds the ukey lock so the handler will fail to
> grab it. This is fine, if traffic continues to miss then a subsequent
> miss upcall will hit the third case.
> * Thirdly, the flow may have been recently deleted by a revalidator
> thread. In this case, we can grab the lock. From the handler thread
> we swap the original key out for a new one and rcu-defer its deletion.
>
Sweeper code gets the ukey lock, looks up flow_exists, then releases the lock.
Now try_ukey_replace succeeds at getting the lock. Sweeper is waiting on the
umap mutex, as ukey_install_start holds it. Now both will free the old ukey.
Is that analysis correct?
Thanks.
Cascardo.
> Signed-off-by: Joe Stringer <joe at ovn.org>
> ---
> ofproto/ofproto-dpif-upcall.c | 29 +++++++++++++++++++++++++++++
> 1 file changed, 29 insertions(+)
>
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index 042a50a9f179..5a0ecc2a6fe6 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -50,6 +50,7 @@ COVERAGE_DEFINE(dumped_duplicate_flow);
> COVERAGE_DEFINE(dumped_new_flow);
> COVERAGE_DEFINE(handler_duplicate_upcall);
> COVERAGE_DEFINE(upcall_ukey_contention);
> +COVERAGE_DEFINE(upcall_ukey_replace);
> COVERAGE_DEFINE(revalidate_missed_dp_flow);
>
> /* A thread that reads upcalls from dpif, forwards each upcall's packet,
> @@ -1569,6 +1570,33 @@ ukey_create_from_dpif_flow(const struct udpif *udpif,
> return 0;
> }
>
> +static bool
> +try_ukey_replace(struct umap *umap, struct udpif_key *old_ukey,
> + struct udpif_key *new_ukey)
> + OVS_REQUIRES(umap->mutex)
> + OVS_TRY_LOCK(true, new_ukey->mutex)
> +{
> + bool replaced = false;
> +
> + if (!ovs_mutex_trylock(&old_ukey->mutex)) {
> + if (!old_ukey->flow_exists) {
> + /* The flow was deleted during the current revalidator dump,
> + * but its ukey won't be cleaned up until the sweep phase.
> + * In the mean time, we are receiving upcalls for this traffic.
> + * Expedite the flow install by replacing the ukey. */
> + COVERAGE_INC(upcall_ukey_replace);
> + ovs_mutex_lock(&new_ukey->mutex);
> + cmap_replace(&umap->cmap, &old_ukey->cmap_node,
> + &new_ukey->cmap_node, new_ukey->hash);
> + ovsrcu_postpone(ukey_delete__, old_ukey);
> + replaced = true;
> + }
> + ovs_mutex_unlock(&old_ukey->mutex);
> + }
> +
> + return replaced;
> +}
> +
> /* Attempts to insert a ukey into the shared ukey maps.
> *
> * On success, returns true, installs the ukey and returns it in a locked
> @@ -1591,6 +1619,7 @@ ukey_install_start(struct udpif *udpif, struct udpif_key *new_ukey)
> if (old_ukey->key_len == new_ukey->key_len
> && !memcmp(old_ukey->key, new_ukey->key, new_ukey->key_len)) {
> COVERAGE_INC(handler_duplicate_upcall);
> + locked = try_ukey_replace(umap, old_ukey, new_ukey);
> } else {
> struct ds ds = DS_EMPTY_INITIALIZER;
>
> --
> 2.9.3
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list