On Wed, Sep 09, 2015 at 05:33:42PM +0530, [email protected] wrote:
> From: Niti Rohilla <[email protected]>
>
> 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]>
> ---
> Difference between v7->v8:
> - Memory leak issue in ofputil_re_encode_requestforward() has been resolved.
> - Modified the test case so that ofputil_re_encode_requestforward() get
> excercised in the testsuite to re-encode the request.
> - Rebased with the latest master.
After I looked at this for a while, I realized that there was more
decoding than necessary. It shouldn't be necessary to decode a message
once to execute it, then decode it again to reencode it inside
ofputil_re_encode_requestforward(). That even introduces a possibility
for failure the second time (though it shouldn't happen).
I decided that it's better, therefore, to make ofputil_requestforward
include the decoded form of the inner message instead of the raw form,
like this:
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;
};
};
};
This required further changes elsewhere, but they were straightforward.
Anyway, I folded in the following incremental and applied this to
master. Thanks!
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index b2d3b4f..d0c94ce 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -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;
@@ -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);
}
@@ -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;
@@ -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;
@@ -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);
}
@@ -3057,7 +3069,6 @@ ofp_print_requestforward(struct ds *string, const struct
ofp_header *oh)
{
struct ofputil_requestforward rf;
enum ofperr error;
- enum ofptype type;
error = ofputil_decode_requestforward(oh, &rf);
if (error) {
@@ -3065,21 +3076,20 @@ ofp_print_requestforward(struct ds *string, const
struct ofp_header *oh)
return;
}
- error = ofptype_decode(&type, rf.request);
- if (error) {
- ofp_print_error(string, error);
- return;
- }
-
ds_put_cstr(string, " reason=");
- if (type == OFPTYPE_GROUP_MOD) {
+ switch (rf.reason) {
+ case OFPRFR_GROUP_MOD:
ds_put_cstr(string, "group_mod");
- ofp_print_group_mod(string, rf.request);
- } else if (type == OFPTYPE_METER_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.request);
+ ofp_print_meter_mod__(string, rf.meter_mod);
+ break;
}
+ ofputil_destroy_requestforward(&rf);
}
static void
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 05ee6bb..d90cca8 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -5376,106 +5376,125 @@ ofputil_decode_role_status(const struct ofp_header
*oh,
return 0;
}
-/* Re-encodes the "GROUP_MOD" or "METER_MOD" request header for the
- * 'protocol' in the ofconn. */
-enum ofperr
-ofputil_re_encode_requestforward(uint8_t reason,
- const struct ofp_header *request,
- struct ofp_header **requestp,
- enum ofputil_protocol protocol)
+/* 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 version;
- struct ofp_header *rf;
- struct ofpbuf *buf;
- enum ofperr error;
-
- version = ofputil_protocol_to_ofp_version(protocol);
- switch (reason) {
- case OFPRFR_GROUP_MOD: {
- struct ofputil_group_mod gm;
+ enum ofp_version ofp_version = ofputil_protocol_to_ofp_version(protocol);
+ struct ofpbuf *inner;
- error = ofputil_decode_group_mod(request, &gm);
- if (error) {
- return error;
- }
- buf = ofputil_encode_group_mod(version, &gm);
- ofputil_bucket_list_destroy(&gm.buckets);
+ switch (rf->reason) {
+ case OFPRFR_GROUP_MOD:
+ inner = ofputil_encode_group_mod(ofp_version, rf->group_mod);
break;
- }
- case OFPRFR_METER_MOD: {
- struct ofputil_meter_mod mm;
- struct ofpbuf bands;
- ofpbuf_init(&bands, 64);
- error = ofputil_decode_meter_mod(request, &mm, &bands);
- if (error) {
- ofpbuf_uninit(&bands);
- return error;
- }
- buf = ofputil_encode_meter_mod(version, &mm);
- ofpbuf_uninit(&bands);
+ case OFPRFR_METER_MOD:
+ inner = ofputil_encode_meter_mod(ofp_version, rf->meter_mod);
break;
- }
+
default:
OVS_NOT_REACHED();
}
- rf = buf->data;
- rf->length = htons(buf->size);
- rf->xid = request->xid;
- *requestp = rf;
- return 0;
-}
-/* Encodes "request forward" message encapsulating "GROUP_MOD" or "METER_MOD"
- * request in 'rf'. The OpenFlow version of OFPT_REQUESTFORWARD message and
- * 'rf->request' should be same.
- * 'rf->request' is not converted from host to network byte order because
- * "GROUP_MOD" or "METER_MOD" request header in 'rf' is directly encapsulated
- * in request forward message. */
-struct ofpbuf *
-ofputil_encode_requestforward(const struct ofputil_requestforward *rf)
-{
- struct ofpbuf *buf;
+ struct ofp_header *inner_oh = inner->data;
+ inner_oh->xid = rf->xid;
+ inner_oh->length = htons(inner->size);
- buf = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD, rf->request->version,
- htonl(0), ntohs(rf->request->length));
- ofpbuf_put(buf, rf->request, ntohs(rf->request->length));
- return buf;
+ 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;
}
-/* Converts OpenFlow request forward message 'oh' into an abstract request
- * forward in 'rf'. Returns 0 if successful, otherwise an OpenFlow error
- * code. */
+/* 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 *oh,
+ofputil_decode_requestforward(const struct ofp_header *outer,
struct ofputil_requestforward *rf)
{
struct ofpbuf b;
- enum ofpraw raw;
enum ofperr error;
- size_t inner_len;
- ofpbuf_use_const(&b, oh, ntohs(oh->length));
- error = ofpraw_pull(&raw, &b);
- if (error) {
- return error;
- }
-
- ovs_assert(raw == OFPRAW_OFPT14_REQUESTFORWARD);
+ ofpbuf_use_const(&b, outer, ntohs(outer->length));
- rf->request = b.data;
+ /* Skip past outer message. */
+ enum ofpraw outer_raw = ofpraw_pull_assert(&b);
+ ovs_assert(outer_raw == OFPRAW_OFPT14_REQUESTFORWARD);
- if (rf->request->version != oh->version) {
- return OFPERR_OFPBRC_BAD_VERSION;
+ /* Validate inner message. */
+ if (b.size < sizeof(struct ofp_header)) {
+ return OFPERR_OFPBFC_MSG_BAD_LEN;
}
- inner_len = ntohs(rf->request->length);
+ 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
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 7589f51..cbd6175 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -861,22 +861,6 @@ struct ofpbuf *ofputil_encode_role_status(
enum ofperr ofputil_decode_role_status(const struct ofp_header *oh,
struct ofputil_role_status *rs);
-struct ofputil_requestforward {
- const struct ofp_header *request;
-};
-
-enum ofperr
-ofputil_re_encode_requestforward(uint8_t reason,
- const struct ofp_header *request,
- struct ofp_header **requestp,
- enum ofputil_protocol protocol);
-struct ofpbuf *
-ofputil_encode_requestforward(const struct ofputil_requestforward *rf);
-
-enum ofperr
-ofputil_decode_requestforward(const struct ofp_header *oh,
- struct ofputil_requestforward *rf);
-
/* Abstract table stats.
*
* This corresponds to the OpenFlow 1.3 table statistics structure, which only
@@ -1255,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 */
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 60f3d9a..ef2c06f 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -1714,46 +1714,21 @@ connmgr_send_port_status(struct connmgr *mgr, struct
ofconn *source,
* controller OFPT_GROUP_MOD and OFPT_METER_MOD, specify 'source' as the
* controller connection that sent the request; otherwise, specify 'source'
* as NULL. */
-enum ofperr
-connmgr_send_requestforward(struct connmgr *mgr, struct ofconn *source,
- uint8_t reason, const struct ofp_header *oh)
+void
+connmgr_send_requestforward(struct connmgr *mgr, const struct ofconn *source,
+ const struct ofputil_requestforward *rf)
{
- struct ofputil_requestforward rf;
struct ofconn *ofconn;
- struct ofp_header *request = NULL;
- enum ofperr error;
LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
- if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, reason)) {
- struct ofpbuf *msg;
-
- rf.request = oh;
- /* For OpenFlow 1.4 and later, it generates OFPT_REQUESTFORWARD
- * for OFPT_GROUP_MOD and OFPT_METER_MOD, but not back to the
- * originating controller. In a single-controller environment, in
- * particular, this means that it will never generate
- * OFPT_REQUESTFORWARD for OFPT_GROUP_MOD and OFPT_METER_MOD at
- * all. */
- if (rconn_get_version(ofconn->rconn) < OFP14_VERSION
- || ofconn == source) {
- continue;
- }
- /* When the version of GROUP_MOD or METER_MOD request is not same
- * as that of ofconn, then re-encode the GROUP_MOD or METER_MOD
- * request for the protocol in use. */
- if (oh->version != rconn_get_version(ofconn->rconn)) {
- error = ofputil_re_encode_requestforward(reason, oh, &request,
- ofconn_get_protocol(ofconn));
- if (error) {
- return error;
- }
- rf.request = request;
- }
- msg = ofputil_encode_requestforward(&rf);
- ofconn_send(ofconn, msg, NULL);
+ if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, rf->reason)
+ && rconn_get_version(ofconn->rconn) >= OFP14_VERSION
+ && ofconn != source) {
+ enum ofputil_protocol protocol = ofconn_get_protocol(ofconn);
+ ofconn_send(ofconn, ofputil_encode_requestforward(rf, protocol),
+ NULL);
}
}
- return 0;
}
/* Sends an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message based on 'fr' to
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 2de7f6f..8048424 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -168,9 +168,8 @@ void connmgr_send_packet_in(struct connmgr *,
void ofconn_send_role_status(struct ofconn *ofconn, uint32_t role,
uint8_t reason);
-enum ofperr
-connmgr_send_requestforward(struct connmgr *, struct ofconn *source,
- uint8_t reason, const struct ofp_header *);
+void connmgr_send_requestforward(struct connmgr *, const struct ofconn *source,
+ const struct ofputil_requestforward *);
/* Fail-open settings. */
enum ofproto_fail_mode connmgr_get_fail_mode(const struct connmgr *);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 99b743c..c1301b5 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -5909,8 +5909,11 @@ handle_meter_mod(struct ofconn *ofconn, const struct
ofp_header *oh)
}
if (!error) {
- error = connmgr_send_requestforward(ofproto->connmgr, ofconn,
- OFPRFR_METER_MOD, oh);
+ struct ofputil_requestforward rf;
+ rf.xid = oh->xid;
+ rf.reason = OFPRFR_METER_MOD;
+ rf.meter_mod = &mm;
+ connmgr_send_requestforward(ofproto->connmgr, ofconn, &rf);
}
exit_free_bands:
@@ -6609,8 +6612,11 @@ handle_group_mod(struct ofconn *ofconn, const struct
ofp_header *oh)
}
if (!error) {
- error = connmgr_send_requestforward(ofproto->connmgr, ofconn,
- OFPRFR_GROUP_MOD, oh);
+ struct ofputil_requestforward rf;
+ rf.xid = oh->xid;
+ rf.reason = OFPRFR_GROUP_MOD;
+ rf.group_mod = &gm;
+ connmgr_send_requestforward(ofproto->connmgr, ofconn, &rf);
}
return error;
}
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 38d8ba6..7e80293 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2904,7 +2904,7 @@ dnl command is sent from one controller and the reply is
received by
dnl other controllers.
AT_SETUP([ofproto - requestforward (OpenFlow 1.4)])
OVS_VSWITCHD_START
-ON_EXIT([kill `cat c1.pid c2.pid c3.pid`])
+on_exit 'kill `cat c1.pid c2.pid c3.pid`'
# Start two ovs-ofctl controller processes.
AT_CAPTURE_FILE([monitor1.log])
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev