From 777af88d50b8271a8cc8f0a79d17022944481506 Mon Sep 17 00:00:00 2001 From: Alexandru Copot Date: Fri, 2 May 2014 09:54:27 +0300 Subject: [PATCH] Add basic implementation for OpenFlow 1.4 bundles This is only the communication part of the bundles functionality. The actual message pre-validation and commits are not implemented. We also enable OF1.4 for all the tests. Signed-off-by: Alexandru Copot Cc: Daniel Baluta [blp@nicira.com made ofputil_decode_bundle_add() more obviously correct] Signed-off-by: Ben Pfaff --- include/openflow/openflow-1.4.h | 31 ++-- lib/learning-switch.c | 2 + lib/ofp-errors.h | 52 +++++++ lib/ofp-msgs.h | 10 ++ lib/ofp-print.c | 92 ++++++++++++ lib/ofp-util.c | 80 ++++++++++ lib/ofp-util.h | 23 +++ lib/rconn.c | 2 + ofproto/automake.mk | 5 +- ofproto/bundles.c | 251 ++++++++++++++++++++++++++++++++ ofproto/bundles.h | 49 +++++++ ofproto/connmgr.c | 16 ++ ofproto/connmgr.h | 2 + ofproto/ofproto.c | 70 +++++++++ tests/ofp-print.at | 125 ++++++++++++++++ tests/ofproto-macros.at | 4 +- tests/ofproto.at | 234 +++++++++++++++++++++++++++++ 17 files changed, 1024 insertions(+), 24 deletions(-) create mode 100644 ofproto/bundles.c create mode 100644 ofproto/bundles.h diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h index 6efa3b9e9..cf83c61fc 100644 --- a/include/openflow/openflow-1.4.h +++ b/include/openflow/openflow-1.4.h @@ -171,31 +171,20 @@ enum ofp14_bundle_flags { OFPBF_ORDERED = 1 << 1, /* Execute in specified order. */ }; -/* Message structure for ONF_ET_BUNDLE_CONTROL. */ +/* Message structure for OFPT_BUNDLE_CONTROL and OFPT_BUNDLE_ADD_MESSAGE. */ struct ofp14_bundle_ctrl_msg { ovs_be32 bundle_id; /* Identify the bundle. */ - ovs_be16 type; /* OFPBCT_*. */ + ovs_be16 type; /* OFPT_BUNDLE_CONTROL: one of OFPBCT_*. + * OFPT_BUNDLE_ADD_MESSAGE: not used. */ ovs_be16 flags; /* Bitmap of OFPBF_* flags. */ - /* Bundle Property list. */ - /* struct ofp14_bundle_prop_header properties[0]; */ + /* Followed by: + * - For OFPT_BUNDLE_ADD_MESSAGE only, an encapsulated OpenFlow message, + * beginning with an ofp_header whose xid is identical to this message's + * outer xid. + * - For OFPT_BUNDLE_ADD_MESSAGE only, and only if at least one property is + * present, 0 to 7 bytes of padding to align on a 64-bit boundary. + * - Zero or more properties (see struct ofp14_bundle_prop_header). */ }; OFP_ASSERT(sizeof(struct ofp14_bundle_ctrl_msg) == 8); -/* Message structure for OFP_BUNDLE_ADD_MESSAGE. -* Adding a message in a bundle is done with. */ -struct ofp14_bundle_add_msg { - ovs_be32 bundle_id; /* Identify the bundle. */ - uint8_t pad[2]; /* Align to 64 bits. */ - ovs_be16 flags; /* Bitmap of ONF_BF_* flags. */ - - struct ofp_header message; /* Message added to the bundle. */ - - /* If there is one property or more, 'message' is followed by: - * - Exactly (message.length + 7)/8*8 - (message.length) (between 0 and 7) - * bytes of all-zero bytes */ - - /* Bundle Property list. */ - /* struct ofp14_bundle_prop_header properties[0]; */ -}; -OFP_ASSERT(sizeof(struct ofp14_bundle_add_msg) == 16); #endif /* openflow/openflow-1.4.h */ diff --git a/lib/learning-switch.c b/lib/learning-switch.c index c818a3213..ca579116f 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 c80a75eb0..b1bcf7cc1 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 d8dee5b53..ded904265 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_ctrl_msg, 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 38e228c9d..a2e515d2d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -2668,6 +2668,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, 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) @@ -2913,6 +2997,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 3484394c5..d17811348 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -7054,3 +7054,83 @@ 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) +{ + const struct ofp14_bundle_ctrl_msg *m; + struct ofpbuf b; + enum ofpraw raw; + size_t inner_len; + + ofpbuf_use_const(&b, oh, ntohs(oh->length)); + raw = ofpraw_pull_assert(&b); + ovs_assert(raw == OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE); + + m = ofpbuf_pull(&b, sizeof *m); + msg->bundle_id = ntohl(m->bundle_id); + msg->flags = ntohs(m->flags); + + msg->msg = ofpbuf_data(&b); + inner_len = ntohs(msg->msg->length); + if (inner_len < sizeof(struct ofp_header) || inner_len > ofpbuf_size(&b)) { + return OFPERR_OFPBFC_MSG_BAD_LEN; + } + + return 0; +} + +struct ofpbuf * +ofputil_encode_bundle_add(enum ofp_version ofp_version, + struct ofputil_bundle_add_msg *msg) +{ + struct ofpbuf *request; + struct ofp14_bundle_ctrl_msg *m; + + request = ofpraw_alloc(OFPRAW_OFPT14_BUNDLE_ADD_MESSAGE, ofp_version, 0); + m = ofpbuf_put_zeros(request, sizeof *m); + + m->bundle_id = htonl(msg->bundle_id); + m->flags = htons(msg->flags); + ofpbuf_put(request, msg->msg, ntohs(msg->msg->length)); + + return request; +} diff --git a/lib/ofp-util.h b/lib/ofp-util.h index 7c2803461..782e512a2 100644 --- a/lib/ofp-util.h +++ b/lib/ofp-util.h @@ -1137,4 +1137,27 @@ 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; +}; + +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 *); + +struct ofpbuf *ofputil_encode_bundle_add(enum ofp_version ofp_version, + struct ofputil_bundle_add_msg *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 cb3cdd5d4..2c49ca850 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 cbdbd6f05..22c50d10a 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 000000000..990446561 --- /dev/null +++ b/ofproto/bundles.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2013, 2014 Alexandru Copot , with support from IXIA. + * Copyright (c) 2013, 2014 Daniel Baluta + * + * 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 + +#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 OFPERR_OFPBFC_MSG_UNSUP; +} + +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 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; + } + + bmsg = xmalloc(sizeof *bmsg); + bmsg->msg = xmemdup(badd->msg, ntohs(badd->msg->length)); + 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 000000000..9a6dfa5a1 --- /dev/null +++ b/ofproto/bundles.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2013, 2014 Alexandru Copot , with support from IXIA. + * Copyright (c) 2013, 2014 Daniel Baluta + * + * 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 + +#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 9a5167de8..75d616cfc 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 20c81605e..7f69d4f5a 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 eb1f3be8a..7ccff438c 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); @@ -5931,6 +5932,69 @@ handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh) return table_mod(ofproto, &tm); } +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) @@ -6063,6 +6127,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: diff --git a/tests/ofp-print.at b/tests/ofp-print.at index b74b681a7..ba1abf1e3 100644 --- a/tests/ofp-print.at +++ b/tests/ofp-print.at @@ -2807,3 +2807,128 @@ NXST_FLOW_MONITOR reply (xid=0x4): event=ABBREV xid=0x186a0 ]) AT_CLEANUP + + +AT_SETUP([OFPT_BUNDLE_CONTROL - OPEN_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 00 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - OPEN_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 00 00 02 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=OPEN_REQUEST flags=ordered +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - OPEN_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 00 00 03 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic ordered +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - OPEN_REPLY]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 01 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=OPEN_REPLY flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - CLOSE_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 02 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - CLOSE_REPLY]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 03 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=CLOSE_REPLY flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - COMMIT_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 04 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=COMMIT_REQUEST flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - COMMIT_REPLY]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 05 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=COMMIT_REPLY flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - DISCARD_REQUEST]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 06 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=DISCARD_REQUEST flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_CONTROL - DISCARD_REPLY]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 21 00 10 00 00 00 00 \ +00 00 00 01 00 07 00 01 \ +"], [0], [dnl +OFPT_BUNDLE_CONTROL (OF1.4) (xid=0x0): + bundle_id=0x1 type=DISCARD_REPLY flags=atomic +]) +AT_CLEANUP + +AT_SETUP([OFPT_BUNDLE_ADD_MESSAGE - OFPT_HELLO]) +AT_KEYWORDS([ofp-print]) +AT_CHECK([ovs-ofctl ofp-print "\ +05 22 00 20 00 00 00 00 \ +00 00 00 01 00 01 00 01 02 00 00 08 00 00 00 00 \ +00 00 00 00 00 00 00 00 \ +"], [0], [dnl +OFPT_BUNDLE_ADD_MESSAGE (OF1.4) (xid=0x0): + bundle_id=0x1 flags=atomic +OFPT_HELLO (OF1.1) (xid=0x0): + version bitmap: 0x01, 0x02 +]) +AT_CLEANUP diff --git a/tests/ofproto-macros.at b/tests/ofproto-macros.at index fe765eeff..8a058ae45 100644 --- a/tests/ofproto-macros.at +++ b/tests/ofproto-macros.at @@ -73,7 +73,7 @@ m4_define([OVS_VSWITCHD_START], AT_CHECK([ovs-vsctl --no-wait init]) dnl Start ovs-vswitchd. - AT_CHECK([ovs-vswitchd --detach --no-chdir --pidfile --enable-dummy$3 --disable-system --log-file -vvconn -vofproto_dpif], [0], [], [stderr]) + AT_CHECK([ovs-vswitchd --detach --no-chdir --pidfile --enable-dummy$3 --disable-system --log-file -vvconn -vofproto_dpif --enable-of14], [0], [], [stderr]) AT_CAPTURE_FILE([ovs-vswitchd.log]) AT_CHECK([[sed < stderr ' /vlog|INFO|opened log file/d @@ -83,7 +83,7 @@ m4_define([OVS_VSWITCHD_START], /ofproto|INFO|datapath ID changed to fedcba9876543210/d']]) dnl Add bridges, ports, etc. - AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2]) + AT_CHECK([ovs-vsctl -- add-br br0 -- set bridge br0 datapath-type=dummy other-config:datapath-id=fedcba9876543210 other-config:hwaddr=aa:55:aa:55:00:00 protocols=[[OpenFlow10,OpenFlow11,OpenFlow12,OpenFlow13,OpenFlow14]] fail-mode=secure -- $1 m4_if([$2], [], [], [| ${PERL} $srcdir/uuidfilt.pl])], [0], [$2]) ]) m4_divert_push([PREPARE_TESTS]) diff --git a/tests/ofproto.at b/tests/ofproto.at index dfa89151f..2ffe65302 100644 --- a/tests/ofproto.at +++ b/tests/ofproto.at @@ -2329,3 +2329,237 @@ for pre in '1 2' '[[]] 2' '1 [[]]' '[[]] [[]]' '2 1' '[[]] 1' '2 [[]]' \ done OVS_VSWITCHD_STOP AT_CLEANUP + + +AT_SETUP([ofproto - bundles, open (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a) +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundles, double open (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Send twice an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a) +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_ERROR (OF1.4): OFPBFC_BAD_ID +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle close without open (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +OFPT_ERROR (OF1.4): OFPBFC_BAD_ID +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle double close (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Open, Close, Close +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +OFPT_ERROR (OF1.4): OFPBFC_BUNDLE_CLOSED +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=atomic +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle close, different flags (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Open, Close, Close +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 02 00 02" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=ordered +OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=CLOSE_REQUEST flags=ordered +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle commit without open (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Open, Close, Close +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 04 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=COMMIT_REQUEST flags=atomic +OFPT_ERROR (OF1.4): OFPBFC_BAD_ID +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=COMMIT_REQUEST flags=atomic +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle commit, different flags (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Open, Close, Close +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 04 00 02" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REQUEST flags=atomic +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=OPEN_REPLY flags=0 +OFPT_BARRIER_REPLY (OF1.4): +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=COMMIT_REQUEST flags=ordered +OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=COMMIT_REQUEST flags=ordered +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([ofproto - bundle discard without open (OpenFlow 1.4)]) +AT_KEYWORDS([monitor]) +OVS_VSWITCHD_START + +# Start a monitor, use the required protocol version +ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 +AT_CAPTURE_FILE([monitor.log]) + +# Open, Close, Close +ovs-appctl -t ovs-ofctl ofctl/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 06 00 01" +ovs-appctl -t ovs-ofctl ofctl/barrier +ovs-appctl -t ovs-ofctl exit + +AT_CHECK([ofctl_strip < monitor.log], [0], [dnl +send: OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=DISCARD_REQUEST flags=atomic +OFPT_ERROR (OF1.4): OFPBFC_BAD_ID +OFPT_BUNDLE_CONTROL (OF1.4): + bundle_id=0x1 type=DISCARD_REQUEST flags=atomic +OFPT_BARRIER_REPLY (OF1.4): +]) + +OVS_VSWITCHD_STOP +AT_CLEANUP -- 2.43.0