[ovs-dev] [of1.1 draft 03/10] Introduce ofputil_protocol, to abstract the protocol in use on a connection.
Ben Pfaff
blp at nicira.com
Thu Dec 8 04:17:22 UTC 2011
Open vSwitch already handles a few different protocol variations, but it
does so in a nonuniform manner:
- OpenFlow 1.0 and NXM flow formats are distinguished using the NXFF_*
constant values from nicira-ext.h.
- The "flow_mod_table_id" feature setting is maintained in ofproto as
part of an OpenFlow connection's (ofconn's) state.
There's no way to easily communicate this state among components. It's
not much of a problem yet, but as more protocol support is added it seems
better to have an abstract, uniform way to represent protocol versions and
variants. This commit implements that by introducing a new type
"enum ofputil_protocol". Each ofputil_protocol value represents a variant
of a protocol version. Each value is a separate bit, so a single enum
can also represent a set of protocols, which is often useful as well.
This commit needs the following improvements:
- learning-switch.c should understand how to negotiate the protocol, so
that it can properly implement the ovs-controller --with-flows option
based on what the switch supports.
- ovs-ofctl needs documentation updates, possibly ovs-controller too.
---
lib/learning-switch.c | 20 ++-
lib/learning-switch.h | 8 +-
lib/ofp-parse.c | 70 +++-----
lib/ofp-parse.h | 13 +-
lib/ofp-print.c | 6 +-
lib/ofp-util.c | 433 ++++++++++++++++++++++++++++++++++++--------
lib/ofp-util.h | 85 +++++++--
lib/rconn.c | 6 +
lib/rconn.h | 1 +
lib/util.h | 6 +
lib/vconn.c | 21 ++-
lib/vconn.h | 1 +
ofproto/connmgr.c | 41 ++---
ofproto/connmgr.h | 7 +-
ofproto/ofproto.c | 32 +++-
tests/autopath.at | 8 +-
tests/learn.at | 19 ++-
tests/ovs-ofctl.at | 65 +++++--
utilities/ovs-controller.c | 35 +---
utilities/ovs-ofctl.c | 421 +++++++++++++++++++++++-------------------
20 files changed, 844 insertions(+), 454 deletions(-)
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index c47fcb6..4bf4724 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -137,15 +137,25 @@ lswitch_create(struct rconn *rconn, const struct lswitch_config *cfg)
send_features_request(sw, rconn);
if (cfg->default_flows) {
- const struct ofpbuf *b;
+ enum ofputil_protocol protocol;
+ int ofp_version;
+ size_t i;
- LIST_FOR_EACH (b, list_node, cfg->default_flows) {
- struct ofpbuf *copy = ofpbuf_clone(b);
- int error = rconn_send(rconn, copy, NULL);
+ /* XXX negotiate protocol */
+
+ ofp_version = rconn_get_version(rconn);
+ protocol = ofputil_protocol_from_ofp_version(ofp_version);
+
+ for (i = 0; i < cfg->n_default_flows; i++) {
+ struct ofpbuf *msg;
+ int error;
+
+ msg = ofputil_encode_flow_mod(&cfg->default_flows[i], protocol);
+ error = rconn_send(rconn, msg, NULL);
if (error) {
VLOG_INFO_RL(&rl, "%s: failed to queue default flows (%s)",
rconn_get_name(rconn), strerror(error));
- ofpbuf_delete(copy);
+ ofpbuf_delete(msg);
break;
}
}
diff --git a/lib/learning-switch.h b/lib/learning-switch.h
index c6f347e..833b94d 100644
--- a/lib/learning-switch.h
+++ b/lib/learning-switch.h
@@ -46,10 +46,10 @@ struct lswitch_config {
* OFP_FLOW_PERMANENT: Set up permanent flows. */
int max_idle;
- /* Optionally, a list of one or more "struct ofpbuf"s containing OpenFlow
- * messages to send to the switch at time of connection. Presumably these
- * will be OFPT_FLOW_MOD requests to set up the flow table. */
- const struct list *default_flows;
+ /* Optional "flow mod" requests to send to the switch at connection time,
+ * to set up the flow table. */
+ const struct ofputil_flow_mod *default_flows;
+ size_t n_default_flows;
/* The OpenFlow queue to use by default. Use UINT32_MAX to avoid
* specifying a particular queue. */
diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index 4021551..9ce9eb4 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -607,67 +607,49 @@ parse_ofp_str(struct ofputil_flow_mod *fm, int command, const char *str_,
}
/* Parses 'string' as an OFPT_FLOW_MOD or NXT_FLOW_MOD with command 'command'
- * (one of OFPFC_*) and appends the parsed OpenFlow message to 'packets'.
- * '*cur_format' should initially contain the flow format currently configured
- * on the connection; this function will add a message to change the flow
- * format and update '*cur_format', if this is necessary to add the parsed
- * flow. */
+ * (one of OFPFC_*) into 'fm'. */
void
-parse_ofp_flow_mod_str(struct list *packets, enum nx_flow_format *cur_format,
- bool *flow_mod_table_id, char *string, uint16_t command,
- bool verbose)
+parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, char *string,
+ uint16_t command, bool verbose)
{
- enum nx_flow_format min_format, next_format;
struct cls_rule rule_copy;
- struct ofpbuf *ofm;
- struct ofputil_flow_mod fm;
-
- parse_ofp_str(&fm, command, string, verbose);
- min_format = ofputil_min_flow_format(&fm.cr);
- next_format = MAX(*cur_format, min_format);
- if (next_format != *cur_format) {
- struct ofpbuf *sff = ofputil_make_set_flow_format(next_format);
- list_push_back(packets, &sff->list_node);
- *cur_format = next_format;
- }
+ parse_ofp_str(fm, command, string, verbose);
/* Normalize a copy of the rule. This ensures that non-normalized flows
* get logged but doesn't affect what gets sent to the switch, so that the
* switch can do whatever it likes with the flow. */
- rule_copy = fm.cr;
- ofputil_normalize_rule(&rule_copy, next_format);
-
- if (fm.table_id != 0xff && !*flow_mod_table_id) {
- struct ofpbuf *sff = ofputil_make_flow_mod_table_id(true);
- list_push_back(packets, &sff->list_node);
- *flow_mod_table_id = true;
- }
-
- ofm = ofputil_encode_flow_mod(&fm, *cur_format, *flow_mod_table_id);
- list_push_back(packets, &ofm->list_node);
+ rule_copy = fm->cr;
+ ofputil_normalize_rule(&rule_copy);
}
-/* Similar to parse_ofp_flow_mod_str(), except that the string is read from
- * 'stream' and the command is always OFPFC_ADD. Returns false if end-of-file
- * is reached before reading a flow, otherwise true. */
-bool
-parse_ofp_flow_mod_file(struct list *packets,
- enum nx_flow_format *cur, bool *flow_mod_table_id,
- FILE *stream, uint16_t command)
+void
+parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
+ struct ofputil_flow_mod **fms, size_t *n_fms)
{
+ size_t allocated_fms;
+ FILE *stream;
struct ds s;
- bool ok;
+ stream = !strcmp(file_name, "-") ? stdin : fopen(file_name, "r");
+ if (stream == NULL) {
+ ovs_fatal(errno, "%s: open", file_name);
+ }
+
+ allocated_fms = *n_fms;
ds_init(&s);
- ok = ds_get_preprocessed_line(&s, stream) == 0;
- if (ok) {
- parse_ofp_flow_mod_str(packets, cur, flow_mod_table_id,
- ds_cstr(&s), command, true);
+ while (!ds_get_preprocessed_line(&s, stream)) {
+ if (*n_fms >= allocated_fms) {
+ *fms = x2nrealloc(*fms, &allocated_fms, sizeof **fms);
+ }
+ parse_ofp_flow_mod_str(&(*fms)[*n_fms], ds_cstr(&s), command, false);
+ *n_fms += 1;
}
ds_destroy(&s);
- return ok;
+ if (stream != stdin) {
+ fclose(stream);
+ }
}
void
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index 80fca97..430d7d3 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -22,22 +22,17 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
-#include "openflow/nicira-ext.h"
-struct list;
-struct ofpbuf;
struct ofputil_flow_mod;
struct ofputil_flow_stats_request;
void parse_ofp_str(struct ofputil_flow_mod *, int command, const char *str_,
bool verbose);
-void parse_ofp_flow_mod_str(struct list *packets,
- enum nx_flow_format *cur, bool *flow_mod_table_id,
- char *string, uint16_t command, bool verbose);
-bool parse_ofp_flow_mod_file(struct list *packets,
- enum nx_flow_format *cur, bool *flow_mod_table_id,
- FILE *, uint16_t command);
+void parse_ofp_flow_mod_str(struct ofputil_flow_mod *, char *string,
+ uint16_t command, bool verbose);
+void parse_ofp_flow_mod_file(const char *file_name, uint16_t command,
+ struct ofputil_flow_mod **fms, size_t *n_fms);
void parse_ofp_flow_stats_request_str(struct ofputil_flow_stats_request *,
bool aggregate, char *string);
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index c231a15..0527a3d 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -755,7 +755,7 @@ ofp_print_flow_mod(struct ds *s, const struct ofp_header *oh,
bool need_priority;
enum ofperr error;
- error = ofputil_decode_flow_mod(&fm, oh, true);
+ error = ofputil_decode_flow_mod(&fm, oh, OFPUTIL_P_OF10_TID);
if (error) {
ofp_print_error(s, error);
return;
@@ -1264,8 +1264,8 @@ ofp_print_nxt_set_flow_format(struct ds *string,
uint32_t format = ntohl(nsff->format);
ds_put_cstr(string, " format=");
- if (ofputil_flow_format_is_valid(format)) {
- ds_put_cstr(string, ofputil_flow_format_to_string(format));
+ if (ofputil_nx_flow_format_is_valid(format)) {
+ ds_put_cstr(string, ofputil_nx_flow_format_to_string(format));
} else {
ds_put_format(string, "%"PRIu32, format);
}
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 0bce510..04468fe 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -802,39 +802,253 @@ ofputil_msg_type_code(const struct ofputil_msg_type *type)
return type->code;
}
-/* Flow formats. */
+/* Protocols. */
+struct proto_abbrev {
+ enum ofputil_protocol protocol;
+ const char *name;
+};
+
+/* A map from OFPUTIL_P_* values to abbreviated protocol names that may be
+ * specified by users.
+ *
+ * Some of the differences between protocols really aren't of interest to
+ * users. These abbreviations avoid exposing users to distinctions that they
+ * don't care about.
+ */
+static const struct proto_abbrev proto_abbrevs[] = {
+ { OFPUTIL_P_ANY, "any" },
+ { OFPUTIL_P_OF10_ANY, "OpenFlow10" },
+ { OFPUTIL_P_NXM_ANY, "NXM" },
+};
+#define N_PROTO_ABBREVS ARRAY_SIZE(proto_abbrevs)
+
+enum ofputil_protocol ofputil_flow_dump_protocols[] = {
+ OFPUTIL_P_NXM,
+ OFPUTIL_P_OF10,
+};
+size_t ofputil_n_flow_dump_protocols = ARRAY_SIZE(ofputil_flow_dump_protocols);
+
+/* Returns the ofputil_protocol that is initially in effect on an OpenFlow
+ * connection that has negotiated the given 'version'. 'version' should
+ * normally be an 8-bit OpenFlow version identifier (e.g. 0x01 for OpenFlow
+ * 1.0, 0x02 for OpenFlow 1.1). Returns 0 if 'version' is not supported or
+ * outside the valid range. */
+enum ofputil_protocol
+ofputil_protocol_from_ofp_version(int version)
+{
+ switch (version) {
+ case OFP_VERSION: return OFPUTIL_P_OF10;
+ default: return 0;
+ }
+}
+
+/* Returns true if 'protocol' is a single OFPUTIL_P_* value, false
+ * otherwise. */
bool
-ofputil_flow_format_is_valid(enum nx_flow_format flow_format)
+ofputil_protocol_is_valid(enum ofputil_protocol protocol)
{
- switch (flow_format) {
- case NXFF_OPENFLOW10:
- case NXFF_NXM:
- return true;
+ return protocol & OFPUTIL_P_ANY && is_pow2(protocol);
+}
+
+/* Returns the equivalent of 'protocol' with the Nicira flow_mod_table_id
+ * extension turned on or off if 'enable' is true or false, respectively.
+ *
+ * This extension is only useful for protocols whose "standard" version does
+ * not allow specific tables to be modified. In particular, this is true of
+ * OpenFlow 1.0. In later versions of OpenFlow, a flow_mod request always
+ * specifies a table ID and so there is no need for such an extension. When
+ * 'protocol' is such a protocol that doesn't need a flow_mod_table_id
+ * extension, this function just returns its 'protocol' argument unchanged
+ * regardless of the value of 'enable'. */
+enum ofputil_protocol
+ofputil_protocol_set_tid(enum ofputil_protocol protocol, bool enable)
+{
+ switch (protocol) {
+ case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_TID:
+ return enable ? OFPUTIL_P_OF10_TID : OFPUTIL_P_OF10;
+
+ case OFPUTIL_P_NXM:
+ case OFPUTIL_P_NXM_TID:
+ return enable ? OFPUTIL_P_NXM_TID : OFPUTIL_P_NXM;
+
+ default:
+ NOT_REACHED();
}
+}
- return false;
+/* Returns the "base" version of 'protocol'. That is, if 'protocol' includes
+ * some extension to a standard protocol version, the return value is the
+ * standard version of that protocol without any extension. If 'protocol' is a
+ * standard protocol version, returns 'protocol' unchanged. */
+enum ofputil_protocol
+ofputil_protocol_to_base(enum ofputil_protocol protocol)
+{
+ return ofputil_protocol_set_tid(protocol, false);
}
-const char *
-ofputil_flow_format_to_string(enum nx_flow_format flow_format)
+/* Returns 'new_base' with any extensions taken from 'cur'. */
+enum ofputil_protocol
+ofputil_protocol_set_base(enum ofputil_protocol cur,
+ enum ofputil_protocol new_base)
{
- switch (flow_format) {
- case NXFF_OPENFLOW10:
- return "openflow10";
- case NXFF_NXM:
- return "nxm";
+ bool tid = (cur & OFPUTIL_P_TID) != 0;
+
+ switch (new_base) {
+ case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_TID:
+ return ofputil_protocol_set_tid(OFPUTIL_P_OF10, tid);
+
+ case OFPUTIL_P_NXM:
+ case OFPUTIL_P_NXM_TID:
+ return ofputil_protocol_set_tid(OFPUTIL_P_NXM, tid);
+
default:
NOT_REACHED();
}
}
-int
-ofputil_flow_format_from_string(const char *s)
+/* Returns a string form of 'protocol', if a simple form exists (that is, if
+ * 'protocol' is either a single protocol or it is a combination of protocols
+ * that have a single abbreviation). Otherwise, returns NULL. */
+const char *
+ofputil_protocol_to_string(enum ofputil_protocol protocol)
+{
+ const struct proto_abbrev *p;
+
+ /* Use a "switch" statement for single-bit names so that we get a compiler
+ * warning if we forget any. */
+ switch (protocol) {
+ case OFPUTIL_P_NXM:
+ return "NXM-table_id";
+
+ case OFPUTIL_P_NXM_TID:
+ return "NXM+table_id";
+
+ case OFPUTIL_P_OF10:
+ return "OpenFlow10-table_id";
+
+ case OFPUTIL_P_OF10_TID:
+ return "OpenFlow10+table_id";
+ }
+
+ /* Check abbreviations. */
+ for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
+ if (protocol == p->protocol) {
+ return p->name;
+ }
+ }
+
+ return NULL;
+}
+
+/* Returns a string that represents 'protocols'. The return value might be a
+ * comma-separated list if 'protocols' doesn't have a simple name. The return
+ * value is "none" if 'protocols' is 0.
+ *
+ * The caller must free the returned string (with free()). */
+char *
+ofputil_protocols_to_string(enum ofputil_protocol protocols)
+{
+ struct ds s;
+
+ assert(!(protocols & ~OFPUTIL_P_ANY));
+ if (protocols == 0) {
+ return xstrdup("none");
+ }
+
+ ds_init(&s);
+ while (protocols) {
+ const struct proto_abbrev *p;
+ int i;
+
+ if (s.length) {
+ ds_put_char(&s, ',');
+ }
+
+ for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
+ if ((protocols & p->protocol) == p->protocol) {
+ ds_put_cstr(&s, p->name);
+ protocols &= ~p->protocol;
+ goto match;
+ }
+ }
+
+ for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) {
+ enum ofputil_protocol bit = 1u << i;
+
+ if (protocols & bit) {
+ ds_put_cstr(&s, ofputil_protocol_to_string(bit));
+ protocols &= ~bit;
+ goto match;
+ }
+ }
+ NOT_REACHED();
+
+ match: ;
+ }
+ return ds_steal_cstr(&s);
+}
+
+static enum ofputil_protocol
+ofputil_protocol_from_string__(const char *s, size_t n)
{
- return (!strcmp(s, "openflow10") ? NXFF_OPENFLOW10
- : !strcmp(s, "nxm") ? NXFF_NXM
- : -1);
+ const struct proto_abbrev *p;
+ int i;
+
+ for (i = 0; i < CHAR_BIT * sizeof(enum ofputil_protocol); i++) {
+ enum ofputil_protocol bit = 1u << i;
+ const char *name = ofputil_protocol_to_string(bit);
+
+ if (name && n == strlen(name) && !strncasecmp(s, name, n)) {
+ return bit;
+ }
+ }
+
+ for (p = proto_abbrevs; p < &proto_abbrevs[N_PROTO_ABBREVS]; p++) {
+ if (n == strlen(p->name) && !strncasecmp(s, p->name, n)) {
+ return p->protocol;
+ }
+ }
+
+ return 0;
+}
+
+/* Returns the nonempty set of protocols represented by 's', which can be a
+ * single protocol name or abbreviation or a comma-separated list of them.
+ *
+ * Aborts the program with an error message if 's' is invalid. */
+enum ofputil_protocol
+ofputil_protocols_from_string(const char *s)
+{
+ const char *orig_s = s;
+ enum ofputil_protocol protocols;
+
+ protocols = 0;
+ while (*s) {
+ enum ofputil_protocol p;
+ size_t n;
+
+ n = strcspn(s, ",");
+ if (n == 0) {
+ s++;
+ continue;
+ }
+
+ p = ofputil_protocol_from_string__(s, n);
+ if (!p) {
+ ovs_fatal(0, "%.*s: unknown flow protocol", (int) n, s);
+ }
+ protocols |= p;
+
+ s += n;
+ }
+
+ if (!protocols) {
+ ovs_fatal(0, "%s: no flow protocol specified", orig_s);
+ }
+ return protocols;
}
static bool
@@ -850,12 +1064,12 @@ regs_fully_wildcarded(const struct flow_wildcards *wc)
return true;
}
-/* Returns the minimum nx_flow_format to use for sending 'rule' to a switch
- * (e.g. to add or remove a flow). Only NXM can handle tunnel IDs, registers,
- * or fixing the Ethernet multicast bit. Otherwise, it's better to use
- * NXFF_OPENFLOW10 for backward compatibility. */
-enum nx_flow_format
-ofputil_min_flow_format(const struct cls_rule *rule)
+/* Returns a bit-mask of ofputil_protocols that can be used for sending 'rule'
+ * to a switch (e.g. to add or remove a flow). Only NXM can handle tunnel IDs,
+ * registers, or fixing the Ethernet multicast bit. Otherwise, it's better to
+ * use OpenFlow 1.0 protocol for backward compatibility. */
+enum ofputil_protocol
+ofputil_usable_protocols(const struct cls_rule *rule)
{
const struct flow_wildcards *wc = &rule->wc;
@@ -863,68 +1077,95 @@ ofputil_min_flow_format(const struct cls_rule *rule)
/* Only NXM supports separately wildcards the Ethernet multicast bit. */
if (!(wc->wildcards & FWW_DL_DST) != !(wc->wildcards & FWW_ETH_MCAST)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching ARP hardware addresses. */
if (!(wc->wildcards & FWW_ARP_SHA) || !(wc->wildcards & FWW_ARP_THA)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching IPv6 traffic. */
if (!(wc->wildcards & FWW_DL_TYPE)
&& (rule->flow.dl_type == htons(ETH_TYPE_IPV6))) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching registers. */
if (!regs_fully_wildcarded(wc)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching tun_id. */
if (wc->tun_id_mask != htonll(0)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching fragments. */
if (wc->nw_frag_mask) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching IPv6 flow label. */
if (!(wc->wildcards & FWW_IPV6_LABEL)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching IP ECN bits. */
if (!(wc->wildcards & FWW_NW_ECN)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
/* Only NXM supports matching IP TTL/hop limit. */
if (!(wc->wildcards & FWW_NW_TTL)) {
- return NXFF_NXM;
+ return OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID;
}
- /* Other formats can express this rule. */
- return NXFF_OPENFLOW10;
+ /* Any protocol can express this rule. */
+ return OFPUTIL_P_ANY;
}
-/* Returns an OpenFlow message that can be used to set the flow format to
- * 'flow_format'. */
+/* Returns an NXT_SET_FLOW_FORMAT message that can be used to set the flow
+ * format to 'nxff'. */
struct ofpbuf *
-ofputil_make_set_flow_format(enum nx_flow_format flow_format)
+ofputil_encode_nx_set_flow_format(enum nx_flow_format nxff)
{
struct nx_set_flow_format *sff;
struct ofpbuf *msg;
+ assert(ofputil_nx_flow_format_is_valid(nxff));
+
sff = make_nxmsg(sizeof *sff, NXT_SET_FLOW_FORMAT, &msg);
- sff->format = htonl(flow_format);
+ sff->format = htonl(nxff);
return msg;
}
+bool
+ofputil_nx_flow_format_is_valid(enum nx_flow_format flow_format)
+{
+ switch (flow_format) {
+ case NXFF_OPENFLOW10:
+ case NXFF_NXM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+const char *
+ofputil_nx_flow_format_to_string(enum nx_flow_format flow_format)
+{
+ switch (flow_format) {
+ case NXFF_OPENFLOW10:
+ return "openflow10";
+ case NXFF_NXM:
+ return "nxm";
+ default:
+ NOT_REACHED();
+ }
+}
+
/* Returns an OpenFlow message that can be used to turn the flow_mod_table_id
* extension on or off (according to 'flow_mod_table_id'). */
struct ofpbuf *
@@ -942,13 +1183,11 @@ ofputil_make_flow_mod_table_id(bool flow_mod_table_id)
* flow_mod in 'fm'. Returns 0 if successful, otherwise an OpenFlow error
* code.
*
- * 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
- * enabled, false otherwise.
- *
* Does not validate the flow_mod actions. */
enum ofperr
ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
- const struct ofp_header *oh, bool flow_mod_table_id)
+ const struct ofp_header *oh,
+ enum ofputil_protocol protocol)
{
const struct ofputil_msg_type *type;
uint16_t command;
@@ -981,7 +1220,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
/* Translate the rule. */
ofputil_cls_rule_from_match(&ofm->match, priority, &fm->cr);
- ofputil_normalize_rule(&fm->cr, NXFF_OPENFLOW10);
+ ofputil_normalize_rule(&fm->cr);
/* Translate the message. */
fm->cookie = ofm->cookie;
@@ -1020,7 +1259,7 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
NOT_REACHED();
}
- if (flow_mod_table_id) {
+ if (protocol & OFPUTIL_P_TID) {
fm->command = command & 0xff;
fm->table_id = command >> 8;
} else {
@@ -1032,26 +1271,28 @@ ofputil_decode_flow_mod(struct ofputil_flow_mod *fm,
}
/* Converts 'fm' into an OFPT_FLOW_MOD or NXT_FLOW_MOD message according to
- * 'flow_format' and returns the message.
+ * 'protocol' and returns the message.
*
* 'flow_mod_table_id' should be true if the NXT_FLOW_MOD_TABLE_ID extension is
* enabled, false otherwise. */
struct ofpbuf *
ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
- enum nx_flow_format flow_format,
- bool flow_mod_table_id)
+ enum ofputil_protocol protocol)
{
size_t actions_len = fm->n_actions * sizeof *fm->actions;
+ struct ofp_flow_mod *ofm;
+ struct nx_flow_mod *nfm;
struct ofpbuf *msg;
uint16_t command;
+ int match_len;
- command = (flow_mod_table_id
+ command = (protocol & OFPUTIL_P_TID
? (fm->command & 0xff) | (fm->table_id << 8)
: fm->command);
- if (flow_format == NXFF_OPENFLOW10) {
- struct ofp_flow_mod *ofm;
-
+ switch (protocol) {
+ case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_TID:
msg = ofpbuf_new(sizeof *ofm + actions_len);
ofm = put_openflow(sizeof *ofm, OFPT_FLOW_MOD, msg);
ofputil_cls_rule_to_match(&fm->cr, &ofm->match);
@@ -1063,10 +1304,10 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
ofm->buffer_id = htonl(fm->buffer_id);
ofm->out_port = htons(fm->out_port);
ofm->flags = htons(fm->flags);
- } else if (flow_format == NXFF_NXM) {
- struct nx_flow_mod *nfm;
- int match_len;
+ break;
+ case OFPUTIL_P_NXM:
+ case OFPUTIL_P_NXM_TID:
msg = ofpbuf_new(sizeof *nfm + NXM_TYPICAL_LEN + actions_len);
put_nxmsg(sizeof *nfm, NXT_FLOW_MOD, msg);
match_len = nx_put_match(msg, &fm->cr);
@@ -1081,7 +1322,9 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
nfm->out_port = htons(fm->out_port);
nfm->flags = htons(fm->flags);
nfm->match_len = htons(match_len);
- } else {
+ break;
+
+ default:
NOT_REACHED();
}
@@ -1090,6 +1333,27 @@ ofputil_encode_flow_mod(const struct ofputil_flow_mod *fm,
return msg;
}
+enum ofputil_protocol
+ofputil_flow_mod_usable_protocols(const struct ofputil_flow_mod *fms,
+ size_t n_fms)
+{
+ enum ofputil_protocol usable_protocols;
+ size_t i;
+
+ usable_protocols = OFPUTIL_P_ANY;
+ for (i = 0; i < n_fms; i++) {
+ const struct ofputil_flow_mod *fm = &fms[i];
+
+ usable_protocols &= ofputil_usable_protocols(&fm->cr);
+ if (fm->table_id != 0xff) {
+ usable_protocols &= OFPUTIL_P_TID;
+ }
+ }
+ assert(usable_protocols);
+
+ return usable_protocols;
+}
+
static enum ofperr
ofputil_decode_ofpst_flow_request(struct ofputil_flow_stats_request *fsr,
const struct ofp_header *oh,
@@ -1169,14 +1433,16 @@ ofputil_decode_flow_stats_request(struct ofputil_flow_stats_request *fsr,
/* Converts abstract flow_stats_request 'fsr' into an OFPST_FLOW,
* OFPST_AGGREGATE, NXST_FLOW, or NXST_AGGREGATE request 'oh' according to
- * 'flow_format', and returns the message. */
+ * 'protocol', and returns the message. */
struct ofpbuf *
ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
- enum nx_flow_format flow_format)
+ enum ofputil_protocol protocol)
{
struct ofpbuf *msg;
- if (flow_format == NXFF_OPENFLOW10) {
+ switch (protocol) {
+ case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_TID: {
struct ofp_flow_stats_request *ofsr;
int type;
@@ -1185,7 +1451,11 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
ofputil_cls_rule_to_match(&fsr->match, &ofsr->match);
ofsr->table_id = fsr->table_id;
ofsr->out_port = htons(fsr->out_port);
- } else if (flow_format == NXFF_NXM) {
+ break;
+ }
+
+ case OFPUTIL_P_NXM:
+ case OFPUTIL_P_NXM_TID: {
struct nx_flow_stats_request *nfsr;
int match_len;
int subtype;
@@ -1198,7 +1468,10 @@ ofputil_encode_flow_stats_request(const struct ofputil_flow_stats_request *fsr,
nfsr->out_port = htons(fsr->out_port);
nfsr->match_len = htons(match_len);
nfsr->table_id = fsr->table_id;
- } else {
+ break;
+ }
+
+ default:
NOT_REACHED();
}
@@ -1385,7 +1658,7 @@ ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *fs,
}
/* Converts abstract ofputil_aggregate_stats 'stats' into an OFPST_AGGREGATE or
- * NXST_AGGREGATE reply according to 'flow_format', and returns the message. */
+ * NXST_AGGREGATE reply according to 'protocol', and returns the message. */
struct ofpbuf *
ofputil_encode_aggregate_stats_reply(
const struct ofputil_aggregate_stats *stats,
@@ -1474,15 +1747,17 @@ ofputil_decode_flow_removed(struct ofputil_flow_removed *fr,
}
/* Converts abstract ofputil_flow_removed 'fr' into an OFPT_FLOW_REMOVED or
- * NXT_FLOW_REMOVED message 'oh' according to 'flow_format', and returns the
+ * NXT_FLOW_REMOVED message 'oh' according to 'protocol', and returns the
* message. */
struct ofpbuf *
ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
- enum nx_flow_format flow_format)
+ enum ofputil_protocol protocol)
{
struct ofpbuf *msg;
- if (flow_format == NXFF_OPENFLOW10) {
+ switch (protocol) {
+ case OFPUTIL_P_OF10:
+ case OFPUTIL_P_OF10_TID: {
struct ofp_flow_removed *ofr;
ofr = make_openflow_xid(sizeof *ofr, OFPT_FLOW_REMOVED, htonl(0),
@@ -1496,7 +1771,11 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
ofr->idle_timeout = htons(fr->idle_timeout);
ofr->packet_count = htonll(unknown_to_zero(fr->packet_count));
ofr->byte_count = htonll(unknown_to_zero(fr->byte_count));
- } else if (flow_format == NXFF_NXM) {
+ break;
+ }
+
+ case OFPUTIL_P_NXM:
+ case OFPUTIL_P_NXM_TID: {
struct nx_flow_removed *nfr;
int match_len;
@@ -1513,7 +1792,10 @@ ofputil_encode_flow_removed(const struct ofputil_flow_removed *fr,
nfr->match_len = htons(match_len);
nfr->packet_count = htonll(fr->packet_count);
nfr->byte_count = htonll(fr->byte_count);
- } else {
+ break;
+ }
+
+ default:
NOT_REACHED();
}
@@ -2505,12 +2787,9 @@ action_outputs_to_port(const union ofp_action *action, ovs_be16 port)
* example, Open vSwitch does not understand SCTP, an L4 protocol, so the
* L4 fields tp_src and tp_dst must be wildcarded if 'rule' specifies an
* SCTP flow.
- *
- * 'flow_format' specifies the format of the flow as received or as intended to
- * be sent. This is important for IPv6 and ARP, for which NXM supports more
- * detailed matching. */
+ */
void
-ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
+ofputil_normalize_rule(struct cls_rule *rule)
{
enum {
MAY_NW_ADDR = 1 << 0, /* nw_src, nw_dst */
@@ -2533,8 +2812,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
rule->flow.nw_proto == IPPROTO_ICMP) {
may_match |= MAY_TP_ADDR;
}
- } else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)
- && flow_format == NXFF_NXM) {
+ } else if (rule->flow.dl_type == htons(ETH_TYPE_IPV6)) {
may_match = MAY_NW_PROTO | MAY_IPVx | MAY_IPV6;
if (rule->flow.nw_proto == IPPROTO_TCP ||
rule->flow.nw_proto == IPPROTO_UDP) {
@@ -2548,10 +2826,7 @@ ofputil_normalize_rule(struct cls_rule *rule, enum nx_flow_format flow_format)
}
}
} else if (rule->flow.dl_type == htons(ETH_TYPE_ARP)) {
- may_match = MAY_NW_PROTO | MAY_NW_ADDR;
- if (flow_format == NXFF_NXM) {
- may_match |= MAY_ARP_SHA | MAY_ARP_THA;
- }
+ may_match = MAY_NW_PROTO | MAY_NW_ADDR | MAY_ARP_SHA | MAY_ARP_THA;
} else {
may_match = 0;
}
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 88e998e..15bd5c3 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -106,29 +106,74 @@ void ofputil_format_port(uint16_t port, struct ds *);
ovs_be32 ofputil_wcbits_to_netmask(int wcbits);
int ofputil_netmask_to_wcbits(ovs_be32 netmask);
+/* Protocols.
+ *
+ * These are arranged from most portable to least portable, or alternatively
+ * from least powerful to most powerful. Formats earlier on the list are more
+ * likely to be understood for the purpose of making requests, but formats
+ * later on the list are more likely to accurately describe a flow within a
+ * switch.
+ *
+ * On any given OpenFlow connection, a single protocol is in effect at any
+ * given time. These values use separate bits only because that makes it easy
+ * to test whether a particular protocol is within a given set of protocols and
+ * to implement set union and intersection.
+ */
+enum ofputil_protocol {
+ /* OpenFlow 1.0-based protocols. */
+ OFPUTIL_P_OF10 = 1 << 0, /* OpenFlow 1.0 flow format. */
+ OFPUTIL_P_OF10_TID = 1 << 1, /* OF1.0 + flow_mod_table_id extension. */
+#define OFPUTIL_P_OF10_ANY (OFPUTIL_P_OF10 | OFPUTIL_P_OF10_TID)
+
+ /* OpenFlow 1.0 with NXM-based flow formats. */
+ OFPUTIL_P_NXM = 1 << 2, /* Nicira extended match. */
+ OFPUTIL_P_NXM_TID = 1 << 3, /* NXM + flow_mod_table_id extension. */
+#define OFPUTIL_P_NXM_ANY (OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID)
+
+ /* All protocols. */
+#define OFPUTIL_P_ANY (OFPUTIL_P_OF10_ANY | OFPUTIL_P_NXM_ANY)
+
+ /* Protocols in which a specific table may be specified in flow_mods. */
+#define OFPUTIL_P_TID (OFPUTIL_P_OF10_TID | OFPUTIL_P_NXM_TID)
+};
+
+/* Protocols to use for flow dumps, from most to least preferred. */
+extern enum ofputil_protocol ofputil_flow_dump_protocols[];
+extern size_t ofputil_n_flow_dump_protocols;
+
+enum ofputil_protocol ofputil_protocol_from_ofp_version(int version);
+bool ofputil_protocol_is_valid(enum ofputil_protocol);
+enum ofputil_protocol ofputil_protocol_set_tid(enum ofputil_protocol,
+ bool enable);
+enum ofputil_protocol ofputil_protocol_to_base(enum ofputil_protocol);
+enum ofputil_protocol ofputil_protocol_set_base(
+ enum ofputil_protocol cur, enum ofputil_protocol new_base);
+
+const char *ofputil_protocol_to_string(enum ofputil_protocol);
+char *ofputil_protocols_to_string(enum ofputil_protocol);
+enum ofputil_protocol ofputil_protocols_from_string(const char *);
+enum ofputil_protocol ofputil_usable_protocols(const struct cls_rule *);
+
+/* nx_flow_format */
+struct ofpbuf *ofputil_encode_nx_set_flow_format(enum nx_flow_format);
+bool ofputil_nx_flow_format_is_valid(enum nx_flow_format);
+const char *ofputil_nx_flow_format_to_string(enum nx_flow_format);
+
/* Work with OpenFlow 1.0 ofp_match. */
void ofputil_wildcard_from_openflow(uint32_t ofpfw, struct flow_wildcards *);
void ofputil_cls_rule_from_match(const struct ofp_match *,
unsigned int priority, struct cls_rule *);
-void ofputil_normalize_rule(struct cls_rule *, enum nx_flow_format);
+void ofputil_normalize_rule(struct cls_rule *);
void ofputil_cls_rule_to_match(const struct cls_rule *, struct ofp_match *);
/* dl_type translation between OpenFlow and 'struct flow' format. */
ovs_be16 ofputil_dl_type_to_openflow(ovs_be16 flow_dl_type);
ovs_be16 ofputil_dl_type_from_openflow(ovs_be16 ofp_dl_type);
-/* Flow formats. */
-bool ofputil_flow_format_is_valid(enum nx_flow_format);
-const char *ofputil_flow_format_to_string(enum nx_flow_format);
-int ofputil_flow_format_from_string(const char *);
-enum nx_flow_format ofputil_min_flow_format(const struct cls_rule *);
-
-struct ofpbuf *ofputil_make_set_flow_format(enum nx_flow_format);
-
/* NXT_FLOW_MOD_TABLE_ID extension. */
struct ofpbuf *ofputil_make_flow_mod_table_id(bool flow_mod_table_id);
-/* Flow format independent flow_mod. */
+/* Protocol-independent flow_mod. */
struct ofputil_flow_mod {
struct cls_rule cr;
ovs_be64 cookie;
@@ -145,12 +190,14 @@ struct ofputil_flow_mod {
enum ofperr ofputil_decode_flow_mod(struct ofputil_flow_mod *,
const struct ofp_header *,
- bool flow_mod_table_id);
+ enum ofputil_protocol);
struct ofpbuf *ofputil_encode_flow_mod(const struct ofputil_flow_mod *,
- enum nx_flow_format,
- bool flow_mod_table_id);
+ enum ofputil_protocol);
+
+enum ofputil_protocol ofputil_flow_mod_usable_protocols(
+ const struct ofputil_flow_mod *fms, size_t n_fms);
-/* Flow stats or aggregate stats request, independent of flow format. */
+/* Flow stats or aggregate stats request, independent of protocol. */
struct ofputil_flow_stats_request {
bool aggregate; /* Aggregate results? */
struct cls_rule match;
@@ -161,9 +208,9 @@ struct ofputil_flow_stats_request {
enum ofperr ofputil_decode_flow_stats_request(
struct ofputil_flow_stats_request *, const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_stats_request(
- const struct ofputil_flow_stats_request *, enum nx_flow_format);
+ const struct ofputil_flow_stats_request *, enum ofputil_protocol);
-/* Flow stats reply, independent of flow format. */
+/* Flow stats reply, independent of protocol. */
struct ofputil_flow_stats {
struct cls_rule rule;
ovs_be64 cookie;
@@ -183,7 +230,7 @@ int ofputil_decode_flow_stats_reply(struct ofputil_flow_stats *,
void ofputil_append_flow_stats_reply(const struct ofputil_flow_stats *,
struct list *replies);
-/* Aggregate stats reply, independent of flow format. */
+/* Aggregate stats reply, independent of protocol. */
struct ofputil_aggregate_stats {
uint64_t packet_count; /* Packet count, UINT64_MAX if unknown. */
uint64_t byte_count; /* Byte count, UINT64_MAX if unknown. */
@@ -194,7 +241,7 @@ struct ofpbuf *ofputil_encode_aggregate_stats_reply(
const struct ofputil_aggregate_stats *stats,
const struct ofp_stats_msg *request);
-/* Flow removed message, independent of flow format. */
+/* Flow removed message, independent of protocol. */
struct ofputil_flow_removed {
struct cls_rule rule;
ovs_be64 cookie;
@@ -209,7 +256,7 @@ struct ofputil_flow_removed {
enum ofperr ofputil_decode_flow_removed(struct ofputil_flow_removed *,
const struct ofp_header *);
struct ofpbuf *ofputil_encode_flow_removed(const struct ofputil_flow_removed *,
- enum nx_flow_format);
+ enum ofputil_protocol);
/* Abstract packet-in message. */
struct ofputil_packet_in {
diff --git a/lib/rconn.c b/lib/rconn.c
index 1b69b8f..753a073 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -731,6 +731,12 @@ rconn_get_local_port(const struct rconn *rconn)
return rconn->vconn ? vconn_get_local_port(rconn->vconn) : 0;
}
+int
+rconn_get_version(const struct rconn *rconn)
+{
+ return rconn->vconn ? vconn_get_version(rconn->vconn) : -1;
+}
+
/* Returns the total number of packets successfully received by the underlying
* vconn. */
unsigned int
diff --git a/lib/rconn.h b/lib/rconn.h
index a6c2fa7..d0326e6 100644
--- a/lib/rconn.h
+++ b/lib/rconn.h
@@ -76,6 +76,7 @@ ovs_be32 rconn_get_remote_ip(const struct rconn *);
ovs_be16 rconn_get_remote_port(const struct rconn *);
ovs_be32 rconn_get_local_ip(const struct rconn *);
ovs_be16 rconn_get_local_port(const struct rconn *);
+int rconn_get_version(const struct rconn *);
const char *rconn_get_state(const struct rconn *);
unsigned int rconn_get_attempted_connections(const struct rconn *);
diff --git a/lib/util.h b/lib/util.h
index 61039be..3113e8f 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -78,6 +78,12 @@ extern const char *program_name;
/* Returns true if X is a power of 2, otherwise false. */
#define IS_POW2(X) ((X) && !((X) & ((X) - 1)))
+static inline bool
+is_pow2(uintmax_t x)
+{
+ return IS_POW2(x);
+}
+
#ifndef MIN
#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
#endif
diff --git a/lib/vconn.c b/lib/vconn.c
index 8e6374e..c71c61d 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -353,6 +353,17 @@ vconn_get_local_port(const struct vconn *vconn)
return vconn->local_port;
}
+/* Returns the OpenFlow version negotiated with the peer, or -1 if version
+ * negotiation is not yet complete.
+ *
+ * A vconn that has successfully connected (that is, vconn_connect() or
+ * vconn_send() or vconn_recv() has returned 0) always negotiated a version. */
+int
+vconn_get_version(const struct vconn *vconn)
+{
+ return vconn->version;
+}
+
static void
vcs_connecting(struct vconn *vconn)
{
@@ -471,7 +482,7 @@ vconn_connect(struct vconn *vconn)
{
enum vconn_state last_state;
- assert(vconn->min_version >= 0);
+ assert(vconn->min_version > 0);
do {
last_state = vconn->state;
switch (vconn->state) {
@@ -538,14 +549,14 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp)
}
oh = ofpbuf_at_assert(*msgp, 0, sizeof *oh);
- if (oh->version != vconn->version
+ if ((oh->version != vconn->version || oh->version == 0)
&& oh->type != OFPT_HELLO
&& oh->type != OFPT_ERROR
&& oh->type != OFPT_ECHO_REQUEST
&& oh->type != OFPT_ECHO_REPLY
&& oh->type != OFPT_VENDOR)
{
- if (vconn->version < 0) {
+ if (vconn->version == 0) {
VLOG_ERR_RL(&bad_ofmsg_rl,
"%s: received OpenFlow message type %"PRIu8" "
"before version negotiation complete",
@@ -995,8 +1006,8 @@ vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
: !connect_status ? VCS_SEND_HELLO
: VCS_DISCONNECTED);
vconn->error = connect_status;
- vconn->version = -1;
- vconn->min_version = -1;
+ vconn->version = 0;
+ vconn->min_version = 0;
vconn->remote_ip = 0;
vconn->remote_port = 0;
vconn->local_ip = 0;
diff --git a/lib/vconn.h b/lib/vconn.h
index 74b6b49..516e2d3 100644
--- a/lib/vconn.h
+++ b/lib/vconn.h
@@ -40,6 +40,7 @@ ovs_be32 vconn_get_remote_ip(const struct vconn *);
ovs_be16 vconn_get_remote_port(const struct vconn *);
ovs_be32 vconn_get_local_ip(const struct vconn *);
ovs_be16 vconn_get_local_port(const struct vconn *);
+int vconn_get_version(const struct vconn *);
int vconn_connect(struct vconn *);
int vconn_recv(struct vconn *, struct ofpbuf **);
int vconn_send(struct vconn *, struct ofpbuf *);
diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
index 63cb133..1be5a45 100644
--- a/ofproto/connmgr.c
+++ b/ofproto/connmgr.c
@@ -46,7 +46,7 @@ struct ofconn {
struct list node; /* In struct connmgr's "all_conns" list. */
struct rconn *rconn; /* OpenFlow connection. */
enum ofconn_type type; /* Type. */
- enum nx_flow_format flow_format; /* Currently selected flow format. */
+ enum ofputil_protocol protocol; /* Current protocol variant. */
bool flow_mod_table_id; /* NXT_FLOW_MOD_TABLE_ID enabled? */
/* Asynchronous flow table operation support. */
@@ -750,38 +750,23 @@ ofconn_set_role(struct ofconn *ofconn, enum nx_role role)
ofconn->role = role;
}
-/* Returns the currently configured flow format for 'ofconn', one of NXFF_*.
+/* Returns the currently configured protocol for 'ofconn', one of OFPUTIL_P_*.
*
- * The default, if no other format has been set, is NXFF_OPENFLOW10. */
-enum nx_flow_format
-ofconn_get_flow_format(struct ofconn *ofconn)
+ * The default, if no other format has been set, is OFPUTIL_P_OPENFLOW10. */
+enum ofputil_protocol
+ofconn_get_protocol(struct ofconn *ofconn)
{
- return ofconn->flow_format;
+ return ofconn->protocol;
}
-/* Sets the flow format for 'ofconn' to 'flow_format' (one of NXFF_*). */
-void
-ofconn_set_flow_format(struct ofconn *ofconn, enum nx_flow_format flow_format)
-{
- ofconn->flow_format = flow_format;
-}
-
-/* Returns true if the NXT_FLOW_MOD_TABLE_ID extension is enabled, false
- * otherwise.
+/* Sets the protocol for 'ofconn' to 'protocol' (one of OFPUTIL_P_*).
*
- * By default the extension is not enabled. */
-bool
-ofconn_get_flow_mod_table_id(const struct ofconn *ofconn)
-{
- return ofconn->flow_mod_table_id;
-}
-
-/* Enables or disables (according to 'enable') the NXT_FLOW_MOD_TABLE_ID
- * extension on 'ofconn'. */
+ * (This doesn't actually send anything to accomplish this. Presumably the
+ * caller already did that.) */
void
-ofconn_set_flow_mod_table_id(struct ofconn *ofconn, bool enable)
+ofconn_set_protocol(struct ofconn *ofconn, enum ofputil_protocol protocol)
{
- ofconn->flow_mod_table_id = enable;
+ ofconn->protocol = protocol;
}
/* Returns the default miss send length for 'ofconn'. */
@@ -899,7 +884,7 @@ ofconn_create(struct connmgr *mgr, struct rconn *rconn, enum ofconn_type type)
list_push_back(&mgr->all_conns, &ofconn->node);
ofconn->rconn = rconn;
ofconn->type = type;
- ofconn->flow_format = NXFF_OPENFLOW10;
+ ofconn->protocol = OFPUTIL_P_OF10;
ofconn->flow_mod_table_id = false;
list_init(&ofconn->opgroups);
ofconn->role = NX_ROLE_OTHER;
@@ -1139,7 +1124,7 @@ connmgr_send_flow_removed(struct connmgr *mgr,
* prevents new flows from being added (and expiring). (It also
* prevents processing OpenFlow requests that would not add new flows,
* so it is imperfect.) */
- msg = ofputil_encode_flow_removed(fr, ofconn->flow_format);
+ msg = ofputil_encode_flow_removed(fr, ofconn->protocol);
ofconn_send_reply(ofconn, msg);
}
}
diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
index 0040c98..1b49abf 100644
--- a/ofproto/connmgr.h
+++ b/ofproto/connmgr.h
@@ -83,11 +83,8 @@ enum ofconn_type ofconn_get_type(const struct ofconn *);
enum nx_role ofconn_get_role(const struct ofconn *);
void ofconn_set_role(struct ofconn *, enum nx_role);
-enum nx_flow_format ofconn_get_flow_format(struct ofconn *);
-void ofconn_set_flow_format(struct ofconn *, enum nx_flow_format);
-
-bool ofconn_get_flow_mod_table_id(const struct ofconn *);
-void ofconn_set_flow_mod_table_id(struct ofconn *, bool enable);
+enum ofputil_protocol ofconn_get_protocol(struct ofconn *);
+void ofconn_set_protocol(struct ofconn *, enum ofputil_protocol);
int ofconn_get_miss_send_len(const struct ofconn *);
void ofconn_set_miss_send_len(struct ofconn *, int miss_send_len);
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index fc53bf2..0f028be 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2722,8 +2722,7 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
return error;
}
- error = ofputil_decode_flow_mod(&fm, oh,
- ofconn_get_flow_mod_table_id(ofconn));
+ error = ofputil_decode_flow_mod(&fm, oh, ofconn_get_protocol(ofconn));
if (error) {
return error;
}
@@ -2812,8 +2811,12 @@ handle_nxt_flow_mod_table_id(struct ofconn *ofconn,
{
const struct nx_flow_mod_table_id *msg
= (const struct nx_flow_mod_table_id *) oh;
+ enum ofputil_protocol cur, next;
+
+ cur = ofconn_get_protocol(ofconn);
+ next = ofputil_protocol_set_tid(cur, msg->set != 0);
+ ofconn_set_protocol(ofconn, next);
- ofconn_set_flow_mod_table_id(ofconn, msg->set != 0);
return 0;
}
@@ -2822,20 +2825,29 @@ handle_nxt_set_flow_format(struct ofconn *ofconn, const struct ofp_header *oh)
{
const struct nx_set_flow_format *msg
= (const struct nx_set_flow_format *) oh;
- uint32_t format;
+ enum ofputil_protocol cur, next;
+
+ cur = ofconn_get_protocol(ofconn);
+
+ switch (ntohl(msg->format)) {
+ case NXFF_OPENFLOW10:
+ next = ofputil_protocol_set_base(cur, OFPUTIL_P_OF10);
+ break;
- format = ntohl(msg->format);
- if (format != NXFF_OPENFLOW10 && format != NXFF_NXM) {
+ case NXFF_NXM:
+ next = ofputil_protocol_set_base(cur, OFPUTIL_P_NXM);
+ break;
+
+ default:
return OFPERR_OFPBRC_EPERM;
}
- if (format != ofconn_get_flow_format(ofconn)
- && ofconn_has_pending_opgroups(ofconn)) {
- /* Avoid sending async messages in surprising flow format. */
+ if (cur != next && ofconn_has_pending_opgroups(ofconn)) {
+ /* Avoid sending async messages in surprising protocol. */
return OFPROTO_POSTPONE;
}
- ofconn_set_flow_format(ofconn, format);
+ ofconn_set_protocol(ofconn, next);
return 0;
}
diff --git a/tests/autopath.at b/tests/autopath.at
index 6b837f8..c3e0b34 100644
--- a/tests/autopath.at
+++ b/tests/autopath.at
@@ -2,10 +2,14 @@ AT_BANNER([autopath link selection])
AT_SETUP([autopath basic])
AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(1, NXM_NX_REG0[[]])'], [0],
- [OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(1,NXM_NX_REG0[[]])
+ [usable protocols: any
+chosen protocol: OpenFlow10-table_id
+OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(1,NXM_NX_REG0[[]])
])
AT_CHECK([ovs-ofctl parse-flow 'actions=autopath(2, NXM_NX_REG0[[2..30]])'], [0],
- [OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(2,NXM_NX_REG0[[2..30]])
+ [usable protocols: any
+chosen protocol: OpenFlow10-table_id
+OFPT_FLOW_MOD (xid=0x1): ADD actions=autopath(2,NXM_NX_REG0[[2..30]])
])
AT_CLEANUP
diff --git a/tests/learn.at b/tests/learn.at
index 93192ab..86cfa60 100644
--- a/tests/learn.at
+++ b/tests/learn.at
@@ -7,7 +7,9 @@ actions=learn(NXM_OF_VLAN_TCI[0..11], NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[], output:
actions=learn(table=1,idle_timeout=1, hard_timeout=2, priority=10, cookie=0xfedcba9876543210, in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
]])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
-[[OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
+[[usable protocols: any
+chosen protocol: OpenFlow10-table_id
+OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1)
OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[],load:0x000a->NXM_NX_REG0[5..10])
OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,idle_timeout=1,hard_timeout=2,priority=10,cookie=0xfedcba9876543210,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
]])
@@ -22,11 +24,12 @@ table=0 actions=learn(table=1,hard_timeout=10, NXM_OF_VLAN_TCI[0..11],output:NXM
table=1 priority=0 actions=flood
]])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
-[[OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
-OFPT_FLOW_MOD (xid=0x2): ADD actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
-NXT_FLOW_MOD_TABLE_ID (xid=0x3): enable
-OFPT_FLOW_MOD (xid=0x4): ADD actions=learn(table=1,hard_timeout=10,NXM_OF_VLAN_TCI[0..11],output:NXM_OF_IN_PORT[]),resubmit(,1)
-OFPT_FLOW_MOD (xid=0x5): ADD table:1 priority=0 actions=FLOOD
+[[usable protocols: OpenFlow10+table_id,NXM+table_id
+chosen protocol: OpenFlow10+table_id
+OFPT_FLOW_MOD (xid=0x1): ADD table:255 actions=learn(table=1,in_port=99,NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],load:NXM_OF_IN_PORT[]->NXM_NX_REG1[16..31])
+OFPT_FLOW_MOD (xid=0x2): ADD table:255 actions=learn(table=1,NXM_OF_VLAN_TCI[0..11],NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],output:NXM_OF_IN_PORT[])
+OFPT_FLOW_MOD (xid=0x3): ADD actions=learn(table=1,hard_timeout=10,NXM_OF_VLAN_TCI[0..11],output:NXM_OF_IN_PORT[]),resubmit(,1)
+OFPT_FLOW_MOD (xid=0x4): ADD table:1 priority=0 actions=FLOOD
]])
AT_CLEANUP
@@ -37,7 +40,9 @@ ip,actions=learn(load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
ip,actions=learn(eth_type=0x800,NXM_OF_IP_DST[])
]])
AT_CHECK([ovs-ofctl parse-flows flows.txt], [0],
-[[OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x00000005->NXM_OF_IP_DST[])
+[[usable protocols: any
+chosen protocol: OpenFlow10-table_id
+OFPT_FLOW_MOD (xid=0x1): ADD actions=learn(table=1,eth_type=0x800,load:0x00000005->NXM_OF_IP_DST[])
OFPT_FLOW_MOD (xid=0x2): ADD ip actions=learn(table=1,load:NXM_OF_IP_DST[]->NXM_NX_REG1[])
OFPT_FLOW_MOD (xid=0x3): ADD ip actions=learn(table=1,eth_type=0x800,NXM_OF_IP_DST[])
]])
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index acf5809..f186c99 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -1,6 +1,33 @@
AT_BANNER([ovs-ofctl])
-AT_SETUP([ovs-ofctl parse-flows])
+AT_SETUP([ovs-ofctl parse-flows (OpenFlow 1.0)])
+AT_DATA([flows.txt], [[
+# comment
+tcp,tp_src=123,actions=flood
+in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop
+udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0
+tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
+udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
+cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
+actions=note:41.42.43,note:00.01.02.03.04.05.06.07,note
+]])
+
+AT_CHECK([ovs-ofctl parse-flows flows.txt
+], [0], [stdout])
+AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
+[[usable protocols: any
+chosen protocol: OpenFlow10-table_id
+OFPT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD
+OFPT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
+OFPT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
+OFPT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
+OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
+OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
+OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
+]])
+AT_CLEANUP
+
+AT_SETUP([ovs-ofctl parse-flows (NXM)])
AT_DATA([flows.txt], [[
# comment
tcp,tp_src=123,actions=flood
@@ -31,19 +58,19 @@ actions=output:1,exit,output:2
AT_CHECK([ovs-ofctl parse-flows flows.txt
], [0], [stdout])
-AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
-[[OFPT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD
-OFPT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
-OFPT_FLOW_MOD: ADD udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
-OFPT_FLOW_MOD: ADD tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
-OFPT_FLOW_MOD: ADD udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
-OFPT_FLOW_MOD: ADD priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
-OFPT_FLOW_MOD: ADD actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
-NXT_SET_FLOW_FORMAT: format=nxm
-NXT_FLOW_MOD: ADD tun_id=0x1234 cookie:0x5678 actions=FLOOD
-NXT_FLOW_MOD: ADD actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
-NXT_FLOW_MOD: ADD actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
-NXT_FLOW_MOD_TABLE_ID: enable
+AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
+[[usable protocols: NXM+table_id
+chosen protocol: NXM+table_id
+NXT_FLOW_MOD: ADD table:255 tcp,tp_src=123 actions=FLOOD
+NXT_FLOW_MOD: ADD table:255 in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
+NXT_FLOW_MOD: ADD table:255 udp,dl_vlan_pcp=7 idle:5 actions=strip_vlan,output:0
+NXT_FLOW_MOD: ADD table:255 tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
+NXT_FLOW_MOD: ADD table:255 udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
+NXT_FLOW_MOD: ADD table:255 priority=60000 cookie:0x123456789abcdef hard:10 actions=CONTROLLER:65535
+NXT_FLOW_MOD: ADD table:255 actions=note:41.42.43.00.00.00,note:00.01.02.03.04.05.06.07.00.00.00.00.00.00,note:00.00.00.00.00.00
+NXT_FLOW_MOD: ADD table:255 tun_id=0x1234 cookie:0x5678 actions=FLOOD
+NXT_FLOW_MOD: ADD table:255 actions=set_tunnel:0x1234,set_tunnel64:0x9876,set_tunnel64:0x123456789
+NXT_FLOW_MOD: ADD table:255 actions=multipath(eth_src,50,hrw,12,0,NXM_NX_REG0[0..3]),multipath(symmetric_l4,1024,iter_hash,5000,5050,NXM_NX_REG0[0..12])
NXT_FLOW_MOD: ADD table:1 actions=drop
NXT_FLOW_MOD: ADD table:255 tun_id=0x1234000056780000/0xffff0000ffff0000 actions=drop
NXT_FLOW_MOD: ADD table:255 actions=bundle(eth_src,50,active_backup,ofport,slaves:1)
@@ -92,6 +119,8 @@ dl_dst=aa:bb:cc:dd:ee:ff/00:00:00:00:00:00,actions=drop
])
AT_CHECK([ovs-ofctl -F nxm parse-flows flows.txt], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0], [dnl
+usable protocols: NXM
+chosen protocol: NXM-table_id
NXT_FLOW_MOD: ADD tcp,tp_src=123 actions=FLOOD
NXT_FLOW_MOD: ADD in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0 actions=drop
NXT_FLOW_MOD: ADD arp,dl_src=00:0a:e4:25:6b:b0,arp_sha=00:0a:e4:25:6b:b0 actions=drop
@@ -149,7 +178,9 @@ vlan_tci=0x1123/0x1fff,actions=drop
]])
AT_CHECK([ovs-ofctl -F nxm -mmm parse-flows flows.txt], [0], [stdout])
AT_CHECK([[sed 's/ (xid=0x[0-9a-fA-F]*)//' stdout]], [0],
-[[NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(007b) actions=FLOOD
+[[usable protocols: NXM
+chosen protocol: NXM-table_id
+NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(0800), NXM_OF_IP_PROTO(06), NXM_OF_TCP_SRC(007b) actions=FLOOD
NXT_FLOW_MOD: ADD NXM_OF_IN_PORT(fffe), NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_VLAN_TCI_W(1009/1fff) actions=drop
NXT_FLOW_MOD: ADD NXM_OF_ETH_SRC(000ae4256bb0), NXM_OF_ETH_TYPE(0806), NXM_NX_ARP_SHA(000ae4256bb0) actions=drop
NXT_FLOW_MOD: ADD NXM_OF_ETH_TYPE(86dd), NXM_NX_IPV6_LABEL(00012345) actions=output:2
@@ -561,7 +592,7 @@ dnl Check that "-F openflow10" rejects a flow_mod with a tun_id, since
dnl OpenFlow 1.0 doesn't support tunnels.
AT_SETUP([ovs-ofctl -F option and tun_id])
AT_CHECK([ovs-ofctl -F openflow10 add-flow dummy tun_id=123,actions=drop],
- [1], [], [ovs-ofctl: flow cannot be expressed in flow format openflow10 (flow format nxm or better is required)
+ [1], [], [ovs-ofctl: none of the usable flow formats (NXM) is among the allowed flow formats (OpenFlow10)
])
AT_CLEANUP
@@ -596,7 +627,7 @@ dnl can't be represented in OpenFlow 1.0.
AT_SETUP([ovs-ofctl dump-flows rejects bad -F option])
OVS_VSWITCHD_START
AT_CHECK([ovs-ofctl -F openflow10 dump-flows unix:br0.mgmt reg0=0xabcdef], [1], [],
- [ovs-ofctl: unix:br0.mgmt: cannot use requested flow format nxm for specified flow
+ [ovs-ofctl: none of the usable flow formats (NXM) is among the allowed flow formats (OpenFlow10)
])
OVS_VSWITCHD_STOP
AT_CLEANUP
diff --git a/utilities/ovs-controller.c b/utilities/ovs-controller.c
index cb70e4f..25deaff 100644
--- a/utilities/ovs-controller.c
+++ b/utilities/ovs-controller.c
@@ -78,9 +78,9 @@ static uint32_t default_queue = UINT32_MAX;
/* -Q, --port-queue: map from port name to port number (cast to void *). */
static struct shash port_queues = SHASH_INITIALIZER(&port_queues);
-/* --with-flows: Flows to send to switch, or an empty list not to send any
- * default flows. */
-static struct list default_flows = LIST_INITIALIZER(&default_flows);
+/* --with-flows: Flows to send to switch. */
+static struct ofputil_flow_mod *default_flows;
+static size_t n_default_flows;
/* --unixctl: Name of unixctl socket, or null to use the default. */
static char *unixctl_path = NULL;
@@ -230,7 +230,8 @@ new_switch(struct switch_ *sw, struct vconn *vconn)
: LSW_FLOOD);
cfg.wildcards = wildcards;
cfg.max_idle = set_up_flows ? max_idle : -1;
- cfg.default_flows = &default_flows;
+ cfg.default_flows = default_flows;
+ cfg.n_default_flows = n_default_flows;
cfg.default_queue = default_queue;
cfg.port_queues = &port_queues;
sw->lswitch = lswitch_create(sw->rconn, &cfg);
@@ -259,29 +260,6 @@ do_switching(struct switch_ *sw)
}
static void
-read_flow_file(const char *name)
-{
- enum nx_flow_format flow_format;
- bool flow_mod_table_id;
- FILE *stream;
-
- stream = fopen(optarg, "r");
- if (!stream) {
- ovs_fatal(errno, "%s: open", name);
- }
-
- flow_format = NXFF_OPENFLOW10;
- flow_mod_table_id = false;
- while (parse_ofp_flow_mod_file(&default_flows,
- &flow_format, &flow_mod_table_id,
- stream, OFPFC_ADD)) {
- continue;
- }
-
- fclose(stream);
-}
-
-static void
add_port_queue(char *s)
{
char *save_ptr = NULL;
@@ -386,7 +364,8 @@ parse_options(int argc, char *argv[])
break;
case OPT_WITH_FLOWS:
- read_flow_file(optarg);
+ parse_ofp_flow_mod_file(optarg, OFPFC_ADD, &default_flows,
+ &n_default_flows);
break;
case OPT_UNIXCTL:
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index bd184b8..c31b452 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -60,9 +60,9 @@ static bool strict;
* (to reset flow counters). */
static bool readd;
-/* -F, --flow-format: Flow format to use. Either one of NXFF_* to force a
- * particular flow format or -1 to let ovs-ofctl choose intelligently. */
-static int preferred_flow_format = -1;
+/* -F, --flow-format: Allowed protocols. By default, any protocol is
+ * allowed. */
+static enum ofputil_protocol allowed_protocols = OFPUTIL_P_ANY;
/* -m, --more: Additional verbosity for ofp-print functions. */
static int verbosity;
@@ -125,9 +125,9 @@ parse_options(int argc, char *argv[])
break;
case 'F':
- preferred_flow_format = ofputil_flow_format_from_string(optarg);
- if (preferred_flow_format < 0) {
- ovs_fatal(0, "unknown flow format `%s'", optarg);
+ allowed_protocols = ofputil_protocols_from_string(optarg);
+ if (!allowed_protocols) {
+ ovs_fatal(0, "%s: invalid flow format(s)", optarg);
}
break;
@@ -231,12 +231,14 @@ open_vconn_socket(const char *name, struct vconn **vconnp)
free(vconn_name);
}
-static void
+static enum ofputil_protocol
open_vconn__(const char *name, const char *default_suffix,
struct vconn **vconnp)
{
char *datapath_name, *datapath_type, *socket_name;
+ enum ofputil_protocol protocol;
char *bridge_path;
+ int ofp_version;
struct stat s;
bridge_path = xasprintf("%s/%s.%s", ovs_rundir(), name, default_suffix);
@@ -266,9 +268,17 @@ open_vconn__(const char *name, const char *default_suffix,
free(bridge_path);
free(socket_name);
+
+ ofp_version = vconn_get_version(*vconnp);
+ protocol = ofputil_protocol_from_ofp_version(ofp_version);
+ if (!protocol) {
+ ovs_fatal(0, "%s: unsupported OpenFlow version 0x%02x",
+ name, ofp_version);
+ }
+ return protocol;
}
-static void
+static enum ofputil_protocol
open_vconn(const char *name, struct vconn **vconnp)
{
return open_vconn__(name, "mgmt", vconnp);
@@ -511,18 +521,17 @@ str_to_port_no(const char *vconn_name, const char *port_name)
}
static bool
-try_set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
+set_nx_flow_format(struct vconn *vconn, enum nx_flow_format nxff)
{
struct ofpbuf *sff, *reply;
- sff = ofputil_make_set_flow_format(flow_format);
+ sff = ofputil_encode_nx_set_flow_format(nxff);
run(vconn_transact_noreply(vconn, sff, &reply),
"talking to %s", vconn_get_name(vconn));
if (reply) {
char *s = ofp_to_string(reply->data, reply->size, 2);
- VLOG_DBG("%s: failed to set flow format %s, controller replied: %s",
- vconn_get_name(vconn),
- ofputil_flow_format_to_string(flow_format),
+ VLOG_DBG("%s: failed to set flow format %s, switch replied: %s",
+ vconn_get_name(vconn), ofputil_nx_flow_format_to_string(nxff),
s);
free(s);
ofpbuf_delete(reply);
@@ -531,64 +540,113 @@ try_set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
return true;
}
-static void
-set_flow_format(struct vconn *vconn, enum nx_flow_format flow_format)
+static bool
+set_flow_mod_table_id(struct vconn *vconn, bool enable)
{
- struct ofpbuf *sff = ofputil_make_set_flow_format(flow_format);
- transact_noreply(vconn, sff);
- VLOG_DBG("%s: using user-specified flow format %s",
- vconn_get_name(vconn),
- ofputil_flow_format_to_string(flow_format));
+ struct ofpbuf *sfmti, *reply;
+
+ sfmti = ofputil_make_flow_mod_table_id(enable);
+ run(vconn_transact_noreply(vconn, sfmti, &reply),
+ "talking to %s", vconn_get_name(vconn));
+ if (reply) {
+ char *s = ofp_to_string(reply->data, reply->size, 2);
+ VLOG_DBG("%s: failed to %s flow mod table ID extension, "
+ "switch replied: %s",
+ vconn_get_name(vconn),
+ enable ? "enable" : "disable", s);
+ free(s);
+ ofpbuf_delete(reply);
+ return false;
+ }
+ return true;
}
-static enum nx_flow_format
-negotiate_highest_flow_format(struct vconn *vconn,
- enum nx_flow_format min_format)
+static bool
+try_set_protocol(struct vconn *vconn, enum ofputil_protocol next,
+ enum ofputil_protocol *cur)
{
- if (preferred_flow_format != -1) {
- if (preferred_flow_format < min_format) {
- ovs_fatal(0, "%s: cannot use requested flow format %s for "
- "specified flow", vconn_get_name(vconn),
- ofputil_flow_format_to_string(min_format));
+ if (*cur == next) {
+ return true;
+ }
+
+ if (*cur & (OFPUTIL_P_OF10 | OFPUTIL_P_OF10_TID) &&
+ next & (OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID)) {
+ if (!set_nx_flow_format(vconn, NXFF_NXM)) {
+ return false;
+ }
+ *cur = *cur == OFPUTIL_P_OF10 ? OFPUTIL_P_NXM : OFPUTIL_P_NXM_TID;
+ } else if (*cur & (OFPUTIL_P_NXM | OFPUTIL_P_NXM_TID) &&
+ next & (OFPUTIL_P_OF10 | OFPUTIL_P_OF10_TID)) {
+ if (!set_nx_flow_format(vconn, NXFF_OPENFLOW10)) {
+ return false;
}
+ *cur = *cur == OFPUTIL_P_NXM ? OFPUTIL_P_OF10 : OFPUTIL_P_OF10_TID;
+ }
- set_flow_format(vconn, preferred_flow_format);
- return preferred_flow_format;
- } else {
- enum nx_flow_format flow_format;
+ if (*cur == next) {
+ return true;
+ }
- if (try_set_flow_format(vconn, NXFF_NXM)) {
- flow_format = NXFF_NXM;
- } else {
- flow_format = NXFF_OPENFLOW10;
+ if (!(*cur & OFPUTIL_P_TID) && next & OFPUTIL_P_TID) {
+ if (!set_flow_mod_table_id(vconn, true)) {
+ return false;
+ }
+ *cur = *cur == OFPUTIL_P_OF10 ? OFPUTIL_P_OF10_TID : OFPUTIL_P_NXM_TID;
+ } else if (*cur & OFPUTIL_P_TID && !(next & OFPUTIL_P_TID)) {
+ if (!set_flow_mod_table_id(vconn, false)) {
+ return false;
}
+ *cur = *cur == OFPUTIL_P_OF10_TID ? OFPUTIL_P_OF10 : OFPUTIL_P_NXM;
+
+ }
+
+ return *cur == next;
+}
- if (flow_format < min_format) {
- ovs_fatal(0, "%s: cannot use switch's most advanced flow format "
- "%s for specified flow", vconn_get_name(vconn),
- ofputil_flow_format_to_string(min_format));
+/* Checks that at least one of the 'protocols' is acceptable as a flow
+ * format after a flow_mod operation, given the global
+ * 'allowed_protocols'. */
+static enum ofputil_protocol
+set_protocol_for_flow_dump(struct vconn *vconn,
+ enum ofputil_protocol cur_protocol,
+ enum ofputil_protocol usable_protocols)
+{
+ char *usable_s;
+ int i;
+
+ for (i = 0; i < ofputil_n_flow_dump_protocols; i++) {
+ enum ofputil_protocol f = ofputil_flow_dump_protocols[i];
+ if (f & usable_protocols & allowed_protocols
+ && try_set_protocol(vconn, f, &cur_protocol)) {
+ return f;
}
+ }
- VLOG_DBG("%s: negotiated flow format %s", vconn_get_name(vconn),
- ofputil_flow_format_to_string(flow_format));
- return flow_format;
+ usable_s = ofputil_protocols_to_string(usable_protocols);
+ if (usable_protocols & allowed_protocols) {
+ ovs_fatal(0, "switch does not support any of the usable flow "
+ "formats (%s)", usable_s);
+ } else {
+ char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
+ ovs_fatal(0, "none of the usable flow formats (%s) is among the "
+ "allowed flow formats (%s)", usable_s, allowed_s);
}
}
static void
do_dump_flows__(int argc, char *argv[], bool aggregate)
{
- enum nx_flow_format min_flow_format, flow_format;
+ enum ofputil_protocol usable_protocols, protocol;
struct ofputil_flow_stats_request fsr;
struct ofpbuf *request;
struct vconn *vconn;
parse_ofp_flow_stats_request_str(&fsr, aggregate, argc > 2 ? argv[2] : "");
+ usable_protocols = ofputil_usable_protocols(&fsr.match);
- open_vconn(argv[1], &vconn);
- min_flow_format = ofputil_min_flow_format(&fsr.match);
- flow_format = negotiate_highest_flow_format(vconn, min_flow_format);
- request = ofputil_encode_flow_stats_request(&fsr, flow_format);
+ protocol = open_vconn(argv[1], &vconn);
+ protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
+ request = ofputil_encode_flow_stats_request(&fsr, protocol);
dump_stats_transaction(argv[1], request);
vconn_close(vconn);
}
@@ -629,122 +687,110 @@ do_queue_stats(int argc, char *argv[])
dump_stats_transaction(argv[1], request);
}
-/* Sets up the flow format for a vconn that will be used to modify the flow
- * table. Returns the flow format used, after possibly adding an OpenFlow
- * request to 'requests'.
- *
- * If 'preferred_flow_format' is -1, returns NXFF_OPENFLOW10 without modifying
- * 'requests', since NXFF_OPENFLOW10 is the default flow format for any
- * OpenFlow connection.
- *
- * If 'preferred_flow_format' is a specific format, adds a request to set that
- * format to 'requests' and returns the format. */
-static enum nx_flow_format
-set_initial_format_for_flow_mod(struct list *requests)
+static enum ofputil_protocol
+open_vconn_for_flow_mod(const char *remote,
+ const struct ofputil_flow_mod *fms, size_t n_fms,
+ struct vconn **vconnp)
{
- if (preferred_flow_format < 0) {
- return NXFF_OPENFLOW10;
- } else {
- struct ofpbuf *sff;
+ enum ofputil_protocol usable_protocols;
+ enum ofputil_protocol cur_protocol;
+ char *usable_s;
+ int i;
- sff = ofputil_make_set_flow_format(preferred_flow_format);
- list_push_back(requests, &sff->list_node);
- return preferred_flow_format;
+ /* Figure out what flow formats will work. */
+ usable_protocols = ofputil_flow_mod_usable_protocols(fms, n_fms);
+ if (!(usable_protocols & allowed_protocols)) {
+ char *allowed_s = ofputil_protocols_to_string(allowed_protocols);
+ usable_s = ofputil_protocols_to_string(usable_protocols);
+ ovs_fatal(0, "none of the usable flow formats (%s) is among the "
+ "allowed flow formats (%s)", usable_s, allowed_s);
}
-}
-/* Checks that 'flow_format' is acceptable as a flow format after a flow_mod
- * operation, given the global 'preferred_flow_format'. */
-static void
-check_final_format_for_flow_mod(enum nx_flow_format flow_format)
-{
- if (preferred_flow_format >= 0 && flow_format > preferred_flow_format) {
- ovs_fatal(0, "flow cannot be expressed in flow format %s "
- "(flow format %s or better is required)",
- ofputil_flow_format_to_string(preferred_flow_format),
- ofputil_flow_format_to_string(flow_format));
+ /* If the initial flow format is allowed and usable, keep it. */
+ cur_protocol = open_vconn(remote, vconnp);
+ if (usable_protocols & allowed_protocols & cur_protocol) {
+ return cur_protocol;
+ }
+
+ /* Otherwise try each flow format in turn. */
+ for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
+ enum ofputil_protocol f = 1 << i;
+
+ if (f != cur_protocol
+ && f & usable_protocols & allowed_protocols
+ && try_set_protocol(*vconnp, f, &cur_protocol)) {
+ return f;
+ }
}
+
+ usable_s = ofputil_protocols_to_string(usable_protocols);
+ ovs_fatal(0, "switch does not support any of the usable flow "
+ "formats (%s)", usable_s);
}
static void
-do_flow_mod_file__(int argc OVS_UNUSED, char *argv[], uint16_t command)
+do_flow_mod__(const char *remote, struct ofputil_flow_mod *fms, size_t n_fms)
{
- enum nx_flow_format flow_format;
- bool flow_mod_table_id;
- struct list requests;
+ enum ofputil_protocol protocol;
struct vconn *vconn;
- FILE *file;
+ size_t i;
- file = !strcmp(argv[2], "-") ? stdin : fopen(argv[2], "r");
- if (file == NULL) {
- ovs_fatal(errno, "%s: open", argv[2]);
- }
+ protocol = open_vconn_for_flow_mod(remote, fms, n_fms, &vconn);
- list_init(&requests);
- flow_format = set_initial_format_for_flow_mod(&requests);
- flow_mod_table_id = false;
+ for (i = 0; i < n_fms; i++) {
+ struct ofputil_flow_mod *fm = &fms[i];
- open_vconn(argv[1], &vconn);
- while (parse_ofp_flow_mod_file(&requests, &flow_format, &flow_mod_table_id,
- file, command)) {
- check_final_format_for_flow_mod(flow_format);
- transact_multiple_noreply(vconn, &requests);
+ transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
+ free(fm->actions);
}
vconn_close(vconn);
-
- if (file != stdin) {
- fclose(file);
- }
}
static void
-do_flow_mod__(int argc, char *argv[], uint16_t command)
+do_flow_mod_file(int argc OVS_UNUSED, char *argv[], uint16_t command)
{
- enum nx_flow_format flow_format;
- bool flow_mod_table_id;
- struct list requests;
- struct vconn *vconn;
+ struct ofputil_flow_mod *fms = NULL;
+ size_t n_fms = 0;
+
+ parse_ofp_flow_mod_file(argv[2], command, &fms, &n_fms);
+ do_flow_mod__(argv[1], fms, n_fms);
+ free(fms);
+}
+static void
+do_flow_mod(int argc, char *argv[], uint16_t command)
+{
if (argc > 2 && !strcmp(argv[2], "-")) {
- do_flow_mod_file__(argc, argv, command);
- return;
+ do_flow_mod_file(argc, argv, command);
+ } else {
+ struct ofputil_flow_mod fm;
+ parse_ofp_flow_mod_str(&fm, argc > 2 ? argv[2] : "", command, false);
+ do_flow_mod__(argv[1], &fm, 1);
}
-
- list_init(&requests);
- flow_format = set_initial_format_for_flow_mod(&requests);
- flow_mod_table_id = false;
-
- parse_ofp_flow_mod_str(&requests, &flow_format, &flow_mod_table_id,
- argc > 2 ? argv[2] : "", command, false);
- check_final_format_for_flow_mod(flow_format);
-
- open_vconn(argv[1], &vconn);
- transact_multiple_noreply(vconn, &requests);
- vconn_close(vconn);
}
static void
do_add_flow(int argc, char *argv[])
{
- do_flow_mod__(argc, argv, OFPFC_ADD);
+ do_flow_mod(argc, argv, OFPFC_ADD);
}
static void
do_add_flows(int argc, char *argv[])
{
- do_flow_mod_file__(argc, argv, OFPFC_ADD);
+ do_flow_mod_file(argc, argv, OFPFC_ADD);
}
static void
do_mod_flows(int argc, char *argv[])
{
- do_flow_mod__(argc, argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
+ do_flow_mod(argc, argv, strict ? OFPFC_MODIFY_STRICT : OFPFC_MODIFY);
}
static void
do_del_flows(int argc, char *argv[])
{
- do_flow_mod__(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
+ do_flow_mod(argc, argv, strict ? OFPFC_DELETE_STRICT : OFPFC_DELETE);
}
static void
@@ -1116,12 +1162,12 @@ fte_insert(struct classifier *cls, const struct cls_rule *rule,
}
/* Reads the flows in 'filename' as flow table entries in 'cls' for the version
- * with the specified 'index'. Returns the minimum flow format required to
- * represent the flows that were read. */
-static enum nx_flow_format
+ * with the specified 'index'. Returns the flow formats able to represent the
+ * flows that were read. */
+static enum ofputil_protocol
read_flows_from_file(const char *filename, struct classifier *cls, int index)
{
- enum nx_flow_format min_flow_format;
+ enum ofputil_protocol usable_protocols;
struct ds s;
FILE *file;
@@ -1131,11 +1177,10 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
}
ds_init(&s);
- min_flow_format = NXFF_OPENFLOW10;
+ usable_protocols = OFPUTIL_P_ANY;
while (!ds_get_preprocessed_line(&s, file)) {
struct fte_version *version;
struct ofputil_flow_mod fm;
- enum nx_flow_format min_ff;
parse_ofp_str(&fm, OFPFC_ADD, ds_cstr(&s), true);
@@ -1147,9 +1192,7 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
version->actions = fm.actions;
version->n_actions = fm.n_actions;
- min_ff = ofputil_min_flow_format(&fm.cr);
- min_flow_format = MAX(min_flow_format, min_ff);
- check_final_format_for_flow_mod(min_flow_format);
+ usable_protocols &= ofputil_usable_protocols(&fm.cr);
fte_insert(cls, &fm.cr, version, index);
}
@@ -1159,14 +1202,15 @@ read_flows_from_file(const char *filename, struct classifier *cls, int index)
fclose(file);
}
- return min_flow_format;
+ return usable_protocols;
}
/* Reads the OpenFlow flow table from 'vconn', which has currently active flow
- * format 'flow_format', and adds them as flow table entries in 'cls' for the
+ * format 'protocol', and adds them as flow table entries in 'cls' for the
* version with the specified 'index'. */
static void
-read_flows_from_switch(struct vconn *vconn, enum nx_flow_format flow_format,
+read_flows_from_switch(struct vconn *vconn,
+ enum ofputil_protocol protocol,
struct classifier *cls, int index)
{
struct ofputil_flow_stats_request fsr;
@@ -1178,7 +1222,7 @@ read_flows_from_switch(struct vconn *vconn, enum nx_flow_format flow_format,
cls_rule_init_catchall(&fsr.match, 0);
fsr.out_port = OFPP_NONE;
fsr.table_id = 0xff;
- request = ofputil_encode_flow_stats_request(&fsr, flow_format);
+ request = ofputil_encode_flow_stats_request(&fsr, protocol);
send_xid = ((struct ofp_header *) request->data)->xid;
send_openflow_buffer(vconn, request);
@@ -1242,7 +1286,7 @@ read_flows_from_switch(struct vconn *vconn, enum nx_flow_format flow_format,
static void
fte_make_flow_mod(const struct fte *fte, int index, uint16_t command,
- enum nx_flow_format flow_format, struct list *packets)
+ enum ofputil_protocol protocol, struct list *packets)
{
const struct fte_version *version = fte->versions[index];
struct ofputil_flow_mod fm;
@@ -1266,7 +1310,7 @@ fte_make_flow_mod(const struct fte *fte, int index, uint16_t command,
fm.n_actions = 0;
}
- ofm = ofputil_encode_flow_mod(&fm, flow_format, false);
+ ofm = ofputil_encode_flow_mod(&fm, protocol);
list_push_back(packets, &ofm->list_node);
}
@@ -1274,7 +1318,7 @@ static void
do_replace_flows(int argc OVS_UNUSED, char *argv[])
{
enum { FILE_IDX = 0, SWITCH_IDX = 1 };
- enum nx_flow_format min_flow_format, flow_format;
+ enum ofputil_protocol usable_protocols, protocol;
struct cls_cursor cursor;
struct classifier cls;
struct list requests;
@@ -1282,11 +1326,12 @@ do_replace_flows(int argc OVS_UNUSED, char *argv[])
struct fte *fte;
classifier_init(&cls);
- min_flow_format = read_flows_from_file(argv[2], &cls, FILE_IDX);
+ usable_protocols = read_flows_from_file(argv[2], &cls, FILE_IDX);
- open_vconn(argv[1], &vconn);
- flow_format = negotiate_highest_flow_format(vconn, min_flow_format);
- read_flows_from_switch(vconn, flow_format, &cls, SWITCH_IDX);
+ protocol = open_vconn(argv[1], &vconn);
+ protocol = set_protocol_for_flow_dump(vconn, protocol, usable_protocols);
+
+ read_flows_from_switch(vconn, protocol, &cls, SWITCH_IDX);
list_init(&requests);
@@ -1298,7 +1343,7 @@ do_replace_flows(int argc OVS_UNUSED, char *argv[])
if (sw_ver && !file_ver) {
fte_make_flow_mod(fte, SWITCH_IDX, OFPFC_DELETE_STRICT,
- flow_format, &requests);
+ protocol, &requests);
}
}
@@ -1311,8 +1356,7 @@ do_replace_flows(int argc OVS_UNUSED, char *argv[])
if (file_ver
&& (readd || !sw_ver || !fte_version_equals(sw_ver, file_ver))) {
- fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, flow_format,
- &requests);
+ fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests);
}
}
transact_multiple_noreply(vconn, &requests);
@@ -1330,12 +1374,12 @@ read_flows_from_source(const char *source, struct classifier *cls, int index)
|| (!strchr(source, ':') && !stat(source, &s))) {
read_flows_from_file(source, cls, index);
} else {
- enum nx_flow_format flow_format;
+ enum ofputil_protocol protocol;
struct vconn *vconn;
- open_vconn(source, &vconn);
- flow_format = negotiate_highest_flow_format(vconn, NXFF_OPENFLOW10);
- read_flows_from_switch(vconn, flow_format, cls, index);
+ protocol = open_vconn(source, &vconn);
+ protocol = set_protocol_for_flow_dump(vconn, protocol, OFPUTIL_P_ANY);
+ read_flows_from_switch(vconn, protocol, cls, index);
vconn_close(vconn);
}
}
@@ -1383,14 +1427,39 @@ do_diff_flows(int argc OVS_UNUSED, char *argv[])
/* Undocumented commands for unit testing. */
static void
-print_packet_list(struct list *packets)
+do_parse_flows__(struct ofputil_flow_mod *fms, size_t n_fms)
{
- struct ofpbuf *packet, *next;
+ enum ofputil_protocol usable_protocols;
+ enum ofputil_protocol protocol = 0;
+ char *usable_s;
+ size_t i;
+
+ usable_protocols = ofputil_flow_mod_usable_protocols(fms, n_fms);
+ usable_s = ofputil_protocols_to_string(usable_protocols);
+ printf("usable protocols: %s\n", usable_s);
+ free(usable_s);
- LIST_FOR_EACH_SAFE (packet, next, list_node, packets) {
- ofp_print(stdout, packet->data, packet->size, verbosity);
- list_remove(&packet->list_node);
- ofpbuf_delete(packet);
+ if (!(usable_protocols & allowed_protocols)) {
+ ovs_fatal(0, "no usable protocol");
+ }
+ for (i = 0; i < sizeof(enum ofputil_protocol) * CHAR_BIT; i++) {
+ protocol = 1 << i;
+ if (protocol & usable_protocols & allowed_protocols) {
+ break;
+ }
+ }
+
+ printf("chosen protocol: %s\n", ofputil_protocol_to_string(protocol));
+
+ for (i = 0; i < n_fms; i++) {
+ struct ofputil_flow_mod *fm = &fms[i];
+ struct ofpbuf *msg;
+
+ msg = ofputil_encode_flow_mod(fm, protocol);
+ ofp_print(stdout, msg->data, msg->size, verbosity);
+ ofpbuf_delete(msg);
+
+ free(fm->actions);
}
}
@@ -1399,20 +1468,10 @@ print_packet_list(struct list *packets)
static void
do_parse_flow(int argc OVS_UNUSED, char *argv[])
{
- enum nx_flow_format flow_format;
- bool flow_mod_table_id;
- struct list packets;
-
- flow_format = NXFF_OPENFLOW10;
- if (preferred_flow_format > 0) {
- flow_format = preferred_flow_format;
- }
- flow_mod_table_id = false;
+ struct ofputil_flow_mod fm;
- list_init(&packets);
- parse_ofp_flow_mod_str(&packets, &flow_format, &flow_mod_table_id,
- argv[1], OFPFC_ADD, false);
- print_packet_list(&packets);
+ parse_ofp_flow_mod_str(&fm, argv[1], OFPFC_ADD, false);
+ do_parse_flows__(&fm, 1);
}
/* "parse-flows FILENAME": reads the named file as a sequence of flows (like
@@ -1420,28 +1479,12 @@ do_parse_flow(int argc OVS_UNUSED, char *argv[])
static void
do_parse_flows(int argc OVS_UNUSED, char *argv[])
{
- enum nx_flow_format flow_format;
- bool flow_mod_table_id;
- struct list packets;
- FILE *file;
+ struct ofputil_flow_mod *fms = NULL;
+ size_t n_fms = 0;
- file = fopen(argv[1], "r");
- if (file == NULL) {
- ovs_fatal(errno, "%s: open", argv[1]);
- }
-
- flow_format = NXFF_OPENFLOW10;
- if (preferred_flow_format > 0) {
- flow_format = preferred_flow_format;
- }
- flow_mod_table_id = false;
-
- list_init(&packets);
- while (parse_ofp_flow_mod_file(&packets, &flow_format, &flow_mod_table_id,
- file, OFPFC_ADD)) {
- print_packet_list(&packets);
- }
- fclose(file);
+ parse_ofp_flow_mod_file(argv[1], OFPFC_ADD, &fms, &n_fms);
+ do_parse_flows__(fms, n_fms);
+ free(fms);
}
/* "parse-nx-match": reads a series of nx_match specifications as strings from
--
1.7.2.5
More information about the dev
mailing list