From patchwork Tue Sep 1 11:00:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Saloni Jain X-Patchwork-Id: 512780 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (unknown [IPv6:2600:3c00::f03c:91ff:fe6e:bdf7]) by ozlabs.org (Postfix) with ESMTP id C200F14076A for ; Tue, 1 Sep 2015 21:00:42 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id BD245106BC; Tue, 1 Sep 2015 04:00:40 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id A0C7B106BB for ; Tue, 1 Sep 2015 04:00:39 -0700 (PDT) Received: from bar3.cudamail.com (bar1 [192.168.15.1]) by mx3v1.cudamail.com (Postfix) with ESMTP id 015F0618EDA for ; Tue, 1 Sep 2015 05:00:39 -0600 (MDT) X-ASG-Debug-ID: 1441105229-03dd7b127e3c8cb0001-byXFYA Received: from mx3-pf2.cudamail.com ([192.168.14.1]) by bar3.cudamail.com with ESMTP id xzO2M2wGzHtKZyHo (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 01 Sep 2015 05:00:29 -0600 (MDT) X-Barracuda-Envelope-From: prvs=679687cfd=saloni.jain@tcs.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.1 Received: from unknown (HELO indelg01.tcs.com) (203.200.109.55) by mx3-pf2.cudamail.com with SMTP; 1 Sep 2015 11:00:26 -0000 Received-SPF: pass (mx3-pf2.cudamail.com: SPF record at tcs.com designates 203.200.109.55 as permitted sender) X-Barracuda-Apparent-Source-IP: 203.200.109.55 X-Barracuda-RBL-IP: 203.200.109.55 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A2BEAgCOhOVV/0YgFaxdg29pvi0BCYFvhgMCgW0UAQEBAQEBAYEKhCMBAQEEGgEMUhAFBAINBAMBAiEBBgchJQkIBgEKCBEKh34DlSucKwEBAZBgDYUVAQEBAQEBAQEBAQEBAQEBAQEBAQEBF4Z0hHyBT4EAgisRBwaDEoEUBYcohjs4hyaFB4YBg32MYYQ/hzyCNRyBXGmCTQEBAQ X-IPAS-Result: A2BEAgCOhOVV/0YgFaxdg29pvi0BCYFvhgMCgW0UAQEBAQEBAYEKhCMBAQEEGgEMUhAFBAINBAMBAiEBBgchJQkIBgEKCBEKh34DlSucKwEBAZBgDYUVAQEBAQEBAQEBAQEBAQEBAQEBAQEBF4Z0hHyBT4EAgisRBwaDEoEUBYcohjs4hyaFB4YBg32MYYQ/hzyCNRyBXGmCTQEBAQ X-IronPort-AV: E=Sophos;i="5.17,448,1437417000"; d="scan'208,217";a="122669322" MIME-Version: 1.0 Importance: Normal X-Priority: 3 (Normal) In-Reply-To: <1440497415-1374-1-git-send-email-saloni.jain@tcs.com> References: <1440497415-1374-1-git-send-email-saloni.jain@tcs.com> X-CudaMail-MID: CM-V2-831005449 X-CudaMail-DTE: 090115 X-CudaMail-Originating-IP: 203.200.109.55 X-CudaMail-Envelope-Sender: prvs=679687cfd=saloni.jain@tcs.com X-ASG-Orig-Subj: [##CM-V2-831005449##]Re: [PATCH v3 1/3] Implement Openflow 1.4 Vacancy Events for OFPT_TABLE_MOD. From: Saloni Jain To: saloni.jain12@gmail.com, dev@openvswitch.org, "Ben Pfaff" Message-ID: Date: Tue, 1 Sep 2015 16:30:09 +0530 X-Mailer: Lotus Domino Web Server Release 9.0.1FP4 June 07, 2015 X-MIMETrack: Serialize by http on InDelM02/TCS(Release 9.0.1FP4|June 07, 2015) at 09/01/2015 16:30:09, Serialize complete at 09/01/2015 16:30:10, Itemize by http on InDelM02/TCS(Release 9.0.1FP4|June 07, 2015) at 09/01/2015 16:30:10, Serialize by Router on InDelM02/TCS(Release 9.0.1FP4|June 07, 2015) at 09/01/2015 16:30:15 X-GBUdb-Analysis: 0, 203.200.109.55, Ugly c=0.200527 p=-0.142857 Source Normal X-MessageSniffer-Rules: 0-0-0-32767-c X-Barracuda-Connect: UNKNOWN[192.168.14.1] X-Barracuda-Start-Time: 1441105229 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-Spam-Score: 0.60 X-Barracuda-Spam-Status: No, SCORE=0.60 using per-user scores of TAG_LEVEL=3.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=3.0 tests=BSF_SC5_MJ1963, HTML_MESSAGE, RDNS_NONE X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.22116 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.00 HTML_MESSAGE BODY: HTML included in message 0.10 RDNS_NONE Delivered to trusted network by a host with no rDNS 0.50 BSF_SC5_MJ1963 Custom Rule MJ1963 X-Content-Filtered-By: Mailman/MimeDel 2.1.16 Cc: Deepankar Gupta , Partha Datta Subject: Re: [ovs-dev] [PATCH v3 1/3] Implement Openflow 1.4 Vacancy Events for OFPT_TABLE_MOD. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@openvswitch.org Sender: "dev" 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 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); ÿ} ÿ