* New OpenFlow extension NXM_NX_MPLS_TTL to provide access to MPLS TTL.
* New output option, output(port=N,max_len=M), to allow truncating a
packet to size M bytes when outputting to port N.
+ * New command OFPGC_ADD_OR_MOD for OFPT_GROUP_MOD message that adds a
+ new group or modifies an existing groups
- ovs-ofctl:
* queue-get-config command now allows a queue ID to be specified.
* '--bundle' option can now be used with OpenFlow 1.3.
* New option "--color" to produce colorized output for some commands.
+ * New option '--may-create' to use OFPGC_ADD_OR_MOD in mod-group command.
- IPFIX:
* New "sampling_port" option for "sample" action to allow sampling
ingress and egress tunnel metadata with IPFIX.
OFPGC11_ADD, /* New group. */
OFPGC11_MODIFY, /* Modify all matching groups. */
OFPGC11_DELETE, /* Delete all matching groups. */
+ OFPGC11_ADD_OR_MOD = 0x8000, /* Create new or modify existing group. */
};
/* OpenFlow 1.1 specific capabilities supported by the datapath (struct
/* OFPGCXX_YYY = 4, */ /* Reserved for future use. */
OFPGC15_REMOVE_BUCKET = 5,/* Remove all action buckets or any specific
action bucket from matching group */
+ OFPGC15_ADD_OR_MOD = 0x8000, /* Create new or modify existing group. */
};
/* Group bucket property types. */
fields = F_GROUP_TYPE | F_BUCKETS;
break;
+ case OFPGC11_ADD_OR_MOD:
+ fields = F_GROUP_TYPE | F_BUCKETS;
+ break;
+
case OFPGC15_INSERT_BUCKET:
fields = F_BUCKETS | F_COMMAND_BUCKET_ID;
*usable_protocols &= OFPUTIL_P_OF15_UP;
ds_put_cstr(s, "MOD");
break;
+ case OFPGC11_ADD_OR_MOD:
+ ds_put_cstr(s, "ADD_OR_MOD");
+ break;
+
case OFPGC11_DELETE:
ds_put_cstr(s, "DEL");
break;
switch (group_cmd) {
case OFPGC15_ADD:
case OFPGC15_MODIFY:
+ case OFPGC15_ADD_OR_MOD:
break;
case OFPGC15_DELETE:
case OFPGC15_INSERT_BUCKET:
switch (cmd) {
case OFPGC15_ADD:
case OFPGC15_MODIFY:
+ case OFPGC15_ADD_OR_MOD:
case OFPGC15_DELETE:
version = "1.1";
opt_version = "11";
break;
case OFPGC15_MODIFY:
+ case OFPGC15_ADD_OR_MOD:
cmd_str = "mod-group";
break;
case OFP12_VERSION:
case OFP13_VERSION:
case OFP14_VERSION:
- if (gm->command > OFPGC11_DELETE) {
+ if (gm->command > OFPGC11_DELETE && gm->command != OFPGC11_ADD_OR_MOD) {
bad_group_cmd(gm->command);
}
return ofputil_encode_ofp11_group_mod(ofp_version, gm);
case OFPGC11_ADD:
case OFPGC11_MODIFY:
+ case OFPGC11_ADD_OR_MOD:
case OFPGC11_DELETE:
default:
if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
switch (gm->command) {
case OFPGC11_ADD:
case OFPGC11_MODIFY:
+ case OFPGC11_ADD_OR_MOD:
case OFPGC11_DELETE:
case OFPGC15_INSERT_BUCKET:
break;
return error;
}
+/* Implements the OFPGC11_ADD_OR_MOD command which creates the group when it does not
+ * exist yet and modifies it otherwise */
+static enum ofperr
+add_or_modify_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm)
+{
+ struct ofgroup *ofgroup;
+ enum ofperr error;
+ bool exists;
+
+ ovs_rwlock_rdlock(&ofproto->groups_rwlock);
+ exists = ofproto_group_lookup__(ofproto, gm->group_id, &ofgroup);
+ ovs_rwlock_unlock(&ofproto->groups_rwlock);
+
+ if (!exists) {
+ error = add_group(ofproto, gm);
+ } else {
+ error = modify_group(ofproto, gm);
+ }
+ return error;
+}
+
static void
delete_group__(struct ofproto *ofproto, struct ofgroup *ofgroup)
OVS_RELEASES(ofproto->groups_rwlock)
error = modify_group(ofproto, &gm);
break;
+ case OFPGC11_ADD_OR_MOD:
+ error = add_or_modify_group(ofproto, &gm);
+ break;
+
case OFPGC11_DELETE:
delete_group(ofproto, gm.group_id);
error = 0;
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - group_mod with mod and add_or_mod command])
+OVS_VSWITCHD_START
+dnl Check that mod-group for non-existing group fails without --may-create
+AT_DATA([stderr], [dnl
+OFPT_ERROR (OF1.3) (xid=0x2): OFPGMFC_UNKNOWN_GROUP
+OFPT_GROUP_MOD (OF1.3) (xid=0x2):
+ MOD group_id=1234,type=indirect,bucket=actions=output:2
+])
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'], [1], , [stderr])
+dnl Check that mod-group for non-existing group succeeds with --may-create
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=2'])
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
+AT_CHECK([strip_xids < stdout], [0], [dnl
+OFPST_GROUP_DESC reply (OF1.3):
+ group_id=1234,type=indirect,bucket=actions=output:2
+])
+dnl Check that mod-group for existing group succeeds with --may-create
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn --may-create mod-group br0 'group_id=1234,type=indirect,bucket=actions=3'])
+AT_CHECK([ovs-ofctl -O OpenFlow13 -vwarn dump-groups br0], [0], [stdout])
+AT_CHECK([strip_xids < stdout], [0], [dnl
+OFPST_GROUP_DESC reply (OF1.3):
+ group_id=1234,type=indirect,bucket=actions=output:3
+])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
dnl This is really bare-bones.
dnl It at least checks request and reply serialization and deserialization.
dnl Actions definition listed in both supported formats (w/ actions=)
.IQ "\fBadd\-groups \fIswitch file\fR"
Add each group entry to \fIswitch\fR's tables.
.
-.IP "\fBmod\-group \fIswitch group\fR"
-.IQ "\fBmod\-group \fIswitch \fB\- < \fIfile\fR"
+.IP "[\fB\-\-may\-create\fR] \fBmod\-group \fIswitch group\fR"
+.IQ "[\fB\-\-may\-create\fR] \fBmod\-group \fIswitch \fB\- < \fIfile\fR"
Modify the action buckets in entries from \fIswitch\fR's tables for
-each group entry.
+each group entry. If a specified group does not already exist, then
+without \fB\-\-may\-create\fR, this command has no effect; with
+\fB\-\-may\-create\fR, it creates a new group. The
+\fB\-\-may\-create\fR option uses an Open vSwitch extension to
+OpenFlow only implemented in Open vSwitch 2.6 and later.
.
.IP "\fBdel\-groups \fIswitch\fR"
.IQ "\fBdel\-groups \fIswitch \fR[\fIgroup\fR]"
*/
static bool strict;
+/* --may-create: If true, the mod-group command creates a group that does not
+ * yet exist; otherwise, such a command has no effect. */
+static bool may_create;
+
/* --readd: If true, on replace-flows, re-add even flows that have not changed
* (to reset flow counters). */
static bool readd;
OPT_UNIXCTL,
OPT_BUNDLE,
OPT_COLOR,
+ OPT_MAY_CREATE,
DAEMON_OPTION_ENUMS,
OFP_VERSION_OPTION_ENUMS,
VLOG_OPTION_ENUMS
{"option", no_argument, NULL, 'o'},
{"bundle", no_argument, NULL, OPT_BUNDLE},
{"color", optional_argument, NULL, OPT_COLOR},
+ {"may-create", no_argument, NULL, OPT_MAY_CREATE},
DAEMON_LONG_OPTIONS,
OFP_VERSION_LONG_OPTIONS,
VLOG_LONG_OPTIONS,
}
break;
+ case OPT_MAY_CREATE:
+ may_create = true;
+ break;
+
DAEMON_OPTION_HANDLERS
OFP_VERSION_OPTION_HANDLERS
VLOG_OPTION_HANDLERS
" snoop SWITCH snoop on SWITCH and its controller\n"
" add-group SWITCH GROUP add group described by GROUP\n"
" add-groups SWITCH FILE add group from FILE\n"
- " mod-group SWITCH GROUP modify specific group\n"
+ " [--may-create] mod-group SWITCH GROUP modify specific group\n"
" del-groups SWITCH [GROUP] delete matching GROUPs\n"
" insert-buckets SWITCH [GROUP] add buckets to GROUP\n"
" remove-buckets SWITCH [GROUP] remove buckets from GROUP\n"
static void
ofctl_mod_group(struct ovs_cmdl_context *ctx)
{
- ofctl_group_mod(ctx->argc, ctx->argv, OFPGC11_MODIFY);
+ ofctl_group_mod(ctx->argc, ctx->argv,
+ may_create ? OFPGC11_ADD_OR_MOD : OFPGC11_MODIFY);
}
static void