[ovs-dev] [PATCH 03/11] datapath: Fold key_len and hash into sw_flow_key.

Jarno Rajahalme jarno.rajahalme at nsn.com
Mon Feb 11 14:46:19 UTC 2013


Store key_len and hash fields at the end of struct sw_flow_key, past the
area being hashed.
Rename functions operating on keys from "_flow_" to "_flow_key_".
Shift the responsibility for key hashing from lookup and insert to key
construction side, which helps avaiding unnecessary hash computations.

Signed-off-by: Jarno Rajahalme <jarno.rajahalme at nsn.com>
---
 datapath/datapath.c    |   42 ++++++------
 datapath/flow.c        |  165 ++++++++++++++++++++++++------------------------
 datapath/flow.h        |   24 ++++---
 datapath/vport-vxlan.c |    2 +-
 4 files changed, 118 insertions(+), 115 deletions(-)

diff --git a/datapath/datapath.c b/datapath/datapath.c
index 87c96ae..2e01740 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -209,18 +209,16 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 
 	if (!OVS_CB(skb)->flow) {
 		struct sw_flow_key key;
-		int key_len;
 
 		/* Extract flow from 'skb' into 'key'. */
-		error = ovs_flow_extract(skb, p->port_no, &key, &key_len);
+		error = ovs_flow_key_extract(skb, p->port_no, &key);
 		if (unlikely(error)) {
 			kfree_skb(skb);
 			return;
 		}
 
 		/* Look up flow. */
-		flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table),
-					   &key, key_len);
+		flow = ovs_flow_tbl_lookup(rcu_dereference(dp->table), &key);
 		if (unlikely(!flow)) {
 			struct dp_upcall_info upcall;
 
@@ -318,12 +316,14 @@ static int queue_gso_packets(struct net *net, int dp_ifindex,
 			break;
 
 		if (skb == segs && gso_type & SKB_GSO_UDP) {
-			/* The initial flow key extracted by ovs_flow_extract()
-			 * in this case is for a first fragment, so we need to
-			 * properly mark later fragments.
+			/* The initial flow key extracted by
+			 * ovs_flow_key_extract() in this case is for a first
+			 * fragment, so we need to properly mark later
+			 * fragments.
 			 */
 			later_key = *upcall_info->key;
 			later_key.ip.frag = OVS_FRAG_TYPE_LATER;
+			ovs_flow_key_hash_set(&later_key); /* Update hash */
 
 			later_info = *upcall_info;
 			later_info.key = &later_key;
@@ -358,7 +358,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
 		nskb = skb_clone(skb, GFP_ATOMIC);
 		if (!nskb)
 			return -ENOMEM;
-		
+
 		err = vlan_deaccel_tag(nskb);
 		if (err)
 			return err;
@@ -388,7 +388,7 @@ static int queue_userspace_packet(struct net *net, int dp_ifindex,
 	upcall->dp_ifindex = dp_ifindex;
 
 	nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_KEY);
-	ovs_flow_to_nlattrs(upcall_info->key, user_skb);
+	ovs_flow_key_to_nlattrs(upcall_info->key, user_skb);
 	nla_nest_end(user_skb, nla);
 
 	if (upcall_info->userdata)
@@ -815,7 +815,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	struct ethhdr *eth;
 	int len;
 	int err;
-	int key_len;
 
 	err = -EINVAL;
 	if (!a[OVS_PACKET_ATTR_PACKET] || !a[OVS_PACKET_ATTR_KEY] ||
@@ -849,11 +848,11 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
 	if (IS_ERR(flow))
 		goto err_kfree_skb;
 
-	err = ovs_flow_extract(packet, -1, &flow->key, &key_len);
+	err = ovs_flow_key_extract(packet, -1, &flow->key);
 	if (err)
 		goto err_flow_free;
 
-	err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]);
+	err = ovs_flow_key_metadata_from_nlattrs(&flow->key, a[OVS_PACKET_ATTR_KEY]);
 	if (err)
 		goto err_flow_free;
 	acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS]));
@@ -1073,7 +1072,7 @@ static int ovs_flow_cmd_fill_info(struct sw_flow *flow, struct datapath *dp,
 	nla = nla_nest_start(skb, OVS_FLOW_ATTR_KEY);
 	if (!nla)
 		goto nla_put_failure;
-	err = ovs_flow_to_nlattrs(&flow->key, skb);
+	err = ovs_flow_key_to_nlattrs(&flow->key, skb);
 	if (err)
 		goto error;
 	nla_nest_end(skb, nla);
@@ -1182,13 +1181,12 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 	struct flow_table *table;
 	struct sw_flow_actions *acts = NULL;
 	int error;
-	int key_len;
 
 	/* Extract key. */
 	error = -EINVAL;
 	if (!a[OVS_FLOW_ATTR_KEY])
 		goto error;
-	error = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	error = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]);
 	if (error)
 		goto error;
 
@@ -1213,7 +1211,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 		goto err_kfree;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &key);
 	if (!flow) {
 		/* Bail out if we're not allowed to create a new flow. */
 		error = -ENOENT;
@@ -1243,7 +1241,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info)
 		rcu_assign_pointer(flow->sf_acts, acts);
 
 		/* Put flow in bucket. */
-		ovs_flow_tbl_insert(table, flow, &key, key_len);
+		ovs_flow_tbl_insert(table, flow, &key);
 
 		reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid,
 						info->snd_seq,
@@ -1305,11 +1303,10 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 	struct datapath *dp;
 	struct flow_table *table;
 	int err;
-	int key_len;
 
 	if (!a[OVS_FLOW_ATTR_KEY])
 		return -EINVAL;
-	err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	err = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]);
 	if (err)
 		return err;
 
@@ -1318,7 +1315,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info)
 		return -ENODEV;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &key);
 	if (!flow)
 		return -ENOENT;
 
@@ -1340,7 +1337,6 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	struct datapath *dp;
 	struct flow_table *table;
 	int err;
-	int key_len;
 
 	dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
 	if (!dp)
@@ -1349,12 +1345,12 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info)
 	if (!a[OVS_FLOW_ATTR_KEY])
 		return flush_flows(dp);
 
-	err = ovs_flow_from_nlattrs(&key, &key_len, a[OVS_FLOW_ATTR_KEY]);
+	err = ovs_flow_key_from_nlattrs(&key, a[OVS_FLOW_ATTR_KEY]);
 	if (err)
 		return err;
 
 	table = genl_dereference(dp->table);
-	flow = ovs_flow_tbl_lookup(table, &key, key_len);
+	flow = ovs_flow_tbl_lookup(table, &key);
 	if (!flow)
 		return -ENOENT;
 
diff --git a/datapath/flow.c b/datapath/flow.c
index fad9e19..4c85e81 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -126,8 +126,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies)
 	(offsetof(struct sw_flow_key, field) +	\
 	 FIELD_SIZEOF(struct sw_flow_key, field))
 
-static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
-			 int *key_lenp)
+static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key)
 {
 	unsigned int nh_ofs = skb_network_offset(skb);
 	unsigned int nh_len;
@@ -137,7 +136,7 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key,
 	__be16 frag_off;
 	int err;
 
-	*key_lenp = SW_FLOW_KEY_OFFSET(ipv6.label);
+	key->key_len = SW_FLOW_KEY_OFFSET(ipv6.label);
 
 	err = check_header(skb, nh_ofs + sizeof(*nh));
 	if (unlikely(err))
@@ -351,14 +350,13 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la
 		(*bucket)++;
 		*last = 0;
 	}
-
 	return NULL;
 }
 
 static void __flow_tbl_insert(struct flow_table *table, struct sw_flow *flow)
 {
 	struct hlist_head *head;
-	head = find_bucket(table, flow->hash);
+	head = find_bucket(table, flow->key.hash);
 	hlist_add_head_rcu(&flow->hash_node[table->node_ver], head);
 	table->count++;
 }
@@ -504,18 +502,17 @@ static __be16 parse_ethertype(struct sk_buff *skb)
 }
 
 static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
-			int *key_lenp, int nh_len)
+			int nh_len)
 {
 	struct icmp6hdr *icmp = icmp6_hdr(skb);
 	int error = 0;
-	int key_len;
 
 	/* The ICMPv6 type and code fields use the 16-bit transport port
 	 * fields, so we need to store them in 16-bit network byte order.
 	 */
 	key->ipv6.tp.src = htons(icmp->icmp6_type);
 	key->ipv6.tp.dst = htons(icmp->icmp6_code);
-	key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+	key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 
 	if (icmp->icmp6_code == 0 &&
 	    (icmp->icmp6_type == NDISC_NEIGHBOUR_SOLICITATION ||
@@ -524,7 +521,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
 		struct nd_msg *nd;
 		int offset;
 
-		key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
+		key->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
 
 		/* In order to process neighbor discovery options, we need the
 		 * entire packet.
@@ -538,7 +535,7 @@ static int parse_icmpv6(struct sk_buff *skb, struct sw_flow_key *key,
 
 		nd = (struct nd_msg *)skb_transport_header(skb);
 		key->ipv6.nd.target = nd->target;
-		key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
+		key->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
 
 		icmp_len -= sizeof(*nd);
 		offset = 0;
@@ -581,22 +578,24 @@ invalid:
 	memset(key->ipv6.nd.tll, 0, sizeof(key->ipv6.nd.tll));
 
 out:
-	*key_lenp = key_len;
 	return error;
 }
 
 /**
- * ovs_flow_extract - extracts a flow key from an Ethernet frame.
+ * ovs_flow_key_extract - extracts a flow key from an Ethernet frame.
  * @skb: sk_buff that contains the frame, with skb->data pointing to the
  * Ethernet header
  * @in_port: port number on which @skb was received.
  * @key: output flow key
- * @key_lenp: length of output flow key
  *
  * The caller must ensure that skb->len >= ETH_HLEN.
  *
  * Returns 0 if successful, otherwise a negative errno value.
  *
+ * Initializes @key metadata fields and hash value only if @in_port != -1.
+ * If @in_port is -1 ovs_flow_key_metadata_from_nlattrs() must be called
+ * after this to initialize the metadata and hash fields.
+ *
  * Initializes @skb header pointers as follows:
  *
  *    - skb->mac_header: the Ethernet header.
@@ -609,20 +608,14 @@ out:
  *      of a correct length, otherwise the same as skb->network_header.
  *      For other key->dl_type values it is left untouched.
  */
-int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
-		 int *key_lenp)
+int ovs_flow_key_extract(struct sk_buff *skb, u16 in_port,
+			 struct sw_flow_key *key)
 {
 	int error = 0;
-	int key_len = SW_FLOW_KEY_OFFSET(eth);
 	struct ethhdr *eth;
 
 	memset(key, 0, sizeof(*key));
-
-	key->phy.priority = skb->priority;
-	if (OVS_CB(skb)->tun_key)
-		memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
-	key->phy.in_port = in_port;
-	key->phy.skb_mark = skb_get_mark(skb);
+	key->key_len = SW_FLOW_KEY_OFFSET(eth);
 
 	skb_reset_mac_header(skb);
 
@@ -653,7 +646,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 		struct iphdr *nh;
 		__be16 offset;
 
-		key_len = SW_FLOW_KEY_OFFSET(ipv4.addr);
+		key->key_len = SW_FLOW_KEY_OFFSET(ipv4.addr);
 
 		error = check_iphdr(skb);
 		if (unlikely(error)) {
@@ -683,21 +676,21 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 
 		/* Transport layer. */
 		if (key->ip.proto == IPPROTO_TCP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 			if (tcphdr_ok(skb)) {
 				struct tcphdr *tcp = tcp_hdr(skb);
 				key->ipv4.tp.src = tcp->source;
 				key->ipv4.tp.dst = tcp->dest;
 			}
 		} else if (key->ip.proto == IPPROTO_UDP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 			if (udphdr_ok(skb)) {
 				struct udphdr *udp = udp_hdr(skb);
 				key->ipv4.tp.src = udp->source;
 				key->ipv4.tp.dst = udp->dest;
 			}
 		} else if (key->ip.proto == IPPROTO_ICMP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 			if (icmphdr_ok(skb)) {
 				struct icmphdr *icmp = icmp_hdr(skb);
 				/* The ICMP type and code fields use the 16-bit
@@ -726,12 +719,12 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 			memcpy(&key->ipv4.addr.dst, arp->ar_tip, sizeof(key->ipv4.addr.dst));
 			memcpy(key->ipv4.arp.sha, arp->ar_sha, ETH_ALEN);
 			memcpy(key->ipv4.arp.tha, arp->ar_tha, ETH_ALEN);
-			key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
 		}
 	} else if (key->eth.type == htons(ETH_P_IPV6)) {
 		int nh_len;             /* IPv6 Header + Extensions */
 
-		nh_len = parse_ipv6hdr(skb, key, &key_len);
+		nh_len = parse_ipv6hdr(skb, key);
 		if (unlikely(nh_len < 0)) {
 			if (nh_len == -EINVAL)
 				skb->transport_header = skb->network_header;
@@ -747,23 +740,23 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 
 		/* Transport layer. */
 		if (key->ip.proto == NEXTHDR_TCP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 			if (tcphdr_ok(skb)) {
 				struct tcphdr *tcp = tcp_hdr(skb);
 				key->ipv6.tp.src = tcp->source;
 				key->ipv6.tp.dst = tcp->dest;
 			}
 		} else if (key->ip.proto == NEXTHDR_UDP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 			if (udphdr_ok(skb)) {
 				struct udphdr *udp = udp_hdr(skb);
 				key->ipv6.tp.src = udp->source;
 				key->ipv6.tp.dst = udp->dest;
 			}
 		} else if (key->ip.proto == NEXTHDR_ICMP) {
-			key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+			key->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 			if (icmp6hdr_ok(skb)) {
-				error = parse_icmpv6(skb, key, &key_len, nh_len);
+				error = parse_icmpv6(skb, key, nh_len);
 				if (error < 0)
 					goto out;
 			}
@@ -771,14 +764,24 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port, struct sw_flow_key *key,
 	}
 
 out:
-	*key_lenp = key_len;
+	if (in_port != -1 && !error) {
+		key->phy.priority = skb->priority;
+		if (OVS_CB(skb)->tun_key)
+			memcpy(&key->tun_key, OVS_CB(skb)->tun_key,
+			       sizeof(key->tun_key));
+		key->phy.in_port = in_port;
+		key->phy.skb_mark = skb_get_mark(skb);
+
+		ovs_flow_key_hash_set(key);
+	}
+
 	return error;
 }
 
-static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len)
+static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start)
 {
 	return jhash2((u32 *)((u8 *)key + key_start),
-		      DIV_ROUND_UP(key_len - key_start, sizeof(u32)), 0);
+		      DIV_ROUND_UP(key->key_len - key_start, sizeof(u32)), 0);
 }
 
 static int flow_key_start(struct sw_flow_key *key)
@@ -789,35 +792,38 @@ static int flow_key_start(struct sw_flow_key *key)
 		return offsetof(struct sw_flow_key, phy);
 }
 
+void ovs_flow_key_hash_set(struct sw_flow_key *key)
+{
+	key->hash = ovs_flow_hash(key, flow_key_start(key));
+}
+
 struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
-				struct sw_flow_key *key, int key_len)
+				    struct sw_flow_key *key)
 {
 	struct sw_flow *flow;
 	struct hlist_node *n;
 	struct hlist_head *head;
 	u8 *_key;
 	int key_start;
-	u32 hash;
 
 	key_start = flow_key_start(key);
-	hash = ovs_flow_hash(key, key_start, key_len);
 
 	_key = (u8 *) key + key_start;
-	head = find_bucket(table, hash);
+	head = find_bucket(table, key->hash);
 	hlist_for_each_entry_rcu(flow, n, head, hash_node[table->node_ver]) {
 
-		if (flow->hash == hash &&
-		    !memcmp((u8 *)&flow->key + key_start, _key, key_len - key_start)) {
+		if (flow->key.hash == key->hash &&
+		    !memcmp((u8 *)&flow->key + key_start, _key, key->key_len - key_start)) {
 			return flow;
 		}
 	}
+
 	return NULL;
 }
 
 void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
-			 struct sw_flow_key *key, int key_len)
+			 struct sw_flow_key *key)
 {
-	flow->hash = ovs_flow_hash(key, flow_key_start(key), key_len);
 	memcpy(&flow->key, key, sizeof(flow->key));
 	__flow_tbl_insert(table, flow);
 }
@@ -852,7 +858,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
 	[OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
 };
 
-static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
+static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey,
 				  const struct nlattr *a[], u64 *attrs)
 {
 	const struct ovs_key_icmp *icmp_key;
@@ -865,7 +871,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_TCP);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 		tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
 		swkey->ipv4.tp.src = tcp_key->tcp_src;
 		swkey->ipv4.tp.dst = tcp_key->tcp_dst;
@@ -876,7 +882,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_UDP);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 		udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
 		swkey->ipv4.tp.src = udp_key->udp_src;
 		swkey->ipv4.tp.dst = udp_key->udp_dst;
@@ -887,7 +893,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_ICMP);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.tp);
 		icmp_key = nla_data(a[OVS_KEY_ATTR_ICMP]);
 		swkey->ipv4.tp.src = htons(icmp_key->icmp_type);
 		swkey->ipv4.tp.dst = htons(icmp_key->icmp_code);
@@ -897,7 +903,7 @@ static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 	return 0;
 }
 
-static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
+static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey,
 				  const struct nlattr *a[], u64 *attrs)
 {
 	const struct ovs_key_icmpv6 *icmpv6_key;
@@ -910,7 +916,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_TCP);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 		tcp_key = nla_data(a[OVS_KEY_ATTR_TCP]);
 		swkey->ipv6.tp.src = tcp_key->tcp_src;
 		swkey->ipv6.tp.dst = tcp_key->tcp_dst;
@@ -921,7 +927,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_UDP);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 		udp_key = nla_data(a[OVS_KEY_ATTR_UDP]);
 		swkey->ipv6.tp.src = udp_key->udp_src;
 		swkey->ipv6.tp.dst = udp_key->udp_dst;
@@ -932,7 +938,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 			return -EINVAL;
 		*attrs &= ~(1 << OVS_KEY_ATTR_ICMPV6);
 
-		*key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.tp);
 		icmpv6_key = nla_data(a[OVS_KEY_ATTR_ICMPV6]);
 		swkey->ipv6.tp.src = htons(icmpv6_key->icmpv6_type);
 		swkey->ipv6.tp.dst = htons(icmpv6_key->icmpv6_code);
@@ -945,7 +951,7 @@ static int ipv6_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
 				return -EINVAL;
 			*attrs &= ~(1 << OVS_KEY_ATTR_ND);
 
-			*key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
+			swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.nd);
 			nd_key = nla_data(a[OVS_KEY_ATTR_ND]);
 			memcpy(&swkey->ipv6.nd.target, nd_key->nd_target,
 			       sizeof(swkey->ipv6.nd.target));
@@ -1087,23 +1093,21 @@ int ipv4_tun_to_nlattr(struct sk_buff *skb,
 }
 
 /**
- * ovs_flow_from_nlattrs - parses Netlink attributes into a flow key.
+ * ovs_flow_key_from_nlattrs - parses Netlink attributes into a flow key.
  * @swkey: receives the extracted flow key.
- * @key_lenp: number of bytes used in @swkey.
  * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
  * sequence.
  */
-int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
-		      const struct nlattr *attr)
+int ovs_flow_key_from_nlattrs(struct sw_flow_key *swkey,
+			      const struct nlattr *attr)
 {
 	const struct nlattr *a[OVS_KEY_ATTR_MAX + 1];
 	const struct ovs_key_ethernet *eth_key;
-	int key_len;
 	u64 attrs;
 	int err;
 
 	memset(swkey, 0, sizeof(struct sw_flow_key));
-	key_len = SW_FLOW_KEY_OFFSET(eth);
+	swkey->key_len = SW_FLOW_KEY_OFFSET(eth);
 
 	err = parse_flow_nlattrs(attr, a, &attrs);
 	if (err)
@@ -1192,7 +1196,6 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 				return -EINVAL;
 
 			swkey->eth.type = htons(ETH_P_8021Q);
-			*key_lenp = key_len;
 			return 0;
 		} else {
 			return -EINVAL;
@@ -1215,7 +1218,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 			return -EINVAL;
 		attrs &= ~(1 << OVS_KEY_ATTR_IPV4);
 
-		key_len = SW_FLOW_KEY_OFFSET(ipv4.addr);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.addr);
 		ipv4_key = nla_data(a[OVS_KEY_ATTR_IPV4]);
 		if (ipv4_key->ipv4_frag > OVS_FRAG_TYPE_MAX)
 			return -EINVAL;
@@ -1227,7 +1230,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 		swkey->ipv4.addr.dst = ipv4_key->ipv4_dst;
 
 		if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
-			err = ipv4_flow_from_nlattrs(swkey, &key_len, a, &attrs);
+			err = ipv4_flow_from_nlattrs(swkey, a, &attrs);
 			if (err)
 				return err;
 		}
@@ -1238,7 +1241,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 			return -EINVAL;
 		attrs &= ~(1 << OVS_KEY_ATTR_IPV6);
 
-		key_len = SW_FLOW_KEY_OFFSET(ipv6.label);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv6.label);
 		ipv6_key = nla_data(a[OVS_KEY_ATTR_IPV6]);
 		if (ipv6_key->ipv6_frag > OVS_FRAG_TYPE_MAX)
 			return -EINVAL;
@@ -1253,7 +1256,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 		       sizeof(swkey->ipv6.addr.dst));
 
 		if (swkey->ip.frag != OVS_FRAG_TYPE_LATER) {
-			err = ipv6_flow_from_nlattrs(swkey, &key_len, a, &attrs);
+			err = ipv6_flow_from_nlattrs(swkey, a, &attrs);
 			if (err)
 				return err;
 		}
@@ -1265,7 +1268,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 			return -EINVAL;
 		attrs &= ~(1 << OVS_KEY_ATTR_ARP);
 
-		key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
+		swkey->key_len = SW_FLOW_KEY_OFFSET(ipv4.arp);
 		arp_key = nla_data(a[OVS_KEY_ATTR_ARP]);
 		swkey->ipv4.addr.src = arp_key->arp_sip;
 		swkey->ipv4.addr.dst = arp_key->arp_tip;
@@ -1278,16 +1281,17 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
 
 	if (attrs)
 		return -EINVAL;
-	*key_lenp = key_len;
+
+	swkey->hash = ovs_flow_hash(swkey, flow_key_start(swkey));
 
 	return 0;
 }
 
 /**
- * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key.
- * @in_port: receives the extracted input port.
- * @tun_id: receives the extracted tunnel ID.
- * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
+ * ovs_flow_key_metadata_from_nlattrs - parses Netlink attributes into a flow
+ * key.
+ * @sw_flow_key: receives the extracted metadata.
+ * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute
  * sequence.
  *
  * This parses a series of Netlink attributes that form a flow key, which must
@@ -1296,17 +1300,17 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
  * extracted from the packet itself.
  */
 
-int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr)
+int ovs_flow_key_metadata_from_nlattrs(struct sw_flow_key *swkey, const struct nlattr *attr)
 {
-	struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key;
+	struct ovs_key_ipv4_tunnel *tun_key = &swkey->tun_key;
 	const struct nlattr *nla;
 	int rem;
 	__be64 tun_id = 0;
 
-	flow->key.phy.in_port = DP_MAX_PORTS;
-	flow->key.phy.priority = 0;
-	flow->key.phy.skb_mark = 0;
-	memset(tun_key, 0, sizeof(flow->key.tun_key));
+	swkey->phy.in_port = DP_MAX_PORTS;
+	swkey->phy.priority = 0;
+	swkey->phy.skb_mark = 0;
+	memset(tun_key, 0, sizeof(swkey->tun_key));
 
 	nla_for_each_nested(nla, attr, rem) {
 		int type = nla_type(nla);
@@ -1319,7 +1323,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
 
 			switch (type) {
 			case OVS_KEY_ATTR_PRIORITY:
-				flow->key.phy.priority = nla_get_u32(nla);
+				swkey->phy.priority = nla_get_u32(nla);
 				break;
 
 			case OVS_KEY_ATTR_TUN_ID:
@@ -1359,7 +1363,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
 			case OVS_KEY_ATTR_IN_PORT:
 				if (nla_get_u32(nla) >= DP_MAX_PORTS)
 					return -EINVAL;
-				flow->key.phy.in_port = nla_get_u32(nla);
+				swkey->phy.in_port = nla_get_u32(nla);
 				break;
 
 			case OVS_KEY_ATTR_SKB_MARK:
@@ -1367,7 +1371,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
 				if (nla_get_u32(nla) != 0)
 					return -EINVAL;
 #endif
-				flow->key.phy.skb_mark = nla_get_u32(nla);
+				swkey->phy.skb_mark = nla_get_u32(nla);
 				break;
 			}
 		}
@@ -1375,13 +1379,12 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const stru
 	if (rem)
 		return -EINVAL;
 
-	flow->hash = ovs_flow_hash(&flow->key,
-				   flow_key_start(&flow->key), key_len);
+	swkey->hash = ovs_flow_hash(swkey, flow_key_start(swkey));
 
 	return 0;
 }
 
-int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
+int ovs_flow_key_to_nlattrs(const struct sw_flow_key *swkey, struct sk_buff *skb)
 {
 	struct ovs_key_ethernet *eth_key;
 	struct nlattr *nla, *encap;
diff --git a/datapath/flow.h b/datapath/flow.h
index 6949640..dc9c000 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -112,12 +112,15 @@ struct sw_flow_key {
 			} nd;
 		} ipv6;
 	};
+
+	/* Following fields are never included in key hash */
+	int key_len;
+	u32 hash;	/* Valid if key_len != 0 */
 };
 
 struct sw_flow {
 	struct rcu_head rcu;
 	struct hlist_node hash_node[2];
-	u32 hash;
 
 	struct sw_flow_key key;
 	struct sw_flow_actions __rcu *sf_acts;
@@ -143,6 +146,9 @@ struct arp_eth_header {
 	unsigned char       ar_tip[4];		/* target IP address        */
 } __packed;
 
+int ovs_flow_key_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *);
+void ovs_flow_key_hash_set(struct sw_flow_key *key);
+
 int ovs_flow_init(void);
 void ovs_flow_exit(void);
 
@@ -153,8 +159,6 @@ void ovs_flow_free(struct sw_flow *);
 struct sw_flow_actions *ovs_flow_actions_alloc(int actions_len);
 void ovs_flow_deferred_free_acts(struct sw_flow_actions *);
 
-int ovs_flow_extract(struct sk_buff *, u16 in_port, struct sw_flow_key *,
-		     int *key_lenp);
 void ovs_flow_used(struct sw_flow *, struct sk_buff *);
 u64 ovs_flow_used_time(unsigned long flow_jiffies);
 
@@ -188,11 +192,11 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
  */
 #define FLOW_BUFSIZE 220
 
-int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
-int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
-		      const struct nlattr *);
-int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len,
-				   const struct nlattr *attr);
+int ovs_flow_key_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
+int ovs_flow_key_from_nlattrs(struct sw_flow_key *,
+			      const struct nlattr *);
+int ovs_flow_key_metadata_from_nlattrs(struct sw_flow_key *,
+				       const struct nlattr *);
 
 #define MAX_ACTIONS_BUFSIZE	(16 * 1024)
 #define TBL_MIN_BUCKETS		1024
@@ -217,14 +221,14 @@ static inline int ovs_flow_tbl_need_to_expand(struct flow_table *table)
 }
 
 struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
-				    struct sw_flow_key *key, int len);
+				    struct sw_flow_key *key);
 void ovs_flow_tbl_destroy(struct flow_table *table);
 void ovs_flow_tbl_deferred_destroy(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_alloc(int new_size);
 struct flow_table *ovs_flow_tbl_expand(struct flow_table *table);
 struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table);
 void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
-			 struct sw_flow_key *key, int key_len);
+			 struct sw_flow_key *key);
 void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
 
 struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx);
diff --git a/datapath/vport-vxlan.c b/datapath/vport-vxlan.c
index 413452e..6e5141f 100644
--- a/datapath/vport-vxlan.c
+++ b/datapath/vport-vxlan.c
@@ -98,7 +98,7 @@ static u16 get_src_port(struct sk_buff *skb)
 	int low;
 	int high;
 	unsigned int range;
-	u32 hash = OVS_CB(skb)->flow->hash;
+	u32 hash = OVS_CB(skb)->flow->key.hash;
 
         inet_get_local_port_range(&low, &high);
         range = (high - low) + 1;
-- 
1.7.10.4




More information about the dev mailing list