}
/* Caller is responsible for initializing 'dst->values' with enough storage
- * (FLOW_U64S * 8 bytes is enough). */
+ * for FLOW_U32S * 4 bytes. */
void
miniflow_extract(struct ofpbuf *packet, const struct pkt_metadata *md,
struct miniflow *dst)
wc->masks.regs[idx] = mask;
}
-/* Calculates the 5-tuple hash from the given flow. */
+/* Calculates the 5-tuple hash from the given miniflow.
+ * This returns the same value as flow_hash_5tuple for the corresponding
+ * flow. */
uint32_t
miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis)
{
- uint32_t hash = 0;
+ uint32_t hash = basis;
- if (!flow) {
- return 0;
- }
+ if (flow) {
+ ovs_be16 dl_type = MINIFLOW_GET_BE16(flow, dl_type);
+
+ hash = mhash_add(hash, MINIFLOW_GET_U8(flow, nw_proto));
- hash = mhash_add(basis,
- miniflow_get_u32(flow, offsetof(struct flow, nw_src)));
- hash = mhash_add(hash,
- miniflow_get_u32(flow, offsetof(struct flow, nw_dst)));
- hash = mhash_add(hash,
- miniflow_get_u32(flow, offsetof(struct flow, tp_src)));
- hash = mhash_add(hash,
- miniflow_get_u8(flow, offsetof(struct flow, nw_proto)));
+ /* Separate loops for better optimization. */
+ if (dl_type == htons(ETH_TYPE_IPV6)) {
+ uint64_t map = MINIFLOW_MAP(ipv6_src) | MINIFLOW_MAP(ipv6_dst)
+ | MINIFLOW_MAP(tp_src); /* Covers both ports */
+ uint32_t value;
- return mhash_finish(hash, 13);
+ MINIFLOW_FOR_EACH_IN_MAP(value, flow, map) {
+ hash = mhash_add(hash, value);
+ }
+ } else {
+ uint64_t map = MINIFLOW_MAP(nw_src) | MINIFLOW_MAP(nw_dst)
+ | MINIFLOW_MAP(tp_src); /* Covers both ports */
+ uint32_t value;
+
+ MINIFLOW_FOR_EACH_IN_MAP(value, flow, map) {
+ hash = mhash_add(hash, value);
+ }
+ }
+ hash = mhash_finish(hash, 42); /* Arbitrary number. */
+ }
+ return hash;
}
BUILD_ASSERT_DECL(offsetof(struct flow, tp_src) + 2
== offsetof(struct flow, tp_dst) &&
offsetof(struct flow, tp_src) / 4
== offsetof(struct flow, tp_dst) / 4);
+BUILD_ASSERT_DECL(offsetof(struct flow, ipv6_src) + 16
+ == offsetof(struct flow, ipv6_dst));
/* Calculates the 5-tuple hash from the given flow. */
uint32_t
flow_hash_5tuple(const struct flow *flow, uint32_t basis)
{
- const uint32_t *flow_u32 = (const uint32_t *)flow;
- uint32_t hash = 0;
+ uint32_t hash = basis;
- if (!flow) {
- return 0;
- }
+ if (flow) {
+ const uint32_t *flow_u32 = (const uint32_t *)flow;
+
+ hash = mhash_add(hash, flow->nw_proto);
- hash = mhash_add(basis, (OVS_FORCE uint32_t) flow->nw_src);
- hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
- hash = mhash_add(hash, flow_u32[offsetof(struct flow, tp_src) / 4]);
- hash = mhash_add(hash, flow->nw_proto);
+ if (flow->dl_type == htons(ETH_TYPE_IPV6)) {
+ int ofs = offsetof(struct flow, ipv6_src) / 4;
+ int end = ofs + 2 * sizeof flow->ipv6_src / 4;
- return mhash_finish(hash, 13);
+ while (ofs < end) {
+ hash = mhash_add(hash, flow_u32[ofs++]);
+ }
+ } else {
+ hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_src);
+ hash = mhash_add(hash, (OVS_FORCE uint32_t) flow->nw_dst);
+ }
+ hash = mhash_add(hash, flow_u32[offsetof(struct flow, tp_src) / 4]);
+
+ hash = mhash_finish(hash, 42); /* Arbitrary number. */
+ }
+ return hash;
}
/* Hashes 'flow' based on its L2 through L4 protocol information. */
void miniflow_expand(const struct miniflow *, struct flow *);
+#define FLOW_U32_SIZE(FIELD) \
+ DIV_ROUND_UP(sizeof(((struct flow *)0)->FIELD), sizeof(uint32_t))
+
+#define MINIFLOW_MAP(FIELD) \
+ (((UINT64_C(1) << FLOW_U32_SIZE(FIELD)) - 1) \
+ << (offsetof(struct flow, FIELD) / 4))
+
static inline uint32_t
mf_get_next_in_map(uint64_t *fmap, uint64_t rm1bit, const uint32_t **fp,
uint32_t *value)
mf_get_next_in_map(&fmap_, rm1bit_, &fp_, &(VALUE)); \
map_ -= rm1bit_, rm1bit_ = rightmost_1bit(map_))
-/* These accessors use byte offsets, which are assumed to be compile-time
- * constants. */
-static inline uint8_t miniflow_get_u8(const struct miniflow *,
- unsigned int ofs);
-static inline uint16_t miniflow_get_u16(const struct miniflow *,
- unsigned int ofs);
-static inline ovs_be16 miniflow_get_be16(const struct miniflow *,
- unsigned int ofs);
-static inline uint32_t miniflow_get_u32(const struct miniflow *,
- unsigned int ofs);
-static inline ovs_be32 miniflow_get_be32(const struct miniflow *,
- unsigned int ofs);
+/* Get the value of 'FIELD' of an up to 4 byte wide integer type 'TYPE' of
+ * a miniflow. */
+#define MINIFLOW_GET_TYPE(MF, TYPE, OFS) \
+ (((MF)->map & (UINT64_C(1) << (OFS) / 4)) \
+ ? ((OVS_FORCE const TYPE *) \
+ ((MF)->values \
+ + count_1bits((MF)->map & ((UINT64_C(1) << (OFS) / 4) - 1)))) \
+ [(OFS) % 4 / sizeof(TYPE)] \
+ : 0) \
+
+#define MINIFLOW_GET_U8(FLOW, FIELD) \
+ MINIFLOW_GET_TYPE(FLOW, uint8_t, offsetof(struct flow, FIELD))
+#define MINIFLOW_GET_U16(FLOW, FIELD) \
+ MINIFLOW_GET_TYPE(FLOW, uint16_t, offsetof(struct flow, FIELD))
+#define MINIFLOW_GET_BE16(FLOW, FIELD) \
+ MINIFLOW_GET_TYPE(FLOW, ovs_be16, offsetof(struct flow, FIELD))
+#define MINIFLOW_GET_U32(FLOW, FIELD) \
+ MINIFLOW_GET_TYPE(FLOW, uint32_t, offsetof(struct flow, FIELD))
+#define MINIFLOW_GET_BE32(FLOW, FIELD) \
+ MINIFLOW_GET_TYPE(FLOW, ovs_be32, offsetof(struct flow, FIELD))
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 *);
-static inline uint8_t miniflow_get_u8(const struct miniflow *, unsigned int ofs);
bool miniflow_equal(const struct miniflow *a, const struct miniflow *b);
bool miniflow_equal_in_minimask(const struct miniflow *a,
bool minimask_is_catchall(const struct minimask *);
\f
-/* 'OFS' is a compile-time constant. */
-#define MINIFLOW_GET_TYPE(MF, TYPE, OFS) \
- (MF->map & UINT64_C(1) << OFS / 4) \
- ? ((OVS_FORCE const TYPE *) \
- (MF->values + count_1bits(MF->map & ((UINT64_C(1) << OFS / 4) - 1)))) \
- [OFS % 4 / sizeof(TYPE)] \
- : 0
-
-static inline uint8_t
-miniflow_get_u8(const struct miniflow *flow, unsigned int ofs)
-{
- return MINIFLOW_GET_TYPE(flow, uint8_t, ofs);
-}
-
-static inline uint16_t
-miniflow_get_u16(const struct miniflow *flow, unsigned int ofs)
-{
- return MINIFLOW_GET_TYPE(flow, uint16_t, ofs);
-}
-
-/* Returns the ovs_be16 that would be at byte offset 'u8_ofs' if 'flow' were
- * expanded into a "struct flow". */
-static inline ovs_be16
-miniflow_get_be16(const struct miniflow *flow, unsigned int ofs)
-{
- return MINIFLOW_GET_TYPE(flow, ovs_be16, ofs);
-}
-
-static inline uint32_t
-miniflow_get_u32(const struct miniflow *flow, unsigned int ofs)
-{
- return MINIFLOW_GET_TYPE(flow, uint32_t, ofs);
-}
-
-static inline ovs_be32
-miniflow_get_be32(const struct miniflow *flow, unsigned int ofs)
-{
- return MINIFLOW_GET_TYPE(flow, ovs_be32, ofs);
-}
-
-#undef MINIFLOW_GET_TYPE
-
/* Returns the VID within the vlan_tci member of the "struct flow" represented
* by 'flow'. */
static inline uint16_t
miniflow_get_vid(const struct miniflow *flow)
{
- ovs_be16 tci = miniflow_get_be16(flow, offsetof(struct flow, vlan_tci));
+ ovs_be16 tci = MINIFLOW_GET_BE16(flow, vlan_tci);
return vlan_tci_to_vid(tci);
}
static inline uint16_t
miniflow_get_tcp_flags(const struct miniflow *flow)
{
- return ntohs(miniflow_get_be16(flow, offsetof(struct flow, tcp_flags)));
+ return ntohs(MINIFLOW_GET_BE16(flow, tcp_flags));
}
/* Returns the value of the OpenFlow 1.1+ "metadata" field in 'flow'. */
static inline ovs_be64
miniflow_get_metadata(const struct miniflow *flow)
{
+ union {
+ ovs_be64 be64;
+ struct {
+ ovs_be32 hi;
+ ovs_be32 lo;
+ };
+ } value;
+
enum { MD_OFS = offsetof(struct flow, metadata) };
BUILD_ASSERT_DECL(MD_OFS % sizeof(uint32_t) == 0);
- ovs_be32 hi = miniflow_get_be32(flow, MD_OFS);
- ovs_be32 lo = miniflow_get_be32(flow, MD_OFS + 4);
+ value.hi = MINIFLOW_GET_TYPE(flow, ovs_be32, MD_OFS);
+ value.lo = MINIFLOW_GET_TYPE(flow, ovs_be32, MD_OFS + 4);
- return htonll(((uint64_t) ntohl(hi) << 32) | ntohl(lo));
+ return value.be64;
}
/* Returns the mask for the OpenFlow 1.1+ "metadata" field in 'mask'.