Add support for configuring meters through the Meter and Meter_Band tables in the Northbound database. This commit also has ovn-northd sync those tables between the Northbound and Southbound databases.
Add support for configuring meters with ovn-nbctl. Signed-off-by: Justin Pettit <jpet...@ovn.org> --- ovn/northd/ovn-northd.c | 145 ++++++++++++++++++++++++++++++++++ ovn/ovn-nb.ovsschema | 33 +++++++- ovn/ovn-nb.xml | 80 +++++++++++++++++++ ovn/ovn-sb.ovsschema | 27 ++++++- ovn/ovn-sb.xml | 72 +++++++++++++++++ ovn/utilities/ovn-nbctl.8.xml | 50 ++++++++++++ ovn/utilities/ovn-nbctl.c | 143 +++++++++++++++++++++++++++++++++ tests/ovn-nbctl.at | 58 ++++++++++++++ 8 files changed, 604 insertions(+), 4 deletions(-) diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 04a072ba8de7..45557170edc8 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -6606,6 +6606,140 @@ sync_port_groups(struct northd_context *ctx) shash_destroy(&sb_port_groups); } +struct band_entry { + int64_t rate; + int64_t burst_size; + const char *action; +}; + +static int +band_cmp(const void *band1_, const void *band2_) +{ + const struct band_entry *band1p = band1_; + const struct band_entry *band2p = band2_; + + if (band1p->rate != band2p->rate) { + return band1p->rate > band2p->rate ? -1 : 1; + } else if (band1p->burst_size != band2p->burst_size) { + return band1p->burst_size > band2p->burst_size ? -1 : 1; + } else { + return strcmp(band1p->action, band2p->action); + } +} + +static bool +bands_need_update(const struct nbrec_meter *nb_meter, + const struct sbrec_meter *sb_meter) +{ + if (nb_meter->n_bands != sb_meter->n_bands) { + return true; + } + + /* A single band is the most common scenario, so speed up that + * check. */ + if (nb_meter->n_bands == 1) { + struct nbrec_meter_band *nb_band = nb_meter->bands[0]; + struct sbrec_meter_band *sb_band = sb_meter->bands[0]; + + return !(nb_band->rate == sb_band->rate + && nb_band->burst_size == sb_band->burst_size + && !strcmp(sb_band->action, nb_band->action)); + } + + /* Place the Northbound entries in sorted order. */ + struct band_entry *nb_bands; + nb_bands = xmalloc(sizeof *nb_bands * nb_meter->n_bands); + for (size_t i = 0; i < nb_meter->n_bands; i++) { + struct nbrec_meter_band *nb_band = nb_meter->bands[i]; + + nb_bands[i].rate = nb_band->rate; + nb_bands[i].burst_size = nb_band->burst_size; + nb_bands[i].action = nb_band->action; + } + qsort(nb_bands, nb_meter->n_bands, sizeof *nb_bands, band_cmp); + + /* Place the Southbound entries in sorted order. */ + struct band_entry *sb_bands; + sb_bands = xmalloc(sizeof *sb_bands * sb_meter->n_bands); + for (size_t i = 0; i < sb_meter->n_bands; i++) { + struct sbrec_meter_band *sb_band = sb_meter->bands[i]; + + sb_bands[i].rate = sb_band->rate; + sb_bands[i].burst_size = sb_band->burst_size; + sb_bands[i].action = sb_band->action; + } + qsort(sb_bands, sb_meter->n_bands, sizeof *sb_bands, band_cmp); + + bool need_update = false; + for (size_t i = 0; i < nb_meter->n_bands; i++) { + if (nb_bands[i].rate != sb_bands[i].rate + || nb_bands[i].burst_size != sb_bands[i].burst_size + || strcmp(nb_bands[i].action, nb_bands[i].action)) { + need_update = true; + goto done; + } + } + +done: + free(nb_bands); + free(sb_bands); + + return need_update; +} + +/* Each entry in the Meter and Meter_Band tables in OVN_Northbound have + * a corresponding entries in the Meter and Meter_Band tables in + * OVN_Southbound. + */ +static void +sync_meters(struct northd_context *ctx) +{ + struct shash sb_meters = SHASH_INITIALIZER(&sb_meters); + + const struct sbrec_meter *sb_meter; + SBREC_METER_FOR_EACH (sb_meter, ctx->ovnsb_idl) { + shash_add(&sb_meters, sb_meter->name, sb_meter); + } + + const struct nbrec_meter *nb_meter; + NBREC_METER_FOR_EACH (nb_meter, ctx->ovnnb_idl) { + bool new_sb_meter = false; + + sb_meter = shash_find_and_delete(&sb_meters, nb_meter->name); + if (!sb_meter) { + sb_meter = sbrec_meter_insert(ctx->ovnsb_txn); + sbrec_meter_set_name(sb_meter, nb_meter->name); + new_sb_meter = true; + } + + if (new_sb_meter || bands_need_update(nb_meter, sb_meter)) { + struct sbrec_meter_band **sb_bands; + sb_bands = xcalloc(nb_meter->n_bands, sizeof *sb_bands); + for (size_t i = 0; i < nb_meter->n_bands; i++) { + const struct nbrec_meter_band *nb_band = nb_meter->bands[i]; + + sb_bands[i] = sbrec_meter_band_insert(ctx->ovnsb_txn); + + sbrec_meter_band_set_action(sb_bands[i], nb_band->action); + sbrec_meter_band_set_rate(sb_bands[i], nb_band->rate); + sbrec_meter_band_set_burst_size(sb_bands[i], + nb_band->burst_size); + } + sbrec_meter_set_bands(sb_meter, sb_bands, nb_meter->n_bands); + free(sb_bands); + } + + sbrec_meter_set_unit(sb_meter, nb_meter->unit); + } + + struct shash_node *node, *next; + SHASH_FOR_EACH_SAFE (node, next, &sb_meters) { + sbrec_meter_delete(node->data); + shash_delete(&sb_meters, node); + } + shash_destroy(&sb_meters); +} + /* * struct 'dns_info' is used to sync the DNS records between OVN Northbound db * and Southbound db. @@ -6726,6 +6860,7 @@ ovnnb_db_run(struct northd_context *ctx, sync_address_sets(ctx); sync_port_groups(ctx); + sync_meters(ctx); sync_dns_entries(ctx, &datapaths); struct ovn_port_group *pg, *next_pg; @@ -7351,6 +7486,16 @@ main(int argc, char *argv[]) &sbrec_rbac_permission_col_insert_delete); add_column_noalert(ovnsb_idl_loop.idl, &sbrec_rbac_permission_col_update); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_name); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_unit); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_col_bands); + + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_meter_band); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_action); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_rate); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_meter_band_col_burst_size); + ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_chassis); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_nb_cfg); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_chassis_col_name); diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 8e6ddec4662f..9a0d8ec70514 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.11.0", - "cksum": "1149260021 18713", + "version": "5.12.0", + "cksum": "2812995200 20238", "tables": { "NB_Global": { "columns": { @@ -195,6 +195,35 @@ "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, "isRoot": false}, + "Meter": { + "columns": { + "name": {"type": "string"}, + "unit": {"type": {"key": {"type": "string", + "enum": ["set", ["kbps", "pktps"]]}}}, + "bands": {"type": {"key": {"type": "uuid", + "refTable": "Meter_Band", + "refType": "strong"}, + "min": 1, + "max": "unlimited"}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, + "Meter_Band": { + "columns": { + "action": {"type": {"key": {"type": "string", + "enum": ["set", ["drop"]]}}}, + "rate": {"type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 4294967295}}}, + "burst_size": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 4294967295}}}, + "external_ids": { + "type": {"key": "string", "value": "string", + "min": 0, "max": "unlimited"}}}, + "isRoot": false}, "Logical_Router": { "columns": { "name": {"type": "string"}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index e4e72b27cf36..1feb2af52027 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -1356,6 +1356,86 @@ </column> </table> + <table name="Meter" title="Meter table"> + <p> + Each row in this table represents a meter that can be used for QoS or + rate-limiting. + </p> + + <column name="name"> + <p> + A name for this meter. + </p> + + <p> + Names that begin with "__" are reserved for OVN internal use and should + not be added manually. + </p> + </column> + + <column name="unit"> + <p> + The unit for <ref column="rate" table="Meter_Band"/> and + <ref column="burst_rate" table="Meter_Band"/> parameters in + the <ref column="bands"/> entry. <code>kbps</code> specifies + kilobits per second, and <code>pktps</code> specifies packets + per second. + </p> + </column> + + <column name="bands"> + <p> + The bands associated with this meter. Each band specifies a + rate above which the band is to take the action + <code>action</code>. If multiple bands' rates are exceeded, + then the band with the highest rate among the exceeded bands is + selected. + </p> + </column> + + <column name="external_ids"> + See <em>External IDs</em> at the beginning of this document. + </column> + </table> + + <table name="Meter_Band" title="Meter_Band table"> + <p> + Each row in this table represents a meter band which specifies the + rate above which the configured action should be applied. These bands + are referenced by the <ref column="bands" table="Meter"/> column in + the <ref table="Meter"/> table. + </p> + + <column name="action"> + <p> + The action to execute when this band matches. The only supported + action is <code>drop</code>. + </p> + </column> + + <column name="rate"> + <p> + The relative rate limit for this band, in kilobits per second or + bits per second, depending on whether the parent <ref table="Meter"/> + entry's <ref column="unit" table="Meter"/> column specified + <code>kbps</code> or <code>pktps</code>. + </p> + </column> + + <column name="burst_size"> + <p> + The maximum burst allowed for the band in kilobits or packets, + depending on whether <code>kbps</code> or <code>pktps</code> was + selected in the parent <ref table="Meter"/> entry's + <ref column="unit" table="Meter"/> column. + </p> + </column> + + <column name="external_ids"> + See <em>External IDs</em> at the beginning of this document. + </column> + </table> + <table name="Logical_Router_Port" title="L3 logical router port"> <p> A port within an L3 logical router. diff --git a/ovn/ovn-sb.ovsschema b/ovn/ovn-sb.ovsschema index 9e271d433246..ad6ad3b71da0 100644 --- a/ovn/ovn-sb.ovsschema +++ b/ovn/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "1.15.0", - "cksum": "1839738004 13639", + "version": "1.16.0", + "cksum": "3046632234 14844", "tables": { "SB_Global": { "columns": { @@ -98,6 +98,29 @@ "indexes": [["datapath", "tunnel_key"], ["datapath", "name"]], "isRoot": true}, + "Meter": { + "columns": { + "name": {"type": "string"}, + "unit": {"type": {"key": {"type": "string", + "enum": ["set", ["kbps", "pktps"]]}}}, + "bands": {"type": {"key": {"type": "uuid", + "refTable": "Meter_Band", + "refType": "strong"}, + "min": 1, + "max": "unlimited"}}}, + "indexes": [["name"]], + "isRoot": true}, + "Meter_Band": { + "columns": { + "action": {"type": {"key": {"type": "string", + "enum": ["set", ["drop"]]}}}, + "rate": {"type": {"key": {"type": "integer", + "minInteger": 1, + "maxInteger": 4294967295}}}, + "burst_size": {"type": {"key": {"type": "integer", + "minInteger": 0, + "maxInteger": 4294967295}}}}, + "isRoot": false}, "Datapath_Binding": { "columns": { "tunnel_key": { diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index f9724d398ce6..57d8a9e042a5 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1923,6 +1923,78 @@ tcp.flags = RST; </column> </table> + <table name="Meter" title="Meter table"> + <p> + Each row in this table represents a meter that can be used for QoS or + rate-limiting. + </p> + + <column name="name"> + <p> + A name for this meter. + </p> + + <p> + Names that begin with "__" are reserved for OVN internal use and should + not be added manually. + </p> + </column> + + <column name="unit"> + <p> + The unit for <ref column="rate" table="Meter_Band"/> and + <ref column="burst_rate" table="Meter_Band"/> parameters in + the <ref column="bands"/> entry. <code>kbps</code> specifies + kilobits per second, and <code>pktps</code> specifies packets + per second. + </p> + </column> + + <column name="bands"> + <p> + The bands associated with this meter. Each band specifies a + rate above which the band is to take the action + <code>action</code>. If multiple bands' rates are exceeded, + then the band with the highest rate among the exceeded bands is + selected. + </p> + </column> + </table> + + <table name="Meter_Band" title="Meter_Band table"> + <p> + Each row in this table represents a meter band which specifies the + rate above which the configured action should be applied. These bands + are referenced by the <ref column="bands" table="Meter"/> column in + the <ref table="Meter"/> table. + </p> + + <column name="action"> + <p> + The action to execute when this band matches. The only supported + action is <code>drop</code>. + </p> + </column> + + <column name="rate"> + <p> + The relative rate limit for this band, in kilobits per second or + bits per second, depending on whether the parent <ref table="Meter"/> + entry's <ref column="unit" table="Meter"/> column specified + <code>kbps</code> or <code>pktps</code>. + </p> + </column> + + <column name="burst_size"> + <p> + The maximum burst allowed for the band in kilobits or packets, + depending on whether <code>kbps</code> or <code>pktps</code> was + selected in the parent <ref table="Meter"/> entry's + <ref column="unit" table="Meter"/> column. + </p> + </column> + </table> + <table name="Datapath_Binding" title="Physical-Logical Datapath Bindings"> <p> Each row in this table represents a logical datapath, which implements a diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index 2cd2fab304cd..a8ea7d8cb1e1 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -172,6 +172,56 @@ </dd> </dl> + <h1>Meter Commands</h1> + <dl> + <dt><code>meter-add</code> <var>name</var> <var>unit</var> <var>action</var> <var>rate</var> [<var>burst_size</var>]</dt> + <dd> + <p> + Adds the specified meter. <var>name</var> must be a unique + name to identify this meter. The <var>action</var> argument + specifies what should happen when this meter is exceeded. + The only supported action is <code>drop</code>. + </p> + + <p> + The <var>unit</var> specifies the unit for the <var>rate</var> + argument; valid values are <code>kbps</code> and + <code>pktps</code> for kilobits per second and packets per + second, respectively. The <var>burst_rate</var> option + configures the maximum burst allowed for the band in kilobits + or packets depending on whether the <var>unit</var> chosen was + <code>kbps</code> or <code>pktps</code>, respectively. + </p> + + <p> + <code>ovn-nbctl</code> only supports adding a meter with a + single band, but the other commands support meters with + multiple bands. + </p> + + <p> + Names that start with "__" are reserved for internal use by OVN, + so <code>ovn-nbctl</code> does not allow adding them. + </p> + </dd> + + <dt><code>meter-del</code> [<var>name</var>]</dt> + <dd> + <p> + Deletes meters. By default, all meters are deleted. If + <var>name</var> is supplied, only the meter with that name + will be deleted. + </p> + </dd> + + <dt><code>meter-list</code></dt> + <dd> + <p> + Lists all meters. + </p> + </dd> + </dl> + <h1>Logical Switch Port Commands</h1> <dl> <dt>[<code>--may-exist</code>] <code>lsp-add</code> <var>switch</var> <var>port</var></dt> diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index 3c3e582cb906..9f0e6347c104 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -496,6 +496,12 @@ QoS commands:\n\ remove QoS rules from SWITCH\n\ qos-list SWITCH print QoS rules for SWITCH\n\ \n\ +Meter commands:\n\ + meter-add NAME UNIT ACTION RATE [BURST_SIZE]\n\ + add a meter\n\ + meter-del [NAME] remove meters\n\ + meter-list print meters\n\ +\n\ Logical switch port commands:\n\ lsp-add SWITCH PORT add logical port PORT on SWITCH\n\ lsp-add SWITCH PORT PARENT TAG\n\ @@ -2290,6 +2296,137 @@ nbctl_qos_del(struct ctl_context *ctx) } } +static int +meter_cmp(const void *meter1_, const void *meter2_) +{ + struct nbrec_meter *const *meter1p = meter1_; + struct nbrec_meter *const *meter2p = meter2_; + const struct nbrec_meter *meter1 = *meter1p; + const struct nbrec_meter *meter2 = *meter2p; + + return strcmp(meter1->name, meter2->name); +} + +static void +nbctl_meter_list(struct ctl_context *ctx) +{ + const struct nbrec_meter **meters = NULL; + const struct nbrec_meter *meter; + size_t n_capacity = 0; + size_t n_meters = 0; + + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (n_meters == n_capacity) { + meters = x2nrealloc(meters, &n_capacity, sizeof *meters); + } + + meters[n_meters] = meter; + n_meters++; + } + + if (n_meters) { + qsort(meters, n_meters, sizeof *meters, meter_cmp); + } + + for (size_t i = 0; i < n_meters; i++) { + meter = meters[i]; + ds_put_format(&ctx->output, "%s: unit=%s bands:\n", meter->name, + meter->unit); + + for (size_t j = 0; j < meter->n_bands; j++) { + const struct nbrec_meter_band *band = meter->bands[j]; + + ds_put_format(&ctx->output, " %s: rate=%"PRId64"", + band->action, band->rate); + if (band->burst_size) { + ds_put_format(&ctx->output, ", burst_size=%"PRId64"", + band->burst_size); + } + } + + ds_put_cstr(&ctx->output, "\n"); + } + + free(meters); +} + +static void +nbctl_meter_add(struct ctl_context *ctx) +{ + const struct nbrec_meter *meter; + + const char *name = ctx->argv[1]; + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (!strcmp(meter->name, name)) { + ctl_fatal("meter with name \"%s\" already exists", name); + } + } + + if (!strncmp(name, "__", 2)) { + ctl_fatal("meter names that begin with \"__\" are reserved"); + } + + const char *unit = ctx->argv[2]; + if (strcmp(unit, "kbps") && strcmp(unit, "pktps")) { + ctl_fatal("unit must be \"kbps\" or \"pktps\""); + } + + const char *action = ctx->argv[3]; + if (strcmp(action, "drop")) { + ctl_fatal("action must be \"drop\""); + } + + int64_t rate; + if (!ovs_scan(ctx->argv[4], "%"SCNd64, &rate) + || rate < 1 || rate > UINT32_MAX) { + ctl_fatal("rate must be in the range 1...4294967295"); + } + + int64_t burst_size = 0; + if (ctx->argc > 5) { + if (!ovs_scan(ctx->argv[5], "%"SCNd64, &burst_size) + || burst_size < 0 || burst_size > UINT32_MAX) { + ctl_fatal("burst_size must be in the range 0...4294967295"); + } + } + + /* Create the band. We only support adding a single band. */ + struct nbrec_meter_band *band = nbrec_meter_band_insert(ctx->txn); + nbrec_meter_band_set_action(band, action); + nbrec_meter_band_set_rate(band, rate); + nbrec_meter_band_set_burst_size(band, burst_size); + + /* Create the meter. */ + meter = nbrec_meter_insert(ctx->txn); + nbrec_meter_set_name(meter, name); + nbrec_meter_set_unit(meter, unit); + nbrec_meter_set_bands(meter, &band, 1); +} + +static void +nbctl_meter_del(struct ctl_context *ctx) +{ + const struct nbrec_meter *meter, *next; + + /* If a name is not specified, delete all meters. */ + if (ctx->argc == 1) { + NBREC_METER_FOR_EACH_SAFE (meter, next, ctx->idl) { + nbrec_meter_delete(meter); + } + return; + } + + /* Remove the matching meter. */ + NBREC_METER_FOR_EACH (meter, ctx->idl) { + if (strcmp(ctx->argv[1], meter->name)) { + continue; + } + + nbrec_meter_delete(meter); + return; + } +} + static void nbctl_lb_add(struct ctl_context *ctx) { @@ -4678,6 +4815,12 @@ static const struct ctl_command_syntax nbctl_commands[] = { nbctl_qos_del, NULL, "", RW }, { "qos-list", 1, 1, "SWITCH", NULL, nbctl_qos_list, NULL, "", RO }, + /* meter commands. */ + { "meter-add", 4, 5, "NAME UNIT ACTION RATE [BURST_SIZE]", NULL, + nbctl_meter_add, NULL, "", RW }, + { "meter-del", 0, 1, "[NAME]", NULL, nbctl_meter_del, NULL, "", RW }, + { "meter-list", 0, 0, "", NULL, nbctl_meter_list, NULL, "", RO }, + /* logical switch port commands. */ { "lsp-add", 2, 4, "SWITCH PORT [PARENT] [TAG]", NULL, nbctl_lsp_add, NULL, "--may-exist", RW }, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index 64e217654c2f..7a1445e312ff 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -323,6 +323,64 @@ OVN_NBCTL_TEST_STOP AT_CLEANUP dnl --------------------------------------------------------------------- + +AT_SETUP([ovn-nbctl - Meters]) +OVN_NBCTL_TEST_START + +AT_CHECK([ovn-nbctl meter-add meter1 kbps drop 10]) +AT_CHECK([ovn-nbctl meter-add meter2 kbps drop 3 2]) +AT_CHECK([ovn-nbctl meter-add meter3 kbps drop 100 200]) + +dnl Add duplicate meter name +AT_CHECK([ovn-nbctl meter-add meter1 kbps drop 10], [1], [], [stderr]) +AT_CHECK([grep 'already exists' stderr], [0], [ignore]) + +dnl Add reserved meter name +AT_CHECK([ovn-nbctl meter-add __meter1 kbps drop 10], [1], [], [stderr]) +AT_CHECK([grep 'reserved' stderr], [0], [ignore]) + +dnl Add meter with invalid rates +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 100010111111], [1], [], +[ovn-nbctl: rate must be in the range 1...4294967295 +]) + +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 0], [1], [], +[ovn-nbctl: rate must be in the range 1...4294967295 +]) + +dnl Add meter with invalid burst_size +AT_CHECK([ovn-nbctl meter-add meter4 kbps drop 10 100010111111], [1], [], +[ovn-nbctl: burst_size must be in the range 0...4294967295 +]) + +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +meter1: unit=kbps bands: + drop: rate=10 +meter2: unit=kbps bands: + drop: rate=3, burst_size=2 +meter3: unit=kbps bands: + drop: rate=100, burst_size=200 +]) + +dnl Delete a single meter. +AT_CHECK([ovn-nbctl meter-del meter2]) +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +meter1: unit=kbps bands: + drop: rate=10 +meter3: unit=kbps bands: + drop: rate=100, burst_size=200 +]) + +dnl Delete all meters. +AT_CHECK([ovn-nbctl meter-del]) +AT_CHECK([ovn-nbctl meter-list], [0], [dnl +]) + +OVN_NBCTL_TEST_STOP +AT_CLEANUP + +dnl --------------------------------------------------------------------- + AT_SETUP([ovn-nbctl - NATs]) OVN_NBCTL_TEST_START AT_CHECK([ovn-nbctl lr-add lr0]) -- 2.17.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev