> On Sep 8, 2014, at 3:23 AM, Joe Stringer <joestrin...@nicira.com> wrote:
> 
> It's highly unlikely that two flows will hash to the same UID. However,
> we could handle multiple upcalls from the same flow. If we hash the flow
> with an additional hash function and the hashes are the same, then the
> upcalls are most likely from the same flow (assuming that the hash
> collisions are different for each functions). If the hashes are
> different, then we have generated the same UID hash for two different
> flows, and we should log a warning.

I did not look at the patch, but would it be possible to detect a duplicate 
upcall by comparing the flow keys when the hashes collide?

  Jarno

> 
> Signed-off-by: Joe Stringer <joestrin...@nicira.com>
> ---
> RFC. This is really unlikely, but we don't have any way of detecting
> this case currently. This makes it likely that we'll detect such cases,
> but it's still theoretically possible we'll miss them. Not sure whether
> the extra code is warranted or not. During testing I've only triggered
> the handler_duplicate_upcall case and never the VLOG_WARN case.
> ---
> ofproto/ofproto-dpif-upcall.c |   48 +++++++++++++++++++++++++++++++++++------
> 1 file changed, 42 insertions(+), 6 deletions(-)
> 
> diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index ad50f79..e663f78 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -46,7 +46,7 @@
> 
> VLOG_DEFINE_THIS_MODULE(ofproto_dpif_upcall);
> 
> -COVERAGE_DEFINE(handler_install_conflict);
> +COVERAGE_DEFINE(handler_duplicate_upcall);
> COVERAGE_DEFINE(upcall_ukey_contention);
> COVERAGE_DEFINE(dumped_duplicate_flow);
> COVERAGE_DEFINE(dumped_new_flow);
> @@ -99,6 +99,8 @@ struct udpif {
>     struct dpif *dpif;                 /* Datapath handle. */
>     struct dpif_backer *backer;        /* Opaque dpif_backer pointer. */
> 
> +    uint32_t secret;                   /* Random seed for udpif_key 'check'. 
> */
> +
>     struct handler *handlers;          /* Upcall handlers. */
>     size_t n_handlers;
> 
> @@ -207,6 +209,8 @@ struct udpif_key {
>     struct ofpbuf *actions;        /* Datapath flow actions as nlattrs. */
>     ovs_u128 uid;                  /* Unique flow identifier. */
>     uint32_t hash;                 /* Pre-computed hash for 'key'. */
> +    uint32_t check;                /* Additional hash for detecting duplicate
> +                                      upcalls. */
>     atomic_bool installed;         /* True if the datapath flow has been
>                                       installed and handlers are finished with
>                                       this ukey. Used to reduce contention. */
> @@ -268,7 +272,7 @@ static void upcall_unixctl_set_flow_limit(struct 
> unixctl_conn *conn, int argc,
> static void upcall_unixctl_dump_wait(struct unixctl_conn *conn, int argc,
>                                      const char *argv[], void *aux);
> 
> -static struct udpif_key *ukey_new(struct upcall *);
> +static struct udpif_key *ukey_new(struct udpif *udpif, struct upcall *);
> static bool ukey_install_start(struct udpif *, struct udpif_key *ukey);
> static void ukey_install_finish(struct udpif_key *ukey, int error);
> static bool ukey_install(struct udpif *udpif, struct udpif_key *ukey);
> @@ -316,6 +320,7 @@ udpif_create(struct dpif_backer *backer, struct dpif 
> *dpif)
>     udpif->dpif = dpif;
>     udpif->backer = backer;
>     atomic_init(&udpif->flow_limit, MIN(ofproto_flow_limit, 10000));
> +    udpif->secret = random_uint32();
>     udpif->reval_seq = seq_create();
>     udpif->dump_seq = seq_create();
>     latch_init(&udpif->exit_latch);
> @@ -958,7 +963,7 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall,
>                           &upcall->put_actions);
>     }
> 
> -    upcall->ukey = ukey_new(upcall);
> +    upcall->ukey = ukey_new(udpif, upcall);
> }
> 
> static void
> @@ -1236,7 +1241,23 @@ ukey_lookup(struct udpif *udpif, const ovs_u128 *uid)
> }
> 
> static struct udpif_key *
> -ukey_new(struct upcall *upcall)
> +ukey_lookup_by_uid_check(struct udpif *udpif, const ovs_u128 *uid,
> +                         const uint32_t check)
> +{
> +    struct udpif_key *ukey;
> +    int idx = get_uid_hash(uid) % N_UMAPS;
> +    struct cmap *cmap = &udpif->ukeys[idx].cmap;
> +
> +    CMAP_FOR_EACH_WITH_HASH (ukey, cmap_node, get_uid_hash(uid), cmap) {
> +        if (!memcmp(&ukey->check, &check, sizeof check)) {
> +            return ukey;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +static struct udpif_key *
> +ukey_new(struct udpif *udpif, struct upcall *upcall)
>     OVS_NO_THREAD_SAFETY_ANALYSIS
> {
>     struct udpif_key *ukey = xzalloc(sizeof *ukey);
> @@ -1268,6 +1289,8 @@ ukey_new(struct upcall *upcall)
>     ukey->mask_len = ofpbuf_size(&mask);
>     memcpy(&ukey->uid, upcall->uid, sizeof ukey->uid);
>     ukey->hash = get_uid_hash(&ukey->uid);
> +    ukey->check = hash_words(ALIGNED_CAST(uint32_t*,ukey->key), 
> ukey->key_len,
> +                             udpif->secret);
>     ukey->actions = ofpbuf_clone(&upcall->put_actions);
> 
>     atomic_init(&ukey->installed, false);
> @@ -1300,8 +1323,21 @@ ukey_install_start(struct udpif *udpif, struct 
> udpif_key *ukey)
>         cmap_insert(&umap->cmap, &ukey->cmap_node, ukey->hash);
>         locked = true;
>     } else {
> -        COVERAGE_INC(handler_install_conflict);
> -        VLOG_DBG("Failed to ukey_install_start(): 0x%"PRIx32, ukey->hash);
> +        /* It's highly unlikely that two flows will hash to the same UID.
> +         * However, we could be handling multiple upcalls from the same flow.
> +         * If we hash the flow with a different hash function and the hashes
> +         * are the same, then the upcalls are most likely from the same flow.
> +         * If the hashes are different, then we have generated the same UID
> +         * hash for two different flows. */
> +        if (ukey_lookup_by_uid_check(udpif, &ukey->uid, ukey->check)) {
> +            COVERAGE_INC(handler_duplicate_upcall);
> +        } else {
> +            struct ds ds = DS_EMPTY_INITIALIZER;
> +
> +            odp_format_uid(&ukey->uid, &ds);
> +            VLOG_WARN("Conflicting ukey with %s", ds_cstr(&ds));
> +            ds_destroy(&ds);
> +        }
>     }
>     ovs_mutex_unlock(&umap->mutex);
> 
> -- 
> 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