Skip to content

Commit

Permalink
ofproto: Add relaxed group_mod command ADD_OR_MOD
Browse files Browse the repository at this point in the history
This patch adds support for a new Group Mod command OFPGC_ADD_OR_MOD to
OVS for all OpenFlow versions that support groups (OF11 and higher).
The new ADD_OR_MOD creates a group that does not yet exist (like ADD)
and modifies an existing group (like MODIFY).

Rational: In OpenFlow 1.x the Group Mod commands OFPGC_ADD and
OFPGC_MODIFY have strict semantics: ADD fails if the group exists,
while MODIFY fails if the group does not exist. This requires a
controller to exactly know the state of the switch when programming a
group in order not run the risk of getting an OFP Error message in
response. This is hard to achieve and maintain at all times in view of
possible switch and controller restarts or other connection losses
between switch and controller.

Due to the un-acknowledged nature of the Group Mod message programming
groups safely and efficiently at the same time is virtually impossible
as the controller has to either query the existence of the group prior
to each Group Mod message or to insert a Barrier Request/Reply after
every group to be sure that no Error can be received at a later stage
and require a complicated roll-back of any dependent actions taken
between the failed Group Mod and the Error.

In the ovs-ofctl command line the ADD_OR_MOD command is made available
through the new option --may-create in the mod-group command:

$ ovs-ofctl -Oopenflow13 del-groups br-int group_id=100

$ ovs-ofctl -Oopenflow13 mod-group br-int
group_id=100,type=indirect,bucket=actions=2 OFPT_ERROR (OF1.3)
(xid=0x2): OFPGMFC_UNKNOWN_GROUP OFPT_GROUP_MOD (OF1.3) (xid=0x2):
 MOD group_id=100,type=indirect,bucket=actions=output:2

$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=2

$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
 group_id=100,type=indirect,bucket=actions=output:2

$ ovs-ofctl -Oopenflow13 --may-create mod-group br-int
group_id=100,type=indirect,bucket=actions=3

$ ovs-ofctl -Oopenflow13 dump-groups br-int
OFPST_GROUP_DESC reply (OF1.3) (xid=0x2):
 group_id=100,type=indirect,bucket=actions=output:3

Signed-off-by: Jan Scheurich <jan.scheurich at web.de>
Signed-off-by: Ben Pfaff <blp@ovn.org>
  • Loading branch information
JScheurich authored and blp committed Jul 3, 2016
1 parent 2c5cbb1 commit b3d4244
Show file tree
Hide file tree
Showing 10 changed files with 90 additions and 6 deletions.
3 changes: 3 additions & 0 deletions NEWS
Expand Up @@ -17,10 +17,13 @@ Post-v2.5.0
* 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.
Expand Down
1 change: 1 addition & 0 deletions include/openflow/openflow-1.1.h
Expand Up @@ -172,6 +172,7 @@ enum ofp11_group_mod_command {
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
Expand Down
1 change: 1 addition & 0 deletions include/openflow/openflow-1.5.h
Expand Up @@ -59,6 +59,7 @@ enum ofp15_group_mod_command {
/* 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. */
Expand Down
4 changes: 4 additions & 0 deletions lib/ofp-parse.c
Expand Up @@ -1380,6 +1380,10 @@ parse_ofp_group_mod_str__(struct ofputil_group_mod *gm, uint16_t command,
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;
Expand Down
4 changes: 4 additions & 0 deletions lib/ofp-print.c
Expand Up @@ -2703,6 +2703,10 @@ ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version,
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;
Expand Down
7 changes: 6 additions & 1 deletion lib/ofp-util.c
Expand Up @@ -8896,6 +8896,7 @@ parse_group_prop_ntr_selection_method(struct ofpbuf *payload,
switch (group_cmd) {
case OFPGC15_ADD:
case OFPGC15_MODIFY:
case OFPGC15_ADD_OR_MOD:
break;
case OFPGC15_DELETE:
case OFPGC15_INSERT_BUCKET:
Expand Down Expand Up @@ -9224,6 +9225,7 @@ bad_group_cmd(enum ofp15_group_mod_command cmd)
switch (cmd) {
case OFPGC15_ADD:
case OFPGC15_MODIFY:
case OFPGC15_ADD_OR_MOD:
case OFPGC15_DELETE:
version = "1.1";
opt_version = "11";
Expand All @@ -9245,6 +9247,7 @@ bad_group_cmd(enum ofp15_group_mod_command cmd)
break;

case OFPGC15_MODIFY:
case OFPGC15_ADD_OR_MOD:
cmd_str = "mod-group";
break;

Expand Down Expand Up @@ -9284,7 +9287,7 @@ ofputil_encode_group_mod(enum ofp_version ofp_version,
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);
Expand Down Expand Up @@ -9355,6 +9358,7 @@ ofputil_pull_ofp15_group_mod(struct ofpbuf *msg, enum ofp_version ofp_version,

case OFPGC11_ADD:
case OFPGC11_MODIFY:
case OFPGC11_ADD_OR_MOD:
case OFPGC11_DELETE:
default:
if (gm->command_bucket_id == OFPG15_BUCKET_ALL) {
Expand Down Expand Up @@ -9433,6 +9437,7 @@ ofputil_decode_group_mod(const struct ofp_header *oh,
switch (gm->command) {
case OFPGC11_ADD:
case OFPGC11_MODIFY:
case OFPGC11_ADD_OR_MOD:
case OFPGC11_DELETE:
case OFPGC15_INSERT_BUCKET:
break;
Expand Down
25 changes: 25 additions & 0 deletions ofproto/ofproto.c
Expand Up @@ -6695,6 +6695,27 @@ modify_group(struct ofproto *ofproto, const struct ofputil_group_mod *gm)
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)
Expand Down Expand Up @@ -6784,6 +6805,10 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
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;
Expand Down
26 changes: 26 additions & 0 deletions tests/ofproto.at
Expand Up @@ -393,6 +393,32 @@ AT_CHECK([ovs-ofctl -O OpenFlow11 -vwarn add-group br0 'group_id=1236,type=indir
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=)
Expand Down
10 changes: 7 additions & 3 deletions utilities/ovs-ofctl.8.in 100644 → 100755
Expand Up @@ -431,10 +431,14 @@ zero or more groups in the same syntax, one per line.
.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]"
Expand Down
15 changes: 13 additions & 2 deletions utilities/ovs-ofctl.c
Expand Up @@ -84,6 +84,10 @@ static bool enable_color;
*/
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;
Expand Down Expand Up @@ -175,6 +179,7 @@ parse_options(int argc, char *argv[])
OPT_UNIXCTL,
OPT_BUNDLE,
OPT_COLOR,
OPT_MAY_CREATE,
DAEMON_OPTION_ENUMS,
OFP_VERSION_OPTION_ENUMS,
VLOG_OPTION_ENUMS
Expand All @@ -194,6 +199,7 @@ parse_options(int argc, char *argv[])
{"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,
Expand Down Expand Up @@ -319,6 +325,10 @@ parse_options(int argc, char *argv[])
}
break;

case OPT_MAY_CREATE:
may_create = true;
break;

DAEMON_OPTION_HANDLERS
OFP_VERSION_OPTION_HANDLERS
VLOG_OPTION_HANDLERS
Expand Down Expand Up @@ -406,7 +416,7 @@ usage(void)
" 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"
Expand Down Expand Up @@ -2534,7 +2544,8 @@ ofctl_add_groups(struct ovs_cmdl_context *ctx)
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
Expand Down

0 comments on commit b3d4244

Please sign in to comment.