2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00

ovsdb-data: Add support for integer ranges in database commands

Adding / removing a range of integers to a column accepting a set of
integers requires enumarating all of the integers. This patch simplifies
it by introducing 'range' concept to the database commands. Two integers
separated by a hyphen represent an inclusive range.

The patch adds positive and negative tests for the new syntax.
The patch was tested by 'make check'. Covarage was tested by
'make check-lcov'.

Signed-off-by: Lukasz Rzasik <lukasz.rzasik@gmail.com>
Suggested-by: <my_ovs_discuss@yahoo.com>
Suggested-by: Ben Pfaff <blp@ovn.org>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Lukasz Rzasik 2016-12-29 15:55:46 -07:00 committed by Ben Pfaff
parent 84d0ca5d00
commit 1ab39058cc
11 changed files with 284 additions and 67 deletions

View File

@ -190,6 +190,7 @@ Luca Giraudo lgiraudo@nicira.com
Lucian Petrut lpetrut@cloudbasesolutions.com
Luigi Rizzo rizzo@iet.unipi.it
Luis E. P. l31g@hotmail.com
Lukasz Rzasik lukasz.rzasik@gmail.com
Madhu Challa challa@noironetworks.com
Mario Cabrera mario.cabrera@hpe.com
Mark D. Gray mark.d.gray@intel.com

3
NEWS
View File

@ -59,6 +59,9 @@ Post-v2.6.0
* Ports now have a "protected" flag. Protected ports can not forward
frames to other protected ports. Unprotected ports can receive and
forward frames to protected and other unprotected ports.
- ovs-vsctl, ovn-nbctl, ovn-sbctl, vtep-ctl:
* Database commands now accept integer ranges, e.g. "set port
eth0 trunks=1-10" to enable trunking VLANs 1 to 10.
v2.6.0 - 27 Sep 2016
---------------------

View File

@ -677,7 +677,7 @@ is_condition_satisfied(const struct ctl_table_class *table,
column->name);
}
die_if_error(ovsdb_atom_from_string(&want_key, &column->type.key,
die_if_error(ovsdb_atom_from_string(&want_key, NULL, &column->type.key,
key_string, symtab));
type.key = type.value;
@ -823,7 +823,7 @@ cmd_get(struct ctl_context *ctx)
column->name);
}
die_if_error(ovsdb_atom_from_string(&key,
die_if_error(ovsdb_atom_from_string(&key, NULL,
&column->type.key,
key_string, ctx->symtab));
@ -1118,13 +1118,13 @@ set_column(const struct ctl_table_class *table,
column->name);
}
die_if_error(ovsdb_atom_from_string(&key, &column->type.key,
die_if_error(ovsdb_atom_from_string(&key, NULL, &column->type.key,
key_string, symtab));
die_if_error(ovsdb_atom_from_string(&value, &column->type.value,
die_if_error(ovsdb_atom_from_string(&value, NULL, &column->type.value,
value_string, symtab));
ovsdb_datum_init_empty(&datum);
ovsdb_datum_add_unsafe(&datum, &key, &value, &column->type);
ovsdb_datum_add_unsafe(&datum, &key, &value, &column->type, NULL);
ovsdb_atom_destroy(&key, column->type.key.type);
ovsdb_atom_destroy(&value, column->type.value.type);

View File

@ -29,7 +29,11 @@ single comma. When multiple values are present, duplicates are not
allowed, and order is not important. Conversely, some database
columns can have an empty set of values, represented as \fB[]\fR, and
square brackets may optionally enclose other non-empty sets or single
values as well.
values as well. For a column accepting a set of integers, database commands
accept a range. A range is represented by two integers separated by
\fB-\fR. A range is inclusive. A range has a maximum size of 4096
elements. If more elements are needed, they can be specified in seperate
ranges.
.PP
A few database columns are ``maps'' of key-value pairs, where the key
and the value are each some fixed database type. These are specified

View File

@ -305,6 +305,25 @@ ovsdb_symbol_referenced(struct ovsdb_symbol *symbol,
}
}
static union ovsdb_atom *
alloc_default_atoms(enum ovsdb_atomic_type type, size_t n)
{
if (type != OVSDB_TYPE_VOID && n) {
union ovsdb_atom *atoms;
unsigned int i;
atoms = xmalloc(n * sizeof *atoms);
for (i = 0; i < n; i++) {
ovsdb_atom_init_default(&atoms[i], type);
}
return atoms;
} else {
/* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
* treated as xmalloc(1). */
return NULL;
}
}
static struct ovsdb_error * OVS_WARN_UNUSED_RESULT
ovsdb_atom_parse_uuid(struct uuid *uuid, const struct json *json,
struct ovsdb_symbol_table *symtab,
@ -468,6 +487,7 @@ ovsdb_atom_to_json(const union ovsdb_atom *atom, enum ovsdb_atomic_type type)
static char *
ovsdb_atom_from_string__(union ovsdb_atom *atom,
union ovsdb_atom **range_end_atom,
const struct ovsdb_base_type *base, const char *s,
struct ovsdb_symbol_table *symtab)
{
@ -478,9 +498,20 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom,
OVS_NOT_REACHED();
case OVSDB_TYPE_INTEGER: {
long long int integer;
if (!str_to_llong(s, 10, &integer)) {
return xasprintf("\"%s\" is not a valid integer", s);
long long int integer, end;
if (range_end_atom
&& str_to_llong_range(s, 10, &integer, &end)) {
if (end < integer) {
return xasprintf("\"%s\" is not a valid range. "
"Range end cannot be before start.", s);
}
*range_end_atom = alloc_default_atoms(type, 1);
if (!(*range_end_atom)) {
return xasprintf("\"%s\" is not a valid range", s);
}
(*range_end_atom)->integer = end;
} else if (!str_to_llong(s, 10, &integer)) {
return xasprintf("\"%s\" is not a valid integer or range", s);
}
atom->integer = integer;
}
@ -549,10 +580,13 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom,
return NULL;
}
/* Initializes 'atom' to a value of type 'base' parsed from 's', which takes
* one of the following forms:
/* Initializes 'atom' and optionally 'range_end_atom' to a value of type 'base'
* parsed from 's', which takes one of the following forms:
*
* - OVSDB_TYPE_INTEGER: A decimal integer optionally preceded by a sign.
* - OVSDB_TYPE_INTEGER: A decimal integer optionally preceded by a sign
* or two decimal integers optionally preceded by a sign and separated
* by a hyphen, representing inclusive range of integers
* ['atom', 'range_end_atom'].
*
* - OVSDB_TYPE_REAL: A floating-point number in the format accepted by
* strtod().
@ -574,23 +608,62 @@ ovsdb_atom_from_string__(union ovsdb_atom *atom,
* Returns a null pointer if successful, otherwise an error message describing
* the problem. On failure, the contents of 'atom' are indeterminate. The
* caller is responsible for freeing the atom or the error.
*
* Does not attempt to parse range if 'range_end_atom' is a null pointer.
* Dynamically allocates ovdsb_atom and stores its address in '*range_end_atom'
* if successfully parses range. Caller is responsible for deallocating
* the memory by calling 'ovsdb_atom_destroy' and then 'free' on the address.
* Does not allocate memory and sets '*range_end_atom' to a null pointer
* if does not parse a range or fails for any reason.
*/
char *
ovsdb_atom_from_string(union ovsdb_atom *atom,
union ovsdb_atom **range_end_atom,
const struct ovsdb_base_type *base, const char *s,
struct ovsdb_symbol_table *symtab)
{
struct ovsdb_error *error;
char *msg;
msg = ovsdb_atom_from_string__(atom, base, s, symtab);
if (range_end_atom) {
*range_end_atom = NULL;
}
msg = ovsdb_atom_from_string__(atom, range_end_atom, base, s, symtab);
if (msg) {
return msg;
}
error = ovsdb_atom_check_constraints(atom, base);
if (!error && range_end_atom && *range_end_atom) {
/* Check range constraints */
int64_t start = atom->integer;
int64_t end = (*range_end_atom)->integer;
if (base->enum_) {
for (int64_t i = start + 1; i <= end; i++) {
union ovsdb_atom ai = { .integer = i };
error = ovsdb_atom_check_constraints(&ai, base);
if (error) {
break;
}
}
} else {
error = ovsdb_atom_check_constraints(*range_end_atom, base);
}
if (!error) {
error = ovsdb_atom_range_check_size(start, end);
}
}
if (error) {
ovsdb_atom_destroy(atom, base->type);
if (range_end_atom && *range_end_atom) {
ovsdb_atom_destroy(*range_end_atom, base->type);
free(*range_end_atom);
*range_end_atom = NULL;
}
msg = ovsdb_error_to_string(error);
ovsdb_error_destroy(error);
}
@ -811,25 +884,6 @@ ovsdb_atom_check_constraints(const union ovsdb_atom *atom,
}
}
static union ovsdb_atom *
alloc_default_atoms(enum ovsdb_atomic_type type, size_t n)
{
if (type != OVSDB_TYPE_VOID && n) {
union ovsdb_atom *atoms;
unsigned int i;
atoms = xmalloc(n * sizeof *atoms);
for (i = 0; i < n; i++) {
ovsdb_atom_init_default(&atoms[i], type);
}
return atoms;
} else {
/* Avoid wasting memory in the n == 0 case, because xmalloc(0) is
* treated as xmalloc(1). */
return NULL;
}
}
/* Initializes 'datum' as an empty datum. (An empty datum can be treated as
* any type.) */
void
@ -1336,13 +1390,15 @@ skip_spaces(const char *p)
static char *
parse_atom_token(const char **s, const struct ovsdb_base_type *base,
union ovsdb_atom *atom, struct ovsdb_symbol_table *symtab)
union ovsdb_atom *atom, union ovsdb_atom **range_end_atom,
struct ovsdb_symbol_table *symtab)
{
char *token, *error;
error = ovsdb_token_parse(s, &token);
if (!error) {
error = ovsdb_atom_from_string(atom, base, token, symtab);
error = ovsdb_atom_from_string(atom, range_end_atom,
base, token, symtab);
free(token);
}
return error;
@ -1351,37 +1407,50 @@ parse_atom_token(const char **s, const struct ovsdb_base_type *base,
static char *
parse_key_value(const char **s, const struct ovsdb_type *type,
union ovsdb_atom *key, union ovsdb_atom *value,
struct ovsdb_symbol_table *symtab)
struct ovsdb_symbol_table *symtab,
union ovsdb_atom **range_end_key)
{
const char *start = *s;
char *error;
error = parse_atom_token(s, &type->key, key, symtab);
error = parse_atom_token(s, &type->key, key, range_end_key, symtab);
if (!error && type->value.type != OVSDB_TYPE_VOID) {
*s = skip_spaces(*s);
if (**s == '=') {
(*s)++;
*s = skip_spaces(*s);
error = parse_atom_token(s, &type->value, value, symtab);
error = parse_atom_token(s, &type->value, value, NULL, symtab);
} else {
error = xasprintf("%s: syntax error at \"%c\" expecting \"=\"",
start, **s);
}
if (error) {
ovsdb_atom_destroy(key, type->key.type);
if (range_end_key && *range_end_key) {
ovsdb_atom_destroy(*range_end_key, type->key.type);
free(*range_end_key);
*range_end_key = NULL;
}
}
}
return error;
}
static void
free_key_value(const struct ovsdb_type *type,
union ovsdb_atom *key, union ovsdb_atom *value)
free_key_value_range(const struct ovsdb_type *type,
union ovsdb_atom *key, union ovsdb_atom *value,
union ovsdb_atom **range_end_atom)
{
ovsdb_atom_destroy(key, type->key.type);
if (type->value.type != OVSDB_TYPE_VOID) {
ovsdb_atom_destroy(value, type->value.type);
}
if (range_end_atom && *range_end_atom) {
ovsdb_atom_destroy(*range_end_atom, type->key.type);
free(*range_end_atom);
*range_end_atom = NULL;
}
}
/* Initializes 'datum' as a datum of the given 'type', parsing its contents
@ -1423,6 +1492,7 @@ ovsdb_datum_from_string(struct ovsdb_datum *datum,
while (*p && *p != end_delim) {
union ovsdb_atom key, value;
union ovsdb_atom *range_end_key = NULL;
if (ovsdb_token_is_delim(*p)) {
char *type_str = ovsdb_type_to_english(type);
@ -1433,12 +1503,13 @@ ovsdb_datum_from_string(struct ovsdb_datum *datum,
}
/* Add to datum. */
error = parse_key_value(&p, type, &key, &value, symtab);
error = parse_key_value(&p, type, &key, &value,
symtab, &range_end_key);
if (error) {
goto error;
}
ovsdb_datum_add_unsafe(datum, &key, &value, type);
free_key_value(type, &key, &value);
ovsdb_datum_add_unsafe(datum, &key, &value, type, range_end_key);
free_key_value_range(type, &key, &value, &range_end_key);
/* Skip optional white space and comma. */
p = skip_spaces(p);
@ -1760,11 +1831,16 @@ ovsdb_datum_remove_unsafe(struct ovsdb_datum *datum, size_t idx,
}
/* Adds the element with the given 'key' and 'value' to 'datum', which must
* have the specified 'type'.
* have the specified 'type'. Optionally if 'range_end_atom' is not
* a null pointer, adds a set of integers to 'datum' from inclusive
* range ['key', 'range_end_atom'].
*
* This function always allocates memory, so it is not an efficient way to add
* a number of elements to a datum.
*
* When adding a range of integers, this function allocates the memory once
* for the whole range.
*
* This function does not maintain ovsdb_datum invariants. Use
* ovsdb_datum_sort() to check and restore these invariants. (But a datum with
* 0 or 1 elements cannot violate the invariants anyhow.) */
@ -1772,15 +1848,24 @@ void
ovsdb_datum_add_unsafe(struct ovsdb_datum *datum,
const union ovsdb_atom *key,
const union ovsdb_atom *value,
const struct ovsdb_type *type)
const struct ovsdb_type *type,
const union ovsdb_atom *range_end_atom)
{
size_t idx = datum->n++;
size_t idx = datum->n;
datum->n += range_end_atom ?
(range_end_atom->integer - key->integer + 1) : 1;
datum->keys = xrealloc(datum->keys, datum->n * sizeof *datum->keys);
ovsdb_atom_clone(&datum->keys[idx], key, type->key.type);
if (type->value.type != OVSDB_TYPE_VOID) {
datum->values = xrealloc(datum->values,
datum->n * sizeof *datum->values);
ovsdb_atom_clone(&datum->values[idx], value, type->value.type);
if (range_end_atom && key->integer <= range_end_atom->integer) {
for (int64_t i = key->integer; i <= range_end_atom->integer; i++) {
datum->keys[idx++].integer = i;
}
} else {
ovsdb_atom_clone(&datum->keys[idx], key, type->key.type);
if (type->value.type != OVSDB_TYPE_VOID) {
datum->values = xrealloc(datum->values,
datum->n * sizeof *datum->values);
ovsdb_atom_clone(&datum->values[idx], value, type->value.type);
}
}
}
@ -1937,29 +2022,31 @@ ovsdb_datum_diff(struct ovsdb_datum *diff,
type->key.type);
if (c < 0) {
ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi],
type);
type, NULL);
oi++;
} else if (c > 0) {
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
type);
type, NULL);
ni++;
} else {
if (type->value.type != OVSDB_TYPE_VOID &&
ovsdb_atom_compare_3way(&old->values[oi], &new->values[ni],
type->value.type)) {
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
type);
type, NULL);
}
oi++; ni++;
}
}
for (; oi < old->n; oi++) {
ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi], type);
ovsdb_datum_add_unsafe(diff, &old->keys[oi], &old->values[oi],
type, NULL);
}
for (; ni < new->n; ni++) {
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni], type);
ovsdb_datum_add_unsafe(diff, &new->keys[ni], &new->values[ni],
type, NULL);
}
}
@ -2051,3 +2138,16 @@ ovsdb_token_is_delim(unsigned char c)
{
return strchr(":=, []{}!<>", c) != NULL;
}
struct ovsdb_error *
ovsdb_atom_range_check_size(int64_t range_start, int64_t range_end)
{
if ((uint64_t) range_end - (uint64_t) range_start
>= MAX_OVSDB_ATOM_RANGE_SIZE) {
return ovsdb_error("constraint violation",
"Range \"%"PRId64"-%"PRId64"\" is too big. "
"Maximum allowed size is %d.",
range_start, range_end, MAX_OVSDB_ATOM_RANGE_SIZE);
}
return NULL;
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2009, 2010, 2011, 2012, 2015, 2016 Nicira, Inc.
/* Copyright (c) 2009, 2010, 2011, 2012, 2015, 2016, 2017 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,8 @@
#include "ovsdb-types.h"
#include "openvswitch/shash.h"
#define MAX_OVSDB_ATOM_RANGE_SIZE 4096
struct ds;
struct ovsdb_symbol_table;
struct smap;
@ -89,7 +91,7 @@ struct ovsdb_error *ovsdb_atom_from_json(union ovsdb_atom *,
struct json *ovsdb_atom_to_json(const union ovsdb_atom *,
enum ovsdb_atomic_type);
char *ovsdb_atom_from_string(union ovsdb_atom *,
char *ovsdb_atom_from_string(union ovsdb_atom *, union ovsdb_atom **,
const struct ovsdb_base_type *, const char *,
struct ovsdb_symbol_table *)
OVS_WARN_UNUSED_RESULT;
@ -235,7 +237,8 @@ void ovsdb_datum_remove_unsafe(struct ovsdb_datum *, size_t idx,
void ovsdb_datum_add_unsafe(struct ovsdb_datum *,
const union ovsdb_atom *key,
const union ovsdb_atom *value,
const struct ovsdb_type *);
const struct ovsdb_type *,
const union ovsdb_atom *range_end_atom);
/* Type checking. */
static inline bool
@ -276,4 +279,7 @@ struct ovsdb_symbol *ovsdb_symbol_table_insert(struct ovsdb_symbol_table *,
char *ovsdb_token_parse(const char **, char **outp) OVS_WARN_UNUSED_RESULT;
bool ovsdb_token_is_delim(unsigned char);
struct ovsdb_error *ovsdb_atom_range_check_size(int64_t range_start,
int64_t range_end);
#endif /* ovsdb-data.h */

View File

@ -640,11 +640,22 @@ str_to_long(const char *s, int base, long *li)
bool
str_to_llong(const char *s, int base, long long *x)
{
int save_errno = errno;
char *tail;
bool ok = str_to_llong_with_tail(s, &tail, base, x);
if (*tail != '\0') {
*x = 0;
return false;
}
return ok;
}
bool
str_to_llong_with_tail(const char *s, char **tail, int base, long long *x)
{
int save_errno = errno;
errno = 0;
*x = strtoll(s, &tail, base);
if (errno == EINVAL || errno == ERANGE || tail == s || *tail != '\0') {
*x = strtoll(s, tail, base);
if (errno == EINVAL || errno == ERANGE || *tail == s) {
errno = save_errno;
*x = 0;
return false;
@ -668,6 +679,21 @@ str_to_uint(const char *s, int base, unsigned int *u)
}
}
bool
str_to_llong_range(const char *s, int base, long long *begin,
long long *end)
{
char *tail;
if (str_to_llong_with_tail(s, &tail, base, begin)
&& *tail == '-'
&& str_to_llong(tail + 1, base, end)) {
return true;
}
*begin = 0;
*end = 0;
return false;
}
/* Converts floating-point string 's' into a double. If successful, stores
* the double in '*d' and returns true; on failure, stores 0 in '*d' and
* returns false.

View File

@ -153,7 +153,9 @@ void ovs_hex_dump(FILE *, const void *, size_t, uintptr_t offset, bool ascii);
bool str_to_int(const char *, int base, int *);
bool str_to_long(const char *, int base, long *);
bool str_to_llong(const char *, int base, long long *);
bool str_to_llong_with_tail(const char *, char **, int base, long long *);
bool str_to_uint(const char *, int base, unsigned int *);
bool str_to_llong_range(const char *, int base, long long *, long long *);
bool ovs_scan(const char *s, const char *format, ...) OVS_SCANF_FORMAT(2, 3);
bool ovs_scan_len(const char *s, int *n, const char *format, ...);

View File

@ -860,7 +860,7 @@ AT_CHECK([RUN_OVS_VSCTL([remove bridge br0 name br1])],
[1], [], [ovs-vsctl: cannot modify read-only column name in table Bridge
], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([remove bridge br1 flood-vlans true])],
[1], [], [ovs-vsctl: "true" is not a valid integer
[1], [], [ovs-vsctl: "true" is not a valid integer or range
], [OVS_VSCTL_CLEANUP])
AT_CHECK([RUN_OVS_VSCTL([clear bridge br1 name])],
[1], [], [ovs-vsctl: cannot modify read-only column name in table Bridge

View File

@ -92,12 +92,26 @@ OVSDB_CHECK_POSITIVE([integer atom from string],
'-1' \
'+1000' \
'9223372036854775807' \
'-9223372036854775808' ]],
'-9223372036854775808' \
'0-1000' \
'-1000-+1000' \
'-1000--10' \
'+10-+1000' \
'1-4096' \
'-4096--1' \
'-2000-2095']],
[0
-1
1000
9223372036854775807
-9223372036854775808])
-9223372036854775808
0-1000
-1000-1000
-1000--10
10-1000
1-4096
-4096--1
-2000-2095])
OVSDB_CHECK_POSITIVE_CPY([real atom from JSON],
[[parse-atoms '["real"]' \
@ -258,6 +272,30 @@ OVSDB_CHECK_NEGATIVE([real not acceptable integer string atom],
[[parse-atom-strings '["integer"]' '0.5' ]],
["0.5" is not a valid integer])
OVSDB_CHECK_NEGATIVE([inverted range is not acceptable integer string atom positive and negative],
[[parse-atom-strings -- '["integer"]' '10--10' ]],
["10--10" is not a valid range. Range end cannot be before start.])
OVSDB_CHECK_NEGATIVE([inverted range is not acceptable integer string atom negative],
[[parse-atom-strings -- '["integer"]' '-10--100' ]],
["-10--100" is not a valid range. Range end cannot be before start.])
OVSDB_CHECK_NEGATIVE([inverted range is not acceptable integer string atom positive],
[[parse-atom-strings -- '["integer"]' '100-10' ]],
["100-10" is not a valid range. Range end cannot be before start.])
OVSDB_CHECK_NEGATIVE([too big range is not acceptable integer string atom positive and negative],
[[parse-atom-strings -- '["integer"]' '-2000-2096' ]],
[Range "-2000-2096" is too big.])
OVSDB_CHECK_NEGATIVE([too big range is not acceptable integer string atom negative],
[[parse-atom-strings -- '["integer"]' '-4097--1' ]],
[Range "-4097--1" is too big.])
OVSDB_CHECK_NEGATIVE([too big range is not acceptable integer string atom positive],
[[parse-atom-strings -- '["integer"]' '1-4097' ]],
[Range "1-4097" is too big.])
OVSDB_CHECK_POSITIVE_CPY([string "true" not acceptable boolean JSON atom],
[[parse-atoms '["boolean"]' '["true"]' ]],
[syntax ""true"": syntax error: expected boolean])
@ -323,6 +361,27 @@ constraint violation: 9 is not one of the allowed values ([1, 6, 8, 10])
10
constraint violation: 11 is not one of the allowed values ([1, 6, 8, 10])]])
OVSDB_CHECK_POSITIVE([integer atom enum from string],
[[parse-atom-strings '[{"type": "integer", "enum": ["set", [1, 6, 8, 10, 20, 21, 22, 23, 24, 25]]}]' \
'1' \
'6' \
'8' \
'10' \
'20-25']],
[[1
6
8
10
20-25]])
OVSDB_CHECK_NEGATIVE([integer not in enum set from string],
[[parse-atom-strings '[{"type": "integer", "enum": ["set", [1, 6, 8, 10]]}]' '0' ]],
[[constraint violation: 0 is not one of the allowed values ([1, 6, 8, 10])]])
OVSDB_CHECK_NEGATIVE([integer range not in enum set from string],
[[parse-atom-strings '[{"type": "integer", "enum": ["set", [1, 6, 8, 10]]}]' '8-10' ]],
[[constraint violation: 9 is not one of the allowed values ([1, 6, 8, 10])]])
OVSDB_CHECK_POSITIVE_CPY([real atom enum],
[[parse-atoms '[{"type": "real", "enum": ["set", [-1.5, 1.5]]}]' \
'[-2]' \
@ -590,12 +649,16 @@ OVSDB_CHECK_POSITIVE([string set of 0 or more integers],
'0, 1, 2' \
'[0, 1,2, 3, 4, 5]' \
'0, 1,2, 3,4, 5, 6, 7, 8' \
'[0, 1, 2, 3, 4,5, 6,7, 8, 9, 10]']],
'[0, 1, 2, 3, 4,5, 6,7, 8, 9, 10]' \
'0-8' \
'[0-10']]],
[[[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3, 4, 5]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]])
OVSDB_CHECK_POSITIVE_CPY([JSON set of 1 to 3 uuids],

View File

@ -554,17 +554,29 @@ do_parse_atom_strings(struct ovs_cmdl_context *ctx)
json_destroy(json);
for (i = 2; i < ctx->argc; i++) {
union ovsdb_atom atom;
union ovsdb_atom atom, *range_end_atom = NULL;
struct ds out;
die_if_error(ovsdb_atom_from_string(&atom, &base, ctx->argv[i], NULL));
die_if_error(ovsdb_atom_from_string(&atom, &range_end_atom, &base,
ctx->argv[i], NULL));
ds_init(&out);
ovsdb_atom_to_string(&atom, base.type, &out);
if (range_end_atom) {
struct ds range_end_ds;
ds_init(&range_end_ds);
ovsdb_atom_to_string(range_end_atom, base.type, &range_end_ds);
ds_put_char(&out, '-');
ds_put_cstr(&out, ds_cstr(&range_end_ds));;
ds_destroy(&range_end_ds);
}
puts(ds_cstr(&out));
ds_destroy(&out);
ovsdb_atom_destroy(&atom, base.type);
if (range_end_atom) {
ovsdb_atom_destroy(range_end_atom, base.type);
}
}
ovsdb_base_type_destroy(&base);
}