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/openvswitch | |
| 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/openvswitch')
| -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]; |
