From: Saloni Jain <saloni.j...@tcs.com> OpenFlow 1.4 introduces the ability to turn on vacancy events with an OFPT_TABLE_MOD message specifying OFPTC_VACANCY_EVENTS. This commit adds support for the new feature in ovs-ofctl mod-table. As per the openflow specification-1.4, vacancy event adds a mechanism enabling the controller to get an early warning based on capacity threshold chosen by the controller.
With this commit, vacancy events can be configured as: ovs-ofctl -O OpenFlow14 mod-table <bridge> <table> vacancy-<range> The syntax of <range> as <low..high>. <range> specify vacancy threshold values, vacancy down and vacancy up. To disable vacancy events, following command should be given: ovs-ofctl -O OpenFlow14 mod-table <bridge> <table> novacancy Signed-off-by: Saloni Jain <saloni.j...@tcs.com> --- lib/ofp-parse.c | 65 +++++++++++++++++++++++++++++--- lib/ofp-parse.h | 3 ++ lib/ofp-print.c | 22 +++++++++++ lib/ofp-util.c | 87 ++++++++++++++++++++++++++++++++++++++---- lib/ofp-util.h | 39 +++++++++++++++++++ ofproto/ofproto-provider.h | 11 ++++++ ofproto/ofproto.c | 24 ++++++++---- tests/ofp-print.at | 2 +- utilities/ovs-ofctl.c | 90 +++++++++++++++++++++++++++++++++++++++++++- 9 files changed, 319 insertions(+), 24 deletions(-) diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 8cdda50..9239bb2 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 6db32d1..cf35aa6 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -993,6 +993,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) { @@ -1023,6 +1035,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 9996e84..e2e90ff 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 { @@ -5015,9 +5018,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, @@ -5054,8 +5102,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) { @@ -5088,11 +5138,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(); } @@ -5142,6 +5197,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); @@ -5156,6 +5212,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; @@ -5171,6 +5228,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; @@ -5212,19 +5273,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); @@ -5232,6 +5294,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: @@ -5579,6 +5649,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 1fc5001..123e1ba 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 a724071..176ff10 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -6609,20 +6609,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; } @@ -6633,6 +6633,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 @@ -6656,7 +6666,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 { @@ -6664,7 +6674,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 127bcf1..6abbc1e 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 0bc7089..4c300b1 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -1865,6 +1865,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) { @@ -1872,6 +1936,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); @@ -1888,9 +1953,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); } -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev