From: Cian Ferriter <cian.ferri...@intel.com> Replaces miniflow_hash_5tuple() with miniflow_hash_ntuple() which calls the dynamically generated OVS_HASH_FIELDS macro. This macro is generated at the configure stage of OVS compilation and depends on the standard header fields in the P4 input file. As a first pass, all standard header fields defined in the P4 input file are hashed.
When testing the functionality and performance of this patch, dp_packet_rss_valid() was modified to always return false, forcing the calculation of the hash to take place in software. There is some performance degradation associated with this patch. The amount of degradation depends on the amount of header fields from the P4 file that are used for hashing. The performance comparisons were carried out between commit eb8917d on the 'p4' branch and this patch applied on top of that commit. A 16% performance degradation is seen when the Ethernet header structure is defined in the P4 input file. A 28% performance degradation is seen when the Ethernet/IPv4 header structures are defined in the P4 input file. These performance degradations are caused by the large amount of fields being hashed and the pointer manipulation necessary to hash the awkwardly sized Ethernet destination and source addresses. These problems should be alleviated by implementing a method in P4 to specify which fields should be hashed and by investigating whether a better method for hashing awkwardly sized fields can be found. Signed-off-by: Cian Ferriter <cian.ferri...@intel.com> --- lib/dpif-netdev.c | 2 +- lib/flow.c | 41 +++++------------------------------------ lib/flow.h | 6 ++++++ 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index e0107b7..7a1c8c9 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -3600,7 +3600,7 @@ dpif_netdev_packet_get_rss_hash(struct dp_packet *packet, if (OVS_LIKELY(dp_packet_rss_valid(packet))) { hash = dp_packet_get_rss_hash(packet); } else { - hash = miniflow_hash_5tuple(mf, 0); + hash = miniflow_hash_ntuple(mf, 0); dp_packet_set_rss_hash(packet, hash); } diff --git a/lib/flow.c b/lib/flow.c index 4c8ac84..46be83d 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -41,7 +41,9 @@ #include "unaligned.h" // @P4: +#include "p4/src/lib/packets.h.h" #include "p4/src/lib/flow.c.h" +#include "p4/src/lib/hash.c.h" COVERAGE_DEFINE(flow_extract); COVERAGE_DEFINE(miniflow_malloc); @@ -1611,49 +1613,16 @@ flow_wildcards_set_xreg_mask(struct flow_wildcards *wc, int idx, uint64_t mask) flow_set_xreg(&wc->masks, idx, mask); } -/* Calculates the 5-tuple hash from the given miniflow. +/* Calculates the n-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) +miniflow_hash_ntuple(const struct miniflow *flow, uint32_t basis) { BUILD_ASSERT_DECL(FLOW_WC_SEQ == 35); uint32_t hash = basis; - if (flow) { - ovs_be16 dl_type = MINIFLOW_GET_BE16(flow, dl_type); - uint8_t nw_proto; - - if (dl_type == htons(ETH_TYPE_IPV6)) { - struct flowmap map = FLOWMAP_EMPTY_INITIALIZER; - uint64_t value; - - FLOWMAP_SET(&map, ipv6_src); - FLOWMAP_SET(&map, ipv6_dst); - - MINIFLOW_FOR_EACH_IN_FLOWMAP(value, flow, map) { - hash = hash_add64(hash, value); - } - } else if (dl_type == htons(ETH_TYPE_IP) - || dl_type == htons(ETH_TYPE_ARP)) { - hash = hash_add(hash, MINIFLOW_GET_U32(flow, nw_src)); - hash = hash_add(hash, MINIFLOW_GET_U32(flow, nw_dst)); - } else { - goto out; - } - - nw_proto = MINIFLOW_GET_U8(flow, nw_proto); - hash = hash_add(hash, nw_proto); - if (nw_proto != IPPROTO_TCP && nw_proto != IPPROTO_UDP - && nw_proto != IPPROTO_SCTP && nw_proto != IPPROTO_ICMP - && nw_proto != IPPROTO_ICMPV6) { - goto out; - } - - /* Add both ports at once. */ - hash = hash_add(hash, MINIFLOW_GET_U32(flow, tp_src)); - } -out: + OVS_HASH_FIELDS return hash_finish(hash, 42); } diff --git a/lib/flow.h b/lib/flow.h index 5479677..f857997 100644 --- a/lib/flow.h +++ b/lib/flow.h @@ -617,6 +617,11 @@ miniflow_get__(const struct miniflow *mf, size_t idx) [FLOW_U64_OFFREM(FIELD) / sizeof(TYPE)] \ : 0) +#define MINIFLOW_GET_ADDRESS(MF, FIELD) \ + (MINIFLOW_IN_MAP(MF, FLOW_U64_OFFSET(FIELD)) \ + ? ((OVS_FORCE const void *)miniflow_get__(MF, FLOW_U64_OFFSET(FIELD))) \ + : 0) + #define MINIFLOW_GET_U128(FLOW, FIELD) \ (ovs_u128) { .u64 = { \ (MINIFLOW_IN_MAP(FLOW, FLOW_U64_OFFSET(FIELD)) ? \ @@ -657,6 +662,7 @@ bool miniflow_equal_flow_in_minimask(const struct miniflow *a, const struct flow *b, const struct minimask *); uint32_t miniflow_hash_5tuple(const struct miniflow *flow, uint32_t basis); +uint32_t miniflow_hash_ntuple(const struct miniflow *flow, uint32_t basis); /* Compressed flow wildcards. */ -- 2.7.4 (Apple Git-66) _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev