@@ -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+ OFPTC_VACANCY_EVENTS is now implemented.
* OpenFlow 1.4+ OFPMP_TABLE_DESC is now implemented.
* Allow modifying the ICMPv4/ICMPv6 type and code fields.
- Support for matching/generating options as well as the OAM bit with
@@ -880,6 +880,49 @@ parse_ofp_flow_mod_str(struct ofputil_flow_mod *fm, const char *string,
return error;
}
+/* Convert 'setting' (as described for the "mod-table" command
+ * in ovs-ofctl man page) into 'tm->table_vacancy->vacancy_up' and
+ * 'tm->table_vacancy->vacancy_down' threshold values.
+ * For the two threshold values, value of vacancy_up is always greater
+ * than value of vacancy_down.
+ *
+ * Returns NULL if successful, otherwise a malloc()'d string describing the
+ * error. The caller is responsible for freeing the returned string. */
+char * OVS_WARN_UNUSED_RESULT
+parse_ofp_table_vacancy(struct ofputil_table_mod *tm, const char *setting)
+{
+ char *save_ptr = NULL;
+ char *vac_up, *vac_down;
+ char *value = strdup(setting);
+ int vacancy_up, vacancy_down;
+
+ strtok_r(value, ":", &save_ptr);
+ vac_down = strtok_r(NULL, ",", &save_ptr);
+ if (!vac_down) {
+ return xasprintf("Vacancy down value missing");
+ }
+ if (!str_to_int(vac_down, 0, &vacancy_down) ||
+ vacancy_down < 0 || vacancy_down > 100) {
+ return xasprintf("Invalid vacancy down value \"%s\"", vac_down);
+ }
+ vac_up = strtok_r(NULL, ",", &save_ptr);
+ if (!vac_up) {
+ return xasprintf("Vacancy up value missing");
+ }
+ if (!str_to_int(vac_up, 0, &vacancy_up) ||
+ vacancy_up < 0 || vacancy_up > 100) {
+ return xasprintf("Invalid vacancy up value \"%s\"", vac_up);
+ }
+ if (vacancy_down > vacancy_up) {
+ return xasprintf("Invalid vacancy range, vacancy up should be greater"
+ " than vacancy down ""(%s)",
+ ofperr_to_string(OFPERR_OFPBPC_BAD_VALUE));
+ }
+ tm->table_vacancy.vacancy_down = vacancy_down;
+ tm->table_vacancy.vacancy_up = vacancy_up;
+ return NULL;
+}
+
/* Convert 'table_id' and 'setting' (as described for the "mod-table" command
* in the ovs-ofctl man page) into 'tm' for sending a table_mod command to a
* switch.
@@ -906,13 +949,13 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
tm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
tm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
tm->eviction_flags = UINT32_MAX;
-
+ tm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
+ tm->table_vacancy.vacancy_down = 0;
+ tm->table_vacancy.vacancy_up = 0;
+ tm->table_vacancy.vacancy = 0;
/* Only OpenFlow 1.1 and 1.2 can configure table-miss via table_mod.
- * Only OpenFlow 1.4+ can configure eviction via table_mod.
- *
- * (OpenFlow 1.4+ can also configure vacancy events via table_mod, but OVS
- * doesn't support those yet and they're also logically a per-OpenFlow
- * session setting so it wouldn't make sense to support them here anyway.)
+ * Only OpenFlow 1.4+ can configure eviction and vacancy events
+ * via table_mod.
*/
if (!strcmp(setting, "controller")) {
tm->miss = OFPUTIL_TABLE_MISS_CONTROLLER;
@@ -929,6 +972,16 @@ parse_ofp_table_mod(struct ofputil_table_mod *tm, const char *table_id,
} else if (!strcmp(setting, "noevict")) {
tm->eviction = OFPUTIL_TABLE_EVICTION_OFF;
*usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
+ } else if (!strncmp(setting, "vacancy", strcspn(setting, ":"))) {
+ tm->vacancy = OFPUTIL_TABLE_VACANCY_ON;
+ *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
+ char *error = parse_ofp_table_vacancy(tm, setting);
+ if (error) {
+ return error;
+ }
+ } else if (!strcmp(setting, "novacancy")) {
+ tm->vacancy = OFPUTIL_TABLE_VACANCY_OFF;
+ *usable_versions = (1 << OFP14_VERSION) | (1u << OFP15_VERSION);
} else {
return xasprintf("invalid table_mod setting %s", setting);
}
@@ -100,5 +100,8 @@ char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT;
char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT;
char *str_to_connhelper(const char *str, uint16_t *alg) OVS_WARN_UNUSED_RESULT;
+char *parse_ofp_table_vacancy(struct ofputil_table_mod *,
+ const char *flow_miss_handling)
+ OVS_WARN_UNUSED_RESULT;
#endif /* ofp-parse.h */
@@ -990,6 +990,18 @@ ofputil_put_eviction_flags(struct ds *string, uint32_t eviction_flags)
}
}
+static const char *
+ofputil_table_vacancy_to_string(enum ofputil_table_vacancy vacancy)
+{
+ switch (vacancy) {
+ case OFPUTIL_TABLE_VACANCY_DEFAULT: return "default";
+ case OFPUTIL_TABLE_VACANCY_ON: return "on";
+ case OFPUTIL_TABLE_VACANCY_OFF: return "off";
+ default: return "***error***";
+ }
+
+}
+
static void
ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
{
@@ -1020,6 +1032,15 @@ ofp_print_table_mod(struct ds *string, const struct ofp_header *oh)
ds_put_cstr(string, "eviction_flags=");
ofputil_put_eviction_flags(string, pm.eviction_flags);
}
+ if (pm.vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
+ ds_put_format(string, ", vacancy=%s",
+ ofputil_table_vacancy_to_string(pm.vacancy));
+ if (pm.vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ ds_put_format(string, " vacancy:%"PRIu8""
+ ",%"PRIu8"", pm.table_vacancy.vacancy_down,
+ pm.table_vacancy.vacancy_up);
+ }
+ }
}
/* This function will print the Table description properties. */
@@ -53,10 +53,13 @@ VLOG_DEFINE_THIS_MODULE(ofp_util);
* in the peer and so there's not much point in showing a lot of them. */
static struct vlog_rate_limit bad_ofmsg_rl = VLOG_RATE_LIMIT_INIT(1, 5);
+static enum ofputil_table_vacancy ofputil_decode_table_vacancy(
+ ovs_be32 config, enum ofp_version);
static enum ofputil_table_eviction ofputil_decode_table_eviction(
ovs_be32 config, enum ofp_version);
static ovs_be32 ofputil_encode_table_config(enum ofputil_table_miss,
enum ofputil_table_eviction,
+ enum ofputil_table_vacancy,
enum ofp_version);
struct ofp_prop_header {
@@ -4999,9 +5002,60 @@ ofputil_append_table_desc_reply(const struct ofputil_table_desc *td,
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);
+ td->eviction, td->vacancy,
+ version);
ofpmp_postappend(replies, start_otd);
}
+/* This function parses Vacancy property, and decodes the
+ * ofp14_table_mod_prop_vacancy in ofputil_table_mod.
+ * Returns OFPERR_OFPBPC_BAD_VALUE error code when vacancy_down is
+ * greater than vacancy_up and also when current vacancy has non-zero
+ * value. Returns 0 on success. */
+static enum ofperr
+parse_table_mod_vacancy_property(struct ofpbuf *property,
+ struct ofputil_table_mod *tm)
+{
+ struct ofp14_table_mod_prop_vacancy *otv = property->data;
+
+ if (property->size != sizeof *otv) {
+ return OFPERR_OFPBPC_BAD_LEN;
+ }
+ tm->table_vacancy.vacancy_down = otv->vacancy_down;
+ tm->table_vacancy.vacancy_up = otv->vacancy_up;
+ if (tm->table_vacancy.vacancy_down > tm->table_vacancy.vacancy_up) {
+ log_property(false, "Value of vacancy_down is greater than "
+ "vacancy_up");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+ if (tm->table_vacancy.vacancy_down > 100 ||
+ tm->table_vacancy.vacancy_up > 100) {
+ log_property(false, "Vacancy threshold percentage should not be"
+ "greater than 100");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+ tm->table_vacancy.vacancy = otv->vacancy;
+ if (tm->table_vacancy.vacancy) {
+ log_property(false, "Vacancy value should be zero for table-mod "
+ "messages");
+ return OFPERR_OFPBPC_BAD_VALUE;
+ }
+ return 0;
+}
+
+/* Given 'config', taken from an OpenFlow 'version' message that specifies
+ * table configuration (a table mod, table stats, or table features message),
+ * returns the table vacancy configuration that it specifies.
+ *
+ * Only OpenFlow 1.4 and later specify table vacancy configuration this way,
+ * so for other 'version' this function always returns
+ * OFPUTIL_TABLE_VACANCY_DEFAULT. */
+static enum ofputil_table_vacancy
+ofputil_decode_table_vacancy(ovs_be32 config, enum ofp_version version)
+{
+ return (version < OFP14_VERSION ? OFPUTIL_TABLE_VACANCY_DEFAULT
+ : config & htonl(OFPTC14_VACANCY_EVENTS) ? OFPUTIL_TABLE_VACANCY_ON
+ : OFPUTIL_TABLE_VACANCY_OFF);
+}
static enum ofperr
parse_table_mod_eviction_property(struct ofpbuf *property,
@@ -5038,8 +5092,10 @@ ofputil_decode_table_eviction(ovs_be32 config, enum ofp_version version)
static ovs_be32
ofputil_encode_table_config(enum ofputil_table_miss miss,
enum ofputil_table_eviction eviction,
+ enum ofputil_table_vacancy vacancy,
enum ofp_version version)
{
+ uint32_t config = 0;
/* See the section "OFPTC_* Table Configuration" in DESIGN.md for more
* information on the crazy evolution of this field. */
switch (version) {
@@ -5072,11 +5128,16 @@ ofputil_encode_table_config(enum ofputil_table_miss miss,
case OFP14_VERSION:
case OFP15_VERSION:
- /* OpenFlow 1.4 introduced OFPTC14_EVICTION and OFPTC14_VACANCY_EVENTS
- * and we don't support the latter yet. */
- return htonl(eviction == OFPUTIL_TABLE_EVICTION_ON
- ? OFPTC14_EVICTION : 0);
- }
+ /* OpenFlow 1.4 introduced OFPTC14_EVICTION and
+ * OFPTC14_VACANCY_EVENTS. */
+ if (eviction == OFPUTIL_TABLE_EVICTION_ON) {
+ config |= OFPTC14_EVICTION;
+ }
+ if (vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ config |= OFPTC14_VACANCY_EVENTS;
+ }
+ return htonl(config);
+}
OVS_NOT_REACHED();
}
@@ -5126,6 +5187,7 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
pm->miss = OFPUTIL_TABLE_MISS_DEFAULT;
pm->eviction = OFPUTIL_TABLE_EVICTION_DEFAULT;
pm->eviction_flags = UINT32_MAX;
+ pm->vacancy = OFPUTIL_TABLE_VACANCY_DEFAULT;
ofpbuf_use_const(&b, oh, ntohs(oh->length));
raw = ofpraw_pull_assert(&b);
@@ -5140,6 +5202,7 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
pm->table_id = otm->table_id;
pm->miss = ofputil_decode_table_miss(otm->config, oh->version);
pm->eviction = ofputil_decode_table_eviction(otm->config, oh->version);
+ pm->vacancy = ofputil_decode_table_vacancy(otm->config, oh->version);
while (b.size > 0) {
struct ofpbuf property;
enum ofperr error;
@@ -5155,6 +5218,10 @@ ofputil_decode_table_mod(const struct ofp_header *oh,
error = parse_table_mod_eviction_property(&property, pm);
break;
+ case OFPTMPT14_VACANCY:
+ error = parse_table_mod_vacancy_property(&property, pm);
+ break;
+
default:
error = OFPERR_OFPBRC_BAD_TYPE;
break;
@@ -5196,19 +5263,20 @@ ofputil_encode_table_mod(const struct ofputil_table_mod *tm,
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = tm->table_id;
otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
- ofp_version);
+ tm->vacancy, ofp_version);
break;
}
case OFP14_VERSION:
case OFP15_VERSION: {
struct ofp14_table_mod *otm;
struct ofp14_table_mod_prop_eviction *ote;
+ struct ofp14_table_mod_prop_vacancy *otv;
b = ofpraw_alloc(OFPRAW_OFPT14_TABLE_MOD, ofp_version, 0);
otm = ofpbuf_put_zeros(b, sizeof *otm);
otm->table_id = tm->table_id;
otm->config = ofputil_encode_table_config(tm->miss, tm->eviction,
- ofp_version);
+ tm->vacancy, ofp_version);
if (tm->eviction_flags != UINT32_MAX) {
ote = ofpbuf_put_zeros(b, sizeof *ote);
@@ -5216,6 +5284,13 @@ ofputil_encode_table_mod(const struct ofputil_table_mod *tm,
ote->length = htons(sizeof *ote);
ote->flags = htonl(tm->eviction_flags);
}
+ if (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON) {
+ otv = ofpbuf_put_zeros(b, sizeof *otv);
+ otv->type = htons(OFPTMPT14_VACANCY);
+ otv->length = htons(sizeof *otv);
+ otv->vacancy_down = tm->table_vacancy.vacancy_down;
+ otv->vacancy_up = tm->table_vacancy.vacancy_up;
+ }
break;
}
default:
@@ -5682,6 +5757,7 @@ ofputil_put_ofp12_table_stats(const struct ofputil_table_stats *stats,
features->nonmiss.instructions, OFP12_VERSION);
out->config = ofputil_encode_table_config(features->miss_config,
OFPUTIL_TABLE_EVICTION_DEFAULT,
+ OFPUTIL_TABLE_VACANCY_DEFAULT,
OFP12_VERSION);
out->max_entries = htonl(features->max_entries);
out->active_count = htonl(stats->active_count);
@@ -620,6 +620,33 @@ enum ofputil_table_eviction {
OFPUTIL_TABLE_EVICTION_OFF /* Disable eviction. */
};
+/* Abstract version of OFPTC14_VACANCY_EVENTS.
+ *
+ * OpenFlow 1.0 through 1.3 don't know anything about vacancy events, so
+ * decoding a message for one of these protocols always yields
+ * OFPUTIL_TABLE_VACANCY_DEFAULT. */
+enum ofputil_table_vacancy {
+ OFPUTIL_TABLE_VACANCY_DEFAULT, /* No value. */
+ OFPUTIL_TABLE_VACANCY_ON, /* Enable vacancy events. */
+ OFPUTIL_TABLE_VACANCY_OFF /* Disable vacancy events. */
+};
+
+/* Abstract version of OFPTMPT_VACANCY.
+ *
+ * Openflow 1.4+ defines vacancy events.
+ * The fields vacancy_down and vacancy_up are the threshold for generating
+ * vacancy events that should be configured on the flow table, expressed as
+ * a percent.
+ * The vacancy field is only used when this property in included in a
+ * OFPMP_TABLE_DESC multipart reply or a OFPT_TABLE_STATUS message and
+ * represent the current vacancy of the table, expressed as a percent. In
+ * OFP_TABLE_MOD requests, this field must be set to 0 */
+struct ofputil_table_mod_prop_vacancy {
+ uint8_t vacancy_down; /* Vacancy threshold when space decreases (%). */
+ uint8_t vacancy_up; /* Vacancy threshold when space increases (%). */
+ uint8_t vacancy; /* Current vacancy (%). */
+};
+
/* Abstract ofp_table_mod. */
struct ofputil_table_mod {
uint8_t table_id; /* ID of the table, 0xff indicates all tables. */
@@ -636,6 +663,16 @@ struct ofputil_table_mod {
* absence. For other versions, ignored on encoding, decoded to
* UINT32_MAX.*/
uint32_t eviction_flags; /* OFPTMPEF14_*. */
+
+ /* OpenFlow 1.4+ only. For other versions, ignored on encoding, decoded to
+ * OFPUTIL_TABLE_VACANCY_DEFAULT. */
+ enum ofputil_table_vacancy vacancy;
+
+ /* Openflow 1.4+ only. Defines threshold values of vacancy expressed as
+ * percent, value of Current vacancy is set to zero for table-mod.
+ * For other versions, ignored on encoding, all values decoded to
+ * zero. */
+ struct ofputil_table_mod_prop_vacancy table_vacancy;
};
/* Abstract ofp14_table_desc. */
@@ -643,6 +680,8 @@ 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 ofputil_table_vacancy vacancy;
+ struct ofputil_table_mod_prop_vacancy table_vacancy;
};
enum ofperr ofputil_decode_table_mod(const struct ofp_header *,
@@ -256,6 +256,17 @@ struct oftable {
#define EVICTION_OPENFLOW (1 << 1) /* Set to 1 if OpenFlow enables eviction. */
unsigned int eviction;
+ /* Either of the Vacancy Events are enabled when this value is set to
+ * OFPTC14_VACANCY_EVENTS. When this flag is unset, vacancy events are
+ * disabled */
+ bool vacancy_enabled;
+
+ /* Non-zero values for vacancy_up and vacancy_down indicates that vacancy
+ * is enabled by table-mod, else these values are set to zero when
+ * vacancy is disabled */
+ uint8_t vacancy_down; /* Vacancy threshold when space decreases (%). */
+ uint8_t vacancy_up; /* Vacancy threshold when space increases (%). */
+
atomic_ulong n_matched;
atomic_ulong n_missed;
};
@@ -4664,6 +4664,7 @@ add_flow_finish(struct ofproto *ofproto, struct ofproto_flow_mod *ofm,
ofmonitor_report(ofproto->connmgr, new_rule, NXFME_ADDED, 0,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
+
}
send_buffered_packet(req, fm->buffer_id, new_rule);
@@ -5059,6 +5060,7 @@ delete_flows_finish__(struct ofproto *ofproto,
ofmonitor_report(ofproto->connmgr, rule, NXFME_DELETED, reason,
req ? req->ofconn : NULL,
req ? req->request->xid : 0, NULL);
+
ofproto_rule_remove__(ofproto, rule);
learned_cookies_dec(ofproto, rule_get_actions(rule),
&dead_cookies);
@@ -6644,20 +6646,20 @@ ofproto_table_get_miss_config(const struct ofproto *ofproto, uint8_t table_id)
static void
table_mod__(struct oftable *oftable,
- enum ofputil_table_miss miss, enum ofputil_table_eviction eviction)
+ const struct ofputil_table_mod *tm)
{
- if (miss == OFPUTIL_TABLE_MISS_DEFAULT) {
+ if (tm->miss == OFPUTIL_TABLE_MISS_DEFAULT) {
/* This is how an OFPT_TABLE_MOD decodes if it doesn't specify any
* table-miss configuration (because the protocol used doesn't have
* such a concept), so there's nothing to do. */
} else {
- atomic_store_relaxed(&oftable->miss_config, miss);
+ atomic_store_relaxed(&oftable->miss_config, tm->miss);
}
unsigned int new_eviction = oftable->eviction;
- if (eviction == OFPUTIL_TABLE_EVICTION_ON) {
+ if (tm->eviction == OFPUTIL_TABLE_EVICTION_ON) {
new_eviction |= EVICTION_OPENFLOW;
- } else if (eviction == OFPUTIL_TABLE_EVICTION_OFF) {
+ } else if (tm->eviction == OFPUTIL_TABLE_EVICTION_OFF) {
new_eviction &= ~EVICTION_OPENFLOW;
}
@@ -6668,6 +6670,16 @@ table_mod__(struct oftable *oftable,
oftable->n_eviction_fields);
ovs_mutex_unlock(&ofproto_mutex);
}
+
+ if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
+ ovs_mutex_lock(&ofproto_mutex);
+ oftable->vacancy_enabled = (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON
+ ? OFPTC14_VACANCY_EVENTS
+ : 0);
+ oftable->vacancy_down = tm->table_vacancy.vacancy_down;
+ oftable->vacancy_up = tm->table_vacancy.vacancy_up;
+ ovs_mutex_unlock(&ofproto_mutex);
+ }
}
static enum ofperr
@@ -6691,7 +6703,7 @@ table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
struct oftable *oftable;
OFPROTO_FOR_EACH_TABLE (oftable, ofproto) {
if (!(oftable->flags & (OFTABLE_HIDDEN | OFTABLE_READONLY))) {
- table_mod__(oftable, tm->miss, tm->eviction);
+ table_mod__(oftable, tm);
}
}
} else {
@@ -6699,7 +6711,7 @@ table_mod(struct ofproto *ofproto, const struct ofputil_table_mod *tm)
if (oftable->flags & OFTABLE_READONLY) {
return OFPERR_OFPTMFC_EPERM;
}
- table_mod__(oftable, tm->miss, tm->eviction);
+ table_mod__(oftable, tm);
}
return 0;
@@ -1132,7 +1132,7 @@ AT_KEYWORDS([ofp-print])
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, eviction=off
+OFPT_TABLE_MOD (OF1.4) (xid=0x2): table_id=2, eviction=off, vacancy=off
])
AT_CLEANUP
@@ -1749,6 +1749,13 @@ 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])
+
+AT_CHECK([ovs-ofctl -O Openflow14 mod-table br0 0 vacancy:20,80])
+# Check that the configuration was updated.
+mv expout orig-expout
+sed -e '3s/vacancy=off/vacancy=on vacancy_down=20% vacancy_up=80% vacancy=0%/' <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
@@ -96,8 +96,14 @@ algorithm described for the \fBFlow_Table\fR table in
\fBovs-vswitchd.conf.db\fR(5).
.IP \fBnoevict\fR
Refuse to add the new flow. (Eviction might still be enabled through
-the \fBoverflow_policy\fR oclumn in the \fBFlow_Table\fR table
+the \fBoverflow_policy\fR column in the \fBFlow_Table\fR table
documented in \fBovs-vswitchd.conf.db\fR(5).)
+.IP \fBvacancy:low,high\fR
+Sends \fBVacancy Events\fR to the controller using \fBTABLE_STATUS\fR
+messages based on percentage of capacity thresholds (low,high) chosen by
+the controller.
+.IP \fBnovacancy\fR
+Disables \fBVacancy Events\fR.
.RE
.
.TP
@@ -347,7 +347,7 @@ usage(void)
" 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"
- " OF1.4+ MOD: evict, noevict\n"
+ " OF1.4+ MOD: evict, noevict, vacancy:low,high, novacancy\n"
" get-frags SWITCH print fragment handling behavior\n"
" set-frags SWITCH FRAG_MODE set fragment handling behavior\n"
" FRAG_MODE: normal, drop, reassemble, nx-match\n"
@@ -1934,6 +1934,70 @@ found:
vconn_close(vconn);
}
+/* This function uses OFPMP14_TABLE_DESC request to get the current
+ * table configuration from switch. The function then modifies
+ * only that table-config property, which has been requested. */
+static void
+fetch_table_desc(struct vconn *vconn, struct ofputil_table_mod *tm,
+ struct ofputil_table_desc *td)
+{
+ struct ofpbuf *request;
+ ovs_be32 send_xid;
+ bool done = false;
+ bool found = false;
+
+ request = ofputil_encode_table_desc_request(vconn_get_version(vconn));
+ send_xid = ((struct ofp_header *) request->data)->xid;
+ send_openflow_buffer(vconn, request);
+ while (!done) {
+ ovs_be32 recv_xid;
+ struct ofpbuf *reply;
+
+ run(vconn_recv_block(vconn, &reply), "OpenFlow packet receive failed");
+ recv_xid = ((struct ofp_header *) reply->data)->xid;
+ if (send_xid == recv_xid) {
+ struct ofp_header *oh = reply->data;
+ enum ofptype type;
+ struct ofpbuf b;
+ uint16_t flags;
+
+ ofpbuf_use_const(&b, oh, ntohs(oh->length));
+ if (ofptype_pull(&type, &b)
+ || type != OFPTYPE_TABLE_DESC_REPLY) {
+ ovs_fatal(0, "received bad reply: %s",
+ ofp_to_string(reply->data, reply->size,
+ verbosity + 1));
+ }
+ flags = ofpmp_flags(oh);
+ done = !(flags & OFPSF_REPLY_MORE);
+ if (found) {
+ /* We've already found the table desc consiting of current
+ * table configuration, but we need to drain the queue of
+ * any other replies for this request. */
+ continue;
+ }
+ while (!ofputil_decode_table_desc(&b, td, oh->version)) {
+ if (td->table_id == tm->table_id) {
+ found = true;
+ break;
+ }
+ }
+ } else {
+ VLOG_DBG("received reply with xid %08"PRIx32" "
+ "!= expected %08"PRIx32, recv_xid, send_xid);
+ }
+ ofpbuf_delete(reply);
+ }
+ if (tm->eviction != OFPUTIL_TABLE_EVICTION_DEFAULT) {
+ tm->vacancy = td->vacancy;
+ tm->table_vacancy.vacancy_down = td->table_vacancy.vacancy_down;
+ tm->table_vacancy.vacancy_up = td->table_vacancy.vacancy_up;
+ } else if (tm->vacancy != OFPUTIL_TABLE_VACANCY_DEFAULT) {
+ tm->eviction = td->eviction;
+ tm->eviction_flags = td->eviction_flags;
+ }
+}
+
static void
ofctl_mod_table(struct ovs_cmdl_context *ctx)
{
@@ -1941,6 +2005,7 @@ ofctl_mod_table(struct ovs_cmdl_context *ctx)
struct ofputil_table_mod tm;
struct vconn *vconn;
char *error;
+ int i;
error = parse_ofp_table_mod(&tm, ctx->argv[2], ctx->argv[3],
&usable_versions);
@@ -1951,15 +2016,36 @@ ofctl_mod_table(struct ovs_cmdl_context *ctx)
uint32_t allowed_versions = get_allowed_ofp_versions();
if (!(allowed_versions & usable_versions)) {
struct ds versions = DS_EMPTY_INITIALIZER;
- ofputil_format_version_bitmap_names(&versions, allowed_versions);
+ ofputil_format_version_bitmap_names(&versions, usable_versions);
ovs_fatal(0, "table_mod '%s' requires one of the OpenFlow "
- "versions %s but none is enabled (use -O)",
+ "versions %s",
ctx->argv[3], ds_cstr(&versions));
}
mask_allowed_ofp_versions(usable_versions);
-
enum ofputil_protocol protocol = open_vconn(ctx->argv[1], &vconn);
- transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
+
+ /* For openflow 1.4+, ovs-ofctl mod-table should not affect table-config
+ * properties that the user didn't request, so it is necessary to restore
+ * the current configuration of table-config parameters using
+ * OFPMP14_TABLE_DESC request. */
+ if ((allowed_versions & (1u << OFP14_VERSION)) ||
+ (allowed_versions & (1u << OFP15_VERSION))) {
+ struct ofputil_table_desc td;
+
+ if (tm.table_id == OFPTT_ALL) {
+ for (i = 0; i < OFPTT_MAX; i++) {
+ tm.table_id = i;
+ fetch_table_desc(vconn, &tm, &td);
+ transact_noreply(vconn,
+ ofputil_encode_table_mod(&tm, protocol));
+ }
+ } else {
+ fetch_table_desc(vconn, &tm, &td);
+ transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
+ }
+ } else {
+ transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
+ }
vconn_close(vconn);
}