From 58828b08f0f8b5a2ea5b88b06f48eb1db83b0938 Mon Sep 17 00:00:00 2001
From: Ansis Atteka <aatteka@nicira.com>
Date: Tue, 8 Nov 2011 14:32:13 -0800
Subject: [PATCH] datapath: Kernel flow metadata parsing should be less
 restrictive

The function flow_metadata_from_nlattrs() is very restrictive
about the ordering and type of metadata attributes that it receives.
This patch will change flow_metadata_from_nlattrs() behavior by
ignoring attributes that it does not understand and allowing them
to be passed in arbitrary order.

Issue #8167

Signed-off-by: Ansis Atteka <aatteka@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
---
 datapath/flow.c | 40 ++++++++++++++++------------------------
 1 file changed, 16 insertions(+), 24 deletions(-)

diff --git a/datapath/flow.c b/datapath/flow.c
index 55e3494a1..152d9be74 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -1160,43 +1160,35 @@ int flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
 			       const struct nlattr *attr)
 {
 	const struct nlattr *nla;
-	u16 prev_type;
 	int rem;
 
 	*in_port = USHRT_MAX;
 	*tun_id = 0;
 	*priority = 0;
 
-	prev_type = OVS_KEY_ATTR_UNSPEC;
 	nla_for_each_nested(nla, attr, rem) {
 		int type = nla_type(nla);
 
-		if (type > OVS_KEY_ATTR_MAX || nla_len(nla) != ovs_key_lens[type])
-			return -EINVAL;
-
-		switch (TRANSITION(prev_type, type)) {
-		case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_PRIORITY):
-			*priority = nla_get_u32(nla);
-			break;
+		if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] != 0) {
+			if (nla_len(nla) != ovs_key_lens[type])
+				return -EINVAL;
 
-		case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_TUN_ID):
-		case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_TUN_ID):
-			*tun_id = nla_get_be64(nla);
-			break;
+			switch (type) {
+			case OVS_KEY_ATTR_PRIORITY:
+				*priority = nla_get_u32(nla);
+				break;
 
-		case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_IN_PORT):
-		case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_IN_PORT):
-		case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_IN_PORT):
-			if (nla_get_u32(nla) >= DP_MAX_PORTS)
-				return -EINVAL;
-			*in_port = nla_get_u32(nla);
-			break;
+			case OVS_KEY_ATTR_TUN_ID:
+				*tun_id = nla_get_be64(nla);
+				break;
 
-		default:
-			return 0;
+			case OVS_KEY_ATTR_IN_PORT:
+				if (nla_get_u32(nla) >= DP_MAX_PORTS)
+					return -EINVAL;
+				*in_port = nla_get_u32(nla);
+				break;
+			}
 		}
-
-		prev_type = type;
 	}
 	if (rem)
 		return -EINVAL;
-- 
2.47.0