flow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
struct flow *flow)
{
- uint32_t buf[FLOW_U32S];
- struct miniflow mf;
+ struct {
+ struct miniflow mf;
+ uint32_t buf[FLOW_U32S];
+ } m;
COVERAGE_INC(flow_extract);
- miniflow_initialize(&mf, buf);
- miniflow_extract(packet, md, &mf);
- miniflow_expand(&mf, flow);
+ miniflow_initialize(&m.mf, m.buf);
+ miniflow_extract(packet, md, &m.mf);
+ miniflow_expand(&m.mf, flow);
}
-/* Caller is responsible for initializing 'dst->values' with enough storage
- * for FLOW_U32S * 4 bytes. */
+/* Caller is responsible for initializing 'dst' with enough storage for
+ * FLOW_U32S * 4 bytes. */
void
miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
struct miniflow *dst)
{
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 };
char *l2;
- struct mf_ctx mf = { 0, dst->values, dst->values + FLOW_U32S };
ovs_be16 dl_type;
uint8_t nw_frag, nw_tos, nw_ttl, nw_proto;
static uint32_t *
miniflow_alloc_values(struct miniflow *flow, int n)
{
- if (n <= MINI_N_INLINE) {
+ if (n <= sizeof flow->inline_values / sizeof(uint32_t)) {
+ flow->values_inline = true;
return flow->inline_values;
} else {
COVERAGE_INC(miniflow_malloc);
- return xmalloc(n * sizeof *flow->values);
+ flow->values_inline = false;
+ flow->offline_values = xmalloc(n * sizeof(uint32_t));
+ return flow->offline_values;
}
}
* when a miniflow is initialized from a (mini)mask, the values can be zeroes,
* so that the flow and mask always have the same maps.
*
- * This function initializes 'dst->values' (either inline if possible or with
+ * This function initializes values (either inline if possible or with
* malloc() otherwise) and copies the uint32_t elements of 'src' indicated by
* 'dst->map' into it. */
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;
+ uint32_t *dst_u32 = miniflow_alloc_values(dst, n);
uint64_t map;
- dst->values = miniflow_alloc_values(dst, n);
- ofs = 0;
for (map = dst->map; map; map = zero_rightmost_1bit(map)) {
- dst->values[ofs++] = src_u32[raw_ctz(map)];
+ *dst_u32++ = src_u32[raw_ctz(map)];
}
}
/* Initializes 'dst' as a copy of 'src'. The caller must eventually free 'dst'
- * with miniflow_destroy(). */
+ * with miniflow_destroy().
+ * Always allocates offline storage. */
void
miniflow_init(struct miniflow *dst, const struct flow *src)
{
{
int n = miniflow_n_values(src);
dst->map = src->map;
- dst->values = miniflow_alloc_values(dst, n);
- memcpy(dst->values, src->values, n * sizeof *dst->values);
+ memcpy(miniflow_alloc_values(dst, n), miniflow_get_values(src),
+ n * sizeof(uint32_t));
}
/* Initializes 'dst' with the data in 'src', destroying 'src'.
void
miniflow_move(struct miniflow *dst, struct miniflow *src)
{
- if (src->values == src->inline_values) {
- dst->values = dst->inline_values;
- memcpy(dst->values, src->values,
- miniflow_n_values(src) * sizeof *dst->values);
- } else {
- dst->values = src->values;
- }
- dst->map = src->map;
+ *dst = *src;
}
/* Frees any memory owned by 'flow'. Does not free the storage in which 'flow'
void
miniflow_destroy(struct miniflow *flow)
{
- if (flow->values != flow->inline_values) {
- free(flow->values);
+ if (!flow->values_inline) {
+ free(flow->offline_values);
}
}
miniflow_get(const struct miniflow *flow, unsigned int u32_ofs)
{
return (flow->map & UINT64_C(1) << u32_ofs)
- ? *(flow->values +
+ ? *(miniflow_get_u32_values(flow) +
count_1bits(flow->map & ((UINT64_C(1) << u32_ofs) - 1)))
: 0;
}
bool
miniflow_equal(const struct miniflow *a, const struct miniflow *b)
{
- const uint32_t *ap = a->values;
- const uint32_t *bp = b->values;
+ const uint32_t *ap = miniflow_get_u32_values(a);
+ const uint32_t *bp = miniflow_get_u32_values(b);
const uint64_t a_map = a->map;
const uint64_t b_map = b->map;
- uint64_t map;
- if (a_map == b_map) {
- for (map = a_map; map; map = zero_rightmost_1bit(map)) {
+ if (OVS_LIKELY(a_map == b_map)) {
+ int count = miniflow_n_values(a);
+
+ while (count--) {
if (*ap++ != *bp++) {
return false;
}
}
} else {
+ uint64_t map;
+
for (map = a_map | b_map; map; map = zero_rightmost_1bit(map)) {
uint64_t bit = rightmost_1bit(map);
uint64_t a_value = a_map & bit ? *ap++ : 0;
miniflow_equal_in_minimask(const struct miniflow *a, const struct miniflow *b,
const struct minimask *mask)
{
- const uint32_t *p;
+ const uint32_t *p = miniflow_get_u32_values(&mask->masks);
uint64_t map;
- p = mask->masks.values;
-
for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
int ofs = raw_ctz(map);
- if ((miniflow_get(a, ofs) ^ miniflow_get(b, ofs)) & *p) {
+ if ((miniflow_get(a, ofs) ^ miniflow_get(b, ofs)) & *p++) {
return false;
}
- p++;
}
return true;
const struct minimask *mask)
{
const uint32_t *b_u32 = (const uint32_t *) b;
- const uint32_t *p;
+ const uint32_t *p = miniflow_get_u32_values(&mask->masks);
uint64_t map;
- p = mask->masks.values;
-
for (map = mask->masks.map; map; map = zero_rightmost_1bit(map)) {
int ofs = raw_ctz(map);
- if ((miniflow_get(a, ofs) ^ b_u32[ofs]) & *p) {
+ if ((miniflow_get(a, ofs) ^ b_u32[ofs]) & *p++) {
return false;
}
- p++;
}
return true;
uint32_t storage[FLOW_U32S])
{
struct miniflow *dst = &dst_->masks;
+ uint32_t *dst_values = storage;
const struct miniflow *a = &a_->masks;
const struct miniflow *b = &b_->masks;
uint64_t map;
int n = 0;
- dst->values = storage;
+ dst->values_inline = false;
+ dst->offline_values = storage;
dst->map = 0;
for (map = a->map & b->map; map; map = zero_rightmost_1bit(map)) {
if (mask) {
dst->map |= rightmost_1bit(map);
- dst->values[n++] = mask;
+ dst_values[n++] = mask;
}
}
}
return miniflow_equal(&a->masks, &b->masks);
}
-/* Returns true if at least one bit is wildcarded in 'a_' but not in 'b_',
+/* 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_)
+minimask_has_extra(const struct minimask *a, const struct minimask *b)
{
- const struct miniflow *a = &a_->masks;
- const struct miniflow *b = &b_->masks;
+ const uint32_t *p = miniflow_get_u32_values(&b->masks);
uint64_t map;
- for (map = a->map | b->map; map; map = zero_rightmost_1bit(map)) {
- int ofs = raw_ctz(map);
- uint32_t a_u32 = miniflow_get(a, ofs);
- uint32_t b_u32 = miniflow_get(b, ofs);
+ for (map = b->masks.map; map; map = zero_rightmost_1bit(map)) {
+ uint32_t a_u32 = minimask_get(a, raw_ctz(map));
+ uint32_t b_u32 = *p++;
if ((a_u32 & b_u32) != b_u32) {
return true;
return false;
}
-
-/* Returns true if 'mask' matches every packet, false if 'mask' fixes any bits
- * or fields. */
-bool
-minimask_is_catchall(const struct minimask *mask_)
-{
- const struct miniflow *mask = &mask_->masks;
- const uint32_t *p = mask->values;
- uint64_t map;
-
- for (map = mask->map; map; map = zero_rightmost_1bit(map)) {
- if (*p++) {
- return false;
- }
- }
- return true;
-}