Skip to content

Commit

Permalink
ofproto: Implement OF1.4 Group & Meter change notification messages
Browse files Browse the repository at this point in the history
This patch adds support for Openflow1.4 Group & meter change notification
messages. In a multi controller environment, when a controller modifies the
state of group and meter table, the request that successfully modifies this
state is forwarded to other controllers. Other controllers are informed with
the OFPT_REQUESTFORWARD message. Request forwarding is enabled on a per
controller channel basis using the Set Asynchronous Configuration Message.

Signed-off-by: Niti Rohilla <[email protected]>
Co-authored-by: Ben Pfaff <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
  • Loading branch information
nitirohilla and blp committed Sep 9, 2015
1 parent 3514c76 commit 3c35db6
Show file tree
Hide file tree
Showing 12 changed files with 422 additions and 36 deletions.
6 changes: 6 additions & 0 deletions include/openflow/openflow-1.4.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,12 @@ struct ofp14_role_prop_experimenter {
};
OFP_ASSERT(sizeof(struct ofp14_role_prop_experimenter) == 12);

/* Group/Meter request forwarding. */
struct ofp14_requestforward {
struct ofp_header request; /* Request being forwarded. */
};
OFP_ASSERT(sizeof(struct ofp14_requestforward) == 8);

/* Bundle control message types */
enum ofp14_bundle_ctrl_type {
OFPBCT_OPEN_REQUEST = 0,
Expand Down
1 change: 1 addition & 0 deletions lib/learning-switch.c
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
case OFPTYPE_ROLE_REQUEST:
case OFPTYPE_ROLE_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_REQUESTFORWARD:
case OFPTYPE_SET_FLOW_FORMAT:
case OFPTYPE_FLOW_MOD_TABLE_ID:
case OFPTYPE_SET_PACKET_IN_FORMAT:
Expand Down
6 changes: 6 additions & 0 deletions lib/ofp-msgs.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ enum ofpraw {
/* OFPT 1.4+ (30): struct ofp14_role_status, uint8_t[8][]. */
OFPRAW_OFPT14_ROLE_STATUS,

/* OFPT 1.4+ (32): struct ofp14_requestforward, uint8_t[8][]. */
OFPRAW_OFPT14_REQUESTFORWARD,

/* OFPT 1.4+ (33): struct ofp14_bundle_ctrl_msg, uint8_t[8][]. */
OFPRAW_OFPT14_BUNDLE_CONTROL,

Expand Down Expand Up @@ -559,6 +562,9 @@ enum ofptype {
/* Controller role change event messages. */
OFPTYPE_ROLE_STATUS, /* OFPRAW_OFPT14_ROLE_STATUS. */

/* Request forwarding by the switch. */
OFPTYPE_REQUESTFORWARD, /* OFPRAW_OFPT14_REQUESTFORWARD. */

OFPTYPE_BUNDLE_CONTROL, /* OFPRAW_OFPT14_BUNDLE_CONTROL. */

OFPTYPE_BUNDLE_ADD_MESSAGE, /* OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE. */
Expand Down
108 changes: 77 additions & 31 deletions lib/ofp-print.c
Original file line number Diff line number Diff line change
Expand Up @@ -1185,21 +1185,9 @@ ofp_print_meter_config(struct ds *s, const struct ofputil_meter_config *mc)
}

static void
ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
ofp_print_meter_mod__(struct ds *s, const struct ofputil_meter_mod *mm)
{
struct ofputil_meter_mod mm;
struct ofpbuf bands;
enum ofperr error;

ofpbuf_init(&bands, 64);
error = ofputil_decode_meter_mod(oh, &mm, &bands);
if (error) {
ofpbuf_uninit(&bands);
ofp_print_error(s, error);
return;
}

switch (mm.command) {
switch (mm->command) {
case OFPMC13_ADD:
ds_put_cstr(s, " ADD ");
break;
Expand All @@ -1210,10 +1198,26 @@ ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
ds_put_cstr(s, " DEL ");
break;
default:
ds_put_format(s, " cmd:%d ", mm.command);
ds_put_format(s, " cmd:%d ", mm->command);
}

ofp_print_meter_config(s, &mm.meter);
ofp_print_meter_config(s, &mm->meter);
}

static void
ofp_print_meter_mod(struct ds *s, const struct ofp_header *oh)
{
struct ofputil_meter_mod mm;
struct ofpbuf bands;
enum ofperr error;

ofpbuf_init(&bands, 64);
error = ofputil_decode_meter_mod(oh, &mm, &bands);
if (error) {
ofp_print_error(s, error);
} else {
ofp_print_meter_mod__(s, &mm);
}
ofpbuf_uninit(&bands);
}

Expand Down Expand Up @@ -2333,7 +2337,8 @@ ofp_print_bucket_id(struct ds *s, const char *label, uint32_t bucket_id,

static void
ofp_print_group(struct ds *s, uint32_t group_id, uint8_t type,
struct ovs_list *p_buckets, struct ofputil_group_props *props,
const struct ovs_list *p_buckets,
const struct ofputil_group_props *props,
enum ofp_version ofp_version, bool suppress_type)
{
struct ofputil_bucket *bucket;
Expand Down Expand Up @@ -2529,22 +2534,15 @@ ofp_print_group_features(struct ds *string, const struct ofp_header *oh)
}

static void
ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
ofp_print_group_mod__(struct ds *s, enum ofp_version ofp_version,
const struct ofputil_group_mod *gm)
{
struct ofputil_group_mod gm;
int error;
bool bucket_command = false;

error = ofputil_decode_group_mod(oh, &gm);
if (error) {
ofp_print_error(s, error);
return;
}

ds_put_char(s, '\n');

ds_put_char(s, ' ');
switch (gm.command) {
switch (gm->command) {
case OFPGC11_ADD:
ds_put_cstr(s, "ADD");
break;
Expand All @@ -2568,17 +2566,31 @@ ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
break;

default:
ds_put_format(s, "cmd:%"PRIu16"", gm.command);
ds_put_format(s, "cmd:%"PRIu16"", gm->command);
}
ds_put_char(s, ' ');

if (bucket_command) {
ofp_print_bucket_id(s, "command_bucket_id:",
gm.command_bucket_id, oh->version);
gm->command_bucket_id, ofp_version);
}

ofp_print_group(s, gm.group_id, gm.type, &gm.buckets, &gm.props,
oh->version, bucket_command);
ofp_print_group(s, gm->group_id, gm->type, &gm->buckets, &gm->props,
ofp_version, bucket_command);
}

static void
ofp_print_group_mod(struct ds *s, const struct ofp_header *oh)
{
struct ofputil_group_mod gm;
int error;

error = ofputil_decode_group_mod(oh, &gm);
if (error) {
ofp_print_error(s, error);
return;
}
ofp_print_group_mod__(s, oh->version, &gm);
ofputil_bucket_list_destroy(&gm.buckets);
}

Expand Down Expand Up @@ -3050,6 +3062,36 @@ ofp_print_geneve_table_reply(struct ds *s, const struct ofp_header *oh)
ofputil_uninit_geneve_table(&gtr.mappings);
}

/* This function will print the request forward message. The reason for
* request forward is taken from rf.request.type */
static void
ofp_print_requestforward(struct ds *string, const struct ofp_header *oh)
{
struct ofputil_requestforward rf;
enum ofperr error;

error = ofputil_decode_requestforward(oh, &rf);
if (error) {
ofp_print_error(string, error);
return;
}

ds_put_cstr(string, " reason=");

switch (rf.reason) {
case OFPRFR_GROUP_MOD:
ds_put_cstr(string, "group_mod");
ofp_print_group_mod__(string, oh->version, rf.group_mod);
break;

case OFPRFR_METER_MOD:
ds_put_cstr(string, "meter_mod");
ofp_print_meter_mod__(string, rf.meter_mod);
break;
}
ofputil_destroy_requestforward(&rf);
}

static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
Expand Down Expand Up @@ -3179,6 +3221,10 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
ofp_print_role_status_message(string, oh);
break;

case OFPTYPE_REQUESTFORWARD:
ofp_print_requestforward(string, oh);
break;

case OFPTYPE_METER_STATS_REQUEST:
case OFPTYPE_METER_CONFIG_STATS_REQUEST:
ofp_print_stats(string, oh);
Expand Down
120 changes: 120 additions & 0 deletions lib/ofp-util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5376,6 +5376,125 @@ ofputil_decode_role_status(const struct ofp_header *oh,
return 0;
}

/* Encodes 'rf' according to 'protocol', and returns the encoded message.
* 'protocol' must be for OpenFlow 1.4 or later. */
struct ofpbuf *
ofputil_encode_requestforward(const struct ofputil_requestforward *rf,
enum ofputil_protocol protocol)
{
enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
struct ofpbuf *inner;

switch (rf->reason) {
case OFPRFR_GROUP_MOD:
inner = ofputil_encode_group_mod(ofp_version, rf->group_mod);
break;

case OFPRFR_METER_MOD:
inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
break;

default:
OVS_NOT_REACHED();
}

struct ofp_header *inner_oh = inner->data;
inner_oh->xid = rf->xid;
inner_oh->length = htons(inner->size);

struct ofpbuf *outer = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD,
ofp_version, htonl(0),
inner->size);
ofpbuf_put(outer, inner->data, inner->size);
ofpbuf_delete(inner);

return outer;
}

/* Decodes OFPT_REQUESTFORWARD message 'outer'. On success, puts the decoded
* form into '*rf' and returns 0, and the caller is later responsible for
* freeing the content of 'rf', with ofputil_destroy_requestforward(rf). On
* failure, returns an ofperr and '*rf' is indeterminate. */
enum ofperr
ofputil_decode_requestforward(const struct ofp_header *outer,
struct ofputil_requestforward *rf)
{
struct ofpbuf b;
enum ofperr error;

ofpbuf_use_const(&b, outer, ntohs(outer->length));

/* Skip past outer message. */
enum ofpraw outer_raw = ofpraw_pull_assert(&b);
ovs_assert(outer_raw == OFPRAW_OFPT14_REQUESTFORWARD);

/* Validate inner message. */
if (b.size < sizeof(struct ofp_header)) {
return OFPERR_OFPBFC_MSG_BAD_LEN;
}
const struct ofp_header *inner = b.data;
unsigned int inner_len = ntohs(inner->length);
if (inner_len < sizeof(struct ofp_header) || inner_len > b.size) {
return OFPERR_OFPBFC_MSG_BAD_LEN;
}
if (inner->version != outer->version) {
return OFPERR_OFPBRC_BAD_VERSION;
}

/* Parse inner message. */
enum ofptype type;
error = ofptype_decode(&type, inner);
if (error) {
return error;
}

rf->xid = inner->xid;
if (type == OFPTYPE_GROUP_MOD) {
rf->reason = OFPRFR_GROUP_MOD;
rf->group_mod = xmalloc(sizeof *rf->group_mod);
error = ofputil_decode_group_mod(inner, rf->group_mod);
if (error) {
free(rf->group_mod);
return error;
}
} else if (type == OFPTYPE_METER_MOD) {
rf->reason = OFPRFR_METER_MOD;
rf->meter_mod = xmalloc(sizeof *rf->meter_mod);
ofpbuf_init(&rf->bands, 64);
error = ofputil_decode_meter_mod(inner, rf->meter_mod, &rf->bands);
if (error) {
free(rf->meter_mod);
ofpbuf_uninit(&rf->bands);
return error;
}
} else {
return OFPERR_OFPBFC_MSG_UNSUP;
}

return 0;
}

/* Frees the content of 'rf', which should have been initialized through a
* successful call to ofputil_decode_requestforward(). */
void
ofputil_destroy_requestforward(struct ofputil_requestforward *rf)
{
if (!rf) {
return;
}

switch (rf->reason) {
case OFPRFR_GROUP_MOD:
ofputil_uninit_group_mod(rf->group_mod);
free(rf->group_mod);
break;

case OFPRFR_METER_MOD:
ofpbuf_uninit(&rf->bands);
free(rf->meter_mod);
}
}

/* Table stats. */

/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
Expand Down Expand Up @@ -9057,6 +9176,7 @@ ofputil_is_bundlable(enum ofptype type)
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_REQUESTFORWARD:
case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
break;
Expand Down
21 changes: 21 additions & 0 deletions lib/ofp-util.h
Original file line number Diff line number Diff line change
Expand Up @@ -1239,4 +1239,25 @@ struct ofpbuf *ofputil_encode_get_async_config(const struct ofp_header *,
uint32_t master[OAM_N_TYPES],
uint32_t slave[OAM_N_TYPES]);

struct ofputil_requestforward {
ovs_be32 xid;
enum ofp14_requestforward_reason reason;
union {
/* reason == OFPRFR_METER_MOD. */
struct ofputil_meter_mod *meter_mod;

/* reason == OFPRFR_GROUP_MOD. */
struct {
struct ofputil_group_mod *group_mod;
struct ofpbuf bands;
};
};
};

struct ofpbuf *ofputil_encode_requestforward(
const struct ofputil_requestforward *, enum ofputil_protocol);
enum ofperr ofputil_decode_requestforward(const struct ofp_header *,
struct ofputil_requestforward *);
void ofputil_destroy_requestforward(struct ofputil_requestforward *);

#endif /* ofp-util.h */
1 change: 1 addition & 0 deletions lib/rconn.c
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,7 @@ is_admitted_msg(const struct ofpbuf *b)
case OFPTYPE_ROLE_REQUEST:
case OFPTYPE_ROLE_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_REQUESTFORWARD:
case OFPTYPE_SET_FLOW_FORMAT:
case OFPTYPE_FLOW_MOD_TABLE_ID:
case OFPTYPE_SET_PACKET_IN_FORMAT:
Expand Down
Loading

0 comments on commit 3c35db6

Please sign in to comment.