aboutsummaryrefslogtreecommitdiffstats
path: root/net/openvswitch
diff options
context:
space:
mode:
authorAndy Zhou <azhou@nicira.com>2013-10-22 13:42:46 -0400
committerJesse Gross <jesse@nicira.com>2013-10-22 13:42:46 -0400
commit1bd7116f1cb833c998cddb6b188df463342069d8 (patch)
tree4afeff18229a412b2ee5b72e3b0d10fc997ce1b6 /net/openvswitch
parent618ed0c805b64c820279f50732110ab873221c3b (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.c38
-rw-r--r--net/openvswitch/datapath.h4
-rw-r--r--net/openvswitch/flow_table.c16
-rw-r--r--net/openvswitch/flow_table.h4
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
566static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) 568static 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
754static 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
746static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) 762static 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 */
50struct dp_stats_percpu { 53struct 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
432struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, 432struct 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
450int 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
447static struct table_instance *table_instance_expand(struct table_instance *ti) 461static 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);
66int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, 66int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow,
67 struct sw_flow_mask *mask); 67 struct sw_flow_mask *mask);
68void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); 68void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow);
69int ovs_flow_tbl_num_masks(const struct flow_table *table);
69struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, 70struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table,
70 u32 *bucket, u32 *idx); 71 u32 *bucket, u32 *idx);
71struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, 72struct 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
74bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, 76bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow,
75 struct sw_flow_match *match); 77 struct sw_flow_match *match);