1 /* Copyright (c) 2009, 2010 Nicira Networks
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
18 #include "ovsdb-types.h"
23 #include "dynamic-string.h"
25 #include "ovsdb-data.h"
26 #include "ovsdb-error.h"
27 #include "ovsdb-parser.h"
29 const struct ovsdb_type ovsdb_type_integer
=
30 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_INTEGER_INIT
);
31 const struct ovsdb_type ovsdb_type_real
=
32 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_REAL_INIT
);
33 const struct ovsdb_type ovsdb_type_boolean
=
34 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_BOOLEAN_INIT
);
35 const struct ovsdb_type ovsdb_type_string
=
36 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_STRING_INIT
);
37 const struct ovsdb_type ovsdb_type_uuid
=
38 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_UUID_INIT
);
40 /* ovsdb_atomic_type */
42 ovsdb_atomic_type_to_string(enum ovsdb_atomic_type type
)
48 case OVSDB_TYPE_INTEGER
:
54 case OVSDB_TYPE_BOOLEAN
:
57 case OVSDB_TYPE_STRING
:
70 ovsdb_atomic_type_to_json(enum ovsdb_atomic_type type
)
72 return json_string_create(ovsdb_atomic_type_to_string(type
));
76 ovsdb_atomic_type_from_string(const char *string
, enum ovsdb_atomic_type
*type
)
78 if (!strcmp(string
, "integer")) {
79 *type
= OVSDB_TYPE_INTEGER
;
80 } else if (!strcmp(string
, "real")) {
81 *type
= OVSDB_TYPE_REAL
;
82 } else if (!strcmp(string
, "boolean")) {
83 *type
= OVSDB_TYPE_BOOLEAN
;
84 } else if (!strcmp(string
, "string")) {
85 *type
= OVSDB_TYPE_STRING
;
86 } else if (!strcmp(string
, "uuid")) {
87 *type
= OVSDB_TYPE_UUID
;
95 ovsdb_atomic_type_from_json(enum ovsdb_atomic_type
*type
,
96 const struct json
*json
)
98 if (json
->type
== JSON_STRING
) {
99 if (ovsdb_atomic_type_from_string(json_string(json
), type
)) {
102 *type
= OVSDB_TYPE_VOID
;
103 return ovsdb_syntax_error(json
, NULL
,
104 "\"%s\" is not an atomic-type",
108 *type
= OVSDB_TYPE_VOID
;
109 return ovsdb_syntax_error(json
, NULL
, "atomic-type expected");
113 /* ovsdb_base_type */
116 ovsdb_base_type_init(struct ovsdb_base_type
*base
, enum ovsdb_atomic_type type
)
121 switch (base
->type
) {
122 case OVSDB_TYPE_VOID
:
125 case OVSDB_TYPE_INTEGER
:
126 base
->u
.integer
.min
= INT64_MIN
;
127 base
->u
.integer
.max
= INT64_MAX
;
130 case OVSDB_TYPE_REAL
:
131 base
->u
.real
.min
= -DBL_MAX
;
132 base
->u
.real
.max
= DBL_MAX
;
135 case OVSDB_TYPE_BOOLEAN
:
138 case OVSDB_TYPE_STRING
:
139 base
->u
.string
.minLen
= 0;
140 base
->u
.string
.maxLen
= UINT_MAX
;
143 case OVSDB_TYPE_UUID
:
144 base
->u
.uuid
.refTableName
= NULL
;
145 base
->u
.uuid
.refTable
= NULL
;
156 /* Returns the type of the 'enum_' member for an ovsdb_base_type whose 'type'
157 * is 'atomic_type'. */
158 const struct ovsdb_type
*
159 ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type atomic_type
)
161 static struct ovsdb_type
*types
[OVSDB_N_TYPES
];
163 if (!types
[atomic_type
]) {
164 struct ovsdb_type
*type
;
166 types
[atomic_type
] = type
= xmalloc(sizeof *type
);
167 ovsdb_base_type_init(&type
->key
, atomic_type
);
168 ovsdb_base_type_init(&type
->value
, OVSDB_TYPE_VOID
);
170 type
->n_max
= UINT_MAX
;
172 return types
[atomic_type
];
176 ovsdb_base_type_clone(struct ovsdb_base_type
*dst
,
177 const struct ovsdb_base_type
*src
)
182 dst
->enum_
= xmalloc(sizeof *dst
->enum_
);
183 ovsdb_datum_clone(dst
->enum_
, src
->enum_
,
184 ovsdb_base_type_get_enum_type(dst
->type
));
188 case OVSDB_TYPE_VOID
:
189 case OVSDB_TYPE_INTEGER
:
190 case OVSDB_TYPE_REAL
:
191 case OVSDB_TYPE_BOOLEAN
:
194 case OVSDB_TYPE_STRING
:
197 case OVSDB_TYPE_UUID
:
198 if (dst
->u
.uuid
.refTableName
) {
199 dst
->u
.uuid
.refTableName
= xstrdup(dst
->u
.uuid
.refTableName
);
210 ovsdb_base_type_destroy(struct ovsdb_base_type
*base
)
214 ovsdb_datum_destroy(base
->enum_
,
215 ovsdb_base_type_get_enum_type(base
->type
));
219 switch (base
->type
) {
220 case OVSDB_TYPE_VOID
:
221 case OVSDB_TYPE_INTEGER
:
222 case OVSDB_TYPE_REAL
:
223 case OVSDB_TYPE_BOOLEAN
:
226 case OVSDB_TYPE_STRING
:
229 case OVSDB_TYPE_UUID
:
230 free(base
->u
.uuid
.refTableName
);
243 ovsdb_base_type_is_valid(const struct ovsdb_base_type
*base
)
245 switch (base
->type
) {
246 case OVSDB_TYPE_VOID
:
249 case OVSDB_TYPE_INTEGER
:
250 return base
->u
.integer
.min
<= base
->u
.integer
.max
;
252 case OVSDB_TYPE_REAL
:
253 return base
->u
.real
.min
<= base
->u
.real
.max
;
255 case OVSDB_TYPE_BOOLEAN
:
258 case OVSDB_TYPE_STRING
:
259 return base
->u
.string
.minLen
<= base
->u
.string
.maxLen
;
261 case OVSDB_TYPE_UUID
:
271 ovsdb_base_type_has_constraints(const struct ovsdb_base_type
*base
)
277 switch (base
->type
) {
278 case OVSDB_TYPE_VOID
:
281 case OVSDB_TYPE_INTEGER
:
282 return (base
->u
.integer
.min
!= INT64_MIN
283 || base
->u
.integer
.max
!= INT64_MAX
);
285 case OVSDB_TYPE_REAL
:
286 return (base
->u
.real
.min
!= -DBL_MAX
287 || base
->u
.real
.max
!= DBL_MAX
);
289 case OVSDB_TYPE_BOOLEAN
:
292 case OVSDB_TYPE_STRING
:
293 return base
->u
.string
.minLen
!= 0 || base
->u
.string
.maxLen
!= UINT_MAX
;
295 case OVSDB_TYPE_UUID
:
296 return base
->u
.uuid
.refTableName
!= NULL
;
307 ovsdb_base_type_clear_constraints(struct ovsdb_base_type
*base
)
309 enum ovsdb_atomic_type type
= base
->type
;
310 ovsdb_base_type_destroy(base
);
311 ovsdb_base_type_init(base
, type
);
314 static struct ovsdb_error
*
315 parse_optional_uint(struct ovsdb_parser
*parser
, const char *member
,
318 const struct json
*json
;
320 json
= ovsdb_parser_member(parser
, member
, OP_INTEGER
| OP_OPTIONAL
);
322 if (json
->u
.integer
< 0 || json
->u
.integer
> UINT_MAX
) {
323 return ovsdb_syntax_error(json
, NULL
,
324 "%s out of valid range 0 to %u",
327 *uint
= json
->u
.integer
;
333 ovsdb_base_type_from_json(struct ovsdb_base_type
*base
,
334 const struct json
*json
)
336 struct ovsdb_parser parser
;
337 struct ovsdb_error
*error
;
338 const struct json
*type
, *enum_
;
340 if (json
->type
== JSON_STRING
) {
341 error
= ovsdb_atomic_type_from_json(&base
->type
, json
);
345 ovsdb_base_type_init(base
, base
->type
);
349 ovsdb_parser_init(&parser
, json
, "ovsdb type");
350 type
= ovsdb_parser_member(&parser
, "type", OP_STRING
);
351 if (ovsdb_parser_has_error(&parser
)) {
352 base
->type
= OVSDB_TYPE_VOID
;
353 return ovsdb_parser_finish(&parser
);
356 error
= ovsdb_atomic_type_from_json(&base
->type
, type
);
361 ovsdb_base_type_init(base
, base
->type
);
363 enum_
= ovsdb_parser_member(&parser
, "enum", OP_ANY
| OP_OPTIONAL
);
365 base
->enum_
= xmalloc(sizeof *base
->enum_
);
366 error
= ovsdb_datum_from_json(
367 base
->enum_
, ovsdb_base_type_get_enum_type(base
->type
),
373 } else if (base
->type
== OVSDB_TYPE_INTEGER
) {
374 const struct json
*min
, *max
;
376 min
= ovsdb_parser_member(&parser
, "minInteger",
377 OP_INTEGER
| OP_OPTIONAL
);
378 max
= ovsdb_parser_member(&parser
, "maxInteger",
379 OP_INTEGER
| OP_OPTIONAL
);
380 base
->u
.integer
.min
= min
? min
->u
.integer
: INT64_MIN
;
381 base
->u
.integer
.max
= max
? max
->u
.integer
: INT64_MAX
;
382 if (base
->u
.integer
.min
> base
->u
.integer
.max
) {
383 error
= ovsdb_syntax_error(json
, NULL
,
384 "minInteger exceeds maxInteger");
386 } else if (base
->type
== OVSDB_TYPE_REAL
) {
387 const struct json
*min
, *max
;
389 min
= ovsdb_parser_member(&parser
, "minReal", OP_NUMBER
| OP_OPTIONAL
);
390 max
= ovsdb_parser_member(&parser
, "maxReal", OP_NUMBER
| OP_OPTIONAL
);
391 base
->u
.real
.min
= min
? json_real(min
) : -DBL_MAX
;
392 base
->u
.real
.max
= max
? json_real(max
) : DBL_MAX
;
393 if (base
->u
.real
.min
> base
->u
.real
.max
) {
394 error
= ovsdb_syntax_error(json
, NULL
, "minReal exceeds maxReal");
396 } else if (base
->type
== OVSDB_TYPE_STRING
) {
398 error
= parse_optional_uint(&parser
, "minLength",
399 &base
->u
.string
.minLen
);
402 error
= parse_optional_uint(&parser
, "maxLength",
403 &base
->u
.string
.maxLen
);
405 if (!error
&& base
->u
.string
.minLen
> base
->u
.string
.maxLen
) {
406 error
= ovsdb_syntax_error(json
, NULL
,
407 "minLength exceeds maxLength");
409 } else if (base
->type
== OVSDB_TYPE_UUID
) {
410 const struct json
*refTable
;
412 refTable
= ovsdb_parser_member(&parser
, "refTable",
413 OP_ID
| OP_OPTIONAL
);
415 base
->u
.uuid
.refTableName
= xstrdup(refTable
->u
.string
);
416 /* We can't set base->u.uuid.refTable here because we don't have
417 * enough context (we might not even be running in ovsdb-server).
418 * ovsdb_create() will set refTable later. */
423 ovsdb_error_destroy(ovsdb_parser_finish(&parser
));
425 error
= ovsdb_parser_finish(&parser
);
428 ovsdb_base_type_destroy(base
);
429 base
->type
= OVSDB_TYPE_VOID
;
435 ovsdb_base_type_to_json(const struct ovsdb_base_type
*base
)
439 if (!ovsdb_base_type_has_constraints(base
)) {
440 return json_string_create(ovsdb_atomic_type_to_string(base
->type
));
443 json
= json_object_create();
444 json_object_put_string(json
, "type",
445 ovsdb_atomic_type_to_string(base
->type
));
448 const struct ovsdb_type
*type
;
450 type
= ovsdb_base_type_get_enum_type(base
->type
);
451 json_object_put(json
, "enum", ovsdb_datum_to_json(base
->enum_
, type
));
454 switch (base
->type
) {
455 case OVSDB_TYPE_VOID
:
458 case OVSDB_TYPE_INTEGER
:
459 if (base
->u
.integer
.min
!= INT64_MIN
) {
460 json_object_put(json
, "minInteger",
461 json_integer_create(base
->u
.integer
.min
));
463 if (base
->u
.integer
.max
!= INT64_MAX
) {
464 json_object_put(json
, "maxInteger",
465 json_integer_create(base
->u
.integer
.max
));
469 case OVSDB_TYPE_REAL
:
470 if (base
->u
.real
.min
!= -DBL_MAX
) {
471 json_object_put(json
, "minReal",
472 json_real_create(base
->u
.real
.min
));
474 if (base
->u
.real
.max
!= DBL_MAX
) {
475 json_object_put(json
, "maxReal",
476 json_real_create(base
->u
.real
.max
));
480 case OVSDB_TYPE_BOOLEAN
:
483 case OVSDB_TYPE_STRING
:
484 if (base
->u
.string
.minLen
!= 0) {
485 json_object_put(json
, "minLength",
486 json_integer_create(base
->u
.string
.minLen
));
488 if (base
->u
.string
.maxLen
!= UINT_MAX
) {
489 json_object_put(json
, "maxLength",
490 json_integer_create(base
->u
.string
.maxLen
));
494 case OVSDB_TYPE_UUID
:
495 if (base
->u
.uuid
.refTableName
) {
496 json_object_put_string(json
, "refTable",
497 base
->u
.uuid
.refTableName
);
514 ovsdb_type_clone(struct ovsdb_type
*dst
, const struct ovsdb_type
*src
)
516 ovsdb_base_type_clone(&dst
->key
, &src
->key
);
517 ovsdb_base_type_clone(&dst
->value
, &src
->value
);
518 dst
->n_min
= src
->n_min
;
519 dst
->n_max
= src
->n_max
;
523 ovsdb_type_destroy(struct ovsdb_type
*type
)
525 ovsdb_base_type_destroy(&type
->key
);
526 ovsdb_base_type_destroy(&type
->value
);
530 ovsdb_type_is_valid(const struct ovsdb_type
*type
)
532 return (type
->key
.type
!= OVSDB_TYPE_VOID
533 && ovsdb_base_type_is_valid(&type
->key
)
534 && ovsdb_base_type_is_valid(&type
->value
)
536 && type
->n_min
<= type
->n_max
537 && type
->n_max
>= 1);
540 static struct ovsdb_error
*
541 n_from_json(const struct json
*json
, unsigned int *n
)
545 } else if (json
->type
== JSON_INTEGER
546 && json
->u
.integer
>= 0 && json
->u
.integer
< UINT_MAX
) {
547 *n
= json
->u
.integer
;
550 return ovsdb_syntax_error(json
, NULL
, "bad min or max value");
555 ovsdb_type_to_english(const struct ovsdb_type
*type
)
557 const char *key
= ovsdb_atomic_type_to_string(type
->key
.type
);
558 const char *value
= ovsdb_atomic_type_to_string(type
->value
.type
);
559 if (ovsdb_type_is_scalar(type
)) {
562 struct ds s
= DS_EMPTY_INITIALIZER
;
563 ds_put_cstr(&s
, ovsdb_type_is_set(type
) ? "set" : "map");
564 if (type
->n_max
== UINT_MAX
) {
566 ds_put_format(&s
, " of %u or more", type
->n_min
);
568 ds_put_cstr(&s
, " of");
570 } else if (type
->n_min
) {
571 ds_put_format(&s
, " of %u to %u", type
->n_min
, type
->n_max
);
573 ds_put_format(&s
, " of up to %u", type
->n_max
);
575 if (ovsdb_type_is_set(type
)) {
576 ds_put_format(&s
, " %ss", key
);
578 ds_put_format(&s
, " (%s, %s) pairs", key
, value
);
585 ovsdb_type_from_json(struct ovsdb_type
*type
, const struct json
*json
)
587 ovsdb_base_type_init(&type
->value
, OVSDB_TYPE_VOID
);
591 if (json
->type
== JSON_STRING
) {
592 return ovsdb_base_type_from_json(&type
->key
, json
);
593 } else if (json
->type
== JSON_OBJECT
) {
594 const struct json
*key
, *value
, *min
, *max
;
595 struct ovsdb_error
*error
;
596 struct ovsdb_parser parser
;
598 ovsdb_parser_init(&parser
, json
, "ovsdb type");
599 key
= ovsdb_parser_member(&parser
, "key", OP_STRING
| OP_OBJECT
);
600 value
= ovsdb_parser_member(&parser
, "value",
601 OP_STRING
| OP_OBJECT
| OP_OPTIONAL
);
602 min
= ovsdb_parser_member(&parser
, "min", OP_INTEGER
| OP_OPTIONAL
);
603 max
= ovsdb_parser_member(&parser
, "max",
604 OP_INTEGER
| OP_STRING
| OP_OPTIONAL
);
605 error
= ovsdb_parser_finish(&parser
);
610 error
= ovsdb_base_type_from_json(&type
->key
, key
);
616 error
= ovsdb_base_type_from_json(&type
->value
, value
);
622 error
= n_from_json(min
, &type
->n_min
);
627 if (max
&& max
->type
== JSON_STRING
628 && !strcmp(max
->u
.string
, "unlimited")) {
629 type
->n_max
= UINT_MAX
;
631 error
= n_from_json(max
, &type
->n_max
);
637 if (!ovsdb_type_is_valid(type
)) {
638 return ovsdb_syntax_error(json
, NULL
,
639 "ovsdb type fails constraint checks");
644 return ovsdb_syntax_error(json
, NULL
, "ovsdb type expected");
649 ovsdb_type_to_json(const struct ovsdb_type
*type
)
651 if (ovsdb_type_is_scalar(type
)
652 && !ovsdb_base_type_has_constraints(&type
->key
)) {
653 return ovsdb_base_type_to_json(&type
->key
);
655 struct json
*json
= json_object_create();
656 json_object_put(json
, "key", ovsdb_base_type_to_json(&type
->key
));
657 if (type
->value
.type
!= OVSDB_TYPE_VOID
) {
658 json_object_put(json
, "value",
659 ovsdb_base_type_to_json(&type
->value
));
661 if (type
->n_min
!= 1) {
662 json_object_put(json
, "min", json_integer_create(type
->n_min
));
664 if (type
->n_max
== UINT_MAX
) {
665 json_object_put_string(json
, "max", "unlimited");
666 } else if (type
->n_max
!= 1) {
667 json_object_put(json
, "max", json_integer_create(type
->n_max
));