[ovs-dev] [PATCH v2 3/3] Implement OpenFlow 1.4+ OFPMP_TABLE_DESC message.
Ben Pfaff
blp at nicira.com
Fri Jul 3 03:41:14 UTC 2015
Signed-off-by: Ben Pfaff <blp at nicira.com>
Co-authored-by: Saloni Jain <saloni.jain at tcs.com>
Signed-off-by: Saloni Jain <saloni.jain at tcs.com>
Acked-by: Jarno Rajahalme <jrajahalme at nicira.com>
---
v1->v2: Use OFPROTO_EVICTION_FLAGS. Fix documentation. Fix style nits.
NEWS | 1 +
include/openflow/openflow-1.4.h | 10 +++
lib/learning-switch.c | 2 +
lib/ofp-msgs.h | 10 +++
lib/ofp-print.c | 39 ++++++++++++
lib/ofp-util.c | 135 ++++++++++++++++++++++++++++++++++++++++
lib/ofp-util.h | 21 +++++++
lib/rconn.c | 2 +
ofproto/ofproto.c | 45 ++++++++++++++
ovn/controller/ofctrl.c | 2 +
tests/ofproto.at | 22 +++++++
utilities/ovs-ofctl.8.in | 4 ++
utilities/ovs-ofctl.c | 19 ++++++
13 files changed, 312 insertions(+)
diff --git a/NEWS b/NEWS
index 57e4f89..59f2552 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ Post-v2.4.0
now supported.
* OpenFlow 1.4+ "importance" is now considered for flow eviction.
* OpenFlow 1.4+ OFPTC_EVICTION is now implemented.
+ * OpenFlow 1.4+ OFPMP_TABLE_DESC is now implemented.
- Support for matching and generating options with Geneve tunnels.
- Support Multicast Listener Discovery (MLDv1 and MLDv2).
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index 7631e47..567aaae 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -155,6 +155,16 @@ struct ofp14_table_mod {
};
OFP_ASSERT(sizeof(struct ofp14_table_mod) == 8);
+/* Body of reply to OFPMP_TABLE_DESC request. */
+struct ofp14_table_desc {
+ ovs_be16 length; /* Length is padded to 64 bits. */
+ uint8_t table_id; /* Identifier of table. Lower numbered tables
+ are consulted first. */
+ uint8_t pad[1]; /* Align to 32-bits. */
+ ovs_be32 config; /* Bitmap of OFPTC_* values. */
+ /* Followed by 0 or more OFPTMPT14_* properties. */
+};
+OFP_ASSERT(sizeof(struct ofp14_table_desc) == 8);
/* ## ---------------- ## */
/* ## ofp14_port_stats ## */
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 2fe38a0..1753cea 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -447,6 +447,8 @@ lswitch_process_packet(struct lswitch *sw, const struct ofpbuf *msg)
case OFPTYPE_METER_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_DESC_REQUEST:
+ case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_BUNDLE_CONTROL:
case OFPTYPE_BUNDLE_ADD_MESSAGE:
case OFPTYPE_NXT_GENEVE_TABLE_MOD:
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index e28bd50..29729c0 100644
--- a/lib/ofp-msgs.h
+++ b/lib/ofp-msgs.h
@@ -369,6 +369,12 @@ enum ofpraw {
/* OFPST 1.3+ (12): struct ofp13_table_features, uint8_t[8][]. */
OFPRAW_OFPST13_TABLE_FEATURES_REPLY,
+ /* OFPST 1.4+ (15): void. */
+ OFPRAW_OFPST14_TABLE_DESC_REQUEST,
+
+ /* OFPST 1.4+ (15): struct ofp14_table_desc, uint8_t[8][]. */
+ OFPRAW_OFPST14_TABLE_DESC_REPLY,
+
/* OFPST 1.0-1.4 (13): void. */
OFPRAW_OFPST10_PORT_DESC_REQUEST,
/* OFPST 1.5+ (13): ovs_be32. */
@@ -611,6 +617,10 @@ enum ofptype {
OFPTYPE_TABLE_FEATURES_STATS_REPLY, /* OFPRAW_OFPST13_TABLE_FEATURES_REPLY. */
+ OFPTYPE_TABLE_DESC_REQUEST, /* OFPRAW_OFPST14_TABLE_DESC_REQUEST. */
+
+ OFPTYPE_TABLE_DESC_REPLY, /* OFPRAW_OFPST14_TABLE_DESC_REPLY. */
+
OFPTYPE_PORT_DESC_STATS_REQUEST, /* OFPRAW_OFPST10_PORT_DESC_REQUEST.
* OFPRAW_OFPST15_PORT_DESC_REQUEST. */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index d76134f..4603bb7 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -1025,6 +1025,18 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
}
}
+/* This function will print the Table description properties. */
+static void
+ofp_print_table_desc(struct ds *string, const struct ofputil_table_desc *td)
+{
+ ds_put_format(string, "\n table %"PRIu8, td->table_id);
+ ds_put_cstr(string, ":\n");
+ ds_put_format(string, " eviction=%s eviction_flags=",
+ ofputil_table_eviction_to_string(td->eviction));
+ ofputil_put_eviction_flags(string, td->eviction_flags);
+ ds_put_char(string, '\n');
+}
+
static void
ofp_print_queue_get_config_request(struct ds *string,
const struct ofp_header *oh)
@@ -2607,6 +2619,28 @@ ofp_print_table_features_reply(struct ds *s, const struct ofp_header *oh)
}
}
+static void
+ofp_print_table_desc_reply(struct ds *s, const struct ofp_header *oh)
+{
+ struct ofpbuf b;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+
+ for (;;) {
+ struct ofputil_table_desc td;
+ int retval;
+
+ retval = ofputil_decode_table_desc(&b, &td, oh->version);
+ if (retval) {
+ if (retval != EOF) {
+ ofp_print_error(s, retval);
+ }
+ return;
+ }
+ ofp_print_table_desc(s, &td);
+ }
+}
+
static const char *
bundle_flags_to_name(uint32_t bit)
{
@@ -2814,6 +2848,11 @@ ofp_to_string__(const struct ofp_header *oh, enum ofpraw raw,
ofp_print_table_features_reply(string, oh);
break;
+ case OFPTYPE_TABLE_DESC_REQUEST:
+ case OFPTYPE_TABLE_DESC_REPLY:
+ ofp_print_table_desc_reply(string, oh);
+ break;
+
case OFPTYPE_HELLO:
ofp_print_hello(string, oh);
break;
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 2e9ae47..f7dbdd5 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4887,6 +4887,139 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
}
static enum ofperr
+parse_table_desc_eviction_property(struct ofpbuf *property,
+ struct ofputil_table_desc *td)
+{
+ struct ofp14_table_mod_prop_eviction *ote = property->data;
+
+ if (property->size != sizeof *ote) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+
+ td->eviction_flags = ntohl(ote->flags);
+ return 0;
+}
+
+/* Decodes the next OpenFlow "table desc" message (of possibly several) from
+ * 'msg' into an abstract form in '*td'. Returns 0 if successful, EOF if the
+ * last "table desc" in 'msg' was already decoded, otherwise an OFPERR_*
+ * value. */
+int
+ofputil_decode_table_desc(struct ofpbuf *msg,
+ struct ofputil_table_desc *td,
+ enum ofp_version version)
+{
+ struct ofp14_table_desc *otd;
+ struct ofpbuf properties;
+ size_t length;
+
+ memset(td, 0, sizeof *td);
+
+ if (!msg->header) {
+ ofpraw_pull_assert(msg);
+ }
+
+ if (!msg->size) {
+ return EOF;
+ }
+
+ otd = ofpbuf_try_pull(msg, sizeof *otd);
+ if (!otd) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply has %"PRIu32" "
+ "leftover bytes at end", msg->size);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ td->table_id = otd->table_id;
+ length = ntohs(otd->length);
+ if (length < sizeof *otd || length - sizeof *otd > msg->size) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC reply claims invalid "
+ "length %"PRIuSIZE, length);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+ length -= sizeof *otd;
+ ofpbuf_use_const(&properties, ofpbuf_pull(msg, length), length);
+
+ td->eviction = ofputil_decode_table_eviction(otd->config, version);
+ td->eviction_flags = UINT32_MAX;
+
+ while (properties.size > 0) {
+ struct ofpbuf payload;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(&properties, &payload, &type);
+ if (error) {
+ return error;
+ }
+
+ switch (type) {
+ case OFPTMPT14_EVICTION:
+ error = parse_table_desc_eviction_property(&payload, td);
+ break;
+
+ default:
+ log_property(true, "unknown table_desc property %"PRIu16, type);
+ error = 0;
+ break;
+ }
+
+ if (error) {
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+/* Encodes and returns a request to obtain description of tables of a switch.
+ * The message is encoded for OpenFlow version 'ofp_version'. */
+struct ofpbuf *
+ofputil_encode_table_desc_request(enum ofp_version ofp_version)
+{
+ struct ofpbuf *request = NULL;
+
+ if (ofp_version >= OFP14_VERSION) {
+ request = ofpraw_alloc(OFPRAW_OFPST14_TABLE_DESC_REQUEST,
+ ofp_version, 0);
+ } else {
+ ovs_fatal(0, "dump-table-desc needs OpenFlow 1.4 or later "
+ "(\'-O OpenFlow14\')");
+ }
+
+ return request;
+}
+
+/* Function to append Table desc information in a reply list. */
+void
+ofputil_append_table_desc_reply(const struct ofputil_table_desc *td,
+ struct ovs_list *replies,
+ enum ofp_version version)
+{
+ struct ofpbuf *reply = ofpbuf_from_list(list_back(replies));
+ size_t start_otd;
+ struct ofp14_table_desc *otd;
+
+ start_otd = reply->size;
+ ofpbuf_put_zeros(reply, sizeof *otd);
+ if (td->eviction_flags != UINT32_MAX) {
+ struct ofp14_table_mod_prop_eviction *ote;
+
+ ote = ofpbuf_put_zeros(reply, sizeof *ote);
+ ote->type = htons(OFPTMPT14_EVICTION);
+ ote->length = htons(sizeof *ote);
+ ote->flags = htonl(td->eviction_flags);
+ }
+
+ otd = ofpbuf_at_assert(reply, start_otd, sizeof *otd);
+ otd->length = htons(reply->size - start_otd);
+ otd->table_id = td->table_id;
+ otd->config = ofputil_encode_table_config(OFPUTIL_TABLE_MISS_DEFAULT,
+ td->eviction, version);
+ ofpmp_postappend(replies, start_otd);
+}
+
+static enum ofperr
parse_table_mod_eviction_property(struct ofpbuf *property,
struct ofputil_table_mod *tm)
{
@@ -8890,6 +9023,7 @@ ofputil_is_bundlable(enum ofptype type)
case OFPTYPE_AGGREGATE_STATS_REQUEST:
case OFPTYPE_TABLE_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
+ case OFPTYPE_TABLE_DESC_REQUEST:
case OFPTYPE_PORT_STATS_REQUEST:
case OFPTYPE_QUEUE_STATS_REQUEST:
case OFPTYPE_PORT_DESC_STATS_REQUEST:
@@ -8931,6 +9065,7 @@ ofputil_is_bundlable(enum ofptype type)
case OFPTYPE_METER_CONFIG_STATS_REPLY:
case OFPTYPE_METER_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_NXT_GENEVE_TABLE_REQUEST:
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index fbc8abf..431f165 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -638,6 +638,13 @@ struct ofputil_table_mod {
uint32_t eviction_flags; /* OFPTMPEF14_*. */
};
+/* Abstract ofp14_table_desc. */
+struct ofputil_table_desc {
+ uint8_t table_id; /* ID of the table. */
+ enum ofputil_table_eviction eviction;
+ uint32_t eviction_flags; /* UINT32_MAX if not present. */
+};
+
enum ofperr ofputil_decode_table_mod(const struct ofp_header *,
struct ofputil_table_mod *);
struct ofpbuf *ofputil_encode_table_mod(const struct ofputil_table_mod *,
@@ -726,11 +733,22 @@ struct ofputil_table_features {
int ofputil_decode_table_features(struct ofpbuf *,
struct ofputil_table_features *, bool loose);
+
+int ofputil_decode_table_desc(struct ofpbuf *,
+ struct ofputil_table_desc *,
+ enum ofp_version);
+
struct ofpbuf *ofputil_encode_table_features_request(enum ofp_version);
+struct ofpbuf *ofputil_encode_table_desc_request(enum ofp_version);
+
void ofputil_append_table_features_reply(
const struct ofputil_table_features *tf, struct ovs_list *replies);
+void ofputil_append_table_desc_reply(const struct ofputil_table_desc *td,
+ struct ovs_list *replies,
+ enum ofp_version);
+
/* Meter band configuration for all supported band types. */
struct ofputil_meter_band {
uint16_t type;
@@ -857,6 +875,9 @@ struct ofputil_table_stats {
};
struct ofpbuf *ofputil_encode_table_stats_reply(const struct ofp_header *rq);
+
+struct ofpbuf *ofputil_encode_table_desc_reply(const struct ofp_header *rq);
+
void ofputil_append_table_stats_reply(struct ofpbuf *reply,
const struct ofputil_table_stats *,
const struct ofputil_table_features *);
diff --git a/lib/rconn.c b/lib/rconn.c
index 776ab9e..37adfa2 100644
--- a/lib/rconn.c
+++ b/lib/rconn.c
@@ -1365,6 +1365,8 @@ is_admitted_msg(const struct ofpbuf *b)
case OFPTYPE_GROUP_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_DESC_REQUEST:
+ case OFPTYPE_TABLE_DESC_REPLY:
return false;
case OFPTYPE_PACKET_IN:
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 970aca3..7ca6504 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -3576,6 +3576,47 @@ handle_table_features_request(struct ofconn *ofconn,
return 0;
}
+/* This function queries the database for dumping table-desc. */
+static void
+query_tables_desc(struct ofproto *ofproto, struct ofputil_table_desc **descp)
+{
+ struct ofputil_table_desc *table_desc;
+ size_t i;
+
+ table_desc = *descp = xcalloc(ofproto->n_tables, sizeof *table_desc);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ struct ofputil_table_desc *td = &table_desc[i];
+ td->table_id = i;
+ td->eviction = (ofproto->tables[i].eviction & EVICTION_OPENFLOW
+ ? OFPUTIL_TABLE_EVICTION_ON
+ : OFPUTIL_TABLE_EVICTION_OFF);
+ td->eviction_flags = OFPROTO_EVICTION_FLAGS;
+ }
+}
+
+/* Function to handle dump-table-desc request. */
+static enum ofperr
+handle_table_desc_request(struct ofconn *ofconn,
+ const struct ofp_header *request)
+{
+ struct ofproto *ofproto = ofconn_get_ofproto(ofconn);
+ struct ofputil_table_desc *table_desc;
+ struct ovs_list replies;
+ size_t i;
+
+ query_tables_desc(ofproto, &table_desc);
+ ofpmp_init(&replies, request);
+ for (i = 0; i < ofproto->n_tables; i++) {
+ if (!(ofproto->tables[i].flags & OFTABLE_HIDDEN)) {
+ ofputil_append_table_desc_reply(&table_desc[i], &replies,
+ request->version);
+ }
+ }
+ ofconn_send_replies(ofconn, &replies);
+ free(table_desc);
+ return 0;
+}
+
static void
append_port_stat(struct ofport *port, struct ovs_list *replies)
{
@@ -7105,6 +7146,9 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
return handle_table_features_request(ofconn, oh);
+ case OFPTYPE_TABLE_DESC_REQUEST:
+ return handle_table_desc_request(ofconn, oh);
+
case OFPTYPE_PORT_STATS_REQUEST:
return handle_port_stats_request(ofconn, oh);
@@ -7176,6 +7220,7 @@ handle_openflow__(struct ofconn *ofconn, const struct ofpbuf *msg)
case OFPTYPE_METER_CONFIG_STATS_REPLY:
case OFPTYPE_METER_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_ROLE_STATUS:
case OFPTYPE_NXT_GENEVE_TABLE_REPLY:
default:
diff --git a/ovn/controller/ofctrl.c b/ovn/controller/ofctrl.c
index 8405001..2c424a6 100644
--- a/ovn/controller/ofctrl.c
+++ b/ovn/controller/ofctrl.c
@@ -225,6 +225,8 @@ ofctrl_recv(const struct ofpbuf *msg)
case OFPTYPE_METER_FEATURES_STATS_REPLY:
case OFPTYPE_TABLE_FEATURES_STATS_REQUEST:
case OFPTYPE_TABLE_FEATURES_STATS_REPLY:
+ case OFPTYPE_TABLE_DESC_REQUEST:
+ case OFPTYPE_TABLE_DESC_REPLY:
case OFPTYPE_BUNDLE_CONTROL:
case OFPTYPE_BUNDLE_ADD_MESSAGE:
case OFPTYPE_NXT_GENEVE_TABLE_MOD:
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 54c077d..232dd2f 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1664,6 +1664,28 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 dump-table-features br0 | sed '/^$/d
OVS_VSWITCHD_STOP
AT_CLEANUP
+AT_SETUP([ofproto - table description (OpenFlow 1.4)])
+OVS_VSWITCHD_START
+(x=0
+ while test $x -lt 254; do
+ y=`expr $x + 1`
+ echo " table $x:
+ eviction=off eviction_flags=OTHER|IMPORTANCE|LIFETIME"
+ x=$y
+ done) > expout
+AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d
+/^OFPST_TABLE_DESC/d'], [0], [expout])
+
+# Change the configuration.
+AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict])
+# Check that the configuration was updated.
+mv expout orig-expout
+sed -e '2s/eviction=off/eviction=on/' <orig-expout > expout
+AT_CHECK([ovs-ofctl -O OpenFlow14 dump-table-desc br0 | sed '/^$/d
+/^OFPST_TABLE_DESC/d'], [0], [expout])
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
AT_SETUP([ofproto - hard limits on flow table size (OpenFlow 1.0)])
OVS_VSWITCHD_START
# Configure a maximum of 4 flows.
diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in
index 058d205..0a40efa 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -62,6 +62,10 @@ Prints to the console statistics for each of the flow tables used by
\fBdump\-table\-features \fIswitch\fR
Prints to the console features for each of the flow tables used by
\fIswitch\fR.
+.TP
+\fBdump\-table\-desc \fIswitch\fR
+Prints to the console configuration for each of the flow tables used
+by \fIswitch\fR for OpenFlow 1.4+.
.IP "\fBmod\-table \fIswitch\fR \fItable_id\fR \fIsetting\fR"
This command configures flow table settings for OpenFlow table
\fItable_id\fR within \fIswitch\fR. The available settings depend on
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index f16cc25..566a6b4 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -338,6 +338,7 @@ usage(void)
" dump-desc SWITCH print switch description\n"
" dump-tables SWITCH print table stats\n"
" dump-table-features SWITCH print table features\n"
+ " dump-table-desc SWITCH print table description (OF1.4+)\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
" mod-table SWITCH MOD modify flow table behavior\n"
" OF1.1/1.2 MOD: controller, continue, drop\n"
@@ -737,6 +738,22 @@ ofctl_dump_table_features(struct ovs_cmdl_context *ctx)
vconn_close(vconn);
}
+static void
+ofctl_dump_table_desc(struct ovs_cmdl_context *ctx)
+{
+ struct ofpbuf *request;
+ struct vconn *vconn;
+
+ open_vconn(ctx->argv[1], &vconn);
+ request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
+ if (request) {
+ dump_stats_transaction(vconn, request);
+ }
+
+ vconn_close(vconn);
+}
+
+
static bool fetch_port_by_stats(struct vconn *,
const char *port_name, ofp_port_t port_no,
struct ofputil_phy_port *);
@@ -3612,6 +3629,8 @@ static const struct ovs_cmdl_command all_commands[] = {
1, 1, ofctl_dump_tables },
{ "dump-table-features", "switch",
1, 1, ofctl_dump_table_features },
+ { "dump-table-desc", "switch",
+ 1, 1, ofctl_dump_table_desc },
{ "dump-flows", "switch",
1, 2, ofctl_dump_flows },
{ "dump-aggregate", "switch",
--
2.1.3
More information about the dev
mailing list