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-error.h"
26 #include "ovsdb-parser.h"
28 const struct ovsdb_type ovsdb_type_integer
=
29 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_INTEGER_INIT
);
30 const struct ovsdb_type ovsdb_type_real
=
31 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_REAL_INIT
);
32 const struct ovsdb_type ovsdb_type_boolean
=
33 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_BOOLEAN_INIT
);
34 const struct ovsdb_type ovsdb_type_string
=
35 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_STRING_INIT
);
36 const struct ovsdb_type ovsdb_type_uuid
=
37 OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_UUID_INIT
);
39 /* ovsdb_atomic_type */
41 ovsdb_atomic_type_to_string(enum ovsdb_atomic_type type
)
47 case OVSDB_TYPE_INTEGER
:
53 case OVSDB_TYPE_BOOLEAN
:
56 case OVSDB_TYPE_STRING
:
69 ovsdb_atomic_type_to_json(enum ovsdb_atomic_type type
)
71 return json_string_create(ovsdb_atomic_type_to_string(type
));
75 ovsdb_atomic_type_from_string(const char *string
, enum ovsdb_atomic_type
*type
)
77 if (!strcmp(string
, "integer")) {
78 *type
= OVSDB_TYPE_INTEGER
;
79 } else if (!strcmp(string
, "real")) {
80 *type
= OVSDB_TYPE_REAL
;
81 } else if (!strcmp(string
, "boolean")) {
82 *type
= OVSDB_TYPE_BOOLEAN
;
83 } else if (!strcmp(string
, "string")) {
84 *type
= OVSDB_TYPE_STRING
;
85 } else if (!strcmp(string
, "uuid")) {
86 *type
= OVSDB_TYPE_UUID
;
94 ovsdb_atomic_type_from_json(enum ovsdb_atomic_type
*type
,
95 const struct json
*json
)
97 if (json
->type
== JSON_STRING
) {
98 if (ovsdb_atomic_type_from_string(json_string(json
), type
)) {
101 *type
= OVSDB_TYPE_VOID
;
102 return ovsdb_syntax_error(json
, NULL
,
103 "\"%s\" is not an atomic-type",
107 *type
= OVSDB_TYPE_VOID
;
108 return ovsdb_syntax_error(json
, NULL
, "atomic-type expected");
112 /* ovsdb_base_type */
115 ovsdb_base_type_init(struct ovsdb_base_type
*base
, enum ovsdb_atomic_type type
)
119 switch (base
->type
) {
120 case OVSDB_TYPE_VOID
:
123 case OVSDB_TYPE_INTEGER
:
124 base
->u
.integer
.min
= INT64_MIN
;
125 base
->u
.integer
.max
= INT64_MAX
;
128 case OVSDB_TYPE_REAL
:
129 base
->u
.real
.min
= -DBL_MAX
;
130 base
->u
.real
.max
= DBL_MAX
;
133 case OVSDB_TYPE_BOOLEAN
:
136 case OVSDB_TYPE_STRING
:
138 base
->u
.string
.re
= NULL
;
140 base
->u
.string
.reMatch
= NULL
;
141 base
->u
.string
.reComment
= NULL
;
142 base
->u
.string
.minLen
= 0;
143 base
->u
.string
.maxLen
= UINT_MAX
;
146 case OVSDB_TYPE_UUID
:
147 base
->u
.uuid
.refTableName
= NULL
;
148 base
->u
.uuid
.refTable
= NULL
;
160 ovsdb_base_type_clone(struct ovsdb_base_type
*dst
,
161 const struct ovsdb_base_type
*src
)
166 case OVSDB_TYPE_VOID
:
167 case OVSDB_TYPE_INTEGER
:
168 case OVSDB_TYPE_REAL
:
169 case OVSDB_TYPE_BOOLEAN
:
172 case OVSDB_TYPE_STRING
:
174 if (dst
->u
.string
.re
) {
175 pcre_refcount(dst
->u
.string
.re
, 1);
178 if (dst
->u
.string
.reMatch
) {
179 dst
->u
.string
.reMatch
= xstrdup(dst
->u
.string
.reMatch
);
181 if (dst
->u
.string
.reComment
) {
182 dst
->u
.string
.reComment
= xstrdup(dst
->u
.string
.reComment
);
188 case OVSDB_TYPE_UUID
:
189 if (dst
->u
.uuid
.refTableName
) {
190 dst
->u
.uuid
.refTableName
= xstrdup(dst
->u
.uuid
.refTableName
);
201 ovsdb_base_type_destroy(struct ovsdb_base_type
*base
)
204 switch (base
->type
) {
205 case OVSDB_TYPE_VOID
:
206 case OVSDB_TYPE_INTEGER
:
207 case OVSDB_TYPE_REAL
:
208 case OVSDB_TYPE_BOOLEAN
:
211 case OVSDB_TYPE_STRING
:
213 if (base
->u
.string
.re
&& !pcre_refcount(base
->u
.string
.re
, -1)) {
214 pcre_free(base
->u
.string
.re
);
215 free(base
->u
.string
.reMatch
);
216 free(base
->u
.string
.reComment
);
219 free(base
->u
.string
.reMatch
);
220 free(base
->u
.string
.reComment
);
224 case OVSDB_TYPE_UUID
:
225 free(base
->u
.uuid
.refTableName
);
238 ovsdb_base_type_is_valid(const struct ovsdb_base_type
*base
)
240 switch (base
->type
) {
241 case OVSDB_TYPE_VOID
:
244 case OVSDB_TYPE_INTEGER
:
245 return base
->u
.integer
.min
<= base
->u
.integer
.max
;
247 case OVSDB_TYPE_REAL
:
248 return base
->u
.real
.min
<= base
->u
.real
.max
;
250 case OVSDB_TYPE_BOOLEAN
:
253 case OVSDB_TYPE_STRING
:
254 return base
->u
.string
.minLen
<= base
->u
.string
.maxLen
;
256 case OVSDB_TYPE_UUID
:
266 ovsdb_base_type_has_constraints(const struct ovsdb_base_type
*base
)
268 switch (base
->type
) {
269 case OVSDB_TYPE_VOID
:
272 case OVSDB_TYPE_INTEGER
:
273 return (base
->u
.integer
.min
!= INT64_MIN
274 || base
->u
.integer
.max
!= INT64_MAX
);
276 case OVSDB_TYPE_REAL
:
277 return (base
->u
.real
.min
!= -DBL_MAX
278 || base
->u
.real
.max
!= DBL_MAX
);
280 case OVSDB_TYPE_BOOLEAN
:
283 case OVSDB_TYPE_STRING
:
284 return (base
->u
.string
.reMatch
!= NULL
285 || base
->u
.string
.minLen
!= 0
286 || base
->u
.string
.maxLen
!= UINT_MAX
);
288 case OVSDB_TYPE_UUID
:
289 return base
->u
.uuid
.refTableName
!= NULL
;
300 ovsdb_base_type_clear_constraints(struct ovsdb_base_type
*base
)
302 enum ovsdb_atomic_type type
= base
->type
;
303 ovsdb_base_type_destroy(base
);
304 ovsdb_base_type_init(base
, type
);
308 ovsdb_base_type_set_regex(struct ovsdb_base_type
*base
,
309 const char *reMatch
, const char *reComment
)
312 const char *errorString
;
316 /* Compile pattern, anchoring it at both ends. */
318 if (pattern
[0] == '\0' || strchr(pattern
, '\0')[-1] != '$') {
319 pattern
= xasprintf("%s$", pattern
);
322 #ifndef PCRE_JAVASCRIPT_COMPAT /* Added in PCRE 7.7. */
323 #define PCRE_JAVASCRIPT_COMPAT 0
325 base
->u
.string
.re
= pcre_compile(pattern
, (PCRE_ANCHORED
| PCRE_UTF8
326 | PCRE_JAVASCRIPT_COMPAT
),
327 &errorString
, &errorOffset
, NULL
);
328 if (pattern
!= reMatch
) {
329 free((char *) pattern
);
331 if (!base
->u
.string
.re
) {
332 return ovsdb_syntax_error(NULL
, "invalid regular expression",
333 "\"%s\" is not a valid regular "
334 "expression: %s", reMatch
, errorString
);
336 pcre_refcount(base
->u
.string
.re
, 1);
339 /* Save regular expression. */
340 base
->u
.string
.reMatch
= xstrdup(reMatch
);
341 base
->u
.string
.reComment
= reComment
? xstrdup(reComment
) : NULL
;
345 static struct ovsdb_error
*
346 parse_optional_uint(struct ovsdb_parser
*parser
, const char *member
,
349 const struct json
*json
;
351 json
= ovsdb_parser_member(parser
, member
, OP_INTEGER
| OP_OPTIONAL
);
353 if (json
->u
.integer
< 0 || json
->u
.integer
> UINT_MAX
) {
354 return ovsdb_syntax_error(json
, NULL
,
355 "%s out of valid range 0 to %u",
358 *uint
= json
->u
.integer
;
364 ovsdb_base_type_from_json(struct ovsdb_base_type
*base
,
365 const struct json
*json
)
367 struct ovsdb_parser parser
;
368 struct ovsdb_error
*error
;
369 const struct json
*type
;
371 if (json
->type
== JSON_STRING
) {
372 error
= ovsdb_atomic_type_from_json(&base
->type
, json
);
376 ovsdb_base_type_init(base
, base
->type
);
380 ovsdb_parser_init(&parser
, json
, "ovsdb type");
381 type
= ovsdb_parser_member(&parser
, "type", OP_STRING
);
382 if (ovsdb_parser_has_error(&parser
)) {
383 base
->type
= OVSDB_TYPE_VOID
;
384 return ovsdb_parser_finish(&parser
);
387 error
= ovsdb_atomic_type_from_json(&base
->type
, type
);
392 ovsdb_base_type_init(base
, base
->type
);
393 if (base
->type
== OVSDB_TYPE_INTEGER
) {
394 const struct json
*min
, *max
;
396 min
= ovsdb_parser_member(&parser
, "minInteger",
397 OP_INTEGER
| OP_OPTIONAL
);
398 max
= ovsdb_parser_member(&parser
, "maxInteger",
399 OP_INTEGER
| OP_OPTIONAL
);
400 base
->u
.integer
.min
= min
? min
->u
.integer
: INT64_MIN
;
401 base
->u
.integer
.max
= max
? max
->u
.integer
: INT64_MAX
;
402 if (base
->u
.integer
.min
> base
->u
.integer
.max
) {
403 error
= ovsdb_syntax_error(json
, NULL
,
404 "minInteger exceeds maxInteger");
406 } else if (base
->type
== OVSDB_TYPE_REAL
) {
407 const struct json
*min
, *max
;
409 min
= ovsdb_parser_member(&parser
, "minReal", OP_NUMBER
| OP_OPTIONAL
);
410 max
= ovsdb_parser_member(&parser
, "maxReal", OP_NUMBER
| OP_OPTIONAL
);
411 base
->u
.real
.min
= min
? json_real(min
) : -DBL_MAX
;
412 base
->u
.real
.max
= max
? json_real(max
) : DBL_MAX
;
413 if (base
->u
.real
.min
> base
->u
.real
.max
) {
414 error
= ovsdb_syntax_error(json
, NULL
, "minReal exceeds maxReal");
416 } else if (base
->type
== OVSDB_TYPE_STRING
) {
417 const struct json
*reMatch
;
419 reMatch
= ovsdb_parser_member(&parser
, "reMatch",
420 OP_STRING
| OP_OPTIONAL
);
422 const struct json
*reComment
;
424 reComment
= ovsdb_parser_member(&parser
, "reComment",
425 OP_STRING
| OP_OPTIONAL
);
426 error
= ovsdb_base_type_set_regex(
427 base
, json_string(reMatch
),
428 reComment
? json_string(reComment
) : NULL
);
432 error
= parse_optional_uint(&parser
, "minLength",
433 &base
->u
.string
.minLen
);
436 error
= parse_optional_uint(&parser
, "maxLength",
437 &base
->u
.string
.maxLen
);
439 if (!error
&& base
->u
.string
.minLen
> base
->u
.string
.maxLen
) {
440 error
= ovsdb_syntax_error(json
, NULL
,
441 "minLength exceeds maxLength");
443 } else if (base
->type
== OVSDB_TYPE_UUID
) {
444 const struct json
*refTable
;
446 refTable
= ovsdb_parser_member(&parser
, "refTable",
447 OP_ID
| OP_OPTIONAL
);
449 base
->u
.uuid
.refTableName
= xstrdup(refTable
->u
.string
);
450 /* We can't set base->u.uuid.refTable here because we don't have
451 * enough context (we might not even be running in ovsdb-server).
452 * ovsdb_create() will set refTable later. */
457 ovsdb_error_destroy(ovsdb_parser_finish(&parser
));
459 error
= ovsdb_parser_finish(&parser
);
462 ovsdb_base_type_destroy(base
);
463 base
->type
= OVSDB_TYPE_VOID
;
469 ovsdb_base_type_to_json(const struct ovsdb_base_type
*base
)
473 if (!ovsdb_base_type_has_constraints(base
)) {
474 return json_string_create(ovsdb_atomic_type_to_string(base
->type
));
477 json
= json_object_create();
478 json_object_put_string(json
, "type",
479 ovsdb_atomic_type_to_string(base
->type
));
480 switch (base
->type
) {
481 case OVSDB_TYPE_VOID
:
484 case OVSDB_TYPE_INTEGER
:
485 if (base
->u
.integer
.min
!= INT64_MIN
) {
486 json_object_put(json
, "minInteger",
487 json_integer_create(base
->u
.integer
.min
));
489 if (base
->u
.integer
.max
!= INT64_MAX
) {
490 json_object_put(json
, "maxInteger",
491 json_integer_create(base
->u
.integer
.max
));
495 case OVSDB_TYPE_REAL
:
496 if (base
->u
.real
.min
!= -DBL_MAX
) {
497 json_object_put(json
, "minReal",
498 json_real_create(base
->u
.real
.min
));
500 if (base
->u
.real
.max
!= DBL_MAX
) {
501 json_object_put(json
, "maxReal",
502 json_real_create(base
->u
.real
.max
));
506 case OVSDB_TYPE_BOOLEAN
:
509 case OVSDB_TYPE_STRING
:
510 if (base
->u
.string
.reMatch
) {
511 json_object_put_string(json
, "reMatch", base
->u
.string
.reMatch
);
512 if (base
->u
.string
.reComment
) {
513 json_object_put_string(json
, "reComment",
514 base
->u
.string
.reComment
);
517 if (base
->u
.string
.minLen
!= 0) {
518 json_object_put(json
, "minLength",
519 json_integer_create(base
->u
.string
.minLen
));
521 if (base
->u
.string
.maxLen
!= UINT_MAX
) {
522 json_object_put(json
, "maxLength",
523 json_integer_create(base
->u
.string
.maxLen
));
527 case OVSDB_TYPE_UUID
:
528 if (base
->u
.uuid
.refTableName
) {
529 json_object_put_string(json
, "refTable",
530 base
->u
.uuid
.refTableName
);
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_min
<= type
->n_max
570 && type
->n_max
>= 1);
573 static struct ovsdb_error
*
574 n_from_json(const struct json
*json
, unsigned int *n
)
578 } else if (json
->type
== JSON_INTEGER
579 && json
->u
.integer
>= 0 && json
->u
.integer
< UINT_MAX
) {
580 *n
= json
->u
.integer
;
583 return ovsdb_syntax_error(json
, NULL
, "bad min or max value");
588 ovsdb_type_to_english(const struct ovsdb_type
*type
)
590 const char *key
= ovsdb_atomic_type_to_string(type
->key
.type
);
591 const char *value
= ovsdb_atomic_type_to_string(type
->value
.type
);
592 if (ovsdb_type_is_scalar(type
)) {
595 struct ds s
= DS_EMPTY_INITIALIZER
;
596 ds_put_cstr(&s
, ovsdb_type_is_set(type
) ? "set" : "map");
597 if (type
->n_max
== UINT_MAX
) {
599 ds_put_format(&s
, " of %u or more", type
->n_min
);
601 ds_put_cstr(&s
, " of");
603 } else if (type
->n_min
) {
604 ds_put_format(&s
, " of %u to %u", type
->n_min
, type
->n_max
);
606 ds_put_format(&s
, " of up to %u", type
->n_max
);
608 if (ovsdb_type_is_set(type
)) {
609 ds_put_format(&s
, " %ss", key
);
611 ds_put_format(&s
, " (%s, %s) pairs", key
, value
);
618 ovsdb_type_from_json(struct ovsdb_type
*type
, const struct json
*json
)
620 type
->value
.type
= OVSDB_TYPE_VOID
;
624 if (json
->type
== JSON_STRING
) {
625 return ovsdb_base_type_from_json(&type
->key
, json
);
626 } else if (json
->type
== JSON_OBJECT
) {
627 const struct json
*key
, *value
, *min
, *max
;
628 struct ovsdb_error
*error
;
629 struct ovsdb_parser parser
;
631 ovsdb_parser_init(&parser
, json
, "ovsdb type");
632 key
= ovsdb_parser_member(&parser
, "key", OP_STRING
| OP_OBJECT
);
633 value
= ovsdb_parser_member(&parser
, "value",
634 OP_STRING
| OP_OBJECT
| OP_OPTIONAL
);
635 min
= ovsdb_parser_member(&parser
, "min", OP_INTEGER
| OP_OPTIONAL
);
636 max
= ovsdb_parser_member(&parser
, "max",
637 OP_INTEGER
| OP_STRING
| OP_OPTIONAL
);
638 error
= ovsdb_parser_finish(&parser
);
643 error
= ovsdb_base_type_from_json(&type
->key
, key
);
649 error
= ovsdb_base_type_from_json(&type
->value
, value
);
655 error
= n_from_json(min
, &type
->n_min
);
660 if (max
&& max
->type
== JSON_STRING
661 && !strcmp(max
->u
.string
, "unlimited")) {
662 type
->n_max
= UINT_MAX
;
664 error
= n_from_json(max
, &type
->n_max
);
670 if (!ovsdb_type_is_valid(type
)) {
671 return ovsdb_syntax_error(json
, NULL
,
672 "ovsdb type fails constraint checks");
677 return ovsdb_syntax_error(json
, NULL
, "ovsdb type expected");
682 ovsdb_type_to_json(const struct ovsdb_type
*type
)
684 if (ovsdb_type_is_scalar(type
)
685 && !ovsdb_base_type_has_constraints(&type
->key
)) {
686 return ovsdb_base_type_to_json(&type
->key
);
688 struct json
*json
= json_object_create();
689 json_object_put(json
, "key", ovsdb_base_type_to_json(&type
->key
));
690 if (type
->value
.type
!= OVSDB_TYPE_VOID
) {
691 json_object_put(json
, "value",
692 ovsdb_base_type_to_json(&type
->value
));
694 if (type
->n_min
!= 1) {
695 json_object_put(json
, "min", json_integer_create(type
->n_min
));
697 if (type
->n_max
== UINT_MAX
) {
698 json_object_put_string(json
, "max", "unlimited");
699 } else if (type
->n_max
!= 1) {
700 json_object_put(json
, "max", json_integer_create(type
->n_max
));