[ovs-dev] [PATCH 2/2] flow: P4 based hash calculation on IP and Ethernet headers

Muhammad Shahbaz mshahbaz at CS.Princeton.EDU
Mon Sep 19 11:49:26 UTC 2016


From: Cian Ferriter <cian.ferriter at 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.ferriter at 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)




More information about the dev mailing list