This patch makes miniflow building utilities available to other modules. A following patch adds support for classifier lookups on miniflows, for which a custom-built miniflow key can be more efficient than building a full struct flow and then converting that to a miniflow.
Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/flow.c | 117 ------------------------------------------------------------ lib/flow.h | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 117 deletions(-) diff --git a/lib/flow.c b/lib/flow.c index 37d6af8..dd27f04 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -108,123 +108,6 @@ data_try_pull(void **datap, size_t *sizep, size_t size) return OVS_LIKELY(*sizep >= size) ? data_pull(datap, sizep, size) : NULL; } -/* Macros for building miniflows. Miniflow fields must be pushed in the order - * they appear in struct flow. Using a out-of-sync FLOW_WC_SEQ value below - * will cause runtime assertions to make sure the code complies with the order - * requirement. */ - -#if (FLOW_WC_SEQ != 28) -#define MINIFLOW_ASSERT(X) ovs_assert(X) -BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " - "assertions enabled. Consider updating FLOW_WC_SEQ value " - "above MINIFLOW_ASSERT() after testing.") -#else -#define MINIFLOW_ASSERT(X) -#endif - -/* This is useful for making sure the buffer is properly aligned. */ -static inline void miniflow_assert_inline(const struct miniflow *mf, - const uint32_t *buf) -{ - ovs_assert(buf == mf->inline_values || buf == (uint32_t *)(mf + 1)); -} - -/* Context for pushing data to a miniflow. */ -struct mf_ctx { - uint64_t map; - uint32_t *data; - uint32_t * const end; -}; - -#define MF_CTX_INITIALIZER(BUF, COUNT) { 0, (BUF), (BUF) + COUNT } -#define MF_CTX_FINISH(CTX, MINIFLOW) \ -do { \ - (MINIFLOW)->map = (CTX).map; \ - (MINIFLOW)->values_inline = true; \ -} while (0) - -/* miniflow_push_* macros allow filling in a miniflow data values in order. - * Assertions are needed only when the layout of the struct flow is modified. - * 'ofs' is a compile-time constant, which allows most of the code be optimized - * away. */ - -#define miniflow_push_uint32_(CTX, OFS, VALUE) \ -do { \ - MINIFLOW_ASSERT((CTX).data < (CTX).end); \ - MINIFLOW_ASSERT((OFS) % 4 == 0); \ - MINIFLOW_ASSERT(!((CTX).map & (UINT64_MAX << (OFS) / 4))); \ - \ - *(CTX).data++ = VALUE; \ - (CTX).map |= UINT64_C(1) << (OFS) / 4; \ -} while (0) - -#define miniflow_push_be32_(CTX, OFS, VALUE) \ - miniflow_push_uint32_(CTX, OFS, (OVS_FORCE uint32_t)(VALUE)) - -#define miniflow_push_uint16_(CTX, OFS, VALUE) \ -do { \ - MINIFLOW_ASSERT((CTX).data < (CTX).end); \ - MINIFLOW_ASSERT(((OFS) % 4 == 0 \ - && !((CTX).map & (UINT64_MAX << (OFS) / 4))) \ - || ((OFS) % 4 == 2 \ - && (CTX).map & (UINT64_C(1) << (OFS) / 4) \ - && !((CTX).map & (UINT64_MAX << ((OFS) / 4 + 1))))); \ - \ - if ((OFS) % 4 == 0) { \ - *(uint16_t *)(CTX).data = VALUE; \ - (CTX).map |= UINT64_C(1) << (OFS) / 4; \ - } else if ((OFS) % 4 == 2) { \ - *((uint16_t *)(CTX).data + 1) = VALUE; \ - (CTX).data++; \ - } \ -} while (0) - -#define miniflow_push_be16_(CTX, OFS, VALUE) \ - miniflow_push_uint16_(CTX, OFS, (OVS_FORCE uint16_t)VALUE); - -/* Data at 'valuep' may be unaligned. */ -#define miniflow_push_words_(CTX, OFS, VALUEP, N_WORDS) \ -do { \ - int ofs32 = (OFS) / 4; \ - \ - MINIFLOW_ASSERT((CTX).data + (N_WORDS) <= (CTX).end); \ - MINIFLOW_ASSERT((OFS) % 4 == 0); \ - MINIFLOW_ASSERT(!((CTX).map & (UINT64_MAX << ofs32))); \ - \ - memcpy((CTX).data, (VALUEP), (N_WORDS) * sizeof *(CTX).data); \ - (CTX).data += (N_WORDS); \ - (CTX).map |= ((UINT64_MAX >> (64 - (N_WORDS))) << ofs32); \ -} while (0) - -#define miniflow_push_uint32(CTX, FIELD, VALUE) \ - miniflow_push_uint32_(CTX, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_be32(CTX, FIELD, VALUE) \ - miniflow_push_be32_(CTX, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_uint32_check(CTX, FIELD, VALUE) \ -do { \ - if (OVS_LIKELY(VALUE)) { \ - miniflow_push_uint32_(CTX, offsetof(struct flow, FIELD), VALUE); \ - } \ -} while (0) - -#define miniflow_push_be32_check(CTX, FIELD, VALUE) \ -do { \ - if (OVS_LIKELY(VALUE)) { \ - miniflow_push_be32_(CTX, offsetof(struct flow, FIELD), VALUE); \ - } \ -} while (0) - -#define miniflow_push_uint16(CTX, FIELD, VALUE) \ - miniflow_push_uint16_(CTX, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_be16(CTX, FIELD, VALUE) \ - miniflow_push_be16_(CTX, offsetof(struct flow, FIELD), VALUE) - -#define miniflow_push_words(CTX, FIELD, VALUEP, N_WORDS) \ - miniflow_push_words_(CTX, offsetof(struct flow, FIELD), VALUEP, N_WORDS) - /* Pulls the MPLS headers at '*datap' and returns the count of them. */ static inline int parse_mpls(void **datap, size_t *sizep) diff --git a/lib/flow.h b/lib/flow.h index f19f330..f9b577f 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -443,6 +443,123 @@ static inline const ovs_be32 *miniflow_get_be32_values(const struct miniflow *mf return (OVS_FORCE const ovs_be32 *)miniflow_get_values(mf); } +/* Macros for building miniflows. Miniflow fields must be pushed in the order + * they appear in struct flow. Using a out-of-sync FLOW_WC_SEQ value below + * will cause runtime assertions to make sure the code complies with the order + * requirement. */ + +#if (FLOW_WC_SEQ != 28) +#define MINIFLOW_ASSERT(X) ovs_assert(X) +BUILD_MESSAGE("FLOW_WC_SEQ changed: miniflow_extract() will have runtime " + "assertions enabled. Consider updating FLOW_WC_SEQ value " + "above MINIFLOW_ASSERT() after testing.") +#else +#define MINIFLOW_ASSERT(X) +#endif + +/* This is useful for making sure the buffer is properly aligned. */ +static inline void miniflow_assert_inline(const struct miniflow *mf, + const uint32_t *buf) +{ + ovs_assert(buf == mf->inline_values || buf == (uint32_t *)(mf + 1)); +} + +/* Context for pushing data to a miniflow. */ +struct mf_ctx { + uint64_t map; + uint32_t *data; + uint32_t * const end; +}; + +#define MF_CTX_INITIALIZER(BUF, COUNT) { 0, (BUF), (BUF) + COUNT } +#define MF_CTX_FINISH(CTX, MINIFLOW) \ +do { \ + (MINIFLOW)->map = (CTX).map; \ + (MINIFLOW)->values_inline = true; \ +} while (0) + +/* miniflow_push_* macros allow filling in a miniflow data values in order. + * Assertions are needed only when the layout of the struct flow is modified. + * 'ofs' is a compile-time constant, which allows most of the code be optimized + * away. */ + +#define miniflow_push_uint32_(CTX, OFS, VALUE) \ +do { \ + MINIFLOW_ASSERT((CTX).data < (CTX).end); \ + MINIFLOW_ASSERT((OFS) % 4 == 0); \ + MINIFLOW_ASSERT(!((CTX).map & (UINT64_MAX << (OFS) / 4))); \ + \ + *(CTX).data++ = VALUE; \ + (CTX).map |= UINT64_C(1) << (OFS) / 4; \ +} while (0) + +#define miniflow_push_be32_(CTX, OFS, VALUE) \ + miniflow_push_uint32_(CTX, OFS, (OVS_FORCE uint32_t)(VALUE)) + +#define miniflow_push_uint16_(CTX, OFS, VALUE) \ +do { \ + MINIFLOW_ASSERT((CTX).data < (CTX).end); \ + MINIFLOW_ASSERT(((OFS) % 4 == 0 \ + && !((CTX).map & (UINT64_MAX << (OFS) / 4))) \ + || ((OFS) % 4 == 2 \ + && (CTX).map & (UINT64_C(1) << (OFS) / 4) \ + && !((CTX).map & (UINT64_MAX << ((OFS) / 4 + 1))))); \ + \ + if ((OFS) % 4 == 0) { \ + *(uint16_t *)(CTX).data = VALUE; \ + (CTX).map |= UINT64_C(1) << (OFS) / 4; \ + } else if ((OFS) % 4 == 2) { \ + *((uint16_t *)(CTX).data + 1) = VALUE; \ + (CTX).data++; \ + } \ +} while (0) + +#define miniflow_push_be16_(CTX, OFS, VALUE) \ + miniflow_push_uint16_(CTX, OFS, (OVS_FORCE uint16_t)VALUE); + +/* Data at 'valuep' may be unaligned. */ +#define miniflow_push_words_(CTX, OFS, VALUEP, N_WORDS) \ +do { \ + int ofs32 = (OFS) / 4; \ + \ + MINIFLOW_ASSERT((CTX).data + (N_WORDS) <= (CTX).end); \ + MINIFLOW_ASSERT((OFS) % 4 == 0); \ + MINIFLOW_ASSERT(!((CTX).map & (UINT64_MAX << ofs32))); \ + \ + memcpy((CTX).data, (VALUEP), (N_WORDS) * sizeof *(CTX).data); \ + (CTX).data += (N_WORDS); \ + (CTX).map |= ((UINT64_MAX >> (64 - (N_WORDS))) << ofs32); \ +} while (0) + +#define miniflow_push_uint32(CTX, FIELD, VALUE) \ + miniflow_push_uint32_(CTX, offsetof(struct flow, FIELD), VALUE) + +#define miniflow_push_be32(CTX, FIELD, VALUE) \ + miniflow_push_be32_(CTX, offsetof(struct flow, FIELD), VALUE) + +#define miniflow_push_uint32_check(CTX, FIELD, VALUE) \ +do { \ + if (OVS_LIKELY(VALUE)) { \ + miniflow_push_uint32_(CTX, offsetof(struct flow, FIELD), VALUE); \ + } \ +} while (0) + +#define miniflow_push_be32_check(CTX, FIELD, VALUE) \ +do { \ + if (OVS_LIKELY(VALUE)) { \ + miniflow_push_be32_(CTX, offsetof(struct flow, FIELD), VALUE); \ + } \ +} while (0) + +#define miniflow_push_uint16(CTX, FIELD, VALUE) \ + miniflow_push_uint16_(CTX, offsetof(struct flow, FIELD), VALUE) + +#define miniflow_push_be16(CTX, FIELD, VALUE) \ + miniflow_push_be16_(CTX, offsetof(struct flow, FIELD), VALUE) + +#define miniflow_push_words(CTX, FIELD, VALUEP, N_WORDS) \ + miniflow_push_words_(CTX, offsetof(struct flow, FIELD), VALUEP, N_WORDS) + struct pkt_metadata; /* The 'dst->values' must be initialized with a buffer with space for -- 1.7.10.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev