Signed-off-by: Alexandru Copot <alex.miha...@gmail.com>
Cc: Daniel Baluta <dbal...@ixiacom.com>
---
 lib/learning-switch.c |   2 +
 lib/ofp-errors.h      |  52 +++++++++++
 lib/ofp-msgs.h        |  10 ++
 lib/ofp-print.c       |  95 +++++++++++++++++++
 lib/ofp-util.c        |  57 ++++++++++++
 lib/ofp-util.h        |  20 ++++
 lib/rconn.c           |   2 +
 ofproto/automake.mk   |   5 +-
 ofproto/bundles.c     | 252 ++++++++++++++++++++++++++++++++++++++++++++++++++
 ofproto/bundles.h     |  53 +++++++++++
 ofproto/connmgr.c     |  23 +++++
 ofproto/connmgr.h     |   3 +
 ofproto/ofproto.c     |  73 +++++++++++++++
 13 files changed, 646 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 5620990..adb276f 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(msg->data, msg->size, 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..bfc94b2 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, uint8_t[16][]. */
+    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 4c48ca6..b9f4077 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -2292,6 +2292,9 @@ ofp_print_version(const struct ofp_header *oh,
     case OFP13_VERSION:
         ds_put_cstr(string, " (OF1.3)");
         break;
+    case OFP14_VERSION:
+        ds_put_cstr(string, " (OF1.4)");
+        break;
     default:
         ds_put_format(string, " (OF 0x%02"PRIx8")", oh->version);
         break;
@@ -2508,6 +2511,90 @@ ofp_print_group_mod(struct ds *s, const struct 
ofp_header *oh)
     ofp_print_group(s, gm.group_id, gm.type, &gm.buckets);
 }
 
+static const char *
+bundle_flags_to_name(uint32_t bit)
+{
+    switch (bit) {
+    case OFPBF_ATOMIC:
+        return "atomic";
+    case OFPBF_ORDERED:
+        return "ordered";
+    default:
+        return "UNKNOWN";
+    }
+}
+
+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, (uint32_t)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((const void*)&badd.msg, ntohs(badd.msg.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)
@@ -2753,6 +2840,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 9a563eb..4edb11f 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -6721,3 +6721,60 @@ 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 = b.l3;
+    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 = b.l3;
+    msg->bundle_id = ntohl(m->bundle_id);
+    msg->flags = ntohs(m->flags);
+    memcpy(&msg->msg, &m->message, sizeof(msg->msg));
+
+    return 0;
+}
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index a4143ad..6ca2507 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -1050,4 +1050,24 @@ 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;
+    struct ofp_header   msg;
+};
+
+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 72688ba..30dd91d 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1344,6 +1344,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 1308820..6ff7f44 100644
--- a/ofproto/automake.mk
+++ b/ofproto/automake.mk
@@ -43,7 +43,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..41efa12
--- /dev/null
+++ b/ofproto/bundles.c
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ *
+ * Alexandru Copot <alex.miha...@gmail.com>, with support from IXIA.
+ *
+ * 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 ovs_mutex  list_mutex;
+};
+
+struct bundle_message {
+       struct ofp_header msg;
+       struct list       node;  /* Element in 'struct ofp_bundles's msg_list */
+};
+
+static uint32_t
+ofp_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, ofp_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);
+    ovs_mutex_init(&bundle->list_mutex);
+
+    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);
+    }
+
+    bundles = ofconn_lock_bundles(ofconn);
+    hmap_remove(bundles, &item->node);
+    ofconn_unlock_bundles(ofconn);
+
+    free(item);
+}
+
+enum ofperr
+ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t flags)
+{
+    struct hmap *bundles;
+    struct ofp_bundle *bundle;
+
+    bundles = ofconn_lock_bundles(ofconn);
+    bundle = ofp_bundle_find(bundles, id);
+    ofconn_unlock_bundles(ofconn);
+
+    if (bundle) {
+        VLOG_INFO("Bundle %x already exists.\n", 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_lock_bundles(ofconn);
+    hmap_insert(bundles, &bundle->node, hash_int(id, 10));
+    ofconn_unlock_bundles(ofconn);
+
+    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_lock_bundles(ofconn);
+    bundle = ofp_bundle_find(bundles, id);
+    ofconn_unlock_bundles(ofconn);
+
+    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_lock_bundles(ofconn);
+    bundle = ofp_bundle_find(bundles, id);
+    ofconn_unlock_bundles(ofconn);
+
+    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_lock_bundles(ofconn);
+    bundle = ofp_bundle_find(bundles, id);
+    ofconn_unlock_bundles(ofconn);
+
+    if (!bundle) {
+        return OFPERR_OFPBFC_BAD_ID;
+    }
+
+    ofp_bundle_remove(ofconn, bundle);
+
+    return 0;
+}
+
+enum ofperr
+ofp_bundle_add_message(struct ofconn *ofconn, uint32_t id, uint16_t flags,
+        struct ofp_header *msg)
+{
+    struct hmap *bundles;
+    struct ofp_bundle *bundle;
+    struct bundle_message *bmsg;
+
+    bundles = ofconn_lock_bundles(ofconn);
+    bundle = ofp_bundle_find(bundles, id);
+    ofconn_unlock_bundles(ofconn);
+
+    if (!bundle) {
+        bundle = ofp_bundle_create(id, flags);
+        bundle->state = BS_OPEN;
+
+        bundles = ofconn_lock_bundles(ofconn);
+        hmap_insert(bundles, &bundle->node, hash_int(id, 10));
+        ofconn_unlock_bundles(ofconn);
+    }
+
+    if (bundle->state == BS_CLOSED) {
+        ofp_bundle_remove(ofconn, bundle);
+        return OFPERR_OFPBFC_BUNDLE_CLOSED;
+    }
+
+    bmsg = xmalloc(sizeof(*bmsg));
+    bmsg->msg = *msg;
+
+    ovs_mutex_lock(&bundle->list_mutex);
+    list_push_back(&bundle->msg_list, &bmsg->node);
+    ovs_mutex_unlock(&bundle->list_mutex);
+
+    return 0;
+}
diff --git a/ofproto/bundles.h b/ofproto/bundles.h
new file mode 100644
index 0000000..396d0cb
--- /dev/null
+++ b/ofproto/bundles.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ *
+ * Alexandru Copot <alex.miha...@gmail.com>, with support from IXIA.
+ *
+ * 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"
+
+#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, uint32_t id, uint16_t flags,
+                       struct ofp_header *msg);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 033ab7d..c5a6efb 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -129,6 +129,10 @@ 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;
+    struct ovs_mutex bundles_mutex;
 };
 
 static struct ofconn *ofconn_create(struct connmgr *, struct rconn *,
@@ -1136,6 +1140,22 @@ ofconn_add_opgroup(struct ofconn *ofconn, struct list 
*ofconn_node)
 {
     list_push_back(&ofconn->opgroups, ofconn_node);
 }
+
+struct hmap *
+ofconn_lock_bundles(struct ofconn *ofconn)
+OVS_ACQUIRES(&ofconn->bundles_mutex)
+{
+    ovs_mutex_lock(&ofconn->bundles_mutex);
+    return &ofconn->bundles;
+}
+
+void
+ofconn_unlock_bundles(struct ofconn *ofconn)
+OVS_RELEASES(&ofconn->bundles_mutex)
+{
+    ovs_mutex_unlock(&ofconn->bundles_mutex);
+}
+
 
 /* Private ofconn functions. */
 
@@ -1163,6 +1183,9 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, 
enum ofconn_type type,
     hmap_init(&ofconn->monitors);
     list_init(&ofconn->updates);
 
+    hmap_init(&ofconn->bundles);
+    ovs_mutex_init(&ofconn->bundles_mutex);
+
     ofconn_flush(ofconn);
 
     return ofconn;
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 3c9216f..bb7caf7 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -146,6 +146,9 @@ 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_lock_bundles(struct ofconn *ofconn);
+void ofconn_unlock_bundles(struct ofconn *ofconn);
+
 /* Sending asynchronous messages. */
 void connmgr_send_port_status(struct connmgr *, struct ofconn *source,
                               const struct ofputil_phy_port *, uint8_t reason);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 19e7091..9e06daa 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -57,6 +57,7 @@
 #include "unaligned.h"
 #include "unixctl.h"
 #include "vlog.h"
+#include "bundles.h"
 
 VLOG_DEFINE_THIS_MODULE(ofproto);
 
@@ -5838,6 +5839,72 @@ 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;
+    }
+
+    error = ofp_bundle_add_message(ofconn, badd.bundle_id,
+                                   badd.flags, &badd.msg);
+
+    return error;
+}
+
+static enum ofperr
 handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
     OVS_EXCLUDED(ofproto_mutex)
 {
@@ -5969,6 +6036,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.0

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to