[ovs-dev] Fwd: [PATCH 1/3] match: New function minimatch_matches_flow().

Andy Zhou azhou at nicira.com
Wed Mar 27 19:14:52 UTC 2013


---------- Forwarded message ----------
From: Andy Zhou <azhou at nicira.com>
Date: Wed, Mar 27, 2013 at 12:14 PM
Subject: Re: [ovs-dev] [PATCH 1/3] match: New function
minimatch_matches_flow().
To: Ben Pfaff <blp at nicira.com>


Looks good. A few minor comments in-line:


On Tue, Mar 26, 2013 at 9:32 PM, Ben Pfaff <blp at nicira.com> wrote:

> Signed-off-by: Ben Pfaff <blp at nicira.com>
> ---
>  lib/classifier.c |    3 +-
>  lib/flow.c       |  122
> ++++++++++++++++++++++++++++++++++++++++++------------
>  lib/flow.h       |   10 +++--
>  lib/match.c      |   31 +++++++++++++-
>  lib/match.h      |   18 ++++----
>  5 files changed, 143 insertions(+), 41 deletions(-)
>
> diff --git a/lib/classifier.c b/lib/classifier.c
> index 2d1e50b..b720378 100644
> --- a/lib/classifier.c
> +++ b/lib/classifier.c
> @@ -641,8 +641,7 @@ find_match(const struct cls_table *table, const struct
> flow *flow)
>      struct cls_rule *rule;
>
>      HMAP_FOR_EACH_WITH_HASH (rule, hmap_node, hash, &table->rules) {
> -        if (miniflow_equal_flow_in_minimask(&rule->match.flow, flow,
> -                                            &table->mask)) {
> +        if (minimatch_matches_flow(&rule->match, flow)) {
>              return rule;
>          }
>      }
> diff --git a/lib/flow.c b/lib/flow.c
> index 678b8f0..56675c3 100644
> --- a/lib/flow.c
> +++ b/lib/flow.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -966,13 +966,30 @@ miniflow_alloc_values(struct miniflow *flow, int n)
>      }
>  }
>

It would be nice to add a comment about what 'n' is.

> +static void
> +miniflow_init__(struct miniflow *dst, const struct flow *src, int n)
> +{
> +    const uint32_t *src_u32 = (const uint32_t *) src;
> +    unsigned int ofs;
> +    int i;
> +
> +    dst->values = miniflow_alloc_values(dst, n);
> +    ofs = 0;
> +    for (i = 0; i < MINI_N_MAPS; i++) {
> +        uint32_t map;
> +
> +        for (map = dst->map[i]; map; map = zero_rightmost_1bit(map)) {
> +            dst->values[ofs++] = src_u32[raw_ctz(map) + i * 32];
> +        }
> +    }
> +}
> +
>  /* Initializes 'dst' as a copy of 'src'.  The caller must eventually free
> 'dst'
>   * with miniflow_destroy(). */
>  void
>  miniflow_init(struct miniflow *dst, const struct flow *src)
>  {
>      const uint32_t *src_u32 = (const uint32_t *) src;
> -    unsigned int ofs;
>      unsigned int i;
>      int n;
>
> @@ -986,16 +1003,21 @@ miniflow_init(struct miniflow *dst, const struct
> flow *src)
>          }
>      }
>
> -    /* Initialize dst->values. */
> -    dst->values = miniflow_alloc_values(dst, n);
> -    ofs = 0;
> -    for (i = 0; i < MINI_N_MAPS; i++) {
> -        uint32_t map;
> +    miniflow_init__(dst, src, n);
> +}
>
> -        for (map = dst->map[i]; map; map = zero_rightmost_1bit(map)) {
> -            dst->values[ofs++] = src_u32[raw_ctz(map) + i * 32];
> -        }
> +/* Initializes 'dst' as a copy of 'src', using 'mask->map' as 'dst''s
> map.  The
> + * caller must eventually free 'dst' with miniflow_destroy(). */
> +void
> +miniflow_init_with_minimask(struct miniflow *dst, const struct flow *src,
> +                            const struct minimask *mask)
> +{
> +    int i;
> +
> +    for (i = 0; i < MINI_N_MAPS; i++) {
> +        dst->map[i] = mask->masks.map[i];
>      }
>
How about use memcpy() instead for loop above?

> +    miniflow_init__(dst, src, miniflow_n_values(dst));
>  }
>
>  /* Initializes 'dst' as a copy of 'src'.  The caller must eventually free
> 'dst'
> @@ -1090,16 +1112,35 @@ miniflow_get_vid(const struct miniflow *flow)
>  bool
>  miniflow_equal(const struct miniflow *a, const struct miniflow *b)
>  {
> +    const uint32_t *ap = a->values;
> +    const uint32_t *bp = b->values;
>      int i;
>
>      for (i = 0; i < MINI_N_MAPS; i++) {
> -        if (a->map[i] != b->map[i]) {
> -            return false;
> +        const uint32_t a_map = a->map[i];
> +        const uint32_t b_map = b->map[i];
> +        uint32_t map;
> +
> +        if (a_map == b_map) {
> +            for (map = a_map; map; map = zero_rightmost_1bit(map)) {
> +                if (*ap++ != *bp++) {
> +                    return false;
> +                }
> +            }
> +        } else {
> +            for (map = a_map | b_map; map; map =
> zero_rightmost_1bit(map)) {
> +                uint32_t bit = rightmost_1bit(map);
> +                uint32_t a_value = a_map & bit ? *ap++ : 0;
> +                uint32_t b_value = b_map & bit ? *bp++ : 0;
> +
> +                if (a_value != b_value) {
> +                    return false;
> +                }
> +            }
>          }
>      }
>
> -    return !memcmp(a->values, b->values,
> -                   miniflow_n_values(a) * sizeof *a->values);
> +    return true;
>  }
>
>  /* Returns true if 'a' and 'b' are equal at the places where there are
> 1-bits
> @@ -1159,10 +1200,24 @@ miniflow_equal_flow_in_minimask(const struct
> miniflow *a, const struct flow *b,
>  uint32_t
>  miniflow_hash(const struct miniflow *flow, uint32_t basis)
>  {
> -    BUILD_ASSERT_DECL(MINI_N_MAPS == 2);
> -    return hash_3words(flow->map[0], flow->map[1],
> -                       hash_words(flow->values, miniflow_n_values(flow),
> -                                  basis));
> +    const uint32_t *p = flow->values;
> +    uint32_t hash = basis;
> +    int i;
> +
> +    for (i = 0; i < MINI_N_MAPS; i++) {
> +        uint32_t hash_map = 0;
> +        uint32_t map;
> +
> +        for (map = flow->map[i]; map; map = zero_rightmost_1bit(map)) {
> +            if (*p) {
> +                hash = mhash_add(hash, *p);
> +                hash_map |= rightmost_1bit(map);
> +            }
> +            p++;
>
This is just a question: Why miniflow_hash skips zero values, while
flow_hash does not?

> +        }
> +        hash = mhash_add(hash, hash_map);
> +    }
> +    return mhash_finish(hash, p - flow->values);
>  }
>
>  /* Returns a hash value for the bits of 'flow' where there are 1-bits in
> @@ -1183,9 +1238,10 @@ miniflow_hash_in_minimask(const struct miniflow
> *flow,
>          uint32_t map;
>
>          for (map = mask->masks.map[i]; map; map =
> zero_rightmost_1bit(map)) {
> -            int ofs = raw_ctz(map) + i * 32;
> -
> -            hash = mhash_add(hash, miniflow_get(flow, ofs) & *p);
> +            if (*p) {
> +                int ofs = raw_ctz(map) + i * 32;
> +                hash = mhash_add(hash, miniflow_get(flow, ofs) & *p);
>
Is possible to avoid calling miniflow_get() in this case, the needed data
from flow is readily available.

> +            }
>              p++;
>          }
>      }
> @@ -1202,21 +1258,23 @@ uint32_t
>  flow_hash_in_minimask(const struct flow *flow, const struct minimask
> *mask,
>                        uint32_t basis)
>  {
> -    const uint32_t *flow_u32 = (const uint32_t *) flow;
> +    const uint32_t *flow_u32;
>      const uint32_t *p = mask->masks.values;
>      uint32_t hash;
>      int i;
>
>      hash = basis;
> +    flow_u32 = (const uint32_t *) flow;
>      for (i = 0; i < MINI_N_MAPS; i++) {
>          uint32_t map;
>
>          for (map = mask->masks.map[i]; map; map =
> zero_rightmost_1bit(map)) {
> -            int ofs = raw_ctz(map) + i * 32;
> -
> -            hash = mhash_add(hash, flow_u32[ofs] & *p);
> +            if (*p) {
> +                hash = mhash_add(hash, flow_u32[raw_ctz(map)] & *p);
> +            }
>              p++;
>          }
> +        flow_u32 += 32;
>      }
>
>      return mhash_finish(hash, (p - mask->masks.values) * 4);
> @@ -1349,7 +1407,17 @@ bool
>  minimask_is_catchall(const struct minimask *mask_)
>  {
>      const struct miniflow *mask = &mask_->masks;
> +    const uint32_t *p = mask->values;
> +    int i;
>
> -    BUILD_ASSERT(MINI_N_MAPS == 2);
> -    return !(mask->map[0] | mask->map[1]);
> +    for (i = 0; i < MINI_N_MAPS; i++) {
> +        uint32_t map;
> +
> +        for (map = mask->map[i]; map; map = zero_rightmost_1bit(map)) {
> +            if (*p++) {
> +                return false;
> +            }
> +        }
> +    }
> +    return true;
>  }
> diff --git a/lib/flow.h b/lib/flow.h
> index 6e169d6..09a472d 100644
> --- a/lib/flow.h
> +++ b/lib/flow.h
> @@ -221,7 +221,7 @@ bool flow_equal_except(const struct flow *a, const
> struct flow *b,
>   *
>   * The 'map' member holds one bit for each uint32_t in a "struct flow".
>  Each
>   * 0-bit indicates that the corresponding uint32_t is zero, each 1-bit
> that it
> - * is nonzero.
> + * *may* be nonzero.
>   *
>   * 'values' points to the start of an array that has one element for each
> 1-bit
>   * in 'map'.  The least-numbered 1-bit is in values[0], the next 1-bit is
> in
> @@ -239,9 +239,9 @@ bool flow_equal_except(const struct flow *a, const
> struct flow *b,
>   *       that makes sense.  So far that's only proved useful for
>   *       minimask_combine(), but the principle works elsewhere.
>   *
> - * The implementation maintains and depends on the invariant that every
> element
> - * in 'values' is nonzero; that is, wherever a 1-bit appears in 'map', the
> - * corresponding element of 'values' must be nonzero.
> + * Elements in 'values' are allowed to be zero.  This is useful for
> "struct
> + * minimatch", for which ensuring that the miniflow and minimask members
> have
> + * same 'map' allows optimization .
>   */
>  struct miniflow {
>      uint32_t *values;
> @@ -250,6 +250,8 @@ struct miniflow {
>  };
>
>  void miniflow_init(struct miniflow *, const struct flow *);
> +void miniflow_init_with_minimask(struct miniflow *, const struct flow *,
> +                                 const struct minimask *);
>  void miniflow_clone(struct miniflow *, const struct miniflow *);
>  void miniflow_destroy(struct miniflow *);
>
> diff --git a/lib/match.c b/lib/match.c
> index 2aa4e89..76c23cf 100644
> --- a/lib/match.c
> +++ b/lib/match.c
> @@ -1087,8 +1087,8 @@ match_print(const struct match *match)
>  void
>  minimatch_init(struct minimatch *dst, const struct match *src)
>  {
> -    miniflow_init(&dst->flow, &src->flow);
>      minimask_init(&dst->mask, &src->wc);
> +    miniflow_init_with_minimask(&dst->flow, &src->flow, &dst->mask);
>  }
>
>  /* Initializes 'dst' as a copy of 'src'.  The caller must eventually free
> 'dst'
> @@ -1132,6 +1132,35 @@ minimatch_hash(const struct minimatch *match,
> uint32_t basis)
>      return miniflow_hash(&match->flow, minimask_hash(&match->mask,
> basis));
>  }
>
> +/* Returns true if 'target' satisifies 'match', that is, if each bit for
> which
> + * 'match' specifies a particular value has the correct value in 'target'.
> + *
> + * This function is equivalent to
> miniflow_equal_flow_in_minimask(&match->flow,
> + * target, &match->mask) but it is faster because of the invariant that
> + * match->flow.map and match->mask.map are the same. */
> +bool
> +minimatch_matches_flow(const struct minimatch *match,
> +                       const struct flow *target)
> +{
> +    const uint32_t *target_u32 = (const uint32_t *) target;
> +    const uint32_t *flowp = match->flow.values;
> +    const uint32_t *maskp = match->mask.masks.values;
> +    int i;
> +
> +    for (i = 0; i < MINI_N_MAPS; i++) {
> +        uint32_t map;
> +
> +        for (map = match->flow.map[i]; map; map =
> zero_rightmost_1bit(map)) {
> +            if ((*flowp++ ^ target_u32[raw_ctz(map)]) & *maskp++) {
> +                return false;
> +            }
> +        }
> +        target_u32 += 32;
> +    }
> +
> +    return true;
> +}
> +
>  /* Appends a string representation of 'match' to 's'.  If 'priority' is
>   * different from OFP_DEFAULT_PRIORITY, includes it in 's'. */
>  void
> diff --git a/lib/match.h b/lib/match.h
> index d435aa4..926ce60 100644
> --- a/lib/match.h
> +++ b/lib/match.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
> + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -131,13 +131,15 @@ void match_print(const struct match *);
>
>  /* A sparse representation of a "struct match".
>   *
> - * This has the same invariant as "struct match", that is, a 1-bit in the
> - * 'flow' must correspond to a 1-bit in 'mask'.
> + * There are two invariants:
>   *
> - * The invariants for the underlying miniflow and minimask are also
> maintained,
> - * which means that 'flow' and 'mask' can have different 'map's.  In
> - * particular, if the match checks that a given 32-bit field has value 0,
> then
> - * 'map' will have a 1-bit in 'mask' but a 0-bit in 'flow' for that
> field. */
> + *   - The same invariant as "struct match", that is, a 1-bit in the
> 'flow'
> + *     must correspond to a 1-bit in 'mask'.
> + *
> + *   - 'flow' and 'mask' have the same 'map'.  This implies that 'flow'
> and
> + *     'mask' have the same part of "struct flow" at the same offset into
> + *     'values', which makes minimatch_matches_flow() faster.
> + */
>  struct minimatch {
>      struct miniflow flow;
>      struct minimask mask;
> @@ -152,6 +154,8 @@ void minimatch_expand(const struct minimatch *, struct
> match *);
>  bool minimatch_equal(const struct minimatch *a, const struct minimatch
> *b);
>  uint32_t minimatch_hash(const struct minimatch *, uint32_t basis);
>
> +bool minimatch_matches_flow(const struct minimatch *, const struct flow
> *);
> +
>  void minimatch_format(const struct minimatch *, struct ds *,
>                        unsigned int priority);
>  char *minimatch_to_string(const struct minimatch *, unsigned int
> priority);
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> dev at openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openvswitch.org/pipermail/ovs-dev/attachments/20130327/90ca05bf/attachment-0003.html>


More information about the dev mailing list