Due to the differences between master and branch-2.3 and pressure to get
this out, I've targetted this first at branch-2.3. I intend to prepare an
equivalent patch for master, separately.


On 28 May 2014 13:19, Joe Stringer <joestrin...@nicira.com> wrote:

> A series of bugs have been identified recently that are caused by a
> combination of the awkward flow dump API, possibility of duplicate flows
> in a flow dump, and premature optimisation of the revalidator logic.
> This patch attempts to simplify the revalidator logic by combining
> multiple critical sections into one, which should make the state more
> consistent.
>
> The new flow of logic is:
> + Lookup the ukey.
> + If the ukey doesn't exist, create it.
> + Insert the ukey into the udpif. If we can't insert it, skip this flow.
> + Lock the ukey. If we can't lock it, skip it.
> + Determine if the ukey was already handled. If it has, skip it.
> + Revalidate.
> + Update ukey's fields (mark, flow_exists).
> + Unlock the ukey.
>
> Previously, we would attempt process a flow without creating a ukey if
> it hadn't been dumped before and it was due to be deleted. This patch
> changes this to always create a ukey, allowing the ukey's
> mutex to be used as the basis for preventing a flow from being handled
> twice. This is expected to cause some minor performance regression for
> cases like TCP_CRR, in favour of correctness and readability.
>
> Bug #1252997.
>
> Signed-off-by: Joe Stringer <joestrin...@nicira.com>
> ---
>  ofproto/ofproto-dpif-upcall.c |   64
> ++++++++++++++++++-----------------------
>  1 file changed, 28 insertions(+), 36 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index 64444d9..906ccb4 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -1205,6 +1205,7 @@ revalidate_ukey(struct udpif *udpif, struct
> udpif_key *ukey,
>                  const struct nlattr *mask, size_t mask_len,
>                  const struct nlattr *actions, size_t actions_len,
>                  const struct dpif_flow_stats *stats)
> +    OVS_REQUIRES(ukey->mutex)
>  {
>      uint64_t slow_path_buf[128 / 8];
>      struct xlate_out xout, *xoutp;
> @@ -1225,7 +1226,6 @@ revalidate_ukey(struct udpif *udpif, struct
> udpif_key *ukey,
>      xoutp = NULL;
>      netflow = NULL;
>
> -    ovs_mutex_lock(&ukey->mutex);
>      last_used = ukey->stats.used;
>      push.used = stats->used;
>      push.tcp_flags = stats->tcp_flags;
> @@ -1236,11 +1236,6 @@ revalidate_ukey(struct udpif *udpif, struct
> udpif_key *ukey,
>          ? stats->n_bytes - ukey->stats.n_bytes
>          : 0;
>
> -    if (!ukey->flow_exists) {
> -        /* Don't bother revalidating if the flow was already deleted. */
> -        goto exit;
> -    }
> -
>      if (udpif->need_revalidate && last_used
>          && !should_revalidate(push.n_packets, last_used)) {
>          ok = false;
> @@ -1320,7 +1315,6 @@ revalidate_ukey(struct udpif *udpif, struct
> udpif_key *ukey,
>      ok = true;
>
>  exit:
> -    ovs_mutex_unlock(&ukey->mutex);
>      if (netflow) {
>          if (!ok) {
>              netflow_expire(netflow, &flow);
> @@ -1460,25 +1454,38 @@ revalidate(struct revalidator *revalidator)
>          ukey = ukey_lookup(udpif, key, key_len, hash);
>
>          used = stats->used;
> -        if (ukey) {
> -            ovs_mutex_lock(&ukey->mutex);
> -
> -            if (ukey->mark || !ukey->flow_exists) {
> -                /* The flow has already been dumped. This can occasionally
> -                 * occur if the datapath is changed in the middle of a
> flow
> -                 * dump. Rather than perform the same work twice, skip the
> -                 * flow this time. */
> -                ovs_mutex_unlock(&ukey->mutex);
> +        if (!ukey) {
> +            ukey = ukey_create(key, key_len, used);
> +            if (!udpif_insert_ukey(udpif, ukey, hash)) {
> +                /* The same ukey has already been created. This means that
> +                 * another revalidator is processing this flow
> +                 * concurrently, so don't bother processing it. */
>                  COVERAGE_INC(upcall_duplicate_flow);
> +                ukey_delete(NULL, ukey);
>                  goto next;
>              }
> +        }
>
> -            if (!used) {
> -                used = ukey->created;
> -            }
> +        if (ovs_mutex_trylock(&ukey->mutex)) {
> +            /* The flow has been dumped, and is being handled by another
> +             * revalidator concurrently. This can occasionally occur if
> the
> +             * datapath is changed in the middle of a flow dump. Rather
> than
> +             * perform the same work twice, skip the flow this time. */
> +            COVERAGE_INC(upcall_duplicate_flow);
> +            goto next;
> +        }
> +
> +        if (ukey->mark || !ukey->flow_exists) {
> +            /* The flow has already been dumped and handled by another
> +             * revalidator during this flow dump operation. Skip it. */
> +            COVERAGE_INC(upcall_duplicate_flow);
>              ovs_mutex_unlock(&ukey->mutex);
> +            goto next;
>          }
>
> +        if (!used) {
> +            used = ukey->created;
> +        }
>          n_flows = udpif_get_n_flows(udpif);
>          max_idle = ofproto_max_idle;
>          if (n_flows > flow_limit) {
> @@ -1488,30 +1495,15 @@ revalidate(struct revalidator *revalidator)
>          if ((used && used < now - max_idle) || n_flows > flow_limit * 2) {
>              mark = false;
>          } else {
> -            if (!ukey) {
> -                ukey = ukey_create(key, key_len, used);
> -                if (!udpif_insert_ukey(udpif, ukey, hash)) {
> -                    /* The same ukey has already been created. This means
> that
> -                     * another revalidator is processing this flow
> -                     * concurrently, so don't bother processing it. */
> -                    ukey_delete(NULL, ukey);
> -                    goto next;
> -                }
> -            }
> -
>              mark = revalidate_ukey(udpif, ukey, mask, mask_len, actions,
>                                     actions_len, stats);
>          }
> -
> -        if (ukey) {
> -            ovs_mutex_lock(&ukey->mutex);
> -            ukey->mark = ukey->flow_exists = mark;
> -            ovs_mutex_unlock(&ukey->mutex);
> -        }
> +        ukey->mark = ukey->flow_exists = mark;
>
>          if (!mark) {
>              dump_op_init(&ops[n_ops++], key, key_len, ukey);
>          }
> +        ovs_mutex_unlock(&ukey->mutex);
>
>      next:
>          may_destroy = dpif_flow_dump_next_may_destroy_keys(&udpif->dump,
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to