[ovs-dev] [PATCH v1 2/2] ofproto: Implement OF1.4 Group & Meter change notification messages
niti1489 at gmail.com
niti1489 at gmail.com
Thu Jul 23 11:36:36 UTC 2015
From: Niti Rohilla <niti.rohilla at tcs.com>
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 <niti.rohilla at tcs.com>
---
include/openflow/openflow-1.4.h | 6 ++++
lib/learning-switch.c | 1 +
lib/ofp-msgs.h | 6 ++++
lib/ofp-print.c | 38 +++++++++++++++++++++
lib/ofp-util.c | 49 ++++++++++++++++++++++++++
lib/ofp-util.h | 12 +++++++
lib/rconn.c | 1 +
ofproto/connmgr.c | 35 +++++++++++++++++++
ofproto/connmgr.h | 3 ++
ofproto/ofproto.c | 25 +++++++++++---
ovn/controller/ofctrl.c | 1 +
tests/ofp-print.at | 46 +++++++++++++++++++++++++
tests/ofproto.at | 76 +++++++++++++++++++++++++++++++++++++++++
13 files changed, 294 insertions(+), 5 deletions(-)
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index 567aaae..3543b25 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -343,6 +343,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,
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 1753cea..7ddf69b 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -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:
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 3d9fedf..cbcd6cc 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -241,6 +241,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,
@@ -550,6 +553,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. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 4603bb7..71e953b 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2804,6 +2804,40 @@ ofp_print_geneve_table_reply(struct ds *s, const struct ofp_header *oh)
ofputil_uninit_geneve_table(>r.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;
+ enum ofptype type;
+
+ error = ofputil_decode_requestforward(oh, &rf);
+ if (error) {
+ ofp_print_error(string, error);
+ 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) {
+ ds_put_cstr(string, "group_mod");
+ ofp_print_group_mod(string, rf.request);
+ } else if (type == OFPTYPE_METER_MOD) {
+ ds_put_cstr(string, "meter_mod");
+ ofp_print_meter_mod(string, rf.request);
+ } else {
+ OVS_NOT_REACHED();
+ }
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
@@ -2933,6 +2967,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);
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index cdb8553..ebf0c04 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -5392,6 +5392,54 @@ ofputil_decode_role_status(const struct ofp_header *oh,
return 0;
}
+/* Encodes "request forward" message 'rf' for sending in the given
+ * 'protocol'. Returns the request forward message, if 'protocol' supports
+ * them, otherwise a null pointer.
+ * '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,
+ enum ofputil_protocol protocol)
+{
+ enum ofp_version version;
+
+ version = ofputil_protocol_to_ofp_version(protocol);
+ if (version >= OFP14_VERSION) {
+ struct ofpbuf *buf;
+
+ buf = ofpraw_alloc_xid(OFPRAW_OFPT14_REQUESTFORWARD, version,
+ htonl(0), 0);
+ ofpbuf_put(buf, rf->request, ntohs(rf->request->length));
+ return buf;
+ } else {
+ return NULL;
+ }
+}
+
+/* Converts OpenFlow request forward message 'oh' into an abstract request
+ * forward in 'rf'. Returns 0 if successful, otherwise an OpenFlow error
+ * code. */
+enum ofperr
+ofputil_decode_requestforward(const struct ofp_header *oh,
+ struct ofputil_requestforward *rf)
+{
+ struct ofpbuf b;
+ enum ofpraw raw;
+ enum ofperr error;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ error = ofpraw_pull(&raw, &b);
+ if (error) {
+ return error;
+ }
+
+ ovs_assert(raw == OFPRAW_OFPT14_REQUESTFORWARD);
+
+ rf->request = b.data;
+ return 0;
+}
+
/* Table stats. */
/* OpenFlow 1.0 and 1.1 don't distinguish between a field that cannot be
@@ -9067,6 +9115,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;
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 431f165..5ccce7c 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -861,6 +861,18 @@ 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;
+};
+
+struct ofpbuf *
+ofputil_encode_requestforward(const struct ofputil_requestforward *rf,
+ enum ofputil_protocol protocol);
+
+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
diff --git a/lib/rconn.c b/lib/rconn.c
index 37adfa2..0a9966a 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -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:
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 302d9ce..4749043 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -1684,6 +1684,41 @@ connmgr_send_port_status(struct connmgr *mgr, struct ofconn *source,
}
}
+/* Sends an OFPT_REQUESTFORWARD message with 'request' and 'reason' to
+ * appropriate controllers managed by 'mgr'. For messages caused by a
+ * controller OFPT_GROUP_MOD and OFPT_METER_MOD, specify 'source' as the
+ * controller connection that sent the request; otherwise, specify 'source'
+ * as NULL. */
+void
+connmgr_send_requestforward(struct connmgr *mgr, struct ofconn *source,
+ uint8_t reason, const struct ofp_header *request)
+{
+ struct ofputil_requestforward rf;
+ struct ofconn *ofconn;
+
+ rf.request = request;
+ LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
+ if (ofconn_receives_async_msg(ofconn, OAM_REQUESTFORWARD, reason)) {
+ struct ofpbuf *msg;
+
+ /* 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;
+ }
+
+ msg = ofputil_encode_requestforward(&rf,
+ ofconn_get_protocol(ofconn));
+ ofconn_send(ofconn, msg, NULL);
+ }
+ }
+}
+
/* Sends an OFPT_FLOW_REMOVED or NXT_FLOW_REMOVED message based on 'fr' to
* appropriate controllers managed by 'mgr'. */
void
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 0e1a5b1..8a1b336 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -176,6 +176,9 @@ void connmgr_send_packet_in(struct connmgr *,
void ofconn_send_role_status(struct ofconn *ofconn, uint32_t role,
uint8_t reason);
+void connmgr_send_requestforward(struct connmgr *, struct ofconn *source,
+ uint8_t reason, const struct ofp_header *);
+
/* Fail-open settings. */
enum ofproto_fail_mode connmgr_get_fail_mode(const struct connmgr *);
void connmgr_set_fail_mode(struct connmgr *, enum ofproto_fail_mode);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 616c04c..8f1abed 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -5924,6 +5924,10 @@ handle_meter_mod(struct ofconn *ofconn, const struct ofp_header *oh)
break;
}
+ if (!error) {
+ connmgr_send_requestforward(ofproto->connmgr, ofconn, OFPRFR_METER_MOD, oh);
+ }
+
exit_free_bands:
ofpbuf_uninit(&bands);
return error;
@@ -6591,20 +6595,25 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
switch (gm.command) {
case OFPGC11_ADD:
- return add_group(ofproto, &gm);
+ error = add_group(ofproto, &gm);
+ break;
case OFPGC11_MODIFY:
- return modify_group(ofproto, &gm);
+ error = modify_group(ofproto, &gm);
+ break;
case OFPGC11_DELETE:
delete_group(ofproto, gm.group_id);
- return 0;
+ error = 0;
+ break;
case OFPGC15_INSERT_BUCKET:
- return modify_group(ofproto, &gm);
+ error = modify_group(ofproto, &gm);
+ break;
case OFPGC15_REMOVE_BUCKET:
- return modify_group(ofproto, &gm);
+ error = modify_group(ofproto, &gm);
+ break;
default:
if (gm.command > OFPGC11_DELETE) {
@@ -6613,6 +6622,11 @@ handle_group_mod(struct ofconn *ofconn, const struct ofp_header *oh)
}
return OFPERR_OFPGMFC_BAD_COMMAND;
}
+
+ if (!error) {
+ connmgr_send_requestforward(ofproto->connmgr, ofconn, OFPRFR_GROUP_MOD, oh);
+ }
+ return error;
}
enum ofputil_table_miss
@@ -7227,6 +7241,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
+ case OFPTYPE_REQUESTFORWARD:
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
default:
if (ofpmsg_is_stat_request(oh)) {
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index 843e1a1..3732e90 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -197,6 +197,7 @@ ofctrl_recv(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:
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 6e11150..55cfa72 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -2676,6 +2676,52 @@ OFPT_ROLE_STATUS (OF1.4) (xid=0xa): role=master generation_id=16 reason=configur
])
AT_CLEANUP
+AT_SETUP([OFP_REQUESTFORWARD - OF1.4])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+05 20 00 18 00 00 00 02 \
+05 0f 00 10 02 00 00 00 \
+00 00 00 00 00 00 00 01 \
+"], [0], [dnl
+OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=group_mod
+ ADD group_id=1,type=all
+])
+AT_CLEANUP
+
+AT_SETUP([OFP_REQUESTFORWARD - OF1.4])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+05 20 00 18 00 00 00 02 \
+05 0f 00 10 02 00 00 00 \
+00 01 01 00 00 00 00 01 \
+"], [0], [dnl
+OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=group_mod
+ MOD group_id=1,type=select
+])
+AT_CLEANUP
+
+AT_SETUP([OFP_REQUESTFORWARD - OF1.4])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+05 20 00 18 00 00 00 02 \
+05 1d 00 10 02 00 00 00 \
+00 00 00 00 00 00 00 01 \
+"], [0], [dnl
+OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=meter_mod ADD meter=1 bands=
+])
+AT_CLEANUP
+
+AT_SETUP([OFP_REQUESTFORWARD - OF1.4])
+AT_KEYWORDS([ofp-print])
+AT_CHECK([ovs-ofctl ofp-print "\
+05 20 00 18 00 00 00 02 \
+05 1d 00 10 02 00 00 00 \
+00 01 01 00 00 00 00 01 \
+"], [0], [dnl
+OFPT_REQUESTFORWARD (OF1.4) (xid=0x2): reason=meter_mod MOD meter=1 flags:0x100 bands=
+])
+AT_CLEANUP
+
AT_SETUP([NXT_SET_PACKET_IN])
AT_KEYWORDS([ofp-print])
AT_CHECK([ovs-ofctl ofp-print "\
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 7d78b57..2e18886 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -2721,6 +2721,82 @@ done
OVS_VSWITCHD_STOP
AT_CLEANUP
+dnl This test checks the Group and meter notifications when a group mod
+dnl command is sent from one controller and the reply is received by
+dnl other controller.
+AT_SETUP([ofproto - requestforward (OpenFlow 1.4)])
+OVS_VSWITCHD_START
+ON_EXIT([kill `cat c1.pid c2.pid`])
+
+# Start two ovs-ofctl controller processes.
+AT_CAPTURE_FILE([monitor1.log])
+AT_CAPTURE_FILE([expout1])
+AT_CAPTURE_FILE([monitor2.log])
+AT_CAPTURE_FILE([expout2])
+for i in 1 2; do
+ AT_CHECK([ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile=`pwd`/c$i.pid --unixctl=`pwd`/c$i])
+done
+
+check_async () {
+ for i in 1 2; do
+ ovs-appctl -t `pwd`/c$i ofctl/barrier
+ ovs-appctl -t `pwd`/c$i ofctl/set-output-file monitor$i.log
+ : > expout$i
+ done
+
+ printf '\n\n--- check_async %d ---\n\n\n' $1
+ INDEX=$1
+ shift
+
+ # OFPGC_ADD
+ ovs-appctl -t `pwd`/c2 ofctl/send 050f0010000000020000000000000001
+ if test X"$1" = X"OFPGC_ADD"; then shift;
+ echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4):
+ ADD group_id=1,type=all"
+ echo >>expout1 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod
+ ADD group_id=1,type=all"
+ fi
+
+ # OFPGC_MODIFY
+ ovs-appctl -t `pwd`/c2 ofctl/send 050f0010000000020001010000000001
+ if test X"$1" = X"OFPGC_MODIFY"; then shift;
+ echo >>expout2 "send: OFPT_GROUP_MOD (OF1.4):
+ MOD group_id=1,type=select"
+ echo >>expout1 "OFPT_REQUESTFORWARD (OF1.4): reason=group_mod
+ MOD group_id=1,type=select"
+ fi
+
+ for i in 1 2; do
+ ovs-appctl -t `pwd`/c$i ofctl/barrier
+ echo >>expout$i "OFPT_BARRIER_REPLY (OF1.4):"
+ done
+
+ # Check output.
+ for i in 1 2; do
+ cp expout$i expout
+ AT_CHECK(
+ [[sed '
+s/ (xid=0x[0-9a-fA-F]*)//'< monitor$i.log]],
+ [0], [expout])
+ done
+}
+
+# controller 1: Become slave
+ovs-appctl -t `pwd`/c1 ofctl/send 051800180000000300000003000000008000000000000002
+
+# controller 2: Become master
+ovs-appctl -t `pwd`/c2 ofctl/send 051800180000000300000002000000008000000000000003
+
+# controller 1: Enabled requestforward using set Asynchronous message
+ovs-appctl -t `pwd`/c1 ofctl/send 051c00280000000200000008000000050002000800000002000400080000001a000a000800000003
+
+# controller 2: Enabled requestforward using set Asynchronous message
+ovs-appctl -t `pwd`/c2 ofctl/send 051c002800000002000100080000000200030008000000050005000800000005000b000800000003
+check_async 1 OFPGC_ADD OFPGC_MODIFY
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
dnl This test checks that OFPT_PACKET_OUT accepts both OFPP_NONE (as
dnl specified by OpenFlow 1.0) and OFPP_CONTROLLER (used by some
dnl controllers despite the spec) as meaning a packet that was generated
--
2.4.4
More information about the dev
mailing list