+/* 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. */
+
+#if (FLOW_WC_SEQ != 34)
+#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")
+#else
+#define MINIFLOW_ASSERT(X)
+#endif
+
+/* True if 'IDX' and higher bits are not set. */
+#define ASSERT_FLOWMAP_NOT_SET(FM, IDX) \
+{ \
+ MINIFLOW_ASSERT(!((FM)->bits[(IDX) / MAP_T_BITS] & \
+ (FLOWMAP_MAX << ((IDX) % MAP_T_BITS)))); \
+ for (size_t i = (IDX) / MAP_T_BITS + 1; i < FLOWMAP_UNITS; i++) { \
+ MINIFLOW_ASSERT(!(FM)->bits[i]); \
+ } \
+}
+
+#define miniflow_set_map(MF, OFS) \
+ { \
+ ASSERT_FLOWMAP_NOT_SET(&MF.map, (OFS)); \
+ flowmap_set(&MF.map, (OFS), 1); \
+}
+
+#define miniflow_assert_in_map(MF, OFS) \
+ MINIFLOW_ASSERT(FLOWMAP_IS_SET(MF.map, (OFS))); \
+ ASSERT_FLOWMAP_NOT_SET(&MF.map, (OFS) + 1)
+
+#define miniflow_push_uint64_(MF, OFS, VALUE) \
+{ \
+ MINIFLOW_ASSERT(MF.data < MF.end && (OFS) % 8 == 0); \
+ *MF.data++ = VALUE; \
+ miniflow_set_map(MF, OFS / 8); \
+}
+
+#define miniflow_push_be64_(MF, OFS, VALUE) \
+ miniflow_push_uint64_(MF, OFS, (OVS_FORCE uint64_t)(VALUE))
+
+#define miniflow_push_uint32_(MF, OFS, VALUE) \
+ { \
+ MINIFLOW_ASSERT(MF.data < MF.end); \
+ \
+ if ((OFS) % 8 == 0) { \
+ miniflow_set_map(MF, OFS / 8); \
+ *(uint32_t *)MF.data = VALUE; \
+ } else if ((OFS) % 8 == 4) { \
+ miniflow_assert_in_map(MF, OFS / 8); \
+ *((uint32_t *)MF.data + 1) = VALUE; \
+ MF.data++; \
+ } \
+}
+
+#define miniflow_push_be32_(MF, OFS, VALUE) \
+ miniflow_push_uint32_(MF, OFS, (OVS_FORCE uint32_t)(VALUE))
+
+#define miniflow_push_uint16_(MF, OFS, VALUE) \
+{ \
+ MINIFLOW_ASSERT(MF.data < MF.end); \
+ \
+ if ((OFS) % 8 == 0) { \
+ miniflow_set_map(MF, OFS / 8); \
+ *(uint16_t *)MF.data = VALUE; \
+ } else if ((OFS) % 8 == 2) { \
+ miniflow_assert_in_map(MF, OFS / 8); \
+ *((uint16_t *)MF.data + 1) = VALUE; \
+ } else if ((OFS) % 8 == 4) { \
+ miniflow_assert_in_map(MF, OFS / 8); \
+ *((uint16_t *)MF.data + 2) = VALUE; \
+ } else if ((OFS) % 8 == 6) { \
+ miniflow_assert_in_map(MF, OFS / 8); \
+ *((uint16_t *)MF.data + 3) = VALUE; \
+ MF.data++; \
+ } \
+}
+
+#define miniflow_pad_to_64_(MF, OFS) \
+{ \
+ MINIFLOW_ASSERT((OFS) % 8 != 0); \
+ miniflow_assert_in_map(MF, OFS / 8); \
+ \
+ memset((uint8_t *)MF.data + (OFS) % 8, 0, 8 - (OFS) % 8); \
+ MF.data++; \
+}
+
+#define miniflow_push_be16_(MF, OFS, VALUE) \
+ miniflow_push_uint16_(MF, OFS, (OVS_FORCE uint16_t)VALUE);
+
+#define miniflow_set_maps(MF, OFS, N_WORDS) \
+{ \
+ size_t ofs = (OFS); \
+ size_t n_words = (N_WORDS); \
+ \
+ MINIFLOW_ASSERT(n_words && MF.data + n_words <= MF.end); \
+ ASSERT_FLOWMAP_NOT_SET(&MF.map, ofs); \
+ flowmap_set(&MF.map, ofs, n_words); \
+}
+
+/* Data at 'valuep' may be unaligned. */
+#define miniflow_push_words_(MF, OFS, VALUEP, N_WORDS) \
+{ \
+ MINIFLOW_ASSERT((OFS) % 8 == 0); \
+ miniflow_set_maps(MF, (OFS) / 8, (N_WORDS)); \
+ memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof *MF.data); \
+ MF.data += (N_WORDS); \
+}
+
+/* Push 32-bit words padded to 64-bits. */
+#define miniflow_push_words_32_(MF, OFS, VALUEP, N_WORDS) \
+{ \
+ miniflow_set_maps(MF, (OFS) / 8, DIV_ROUND_UP(N_WORDS, 2)); \
+ memcpy(MF.data, (VALUEP), (N_WORDS) * sizeof(uint32_t)); \
+ MF.data += DIV_ROUND_UP(N_WORDS, 2); \
+ if ((N_WORDS) & 1) { \
+ *((uint32_t *)MF.data - 1) = 0; \
+ } \
+}
+
+/* Data at 'valuep' may be unaligned. */
+/* MACs start 64-aligned, and must be followed by other data or padding. */
+#define miniflow_push_macs_(MF, OFS, VALUEP) \
+{ \
+ miniflow_set_maps(MF, (OFS) / 8, 2); \
+ memcpy(MF.data, (VALUEP), 2 * ETH_ADDR_LEN); \
+ MF.data += 1; /* First word only. */ \
+}
+
+#define miniflow_push_uint32(MF, FIELD, VALUE) \
+ miniflow_push_uint32_(MF, offsetof(struct flow, FIELD), VALUE)
+
+#define miniflow_push_be32(MF, FIELD, VALUE) \
+ miniflow_push_be32_(MF, offsetof(struct flow, FIELD), VALUE)
+
+#define miniflow_push_uint16(MF, FIELD, VALUE) \
+ miniflow_push_uint16_(MF, offsetof(struct flow, FIELD), VALUE)
+
+#define miniflow_push_be16(MF, FIELD, VALUE) \
+ miniflow_push_be16_(MF, offsetof(struct flow, FIELD), VALUE)
+
+#define miniflow_pad_to_64(MF, FIELD) \
+ miniflow_pad_to_64_(MF, offsetof(struct flow, FIELD))
+
+#define miniflow_push_words(MF, FIELD, VALUEP, N_WORDS) \
+ miniflow_push_words_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS)
+
+#define miniflow_push_words_32(MF, FIELD, VALUEP, N_WORDS) \
+ miniflow_push_words_32_(MF, offsetof(struct flow, FIELD), VALUEP, N_WORDS)
+
+#define miniflow_push_macs(MF, FIELD, VALUEP) \
+ miniflow_push_macs_(MF, offsetof(struct flow, FIELD), VALUEP)
+
+/* Pulls the MPLS headers at '*datap' and returns the count of them. */
+static inline int
+parse_mpls(const void **datap, size_t *sizep)
+{
+ const struct mpls_hdr *mh;
+ int count = 0;
+
+ while ((mh = data_try_pull(datap, sizep, sizeof *mh))) {
+ count++;
+ if (mh->mpls_lse.lo & htons(1 << MPLS_BOS_SHIFT)) {