This is a first step towards implementing the dpif side of groups. In order to be useful the action translation code needs to be taught about groups.
Compile tested only. Signed-off-by: Simon Horman <ho...@verge.net.au> --- v2 * Corrected group_construct_stats() to allocate stats if they are not already allocated rather than the other way around. --- ofproto/ofproto-dpif.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++--- ofproto/ofproto-dpif.h | 27 ++++++++++++ 2 files changed, 132 insertions(+), 6 deletions(-) diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c index 70a226c..8a93ac9 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -4967,6 +4967,105 @@ rule_modify_actions(struct rule *rule_, bool reset_counters) complete_operation(rule); } + +static struct ofgroup * +group_alloc(void) +{ + struct group_dpif *group = xzalloc(sizeof *group); + return &group->up; +} + +static void +group_dealloc(struct ofgroup *group_) +{ + struct group_dpif *group = group_dpif_cast(group_); + free(group); +} + +static void +group_construct_stats(struct group_dpif *group) + OVS_REQUIRES(&group->stats_mutex) +{ + group->packet_count = 0; + group->byte_count = 0; + if (!group->bucket_stats) { + group->bucket_stats = xcalloc(group->up.n_buckets, + sizeof *group->bucket_stats); + } else { + memset(group->bucket_stats, 0, group->up.n_buckets * + sizeof *group->bucket_stats); + } +} + +static enum ofperr +group_construct(struct ofgroup *group_) +{ + struct group_dpif *group = group_dpif_cast(group_); + ovs_mutex_init(&group->stats_mutex); + ovs_mutex_lock(&group->stats_mutex); + group_construct_stats(group); + ovs_mutex_unlock(&group->stats_mutex); + return 0; +} + +static void +group_destruct__(struct group_dpif *group) + OVS_REQUIRES(&group->stats_mutex) +{ + free(group->bucket_stats); + group->bucket_stats = NULL; +} + +static void +group_destruct(struct ofgroup *group_) +{ + struct group_dpif *group = group_dpif_cast(group_); + ovs_mutex_lock(&group->stats_mutex); + group_destruct__(group); + ovs_mutex_unlock(&group->stats_mutex); + ovs_mutex_destroy(&group->stats_mutex); +} + +static enum ofperr +group_modify(struct ofgroup *group_, struct ofgroup *victim_) +{ + struct group_dpif *group = group_dpif_cast(group_); + struct group_dpif *victim = group_dpif_cast(victim_); + + ovs_mutex_lock(&group->stats_mutex); + if (victim->up.n_buckets < group->up.n_buckets) { + group_destruct__(group); + } + group_construct_stats(group); + ovs_mutex_unlock(&group->stats_mutex); + + return 0; +} + + +static enum ofperr +group_get_stats(const struct ofgroup *group_, struct ofputil_group_stats *ogs) +{ + struct group_dpif *group = group_dpif_cast(group_); + struct bucket_counter *bc = (struct bucket_counter *)(ogs + 1); + + /* push_all_stats() can handle flow misses which, when using the learn + * action, can cause groups to be added and deleted. This can corrupt our + * caller's datastructures which assume that group_get_stats() doesn't have + * an impact on the flow table. To be safe, we disable miss handling. */ + push_all_stats__(false); + + /* Start from historical data for 'group' itself that are no longer tracked + * in facets. This counts, for example, facets that have expired. */ + ovs_mutex_lock(&group->stats_mutex); + ogs->packet_count = group->packet_count; + ogs->byte_count = group->byte_count; + memcpy(bc, group->bucket_stats, + group->up.n_buckets * sizeof *group->bucket_stats); + ovs_mutex_unlock(&group->stats_mutex); + + return 0; +} /* Sends 'packet' out 'ofport'. * May modify 'packet'. @@ -6384,10 +6483,10 @@ const struct ofproto_class ofproto_dpif_class = { NULL, /* meter_set */ NULL, /* meter_get */ NULL, /* meter_del */ - NULL, /* group_alloc */ - NULL, /* group_construct */ - NULL, /* group_destruct */ - NULL, /* group_dealloc */ - NULL, /* group_modify */ - NULL, /* group_get_stats */ + group_alloc, /* group_alloc */ + group_construct, /* group_construct */ + group_destruct, /* group_destruct */ + group_dealloc, /* group_dealloc */ + group_modify, /* group_modify */ + group_get_stats, /* group_get_stats */ }; diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h index 15e58e9..61ea52f 100644 --- a/ofproto/ofproto-dpif.h +++ b/ofproto/ofproto-dpif.h @@ -79,6 +79,28 @@ struct rule_dpif { uint64_t byte_count OVS_GUARDED; /* Number of bytes received. */ }; +struct group_dpif { + struct ofgroup up; + + /* These statistics: + * + * - Do include packets and bytes from facets that have been deleted or + * whose own statistics have been folded into the rule. + * + * - Do include packets and bytes sent "by hand" that were accounted to + * the rule without any facet being involved (this is a rare corner + * case in rule_execute()). + * + * - Do not include packet or bytes that can be obtained from any facet's + * packet_count or byte_count member or that can be obtained from the + * datapath by, e.g., dpif_flow_get() for any subfacet. + */ + struct ovs_mutex stats_mutex; + uint64_t packet_count OVS_GUARDED; /* Number of packets received. */ + uint64_t byte_count OVS_GUARDED; /* Number of bytes received. */ + struct bucket_counter *bucket_stats OVS_GUARDED; /* Bucket statistics. */ +}; + static inline struct rule_dpif *rule_dpif_cast(const struct rule *rule) { return rule ? CONTAINER_OF(rule, struct rule_dpif, up) : NULL; @@ -101,6 +123,11 @@ struct rule_dpif *choose_miss_rule(enum ofputil_port_config, struct rule_dpif *miss_rule, struct rule_dpif *no_packet_in_rule); +static inline struct group_dpif *group_dpif_cast(const struct ofgroup *group) +{ + return group ? CONTAINER_OF(group, struct group_dpif, up) : NULL; +} + bool ofproto_has_vlan_splinters(const struct ofproto_dpif *); ofp_port_t vsp_realdev_to_vlandev(const struct ofproto_dpif *, ofp_port_t realdev_ofp_port, -- 1.8.4 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev