[ovs-dev] [PATCH/RFC v2 3/8] Support decoding of NMX selection method
Simon Horman
simon.horman at netronome.com
Fri Jan 30 02:41:51 UTC 2015
This is in preparation for supporting group mod and desc reply
messages with an NMX selection method group experimenter property.
NMX selection method
Signed-off-by: Simon Horman <simon.horman at netronome.com>
---
v2 Use list of struct field_array of TLVs rather than OF1.1 match
for fields field of NMX selection method property
---
lib/meta-flow.c | 26 +++++
lib/meta-flow.h | 13 +++
lib/nx-match.c | 51 ++++++++++
lib/nx-match.h | 3 +
lib/ofp-parse.c | 15 ++-
lib/ofp-print.c | 4 +-
lib/ofp-util.c | 242 +++++++++++++++++++++++++++++++++++++++++++--
lib/ofp-util.h | 15 +++
ofproto/ofproto-provider.h | 5 +
ofproto/ofproto.c | 9 ++
utilities/ovs-ofctl.c | 4 +-
11 files changed, 372 insertions(+), 15 deletions(-)
diff --git a/lib/meta-flow.c b/lib/meta-flow.c
index 9ce4cfe..bd60cb6 100644
--- a/lib/meta-flow.c
+++ b/lib/meta-flow.c
@@ -2242,3 +2242,29 @@ mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s)
}
ds_put_char(s, '0');
}
+
+void
+field_array_push_back(enum mf_field_id id, const union mf_value *value,
+ struct ovs_list *field_array)
+{
+ struct field_array *fa;
+
+ fa = xmalloc(sizeof *fa);
+
+ fa->id = id;
+ fa->value = *value;
+
+ list_init(&fa->list_node);
+ list_push_back(field_array, &fa->list_node);
+}
+
+void
+field_array_delete(struct ovs_list *field_array)
+{
+ struct field_array *fa, *next;
+
+ LIST_FOR_EACH_SAFE (fa, next, list_node, field_array) {
+ list_remove(&fa->list_node);
+ free(fa);
+ }
+}
diff --git a/lib/meta-flow.h b/lib/meta-flow.h
index 4a6c443..a5716da 100644
--- a/lib/meta-flow.h
+++ b/lib/meta-flow.h
@@ -22,6 +22,7 @@
#include <netinet/ip6.h>
#include "bitmap.h"
#include "flow.h"
+#include "list.h"
#include "ofp-errors.h"
#include "packets.h"
#include "util.h"
@@ -1546,6 +1547,13 @@ union mf_subvalue {
};
BUILD_ASSERT_DECL(sizeof(union mf_value) == sizeof (union mf_subvalue));
+/* An array of fields with values */
+struct field_array {
+ struct ovs_list list_node; /* List of other elements in the array */
+ enum mf_field_id id; /* MFF_*. */
+ union mf_value value;
+};
+
/* Finding mf_fields. */
const struct mf_field *mf_from_name(const char *name);
@@ -1624,4 +1632,9 @@ void mf_format(const struct mf_field *,
struct ds *);
void mf_format_subvalue(const union mf_subvalue *subvalue, struct ds *s);
+/* Field Arrays. */
+void field_array_push_back(enum mf_field_id id, const union mf_value *,
+ struct ovs_list *);
+void field_array_delete(struct ovs_list *);
+
#endif /* meta-flow.h */
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 114c35b..4f84619 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -589,6 +589,57 @@ oxm_pull_match_loose(struct ofpbuf *b, struct match *match)
{
return oxm_pull_match__(b, false, match);
}
+
+/* Verify an array of OXM TLVs treating value of each TLV as a mask,
+ * disallowing masks in each TLV and ignoring pre-requisites. */
+enum ofperr
+oxm_pull_field_array(const void *fields_data, size_t fields_len,
+ struct ovs_list *field_array)
+{
+ struct ofpbuf b;
+ struct mf_bitmap used = MF_BITMAP_INITIALIZER;
+
+ ofpbuf_use_const(&b, fields_data, fields_len);
+ while (ofpbuf_size(&b)) {
+ const uint8_t *pos = ofpbuf_data(&b);
+ const struct mf_field *field;
+ union mf_value value, mask;
+ enum ofperr error;
+
+ error = nx_pull_match_entry(&b, false, &field, &value, &mask);
+ if (error) {
+ VLOG_DBG_RL(&rl, "error pulling field array field");
+ return error;
+ } else if (!field) {
+ VLOG_DBG_RL(&rl, "unknown field array field");
+ error = OFPERR_OFPBMC_BAD_FIELD;
+ } else if (bitmap_is_set(used.bm, field->id)) {
+ VLOG_DBG_RL(&rl, "duplicate field array field '%s'", field->name);
+ error = OFPERR_OFPBMC_DUP_FIELD;
+ } else if (!mf_is_mask_valid(field, &value)) {
+ VLOG_DBG_RL(&rl, "bad mask in field array field '%s'", field->name);
+ return OFPERR_OFPBMC_BAD_MASK;
+ } else if (!is_all_ones(&mask, field->n_bytes)) {
+ VLOG_DBG_RL(&rl, "mask has a mask in field array field '%s'",
+ field->name);
+ return OFPERR_OFPBMC_BAD_VALUE;
+ } else {
+ bitmap_set1(used.bm, field->id);
+ field_array_push_back(field->id, &value, field_array);
+ }
+
+ if (error) {
+ const uint8_t *start = fields_data;
+
+ VLOG_DBG_RL(&rl, "error parsing OXM at offset %"PRIdPTR" "
+ "within field array (%s)", pos - start,
+ ofperr_to_string(error));
+ return error;
+ }
+ }
+
+ return 0;
+}
/* nx_put_match() and helpers.
*
diff --git a/lib/nx-match.h b/lib/nx-match.h
index 9cb6461..1c9821c 100644
--- a/lib/nx-match.h
+++ b/lib/nx-match.h
@@ -32,6 +32,7 @@ struct ofpact_reg_move;
struct ofpact_reg_load;
struct ofpact_stack;
struct ofpbuf;
+struct ovs_list;
struct nx_action_reg_load;
struct nx_action_reg_move;
@@ -55,6 +56,8 @@ enum ofperr nx_pull_match_loose(struct ofpbuf *, unsigned int match_len,
ovs_be64 *cookie_mask);
enum ofperr oxm_pull_match(struct ofpbuf *, struct match *);
enum ofperr oxm_pull_match_loose(struct ofpbuf *, struct match *);
+enum ofperr oxm_pull_field_array(const void *, size_t fields_len,
+ struct ovs_list *);
int nx_put_match(struct ofpbuf *, const struct match *,
ovs_be64 cookie, ovs_be64 cookie_mask);
int oxm_put_match(struct ofpbuf *, const struct match *, enum ofp_version);
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 9a5df3b..d033382 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -1209,6 +1209,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
gm->group_id = OFPG_ANY;
gm->command_bucket_id = OFPG15_BUCKET_ALL;
list_init(&gm->buckets);
+ list_init(&gm->props.fields);
if (command == OFPGC11_DELETE && string[0] == '\0') {
gm->group_id = OFPG_ALL;
return NULL;
@@ -1365,7 +1366,7 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
return NULL;
out:
- ofputil_bucket_list_destroy(&gm->buckets);
+ ofputil_uninit_group_mod(gm);
return error;
}
@@ -1380,7 +1381,7 @@ parse_ofp_group_mod_str(struct ofputil_group_mod *gm, uint16_t command,
free(string);
if (error) {
- ofputil_bucket_list_destroy(&gm->buckets);
+ ofputil_uninit_group_mod(gm);
}
return error;
}
@@ -1419,6 +1420,9 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command,
if (list_is_empty(&(*gms)[i].buckets)) {
(*gms)[i].buckets.next = NULL;
}
+ if (list_is_empty(&(*gms)[i].props.fields)) {
+ (*gms)[i].props.fields.next = NULL;
+ }
}
*gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
for (i = 0; i < *n_gms; i++) {
@@ -1427,6 +1431,11 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command,
} else {
list_init(&(*gms)[i].buckets);
}
+ if ((*gms)[i].props.fields.next) {
+ list_moved(&(*gms)[i].props.fields);
+ } else {
+ list_init(&(*gms)[i].props.fields);
+ }
}
}
error = parse_ofp_group_mod_str(&(*gms)[*n_gms], command, ds_cstr(&s),
@@ -1435,7 +1444,7 @@ parse_ofp_group_mod_file(const char *file_name, uint16_t command,
size_t i;
for (i = 0; i < *n_gms; i++) {
- ofputil_bucket_list_destroy(&(*gms)[i].buckets);
+ ofputil_uninit_group_mod(*gms + i);
}
free(*gms);
*gms = NULL;
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index f4c5bc6..a596979 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2219,7 +2219,7 @@ ofp_print_group_desc(struct ds *s, const struct ofp_header *oh)
ds_put_char(s, ' ');
ofp_print_group(s, gd.group_id, gd.type, &gd.buckets, oh->version,
false);
- ofputil_bucket_list_destroy(&gd.buckets);
+ ofputil_uninit_group_desc(&gd);
}
}
@@ -2373,7 +2373,7 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, oh->version,
bucket_command);
- ofputil_bucket_list_destroy(&gm.buckets);
+ ofputil_uninit_group_mod(&gm);
}
static void
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index bf55fb2..9019a258 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -38,6 +38,7 @@
#include "ofp-msgs.h"
#include "ofp-util.h"
#include "ofpbuf.h"
+#include "openflow/netronome-ext.h"
#include "packets.h"
#include "random.h"
#include "unaligned.h"
@@ -59,6 +60,14 @@ struct ofp_prop_header {
ovs_be16 len;
};
+struct ofp_prop_experimenter {
+ ovs_be16 type; /* OFP*_EXPERIMENTER. */
+ ovs_be16 length; /* Length in bytes of this property. */
+ ovs_be32 experimenter; /* Experimenter ID which takes the same form as
+ * in struct ofp_experimenter_header. */
+ ovs_be32 exp_type; /* Experimenter defined. */
+};
+
/* Pulls a property, beginning with struct ofp_prop_header, from the beginning
* of 'msg'. Stores the type of the property in '*typep' and, if 'property' is
* nonnull, the entire property, including the header, in '*property'. Returns
@@ -7014,6 +7023,13 @@ ofputil_encode_group_stats_request(enum ofp_version ofp_version,
return request;
}
+void
+ofputil_uninit_group_desc(struct ofputil_group_desc *gd)
+{
+ ofputil_bucket_list_destroy(&gd->buckets);
+ field_array_delete(&gd->props.fields);
+}
+
/* Decodes the OpenFlow group description request in 'oh', returning the group
* whose description is requested, or OFPG_ALL if stats for all groups was
* requested. */
@@ -7716,6 +7732,191 @@ ofputil_pull_ofp15_buckets(struct ofpbuf *msg, size_t buckets_length,
return 0;
}
+static void
+ofputil_init_group_properties(struct ofputil_group_props *gp)
+{
+ memset(gp, 0, sizeof *gp);
+ list_init(&gp->fields);
+}
+
+static enum ofperr
+parse_group_prop_nmx_selection_method(struct ofpbuf *payload,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ struct nmx_group_prop_selection_method *prop = ofpbuf_data(payload);
+ size_t fields_len, method_len;
+ enum ofperr error;
+
+ switch (group_type) {
+ case OFPGT11_SELECT:
+ break;
+ case OFPGT11_ALL:
+ case OFPGT11_INDIRECT:
+ case OFPGT11_FF:
+ log_property(false, "nmx selection method property is only allowed "
+ "for select groups");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ switch (group_cmd) {
+ case OFPGC15_ADD:
+ case OFPGC15_MODIFY:
+ break;
+ case OFPGC15_DELETE:
+ case OFPGC15_INSERT_BUCKET:
+ case OFPGC15_REMOVE_BUCKET:
+ log_property(false, "nmx selection method property is only allowed "
+ "for add and delete group modifications");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ default:
+ OVS_NOT_REACHED();
+ }
+
+ if (ofpbuf_size(payload) < sizeof *prop) {
+ log_property(false, "nmx selection method property length "
+ "%u is not valid", ofpbuf_size(payload));
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ method_len = strnlen(prop->selection_method, NMX_MAX_SELECTION_METHOD_LEN);
+
+ if (method_len == NMX_MAX_SELECTION_METHOD_LEN) {
+ log_property(false, "nmx selection method is not null terminated");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ strcpy(gp->selection_method, prop->selection_method);
+ gp->selection_method_param = ntohll(prop->selection_method_param);
+
+ if (!method_len && gp->selection_method_param) {
+ log_property(false, "nmx selection method parameter is non-zero but "
+ "selection method is empty");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ ofpbuf_pull(payload, sizeof *prop);
+
+ fields_len = ntohs(prop->length) - sizeof *prop;
+ if (!method_len && fields_len) {
+ log_property(false, "nmx selection method parameter is zero "
+ "but fields are provided");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+
+ error = oxm_pull_field_array(ofpbuf_data(payload), fields_len,
+ &gp->fields);
+ if (error) {
+ log_property(false, "nmx selection method fields are invalid");
+ return error;
+ }
+
+ return 0;
+}
+
+static enum ofperr
+parse_group_prop_nmx(struct ofpbuf *payload, uint32_t exp_type,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ enum ofperr error;
+
+ switch (exp_type) {
+ case NMXT_SELECTION_METHOD:
+ error = parse_group_prop_nmx_selection_method(payload, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property nmx experimenter type "
+ "%"PRIu32, exp_type);
+ error = OFPERR_OFPBPC_BAD_TYPE;
+ break;
+ }
+
+ return error;
+}
+
+static enum ofperr
+parse_ofp15_group_prop_exp(struct ofpbuf *payload,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp)
+{
+ struct ofp_prop_experimenter *prop = ofpbuf_data(payload);
+ uint16_t experimenter;
+ uint32_t exp_type;
+ enum ofperr error;
+
+ if (ofpbuf_size(payload) < sizeof *prop) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ experimenter = ntohl(prop->experimenter);
+ exp_type = ntohl(prop->exp_type);
+
+ switch (experimenter) {
+ case NMX_VENDOR_ID:
+ error = parse_group_prop_nmx(payload, exp_type, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property experimenter %"PRIu16,
+ experimenter);
+ error = OFPERR_OFPBPC_BAD_EXPERIMENTER;
+ break;
+ }
+
+ return error;
+}
+
+static enum ofperr
+parse_ofp15_group_properties(struct ofpbuf *msg,
+ enum ofp11_group_type group_type,
+ enum ofp15_group_mod_command group_cmd,
+ struct ofputil_group_props *gp,
+ size_t properties_len)
+{
+ struct ofpbuf properties;
+
+ ofpbuf_use_const(&properties, ofpbuf_pull(msg, properties_len),
+ properties_len);
+
+ while (ofpbuf_size(&properties) > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(&properties, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch (type) {
+ case OFPGPT15_EXPERIMENTER:
+ error = parse_ofp15_group_prop_exp(&payload, group_type,
+ group_cmd, gp);
+ break;
+
+ default:
+ log_property(false, "unknown group property %"PRIu16, type);
+ error = OFPERR_OFPBPC_BAD_TYPE;
+ break;
+ }
+
+ if (error) {
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static int
ofputil_decode_ofp11_group_desc_reply(struct ofputil_group_desc *gd,
struct ofpbuf *msg,
@@ -7759,6 +7960,7 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
{
struct ofp15_group_desc_stats *ogds;
uint16_t length, bucket_list_len;
+ int error;
if (!msg->frame) {
ofpraw_pull_assert(msg);
@@ -7790,9 +7992,22 @@ ofputil_decode_ofp15_group_desc_reply(struct ofputil_group_desc *gd,
"bucket list length %u", bucket_list_len);
return OFPERR_OFPBRC_BAD_LEN;
}
+ error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, version,
+ &gd->buckets);
+ if (error) {
+ return error;
+ }
- return ofputil_pull_ofp15_buckets(msg, bucket_list_len, version,
- &gd->buckets);
+ /* By definition group desc messages don't have a group mod command.
+ * However, parse_group_prop_nmx_selection_method() checks to make sure
+ * that the command is OFPGC15_ADD or OFPGC15_DELETE to guard
+ * against group mod messages with other commands supplying
+ * a NMX selection method group experimenter property.
+ * Such properties are valid for group desc replies so
+ * claim that the group mod command is OFPGC15_ADD to
+ * satisfy the check in parse_group_prop_nmx_selection_method() */
+ return parse_ofp15_group_properties(msg, gd->type, OFPGC15_ADD, &gd->props,
+ ofpbuf_size(msg));
}
/* Converts a group description reply in 'msg' into an abstract
@@ -7809,6 +8024,8 @@ int
ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
struct ofpbuf *msg, enum ofp_version version)
{
+ ofputil_init_group_properties(&gd->props);
+
switch (version)
{
case OFP11_VERSION:
@@ -7826,6 +8043,13 @@ ofputil_decode_group_desc_reply(struct ofputil_group_desc *gd,
}
}
+void
+ofputil_uninit_group_mod(struct ofputil_group_mod *gm)
+{
+ ofputil_bucket_list_destroy(&gm->buckets);
+ field_array_delete(&gm->props.fields);
+}
+
static struct ofpbuf *
ofputil_encode_ofp11_group_mod(enum ofp_version ofp_version,
const struct ofputil_group_mod *gm)
@@ -8048,14 +8272,14 @@ ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,
}
bucket_list_len = ntohs(ogm->bucket_array_len);
- if (bucket_list_len < ofpbuf_size(msg)) {
- VLOG_WARN_RL(&bad_ofmsg_rl, "group has %u trailing bytes",
- ofpbuf_size(msg) - bucket_list_len);
- return OFPERR_OFPGMFC_BAD_BUCKET;
+ error = ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
+ &gm->buckets);
+ if (error) {
+ return error;
}
- return ofputil_pull_ofp15_buckets(msg, bucket_list_len, ofp_version,
- &gm->buckets);
+ return parse_ofp15_group_properties(msg, gm->type, gm->command, &gm->props,
+ ofpbuf_size(msg));
}
/* Converts OpenFlow group mod message 'oh' into an abstract group mod in
@@ -8072,6 +8296,8 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
ofpbuf_use_const(&msg, oh, ntohs(oh->length));
ofpraw_pull_assert(&msg);
+ ofputil_init_group_properties(&gm->props);
+
switch (ofp_version)
{
case OFP11_VERSION:
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index df4d044..31b250b 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -27,6 +27,7 @@
#include "match.h"
#include "meta-flow.h"
#include "netdev.h"
+#include "openflow/netronome-ext.h"
#include "openflow/nicira-ext.h"
#include "openvswitch/types.h"
#include "type-props.h"
@@ -217,6 +218,8 @@ void ofputil_match_to_ofp10_match(const struct match *, struct ofp10_match *);
/* Work with ofp11_match. */
enum ofperr ofputil_pull_ofp11_match(struct ofpbuf *, struct match *,
uint16_t *padded_match_len);
+enum ofperr ofputil_pull_ofp11_mask(struct ofpbuf *, struct match *,
+ struct mf_bitmap *bm);
enum ofperr ofputil_match_from_ofp11_match(const struct ofp11_match *,
struct match *);
int ofputil_put_ofp11_match(struct ofpbuf *, const struct match *,
@@ -994,6 +997,14 @@ struct ofputil_bucket {
};
/* Protocol-independent group_mod. */
+struct ofputil_group_props {
+ /* NMX selection method */
+ char selection_method[NMX_MAX_SELECTION_METHOD_LEN];
+ uint64_t selection_method_param;
+ struct ovs_list fields; /* A list of struct field_array */
+};
+
+/* Protocol-independent group_mod. */
struct ofputil_group_mod {
uint16_t command; /* One of OFPGC15_*. */
uint8_t type; /* One of OFPGT11_*. */
@@ -1003,6 +1014,7 @@ struct ofputil_group_mod {
* OFPGC15_REMOVE_BUCKET commands
* execution.*/
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
+ struct ofputil_group_props props; /* Group properties. */
};
/* Group stats reply, independent of protocol. */
@@ -1032,6 +1044,7 @@ struct ofputil_group_desc {
uint8_t type; /* One of OFPGT_*. */
uint32_t group_id; /* Group identifier. */
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
+ struct ofputil_group_props props; /* Group properties. */
};
void ofputil_bucket_list_destroy(struct ovs_list *buckets);
@@ -1062,6 +1075,7 @@ struct ofpbuf *ofputil_encode_group_features_reply(
const struct ofputil_group_features *, const struct ofp_header *request);
void ofputil_decode_group_features_reply(const struct ofp_header *,
struct ofputil_group_features *);
+void ofputil_uninit_group_mod(struct ofputil_group_mod *gm);
struct ofpbuf *ofputil_encode_group_mod(enum ofp_version ofp_version,
const struct ofputil_group_mod *gm);
@@ -1071,6 +1085,7 @@ enum ofperr ofputil_decode_group_mod(const struct ofp_header *,
int ofputil_decode_group_stats_reply(struct ofpbuf *,
struct ofputil_group_stats *);
+void ofputil_uninit_group_desc(struct ofputil_group_desc *gd);
uint32_t ofputil_decode_group_desc_request(const struct ofp_header *);
struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version,
uint32_t group_id);
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index d114390..edf448a 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -499,6 +499,11 @@ struct ofgroup {
struct ovs_list buckets; /* Contains "struct ofputil_bucket"s. */
const uint32_t n_buckets;
+
+ /* NMX selection method */
+ const char selection_method[NMX_MAX_SELECTION_METHOD_LEN];
+ const uint64_t selection_method_param;
+ const struct ovs_list fields; /* List of other elements in the array */
};
bool ofproto_group_lookup(const struct ofproto *ofproto, uint32_t group_id,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index b3909ad..2f4d62f 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2673,6 +2673,7 @@ ofproto_group_unref(struct ofgroup *group)
if (group && ovs_refcount_unref(&group->ref_count) == 1) {
group->ofproto->ofproto_class->group_destruct(group);
ofputil_bucket_list_destroy(&group->buckets);
+ field_array_delete(CONST_CAST(struct ovs_list *, &group->fields));
group->ofproto->ofproto_class->group_dealloc(group);
}
}
@@ -5850,6 +5851,14 @@ init_group(struct ofproto *ofproto, struct ofputil_group_mod *gm,
*CONST_CAST(uint32_t *, &(*ofgroup)->n_buckets) =
list_size(&(*ofgroup)->buckets);
+ memcpy(CONST_CAST(char *, (*ofgroup)->selection_method),
+ gm->props.selection_method, NMX_MAX_SELECTION_METHOD_LEN);
+ *CONST_CAST(uint64_t *, &(*ofgroup)->selection_method_param) =
+ gm->props.selection_method_param;
+ list_move(CONST_CAST(struct ovs_list *, &(*ofgroup)->fields),
+ &gm->props.fields);
+ list_init(&gm->props.fields);
+
/* Construct called BEFORE any locks are held. */
error = ofproto->ofproto_class->group_construct(*ofgroup);
if (error) {
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index b5ace5a..4c553b2 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -2127,7 +2127,7 @@ ofctl_group_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
}
ofctl_group_mod__(argv[1], gms, n_gms, usable_protocols);
for (i = 0; i < n_gms; i++) {
- ofputil_bucket_list_destroy(&gms[i].buckets);
+ ofputil_uninit_group_mod(gms + i);
}
free(gms);
}
@@ -2148,7 +2148,7 @@ ofctl_group_mod(int argc, char *argv[], uint16_t command)
ovs_fatal(0, "%s", error);
}
ofctl_group_mod__(argv[1], &gm, 1, usable_protocols);
- ofputil_bucket_list_destroy(&gm.buckets);
+ ofputil_uninit_group_mod(&gm);
}
}
--
2.1.4
More information about the dev
mailing list