[ovs-dev] [PATCH 1/2] revalidator: Eliminate duplicate flow handling.
Ethan Jackson
ethan at nicira.com
Mon Jun 2 20:41:44 UTC 2014
The comment over the trylock exceeds the line limit.
I'm not sure if this is the right patch to fix it or not, but I don't
like how we're overloading the meaning of the 'mark'. I think the
code would be a lot clearer if we had both a "already_dumped" flag and
a "delete" flag on every ukey. What do you think?
Acked-by: Ethan Jackson <ethan at nicira.com>
On Thu, May 29, 2014 at 6:38 PM, Joe Stringer <joestringer at 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 improves code correctness and readability.
>
> Bug #1252997.
>
> Signed-off-by: Joe Stringer <joestringer at nicira.com>
> ---
> The original version of this patch has been merged to branch-2.3, and
> noted a potential performance drop. After testing this patch against
> master in netperf TCP_CRR, there was no measurable difference so I have
> dropped that comment from the commit message.
> ---
> ofproto/ofproto-dpif-upcall.c | 74 ++++++++++++++++++-----------------------
> 1 file changed, 33 insertions(+), 41 deletions(-)
>
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index db0f17e..1c82b6b 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -1097,6 +1097,7 @@ should_revalidate(uint64_t packets, long long int used)
> static bool
> revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
> const struct dpif_flow *f)
> + OVS_REQUIRES(ukey->mutex)
> {
> uint64_t slow_path_buf[128 / 8];
> struct xlate_out xout, *xoutp;
> @@ -1117,7 +1118,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 = f->stats.used;
> push.tcp_flags = f->stats.tcp_flags;
> @@ -1128,11 +1128,6 @@ revalidate_ukey(struct udpif *udpif, struct udpif_key *ukey,
> ? f->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;
> @@ -1212,7 +1207,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);
> @@ -1371,54 +1365,52 @@ revalidate(struct revalidator *revalidator)
> uint32_t hash = hash_bytes(f->key, f->key_len, udpif->secret);
> struct udpif_key *ukey = ukey_lookup(udpif, f->key, f->key_len,
> hash);
> - bool mark;
> -
> - if (ukey) {
> - bool already_dumped;
> -
> - ovs_mutex_lock(&ukey->mutex);
> - already_dumped = ukey->mark || !ukey->flow_exists;
> - if (!used) {
> - used = ukey->created;
> - }
> - ovs_mutex_unlock(&ukey->mutex);
> -
> - if (already_dumped) {
> - /* 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. */
> + bool already_dumped, mark;
> +
> + 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);
> continue;
> }
> }
>
> + 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);
> + continue;
> + }
> +
> + already_dumped = ukey->mark || !ukey->flow_exists;
> + if (already_dumped) {
> + /* 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);
> + continue;
> + }
> +
> + if (!used) {
> + used = ukey->created;
> + }
> if (kill_them_all || (used && used < now - max_idle)) {
> mark = false;
> } else {
> - if (!ukey) {
> - ukey = ukey_create(f->key, f->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);
> - continue;
> - }
> - }
> -
> mark = revalidate_ukey(udpif, ukey, f);
> }
> -
> - 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++], f->key, f->key_len, ukey);
> }
> + ovs_mutex_unlock(&ukey->mutex);
> }
>
> if (n_ops) {
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
More information about the dev
mailing list