[ovs-dev] [PATCH v10] ovs-ofctl:Implementation of eviction on the basis of Importance
saloni.jain12 at gmail.com
saloni.jain12 at gmail.com
Wed Jun 17 12:00:42 UTC 2015
From: Saloni Jain <saloni.jain at tcs.com>
This commit enables the eviction mechanism on the basis of importance as
per the openflow specification 1.4.
"ovs-ofctl -O OpenFlow14 mod-table <switch> <table> evict"
Enable eviction on <table> of <switch>. Eviction adds a mechanism
enabling the switch to automatically eliminate entries of lower
importance to make space for newer entries.If want to enable eviction
on all tables, user can set the <table> as 'ALL'.
"ovs-ofctl -O OpenFlow14 mod-table <switch> <table> noevict"
Disable eviction on <table> of <switch>.
"ovs-ofctl -O OpenFlow14 dump-tables-desc <switch>"
This command provides a way to list the current configuration
(eviction for importance) of the tables on a <switch>, which is set
using the mod-table command.
Signed-off-by: Saloni Jain <saloni.jain at tcs.com>
---
In this patch review comments received on June 05,2015 have been incorporated.
Following are the difference between v9 and v10 versions of the patch:
Translation has been done between OFPUTIL_TABLE_CONFIG_* values and
OFPTC14_* values and vice versa in ofputil_table_config_from_config() and
ofputil_table_config_to_config() functions. For both eviction and no-eviction
OFPTC14_EVICTION is passed in openflow message.
The above 2 mentioned functions are used in mod-table and table-desc encoding
decoding code.
OFPUTIL_TABLE_CONFIG_DEFAULT and OFPUTIL_TABLE_CONFIG_NO_EVICTION are defined
separately, so as to distinguish between the default behavior and whether user
has given no-evict command explicitly.
CLEAR_EVICTION_BIT has been removed from the code. Instead when no eviction
is configured, Eviction bit is cleared in the table-config property in
configure_table_config().
/* We do not understand any properties yet, so we do not bother parsing
them. */ -- comment has been removed.
return UINT32_MAX - (rule->importance) is changed to
return (UINT32_MAX - rule->importance)
DESIGN.md | 18 ++-
include/openflow/openflow-1.4.h | 11 ++
lib/learning-switch.c | 2 +
lib/ofp-msgs.h | 10 ++
lib/ofp-parse.c | 4 +
lib/ofp-print.c | 58 ++++++++++
lib/ofp-util.c | 241 ++++++++++++++++++++++++++++++++++++++-
lib/ofp-util.h | 44 +++++++
lib/rconn.c | 2 +
ofproto/ofproto-provider.h | 2 +
ofproto/ofproto.c | 136 +++++++++++++++++++++-
tests/ofp-print.at | 1 +
tests/ofproto.at | 105 +++++++++++++++++
utilities/ovs-ofctl.8.in | 25 +++-
utilities/ovs-ofctl.c | 19 +++
15 files changed, 664 insertions(+), 14 deletions(-)
diff --git a/DESIGN.md b/DESIGN.md
index e533b7c..daecfb6 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -277,13 +277,19 @@ The table for 1.3 is the same as the one shown above for 1.2.
OpenFlow 1.4
-------------
+-----------
+
+OpenFlow 1.4 makes these changes:
+
+ - Adds the "importance" field to flow_mods, but it does not
+ explicitly specify which kinds of flow_mods set the importance.
+ For consistency, Open vSwitch uses the same rule for importance
+ as for idle_timeout and hard_timeout, that is, only an "ADD"
+ flow_mod sets the importance. (This issue has been filed with
+ the ONF as EXT-496.)
-OpenFlow 1.4 adds the "importance" field to flow_mods, but it does not
-explicitly specify which kinds of flow_mods set the importance. For
-consistency, Open vSwitch uses the same rule for importance as for
-idle_timeout and hard_timeout, that is, only an "ADD" flow_mod sets
-the importance. (This issue has been filed with the ONF as EXT-496.)
+ - Eviction Mechanism to automatically delete entries of lower
+ importance to make space for newer entries.
OpenFlow 1.4 Bundles
diff --git a/include/openflow/openflow-1.4.h b/include/openflow/openflow-1.4.h
index 7631e47..326b220 100644
--- a/include/openflow/openflow-1.4.h
+++ b/include/openflow/openflow-1.4.h
@@ -155,6 +155,17 @@ 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 3c8536d..6e0a82a 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:
default:
diff --git a/lib/ofp-msgs.h b/lib/ofp-msgs.h
index 23c334a..d14c569 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. */
@@ -602,6 +608,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-parse.c b/lib/ofp-parse.c
index 210feed..3c98ab2 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -898,6 +898,10 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
tm->miss_config = OFPUTIL_TABLE_MISS_CONTINUE;
} else if (strcmp(flow_miss_handling, "drop") == 0) {
tm->miss_config = OFPUTIL_TABLE_MISS_DROP;
+ } else if (strcmp(flow_miss_handling, "evict") == 0) {
+ tm->config = OFPUTIL_TABLE_CONFIG_EVICTION;
+ } else if (strcmp(flow_miss_handling, "noevict") == 0) {
+ tm->config = OFPUTIL_TABLE_CONFIG_NO_EVICTION;
} else {
return xasprintf("invalid flow_miss_handling %s", flow_miss_handling);
}
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 2ac11b1..f48886f 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -962,6 +962,22 @@ ofp_print_table_miss_config(struct ds *string, enum ofputil_table_miss miss)
}
}
+/* This Function will print the config properties of table set through
+ * mod-table command. */
+static void
+ofp_print_table_config(struct ds *string, enum ofputil_table_config config,
+ uint32_t flags)
+{
+ if (config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ ds_put_cstr(string, "Eviction");
+ if (flags & OFPTMPEF14_IMPORTANCE) {
+ ds_put_cstr(string, " flag: Importance\n");
+ }
+ } else {
+ ds_put_cstr(string, "No Eviction\n");
+ }
+}
+
static void
ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
{
@@ -984,6 +1000,21 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
ds_put_cstr(string, ", flow_miss_config=");
ofp_print_table_miss_config(string, pm.miss_config);
}
+ if (oh->version >= OFP14_VERSION) {
+ ds_put_cstr(string, "\n config = ");
+ ofp_print_table_config(string, pm.config, pm.eviction_flags);
+ }
+}
+
+/* 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_cstr(string, " config = ");
+ ofp_print_table_config(string, td->config, td->eviction_flags);
}
static void
@@ -2557,6 +2588,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)
{
@@ -2685,6 +2738,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 89359c1..0a663a8 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -4867,6 +4867,201 @@ ofputil_append_table_features_reply(const struct ofputil_table_features *tf,
ofpmp_postappend(replies, start_ofs);
}
+/* Decodes the OpenFlow "table desc" message in '*msg' into an abstract form in
+ * '*td'. Returns 0 if successful, 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;
+ size_t length;
+ size_t property_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;
+ }
+
+ property_length = length - sizeof *otd;
+ td->config = ofputil_table_config_from_config(otd->config,
+ property_length,
+ version);
+
+ while (property_length > 0) {
+ size_t prop_len;
+
+ if (td->config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ struct ofp14_table_mod_prop_eviction *ote;
+
+ ote = (property_length >= sizeof *ote
+ ? ofpbuf_try_pull(msg, sizeof *ote)
+ : NULL);
+
+ if (!ote) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "OFP14_TABLE_DESC property "
+ "end with %"PRIuSIZE" leftover bytes",
+ property_length);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ prop_len = ntohs(ote->length);
+ if (prop_len != sizeof *ote) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "Table property length "
+ "%"PRIuSIZE" is not valid", prop_len);
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ td->eviction_flags = ntohl(ote->flags);
+ property_length = property_length - prop_len;
+ }
+ }
+
+ 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->config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ struct ofp14_table_mod_prop_eviction *ote;
+ size_t start_ote;
+
+ start_ote = reply->size;
+ ofpbuf_put_zeros(reply, sizeof *ote);
+ ote = ofpbuf_at_assert(reply, start_ote, sizeof *ote);
+ ote->type = htons(OFPTMPT14_EVICTION);
+ ote->length = htons(reply->size - start_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_table_config_to_config(td->config, version);
+ ofpmp_postappend(replies, start_otd);
+}
+
+static enum ofperr
+parse_table_mod_eviction_property(struct ofpbuf *property,
+ struct ofputil_table_mod *tm)
+{
+ struct ofp14_table_mod_prop_eviction *ote = property->data;
+
+ if (property->size != sizeof *ote) {
+ return OFPERR_OFPBRC_BAD_LEN;
+ }
+
+ tm->eviction_flags = ntohl(ote->flags);
+ return 0;
+}
+
+/* Converts the standard openflow OFPTC14_* value to corresponding
+ * OFPUTIL_TABLE_CONFIG_* abstract value.
+ * For both evict and no-evict table configuration, OFPTC14_EVICTION
+ * config parameter is received. If eviction is set as table config,
+ * OFPTMPT14_EVICTION property is also sent with openflow message
+ * Whereas when eviction is disabled by no-evict, no property
+ * is sent and in that case, size should be equal to 0. */
+enum ofputil_table_config
+ofputil_table_config_from_config(ovs_be32 config_, size_t size,
+ enum ofp_version version)
+{
+ uint32_t config = ntohl(config_);
+
+ if((version > OFP13_VERSION) && config) {
+ switch (config) {
+ case OFPTC14_EVICTION:
+ if (size > 0) {
+ return OFPUTIL_TABLE_CONFIG_EVICTION;
+ } else {
+ return OFPUTIL_TABLE_CONFIG_NO_EVICTION;
+ }
+
+ default:
+ VLOG_WARN_RL(&bad_ofmsg_rl, "bad table config %d", config);
+ return OFPUTIL_TABLE_CONFIG_DEFAULT;
+ }
+ } else {
+ return OFPUTIL_TABLE_CONFIG_DEFAULT;
+ }
+}
+
+/* Given a table configuration, returns the corresponding OpenFlow
+ * configuration for use in an OpenFlow message for OF 1.4 and
+ * above version.
+ * For evict or no-evict configuration, OFPTC14_EVICTION
+ * is passed in openflow message */
+ovs_be32
+ofputil_table_config_to_config(enum ofputil_table_config config,
+ enum ofp_version version)
+{
+ if(version > OFP13_VERSION) {
+ switch (config) {
+ case OFPUTIL_TABLE_CONFIG_EVICTION:
+ case OFPUTIL_TABLE_CONFIG_NO_EVICTION:
+ return htonl(OFPTC14_EVICTION);
+
+ case OFPUTIL_TABLE_CONFIG_DEFAULT:
+ return htonl(0);
+
+ default:
+ OVS_NOT_REACHED();
+ }
+ } else {
+ return htonl(0);
+ }
+}
+
/* ofputil_table_mod */
/* Given 'config', taken from an OpenFlow 'version' message that specifies
@@ -4932,6 +5127,7 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
enum ofpraw raw;
struct ofpbuf b;
+ memset(pm, 0, sizeof *pm);
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
@@ -4947,8 +5143,32 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
pm->table_id = otm->table_id;
pm->miss_config = ofputil_table_miss_from_config(otm->config,
oh->version);
- /* We do not understand any properties yet, so we do not bother
- * parsing them. */
+ pm->config = ofputil_table_config_from_config(otm->config, b.size,
+ oh->version);
+ while (b.size > 0) {
+ struct ofpbuf property;
+ enum ofperr error;
+ uint16_t type;
+
+ error = ofputil_pull_property(&b, &property, &type);
+ if (error) {
+ return error;
+ }
+
+ switch (type) {
+ case OFPTMPT14_EVICTION:
+ error = parse_table_mod_eviction_property(&property, pm);
+ break;
+
+ default:
+ error = OFPERR_OFPBRC_BAD_TYPE;
+ break;
+ }
+
+ if (error) {
+ return error;
+ }
+ }
} else {
return OFPERR_OFPBRC_BAD_TYPE;
}
@@ -4987,12 +5207,25 @@ ofputil_encode_table_mod(const struct ofputil_table_mod *pm,
case OFP14_VERSION:
case OFP15_VERSION: {
struct ofp14_table_mod *otm;
+ struct ofp14_table_mod_prop_eviction *ote;
+ ovs_be32 miss_config;
+ ovs_be32 config;
b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = pm->table_id;
- otm->config = ofputil_table_miss_to_config(pm->miss_config,
+ miss_config = ofputil_table_miss_to_config(pm->miss_config,
ofp_version);
+ config = ofputil_table_config_to_config(pm->config,
+ ofp_version);
+ otm->config = config | miss_config;
+
+ if (pm->config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ ote = ofpbuf_put_zeros(b, sizeof *ote);
+ ote->type = htons(OFPTMPT14_EVICTION);
+ ote->length = htons(sizeof *ote);
+ ote->flags = htonl(OFPTMPEF14_IMPORTANCE);
+ }
break;
}
default:
@@ -8780,6 +9013,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:
@@ -8821,6 +9055,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:
break;
}
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 596c2e2..db80eca 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -609,13 +609,43 @@ enum ofputil_table_miss {
OFPUTIL_TABLE_MISS_DROP, /* Drop the packet. */
};
+/* Abstract version of OFPTC14_TABLE_CONFIG*. */
+enum ofputil_table_config {
+ /* Table Config default behaviour. By default all config
+ * bits for table config properties are unset. */
+ OFPUTIL_TABLE_CONFIG_DEFAULT = 0 << 0,
+
+ /* OFPUTIL_TABLE_CONFIG_NO_EVICTION is defined so as to differentiate
+ * the case when user has given noevict to disable eviction for table */
+ OFPUTIL_TABLE_CONFIG_NO_EVICTION = 1 << 1,
+
+ /* OFPUTIL_TABLE_CONFIG_EVICTION defines eviction for importance */
+ OFPUTIL_TABLE_CONFIG_EVICTION = 1 << 2,
+};
+
+enum ofputil_table_config
+ofputil_table_config_from_config(ovs_be32 config_, size_t size,
+ enum ofp_version);
+
+ovs_be32 ofputil_table_config_to_config(enum ofputil_table_config,
+ enum ofp_version);
+
ovs_be32 ofputil_table_miss_to_config(enum ofputil_table_miss,
enum ofp_version);
/* Abstract ofp_table_mod. */
struct ofputil_table_mod {
uint8_t table_id; /* ID of the table, 0xff indicates all tables. */
+ enum ofputil_table_config config;
enum ofputil_table_miss miss_config;
+ uint32_t eviction_flags;
+};
+
+/* Abstract ofp14_table_desc. */
+struct ofputil_table_desc {
+ uint8_t table_id; /* ID of the table. */
+ enum ofputil_table_config config;
+ uint32_t eviction_flags;
};
enum ofperr ofputil_decode_table_mod(const struct ofp_header *,
@@ -684,11 +714,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;
@@ -815,6 +856,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 6692b46..9322972 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-provider.h b/ofproto/ofproto-provider.h
index 527823a..09e2dfc 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -248,6 +248,8 @@ struct oftable {
/* Table configuration. */
ATOMIC(enum ofputil_table_miss) miss_config;
+ ATOMIC(enum ofputil_table_config) config;
+ uint32_t eviction_flags; /* Flags of value OFPTMPEF14_*. */
atomic_ulong n_matched;
atomic_ulong n_missed;
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 08ba043..004efdb 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -88,6 +88,8 @@ static void oftable_enable_eviction(struct oftable *,
const struct mf_subfield *fields,
size_t n_fields);
+static void enable_eviction_for_importance(struct oftable *);
+
/* A set of rules within a single OpenFlow table (oftable) that have the same
* values for the oftable's eviction_fields. A rule to be evicted, when one is
* needed, is taken from the eviction group that contains the greatest number
@@ -1419,7 +1421,7 @@ ofproto_configure_table(struct ofproto *ofproto, int table_id,
return;
}
- if (s->groups) {
+ if (s->groups || (table->config & OFPUTIL_TABLE_CONFIG_EVICTION)) {
oftable_enable_eviction(table, s->groups, s->n_groups);
} else {
oftable_disable_eviction(table);
@@ -3571,6 +3573,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;
+ atomic_read_relaxed(&ofproto->tables[i].config, &td->config);
+ if (td->config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ td->eviction_flags = ofproto->tables[i].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)
{
@@ -6556,12 +6599,51 @@ ofproto_table_get_miss_config(const struct ofproto *ofproto, uint8_t table_id)
return value;
}
+/* This function configures table config property as passed in openflow
+ * table-mod message. */
+static void
+configure_table_config(const struct ofputil_table_mod *tm, uint8_t table_id,
+ struct ofproto *ofproto)
+{
+ enum ofputil_table_config table_config;
+
+ atomic_read_relaxed(&ofproto->tables[table_id].config,
+ &table_config);
+
+ /* When Eviction is configured for a given table,
+ * OFPUTIL_TABLE_CONFIG_EVICTION flag is set, switch can evict flow
+ * entries from flow on basis of importance. When no-eviction
+ * is configured, the flag is unset and eviction
+ * for importance is not performed by switch */
+ if (tm->config & OFPUTIL_TABLE_CONFIG_EVICTION) {
+ table_config |= OFPUTIL_TABLE_CONFIG_EVICTION;
+ ofproto->tables[table_id].eviction_flags = tm->eviction_flags;
+ enable_eviction_for_importance(&ofproto->tables[table_id]);
+ } else if (tm->config & OFPUTIL_TABLE_CONFIG_NO_EVICTION) {
+ table_config &= ~(OFPUTIL_TABLE_CONFIG_EVICTION);
+ oftable_disable_eviction(&ofproto->tables[table_id]);
+ }
+ atomic_store_relaxed(&ofproto->tables[table_id].config,
+ table_config);
+}
+
static enum ofperr
table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
{
if (!check_table_id(ofproto, tm->table_id)) {
return OFPERR_OFPTMFC_BAD_TABLE;
- } else if (tm->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) {
+ }
+ if (!(tm->config & OFPUTIL_TABLE_CONFIG_DEFAULT)) {
+ if (tm->table_id == OFPTT_ALL) {
+ int i;
+ for (i = 0; i < ofproto->n_tables; i++) {
+ configure_table_config(tm, i, ofproto);
+ }
+ } else {
+ configure_table_config(tm, tm->table_id, ofproto);
+ }
+ }
+ if (tm->miss_config != OFPUTIL_TABLE_MISS_DEFAULT) {
if (tm->table_id == OFPTT_ALL) {
int i;
for (i = 0; i < ofproto->n_tables; i++) {
@@ -6576,6 +6658,18 @@ table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
return 0;
}
+/* This function is only used when eviction is performed on the basis of
+ * importance. This function enables eviction on a particular table given. */
+static void
+enable_eviction_for_importance(struct oftable *tables)
+{
+ struct mf_subfield *field = NULL;
+ size_t n_field = 0;
+
+ field = xmalloc(n_field* sizeof *field);
+ oftable_enable_eviction(tables, field, n_field);
+}
+
static enum ofperr
handle_table_mod(struct ofconn *ofconn, const struct ofp_header *oh)
{
@@ -7012,6 +7106,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);
@@ -7077,6 +7174,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:
default:
if (ofpmsg_is_stat_request(oh)) {
@@ -7333,7 +7431,7 @@ eviction_group_find(struct oftable *table, uint32_t id)
/* Returns an eviction priority for 'rule'. The return value should be
* interpreted so that higher priorities make a rule more attractive candidates
* for eviction.
- * Called only if have a timeout. */
+ * Called if have a timeout or importance. */
static uint32_t
rule_eviction_priority(struct ofproto *ofproto, struct rule *rule)
OVS_REQUIRES(ofproto_mutex)
@@ -7341,12 +7439,31 @@ rule_eviction_priority(struct ofproto *ofproto, struct rule *rule)
long long int expiration = LLONG_MAX;
long long int modified;
uint32_t expiration_offset;
+ struct oftable *table = &ofproto->tables[rule->table_id];
+ bool has_eviction_by_importance;
/* 'modified' needs protection even when we hold 'ofproto_mutex'. */
ovs_mutex_lock(&rule->mutex);
modified = rule->modified;
ovs_mutex_unlock(&rule->mutex);
+ /* For eviction on basis of importance only those entries will be added
+ * which have eviction fields set, importance parameter given in flow
+ * entry and table config parameter for eviction is set. */
+ has_eviction_by_importance = (table->eviction_fields
+ && rule->importance
+ && (table->config
+ & OFPUTIL_TABLE_CONFIG_EVICTION));
+
+ /* As per the openflow specification 1.4, flow entries with lesser
+ * importance will be evicted before flow entries with higher importance.
+ * So invert the value of importance for calculating the rule eviction
+ * priority as higher priorities make a rule more attractive candidates
+ * for eviction. */
+ if (has_eviction_by_importance) {
+ return (UINT32_MAX - rule->importance);
+ }
+
if (rule->hard_timeout) {
expiration = modified + rule->hard_timeout * 1000;
}
@@ -7388,12 +7505,22 @@ eviction_group_add_rule(struct rule *rule)
struct ofproto *ofproto = rule->ofproto;
struct oftable *table = &ofproto->tables[rule->table_id];
bool has_timeout;
+ bool has_eviction_by_importance;
/* Timeouts may be modified only when holding 'ofproto_mutex'. We have it
* so no additional protection is needed. */
has_timeout = rule->hard_timeout || rule->idle_timeout;
- if (table->eviction_fields && has_timeout) {
+ /* For eviction on basis of importance only those entries will be added
+ * which have eviction fields set, importance parameter is not zero in flow
+ * entry and table config parameter for eviction is set. All rules are
+ * added in a single group when eviction is done on basis of importance. */
+ has_eviction_by_importance = (table->eviction_fields
+ && rule->importance
+ && (table->config
+ & OFPUTIL_TABLE_CONFIG_EVICTION));
+ if ((table->eviction_fields && has_timeout)
+ || has_eviction_by_importance) {
struct eviction_group *evg;
evg = eviction_group_find(table, eviction_group_hash_rule(rule));
@@ -7416,6 +7543,7 @@ oftable_init(struct oftable *table)
table->max_flows = UINT_MAX;
table->n_flows = 0;
atomic_init(&table->miss_config, OFPUTIL_TABLE_MISS_DEFAULT);
+ atomic_init(&table->config, OFPUTIL_TABLE_CONFIG_DEFAULT);
classifier_set_prefix_fields(&table->cls, default_prefix_fields,
ARRAY_SIZE(default_prefix_fields));
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 39a5bbb..f593569 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -1133,6 +1133,7 @@ AT_CHECK([ovs-ofctl ofp-print "\
05 11 00 10 00 00 00 02 02 00 00 00 00 00 00 00 \
" 3], [0], [dnl
OFPT_TABLE_MOD (OF1.4) (xid=0x2): table_id=2
+ config = No Eviction
])
AT_CLEANUP
diff --git a/tests/ofproto.at b/tests/ofproto.at
index 9c5f0bb..527d5b9 100644
--- a/tests/ofproto.at
+++ b/tests/ofproto.at
@@ -1587,6 +1587,111 @@ 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:
+ config = No Eviction"
+ 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
+FLAG_STRING=" flag: Importance"
+sed -e "2s/No Eviction/Eviction/
+2s/$/$FLAG_STRING/" <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 - eviction using importance upon table overflow (OpenFlow 1.4)])
+OVS_VSWITCHD_START
+# Configure a maximum of 4 flows.
+AT_CHECK(
+ [ovs-vsctl \
+ -- --id=@t0 create Flow_Table flow-limit=4 \
+ -- set bridge br0 flow_tables:0=@t0 \
+ | ${PERL} $srcdir/uuidfilt.pl],
+ [0], [<0>
+])
+# set the Eviction configuration.
+AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 evict])
+# Add 4 flows.
+for in_port in 4 3 2 1; do
+ ovs-ofctl -O Openflow14 add-flow br0 importance=$((in_port + 30)),priority=$((in_port + 5)),hard_timeout=$((in_port + 500)),actions=drop
+done
+AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ hard_timeout=501, importance=31, priority=6 actions=drop
+ hard_timeout=502, importance=32, priority=7 actions=drop
+ hard_timeout=503, importance=33, priority=8 actions=drop
+ hard_timeout=504, importance=34, priority=9 actions=drop
+OFPST_FLOW reply (OF1.4):
+])
+# Adding another flow will cause the one with lowest importance to be evicted.
+AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=505,importance=35,priority=10,in_port=2,actions=drop])
+AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ hard_timeout=502, importance=32, priority=7 actions=drop
+ hard_timeout=503, importance=33, priority=8 actions=drop
+ hard_timeout=504, importance=34, priority=9 actions=drop
+ hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop
+OFPST_FLOW reply (OF1.4):
+])
+# Disable the Eviction configuration.
+AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 noevict])
+# Adding another flow will cause the system to give error for FULL TABLE.
+AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 hard_timeout=506,importance=36,priority=11,actions=drop],[1], [], [stderr])
+AT_CHECK([head -n 1 stderr | ofctl_strip], [0],
+ [OFPT_ERROR (OF1.4): OFPFMFC_TABLE_FULL
+])
+#Dump flows. It should show only the old values
+AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ hard_timeout=502, importance=32, priority=7 actions=drop
+ hard_timeout=503, importance=33, priority=8 actions=drop
+ hard_timeout=504, importance=34, priority=9 actions=drop
+ hard_timeout=505, importance=35, priority=10,in_port=2 actions=drop
+OFPST_FLOW reply (OF1.4):
+])
+# mod-flow that would modify a flow will be done successfully.
+AT_CHECK([ovs-ofctl -O Openflow14 mod-flows br0 in_port=2,actions=NORMAL])
+AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ hard_timeout=502, importance=32, priority=7 actions=drop
+ hard_timeout=503, importance=33, priority=8 actions=drop
+ hard_timeout=504, importance=34, priority=9 actions=drop
+ hard_timeout=505, importance=35, priority=10,in_port=2 actions=NORMAL
+OFPST_FLOW reply (OF1.4):
+])
+# Also a mod-flow that would add a flow will be refused.
+AT_CHECK([ovs-ofctl mod-flows br0 in_port=5,actions=drop], [1], [], [stderr])
+AT_CHECK([head -n 1 stderr | ofctl_strip], [0],
+ [OFPT_ERROR: OFPFMFC_TABLE_FULL
+])
+# Now set the eviction on timeout basis.
+AT_CHECK(
+ [ovs-vsctl \
+ -- --id=@t0 create Flow_Table flow-limit=4 overflow-policy=evict \
+ -- set bridge br0 flow_tables:0=@t0 \
+ | ${PERL} $srcdir/uuidfilt.pl],
+ [0], [<0>
+])
+#Now add a new flow
+AT_CHECK([ovs-ofctl -O Openflow14 add-flow br0 importance=37,hard_timeout=507,priority=11,in_port=6,actions=drop])
+AT_CHECK([ovs-ofctl -O Openflow14 dump-flows br0 | ofctl_strip | sort], [0], [dnl
+ hard_timeout=503, importance=33, priority=8 actions=drop
+ hard_timeout=504, importance=34, priority=9 actions=drop
+ hard_timeout=505, importance=35, priority=10,in_port=2 actions=NORMAL
+ hard_timeout=507, importance=37, priority=11,in_port=6 actions=drop
+OFPST_FLOW reply (OF1.4):
+])
+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 63c2ecc..88289ad 100644
--- a/utilities/ovs-ofctl.8.in
+++ b/utilities/ovs-ofctl.8.in
@@ -62,8 +62,14 @@ 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 \fIflow_miss_handling\fR"
+.IP "\fBmod\-table \fIswitch\fR \fItable_id\fR \fIflow_miss_handling/config\fR"
+.RS
+.IP \fIflow_miss_handling\fR
An OpenFlow 1.0 switch looks up each packet that arrives at the switch
in table 0, then in table 1 if there is no match in table 0, then in
table 2, and so on until the packet finds a match in some table.
@@ -87,6 +93,23 @@ tables other than the last one.)
Send to controller. (This is how an OpenFlow 1.0 switch always
handles packets that do not match any flow in the last table.)
.RE
+.IP \fIconfig\fR
+An OpenFlow 1.4+ switch configures the behaviour of the table when the
+table is full.
+.IP
+This command configures the flow table configuration for table
+\fItable_id\fR in \fIswitch\fR. \fItable_id\fR may be an OpenFlow
+table number between 0 and 254, inclusive, or the keyword \fBALL\fR to
+modify all tables. \fIconfig\fR may be any one of the following:
+.RS
+.IP \fBevict\fR
+Enable eviction on \fItable_id\fR of \fIswitch\fR on the basis of
+importance.
+.IP \fBnoevict\fR
+Disable eviction on \fItable_id\fR of \fIswitch\fR on the basis of
+importance.
+.RE
+.RE
.
.TP
\fBdump\-ports \fIswitch\fR [\fInetdev\fR]
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 8df79b8..0970e15 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\n"
" mod-port SWITCH IFACE ACT modify port behavior\n"
" mod-table SWITCH MOD modify flow table behavior\n"
" get-frags SWITCH print fragment handling behavior\n"
@@ -731,6 +732,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 *);
@@ -3565,6 +3582,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",
--
1.7.9.5
More information about the dev
mailing list