Loading include/uapi/linux/openvswitch.h +14 −3 Original line number Diff line number Diff line Loading @@ -63,6 +63,8 @@ enum ovs_datapath_cmd { * not be sent. * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the * datapath. Always present in notifications. * @OVS_DP_ATTR_MEGAFLOW_STATS: Statistics about mega flow masks usage for the * datapath. Always present in notifications. * * These attributes follow the &struct ovs_header within the Generic Netlink * payload for %OVS_DP_* commands. Loading @@ -72,6 +74,7 @@ enum ovs_datapath_attr { OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */ OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */ OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */ OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */ __OVS_DP_ATTR_MAX }; Loading @@ -84,6 +87,14 @@ struct ovs_dp_stats { __u64 n_flows; /* Number of flows present */ }; struct ovs_dp_megaflow_stats { __u64 n_mask_hit; /* Number of masks used for flow lookups. */ __u32 n_masks; /* Number of masks for the datapath. */ __u32 pad0; /* Pad for future expension. */ __u64 pad1; /* Pad for future expension. */ __u64 pad2; /* Pad for future expension. */ }; struct ovs_vport_stats { __u64 rx_packets; /* total packets received */ __u64 tx_packets; /* total packets transmitted */ Loading net/openvswitch/datapath.c +31 −7 Original line number Diff line number Diff line Loading @@ -221,6 +221,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) struct dp_stats_percpu *stats; struct sw_flow_key key; u64 *stats_counter; u32 n_mask_hit; int error; stats = this_cpu_ptr(dp->stats_percpu); Loading @@ -233,7 +234,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) } /* Look up flow. */ flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = ovs_flow_tbl_lookup(&dp->table, &key, &n_mask_hit); if (unlikely(!flow)) { struct dp_upcall_info upcall; Loading @@ -258,6 +259,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) /* Update datapath statistics. */ u64_stats_update_begin(&stats->sync); (*stats_counter)++; stats->n_mask_hit += n_mask_hit; u64_stats_update_end(&stats->sync); } Loading Loading @@ -563,13 +565,18 @@ static struct genl_ops dp_packet_genl_ops[] = { } }; static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, struct ovs_dp_megaflow_stats *mega_stats) { int i; memset(mega_stats, 0, sizeof(*mega_stats)); stats->n_flows = ovs_flow_tbl_count(&dp->table); mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table); stats->n_hit = stats->n_missed = stats->n_lost = 0; for_each_possible_cpu(i) { const struct dp_stats_percpu *percpu_stats; struct dp_stats_percpu local_stats; Loading @@ -585,6 +592,7 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) stats->n_hit += local_stats.n_hit; stats->n_missed += local_stats.n_missed; stats->n_lost += local_stats.n_lost; mega_stats->n_mask_hit += local_stats.n_mask_hit; } } Loading Loading @@ -743,6 +751,14 @@ static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, return skb; } static struct sw_flow *__ovs_flow_tbl_lookup(struct flow_table *tbl, const struct sw_flow_key *key) { u32 __always_unused n_mask_hit; return ovs_flow_tbl_lookup(tbl, key, &n_mask_hit); } static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; Loading Loading @@ -793,7 +809,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto err_unlock_ovs; /* Check if this is a duplicate flow */ flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow) { /* Bail out if we're not allowed to create a new flow. */ error = -ENOENT; Loading Loading @@ -905,7 +921,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) goto unlock; } flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { err = -ENOENT; goto unlock; Loading Loading @@ -953,7 +969,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock; flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { err = -ENOENT; goto unlock; Loading Loading @@ -1067,6 +1083,7 @@ static size_t ovs_dp_cmd_msg_size(void) msgsize += nla_total_size(IFNAMSIZ); msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats)); return msgsize; } Loading @@ -1076,6 +1093,7 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, { struct ovs_header *ovs_header; struct ovs_dp_stats dp_stats; struct ovs_dp_megaflow_stats dp_megaflow_stats; int err; ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family, Loading @@ -1091,8 +1109,14 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, if (err) goto nla_put_failure; get_dp_stats(dp, &dp_stats); if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats)) get_dp_stats(dp, &dp_stats, &dp_megaflow_stats); if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats)) goto nla_put_failure; if (nla_put(skb, OVS_DP_ATTR_MEGAFLOW_STATS, sizeof(struct ovs_dp_megaflow_stats), &dp_megaflow_stats)) goto nla_put_failure; return genlmsg_end(skb, ovs_header); Loading net/openvswitch/datapath.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,11 +46,15 @@ * @n_lost: Number of received packets that had no matching flow in the flow * table that could not be sent to userspace (normally due to an overflow in * one of the datapath's queues). * @n_mask_hit: Number of masks looked up for flow match. * @n_mask_hit / (@n_hit + @n_missed) will be the average masks looked * up per packet. */ struct dp_stats_percpu { u64 n_hit; u64 n_missed; u64 n_lost; u64 n_mask_hit; struct u64_stats_sync sync; }; Loading net/openvswitch/flow_table.c +15 −1 Original line number Diff line number Diff line Loading @@ -430,13 +430,16 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, } struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, const struct sw_flow_key *key) const struct sw_flow_key *key, u32 *n_mask_hit) { struct table_instance *ti = rcu_dereference(tbl->ti); struct sw_flow_mask *mask; struct sw_flow *flow; *n_mask_hit = 0; list_for_each_entry_rcu(mask, &tbl->mask_list, list) { (*n_mask_hit)++; flow = masked_flow_lookup(ti, key, mask); if (flow) /* Found */ return flow; Loading @@ -444,6 +447,17 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, return NULL; } int ovs_flow_tbl_num_masks(const struct flow_table *table) { struct sw_flow_mask *mask; int num = 0; list_for_each_entry(mask, &table->mask_list, list) num++; return num; } static struct table_instance *table_instance_expand(struct table_instance *ti) { return table_instance_rehash(ti, ti->n_buckets * 2); Loading net/openvswitch/flow_table.h +3 −1 Original line number Diff line number Diff line Loading @@ -66,10 +66,12 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table); int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, struct sw_flow_mask *mask); void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); int ovs_flow_tbl_num_masks(const struct flow_table *table); struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, u32 *bucket, u32 *idx); struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, const struct sw_flow_key *); const struct sw_flow_key *, u32 *n_mask_hit); bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, struct sw_flow_match *match); Loading Loading
include/uapi/linux/openvswitch.h +14 −3 Original line number Diff line number Diff line Loading @@ -63,6 +63,8 @@ enum ovs_datapath_cmd { * not be sent. * @OVS_DP_ATTR_STATS: Statistics about packets that have passed through the * datapath. Always present in notifications. * @OVS_DP_ATTR_MEGAFLOW_STATS: Statistics about mega flow masks usage for the * datapath. Always present in notifications. * * These attributes follow the &struct ovs_header within the Generic Netlink * payload for %OVS_DP_* commands. Loading @@ -72,6 +74,7 @@ enum ovs_datapath_attr { OVS_DP_ATTR_NAME, /* name of dp_ifindex netdev */ OVS_DP_ATTR_UPCALL_PID, /* Netlink PID to receive upcalls */ OVS_DP_ATTR_STATS, /* struct ovs_dp_stats */ OVS_DP_ATTR_MEGAFLOW_STATS, /* struct ovs_dp_megaflow_stats */ __OVS_DP_ATTR_MAX }; Loading @@ -84,6 +87,14 @@ struct ovs_dp_stats { __u64 n_flows; /* Number of flows present */ }; struct ovs_dp_megaflow_stats { __u64 n_mask_hit; /* Number of masks used for flow lookups. */ __u32 n_masks; /* Number of masks for the datapath. */ __u32 pad0; /* Pad for future expension. */ __u64 pad1; /* Pad for future expension. */ __u64 pad2; /* Pad for future expension. */ }; struct ovs_vport_stats { __u64 rx_packets; /* total packets received */ __u64 tx_packets; /* total packets transmitted */ Loading
net/openvswitch/datapath.c +31 −7 Original line number Diff line number Diff line Loading @@ -221,6 +221,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) struct dp_stats_percpu *stats; struct sw_flow_key key; u64 *stats_counter; u32 n_mask_hit; int error; stats = this_cpu_ptr(dp->stats_percpu); Loading @@ -233,7 +234,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) } /* Look up flow. */ flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = ovs_flow_tbl_lookup(&dp->table, &key, &n_mask_hit); if (unlikely(!flow)) { struct dp_upcall_info upcall; Loading @@ -258,6 +259,7 @@ void ovs_dp_process_received_packet(struct vport *p, struct sk_buff *skb) /* Update datapath statistics. */ u64_stats_update_begin(&stats->sync); (*stats_counter)++; stats->n_mask_hit += n_mask_hit; u64_stats_update_end(&stats->sync); } Loading Loading @@ -563,13 +565,18 @@ static struct genl_ops dp_packet_genl_ops[] = { } }; static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats, struct ovs_dp_megaflow_stats *mega_stats) { int i; memset(mega_stats, 0, sizeof(*mega_stats)); stats->n_flows = ovs_flow_tbl_count(&dp->table); mega_stats->n_masks = ovs_flow_tbl_num_masks(&dp->table); stats->n_hit = stats->n_missed = stats->n_lost = 0; for_each_possible_cpu(i) { const struct dp_stats_percpu *percpu_stats; struct dp_stats_percpu local_stats; Loading @@ -585,6 +592,7 @@ static void get_dp_stats(struct datapath *dp, struct ovs_dp_stats *stats) stats->n_hit += local_stats.n_hit; stats->n_missed += local_stats.n_missed; stats->n_lost += local_stats.n_lost; mega_stats->n_mask_hit += local_stats.n_mask_hit; } } Loading Loading @@ -743,6 +751,14 @@ static struct sk_buff *ovs_flow_cmd_build_info(struct sw_flow *flow, return skb; } static struct sw_flow *__ovs_flow_tbl_lookup(struct flow_table *tbl, const struct sw_flow_key *key) { u32 __always_unused n_mask_hit; return ovs_flow_tbl_lookup(tbl, key, &n_mask_hit); } static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; Loading Loading @@ -793,7 +809,7 @@ static int ovs_flow_cmd_new_or_set(struct sk_buff *skb, struct genl_info *info) goto err_unlock_ovs; /* Check if this is a duplicate flow */ flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow) { /* Bail out if we're not allowed to create a new flow. */ error = -ENOENT; Loading Loading @@ -905,7 +921,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) goto unlock; } flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { err = -ENOENT; goto unlock; Loading Loading @@ -953,7 +969,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) if (err) goto unlock; flow = ovs_flow_tbl_lookup(&dp->table, &key); flow = __ovs_flow_tbl_lookup(&dp->table, &key); if (!flow || !ovs_flow_cmp_unmasked_key(flow, &match)) { err = -ENOENT; goto unlock; Loading Loading @@ -1067,6 +1083,7 @@ static size_t ovs_dp_cmd_msg_size(void) msgsize += nla_total_size(IFNAMSIZ); msgsize += nla_total_size(sizeof(struct ovs_dp_stats)); msgsize += nla_total_size(sizeof(struct ovs_dp_megaflow_stats)); return msgsize; } Loading @@ -1076,6 +1093,7 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, { struct ovs_header *ovs_header; struct ovs_dp_stats dp_stats; struct ovs_dp_megaflow_stats dp_megaflow_stats; int err; ovs_header = genlmsg_put(skb, portid, seq, &dp_datapath_genl_family, Loading @@ -1091,8 +1109,14 @@ static int ovs_dp_cmd_fill_info(struct datapath *dp, struct sk_buff *skb, if (err) goto nla_put_failure; get_dp_stats(dp, &dp_stats); if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats)) get_dp_stats(dp, &dp_stats, &dp_megaflow_stats); if (nla_put(skb, OVS_DP_ATTR_STATS, sizeof(struct ovs_dp_stats), &dp_stats)) goto nla_put_failure; if (nla_put(skb, OVS_DP_ATTR_MEGAFLOW_STATS, sizeof(struct ovs_dp_megaflow_stats), &dp_megaflow_stats)) goto nla_put_failure; return genlmsg_end(skb, ovs_header); Loading
net/openvswitch/datapath.h +4 −0 Original line number Diff line number Diff line Loading @@ -46,11 +46,15 @@ * @n_lost: Number of received packets that had no matching flow in the flow * table that could not be sent to userspace (normally due to an overflow in * one of the datapath's queues). * @n_mask_hit: Number of masks looked up for flow match. * @n_mask_hit / (@n_hit + @n_missed) will be the average masks looked * up per packet. */ struct dp_stats_percpu { u64 n_hit; u64 n_missed; u64 n_lost; u64 n_mask_hit; struct u64_stats_sync sync; }; Loading
net/openvswitch/flow_table.c +15 −1 Original line number Diff line number Diff line Loading @@ -430,13 +430,16 @@ static struct sw_flow *masked_flow_lookup(struct table_instance *ti, } struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, const struct sw_flow_key *key) const struct sw_flow_key *key, u32 *n_mask_hit) { struct table_instance *ti = rcu_dereference(tbl->ti); struct sw_flow_mask *mask; struct sw_flow *flow; *n_mask_hit = 0; list_for_each_entry_rcu(mask, &tbl->mask_list, list) { (*n_mask_hit)++; flow = masked_flow_lookup(ti, key, mask); if (flow) /* Found */ return flow; Loading @@ -444,6 +447,17 @@ struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *tbl, return NULL; } int ovs_flow_tbl_num_masks(const struct flow_table *table) { struct sw_flow_mask *mask; int num = 0; list_for_each_entry(mask, &table->mask_list, list) num++; return num; } static struct table_instance *table_instance_expand(struct table_instance *ti) { return table_instance_rehash(ti, ti->n_buckets * 2); Loading
net/openvswitch/flow_table.h +3 −1 Original line number Diff line number Diff line Loading @@ -66,10 +66,12 @@ int ovs_flow_tbl_flush(struct flow_table *flow_table); int ovs_flow_tbl_insert(struct flow_table *table, struct sw_flow *flow, struct sw_flow_mask *mask); void ovs_flow_tbl_remove(struct flow_table *table, struct sw_flow *flow); int ovs_flow_tbl_num_masks(const struct flow_table *table); struct sw_flow *ovs_flow_tbl_dump_next(struct table_instance *table, u32 *bucket, u32 *idx); struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *, const struct sw_flow_key *); const struct sw_flow_key *, u32 *n_mask_hit); bool ovs_flow_cmp_unmasked_key(const struct sw_flow *flow, struct sw_flow_match *match); Loading