diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-06-17 20:50:28 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-19 21:07:41 -0400 |
commit | a3e82996a8874c4cfe8c7f1be4d552018d8cba7e (patch) | |
tree | f476c0df25d3076a67594bc15e0cd5190ce18351 /net | |
parent | ffe3f4321745e743dd179ec2b12180c01ba0d3aa (diff) |
openvswitch: Optimize flow key match for non tunnel flows.
Following patch adds start offset for sw_flow-key, so that we can
skip tunneling information in key for non-tunnel flows.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Acked-by: Jesse Gross <jesse@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/openvswitch/datapath.c | 7 | ||||
-rw-r--r-- | net/openvswitch/flow.c | 49 | ||||
-rw-r--r-- | net/openvswitch/flow.h | 6 |
3 files changed, 42 insertions, 20 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index bbd310646bc8..f7e3a0d84c40 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -894,10 +894,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) | |||
894 | if (err) | 894 | if (err) |
895 | goto err_flow_free; | 895 | goto err_flow_free; |
896 | 896 | ||
897 | err = ovs_flow_metadata_from_nlattrs(flow, a[OVS_PACKET_ATTR_KEY]); | 897 | err = ovs_flow_metadata_from_nlattrs(flow, key_len, a[OVS_PACKET_ATTR_KEY]); |
898 | if (err) | 898 | if (err) |
899 | goto err_flow_free; | 899 | goto err_flow_free; |
900 | flow->hash = ovs_flow_hash(&flow->key, key_len); | ||
901 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); | 900 | acts = ovs_flow_actions_alloc(nla_len(a[OVS_PACKET_ATTR_ACTIONS])); |
902 | err = PTR_ERR(acts); | 901 | err = PTR_ERR(acts); |
903 | if (IS_ERR(acts)) | 902 | if (IS_ERR(acts)) |
@@ -1276,14 +1275,12 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
1276 | error = PTR_ERR(flow); | 1275 | error = PTR_ERR(flow); |
1277 | goto err_unlock_ovs; | 1276 | goto err_unlock_ovs; |
1278 | } | 1277 | } |
1279 | flow->key = key; | ||
1280 | clear_stats(flow); | 1278 | clear_stats(flow); |
1281 | 1279 | ||
1282 | rcu_assign_pointer(flow->sf_acts, acts); | 1280 | rcu_assign_pointer(flow->sf_acts, acts); |
1283 | 1281 | ||
1284 | /* Put flow in bucket. */ | 1282 | /* Put flow in bucket. */ |
1285 | flow->hash = ovs_flow_hash(&key, key_len); | 1283 | ovs_flow_tbl_insert(table, flow, &key, key_len); |
1286 | ovs_flow_tbl_insert(table, flow); | ||
1287 | 1284 | ||
1288 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, | 1285 | reply = ovs_flow_cmd_build_info(flow, dp, info->snd_portid, |
1289 | info->snd_seq, | 1286 | info->snd_seq, |
diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 976a8b766a6a..5c519b121e1b 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c | |||
@@ -353,6 +353,14 @@ struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *la | |||
353 | return NULL; | 353 | return NULL; |
354 | } | 354 | } |
355 | 355 | ||
356 | static void __flow_tbl_insert(struct flow_table *table, struct sw_flow *flow) | ||
357 | { | ||
358 | struct hlist_head *head; | ||
359 | head = find_bucket(table, flow->hash); | ||
360 | hlist_add_head_rcu(&flow->hash_node[table->node_ver], head); | ||
361 | table->count++; | ||
362 | } | ||
363 | |||
356 | static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new) | 364 | static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new) |
357 | { | 365 | { |
358 | int old_ver; | 366 | int old_ver; |
@@ -369,7 +377,7 @@ static void flow_table_copy_flows(struct flow_table *old, struct flow_table *new | |||
369 | head = flex_array_get(old->buckets, i); | 377 | head = flex_array_get(old->buckets, i); |
370 | 378 | ||
371 | hlist_for_each_entry(flow, head, hash_node[old_ver]) | 379 | hlist_for_each_entry(flow, head, hash_node[old_ver]) |
372 | ovs_flow_tbl_insert(new, flow); | 380 | __flow_tbl_insert(new, flow); |
373 | } | 381 | } |
374 | old->keep_flows = true; | 382 | old->keep_flows = true; |
375 | } | 383 | } |
@@ -763,9 +771,18 @@ out: | |||
763 | return error; | 771 | return error; |
764 | } | 772 | } |
765 | 773 | ||
766 | u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len) | 774 | static u32 ovs_flow_hash(const struct sw_flow_key *key, int key_start, int key_len) |
775 | { | ||
776 | return jhash2((u32 *)((u8 *)key + key_start), | ||
777 | DIV_ROUND_UP(key_len - key_start, sizeof(u32)), 0); | ||
778 | } | ||
779 | |||
780 | static int flow_key_start(struct sw_flow_key *key) | ||
767 | { | 781 | { |
768 | return jhash2((u32 *)key, DIV_ROUND_UP(key_len, sizeof(u32)), 0); | 782 | if (key->tun_key.ipv4_dst) |
783 | return 0; | ||
784 | else | ||
785 | return offsetof(struct sw_flow_key, phy); | ||
769 | } | 786 | } |
770 | 787 | ||
771 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, | 788 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, |
@@ -773,28 +790,31 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table, | |||
773 | { | 790 | { |
774 | struct sw_flow *flow; | 791 | struct sw_flow *flow; |
775 | struct hlist_head *head; | 792 | struct hlist_head *head; |
793 | u8 *_key; | ||
794 | int key_start; | ||
776 | u32 hash; | 795 | u32 hash; |
777 | 796 | ||
778 | hash = ovs_flow_hash(key, key_len); | 797 | key_start = flow_key_start(key); |
798 | hash = ovs_flow_hash(key, key_start, key_len); | ||
779 | 799 | ||
800 | _key = (u8 *) key + key_start; | ||
780 | head = find_bucket(table, hash); | 801 | head = find_bucket(table, hash); |
781 | hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) { | 802 | hlist_for_each_entry_rcu(flow, head, hash_node[table->node_ver]) { |
782 | 803 | ||
783 | if (flow->hash == hash && | 804 | if (flow->hash == hash && |
784 | !memcmp(&flow->key, key, key_len)) { | 805 | !memcmp((u8 *)&flow->key + key_start, _key, key_len - key_start)) { |
785 | return flow; | 806 | return flow; |
786 | } | 807 | } |
787 | } | 808 | } |
788 | return NULL; | 809 | return NULL; |
789 | } | 810 | } |
790 | 811 | ||
791 | void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow) | 812 | void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, |
813 | struct sw_flow_key *key, int key_len) | ||
792 | { | 814 | { |
793 | struct hlist_head *head; | 815 | flow->hash = ovs_flow_hash(key, flow_key_start(key), key_len); |
794 | 816 | memcpy(&flow->key, key, sizeof(flow->key)); | |
795 | head = find_bucket(table, flow->hash); | 817 | __flow_tbl_insert(table, flow); |
796 | hlist_add_head_rcu(&flow->hash_node[table->node_ver], head); | ||
797 | table->count++; | ||
798 | } | 818 | } |
799 | 819 | ||
800 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) | 820 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow) |
@@ -1235,6 +1255,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
1235 | /** | 1255 | /** |
1236 | * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. | 1256 | * ovs_flow_metadata_from_nlattrs - parses Netlink attributes into a flow key. |
1237 | * @flow: Receives extracted in_port, priority, tun_key and skb_mark. | 1257 | * @flow: Receives extracted in_port, priority, tun_key and skb_mark. |
1258 | * @key_len: Length of key in @flow. Used for calculating flow hash. | ||
1238 | * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute | 1259 | * @attr: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute |
1239 | * sequence. | 1260 | * sequence. |
1240 | * | 1261 | * |
@@ -1243,7 +1264,7 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | |||
1243 | * get the metadata, that is, the parts of the flow key that cannot be | 1264 | * get the metadata, that is, the parts of the flow key that cannot be |
1244 | * extracted from the packet itself. | 1265 | * extracted from the packet itself. |
1245 | */ | 1266 | */ |
1246 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, | 1267 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, |
1247 | const struct nlattr *attr) | 1268 | const struct nlattr *attr) |
1248 | { | 1269 | { |
1249 | struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; | 1270 | struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key; |
@@ -1289,6 +1310,10 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, | |||
1289 | } | 1310 | } |
1290 | if (rem) | 1311 | if (rem) |
1291 | return -EINVAL; | 1312 | return -EINVAL; |
1313 | |||
1314 | flow->hash = ovs_flow_hash(&flow->key, | ||
1315 | flow_key_start(&flow->key), key_len); | ||
1316 | |||
1292 | return 0; | 1317 | return 0; |
1293 | } | 1318 | } |
1294 | 1319 | ||
diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index bfe80b960759..999842f247a0 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h | |||
@@ -156,7 +156,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies); | |||
156 | int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); | 156 | int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *); |
157 | int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, | 157 | int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp, |
158 | const struct nlattr *); | 158 | const struct nlattr *); |
159 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, | 159 | int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, |
160 | const struct nlattr *attr); | 160 | const struct nlattr *attr); |
161 | 161 | ||
162 | #define MAX_ACTIONS_BUFSIZE (32 * 1024) | 162 | #define MAX_ACTIONS_BUFSIZE (32 * 1024) |
@@ -188,9 +188,9 @@ void ovs_flow_tbl_deferred_destroy(struct flow_table *table); | |||
188 | struct flow_table *ovs_flow_tbl_alloc(int new_size); | 188 | struct flow_table *ovs_flow_tbl_alloc(int new_size); |
189 | struct flow_table *ovs_flow_tbl_expand(struct flow_table *table); | 189 | struct flow_table *ovs_flow_tbl_expand(struct flow_table *table); |
190 | struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table); | 190 | struct flow_table *ovs_flow_tbl_rehash(struct flow_table *table); |
191 | void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow); | 191 | void ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, |
192 | struct sw_flow_key *key, int key_len); | ||
192 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); | 193 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); |
193 | u32 ovs_flow_hash(const struct sw_flow_key *key, int key_len); | ||
194 | 194 | ||
195 | struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); | 195 | struct sw_flow *ovs_flow_tbl_next(struct flow_table *table, u32 *bucket, u32 *idx); |
196 | extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; | 196 | extern const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1]; |