[ovs-dev,v3,1/3] Implement Openflow 1.4 Vacancy Events for OFPT_TABLE_MOD.
diff mbox

Message ID OF4898ABE1.A32526DB-ON65257EB3.003C706A-65257EB3.003C706F@tcs.com
State Changes Requested
Headers show

Commit Message

Saloni Jain Sept. 1, 2015, 11 a.m. UTC
Hi Ben,

Greetings!
This is in reference to the patch series "Implementation of OpenFlow 1.4 Vacancy Events"[Version 3] which is under review.

1. [PATCH v3 1/3] : Implement Openflow 1.4 Vacancy Events for OFPT_TABLE_MOD.

2. [PATCH v3 2/3] : Implement Vacancy Events for OFPMP_TABLE_DESC.

3. [PATCH v3 3/3] : Implement OFPT_TABLE_STATUS Message.

Request to kindly provide  inputs on the same(if any) or if any action is required from our end.

Thanks and Regards,
Saloni Jain
Tata Consultancy Services
Mailto: saloni.jain@tcs.com
Website: http://www.tcs.com

Patch
diff mbox

diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c
index ade664b..ceb07be 100644
--- a/lib/ofp-parse.c
+++ b/lib/ofp-parse.c
@@ -869,6 +869,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.
@@ -895,13 +938,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;
@@ -918,6 +961,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);
ÿÿ ÿ }
diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h
index 930e3d9..b283e07 100644
--- a/lib/ofp-parse.h
+++ b/lib/ofp-parse.h
@@ -99,5 +99,8 @@  char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT;
ÿchar *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT;
ÿchar *str_to_mac(const char *str, uint8_t mac[ETH_ADDR_LEN]) OVS_WARN_UNUSED_RESULT;
ÿchar *str_to_ip(const char *str, ovs_be32 *ip) 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 */
diff --git a/lib/ofp-print.c b/lib/ofp-print.c
index 6e32d4d..9fe05bd 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -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,16 @@  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_down=%"PRIu8"%%",
+ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿpm.table_vacancy.vacancy_down);
+ ÿ ÿ ÿ ÿ ÿ ÿds_put_format(string, " vacancy_up=%"PRIu8"%%",
+ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿpm.table_vacancy.vacancy_up);
+ ÿ ÿ ÿ ÿ}
+ ÿ ÿ}
ÿ}
ÿ
ÿ/* This function will print the Table description properties. */
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 0a5232d..eaaf0ab 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -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 {
@@ -5013,9 +5016,54 @@  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;
+ ÿ ÿ}
+ ÿ ÿ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,
@@ -5052,8 +5100,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) {
@@ -5086,11 +5136,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();
ÿ}
@@ -5140,6 +5195,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);
ÿ
@@ -5154,6 +5210,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;
@@ -5169,6 +5226,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;
@@ -5210,19 +5271,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);
@@ -5230,6 +5292,14 @@  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;
+ ÿ ÿ ÿ ÿ ÿ ÿotv->vacancy = tm->table_vacancy.vacancy;
+ ÿ ÿ ÿ ÿ}
ÿÿ ÿ ÿ ÿ break;
ÿÿ ÿ }
ÿÿ ÿ default:
@@ -5577,6 +5647,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);
diff --git a/lib/ofp-util.h b/lib/ofp-util.h
index 2668e75..770b33a 100644
--- a/lib/ofp-util.h
+++ b/lib/ofp-util.h
@@ -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 *,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 117cd1f..76b4289 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -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 */
+ ÿ ÿunsigned int vacancy;
+
+ ÿ ÿ/* 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;
ÿ};
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index e9b1472..1663749 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -6610,20 +6610,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;
ÿÿ ÿ }
ÿ
@@ -6634,6 +6634,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 = (tm->vacancy == OFPUTIL_TABLE_VACANCY_ON
+ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ? oftable->vacancy | OFPTC14_VACANCY_EVENTS
+ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ: oftable->vacancy & ~OFPTC14_VACANCY_EVENTS);
+ ÿ ÿ ÿ ÿoftable->vacancy_down = tm->table_vacancy.vacancy_down;
+ ÿ ÿ ÿ ÿoftable->vacancy_up = tm->table_vacancy.vacancy_up;
+ ÿ ÿ ÿ ÿovs_mutex_unlock(&ofproto_mutex);
+ ÿ ÿ}
ÿ}
ÿ
ÿstatic enum ofperr
@@ -6657,7 +6667,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 {
@@ -6665,7 +6675,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;
diff --git a/tests/ofp-print.at b/tests/ofp-print.at
index 35a6262..a2b4359 100644
--- a/tests/ofp-print.at
+++ b/tests/ofp-print.at
@@ -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
ÿ
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 6ec7151..327770e 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -1929,6 +1929,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)
ÿ{
@@ -1936,6 +2000,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);
@@ -1952,9 +2017,30 @@  ofctl_mod_table(struct ovs_cmdl_context *ctx)
ÿÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ ÿ 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 ((usable_versions & (1u << OFP14_VERSION)) ||
+ ÿ ÿ ÿ ÿ(usable_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);
ÿ}
ÿ