On Aug 28, 2013, at 11:55 PM, Ben Pfaff <[email protected]> wrote:
> From: Neil Zhu <[email protected]>
>
> This doesn't include a dpif implementation of groups functionality. In its
> current form, it is untested. Before this is committed, it needs some
> more comments and an ovs-ofctl manpage update.
>
> Signed-off-by: Neil Zhu <[email protected]>
> Co-authored-by: Ben Pfaff <[email protected]>
> Signed-off-by: Ben Pfaff <[email protected]>
I did a review and some initial testing. I'll send an incremental patch
separately for your review. Its all mainly just style issues, but I pointed
out some real issues below.
...
> @@ -1794,6 +1799,7 @@ parse_ofp_flow_stats_request_str(struct
> ofputil_flow_stats_request *fsr,
> fsr->cookie_mask = fm.cookie_mask;
> fsr->match = fm.match;
> fsr->out_port = fm.out_port;
> + fsr->out_group = fm.out_group;
> fsr->table_id = fm.table_id;
> return NULL;
> }
> @@ -1878,3 +1884,257 @@ exit:
> }
> return error;
> }
> +
> +static char * WARN_UNUSED_RESULT
> +parse_bucket_str(struct ofputil_bucket *p_bucket, char *str_,
> + enum ofputil_protocol *usable_protocols)
> +{
> + struct ofpbuf ofpacts;
> + char *pos, *act, *arg;
> + int n_actions;
> +
> + p_bucket->weight = 1;
> + p_bucket->watch_port = OFPP_ANY;
> + p_bucket->watch_group = OFPG11_ANY;
> +
> + pos = str_;
> + n_actions = 0;
> + ofpbuf_init(&ofpacts, 64);
> + while (ofputil_parse_key_value(&pos, &act, &arg)) {
> + char *error = NULL;
> +
> + if (!strcasecmp(act, "weight")) {
The rest to the file only uses strcmp(), not strcasecmp(), except for
actions. I changed these to strcmp()s.
...
> +static char * WARN_UNUSED_RESULT
> +parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
> + char *string,
> + enum ofputil_protocol *usable_protocols)
> +{
> + enum {
> + F_GROUP_TYPE = 1 << 0,
> + F_BUCKETS = 1 << 1,
> + } fields;
> + char *save_ptr = NULL;
> + char *bkt_str = NULL;
> + char *next_bkt_str = NULL;
> + bool had_type = false;
> + char *name;
> +
> + *usable_protocols = OFPUTIL_P_OF11_UP;
> +
> + switch (command) {
> + case OFPGC11_ADD:
> + fields = F_GROUP_TYPE | F_BUCKETS;
> + break;
> +
> + case OFPGC11_DELETE:
> + fields = 0;
> + break;
> +
> + case OFPGC11_MODIFY:
> + fields = F_GROUP_TYPE | F_BUCKETS;
> + break;
> +
> + default:
> + NOT_REACHED();
> + }
> +
> + memset(&gm, 0, sizeof gm);
This needs to be memset(gm, 0, sizeof *gm) instead. Spotted via
"Illegal instruction" signal...
> + gm->command = command;
> + gm->group_id = OFPG_ANY;
> + list_init(&gm->buckets);
> + if (command == OFPGC11_DELETE && string[0] == '\0') {
> + gm->group_id = OFPG_ALL;
> + return NULL;
> + }
> +
> + *usable_protocols = OFPUTIL_P_OF11_UP;
> +
> + bkt_str = strstr(string, "bucket");
> + if (fields & F_BUCKETS && bkt_str) {
> + struct ofputil_bucket *p_bucket = NULL;
> +
> + *bkt_str = '\0';
> +
> + while (bkt_str) {
> + char *error;
> +
> + bkt_str = strchr(bkt_str + 1, '=');
> + if (!bkt_str) {
> + return xstrdup("must specify bucket content");
Here (and elsewhere) already allocated buckets are not freed.
The incremental addresses this.
...
> +int
> +ofputil_decode_group_stats_reply(struct ofpbuf *msg,
> + struct ofputil_group_stats *ogs)
> +{
> + struct ofp11_bucket_counter *obc;
> + struct ofp11_group_stats *ogs11;
> + enum ofpraw raw;
> + enum ofperr error;
> + size_t base_len;
> + size_t length;
> + size_t i;
> +
> + if (!msg->size) {
> + return EOF;
> + }
> +
> + error = (msg->l2
> + ? ofpraw_decode(&raw, msg->l2)
> + : ofpraw_pull(&raw, msg));
> + if (error) {
> + return error;
> + }
> +
> + if (raw == OFPRAW_OFPST11_GROUP_REPLY) {
> + base_len = sizeof *ogs11;
> + ogs11 = ofpbuf_try_pull(msg, sizeof *ogs11);
> + ogs->duration_sec = ogs->duration_nsec = UINT32_MAX;
> + } else if (raw == OFPRAW_OFPST13_GROUP_REPLY) {
> + struct ofp13_group_stats *ogs13;
> +
> + base_len = sizeof *ogs13;
> + ogs13 = ofpbuf_try_pull(msg, sizeof *ogs13);
> + if (ogs13) {
> + ogs11 = &ogs13->gs;
> + ogs->duration_sec = ntohl(ogs13->duration_sec);
> + ogs->duration_nsec = ntohl(ogs13->duration_nsec);
> + } else {
> + ogs11 = NULL;
> + }
> + } else {
> + NOT_REACHED();
> + }
> +
> + ogs->group_id = ntohl(ogs11->group_id);
> + ogs->ref_count = ntohl(ogs11->ref_count);
> + ogs->packet_count = ntohll(ogs11->packet_count);
> + ogs->byte_count = ntohll(ogs11->byte_count);
> +
Here ogs11 may be NULL, so these need to be moved down a bit.
> + if (!ogs11) {
> + VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply has %zu leftover bytes at end",
> + ofpraw_get_name(raw), msg->size);
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> + length = ntohs(ogs11->length);
> + if (length < sizeof base_len) {
> + VLOG_WARN_RL(&bad_ofmsg_rl, "%s reply claims invalid length %zu",
> + ofpraw_get_name(raw), length);
> + return OFPERR_OFPBRC_BAD_LEN;
> + }
> +
>
...
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 820ec34..cfbc240 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -6384,4 +6384,11 @@ 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 */
> + NULL, /* group_get_ref_cnt */
I do not see the value of having a separate function for
group_get_ref_cnt, see below:
...
> +static void
> +append_group_stats(struct ofgroup *group, struct list *replies)
> +{
> + struct ofputil_group_stats ogs;
> + struct ofproto *ofproto = group->ofproto;
> + long long int now = time_msec();
> + int error;
> +
> + error = (ofproto->ofproto_class->group_get_stats
> + ? ofproto->ofproto_class->group_get_stats(group, &ogs)
> + : EOPNOTSUPP);
> + if (error) {
> + ogs.packet_count = UINT64_MAX;
> + ogs.byte_count = UINT64_MAX;
> + ogs.n_buckets = group->n_buckets;
> + memset(ogs.bucket_stats, 0xff,
> + ogs.n_buckets * sizeof *ogs.bucket_stats);
> + }
> +
> + error = (ofproto->ofproto_class->group_get_ref_cnt
> + ? ofproto->ofproto_class->group_get_ref_cnt(group,
> &ogs.ref_count)
> + : EOPNOTSUPP);
> + if (error) {
> + ogs.ref_count = UINT32_MAX;
> + }
> +
It would be simper just to have the group_get_stats return also the
ref_cnt, which is part of the stats structure anyway. In case the ofproto
provider does not support ref_cnt, it can return it as UINT32_MAX to
retain the behavior here.
Also, it seems to me that the reference counting should be implemented
in the ofproto proper anyway, rather than in an ofproto-provider. In the
incremental I have removed the group_get_ref_cnt().
Jarno
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev