From 253d1704aa0f9db3bc0bb1d7a7cbecb5bd526228 Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@nicira.com>
Date: Fri, 16 May 2008 17:00:36 -0700
Subject: [PATCH] Always do exact-match on undefined flow fields, so that such
 flows can be in table-hash.

---
 datapath/flow.c      | 42 ++++++++++++++++++++++++++++--------------
 switch/switch-flow.c |  8 ++++++++
 2 files changed, 36 insertions(+), 14 deletions(-)

diff --git a/datapath/flow.c b/datapath/flow.c
index cdda24ba2..8cf09a1b1 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -73,26 +73,40 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
 	memcpy(to->dl_dst, from->dl_dst, ETH_ALEN);
 	to->dl_type = from->dl_type;
 
-	if (likely(from->dl_type == htons(ETH_P_IP))) {
+	to->nw_src = to->nw_dst = to->nw_proto = 0;
+	to->tp_src = to->tp_dst = 0;
+
+#define OFPFW_TP (OFPFW_TP_SRC | OFPFW_TP_DST)
+#define OFPFW_NW (OFPFW_NW_SRC | OFPFW_NW_DST | OFPFW_NW_PROTO)
+	if (to->wildcards & OFPFW_DL_TYPE) {
+		/* Can't sensibly match on network or transport headers if the
+		 * data link type is unknown. */
+		to->wildcards |= OFPFW_NW | OFPFW_TP;
+	} else if (from->dl_type == htons(ETH_P_IP)) {
 		to->nw_src   = from->nw_src;
 		to->nw_dst   = from->nw_dst;
 		to->nw_proto = from->nw_proto;
 
-		if ((from->nw_proto != IPPROTO_TCP && from->nw_proto != IPPROTO_UDP)) {
-			goto no_th;
+		if (to->wildcards & OFPFW_NW_PROTO) {
+			/* Can't sensibly match on transport headers if the
+			 * network protocol is unknown. */
+			to->wildcards |= OFPFW_TP;
+		} else if (from->nw_proto == IPPROTO_TCP
+			   || from->nw_proto == IPPROTO_UDP) {
+			to->tp_src = from->tp_src;
+			to->tp_dst = from->tp_dst;
+		} else {
+			/* Transport layer fields are undefined.  Mark them as
+			 * exact-match to allow such flows to reside in
+			 * table-hash, instead of falling into table-linear. */
+			to->wildcards &= ~OFPFW_TP;
 		}
-		to->tp_src = from->tp_src;
-		to->tp_dst = from->tp_dst;
-		return;
+	} else {
+		/* Network and transport layer fields are undefined.  Mark them
+		 * as exact-match to allow such flows to reside in table-hash,
+		 * instead of falling into table-linear. */
+		to->wildcards &= ~(OFPFW_NW | OFPFW_TP);
 	}
-
-	to->nw_src = 0;
-	to->nw_dst = 0;
-	to->nw_proto = 0;
-
-no_th:
-	to->tp_src = 0;
-	to->tp_dst = 0;
 }
 
 void flow_fill_match(struct ofp_match* to, const struct sw_flow_key* from)
diff --git a/switch/switch-flow.c b/switch/switch-flow.c
index 39df8622a..4e5d25783 100644
--- a/switch/switch-flow.c
+++ b/switch/switch-flow.c
@@ -102,11 +102,19 @@ void flow_extract_match(struct sw_flow_key* to, const struct ofp_match* from)
         return;
     }
 
+    /* dl_type is not IPv4, so the network layer fields are undefined.  We set
+     * them to zero and mark them as exact-match to allow such flows to reside
+     * in table-hash, instead of falling into table-linear. */
+    to->wildcards &= ~(OFPFW_NW_SRC | OFPFW_NW_DST | OFPFW_NW_PROTO);
     to->flow.nw_src = 0;
     to->flow.nw_dst = 0;
     to->flow.nw_proto = 0;
 
 no_th:
+    /* nw_proto is not TCP or UDP, so the transport layer fields are undefined.
+     * We set them to zero and mark them as exact-match to allow such flows to
+     * reside in table-hash, instead of falling into table-linear. */
+    to->wildcards &= ~(OFPFW_TP_SRC | OFPFW_TP_DST);
     to->flow.tp_src = 0;
     to->flow.tp_dst = 0;
 }
-- 
2.47.0