diff options
author | Andy Zhou <azhou@nicira.com> | 2013-10-22 13:42:46 -0400 |
---|---|---|
committer | Jesse Gross <jesse@nicira.com> | 2013-10-22 13:42:46 -0400 |
commit | 1bd7116f1cb833c998cddb6b188df463342069d8 (patch) | |
tree | 4afeff18229a412b2ee5b72e3b0d10fc997ce1b6 /net/openvswitch | |
parent | 618ed0c805b64c820279f50732110ab873221c3b (diff) |
openvswitch: collect mega flow mask stats
Collect mega flow mask stats. ovs-dpctl show command can be used to
display them for debugging and performance tuning.
Signed-off-by: Andy Zhou <azhou@nicira.com>
Signed-off-by: Jesse Gross <jesse@nicira.com>
Diffstat (limited to 'net/openvswitch')
-rw-r--r-- | net/openvswitch/datapath.c | 38 | ||||
-rw-r--r-- | net/openvswitch/datapath.h | 4 | ||||
-rw-r--r-- | net/openvswitch/flow_table.c | 16 | ||||
-rw-r--r-- | net/openvswitch/flow_table.h | 4 |
4 files changed, 53 insertions, 9 deletions
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index cf270973095d..5bc5a4e64758 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c | |||
@@ -221,6 +221,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
221 | struct dp_stats_percpu *stats; | 221 | struct dp_stats_percpu *stats; |
222 | struct sw_flow_key key; | 222 | struct sw_flow_key key; |
223 | u64 *stats_counter; | 223 | u64 *stats_counter; |
224 | u32 n_mask_hit; | ||
224 | int error; | 225 | int error; |
225 | 226 | ||
226 | stats = this_cpu_ptr(dp->stats_percpu); | 227 | stats = this_cpu_ptr(dp->stats_percpu); |
@@ -233,7 +234,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) | |||
233 | } | 234 | } |
234 | 235 | ||
235 | /* Look up flow. */ | 236 | /* Look up flow. */ |
236 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 237 | flow = ovs_flow_tbl_lookup(&dp->table, &key, &n_mask_hit); |
237 | if (unlikely(!flow)) { | 238 | if (unlikely(!flow)) { |
238 | struct dp_upcall_info upcall; | 239 | struct dp_upcall_info upcall; |
239 | 240 | ||
@@ -258,6 +259,7 @@ out: | |||
258 | /* Update datapath statistics. */ | 259 | /* Update datapath statistics. */ |
259 | u64_stats_update_begin(&stats->sync); | 260 | u64_stats_update_begin(&stats->sync); |
260 | (*stats_counter)++; | 261 | (*stats_counter)++; |
262 | stats->n_mask_hit += n_mask_hit; | ||
261 | u64_stats_update_end(&stats->sync); | 263 | u64_stats_update_end(&stats->sync); |
262 | } | 264 | } |
263 | 265 | ||
@@ -563,13 +565,18 @@ static struct genl_ops dp_packet_genl_ops[] = { | |||
563 | } | 565 | } |
564 | }; | 566 | }; |
565 | 567 | ||
566 | static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) | 568 | static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, |
569 | struct ovs_dp_megaflow_stats *mega_stats) | ||
567 | { | 570 | { |
568 | int i; | 571 | int i; |
569 | 572 | ||
573 | memset(mega_stats, 0, sizeof(*mega_stats)); | ||
574 | |||
570 | stats->n_flows = ovs_flow_tbl_count(&dp->table); | 575 | stats->n_flows = ovs_flow_tbl_count(&dp->table); |
576 | mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table); | ||
571 | 577 | ||
572 | stats->n_hit = stats->n_missed = stats->n_lost = 0; | 578 | stats->n_hit = stats->n_missed = stats->n_lost = 0; |
579 | |||
573 | for_each_possible_cpu(i) { | 580 | for_each_possible_cpu(i) { |
574 | const struct dp_stats_percpu *percpu_stats; | 581 | const struct dp_stats_percpu *percpu_stats; |
575 | struct dp_stats_percpu local_stats; | 582 | struct dp_stats_percpu local_stats; |
@@ -585,6 +592,7 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) | |||
585 | stats->n_hit += local_stats.n_hit; | 592 | stats->n_hit += local_stats.n_hit; |
586 | stats->n_missed += local_stats.n_missed; | 593 | stats->n_missed += local_stats.n_missed; |
587 | stats->n_lost += local_stats.n_lost; | 594 | stats->n_lost += local_stats.n_lost; |
595 | mega_stats->n_mask_hit += local_stats.n_mask_hit; | ||
588 | } | 596 | } |
589 | } | 597 | } |
590 | 598 | ||
@@ -743,6 +751,14 @@ static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, | |||
743 | return skb; | 751 | return skb; |
744 | } | 752 | } |
745 | 753 | ||
754 | static struct sw_flow *__ovs_flow_tbl_lookup(struct flow_table *tbl, | ||
755 | const struct sw_flow_key *key) | ||
756 | { | ||
757 | u32 __always_unused n_mask_hit; | ||
758 | |||
759 | return ovs_flow_tbl_lookup(tbl, key, &n_mask_hit); | ||
760 | } | ||
761 | |||
746 | static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | 762 | static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) |
747 | { | 763 | { |
748 | struct nlattr **a = info->attrs; | 764 | struct nlattr **a = info->attrs; |
@@ -793,7 +809,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) | |||
793 | goto err_unlock_ovs; | 809 | goto err_unlock_ovs; |
794 | 810 | ||
795 | /* Check if this is a duplicate flow */ | 811 | /* Check if this is a duplicate flow */ |
796 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 812 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); |
797 | if (!flow) { | 813 | if (!flow) { |
798 | /* Bail out if we're not allowed to create a new flow. */ | 814 | /* Bail out if we're not allowed to create a new flow. */ |
799 | error = -ENOENT; | 815 | error = -ENOENT; |
@@ -905,7 +921,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) | |||
905 | goto unlock; | 921 | goto unlock; |
906 | } | 922 | } |
907 | 923 | ||
908 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 924 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); |
909 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { | 925 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { |
910 | err = -ENOENT; | 926 | err = -ENOENT; |
911 | goto unlock; | 927 | goto unlock; |
@@ -953,7 +969,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) | |||
953 | if (err) | 969 | if (err) |
954 | goto unlock; | 970 | goto unlock; |
955 | 971 | ||
956 | flow = ovs_flow_tbl_lookup(&dp->table, &key); | 972 | flow = __ovs_flow_tbl_lookup(&dp->table, &key); |
957 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { | 973 | if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { |
958 | err = -ENOENT; | 974 | err = -ENOENT; |
959 | goto unlock; | 975 | goto unlock; |
@@ -1067,6 +1083,7 @@ static size_t ovs_dp_cmd_msg_size(void) | |||
1067 | 1083 | ||
1068 | msgsize += nla_total_size(IFNAMSIZ); | 1084 | msgsize += nla_total_size(IFNAMSIZ); |
1069 | msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); | 1085 | msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); |
1086 | msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats)); | ||
1070 | 1087 | ||
1071 | return msgsize; | 1088 | return msgsize; |
1072 | } | 1089 | } |
@@ -1076,6 +1093,7 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, | |||
1076 | { | 1093 | { |
1077 | struct ovs_header *ovs_header; | 1094 | struct ovs_header *ovs_header; |
1078 | struct ovs_dp_stats dp_stats; | 1095 | struct ovs_dp_stats dp_stats; |
1096 | struct ovs_dp_megaflow_stats dp_megaflow_stats; | ||
1079 | int err; | 1097 | int err; |
1080 | 1098 | ||
1081 | ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family, | 1099 | ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family, |
@@ -1091,8 +1109,14 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, | |||
1091 | if (err) | 1109 | if (err) |
1092 | goto nla_put_failure; | 1110 | goto nla_put_failure; |
1093 | 1111 | ||
1094 | get_dp_stats(dp, &dp_stats); | 1112 | get_dp_stats(dp, &dp_stats, &dp_megaflow_stats); |
1095 | if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats)) | 1113 | if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), |
1114 | &dp_stats)) | ||
1115 | goto nla_put_failure; | ||
1116 | |||
1117 | if (nla_put(skb, OVS_DP_ATTR_MEGAFLOW_STATS, | ||
1118 | sizeof(struct ovs_dp_megaflow_stats), | ||
1119 | &dp_megaflow_stats)) | ||
1096 | goto nla_put_failure; | 1120 | goto nla_put_failure; |
1097 | 1121 | ||
1098 | return genlmsg_end(skb, ovs_header); | 1122 | return genlmsg_end(skb, ovs_header); |
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index acfd4af8ca3a..d3d14a58aa91 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h | |||
@@ -46,11 +46,15 @@ | |||
46 | * @n_lost: Number of received packets that had no matching flow in the flow | 46 | * @n_lost: Number of received packets that had no matching flow in the flow |
47 | * table that could not be sent to userspace (normally due to an overflow in | 47 | * table that could not be sent to userspace (normally due to an overflow in |
48 | * one of the datapath's queues). | 48 | * one of the datapath's queues). |
49 | * @n_mask_hit: Number of masks looked up for flow match. | ||
50 | * @n_mask_hit / (@n_hit + @n_missed) will be the average masks looked | ||
51 | * up per packet. | ||
49 | */ | 52 | */ |
50 | struct dp_stats_percpu { | 53 | struct dp_stats_percpu { |
51 | u64 n_hit; | 54 | u64 n_hit; |
52 | u64 n_missed; | 55 | u64 n_missed; |
53 | u64 n_lost; | 56 | u64 n_lost; |
57 | u64 n_mask_hit; | ||
54 | struct u64_stats_sync sync; | 58 | struct u64_stats_sync sync; |
55 | }; | 59 | }; |
56 | 60 | ||
diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index 036e019f8c3c..536b4d2a42e2 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c | |||
@@ -430,13 +430,16 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, | |||
430 | } | 430 | } |
431 | 431 | ||
432 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, | 432 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, |
433 | const struct sw_flow_key *key) | 433 | const struct sw_flow_key *key, |
434 | u32 *n_mask_hit) | ||
434 | { | 435 | { |
435 | struct table_instance *ti = rcu_dereference(tbl->ti); | 436 | struct table_instance *ti = rcu_dereference(tbl->ti); |
436 | struct sw_flow_mask *mask; | 437 | struct sw_flow_mask *mask; |
437 | struct sw_flow *flow; | 438 | struct sw_flow *flow; |
438 | 439 | ||
440 | *n_mask_hit = 0; | ||
439 | list_for_each_entry_rcu(mask, &tbl->mask_list, list) { | 441 | list_for_each_entry_rcu(mask, &tbl->mask_list, list) { |
442 | (*n_mask_hit)++; | ||
440 | flow = masked_flow_lookup(ti, key, mask); | 443 | flow = masked_flow_lookup(ti, key, mask); |
441 | if (flow) /* Found */ | 444 | if (flow) /* Found */ |
442 | return flow; | 445 | return flow; |
@@ -444,6 +447,17 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, | |||
444 | return NULL; | 447 | return NULL; |
445 | } | 448 | } |
446 | 449 | ||
450 | int ovs_flow_tbl_num_masks(const struct flow_table *table) | ||
451 | { | ||
452 | struct sw_flow_mask *mask; | ||
453 | int num = 0; | ||
454 | |||
455 | list_for_each_entry(mask, &table->mask_list, list) | ||
456 | num++; | ||
457 | |||
458 | return num; | ||
459 | } | ||
460 | |||
447 | static struct table_instance *table_instance_expand(struct table_instance *ti) | 461 | static struct table_instance *table_instance_expand(struct table_instance *ti) |
448 | { | 462 | { |
449 | return table_instance_rehash(ti, ti->n_buckets * 2); | 463 | return table_instance_rehash(ti, ti->n_buckets * 2); |
diff --git a/net/openvswitch/flow_table.h b/net/openvswitch/flow_table.h index 4db5f78b6f81..fbe45d5ad07d 100644 --- a/net/openvswitch/flow_table.h +++ b/net/openvswitch/flow_table.h | |||
@@ -66,10 +66,12 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table); | |||
66 | int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, | 66 | int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, |
67 | struct sw_flow_mask *mask); | 67 | struct sw_flow_mask *mask); |
68 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); | 68 | void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); |
69 | int ovs_flow_tbl_num_masks(const struct flow_table *table); | ||
69 | struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, | 70 | struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, |
70 | u32 *bucket, u32 *idx); | 71 | u32 *bucket, u32 *idx); |
71 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, | 72 | struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, |
72 | const struct sw_flow_key *); | 73 | const struct sw_flow_key *, |
74 | u32 *n_mask_hit); | ||
73 | 75 | ||
74 | bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, | 76 | bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, |
75 | struct sw_flow_match *match); | 77 | struct sw_flow_match *match); |