1 /* Copyright (c) 2009, 2010, 2011, 2013 Nicira, Inc.
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 "openvswitch/dynamic-string.h"
24 #include "openvswitch/json.h"
25 #include "ovs-thread.h"
26 #include "ovsdb-data.h"
27 #include "ovsdb-error.h"
28 #include "ovsdb-parser.h"
31 const struct ovsdb_type ovsdb_type_integer
=
32 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_INTEGER_INIT
);
33 const struct ovsdb_type ovsdb_type_real
=
34 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_REAL_INIT
);
35 const struct ovsdb_type ovsdb_type_boolean
=
36 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_BOOLEAN_INIT
);
37 const struct ovsdb_type ovsdb_type_string
=
38 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_STRING_INIT
);
39 const struct ovsdb_type ovsdb_type_uuid
=
40 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_UUID_INIT
);
42 /* ovsdb_atomic_type */
44 ovsdb_atomic_type_to_string(enum ovsdb_atomic_type type
)
50 case OVSDB_TYPE_INTEGER
:
56 case OVSDB_TYPE_BOOLEAN
:
59 case OVSDB_TYPE_STRING
:
72 ovsdb_atomic_type_to_json(enum ovsdb_atomic_type type
)
74 return json_string_create(ovsdb_atomic_type_to_string(type
));
78 ovsdb_atomic_type_from_string(const char *string
, enum ovsdb_atomic_type
*type
)
80 if (!strcmp(string
, "integer")) {
81 *type
= OVSDB_TYPE_INTEGER
;
82 } else if (!strcmp(string
, "real")) {
83 *type
= OVSDB_TYPE_REAL
;
84 } else if (!strcmp(string
, "boolean")) {
85 *type
= OVSDB_TYPE_BOOLEAN
;
86 } else if (!strcmp(string
, "string")) {
87 *type
= OVSDB_TYPE_STRING
;
88 } else if (!strcmp(string
, "uuid")) {
89 *type
= OVSDB_TYPE_UUID
;
97 ovsdb_atomic_type_from_json(enum ovsdb_atomic_type
*type
,
98 const struct json
*json
)
100 if (json
->type
== JSON_STRING
) {
101 if (ovsdb_atomic_type_from_string(json_string(json
), type
)) {
104 *type
= OVSDB_TYPE_VOID
;
105 return ovsdb_syntax_error(json
, NULL
,
106 "\"%s\" is not an atomic-type",
110 *type
= OVSDB_TYPE_VOID
;
111 return ovsdb_syntax_error(json
, NULL
, "atomic-type expected");
115 /* ovsdb_base_type */
118 ovsdb_base_type_init(struct ovsdb_base_type
*base
, enum ovsdb_atomic_type type
)
123 switch (base
->type
) {
124 case OVSDB_TYPE_VOID
:
127 case OVSDB_TYPE_INTEGER
:
128 base
->integer
.min
= INT64_MIN
;
129 base
->integer
.max
= INT64_MAX
;
132 case OVSDB_TYPE_REAL
:
133 base
->real
.min
= -DBL_MAX
;
134 base
->real
.max
= DBL_MAX
;
137 case OVSDB_TYPE_BOOLEAN
:
140 case OVSDB_TYPE_STRING
:
141 base
->string
.minLen
= 0;
142 base
->string
.maxLen
= UINT_MAX
;
145 case OVSDB_TYPE_UUID
:
146 base
->uuid
.refTableName
= NULL
;
147 base
->uuid
.refTable
= NULL
;
158 /* Returns the type of the 'enum_' member for an ovsdb_base_type whose 'type'
159 * is 'atomic_type'. */
160 const struct ovsdb_type
*
161 ovsdb_base_type_get_enum_type(enum ovsdb_atomic_type atomic_type
)
163 static struct ovsthread_once once
= OVSTHREAD_ONCE_INITIALIZER
;
164 static struct ovsdb_type
*types
[OVSDB_N_TYPES
];
166 if (ovsthread_once_start(&once
)) {
167 enum ovsdb_atomic_type i
;
169 for (i
= 0; i
< OVSDB_N_TYPES
; i
++) {
170 struct ovsdb_type
*type
;
172 types
[i
] = type
= xmalloc(sizeof *type
);
173 ovsdb_base_type_init(&type
->key
, i
);
174 ovsdb_base_type_init(&type
->value
, OVSDB_TYPE_VOID
);
176 type
->n_max
= UINT_MAX
;
179 ovsthread_once_done(&once
);
181 return types
[atomic_type
];
185 ovsdb_base_type_clone(struct ovsdb_base_type
*dst
,
186 const struct ovsdb_base_type
*src
)
191 dst
->enum_
= xmalloc(sizeof *dst
->enum_
);
192 ovsdb_datum_clone(dst
->enum_
, src
->enum_
,
193 ovsdb_base_type_get_enum_type(dst
->type
));
197 case OVSDB_TYPE_VOID
:
198 case OVSDB_TYPE_INTEGER
:
199 case OVSDB_TYPE_REAL
:
200 case OVSDB_TYPE_BOOLEAN
:
203 case OVSDB_TYPE_STRING
:
206 case OVSDB_TYPE_UUID
:
207 if (dst
->uuid
.refTableName
) {
208 dst
->uuid
.refTableName
= xstrdup(dst
->uuid
.refTableName
);
219 ovsdb_base_type_destroy(struct ovsdb_base_type
*base
)
223 ovsdb_datum_destroy(base
->enum_
,
224 ovsdb_base_type_get_enum_type(base
->type
));
228 switch (base
->type
) {
229 case OVSDB_TYPE_VOID
:
230 case OVSDB_TYPE_INTEGER
:
231 case OVSDB_TYPE_REAL
:
232 case OVSDB_TYPE_BOOLEAN
:
235 case OVSDB_TYPE_STRING
:
238 case OVSDB_TYPE_UUID
:
239 free(base
->uuid
.refTableName
);
252 ovsdb_base_type_is_valid(const struct ovsdb_base_type
*base
)
254 switch (base
->type
) {
255 case OVSDB_TYPE_VOID
:
258 case OVSDB_TYPE_INTEGER
:
259 return base
->integer
.min
<= base
->integer
.max
;
261 case OVSDB_TYPE_REAL
:
262 return base
->real
.min
<= base
->real
.max
;
264 case OVSDB_TYPE_BOOLEAN
:
267 case OVSDB_TYPE_STRING
:
268 return base
->string
.minLen
<= base
->string
.maxLen
;
270 case OVSDB_TYPE_UUID
:
280 ovsdb_base_type_has_constraints(const struct ovsdb_base_type
*base
)
286 switch (base
->type
) {
287 case OVSDB_TYPE_VOID
:
290 case OVSDB_TYPE_INTEGER
:
291 return (base
->integer
.min
!= INT64_MIN
292 || base
->integer
.max
!= INT64_MAX
);
294 case OVSDB_TYPE_REAL
:
295 return (base
->real
.min
!= -DBL_MAX
296 || base
->real
.max
!= DBL_MAX
);
298 case OVSDB_TYPE_BOOLEAN
:
301 case OVSDB_TYPE_STRING
:
302 return base
->string
.minLen
!= 0 || base
->string
.maxLen
!= UINT_MAX
;
304 case OVSDB_TYPE_UUID
:
305 return base
->uuid
.refTableName
!= NULL
;
316 ovsdb_base_type_clear_constraints(struct ovsdb_base_type
*base
)
318 enum ovsdb_atomic_type type
= base
->type
;
319 ovsdb_base_type_destroy(base
);
320 ovsdb_base_type_init(base
, type
);
323 static struct ovsdb_error
*
324 parse_optional_uint(struct ovsdb_parser
*parser
, const char *member
,
327 const struct json
*json
;
329 json
= ovsdb_parser_member(parser
, member
, OP_INTEGER
| OP_OPTIONAL
);
331 if (json
->integer
< 0 || json
->integer
> UINT_MAX
) {
332 return ovsdb_syntax_error(json
, NULL
,
333 "%s out of valid range 0 to %u",
336 *uint
= json
->integer
;
342 ovsdb_base_type_from_json(struct ovsdb_base_type
*base
,
343 const struct json
*json
)
345 struct ovsdb_parser parser
;
346 struct ovsdb_error
*error
;
347 const struct json
*type
, *enum_
;
349 if (json
->type
== JSON_STRING
) {
350 error
= ovsdb_atomic_type_from_json(&base
->type
, json
);
354 ovsdb_base_type_init(base
, base
->type
);
358 ovsdb_parser_init(&parser
, json
, "ovsdb type");
359 type
= ovsdb_parser_member(&parser
, "type", OP_STRING
);
360 if (ovsdb_parser_has_error(&parser
)) {
361 base
->type
= OVSDB_TYPE_VOID
;
362 return ovsdb_parser_finish(&parser
);
365 error
= ovsdb_atomic_type_from_json(&base
->type
, type
);
367 ovsdb_error_destroy(ovsdb_parser_destroy(&parser
));
371 ovsdb_base_type_init(base
, base
->type
);
373 enum_
= ovsdb_parser_member(&parser
, "enum", OP_ANY
| OP_OPTIONAL
);
375 base
->enum_
= xmalloc(sizeof *base
->enum_
);
376 error
= ovsdb_datum_from_json(
377 base
->enum_
, ovsdb_base_type_get_enum_type(base
->type
),
383 } else if (base
->type
== OVSDB_TYPE_INTEGER
) {
384 const struct json
*min
, *max
;
386 min
= ovsdb_parser_member(&parser
, "minInteger",
387 OP_INTEGER
| OP_OPTIONAL
);
388 max
= ovsdb_parser_member(&parser
, "maxInteger",
389 OP_INTEGER
| OP_OPTIONAL
);
390 base
->integer
.min
= min
? min
->integer
: INT64_MIN
;
391 base
->integer
.max
= max
? max
->integer
: INT64_MAX
;
392 if (base
->integer
.min
> base
->integer
.max
) {
393 error
= ovsdb_syntax_error(json
, NULL
,
394 "minInteger exceeds maxInteger");
396 } else if (base
->type
== OVSDB_TYPE_REAL
) {
397 const struct json
*min
, *max
;
399 min
= ovsdb_parser_member(&parser
, "minReal", OP_NUMBER
| OP_OPTIONAL
);
400 max
= ovsdb_parser_member(&parser
, "maxReal", OP_NUMBER
| OP_OPTIONAL
);
401 base
->real
.min
= min
? json_real(min
) : -DBL_MAX
;
402 base
->real
.max
= max
? json_real(max
) : DBL_MAX
;
403 if (base
->real
.min
> base
->real
.max
) {
404 error
= ovsdb_syntax_error(json
, NULL
, "minReal exceeds maxReal");
406 } else if (base
->type
== OVSDB_TYPE_STRING
) {
408 error
= parse_optional_uint(&parser
, "minLength",
409 &base
->string
.minLen
);
412 error
= parse_optional_uint(&parser
, "maxLength",
413 &base
->string
.maxLen
);
415 if (!error
&& base
->string
.minLen
> base
->string
.maxLen
) {
416 error
= ovsdb_syntax_error(json
, NULL
,
417 "minLength exceeds maxLength");
419 } else if (base
->type
== OVSDB_TYPE_UUID
) {
420 const struct json
*refTable
;
422 refTable
= ovsdb_parser_member(&parser
, "refTable",
423 OP_ID
| OP_OPTIONAL
);
425 const struct json
*refType
;
427 base
->uuid
.refTableName
= xstrdup(refTable
->string
);
429 /* We can't set base->uuid.refTable here because we don't have
430 * enough context (we might not even be running in ovsdb-server).
431 * ovsdb_create() will set refTable later. */
433 refType
= ovsdb_parser_member(&parser
, "refType",
434 OP_ID
| OP_OPTIONAL
);
436 const char *refType_s
= json_string(refType
);
437 if (!strcmp(refType_s
, "strong")) {
438 base
->uuid
.refType
= OVSDB_REF_STRONG
;
439 } else if (!strcmp(refType_s
, "weak")) {
440 base
->uuid
.refType
= OVSDB_REF_WEAK
;
442 error
= ovsdb_syntax_error(json
, NULL
, "refType must be "
443 "\"strong\" or \"weak\" (not "
444 "\"%s\")", refType_s
);
447 base
->uuid
.refType
= OVSDB_REF_STRONG
;
453 ovsdb_error_destroy(ovsdb_parser_finish(&parser
));
455 error
= ovsdb_parser_finish(&parser
);
458 ovsdb_base_type_destroy(base
);
459 base
->type
= OVSDB_TYPE_VOID
;
465 ovsdb_base_type_to_json(const struct ovsdb_base_type
*base
)
469 if (!ovsdb_base_type_has_constraints(base
)) {
470 return json_string_create(ovsdb_atomic_type_to_string(base
->type
));
473 json
= json_object_create();
474 json_object_put_string(json
, "type",
475 ovsdb_atomic_type_to_string(base
->type
));
478 const struct ovsdb_type
*type
;
480 type
= ovsdb_base_type_get_enum_type(base
->type
);
481 json_object_put(json
, "enum", ovsdb_datum_to_json(base
->enum_
, type
));
484 switch (base
->type
) {
485 case OVSDB_TYPE_VOID
:
488 case OVSDB_TYPE_INTEGER
:
489 if (base
->integer
.min
!= INT64_MIN
) {
490 json_object_put(json
, "minInteger",
491 json_integer_create(base
->integer
.min
));
493 if (base
->integer
.max
!= INT64_MAX
) {
494 json_object_put(json
, "maxInteger",
495 json_integer_create(base
->integer
.max
));
499 case OVSDB_TYPE_REAL
:
500 if (base
->real
.min
!= -DBL_MAX
) {
501 json_object_put(json
, "minReal",
502 json_real_create(base
->real
.min
));
504 if (base
->real
.max
!= DBL_MAX
) {
505 json_object_put(json
, "maxReal",
506 json_real_create(base
->real
.max
));
510 case OVSDB_TYPE_BOOLEAN
:
513 case OVSDB_TYPE_STRING
:
514 if (base
->string
.minLen
!= 0) {
515 json_object_put(json
, "minLength",
516 json_integer_create(base
->string
.minLen
));
518 if (base
->string
.maxLen
!= UINT_MAX
) {
519 json_object_put(json
, "maxLength",
520 json_integer_create(base
->string
.maxLen
));
524 case OVSDB_TYPE_UUID
:
525 if (base
->uuid
.refTableName
) {
526 json_object_put_string(json
, "refTable",
527 base
->uuid
.refTableName
);
528 if (base
->uuid
.refType
== OVSDB_REF_WEAK
) {
529 json_object_put_string(json
, "refType", "weak");
547 ovsdb_type_clone(struct ovsdb_type
*dst
, const struct ovsdb_type
*src
)
549 ovsdb_base_type_clone(&dst
->key
, &src
->key
);
550 ovsdb_base_type_clone(&dst
->value
, &src
->value
);
551 dst
->n_min
= src
->n_min
;
552 dst
->n_max
= src
->n_max
;
556 ovsdb_type_destroy(struct ovsdb_type
*type
)
558 ovsdb_base_type_destroy(&type
->key
);
559 ovsdb_base_type_destroy(&type
->value
);
563 ovsdb_type_is_valid(const struct ovsdb_type
*type
)
565 return (type
->key
.type
!= OVSDB_TYPE_VOID
566 && ovsdb_base_type_is_valid(&type
->key
)
567 && ovsdb_base_type_is_valid(&type
->value
)
569 && type
->n_max
>= 1);
572 static struct ovsdb_error
*
573 n_from_json(const struct json
*json
, unsigned int *n
)
577 } else if (json
->type
== JSON_INTEGER
578 && json
->integer
>= 0 && json
->integer
< UINT_MAX
) {
582 return ovsdb_syntax_error(json
, NULL
, "bad min or max value");
587 ovsdb_type_to_english(const struct ovsdb_type
*type
)
589 const char *key
= ovsdb_atomic_type_to_string(type
->key
.type
);
590 const char *value
= ovsdb_atomic_type_to_string(type
->value
.type
);
591 if (ovsdb_type_is_scalar(type
)) {
594 struct ds s
= DS_EMPTY_INITIALIZER
;
595 ds_put_cstr(&s
, ovsdb_type_is_set(type
) ? "set" : "map");
596 if (type
->n_max
== UINT_MAX
) {
598 ds_put_format(&s
, " of %u or more", type
->n_min
);
600 ds_put_cstr(&s
, " of");
602 } else if (type
->n_min
) {
603 ds_put_format(&s
, " of %u to %u", type
->n_min
, type
->n_max
);
605 ds_put_format(&s
, " of up to %u", type
->n_max
);
607 if (ovsdb_type_is_set(type
)) {
608 ds_put_format(&s
, " %ss", key
);
610 ds_put_format(&s
, " (%s, %s) pairs", key
, value
);
617 ovsdb_type_from_json(struct ovsdb_type
*type
, const struct json
*json
)
619 ovsdb_base_type_init(&type
->value
, OVSDB_TYPE_VOID
);
623 if (json
->type
== JSON_STRING
) {
624 return ovsdb_base_type_from_json(&type
->key
, json
);
625 } else if (json
->type
== JSON_OBJECT
) {
626 const struct json
*key
, *value
, *min
, *max
;
627 struct ovsdb_error
*error
;
628 struct ovsdb_parser parser
;
630 ovsdb_parser_init(&parser
, json
, "ovsdb type");
631 key
= ovsdb_parser_member(&parser
, "key", OP_STRING
| OP_OBJECT
);
632 value
= ovsdb_parser_member(&parser
, "value",
633 OP_STRING
| OP_OBJECT
| OP_OPTIONAL
);
634 min
= ovsdb_parser_member(&parser
, "min", OP_INTEGER
| OP_OPTIONAL
);
635 max
= ovsdb_parser_member(&parser
, "max",
636 OP_INTEGER
| OP_STRING
| OP_OPTIONAL
);
637 error
= ovsdb_parser_finish(&parser
);
642 error
= ovsdb_base_type_from_json(&type
->key
, key
);
648 error
= ovsdb_base_type_from_json(&type
->value
, value
);
654 error
= n_from_json(min
, &type
->n_min
);
659 if (max
&& max
->type
== JSON_STRING
660 && !strcmp(max
->string
, "unlimited")) {
661 type
->n_max
= UINT_MAX
;
663 error
= n_from_json(max
, &type
->n_max
);
669 if (!ovsdb_type_is_valid(type
)) {
670 return ovsdb_syntax_error(json
, NULL
,
671 "ovsdb type fails constraint checks");
676 return ovsdb_syntax_error(json
, NULL
, "ovsdb type expected");
681 ovsdb_type_to_json(const struct ovsdb_type
*type
)
683 if (ovsdb_type_is_scalar(type
)
684 && !ovsdb_base_type_has_constraints(&type
->key
)) {
685 return ovsdb_base_type_to_json(&type
->key
);
687 struct json
*json
= json_object_create();
688 json_object_put(json
, "key", ovsdb_base_type_to_json(&type
->key
));
689 if (type
->value
.type
!= OVSDB_TYPE_VOID
) {
690 json_object_put(json
, "value",
691 ovsdb_base_type_to_json(&type
->value
));
693 if (type
->n_min
!= 1) {
694 json_object_put(json
, "min", json_integer_create(type
->n_min
));
696 if (type
->n_max
== UINT_MAX
) {
697 json_object_put_string(json
, "max", "unlimited");
698 } else if (type
->n_max
!= 1) {
699 json_object_put(json
, "max", json_integer_create(type
->n_max
));