[ovs-dev] [PATCH v4 1/3] Add basic implementation for OpenFlow 1.4 bundles
Alexandru Copot
alex.mihai.c at gmail.com
Wed Apr 23 11:03:56 UTC 2014
This is only the communication part of the bundles functionality.
The actual message pre-validation and commits are not implemented.
Signed-off-by: Alexandru Copot <alex.mihai.c at gmail.com>
---
v4:
* adjust copyright
* fix style issues
* remove all locking
* delete bundles in ofconn_destroy()
v3:
* rebase
* adjusted to use ofpbuf_l3()
* bug fixes
v2: rebase
---
lib/learning-switch.c | 2 +
lib/ofp-errors.h | 52 ++++++++++
lib/ofp-msgs.h | 10 ++
lib/ofp-print.c | 92 ++++++++++++++++++
lib/ofp-util.c | 58 ++++++++++++
lib/ofp-util.h | 21 +++++
lib/rconn.c | 2 +
ofproto/automake.mk | 5 +-
ofproto/bundles.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++
ofproto/bundles.h | 49 ++++++++++
ofproto/connmgr.c | 16 ++++
ofproto/connmgr.h | 2 +
ofproto/ofproto.c | 70 ++++++++++++++
13 files changed, 634 insertions(+), 1 deletion(-)
create mode 100644 ofproto/bundles.c
create mode 100644 ofproto/bundles.h
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index c818a32..ca57911 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -398,6 +398,8 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
case OFPTYPE_METER_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_BUNDLE_CONTROL:
+ case OFPTYPE_BUNDLE_ADD_MESSAGE:
default:
if (VLOG_IS_DBG_ENABLED()) {
char *s = ofp_to_string(ofpbuf_data(msg), ofpbuf_size(msg), 2);
diff --git a/lib/ofp-errors.h b/lib/ofp-errors.h
index c80a75e..b1bcf7c 100644
--- a/lib/ofp-errors.h
+++ b/lib/ofp-errors.h
@@ -557,6 +557,58 @@ enum ofperr {
/* OF1.3+(13,5). Permissions error. */
OFPERR_OFPTFFC_EPERM,
+/* ## -------------------- ## */
+/* ## OFPET_BUNDLE_FAILED ## */
+/* ## -------------------- ## */
+
+ /* OF1.4+(17,0). Unspecified error. */
+ OFPERR_OFPBFC_UNKNOWN,
+
+ /* OF1.4+(17,1). Permissions error. */
+ OFPERR_OFPBFC_EPERM,
+
+ /* OF1.4+(17,2). Bundle ID doesn't exist. */
+ OFPERR_OFPBFC_BAD_ID,
+
+ /* OF1.4+(17,3). Bundle ID already exists. */
+ OFPERR_OFPBFC_BUNDLE_EXIST,
+
+ /* OF1.4+(17,4). Bundle ID is closed. */
+ OFPERR_OFPBFC_BUNDLE_CLOSED,
+
+ /* OF1.4+(17,5). Too many bundle IDs. */
+ OFPERR_OFPBFC_OUT_OF_BUNDLES,
+
+ /* OF1.4+(17,6). Unsupported of unknown message control type. */
+ OFPERR_OFPBFC_BAD_TYPE,
+
+ /* OF1.4+(17,7). Unsupported, unknown, or inconsistent flags. */
+ OFPERR_OFPBFC_BAD_FLAGS,
+
+ /* OF1.4+(17,8). Length problem in included message. */
+ OFPERR_OFPBFC_MSG_BAD_LEN,
+
+ /* OF1.4+(17,9). Inconsistent or duplicate XID. */
+ OFPERR_OFPBFC_MSG_BAD_XID,
+
+ /* OF1.4+(17,10). Unsupported message in this bundle. */
+ OFPERR_OFPBFC_MSG_UNSUP,
+
+ /* OF1.4+(17,11). Unsupported message combination in this bundle. */
+ OFPERR_OFPBFC_MSG_CONFLICT,
+
+ /* OF1.4+(17,12). Cant handle this many messages in bundle. */
+ OFPERR_OFPBFC_MSG_TOO_MANY,
+
+ /* OF1.4+(17,13). One message in bundle failed. */
+ OFPERR_OFPBFC_MSG_FAILED,
+
+ /* OF1.4+(17,14). Bundle is taking too long. */
+ OFPERR_OFPBFC_TIMEOUT,
+
+ /* OF1.4+(17,15). Bundle is locking the resource. */
+ OFPERR_OFPBFC_BUNDLE_IN_PROGRESS,
+
/* ## ------------------ ## */
/* ## OFPET_EXPERIMENTER ## */
/* ## ------------------ ## */
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index d8dee5b..5cded7c 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -233,6 +233,12 @@ enum ofpraw {
/* OFPT 1.4+ (30): struct ofp14_role_status, uint8_t[8][]. */
OFPRAW_OFPT14_ROLE_STATUS,
+ /* OFPT 1.4+ (33): struct ofp14_bundle_ctrl_msg, uint8_t[8][]. */
+ OFPRAW_OFPT14_BUNDLE_CONTROL,
+
+ /* OFPT 1.4+ (34): struct ofp14_bundle_add_msg, struct ofp_header, uint8_t[]. */
+ OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE,
+
/* Standard statistics. */
/* OFPST 1.0+ (0): void. */
@@ -508,6 +514,10 @@ enum ofptype {
/* Controller role change event messages. */
OFPTYPE_ROLE_STATUS, /* OFPRAW_OFPT14_ROLE_STATUS. */
+ OFPTYPE_BUNDLE_CONTROL, /* OFPRAW_OFPT14_BUNDLE_CONTROL. */
+
+ OFPTYPE_BUNDLE_ADD_MESSAGE, /* OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE. */
+
/* Statistics. */
OFPTYPE_DESC_STATS_REQUEST, /* OFPRAW_OFPST_DESC_REQUEST. */
OFPTYPE_DESC_STATS_REPLY, /* OFPRAW_OFPST_DESC_REPLY. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 9091b1b..b1bd2c3 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2665,6 +2665,90 @@ ofp_print_table_features(struct ds *s, const struct ofp_header *oh)
}
}
+static const char *
+bundle_flags_to_name(uint32_t bit)
+{
+ switch (bit) {
+ case OFPBF_ATOMIC:
+ return "atomic";
+ case OFPBF_ORDERED:
+ return "ordered";
+ default:
+ return NULL;
+ }
+}
+
+static void
+ofp_print_bundle_ctrl(struct ds *s, const struct ofp_header *oh)
+{
+ int error;
+ struct ofputil_bundle_ctrl_msg bctrl;
+
+ error = ofputil_decode_bundle_ctrl(oh, &bctrl);
+ if (error) {
+ ofp_print_error(s, error);
+ return;
+ }
+
+ ds_put_char(s, '\n');
+
+ ds_put_format(s, " bundle_id=%#"PRIx32" type=", bctrl.bundle_id);
+ switch (bctrl.type) {
+ case OFPBCT_OPEN_REQUEST:
+ ds_put_cstr(s, "OPEN_REQUEST");
+ break;
+ case OFPBCT_OPEN_REPLY:
+ ds_put_cstr(s, "OPEN_REPLY");
+ break;
+ case OFPBCT_CLOSE_REQUEST:
+ ds_put_cstr(s, "CLOSE_REQUEST");
+ break;
+ case OFPBCT_CLOSE_REPLY:
+ ds_put_cstr(s, "CLOSE_REPLY");
+ break;
+ case OFPBCT_COMMIT_REQUEST:
+ ds_put_cstr(s, "COMMIT_REQUEST");
+ break;
+ case OFPBCT_COMMIT_REPLY:
+ ds_put_cstr(s, "COMMIT_REPLY");
+ break;
+ case OFPBCT_DISCARD_REQUEST:
+ ds_put_cstr(s, "DISCARD_REQUEST");
+ break;
+ case OFPBCT_DISCARD_REPLY:
+ ds_put_cstr(s, "DISCARD_REPLY");
+ break;
+ }
+
+ ds_put_cstr(s, " flags=");
+ ofp_print_bit_names(s, bctrl.flags, bundle_flags_to_name, ' ');
+}
+
+static void
+ofp_print_bundle_add(struct ds *s, const struct ofp_header *oh, int verbosity)
+{
+ int error;
+ struct ofputil_bundle_add_msg badd;
+ char *msg;
+
+ error = ofputil_decode_bundle_add(oh, &badd);
+ if (error) {
+ ofp_print_error(s, error);
+ return;
+ }
+
+ ds_put_char(s, '\n');
+ ds_put_format(s, " bundle_id=%#"PRIx32, badd.bundle_id);
+ ds_put_cstr(s, " flags=");
+ ofp_print_bit_names(s, badd.flags, bundle_flags_to_name, ' ');
+
+ ds_put_char(s, '\n');
+ msg = ofp_to_string(badd.msg, badd.length, verbosity);
+ if (msg) {
+ ds_put_cstr(s, msg);
+ }
+}
+
static void
ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
struct ds *string, int verbosity)
@@ -2910,6 +2994,14 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
case OFPTYPE_FLOW_MONITOR_STATS_REPLY:
ofp_print_nxst_flow_monitor_reply(string, msg);
break;
+
+ case OFPTYPE_BUNDLE_CONTROL:
+ ofp_print_bundle_ctrl(string, msg);
+ break;
+
+ case OFPTYPE_BUNDLE_ADD_MESSAGE:
+ ofp_print_bundle_add(string, msg, verbosity);
+ break;
}
}
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 3484394..d929b65 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -7054,3 +7054,61 @@ ofputil_append_queue_stat(struct list *replies,
OVS_NOT_REACHED();
}
}
+
+enum ofperr
+ofputil_decode_bundle_ctrl(const struct ofp_header *oh,
+ struct ofputil_bundle_ctrl_msg *msg)
+{
+ struct ofpbuf b;
+ enum ofpraw raw;
+ const struct ofp14_bundle_ctrl_msg *m;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_CONTROL);
+
+ m = ofpbuf_l3(&b);
+ msg->bundle_id = ntohl(m->bundle_id);
+ msg->type = ntohs(m->type);
+ msg->flags = ntohs(m->flags);
+
+ return 0;
+}
+
+struct ofpbuf *
+ofputil_encode_bundle_ctrl_reply(const struct ofp_header *oh,
+ struct ofputil_bundle_ctrl_msg *msg)
+{
+ struct ofpbuf *buf;
+ struct ofp14_bundle_ctrl_msg *m;
+
+ buf = ofpraw_alloc_reply(OFPRAW_OFPT14_BUNDLE_CONTROL, oh, 0);
+ m = ofpbuf_put_zeros(buf, sizeof *m);
+
+ m->bundle_id = htonl(msg->bundle_id);
+ m->type = htons(msg->type);
+ m->flags = htons(msg->flags);
+
+ return buf;
+}
+
+enum ofperr
+ofputil_decode_bundle_add(const struct ofp_header *oh,
+ struct ofputil_bundle_add_msg *msg)
+{
+ struct ofpbuf b;
+ enum ofpraw raw;
+ const struct ofp14_bundle_add_msg *m;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ raw = ofpraw_pull_assert(&b);
+ ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE);
+
+ m = ofpbuf_l3(&b);
+ msg->bundle_id = ntohl(m->bundle_id);
+ msg->flags = ntohs(m->flags);
+ msg->length = ntohs(m->message.length);
+ msg->msg = &m->message;
+
+ return 0;
+}
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 245cc4e..91c6a55 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -1135,4 +1135,25 @@ void ofputil_append_group_desc_reply(const struct ofputil_group_desc *,
struct list *replies);
struct ofpbuf *ofputil_encode_group_desc_request(enum ofp_version);
+struct ofputil_bundle_ctrl_msg {
+ uint32_t bundle_id;
+ uint16_t type;
+ uint16_t flags;
+};
+
+struct ofputil_bundle_add_msg {
+ uint32_t bundle_id;
+ uint16_t flags;
+ const struct ofp_header *msg;
+ uint16_t length;
+};
+
+enum ofperr ofputil_decode_bundle_ctrl(const struct ofp_header *,
+ struct ofputil_bundle_ctrl_msg *);
+
+struct ofpbuf *ofputil_encode_bundle_ctrl_reply(const struct ofp_header *,
+ struct ofputil_bundle_ctrl_msg *);
+
+enum ofperr ofputil_decode_bundle_add(const struct ofp_header *,
+ struct ofputil_bundle_add_msg *);
#endif /* ofp-util.h */
diff --git a/lib/rconn.c b/lib/rconn.c
index cb3cdd5..2c49ca8 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1350,6 +1350,8 @@ is_admitted_msg(const struct ofpbuf *b)
case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_BUNDLE_CONTROL:
+ case OFPTYPE_BUNDLE_ADD_MESSAGE:
return false;
case OFPTYPE_PACKET_IN:
diff --git a/ofproto/automake.mk b/ofproto/automake.mk
index cbdbd6f..22c50d1 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -45,7 +45,10 @@ ofproto_libofproto_la_SOURCES = \
ofproto/pinsched.c \
ofproto/pinsched.h \
ofproto/tunnel.c \
- ofproto/tunnel.h
+ ofproto/tunnel.h \
+ ofproto/bundles.c \
+ ofproto/bundles.h
+
ofproto_libofproto_la_CPPFLAGS = $(AM_CPPFLAGS)
ofproto_libofproto_la_CFLAGS = $(AM_CFLAGS)
ofproto_libofproto_la_LIBADD = lib/libsflow.la
diff --git a/ofproto/bundles.c b/ofproto/bundles.c
new file mode 100644
index 0000000..fa27767
--- /dev/null
+++ b/ofproto/bundles.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2013, 2014 Alexandru Copot <alex.mihai.c at gmail.com>, with support from IXIA.
+ * Copyright (c) 2013, 2014 Daniel Baluta <dbaluta at ixiacom.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "coverage.h"
+#include "fail-open.h"
+#include "in-band.h"
+#include "odp-util.h"
+#include "ofp-actions.h"
+#include "ofp-msgs.h"
+#include "ofp-util.h"
+#include "ofpbuf.h"
+#include "ofproto-provider.h"
+#include "pinsched.h"
+#include "poll-loop.h"
+#include "pktbuf.h"
+#include "rconn.h"
+#include "shash.h"
+#include "simap.h"
+#include "stream.h"
+#include "timeval.h"
+#include "vconn.h"
+#include "vlog.h"
+
+#include "bundles.h"
+
+VLOG_DEFINE_THIS_MODULE(bundles);
+
+enum bundle_state {
+ BS_OPEN,
+ BS_CLOSED
+};
+
+struct ofp_bundle {
+ struct hmap_node node; /* In struct ofconn's "bundles" hmap. */
+ uint32_t id;
+ uint16_t flags;
+ enum bundle_state state;
+
+ /* List of 'struct bundle_message's */
+ struct list msg_list;
+};
+
+struct bundle_message {
+ struct ofp_header *msg;
+ struct list node; /* Element in 'struct ofp_bundles's msg_list */
+};
+
+static uint32_t
+bundle_hash(uint32_t id)
+{
+ return hash_int(id, 0);
+}
+
+static struct ofp_bundle *
+ofp_bundle_find(struct hmap *bundles, uint32_t id)
+{
+ struct ofp_bundle *bundle;
+
+ HMAP_FOR_EACH_IN_BUCKET(bundle, node, bundle_hash(id), bundles) {
+ if (bundle->id == id) {
+ return bundle;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ofp_bundle *
+ofp_bundle_create(uint32_t id, uint16_t flags)
+{
+ struct ofp_bundle *bundle;
+
+ bundle = xmalloc(sizeof(*bundle));
+
+ bundle->id = id;
+ bundle->flags = flags;
+
+ list_init(&bundle->msg_list);
+
+ return bundle;
+}
+
+static void
+ofp_bundle_remove(struct ofconn *ofconn, struct ofp_bundle *item)
+{
+ struct bundle_message *msg, *next;
+ struct hmap *bundles;
+
+ LIST_FOR_EACH_SAFE (msg, next, node, &item->msg_list) {
+ list_remove(&msg->node);
+ free(msg->msg);
+ free(msg);
+ }
+
+ bundles = ofconn_get_bundles(ofconn);
+ hmap_remove(bundles, &item->node);
+
+ free(item);
+}
+
+void
+ofp_bundle_remove_all(struct ofconn *ofconn)
+{
+ struct ofp_bundle *b, *next;
+ struct hmap *bundles;
+
+ bundles = ofconn_get_bundles(ofconn);
+
+ HMAP_FOR_EACH_SAFE (b, next, node, bundles) {
+ ofp_bundle_remove(ofconn, b);
+ }
+}
+
+enum ofperr
+ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+{
+ struct hmap *bundles;
+ struct ofp_bundle *bundle;
+
+ bundles = ofconn_get_bundles(ofconn);
+ bundle = ofp_bundle_find(bundles, id);
+
+ if (bundle) {
+ VLOG_INFO("Bundle %x already exists.", id);
+ ofp_bundle_remove(ofconn, bundle);
+
+ return OFPERR_OFPBFC_BAD_ID;
+ }
+
+ /* TODO: Check the limit of open bundles */
+
+ bundle = ofp_bundle_create(id, flags);
+ bundle->state = BS_OPEN;
+
+ bundles = ofconn_get_bundles(ofconn);
+ hmap_insert(bundles, &bundle->node, bundle_hash(id));
+
+ return 0;
+}
+
+enum ofperr
+ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+{
+ struct hmap *bundles;
+ struct ofp_bundle *bundle;
+
+ bundles = ofconn_get_bundles(ofconn);
+ bundle = ofp_bundle_find(bundles, id);
+
+ if (!bundle) {
+ return OFPERR_OFPBFC_BAD_ID;
+ }
+
+ if (bundle->state == BS_CLOSED) {
+ ofp_bundle_remove(ofconn, bundle);
+ return OFPERR_OFPBFC_BUNDLE_CLOSED;
+ }
+
+ if (bundle->flags != flags) {
+ ofp_bundle_remove(ofconn, bundle);
+ return OFPERR_OFPBFC_BAD_FLAGS;
+ }
+
+ bundle->state = BS_CLOSED;
+ return 0;
+}
+
+enum ofperr
+ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+{
+ struct hmap *bundles;
+ struct ofp_bundle *bundle;
+
+ bundles = ofconn_get_bundles(ofconn);
+ bundle = ofp_bundle_find(bundles, id);
+
+ if (!bundle) {
+ return OFPERR_OFPBFC_BAD_ID;
+ }
+ if (bundle->flags != flags) {
+ ofp_bundle_remove(ofconn, bundle);
+ return OFPERR_OFPBFC_BAD_FLAGS;
+ }
+
+ /* TODO: actual commit */
+
+ return 0;
+}
+
+enum ofperr
+ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
+{
+ struct hmap *bundles;
+ struct ofp_bundle *bundle;
+
+ bundles = ofconn_get_bundles(ofconn);
+ bundle = ofp_bundle_find(bundles, id);
+
+ if (!bundle) {
+ return OFPERR_OFPBFC_BAD_ID;
+ }
+
+ ofp_bundle_remove(ofconn, bundle);
+
+ return 0;
+}
+
+enum ofperr
+ofp_bundle_add_message(struct ofconn *ofconn, struct ofputil_bundle_add_msg *badd)
+{
+ struct ofp_header *msg;
+ struct hmap *bundles;
+ struct ofp_bundle *bundle;
+ struct bundle_message *bmsg;
+
+ bundles = ofconn_get_bundles(ofconn);
+ bundle = ofp_bundle_find(bundles, badd->bundle_id);
+
+ if (!bundle) {
+ bundle = ofp_bundle_create(badd->bundle_id, badd->flags);
+ bundle->state = BS_OPEN;
+
+ bundles = ofconn_get_bundles(ofconn);
+ hmap_insert(bundles, &bundle->node, bundle_hash(badd->bundle_id));
+ }
+
+ if (bundle->state == BS_CLOSED) {
+ ofp_bundle_remove(ofconn, bundle);
+ return OFPERR_OFPBFC_BUNDLE_CLOSED;
+ }
+
+ msg = xmemdup(badd->msg, badd->length);
+
+ bmsg = xmalloc(sizeof(*bmsg));
+ bmsg->msg = msg;
+
+ list_push_back(&bundle->msg_list, &bmsg->node);
+
+ return 0;
+}
diff --git a/ofproto/bundles.h b/ofproto/bundles.h
new file mode 100644
index 0000000..9a6dfa5
--- /dev/null
+++ b/ofproto/bundles.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, 2014 Alexandru Copot <alex.mihai.c at gmail.com>, with support from IXIA.
+ * Copyright (c) 2013, 2014 Daniel Baluta <dbaluta at ixiacom.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef BUNDLES_H
+#define BUNDLES_H 1
+
+#include <sys/types.h>
+
+#include "ofp-msgs.h"
+#include "connmgr.h"
+#include "ofp-util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum ofperr ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t flags);
+
+enum ofperr ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t flags);
+
+enum ofperr ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags);
+
+enum ofperr ofp_bundle_discard(struct ofconn *ofconn, uint32_t id);
+
+enum ofperr ofp_bundle_add_message(struct ofconn *ofconn,
+ struct ofputil_bundle_add_msg *badd);
+
+void ofp_bundle_remove_all(struct ofconn *ofconn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 383fbda..ddaa9b4 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -41,6 +41,8 @@
#include "vconn.h"
#include "vlog.h"
+#include "bundles.h"
+
VLOG_DEFINE_THIS_MODULE(connmgr);
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
@@ -129,6 +131,9 @@ struct ofconn {
* contains an update event of type NXFME_ABBREV and false otherwise.. */
struct list updates OVS_GUARDED_BY(ofproto_mutex);
bool sent_abbrev_update OVS_GUARDED_BY(ofproto_mutex);
+
+ /* Active bundles. Contains "struct ofp_bundle"s. */
+ struct hmap bundles;
};
static struct ofconn *ofconn_create(struct connmgr *, struct rconn *,
@@ -1136,6 +1141,13 @@ ofconn_add_opgroup(struct ofconn *ofconn, struct list *ofconn_node)
{
list_push_back(&ofconn->opgroups, ofconn_node);
}
+
+struct hmap *
+ofconn_get_bundles(struct ofconn *ofconn)
+{
+ return &ofconn->bundles;
+}
+
/* Private ofconn functions. */
@@ -1163,6 +1175,8 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type,
hmap_init(&ofconn->monitors);
list_init(&ofconn->updates);
+ hmap_init(&ofconn->bundles);
+
ofconn_flush(ofconn);
return ofconn;
@@ -1263,6 +1277,8 @@ ofconn_destroy(struct ofconn *ofconn)
hmap_remove(&ofconn->connmgr->controllers, &ofconn->hmap_node);
}
+ ofp_bundle_remove_all(ofconn);
+
hmap_destroy(&ofconn->monitors);
list_remove(&ofconn->node);
rconn_destroy(ofconn->rconn);
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 20c8160..7f69d4f 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -161,6 +161,8 @@ void ofconn_add_opgroup(struct ofconn *, struct list *);
void ofconn_remove_opgroup(struct ofconn *, struct list *,
const struct ofp_header *request, int error);
+struct hmap *ofconn_get_bundles(struct ofconn *ofconn);
+
/* Sending asynchronous messages. */
bool connmgr_wants_packet_in_on_miss(struct connmgr *mgr);
void connmgr_send_port_status(struct connmgr *, struct ofconn *source,
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f16005c..de7f8d8 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -58,6 +58,7 @@
#include "unaligned.h"
#include "unixctl.h"
#include "vlog.h"
+#include "bundles.h"
VLOG_DEFINE_THIS_MODULE(ofproto);
@@ -5924,6 +5925,69 @@ handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
}
static enum ofperr
+handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh)
+{
+ enum ofperr error;
+ struct ofputil_bundle_ctrl_msg bctrl;
+ struct ofpbuf *buf;
+ struct ofputil_bundle_ctrl_msg reply;
+
+ error = ofputil_decode_bundle_ctrl(oh, &bctrl);
+ if (error) {
+ return error;
+ }
+ reply.flags = 0;
+ reply.bundle_id = bctrl.bundle_id;
+
+ switch (bctrl.type) {
+ case OFPBCT_OPEN_REQUEST:
+ error = ofp_bundle_open(ofconn, bctrl.bundle_id, bctrl.flags);
+ reply.type = OFPBCT_OPEN_REPLY;
+ break;
+ case OFPBCT_CLOSE_REQUEST:
+ error = ofp_bundle_close(ofconn, bctrl.bundle_id, bctrl.flags);
+ reply.type = OFPBCT_CLOSE_REPLY;;
+ break;
+ case OFPBCT_COMMIT_REQUEST:
+ error = ofp_bundle_commit(ofconn, bctrl.bundle_id, bctrl.flags);
+ reply.type = OFPBCT_COMMIT_REPLY;
+ break;
+ case OFPBCT_DISCARD_REQUEST:
+ error = ofp_bundle_discard(ofconn, bctrl.bundle_id);
+ reply.type = OFPBCT_DISCARD_REPLY;
+ break;
+
+ case OFPBCT_OPEN_REPLY:
+ case OFPBCT_CLOSE_REPLY:
+ case OFPBCT_COMMIT_REPLY:
+ case OFPBCT_DISCARD_REPLY:
+ return OFPERR_OFPBFC_BAD_TYPE;
+ break;
+ }
+
+ if (!error) {
+ buf = ofputil_encode_bundle_ctrl_reply(oh, &reply);
+ ofconn_send_reply(ofconn, buf);
+ }
+ return error;
+}
+
+
+static enum ofperr
+handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
+{
+ enum ofperr error;
+ struct ofputil_bundle_add_msg badd;
+
+ error = ofputil_decode_bundle_add(oh, &badd);
+ if (error) {
+ return error;
+ }
+
+ return ofp_bundle_add_message(ofconn, &badd);
+}
+
+static enum ofperr
handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
OVS_EXCLUDED(ofproto_mutex)
{
@@ -6055,6 +6119,12 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_QUEUE_GET_CONFIG_REQUEST:
return handle_queue_get_config_request(ofconn, oh);
+ case OFPTYPE_BUNDLE_CONTROL:
+ return handle_bundle_control(ofconn, oh);
+
+ case OFPTYPE_BUNDLE_ADD_MESSAGE:
+ return handle_bundle_add(ofconn, oh);
+
case OFPTYPE_HELLO:
case OFPTYPE_ERROR:
case OFPTYPE_FEATURES_REPLY:
--
1.9.2
More information about the dev
mailing list