2
0
mirror of https://github.com/openvswitch/ovs synced 2025-09-03 15:55:19 +00:00

ofproto: Add support for reverting flow mods and bundle commit.

Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Acked-by: Ben Pfaff <blp@nicira.com>
This commit is contained in:
Jarno Rajahalme
2015-06-01 15:47:58 -07:00
parent ce59413fb4
commit 1f42be1c66
6 changed files with 313 additions and 200 deletions

View File

@@ -1795,11 +1795,19 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
fm->command = command & 0xff; fm->command = command & 0xff;
fm->table_id = command >> 8; fm->table_id = command >> 8;
} else { } else {
if (command > 0xff) {
VLOG_WARN_RL(&bad_ofmsg_rl, "flow_mod has explicit table_id "
"but flow_mod_table_id extension is not enabled");
}
fm->command = command; fm->command = command;
fm->table_id = 0xff; fm->table_id = 0xff;
} }
} }
if (fm->command > OFPFC_DELETE_STRICT) {
return OFPERR_OFPFMFC_BAD_COMMAND;
}
error = ofpacts_pull_openflow_instructions(&b, b.size, error = ofpacts_pull_openflow_instructions(&b, b.size,
oh->version, ofpacts); oh->version, ofpacts);
if (error) { if (error) {

View File

@@ -59,11 +59,16 @@ ofp_bundle_create(uint32_t id, uint16_t flags)
} }
void void
ofp_bundle_remove__(struct ofconn *ofconn, struct ofp_bundle *bundle) ofp_bundle_remove__(struct ofconn *ofconn, struct ofp_bundle *bundle,
bool success)
{ {
struct ofp_bundle_entry *msg; struct ofp_bundle_entry *msg;
LIST_FOR_EACH_POP (msg, node, &bundle->msg_list) { LIST_FOR_EACH_POP (msg, node, &bundle->msg_list) {
if (success && msg->type == OFPTYPE_FLOW_MOD) {
/* Tell connmgr about successful flow mods. */
ofconn_report_flow_mod(ofconn, msg->fm.command);
}
ofp_bundle_entry_free(msg); ofp_bundle_entry_free(msg);
} }
@@ -81,7 +86,7 @@ ofp_bundle_open(struct ofconn *ofconn, uint32_t id, uint16_t flags)
if (bundle) { if (bundle) {
VLOG_INFO("Bundle %x already exists.", id); VLOG_INFO("Bundle %x already exists.", id);
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return OFPERR_OFPBFC_BAD_ID; return OFPERR_OFPBFC_BAD_ID;
} }
@@ -107,12 +112,12 @@ ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t flags)
} }
if (bundle->state == BS_CLOSED) { if (bundle->state == BS_CLOSED) {
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return OFPERR_OFPBFC_BUNDLE_CLOSED; return OFPERR_OFPBFC_BUNDLE_CLOSED;
} }
if (bundle->flags != flags) { if (bundle->flags != flags) {
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return OFPERR_OFPBFC_BAD_FLAGS; return OFPERR_OFPBFC_BAD_FLAGS;
} }
@@ -120,31 +125,6 @@ ofp_bundle_close(struct ofconn *ofconn, uint32_t id, uint16_t flags)
return 0; return 0;
} }
enum ofperr
ofp_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
{
struct ofp_bundle *bundle;
enum ofperr error = 0;
struct ofp_bundle_entry *msg;
bundle = ofconn_get_bundle(ofconn, id);
if (!bundle) {
return OFPERR_OFPBFC_BAD_ID;
}
if (bundle->flags != flags) {
error = OFPERR_OFPBFC_BAD_FLAGS;
} else {
LIST_FOR_EACH (msg, node, &bundle->msg_list) {
/* XXX: actual commit */
error = OFPERR_OFPBFC_MSG_FAILED;
}
}
ofp_bundle_remove__(ofconn, bundle);
return error;
}
enum ofperr enum ofperr
ofp_bundle_discard(struct ofconn *ofconn, uint32_t id) ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
{ {
@@ -156,7 +136,7 @@ ofp_bundle_discard(struct ofconn *ofconn, uint32_t id)
return OFPERR_OFPBFC_BAD_ID; return OFPERR_OFPBFC_BAD_ID;
} }
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return 0; return 0;
} }
@@ -179,10 +159,10 @@ ofp_bundle_add_message(struct ofconn *ofconn, uint32_t id, uint16_t flags,
return error; return error;
} }
} else if (bundle->state == BS_CLOSED) { } else if (bundle->state == BS_CLOSED) {
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return OFPERR_OFPBFC_BUNDLE_CLOSED; return OFPERR_OFPBFC_BUNDLE_CLOSED;
} else if (flags != bundle->flags) { } else if (flags != bundle->flags) {
ofp_bundle_remove__(ofconn, bundle); ofp_bundle_remove__(ofconn, bundle, false);
return OFPERR_OFPBFC_BAD_FLAGS; return OFPERR_OFPBFC_BAD_FLAGS;
} }

View File

@@ -24,6 +24,8 @@
#include "connmgr.h" #include "connmgr.h"
#include "ofp-msgs.h" #include "ofp-msgs.h"
#include "ofp-util.h" #include "ofp-util.h"
#include "ofproto-provider.h"
#include "util.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -31,12 +33,19 @@ extern "C" {
struct ofp_bundle_entry { struct ofp_bundle_entry {
struct ovs_list node; struct ovs_list node;
ovs_be32 xid; /* For error returns. */
enum ofptype type; /* OFPTYPE_FLOW_MOD or OFPTYPE_PORT_MOD. */ enum ofptype type; /* OFPTYPE_FLOW_MOD or OFPTYPE_PORT_MOD. */
union { union {
struct ofputil_flow_mod fm; /* 'fm.ofpacts' must be malloced. */ struct ofputil_flow_mod fm; /* 'fm.ofpacts' must be malloced. */
struct ofputil_port_mod pm; struct ofputil_port_mod pm;
}; };
/* Used during commit. */
struct rule_collection rules; /* Affected rules. */
struct rule *rule;
bool modify;
/* OpenFlow header and some of the message contents for error reporting. */
struct ofp_header ofp_msg[DIV_ROUND_UP(64, sizeof(struct ofp_header))];
}; };
enum bundle_state { enum bundle_state {
@@ -55,30 +64,32 @@ struct ofp_bundle {
}; };
static inline struct ofp_bundle_entry *ofp_bundle_entry_alloc( static inline struct ofp_bundle_entry *ofp_bundle_entry_alloc(
enum ofptype type, ovs_be32 xid); enum ofptype type, const struct ofp_header *oh);
static inline void ofp_bundle_entry_free(struct ofp_bundle_entry *); static inline void ofp_bundle_entry_free(struct ofp_bundle_entry *);
enum ofperr ofp_bundle_open(struct ofconn *, uint32_t id, uint16_t flags); enum ofperr ofp_bundle_open(struct ofconn *, uint32_t id, uint16_t flags);
enum ofperr ofp_bundle_close(struct ofconn *, uint32_t id, uint16_t flags); enum ofperr ofp_bundle_close(struct ofconn *, uint32_t id, uint16_t flags);
enum ofperr ofp_bundle_commit(struct ofconn *, uint32_t id, uint16_t flags);
enum ofperr ofp_bundle_discard(struct ofconn *, uint32_t id); enum ofperr ofp_bundle_discard(struct ofconn *, uint32_t id);
enum ofperr ofp_bundle_add_message(struct ofconn *, uint32_t id, enum ofperr ofp_bundle_add_message(struct ofconn *, uint32_t id,
uint16_t flags, struct ofp_bundle_entry *); uint16_t flags, struct ofp_bundle_entry *);
void ofp_bundle_remove__(struct ofconn *ofconn, struct ofp_bundle *bundle); void ofp_bundle_remove__(struct ofconn *, struct ofp_bundle *, bool success);
static inline struct ofp_bundle_entry * static inline struct ofp_bundle_entry *
ofp_bundle_entry_alloc(enum ofptype type, ovs_be32 xid) ofp_bundle_entry_alloc(enum ofptype type, const struct ofp_header *oh)
{ {
struct ofp_bundle_entry *entry = xmalloc(sizeof *entry); struct ofp_bundle_entry *entry = xmalloc(sizeof *entry);
entry->xid = xid;
entry->type = type; entry->type = type;
/* Max 64 bytes for error reporting. */
memcpy(entry->ofp_msg, oh, MIN(ntohs(oh->length), sizeof entry->ofp_msg));
return entry; return entry;
} }
static inline void ofp_bundle_entry_free(struct ofp_bundle_entry *entry) static inline void
ofp_bundle_entry_free(struct ofp_bundle_entry *entry)
{ {
if (entry) { if (entry) {
if (entry->type == OFPTYPE_FLOW_MOD) { if (entry->type == OFPTYPE_FLOW_MOD) {

View File

@@ -1215,7 +1215,7 @@ bundle_remove_all(struct ofconn *ofconn)
struct ofp_bundle *b, *next; struct ofp_bundle *b, *next;
HMAP_FOR_EACH_SAFE (b, next, node, &ofconn->bundles) { HMAP_FOR_EACH_SAFE (b, next, node, &ofconn->bundles) {
ofp_bundle_remove__(ofconn, b); ofp_bundle_remove__(ofconn, b, false);
} }
} }

View File

@@ -253,9 +253,6 @@ struct flow_mod_requester {
}; };
/* OpenFlow. */ /* OpenFlow. */
static enum ofperr add_flow(struct ofproto *, struct ofputil_flow_mod *,
const struct flow_mod_requester *);
static enum ofperr modify_flow_check__(struct ofproto *, static enum ofperr modify_flow_check__(struct ofproto *,
struct ofputil_flow_mod *, struct ofputil_flow_mod *,
const struct rule *) const struct rule *)
@@ -281,6 +278,15 @@ static bool ofproto_group_exists(const struct ofproto *ofproto,
OVS_EXCLUDED(ofproto->groups_rwlock); OVS_EXCLUDED(ofproto->groups_rwlock);
static enum ofperr add_group(struct ofproto *, struct ofputil_group_mod *); static enum ofperr add_group(struct ofproto *, struct ofputil_group_mod *);
static void handle_openflow(struct ofconn *, const struct ofpbuf *); static void handle_openflow(struct ofconn *, const struct ofpbuf *);
static enum ofperr do_bundle_flow_mod_begin(struct ofproto *,
struct ofputil_flow_mod *,
struct ofp_bundle_entry *)
OVS_REQUIRES(ofproto_mutex);
static void do_bundle_flow_mod_finish(struct ofproto *,
struct ofputil_flow_mod *,
const struct flow_mod_requester *,
struct ofp_bundle_entry *)
OVS_REQUIRES(ofproto_mutex);
static enum ofperr handle_flow_mod__(struct ofproto *, static enum ofperr handle_flow_mod__(struct ofproto *,
struct ofputil_flow_mod *, struct ofputil_flow_mod *,
const struct flow_mod_requester *) const struct flow_mod_requester *)
@@ -4338,6 +4344,17 @@ set_conjunctions(struct rule *rule, const struct cls_conjunction *conjs,
cls_rule_set_conjunctions(cr, conjs, n_conjs); cls_rule_set_conjunctions(cr, conjs, n_conjs);
} }
/* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT
* in which no matching flow already exists in the flow table.
*
* Adds the flow specified by 'fm', to the ofproto's flow table. Returns 0 on
* success, or an OpenFlow error code on failure.
*
* On successful return the caller must complete the operation either by
* calling add_flow_finish(), or add_flow_revert() if the operation needs to
* be reverted.
*
* The caller retains ownership of 'fm->ofpacts'. */
static enum ofperr static enum ofperr
add_flow_begin(struct ofproto *ofproto, struct ofputil_flow_mod *fm, add_flow_begin(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
struct rule **rulep, bool *modify) struct rule **rulep, bool *modify)
@@ -4388,7 +4405,8 @@ add_flow_begin(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
cls_rule_init(&cr, &fm->match, fm->priority); cls_rule_init(&cr, &fm->match, fm->priority);
/* Check for the existence of an identical rule. */ /* Check for the existence of an identical rule.
* This will not return rules earlier marked as 'to_be_removed'. */
rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, &cr)); rule = rule_from_cls_rule(classifier_find_rule_exactly(&table->cls, &cr));
if (rule) { if (rule) {
/* Transform "add" into "modify" of an existing identical flow. */ /* Transform "add" into "modify" of an existing identical flow. */
@@ -4450,6 +4468,29 @@ add_flow_begin(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
return 0; return 0;
} }
/* Revert the effects of add_flow_begin().
* 'new_rule' must be passed in as NULL, if no new rule was allocated and
* inserted to the classifier.
* Note: evictions cannot be reverted. */
static void
add_flow_revert(struct ofproto *ofproto, struct rule *new_rule)
OVS_REQUIRES(ofproto_mutex)
{
/* Old rule was not changed yet, only need to revert a new rule. */
if (new_rule) {
struct oftable *table = &ofproto->tables[new_rule->table_id];
if (!classifier_remove(&table->cls, &new_rule->cr)) {
OVS_NOT_REACHED();
}
classifier_publish(&table->cls);
ofproto_rule_remove__(ofproto, new_rule);
ofproto->ofproto_class->rule_delete(new_rule);
ofproto_rule_unref(new_rule);
}
}
static void static void
add_flow_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm, add_flow_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req, const struct flow_mod_requester *req,
@@ -4489,30 +4530,6 @@ add_flow_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
send_buffered_packet(req, fm->buffer_id, rule); send_buffered_packet(req, fm->buffer_id, rule);
} }
/* Implements OFPFC_ADD and the cases for OFPFC_MODIFY and OFPFC_MODIFY_STRICT
* in which no matching flow already exists in the flow table.
*
* Adds the flow specified by 'fm', to the ofproto's flow table. Returns 0 on
* success, or an OpenFlow error code on failure.
*
* The caller retains ownership of 'fm->ofpacts'. */
static enum ofperr
add_flow(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
struct rule *rule;
bool modify;
enum ofperr error;
error = add_flow_begin(ofproto, fm, &rule, &modify);
if (!error) {
add_flow_finish(ofproto, fm, req, rule, modify);
}
return error;
}
/* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */ /* OFPFC_MODIFY and OFPFC_MODIFY_STRICT. */
@@ -4741,6 +4758,17 @@ modify_flows_begin_loose(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
return error; return error;
} }
static void
modify_flows_revert(struct ofproto *ofproto, struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
/* Old rules were not changed yet, only need to revert a new rule. */
if (rules->n == 0 && rules->rules[0] != NULL) {
add_flow_revert(ofproto, rules->rules[0]);
}
rule_collection_destroy(rules);
}
static void static void
modify_flows_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm, modify_flows_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req, const struct flow_mod_requester *req,
@@ -4756,22 +4784,6 @@ modify_flows_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
rule_collection_destroy(rules); rule_collection_destroy(rules);
} }
static enum ofperr
modify_flows_loose(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection rules;
enum ofperr error;
error = modify_flows_begin_loose(ofproto, fm, &rules);
if (!error) {
modify_flows_finish(ofproto, fm, req, &rules);
}
return error;
}
/* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error /* Implements OFPFC_MODIFY_STRICT. Returns 0 on success or an OpenFlow error
* code on failure. */ * code on failure. */
static enum ofperr static enum ofperr
@@ -4799,23 +4811,6 @@ modify_flow_begin_strict(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
} }
return error; return error;
} }
static enum ofperr
modify_flow_strict(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection rules;
enum ofperr error;
error = modify_flow_begin_strict(ofproto, fm, &rules);
if (!error) {
modify_flows_finish(ofproto, fm, req, &rules);
}
return error;
}
/* OFPFC_DELETE implementation. */ /* OFPFC_DELETE implementation. */
@@ -4894,6 +4889,18 @@ delete_flows_begin_loose(struct ofproto *ofproto,
return error; return error;
} }
static void
delete_flows_revert(struct rule_collection *rules)
OVS_REQUIRES(ofproto_mutex)
{
for (size_t i = 0; i < rules->n; i++) {
struct rule *rule = rules->rules[i];
CONST_CAST(struct cls_rule *, &rule->cr)->to_be_removed = false;
}
rule_collection_destroy(rules);
}
static void static void
delete_flows_finish(const struct ofputil_flow_mod *fm, delete_flows_finish(const struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req, const struct flow_mod_requester *req,
@@ -4904,23 +4911,6 @@ delete_flows_finish(const struct ofputil_flow_mod *fm,
rule_collection_destroy(rules); rule_collection_destroy(rules);
} }
static enum ofperr
delete_flows_loose(struct ofproto *ofproto,
const struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection rules;
enum ofperr error;
error = delete_flows_begin_loose(ofproto, fm, &rules);
if (!error) {
delete_flows_finish(fm, req, &rules);
}
return error;
}
/* Implements OFPFC_DELETE_STRICT. */ /* Implements OFPFC_DELETE_STRICT. */
static enum ofperr static enum ofperr
delete_flow_begin_strict(struct ofproto *ofproto, delete_flow_begin_strict(struct ofproto *ofproto,
@@ -4950,22 +4940,6 @@ delete_flow_begin_strict(struct ofproto *ofproto,
return error; return error;
} }
static enum ofperr
delete_flow_strict(struct ofproto *ofproto, const struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req)
OVS_REQUIRES(ofproto_mutex)
{
struct rule_collection rules;
enum ofperr error;
error = delete_flow_begin_strict(ofproto, fm, &rules);
if (!error) {
delete_flows_finish(fm, req, &rules);
}
return error;
}
static void static void
ofproto_rule_send_removed(struct rule *rule, uint8_t reason) ofproto_rule_send_removed(struct rule *rule, uint8_t reason)
OVS_REQUIRES(ofproto_mutex) OVS_REQUIRES(ofproto_mutex)
@@ -5096,38 +5070,13 @@ handle_flow_mod__(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req) const struct flow_mod_requester *req)
OVS_EXCLUDED(ofproto_mutex) OVS_EXCLUDED(ofproto_mutex)
{ {
struct ofp_bundle_entry be;
enum ofperr error; enum ofperr error;
ovs_mutex_lock(&ofproto_mutex); ovs_mutex_lock(&ofproto_mutex);
switch (fm->command) { error = do_bundle_flow_mod_begin(ofproto, fm, &be);
case OFPFC_ADD: if (!error) {
error = add_flow(ofproto, fm, req); do_bundle_flow_mod_finish(ofproto, fm, req, &be);
break;
case OFPFC_MODIFY:
error = modify_flows_loose(ofproto, fm, req);
break;
case OFPFC_MODIFY_STRICT:
error = modify_flow_strict(ofproto, fm, req);
break;
case OFPFC_DELETE:
error = delete_flows_loose(ofproto, fm, req);
break;
case OFPFC_DELETE_STRICT:
error = delete_flow_strict(ofproto, fm, req);
break;
default:
if (fm->command > 0xff) {
VLOG_WARN_RL(&rl, "%s: flow_mod has explicit table_id but "
"flow_mod_table_id extension is not enabled",
ofproto->name);
}
error = OFPERR_OFPFMFC_BAD_COMMAND;
break;
} }
ofmonitor_flush(ofproto->connmgr); ofmonitor_flush(ofproto->connmgr);
ovs_mutex_unlock(&ofproto_mutex); ovs_mutex_unlock(&ofproto_mutex);
@@ -6490,13 +6439,174 @@ handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
return table_mod(ofproto, &tm); return table_mod(ofproto, &tm);
} }
static enum ofperr
do_bundle_flow_mod_begin(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
struct ofp_bundle_entry *be)
OVS_REQUIRES(ofproto_mutex)
{
switch (fm->command) {
case OFPFC_ADD:
return add_flow_begin(ofproto, fm, &be->rule, &be->modify);
case OFPFC_MODIFY:
return modify_flows_begin_loose(ofproto, fm, &be->rules);
case OFPFC_MODIFY_STRICT:
return modify_flow_begin_strict(ofproto, fm, &be->rules);
case OFPFC_DELETE:
return delete_flows_begin_loose(ofproto, fm, &be->rules);
case OFPFC_DELETE_STRICT:
return delete_flow_begin_strict(ofproto, fm, &be->rules);
}
return OFPERR_OFPFMFC_BAD_COMMAND;
}
static void
do_bundle_flow_mod_revert(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
struct ofp_bundle_entry *be)
OVS_REQUIRES(ofproto_mutex)
{
switch (fm->command) {
case OFPFC_ADD:
add_flow_revert(ofproto, be->modify ? NULL : be->rule);
break;
case OFPFC_MODIFY:
case OFPFC_MODIFY_STRICT:
modify_flows_revert(ofproto, &be->rules);
break;
case OFPFC_DELETE:
case OFPFC_DELETE_STRICT:
delete_flows_revert(&be->rules);
break;
default:
break;
}
}
static void
do_bundle_flow_mod_finish(struct ofproto *ofproto, struct ofputil_flow_mod *fm,
const struct flow_mod_requester *req,
struct ofp_bundle_entry *be)
OVS_REQUIRES(ofproto_mutex)
{
switch (fm->command) {
case OFPFC_ADD:
add_flow_finish(ofproto, fm, req, be->rule, be->modify);
break;
case OFPFC_MODIFY:
case OFPFC_MODIFY_STRICT:
modify_flows_finish(ofproto, fm, req, &be->rules);
break;
case OFPFC_DELETE:
case OFPFC_DELETE_STRICT:
delete_flows_finish(fm, req, &be->rules);
break;
default:
break;
}
}
/* Commit phases (all while locking ofproto_mutex):
*
* 1. Gather resources - do not send any events or notifications.
*
* add: Check conflicts, check for a displaced flow. If no displaced flow
* exists, add the new flow, but mark it as "invisible".
* mod: Collect affected flows, Do not modify yet.
* del: Collect affected flows, Do not delete yet.
*
* 2a. Fail if any errors are found. After this point no errors are possible.
* No visible changes were made, so rollback is minimal (remove added invisible
* flows, revert 'to_be_removed' status of flows).
*
* 2b. Commit the changes
*
* add: if have displaced flow, modify it, otherwise mark the new flow as
* "visible".
* mod: Modify the collected flows.
* del: Delete the collected flows.
*/
static enum ofperr
do_bundle_commit(struct ofconn *ofconn, uint32_t id, uint16_t flags)
{
struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
struct ofp_bundle *bundle;
struct ofp_bundle_entry *be;
enum ofperr error;
bundle = ofconn_get_bundle(ofconn, id);
if (!bundle) {
return OFPERR_OFPBFC_BAD_ID;
}
if (bundle->flags != flags) {
error = OFPERR_OFPBFC_BAD_FLAGS;
} else {
error = 0;
ovs_mutex_lock(&ofproto_mutex);
LIST_FOR_EACH (be, node, &bundle->msg_list) {
if (be->type == OFPTYPE_PORT_MOD) {
/* Not supported yet. */
error = OFPERR_OFPBFC_MSG_FAILED;
} else if (be->type == OFPTYPE_FLOW_MOD) {
error = do_bundle_flow_mod_begin(ofproto, &be->fm, be);
} else {
OVS_NOT_REACHED();
}
if (error) {
break;
}
}
if (error) {
/* Send error referring to the original message. */
if (error) {
ofconn_send_error(ofconn, be->ofp_msg, error);
error = OFPERR_OFPBFC_MSG_FAILED;
}
/* Revert all previous entires. */
LIST_FOR_EACH_REVERSE_CONTINUE(be, node, &bundle->msg_list) {
if (be->type == OFPTYPE_FLOW_MOD) {
do_bundle_flow_mod_revert(ofproto, &be->fm, be);
}
}
} else {
/* Finish the changes. */
LIST_FOR_EACH (be, node, &bundle->msg_list) {
if (be->type == OFPTYPE_FLOW_MOD) {
struct flow_mod_requester req = { ofconn, be->ofp_msg };
do_bundle_flow_mod_finish(ofproto, &be->fm, &req, be);
}
}
}
ofmonitor_flush(ofproto->connmgr);
ovs_mutex_unlock(&ofproto_mutex);
run_rule_executes(ofproto);
}
/* The bundle is discarded regardless the outcome. */
ofp_bundle_remove__(ofconn, bundle, !error);
return error;
}
static enum ofperr static enum ofperr
handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh) handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh)
{ {
enum ofperr error;
struct ofputil_bundle_ctrl_msg bctrl; struct ofputil_bundle_ctrl_msg bctrl;
struct ofpbuf *buf;
struct ofputil_bundle_ctrl_msg reply; struct ofputil_bundle_ctrl_msg reply;
struct ofpbuf *buf;
enum ofperr error;
error = reject_slave_controller(ofconn); error = reject_slave_controller(ofconn);
if (error) { if (error) {
@@ -6507,6 +6617,10 @@ handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh)
if (error) { if (error) {
return error; return error;
} }
/* Atomic updates not supported yet. */
if (bctrl.flags & OFPBF_ATOMIC) {
return OFPERR_OFPBFC_BAD_FLAGS;
}
reply.flags = 0; reply.flags = 0;
reply.bundle_id = bctrl.bundle_id; reply.bundle_id = bctrl.bundle_id;
@@ -6520,7 +6634,7 @@ handle_bundle_control(struct ofconn *ofconn, const struct ofp_header *oh)
reply.type = OFPBCT_CLOSE_REPLY;; reply.type = OFPBCT_CLOSE_REPLY;;
break; break;
case OFPBCT_COMMIT_REQUEST: case OFPBCT_COMMIT_REQUEST:
error = ofp_bundle_commit(ofconn, bctrl.bundle_id, bctrl.flags); error = do_bundle_commit(ofconn, bctrl.bundle_id, bctrl.flags);
reply.type = OFPBCT_COMMIT_REPLY; reply.type = OFPBCT_COMMIT_REPLY;
break; break;
case OFPBCT_DISCARD_REQUEST: case OFPBCT_DISCARD_REQUEST:
@@ -6562,7 +6676,7 @@ handle_bundle_add(struct ofconn *ofconn, const struct ofp_header *oh)
return error; return error;
} }
bmsg = ofp_bundle_entry_alloc(type, badd.msg->xid); bmsg = ofp_bundle_entry_alloc(type, badd.msg);
if (type == OFPTYPE_PORT_MOD) { if (type == OFPTYPE_PORT_MOD) {
error = ofputil_decode_port_mod(badd.msg, &bmsg->pm, false); error = ofputil_decode_port_mod(badd.msg, &bmsg->pm, false);

View File

@@ -3227,13 +3227,13 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Send an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a) # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [], [dnl AT_CHECK([ofctl_strip < monitor.log], [], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REPLY flags=0 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
@@ -3251,23 +3251,23 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Send twice an OpenFlow14 message (05), OFPT_BUNDLE_CONTROL (21), length (10), xid (0a) # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REPLY flags=0 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3282,16 +3282,16 @@ OVS_VSWITCHD_START
ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1 ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2>&1
AT_CAPTURE_FILE([monitor.log]) 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/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 ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=atomic bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=atomic bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3307,30 +3307,30 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Open, Close, Close # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier 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/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 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/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 ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REPLY flags=0 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=atomic bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REPLY flags=0 bundle_id=0x1 type=CLOSE_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=atomic bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BUNDLE_CLOSED OFPT_ERROR (OF1.4): OFPBFC_BUNDLE_CLOSED
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=atomic bundle_id=0x1 type=CLOSE_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3346,23 +3346,23 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Open, Close, Close # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier 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/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/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REPLY flags=0 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=ordered bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=CLOSE_REQUEST flags=ordered bundle_id=0x1 type=CLOSE_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3378,16 +3378,16 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Open, Close, Close # 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/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 ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=COMMIT_REQUEST flags=atomic bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=COMMIT_REQUEST flags=atomic bundle_id=0x1 type=COMMIT_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3403,23 +3403,23 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Open, Close, Close # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 00 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier 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/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 ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REQUEST flags=atomic bundle_id=0x1 type=OPEN_REQUEST flags=ordered
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=OPEN_REPLY flags=0 bundle_id=0x1 type=OPEN_REPLY flags=0
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=COMMIT_REQUEST flags=ordered bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS OFPT_ERROR (OF1.4): OFPBFC_BAD_FLAGS
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=COMMIT_REQUEST flags=ordered bundle_id=0x1 type=COMMIT_REQUEST flags=atomic
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])
@@ -3435,16 +3435,16 @@ ovs-ofctl -O OpenFlow14 monitor br0 --detach --no-chdir --pidfile >monitor.log 2
AT_CAPTURE_FILE([monitor.log]) AT_CAPTURE_FILE([monitor.log])
# Open, Close, Close # 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/send "05 21 00 10 00 00 00 0a 00 00 00 01 00 06 00 02"
ovs-appctl -t ovs-ofctl ofctl/barrier ovs-appctl -t ovs-ofctl ofctl/barrier
ovs-appctl -t ovs-ofctl exit ovs-appctl -t ovs-ofctl exit
AT_CHECK([ofctl_strip < monitor.log], [0], [dnl AT_CHECK([ofctl_strip < monitor.log], [0], [dnl
send: OFPT_BUNDLE_CONTROL (OF1.4): send: OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=DISCARD_REQUEST flags=atomic bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_ERROR (OF1.4): OFPBFC_BAD_ID OFPT_ERROR (OF1.4): OFPBFC_BAD_ID
OFPT_BUNDLE_CONTROL (OF1.4): OFPT_BUNDLE_CONTROL (OF1.4):
bundle_id=0x1 type=DISCARD_REQUEST flags=atomic bundle_id=0x1 type=DISCARD_REQUEST flags=ordered
OFPT_BARRIER_REPLY (OF1.4): OFPT_BARRIER_REPLY (OF1.4):
]) ])