miniflow_clone_inline(), miniflow_destroy(), miniflow_expand(), miniflow_get(), miniflow_equal(), minimask_init(), minimask_clone(), minimask_move(), minimask_destroy(), minimask_expand(), minimask_expand, minimask_get(), minimask_equal(), minimask_has_extra(), minimatch_init(), minimatch_clone(), minimatch_move, minimatch_destroy(), minimatch_expand(), minimatch_equal(), and minimatch_matches_flow() are inlined. Many of these call each other, so inlining could be beneficial.
miniflow_equal_in_minimask() is moved to lib/classifier, which is the sole user of it. miniflow_equal_flow_in_minimask() is moved to tests/test-classifier, which is the only user of it. Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/classifier-private.h | 18 ++++ lib/flow.c | 186 ---------------------------------------- lib/flow.h | 213 +++++++++++++++++++++++++++++++++++++++------- lib/match.c | 76 ----------------- lib/match.h | 97 +++++++++++++++++++-- tests/test-classifier.c | 19 +++++ 6 files changed, 307 insertions(+), 302 deletions(-) diff --git a/lib/classifier-private.h b/lib/classifier-private.h index b498eea..abefb06 100644 --- a/lib/classifier-private.h +++ b/lib/classifier-private.h @@ -100,6 +100,24 @@ struct trie_node { * These are only used by the classifier, so place them here to allow * for better optimization. */ +/* Returns true if 'a' and 'b' are equal at the places where there are 1-bits + * in 'mask', false if they differ. */ +static inline bool +miniflow_equal_in_minimask(const struct miniflow *a, const struct miniflow *b, + const struct minimask *mask) +{ + const uint32_t *p = miniflow_get_u32_values(&mask->masks); + int idx; + + MAP_FOR_EACH_INDEX(idx, mask->masks.map) { + if ((miniflow_get(a, idx) ^ miniflow_get(b, idx)) & *p++) { + return false; + } + } + + return true; +} + static inline uint64_t miniflow_get_map_in_range(const struct miniflow *miniflow, uint8_t start, uint8_t end, unsigned int *offset) diff --git a/lib/flow.c b/lib/flow.c index 40fa867..8a98ad6 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -1915,18 +1915,6 @@ miniflow_clone(struct miniflow *dst, const struct miniflow *src) memcpy(values, miniflow_get_values(src), size); } -/* Initializes 'dst' as a copy of 'src'. The caller must have allocated - * 'dst' to have inline space all data in 'src'. */ -void -miniflow_clone_inline(struct miniflow *dst, const struct miniflow *src, - size_t n_values) -{ - dst->values_inline = true; - dst->map = src->map; - memcpy(dst->inline_values, miniflow_get_values(src), - MINIFLOW_VALUES_SIZE(n_values)); -} - /* Initializes 'dst' with the data in 'src', destroying 'src'. * The caller must eventually free 'dst' with miniflow_destroy(). * 'dst' must be regularly sized miniflow, but 'src' can have @@ -1952,122 +1940,7 @@ miniflow_move(struct miniflow *dst, struct miniflow *src) dst->offline_values = src->offline_values; } } - -/* Frees any memory owned by 'flow'. Does not free the storage in which 'flow' - * itself resides; the caller is responsible for that. */ -void -miniflow_destroy(struct miniflow *flow) -{ - if (!flow->values_inline) { - free(flow->offline_values); - } -} - -/* Initializes 'dst' as a copy of 'src'. */ -void -miniflow_expand(const struct miniflow *src, struct flow *dst) -{ - memset(dst, 0, sizeof *dst); - flow_union_with_miniflow(dst, src); -} - -/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'flow' - * were expanded into a "struct flow". */ -static uint32_t -miniflow_get(const struct miniflow *flow, unsigned int u32_ofs) -{ - return flow->map & (UINT64_C(1) << u32_ofs) - ? MINIFLOW_GET__(flow, u32_ofs) : 0; -} - -/* Returns true if 'a' and 'b' are the equal miniflow, false otherwise. */ -bool -miniflow_equal(const struct miniflow *a, const struct miniflow *b) -{ - const uint32_t *ap = miniflow_get_u32_values(a); - const uint32_t *bp = miniflow_get_u32_values(b); - - if (OVS_LIKELY(a->map == b->map)) { - int count = miniflow_n_values(a); - - return !memcmp(ap, bp, count * sizeof *ap); - } else { - int idx; - - MAP_FOR_EACH_INDEX(idx, a->map | b->map) { - uint64_t bit = UINT64_C(1) << idx; - - if ((a->map & bit ? *ap++ : 0) != (b->map & bit ? *bp++ : 0)) { - return false; - } - } - } - - return true; -} - -/* Returns false if 'a' and 'b' differ at the places where there are 1-bits - * in 'mask', true otherwise. */ -bool -miniflow_equal_in_minimask(const struct miniflow *a, const struct miniflow *b, - const struct minimask *mask) -{ - const uint32_t *p = miniflow_get_u32_values(&mask->masks); - int idx; - - MAP_FOR_EACH_INDEX(idx, mask->masks.map) { - if ((miniflow_get(a, idx) ^ miniflow_get(b, idx)) & *p++) { - return false; - } - } - - return true; -} - -/* Returns true if 'a' and 'b' are equal at the places where there are 1-bits - * in 'mask', false if they differ. */ -bool -miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct flow *b, - const struct minimask *mask) -{ - const uint32_t *b_u32 = (const uint32_t *) b; - const uint32_t *p = miniflow_get_u32_values(&mask->masks); - int idx; - - MAP_FOR_EACH_INDEX(idx, mask->masks.map) { - if ((miniflow_get(a, idx) ^ b_u32[idx]) & *p++) { - return false; - } - } - - return true; -} - -/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' - * with minimask_destroy(). */ -void -minimask_init(struct minimask *mask, const struct flow_wildcards *wc) -{ - miniflow_init(&mask->masks, &wc->masks); -} - -/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' - * with minimask_destroy(). */ -void -minimask_clone(struct minimask *dst, const struct minimask *src) -{ - miniflow_clone(&dst->masks, &src->masks); -} - -/* Initializes 'dst' with the data in 'src', destroying 'src'. - * The caller must eventually free 'dst' with minimask_destroy(). */ -void -minimask_move(struct minimask *dst, struct minimask *src) -{ - miniflow_move(&dst->masks, &src->masks); -} - /* Initializes 'dst_' as the bit-wise "and" of 'a_' and 'b_'. * * The caller must provide room for FLOW_U32S "uint32_t"s in 'storage', for use @@ -2097,62 +1970,3 @@ minimask_combine(struct minimask *dst_, } } } - -/* Frees any memory owned by 'mask'. Does not free the storage in which 'mask' - * itself resides; the caller is responsible for that. */ -void -minimask_destroy(struct minimask *mask) -{ - miniflow_destroy(&mask->masks); -} - -/* Initializes 'dst' as a copy of 'src'. */ -void -minimask_expand(const struct minimask *mask, struct flow_wildcards *wc) -{ - miniflow_expand(&mask->masks, &wc->masks); -} - -/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'mask' - * were expanded into a "struct flow_wildcards". */ -uint32_t -minimask_get(const struct minimask *mask, unsigned int u32_ofs) -{ - return miniflow_get(&mask->masks, u32_ofs); -} - -/* Returns true if 'a' and 'b' are the same flow mask, false otherwise. - * Minimasks may not have zero data values, so for the minimasks to be the - * same, they need to have the same map and the same data values. */ -bool -minimask_equal(const struct minimask *a, const struct minimask *b) -{ - return a->masks.map == b->masks.map && - !memcmp(miniflow_get_u32_values(&a->masks), - miniflow_get_u32_values(&b->masks), - count_1bits(a->masks.map) * sizeof *a->masks.inline_values); -} - -/* Returns true if at least one bit matched by 'b' is wildcarded by 'a', - * false otherwise. */ -bool -minimask_has_extra(const struct minimask *a, const struct minimask *b) -{ - const uint32_t *ap = miniflow_get_u32_values(&a->masks); - const uint32_t *bp = miniflow_get_u32_values(&b->masks); - int idx; - - MAP_FOR_EACH_INDEX(idx, b->masks.map) { - uint32_t b_u32 = *bp++; - - /* 'b_u32' is non-zero, check if the data in 'a' is either zero - * or misses some of the bits in 'b_u32'. */ - if (!(a->masks.map & (UINT64_C(1) << idx)) - || ((MINIFLOW_VALUES_GET__(ap, a->masks.map, idx) & b_u32) - != b_u32)) { - return true; /* 'a' wildcards some bits 'b' doesn't. */ - } - } - - return false; -} diff --git a/lib/flow.h b/lib/flow.h index 2a0d390..9e2e561 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -465,12 +465,13 @@ 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_clone_inline(struct miniflow *, const struct miniflow *, - size_t n_values); +static inline void miniflow_clone_inline(struct miniflow *, + const struct miniflow *, + size_t n_values); void miniflow_move(struct miniflow *dst, struct miniflow *); -void miniflow_destroy(struct miniflow *); +static inline void miniflow_destroy(struct miniflow *); -void miniflow_expand(const struct miniflow *, struct flow *); +static inline void miniflow_expand(const struct miniflow *, struct flow *); static inline uint32_t flow_u32_value(const struct flow *flow, size_t index) { @@ -583,13 +584,9 @@ static inline uint16_t miniflow_get_vid(const struct miniflow *); static inline uint16_t miniflow_get_tcp_flags(const struct miniflow *); static inline ovs_be64 miniflow_get_metadata(const struct miniflow *); -bool miniflow_equal(const struct miniflow *a, const struct miniflow *b); -bool miniflow_equal_in_minimask(const struct miniflow *a, - const struct miniflow *b, - const struct minimask *); -bool miniflow_equal_flow_in_minimask(const struct miniflow *a, - const struct flow *b, - const struct minimask *); +static inline bool miniflow_equal(const struct miniflow *a, + const struct miniflow *b); + uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis); @@ -605,24 +602,188 @@ struct minimask { struct miniflow masks; }; -void minimask_init(struct minimask *, const struct flow_wildcards *); -void minimask_clone(struct minimask *, const struct minimask *); -void minimask_move(struct minimask *dst, struct minimask *src); +static inline void minimask_init(struct minimask *, + const struct flow_wildcards *); +static inline void minimask_clone(struct minimask *, const struct minimask *); +static inline void minimask_move(struct minimask *dst, struct minimask *src); void minimask_combine(struct minimask *dst, const struct minimask *a, const struct minimask *b, uint32_t storage[FLOW_U32S]); -void minimask_destroy(struct minimask *); +static inline void minimask_destroy(struct minimask *); -void minimask_expand(const struct minimask *, struct flow_wildcards *); +static inline void minimask_expand(const struct minimask *, + struct flow_wildcards *); -uint32_t minimask_get(const struct minimask *, unsigned int u32_ofs); +static inline uint32_t minimask_get(const struct minimask *, + unsigned int u32_ofs); static inline uint16_t minimask_get_vid_mask(const struct minimask *); static inline ovs_be64 minimask_get_metadata_mask(const struct minimask *); -bool minimask_equal(const struct minimask *a, const struct minimask *b); -bool minimask_has_extra(const struct minimask *, const struct minimask *); +static inline bool minimask_equal(const struct minimask *a, + const struct minimask *b); +static inline bool minimask_has_extra(const struct minimask *, + const struct minimask *); +/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent + * fields in 'dst', storing the result in 'dst'. */ +static inline void +flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) +{ + uint32_t *dst_u32 = (uint32_t *)dst; + const uint32_t *p = miniflow_get_u32_values(src); + int idx; + + MAP_FOR_EACH_INDEX(idx, src->map) { + dst_u32[idx] |= *p++; + } +} + +/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'flow' + * were expanded into a "struct flow". */ +static inline uint32_t +miniflow_get(const struct miniflow *flow, unsigned int u32_ofs) +{ + return flow->map & (UINT64_C(1) << u32_ofs) + ? MINIFLOW_GET__(flow, u32_ofs) : 0; +} + +/* Initializes 'dst' as a copy of 'src'. The caller must have allocated + * 'dst' to have inline space all data in 'src'. */ +static inline void +miniflow_clone_inline(struct miniflow *dst, const struct miniflow *src, + size_t n_values) +{ + dst->values_inline = true; + dst->map = src->map; + memcpy(dst->inline_values, miniflow_get_values(src), + MINIFLOW_VALUES_SIZE(n_values)); +} + +/* Frees any memory owned by 'flow'. Does not free the storage in which 'flow' + * itself resides; the caller is responsible for that. */ +static inline void +miniflow_destroy(struct miniflow *flow) +{ + if (!flow->values_inline) { + free(flow->offline_values); + } +} + +/* Initializes 'dst' as a copy of 'src'. */ +static inline void +miniflow_expand(const struct miniflow *src, struct flow *dst) +{ + memset(dst, 0, sizeof *dst); + flow_union_with_miniflow(dst, src); +} + +/* Returns true if 'a' and 'b' are the equal miniflow, false otherwise. */ +static inline bool +miniflow_equal(const struct miniflow *a, const struct miniflow *b) +{ + const uint32_t *ap = miniflow_get_u32_values(a); + const uint32_t *bp = miniflow_get_u32_values(b); + + if (OVS_LIKELY(a->map == b->map)) { + return !memcmp(ap, bp, count_1bits(a->map) * sizeof *ap); + } else { + int idx; + + MAP_FOR_EACH_INDEX(idx, a->map | b->map) { + uint64_t bit = UINT64_C(1) << idx; + + if ((a->map & bit ? *ap++ : 0) != (b->map & bit ? *bp++ : 0)) { + return false; + } + } + } + return true; +} + +/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' + * with minimask_destroy(). */ +static inline void +minimask_init(struct minimask *mask, const struct flow_wildcards *wc) +{ + miniflow_init(&mask->masks, &wc->masks); +} + +/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' + * with minimask_destroy(). */ +static inline void +minimask_clone(struct minimask *dst, const struct minimask *src) +{ + miniflow_clone(&dst->masks, &src->masks); +} + +/* Initializes 'dst' with the data in 'src', destroying 'src'. + * The caller must eventually free 'dst' with minimask_destroy(). */ +static inline void +minimask_move(struct minimask *dst, struct minimask *src) +{ + miniflow_move(&dst->masks, &src->masks); +} + +/* Frees any memory owned by 'mask'. Does not free the storage in which 'mask' + * itself resides; the caller is responsible for that. */ +static inline void +minimask_destroy(struct minimask *mask) +{ + miniflow_destroy(&mask->masks); +} + +/* Initializes 'dst' as a copy of 'src'. */ +static inline void +minimask_expand(const struct minimask *mask, struct flow_wildcards *wc) +{ + miniflow_expand(&mask->masks, &wc->masks); +} + +/* Returns the uint32_t that would be at byte offset '4 * u32_ofs' if 'mask' + * were expanded into a "struct flow_wildcards". */ +static inline uint32_t +minimask_get(const struct minimask *mask, unsigned int u32_ofs) +{ + return miniflow_get(&mask->masks, u32_ofs); +} + +/* Returns true if 'a' and 'b' are the same flow mask, false otherwise. + * Minimasks may not have zero data values, so for the minimasks to be the + * same, they need to have the same map and the same data values. */ +static inline bool +minimask_equal(const struct minimask *a, const struct minimask *b) +{ + return a->masks.map == b->masks.map && + !memcmp(miniflow_get_u32_values(&a->masks), + miniflow_get_u32_values(&b->masks), + count_1bits(a->masks.map) * sizeof *a->masks.inline_values); +} + +/* Returns true if at least one bit matched by 'b' is wildcarded by 'a', + * false otherwise. */ +static inline bool +minimask_has_extra(const struct minimask *a, const struct minimask *b) +{ + const uint32_t *ap = miniflow_get_u32_values(&a->masks); + const uint32_t *bp = miniflow_get_u32_values(&b->masks); + int idx; + + MAP_FOR_EACH_INDEX(idx, b->masks.map) { + uint32_t b_u32 = *bp++; + + /* 'b_u32' is non-zero, check if the data in 'a' is either zero + * or misses some of the bits in 'b_u32'. */ + if (!(a->masks.map & (UINT64_C(1) << idx)) + || ((MINIFLOW_VALUES_GET__(ap, a->masks.map, idx) & b_u32) + != b_u32)) { + return true; /* 'a' wildcards some bits 'b' doesn't. */ + } + } + + return false; +} + /* Returns true if 'mask' matches every packet, false if 'mask' fixes any bits * or fields. */ static inline bool @@ -690,20 +851,6 @@ minimask_get_metadata_mask(const struct minimask *mask) return miniflow_get_metadata(&mask->masks); } -/* Perform a bitwise OR of miniflow 'src' flow data with the equivalent - * fields in 'dst', storing the result in 'dst'. */ -static inline void -flow_union_with_miniflow(struct flow *dst, const struct miniflow *src) -{ - uint32_t *dst_u32 = (uint32_t *) dst; - const uint32_t *p = miniflow_get_u32_values(src); - int idx; - - MAP_FOR_EACH_INDEX(idx, src->map) { - dst_u32[idx] |= *p++; - } -} - static inline struct pkt_metadata pkt_metadata_from_flow(const struct flow *flow) { diff --git a/lib/match.c b/lib/match.c index 480b972..2e4d0c0 100644 --- a/lib/match.c +++ b/lib/match.c @@ -1138,82 +1138,6 @@ match_print(const struct match *match) free(s); } -/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' - * with minimatch_destroy(). */ -void -minimatch_init(struct minimatch *dst, const struct match *src) -{ - 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' - * with minimatch_destroy(). */ -void -minimatch_clone(struct minimatch *dst, const struct minimatch *src) -{ - miniflow_clone(&dst->flow, &src->flow); - minimask_clone(&dst->mask, &src->mask); -} - -/* Initializes 'dst' with the data in 'src', destroying 'src'. The caller must - * eventually free 'dst' with minimatch_destroy(). */ -void -minimatch_move(struct minimatch *dst, struct minimatch *src) -{ - miniflow_move(&dst->flow, &src->flow); - minimask_move(&dst->mask, &src->mask); -} - -/* Frees any memory owned by 'match'. Does not free the storage in which - * 'match' itself resides; the caller is responsible for that. */ -void -minimatch_destroy(struct minimatch *match) -{ - miniflow_destroy(&match->flow); - minimask_destroy(&match->mask); -} - -/* Initializes 'dst' as a copy of 'src'. */ -void -minimatch_expand(const struct minimatch *src, struct match *dst) -{ - miniflow_expand(&src->flow, &dst->flow); - minimask_expand(&src->mask, &dst->wc); -} - -/* Returns true if 'a' and 'b' match the same packets, false otherwise. */ -bool -minimatch_equal(const struct minimatch *a, const struct minimatch *b) -{ - return (miniflow_equal(&a->flow, &b->flow) - && minimask_equal(&a->mask, &b->mask)); -} - -/* 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 = miniflow_get_u32_values(&match->flow); - const uint32_t *maskp = miniflow_get_u32_values(&match->mask.masks); - int idx; - - MAP_FOR_EACH_INDEX(idx, match->flow.map) { - if ((*flowp++ ^ target_u32[idx]) & *maskp++) { - return false; - } - } - - 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 a245bcf..a737ade 100644 --- a/lib/match.h +++ b/lib/match.h @@ -164,18 +164,101 @@ struct minimatch { struct minimask mask; }; -void minimatch_init(struct minimatch *, const struct match *); -void minimatch_clone(struct minimatch *, const struct minimatch *); -void minimatch_move(struct minimatch *dst, struct minimatch *src); -void minimatch_destroy(struct minimatch *); +static inline void minimatch_init(struct minimatch *, const struct match *); +static inline void minimatch_clone(struct minimatch *, + const struct minimatch *); +static inline void minimatch_move(struct minimatch *dst, + struct minimatch *src); +static inline void minimatch_destroy(struct minimatch *); -void minimatch_expand(const struct minimatch *, struct match *); +static inline void minimatch_expand(const struct minimatch *, struct match *); -bool minimatch_equal(const struct minimatch *a, const struct minimatch *b); +static inline bool minimatch_equal(const struct minimatch *a, + const struct minimatch *b); -bool minimatch_matches_flow(const struct minimatch *, const struct flow *); +static inline bool minimatch_matches_flow(const struct minimatch *, + const struct flow *); void minimatch_format(const struct minimatch *, struct ds *, int priority); char *minimatch_to_string(const struct minimatch *, int priority); + +/* Inline implementations. */ + +/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst' + * with minimatch_destroy(). */ +static inline void +minimatch_init(struct minimatch *dst, const struct match *src) +{ + 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' + * with minimatch_destroy(). */ +static inline void +minimatch_clone(struct minimatch *dst, const struct minimatch *src) +{ + miniflow_clone(&dst->flow, &src->flow); + minimask_clone(&dst->mask, &src->mask); +} + +/* Initializes 'dst' with the data in 'src', destroying 'src'. The caller must + * eventually free 'dst' with minimatch_destroy(). */ +static inline void +minimatch_move(struct minimatch *dst, struct minimatch *src) +{ + miniflow_move(&dst->flow, &src->flow); + minimask_move(&dst->mask, &src->mask); +} + +/* Frees any memory owned by 'match'. Does not free the storage in which + * 'match' itself resides; the caller is responsible for that. */ +static inline void +minimatch_destroy(struct minimatch *match) +{ + miniflow_destroy(&match->flow); + minimask_destroy(&match->mask); +} + +/* Initializes 'dst' as a copy of 'src'. */ +static inline void +minimatch_expand(const struct minimatch *src, struct match *dst) +{ + miniflow_expand(&src->flow, &dst->flow); + minimask_expand(&src->mask, &dst->wc); +} + +/* Returns true if 'a' and 'b' match the same packets, false otherwise. */ +static inline bool +minimatch_equal(const struct minimatch *a, const struct minimatch *b) +{ + return (miniflow_equal(&a->flow, &b->flow) + && minimask_equal(&a->mask, &b->mask)); +} + +/* 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. */ +static inline 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 = miniflow_get_u32_values(&match->flow); + const uint32_t *maskp = miniflow_get_u32_values(&match->mask.masks); + int idx; + + MAP_FOR_EACH_INDEX(idx, match->flow.map) { + if ((*flowp++ ^ target_u32[idx]) & *maskp++) { + return false; + } + } + + return true; +} + #endif /* match.h */ diff --git a/tests/test-classifier.c b/tests/test-classifier.c index e4eb0f4..fde050b 100644 --- a/tests/test-classifier.c +++ b/tests/test-classifier.c @@ -1251,6 +1251,25 @@ wildcard_extra_bits(struct flow_wildcards *mask) } } +/* Returns true if 'a' and 'b' are equal at the places where there are 1-bits + * in 'mask', false if they differ. */ +static bool +miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct flow *b, + const struct minimask *mask) +{ + const uint32_t *b_u32 = (const uint32_t *) b; + const uint32_t *p = miniflow_get_u32_values(&mask->masks); + int idx; + + MAP_FOR_EACH_INDEX(idx, mask->masks.map) { + if ((miniflow_get(a, idx) ^ b_u32[idx]) & *p++) { + return false; + } + } + + return true; +} + static void test_miniflow(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) { -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev