All the users of miniflow extract supply a miniflow with inlined data. Make the extraction a bit more efficient by only supporting this.
Also, clean up miniflow building utilities in preparation for moving them to lib/flow.h in a later patch. Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> --- lib/dpif-netdev.c | 22 +++++--- lib/flow.c | 161 +++++++++++++++++++++++++++++++---------------------- lib/flow.h | 11 ---- 3 files changed, 106 insertions(+), 88 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 83dbd61..b0f3510 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -435,6 +435,8 @@ static void dp_netdev_reset_pmd_threads(struct dp_netdev *dp); static void emc_clear_entry(struct emc_entry *ce); +static inline void netdev_flow_key_init(struct netdev_flow_key *key); + static void emc_cache_init(struct emc_cache *flow_cache) { @@ -444,11 +446,7 @@ emc_cache_init(struct emc_cache *flow_cache) for (i = 0; i < ARRAY_SIZE(flow_cache->entries); i++) { flow_cache->entries[i].flow = NULL; - flow_cache->entries[i].key.hash = 0; - flow_cache->entries[i].key.len - = offsetof(struct miniflow, inline_values); - miniflow_initialize(&flow_cache->entries[i].key.mf, - flow_cache->entries[i].key.buf); + netdev_flow_key_init(&flow_cache->entries[i].key); } } @@ -1289,6 +1287,15 @@ netdev_flow_key_size(uint32_t flow_u32s) MINIFLOW_VALUES_SIZE(flow_u32s); } +static inline void +netdev_flow_key_init(struct netdev_flow_key *key) +{ + key->hash = 0; + key->len = netdev_flow_key_size(0); + key->mf.map = 0; + key->mf.values_inline = true; +} + static inline bool netdev_flow_key_equal(const struct netdev_flow_key *a, const struct netdev_flow_key *b) @@ -1324,8 +1331,6 @@ netdev_flow_key_from_flow(struct netdev_flow_key *dst, uint64_t buf_stub[512 / 8]; struct pkt_metadata md = pkt_metadata_from_flow(src); - miniflow_initialize(&dst->mf, dst->buf); - ofpbuf_use_stub(&packet, buf_stub, sizeof buf_stub); flow_compose(&packet, src); miniflow_extract(&packet, &md, &dst->mf); @@ -2767,7 +2772,6 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, struct dpif_packet **packets, size_t notfound_cnt = 0; n_batches = 0; - miniflow_initialize(&key.mf, key.buf); for (i = 0; i < cnt; i++) { struct dp_netdev_flow *flow; @@ -2777,7 +2781,7 @@ emc_processing(struct dp_netdev_pmd_thread *pmd, struct dpif_packet **packets, } miniflow_extract(&packets[i]->ofpbuf, &packets[i]->md, &key.mf); - key.len = 0; /* Not computed yet. */ + key.len = netdev_flow_key_size(0); /* Not computed yet. */ key.hash = dpif_netdev_packet_get_dp_hash(packets[i], &key.mf); flow = emc_lookup(flow_cache, &key); diff --git a/lib/flow.c b/lib/flow.c index 8a98ad6..37d6af8 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -108,97 +108,122 @@ data_try_pull(void **datap, size_t *sizep, size_t size) return OVS_LIKELY(*sizep >= size) ? data_pull(datap, sizep, size) : NULL; } -/* Context for pushing data to a miniflow. */ -struct mf_ctx { - uint64_t map; - uint32_t *data; - uint32_t * const end; -}; - -/* 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. Some GCC versions gave warnings on ALWAYS_INLINE, so these are - * defined as macros. */ +/* 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 after " - "testing") + "assertions enabled. Consider updating FLOW_WC_SEQ value " + "above MINIFLOW_ASSERT() after testing.") #else #define MINIFLOW_ASSERT(X) #endif -#define miniflow_push_uint32_(MF, OFS, VALUE) \ -{ \ - MINIFLOW_ASSERT(MF.data < MF.end && (OFS) % 4 == 0 \ - && !(MF.map & (UINT64_MAX << (OFS) / 4))); \ - *MF.data++ = VALUE; \ - MF.map |= UINT64_C(1) << (OFS) / 4; \ +/* 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)); } -#define miniflow_push_be32_(MF, OFS, VALUE) \ - miniflow_push_uint32_(MF, OFS, (OVS_FORCE uint32_t)(VALUE)) +/* 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) -#define miniflow_push_uint16_(MF, OFS, VALUE) \ -{ \ - MINIFLOW_ASSERT(MF.data < MF.end && \ - (((OFS) % 4 == 0 && !(MF.map & (UINT64_MAX << (OFS) / 4))) \ - || ((OFS) % 4 == 2 && MF.map & (UINT64_C(1) << (OFS) / 4) \ - && !(MF.map & (UINT64_MAX << ((OFS) / 4 + 1)))))); \ +/* 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 *)MF.data = VALUE; \ - MF.map |= UINT64_C(1) << (OFS) / 4; \ + *(uint16_t *)(CTX).data = VALUE; \ + (CTX).map |= UINT64_C(1) << (OFS) / 4; \ } else if ((OFS) % 4 == 2) { \ - *((uint16_t *)MF.data + 1) = VALUE; \ - MF.data++; \ + *((uint16_t *)(CTX).data + 1) = VALUE; \ + (CTX).data++; \ } \ -} +} while (0) -#define miniflow_push_be16_(MF, OFS, VALUE) \ - miniflow_push_uint16_(MF, OFS, (OVS_FORCE uint16_t)VALUE); +#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_(MF, OFS, VALUEP, N_WORDS) \ -{ \ - int ofs32 = (OFS) / 4; \ +#define miniflow_push_words_(CTX, OFS, VALUEP, N_WORDS) \ +do { \ + int ofs32 = (OFS) / 4; \ \ - MINIFLOW_ASSERT(MF.data + (N_WORDS) <= MF.end && (OFS) % 4 == 0 \ - && !(MF.map & (UINT64_MAX << ofs32))); \ + MINIFLOW_ASSERT((CTX).data + (N_WORDS) <= (CTX).end); \ + MINIFLOW_ASSERT((OFS) % 4 == 0); \ + MINIFLOW_ASSERT(!((CTX).map & (UINT64_MAX << ofs32))); \ \ - memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof *MF.data); \ - MF.data += (N_WORDS); \ - MF.map |= ((UINT64_MAX >> (64 - (N_WORDS))) << 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(MF, FIELD, VALUE) \ - miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), VALUE) +#define miniflow_push_uint32(CTX, FIELD, VALUE) \ + miniflow_push_uint32_(CTX, offsetof(struct flow, FIELD), VALUE) -#define miniflow_push_be32(MF, FIELD, VALUE) \ - miniflow_push_be32_(MF, 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(MF, FIELD, VALUE) \ - { if (OVS_LIKELY(VALUE)) { \ - miniflow_push_uint32_(MF, 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(MF, FIELD, VALUE) \ - { if (OVS_LIKELY(VALUE)) { \ - miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE); \ - } \ - } +#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(MF, FIELD, VALUE) \ - miniflow_push_uint16_(MF, offsetof(struct flow, FIELD), VALUE) +#define miniflow_push_uint16(CTX, FIELD, VALUE) \ + miniflow_push_uint16_(CTX, offsetof(struct flow, FIELD), VALUE) -#define miniflow_push_be16(MF, FIELD, VALUE) \ - miniflow_push_be16_(MF, 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(MF, FIELD, VALUEP, N_WORDS) \ - miniflow_push_words_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS) +#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 @@ -354,7 +379,7 @@ flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, COVERAGE_INC(flow_extract); - miniflow_initialize(&m.mf, m.buf); + miniflow_assert_inline(&m.mf, m.buf); miniflow_extract(packet, md, &m.mf); miniflow_expand(&m.mf, flow); } @@ -367,8 +392,8 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, { void *data = ofpbuf_data(packet); size_t size = ofpbuf_size(packet); - uint32_t *values = miniflow_values(dst); - struct mf_ctx mf = { 0, values, values + FLOW_U32S }; + uint32_t *values = dst->inline_values; + struct mf_ctx mf = MF_CTX_INITIALIZER(values, FLOW_U32S); char *l2; ovs_be16 dl_type; uint8_t nw_frag, nw_tos, nw_ttl, nw_proto; @@ -656,7 +681,7 @@ miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md, miniflow_push_uint32_check(mf, dp_hash, md->dp_hash); } out: - dst->map = mf.map; + MF_CTX_FINISH(mf, dst); } /* For every bit of a field that is wildcarded in 'wildcards', sets the diff --git a/lib/flow.h b/lib/flow.h index 9e2e561..f19f330 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -443,17 +443,6 @@ static inline const ovs_be32 *miniflow_get_be32_values(const struct miniflow *mf return (OVS_FORCE const ovs_be32 *)miniflow_get_values(mf); } -/* This is useful for initializing a miniflow for a miniflow_extract() call. */ -static inline void miniflow_initialize(struct miniflow *mf, - uint32_t buf[FLOW_U32S]) -{ - mf->map = 0; - mf->values_inline = (buf == (uint32_t *)(mf + 1)); - if (!mf->values_inline) { - mf->offline_values = buf; - } -} - 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