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:
parent
84d0ca5d00
commit
1ab39058cc
@ -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
3
NEWS
@ -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
|
||||
---------------------
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
198
lib/ovsdb-data.c
198
lib/ovsdb-data.c
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
32
lib/util.c
32
lib/util.c
@ -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.
|
||||
|
@ -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, ...);
|
||||
|
@ -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
|
||||
|
@ -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],
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user