]>
Commit | Line | Data |
---|---|---|
d2d3264c | 1 | /* Copyright (c) 2009, 2010, 2011, 2013 Nicira, Inc. |
f85f8ebb BP |
2 | * |
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: | |
6 | * | |
7 | * http://www.apache.org/licenses/LICENSE-2.0 | |
8 | * | |
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. | |
14 | */ | |
15 | ||
16 | #include <config.h> | |
17 | ||
18 | #include "ovsdb-types.h" | |
19 | ||
bd76d25d | 20 | #include <float.h> |
f85f8ebb BP |
21 | #include <limits.h> |
22 | ||
3e8a2ad1 | 23 | #include "openvswitch/dynamic-string.h" |
ee89ea7b | 24 | #include "openvswitch/json.h" |
d2d3264c | 25 | #include "ovs-thread.h" |
bfc96d9b | 26 | #include "ovsdb-data.h" |
f85f8ebb BP |
27 | #include "ovsdb-error.h" |
28 | #include "ovsdb-parser.h" | |
ee89ea7b | 29 | #include "util.h" |
f85f8ebb BP |
30 | |
31 | const struct ovsdb_type ovsdb_type_integer = | |
bd76d25d | 32 | OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_INTEGER_INIT); |
f85f8ebb | 33 | const struct ovsdb_type ovsdb_type_real = |
bd76d25d | 34 | OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_REAL_INIT); |
f85f8ebb | 35 | const struct ovsdb_type ovsdb_type_boolean = |
bd76d25d | 36 | OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_BOOLEAN_INIT); |
f85f8ebb | 37 | const struct ovsdb_type ovsdb_type_string = |
bd76d25d | 38 | OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_STRING_INIT); |
f85f8ebb | 39 | const struct ovsdb_type ovsdb_type_uuid = |
bd76d25d BP |
40 | OVSDB_TYPE_SCALAR_INITIALIZER(OVSDB_BASE_UUID_INIT); |
41 | \f | |
42 | /* ovsdb_atomic_type */ | |
f85f8ebb BP |
43 | const char * |
44 | ovsdb_atomic_type_to_string(enum ovsdb_atomic_type type) | |
45 | { | |
46 | switch (type) { | |
47 | case OVSDB_TYPE_VOID: | |
48 | return "void"; | |
49 | ||
50 | case OVSDB_TYPE_INTEGER: | |
51 | return "integer"; | |
52 | ||
53 | case OVSDB_TYPE_REAL: | |
54 | return "real"; | |
55 | ||
56 | case OVSDB_TYPE_BOOLEAN: | |
57 | return "boolean"; | |
58 | ||
59 | case OVSDB_TYPE_STRING: | |
60 | return "string"; | |
61 | ||
62 | case OVSDB_TYPE_UUID: | |
63 | return "uuid"; | |
64 | ||
65 | case OVSDB_N_TYPES: | |
66 | default: | |
67 | return "<invalid>"; | |
68 | } | |
69 | } | |
70 | ||
71 | struct json * | |
72 | ovsdb_atomic_type_to_json(enum ovsdb_atomic_type type) | |
73 | { | |
74 | return json_string_create(ovsdb_atomic_type_to_string(type)); | |
75 | } | |
76 | ||
f85f8ebb BP |
77 | bool |
78 | ovsdb_atomic_type_from_string(const char *string, enum ovsdb_atomic_type *type) | |
79 | { | |
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; | |
90 | } else { | |
91 | return false; | |
92 | } | |
93 | return true; | |
94 | } | |
95 | ||
96 | struct ovsdb_error * | |
97 | ovsdb_atomic_type_from_json(enum ovsdb_atomic_type *type, | |
98 | const struct json *json) | |
99 | { | |
100 | if (json->type == JSON_STRING) { | |
101 | if (ovsdb_atomic_type_from_string(json_string(json), type)) { | |
102 | return NULL; | |
103 | } else { | |
104 | *type = OVSDB_TYPE_VOID; | |
105 | return ovsdb_syntax_error(json, NULL, | |
106 | "\"%s\" is not an atomic-type", | |
107 | json_string(json)); | |
108 | } | |
109 | } else { | |
110 | *type = OVSDB_TYPE_VOID; | |
111 | return ovsdb_syntax_error(json, NULL, "atomic-type expected"); | |
112 | } | |
113 | } | |
bd76d25d BP |
114 | \f |
115 | /* ovsdb_base_type */ | |
116 | ||
117 | void | |
118 | ovsdb_base_type_init(struct ovsdb_base_type *base, enum ovsdb_atomic_type type) | |
119 | { | |
120 | base->type = type; | |
bfc96d9b | 121 | base->enum_ = NULL; |
bd76d25d BP |
122 | |
123 | switch (base->type) { | |
124 | case OVSDB_TYPE_VOID: | |
125 | break; | |
126 | ||
127 | case OVSDB_TYPE_INTEGER: | |
fa37affa BP |
128 | base->integer.min = INT64_MIN; |
129 | base->integer.max = INT64_MAX; | |
bd76d25d BP |
130 | break; |
131 | ||
132 | case OVSDB_TYPE_REAL: | |
fa37affa BP |
133 | base->real.min = -DBL_MAX; |
134 | base->real.max = DBL_MAX; | |
bd76d25d BP |
135 | break; |
136 | ||
137 | case OVSDB_TYPE_BOOLEAN: | |
138 | break; | |
139 | ||
140 | case OVSDB_TYPE_STRING: | |
fa37affa BP |
141 | base->string.minLen = 0; |
142 | base->string.maxLen = UINT_MAX; | |
bd76d25d BP |
143 | break; |
144 | ||
145 | case OVSDB_TYPE_UUID: | |
fa37affa BP |
146 | base->uuid.refTableName = NULL; |
147 | base->uuid.refTable = NULL; | |
bd76d25d BP |
148 | break; |
149 | ||
150 | case OVSDB_N_TYPES: | |
428b2edd | 151 | OVS_NOT_REACHED(); |
bd76d25d BP |
152 | |
153 | default: | |
428b2edd | 154 | OVS_NOT_REACHED(); |
bd76d25d BP |
155 | } |
156 | } | |
157 | ||
bfc96d9b BP |
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) | |
162 | { | |
d2d3264c | 163 | static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; |
bfc96d9b BP |
164 | static struct ovsdb_type *types[OVSDB_N_TYPES]; |
165 | ||
d2d3264c BP |
166 | if (ovsthread_once_start(&once)) { |
167 | enum ovsdb_atomic_type i; | |
bfc96d9b | 168 | |
d2d3264c BP |
169 | for (i = 0; i < OVSDB_N_TYPES; i++) { |
170 | struct ovsdb_type *type; | |
171 | ||
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); | |
175 | type->n_min = 1; | |
176 | type->n_max = UINT_MAX; | |
177 | } | |
178 | ||
179 | ovsthread_once_done(&once); | |
bfc96d9b BP |
180 | } |
181 | return types[atomic_type]; | |
182 | } | |
183 | ||
bd76d25d BP |
184 | void |
185 | ovsdb_base_type_clone(struct ovsdb_base_type *dst, | |
186 | const struct ovsdb_base_type *src) | |
187 | { | |
188 | *dst = *src; | |
189 | ||
bfc96d9b BP |
190 | if (src->enum_) { |
191 | dst->enum_ = xmalloc(sizeof *dst->enum_); | |
192 | ovsdb_datum_clone(dst->enum_, src->enum_, | |
193 | ovsdb_base_type_get_enum_type(dst->type)); | |
194 | } | |
195 | ||
bd76d25d BP |
196 | switch (dst->type) { |
197 | case OVSDB_TYPE_VOID: | |
198 | case OVSDB_TYPE_INTEGER: | |
199 | case OVSDB_TYPE_REAL: | |
200 | case OVSDB_TYPE_BOOLEAN: | |
201 | break; | |
202 | ||
203 | case OVSDB_TYPE_STRING: | |
bd76d25d BP |
204 | break; |
205 | ||
206 | case OVSDB_TYPE_UUID: | |
fa37affa BP |
207 | if (dst->uuid.refTableName) { |
208 | dst->uuid.refTableName = xstrdup(dst->uuid.refTableName); | |
0d0f05b9 | 209 | } |
bd76d25d BP |
210 | break; |
211 | ||
212 | case OVSDB_N_TYPES: | |
213 | default: | |
428b2edd | 214 | OVS_NOT_REACHED(); |
bd76d25d BP |
215 | } |
216 | } | |
217 | ||
218 | void | |
219 | ovsdb_base_type_destroy(struct ovsdb_base_type *base) | |
220 | { | |
221 | if (base) { | |
bfc96d9b BP |
222 | if (base->enum_) { |
223 | ovsdb_datum_destroy(base->enum_, | |
224 | ovsdb_base_type_get_enum_type(base->type)); | |
225 | free(base->enum_); | |
226 | } | |
227 | ||
bd76d25d BP |
228 | switch (base->type) { |
229 | case OVSDB_TYPE_VOID: | |
230 | case OVSDB_TYPE_INTEGER: | |
231 | case OVSDB_TYPE_REAL: | |
232 | case OVSDB_TYPE_BOOLEAN: | |
233 | break; | |
234 | ||
235 | case OVSDB_TYPE_STRING: | |
bd76d25d BP |
236 | break; |
237 | ||
238 | case OVSDB_TYPE_UUID: | |
fa37affa | 239 | free(base->uuid.refTableName); |
bd76d25d BP |
240 | break; |
241 | ||
242 | case OVSDB_N_TYPES: | |
428b2edd | 243 | OVS_NOT_REACHED(); |
bd76d25d BP |
244 | |
245 | default: | |
428b2edd | 246 | OVS_NOT_REACHED(); |
bd76d25d BP |
247 | } |
248 | } | |
249 | } | |
250 | ||
251 | bool | |
252 | ovsdb_base_type_is_valid(const struct ovsdb_base_type *base) | |
253 | { | |
254 | switch (base->type) { | |
255 | case OVSDB_TYPE_VOID: | |
256 | return true; | |
257 | ||
258 | case OVSDB_TYPE_INTEGER: | |
fa37affa | 259 | return base->integer.min <= base->integer.max; |
bd76d25d BP |
260 | |
261 | case OVSDB_TYPE_REAL: | |
fa37affa | 262 | return base->real.min <= base->real.max; |
bd76d25d BP |
263 | |
264 | case OVSDB_TYPE_BOOLEAN: | |
265 | return true; | |
266 | ||
267 | case OVSDB_TYPE_STRING: | |
fa37affa | 268 | return base->string.minLen <= base->string.maxLen; |
bd76d25d BP |
269 | |
270 | case OVSDB_TYPE_UUID: | |
271 | return true; | |
272 | ||
273 | case OVSDB_N_TYPES: | |
274 | default: | |
275 | return false; | |
276 | } | |
277 | } | |
278 | ||
279 | bool | |
280 | ovsdb_base_type_has_constraints(const struct ovsdb_base_type *base) | |
281 | { | |
bfc96d9b BP |
282 | if (base->enum_) { |
283 | return true; | |
284 | } | |
285 | ||
bd76d25d BP |
286 | switch (base->type) { |
287 | case OVSDB_TYPE_VOID: | |
428b2edd | 288 | OVS_NOT_REACHED(); |
bd76d25d BP |
289 | |
290 | case OVSDB_TYPE_INTEGER: | |
fa37affa BP |
291 | return (base->integer.min != INT64_MIN |
292 | || base->integer.max != INT64_MAX); | |
bd76d25d BP |
293 | |
294 | case OVSDB_TYPE_REAL: | |
fa37affa BP |
295 | return (base->real.min != -DBL_MAX |
296 | || base->real.max != DBL_MAX); | |
bd76d25d BP |
297 | |
298 | case OVSDB_TYPE_BOOLEAN: | |
299 | return false; | |
300 | ||
301 | case OVSDB_TYPE_STRING: | |
fa37affa | 302 | return base->string.minLen != 0 || base->string.maxLen != UINT_MAX; |
bd76d25d BP |
303 | |
304 | case OVSDB_TYPE_UUID: | |
fa37affa | 305 | return base->uuid.refTableName != NULL; |
bd76d25d BP |
306 | |
307 | case OVSDB_N_TYPES: | |
428b2edd | 308 | OVS_NOT_REACHED(); |
bd76d25d BP |
309 | |
310 | default: | |
428b2edd | 311 | OVS_NOT_REACHED(); |
bd76d25d BP |
312 | } |
313 | } | |
314 | ||
315 | void | |
316 | ovsdb_base_type_clear_constraints(struct ovsdb_base_type *base) | |
317 | { | |
318 | enum ovsdb_atomic_type type = base->type; | |
319 | ovsdb_base_type_destroy(base); | |
320 | ovsdb_base_type_init(base, type); | |
321 | } | |
322 | ||
bd76d25d BP |
323 | static struct ovsdb_error * |
324 | parse_optional_uint(struct ovsdb_parser *parser, const char *member, | |
325 | unsigned int *uint) | |
326 | { | |
327 | const struct json *json; | |
328 | ||
329 | json = ovsdb_parser_member(parser, member, OP_INTEGER | OP_OPTIONAL); | |
330 | if (json) { | |
fa37affa | 331 | if (json->integer < 0 || json->integer > UINT_MAX) { |
bd76d25d BP |
332 | return ovsdb_syntax_error(json, NULL, |
333 | "%s out of valid range 0 to %u", | |
334 | member, UINT_MAX); | |
335 | } | |
fa37affa | 336 | *uint = json->integer; |
bd76d25d BP |
337 | } |
338 | return NULL; | |
339 | } | |
340 | ||
341 | struct ovsdb_error * | |
342 | ovsdb_base_type_from_json(struct ovsdb_base_type *base, | |
343 | const struct json *json) | |
344 | { | |
345 | struct ovsdb_parser parser; | |
346 | struct ovsdb_error *error; | |
bfc96d9b | 347 | const struct json *type, *enum_; |
bd76d25d BP |
348 | |
349 | if (json->type == JSON_STRING) { | |
350 | error = ovsdb_atomic_type_from_json(&base->type, json); | |
351 | if (error) { | |
352 | return error; | |
353 | } | |
354 | ovsdb_base_type_init(base, base->type); | |
355 | return NULL; | |
356 | } | |
357 | ||
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); | |
363 | } | |
364 | ||
365 | error = ovsdb_atomic_type_from_json(&base->type, type); | |
366 | if (error) { | |
2434d05d | 367 | ovsdb_error_destroy(ovsdb_parser_destroy(&parser)); |
bd76d25d BP |
368 | return error; |
369 | } | |
370 | ||
371 | ovsdb_base_type_init(base, base->type); | |
bfc96d9b BP |
372 | |
373 | enum_ = ovsdb_parser_member(&parser, "enum", OP_ANY | OP_OPTIONAL); | |
374 | if (enum_) { | |
375 | base->enum_ = xmalloc(sizeof *base->enum_); | |
376 | error = ovsdb_datum_from_json( | |
377 | base->enum_, ovsdb_base_type_get_enum_type(base->type), | |
378 | enum_, NULL); | |
379 | if (error) { | |
380 | free(base->enum_); | |
381 | base->enum_ = NULL; | |
382 | } | |
383 | } else if (base->type == OVSDB_TYPE_INTEGER) { | |
bd76d25d BP |
384 | const struct json *min, *max; |
385 | ||
386 | min = ovsdb_parser_member(&parser, "minInteger", | |
387 | OP_INTEGER | OP_OPTIONAL); | |
388 | max = ovsdb_parser_member(&parser, "maxInteger", | |
389 | OP_INTEGER | OP_OPTIONAL); | |
fa37affa BP |
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) { | |
bd76d25d BP |
393 | error = ovsdb_syntax_error(json, NULL, |
394 | "minInteger exceeds maxInteger"); | |
395 | } | |
396 | } else if (base->type == OVSDB_TYPE_REAL) { | |
397 | const struct json *min, *max; | |
398 | ||
399 | min = ovsdb_parser_member(&parser, "minReal", OP_NUMBER | OP_OPTIONAL); | |
400 | max = ovsdb_parser_member(&parser, "maxReal", OP_NUMBER | OP_OPTIONAL); | |
fa37affa BP |
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) { | |
bd76d25d BP |
404 | error = ovsdb_syntax_error(json, NULL, "minReal exceeds maxReal"); |
405 | } | |
406 | } else if (base->type == OVSDB_TYPE_STRING) { | |
bd76d25d BP |
407 | if (!error) { |
408 | error = parse_optional_uint(&parser, "minLength", | |
fa37affa | 409 | &base->string.minLen); |
bd76d25d BP |
410 | } |
411 | if (!error) { | |
412 | error = parse_optional_uint(&parser, "maxLength", | |
fa37affa | 413 | &base->string.maxLen); |
bd76d25d | 414 | } |
fa37affa | 415 | if (!error && base->string.minLen > base->string.maxLen) { |
bd76d25d BP |
416 | error = ovsdb_syntax_error(json, NULL, |
417 | "minLength exceeds maxLength"); | |
418 | } | |
0d0f05b9 BP |
419 | } else if (base->type == OVSDB_TYPE_UUID) { |
420 | const struct json *refTable; | |
421 | ||
422 | refTable = ovsdb_parser_member(&parser, "refTable", | |
423 | OP_ID | OP_OPTIONAL); | |
424 | if (refTable) { | |
7360012b BP |
425 | const struct json *refType; |
426 | ||
fa37affa | 427 | base->uuid.refTableName = xstrdup(refTable->string); |
7360012b | 428 | |
fa37affa | 429 | /* We can't set base->uuid.refTable here because we don't have |
0d0f05b9 BP |
430 | * enough context (we might not even be running in ovsdb-server). |
431 | * ovsdb_create() will set refTable later. */ | |
7360012b BP |
432 | |
433 | refType = ovsdb_parser_member(&parser, "refType", | |
434 | OP_ID | OP_OPTIONAL); | |
435 | if (refType) { | |
436 | const char *refType_s = json_string(refType); | |
437 | if (!strcmp(refType_s, "strong")) { | |
fa37affa | 438 | base->uuid.refType = OVSDB_REF_STRONG; |
7360012b | 439 | } else if (!strcmp(refType_s, "weak")) { |
fa37affa | 440 | base->uuid.refType = OVSDB_REF_WEAK; |
7360012b BP |
441 | } else { |
442 | error = ovsdb_syntax_error(json, NULL, "refType must be " | |
443 | "\"strong\" or \"weak\" (not " | |
444 | "\"%s\")", refType_s); | |
445 | } | |
446 | } else { | |
fa37affa | 447 | base->uuid.refType = OVSDB_REF_STRONG; |
7360012b | 448 | } |
0d0f05b9 | 449 | } |
bd76d25d BP |
450 | } |
451 | ||
452 | if (error) { | |
453 | ovsdb_error_destroy(ovsdb_parser_finish(&parser)); | |
454 | } else { | |
455 | error = ovsdb_parser_finish(&parser); | |
456 | } | |
457 | if (error) { | |
458 | ovsdb_base_type_destroy(base); | |
459 | base->type = OVSDB_TYPE_VOID; | |
460 | } | |
461 | return error; | |
462 | } | |
463 | ||
464 | struct json * | |
465 | ovsdb_base_type_to_json(const struct ovsdb_base_type *base) | |
466 | { | |
467 | struct json *json; | |
468 | ||
469 | if (!ovsdb_base_type_has_constraints(base)) { | |
470 | return json_string_create(ovsdb_atomic_type_to_string(base->type)); | |
471 | } | |
472 | ||
473 | json = json_object_create(); | |
474 | json_object_put_string(json, "type", | |
475 | ovsdb_atomic_type_to_string(base->type)); | |
bfc96d9b BP |
476 | |
477 | if (base->enum_) { | |
478 | const struct ovsdb_type *type; | |
479 | ||
480 | type = ovsdb_base_type_get_enum_type(base->type); | |
481 | json_object_put(json, "enum", ovsdb_datum_to_json(base->enum_, type)); | |
482 | } | |
483 | ||
bd76d25d BP |
484 | switch (base->type) { |
485 | case OVSDB_TYPE_VOID: | |
428b2edd | 486 | OVS_NOT_REACHED(); |
bd76d25d BP |
487 | |
488 | case OVSDB_TYPE_INTEGER: | |
fa37affa | 489 | if (base->integer.min != INT64_MIN) { |
bd76d25d | 490 | json_object_put(json, "minInteger", |
fa37affa | 491 | json_integer_create(base->integer.min)); |
bd76d25d | 492 | } |
fa37affa | 493 | if (base->integer.max != INT64_MAX) { |
bd76d25d | 494 | json_object_put(json, "maxInteger", |
fa37affa | 495 | json_integer_create(base->integer.max)); |
bd76d25d BP |
496 | } |
497 | break; | |
498 | ||
499 | case OVSDB_TYPE_REAL: | |
fa37affa | 500 | if (base->real.min != -DBL_MAX) { |
bd76d25d | 501 | json_object_put(json, "minReal", |
fa37affa | 502 | json_real_create(base->real.min)); |
bd76d25d | 503 | } |
fa37affa | 504 | if (base->real.max != DBL_MAX) { |
bd76d25d | 505 | json_object_put(json, "maxReal", |
fa37affa | 506 | json_real_create(base->real.max)); |
bd76d25d BP |
507 | } |
508 | break; | |
509 | ||
510 | case OVSDB_TYPE_BOOLEAN: | |
511 | break; | |
512 | ||
513 | case OVSDB_TYPE_STRING: | |
fa37affa | 514 | if (base->string.minLen != 0) { |
bd76d25d | 515 | json_object_put(json, "minLength", |
fa37affa | 516 | json_integer_create(base->string.minLen)); |
bd76d25d | 517 | } |
fa37affa | 518 | if (base->string.maxLen != UINT_MAX) { |
bd76d25d | 519 | json_object_put(json, "maxLength", |
fa37affa | 520 | json_integer_create(base->string.maxLen)); |
bd76d25d BP |
521 | } |
522 | break; | |
523 | ||
524 | case OVSDB_TYPE_UUID: | |
fa37affa | 525 | if (base->uuid.refTableName) { |
0d0f05b9 | 526 | json_object_put_string(json, "refTable", |
fa37affa BP |
527 | base->uuid.refTableName); |
528 | if (base->uuid.refType == OVSDB_REF_WEAK) { | |
7360012b BP |
529 | json_object_put_string(json, "refType", "weak"); |
530 | } | |
0d0f05b9 | 531 | } |
bd76d25d BP |
532 | break; |
533 | ||
534 | case OVSDB_N_TYPES: | |
428b2edd | 535 | OVS_NOT_REACHED(); |
bd76d25d BP |
536 | |
537 | default: | |
428b2edd | 538 | OVS_NOT_REACHED(); |
bd76d25d BP |
539 | } |
540 | ||
541 | return json; | |
542 | } | |
543 | \f | |
544 | /* ovsdb_type */ | |
545 | ||
546 | void | |
547 | ovsdb_type_clone(struct ovsdb_type *dst, const struct ovsdb_type *src) | |
548 | { | |
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; | |
553 | } | |
554 | ||
555 | void | |
556 | ovsdb_type_destroy(struct ovsdb_type *type) | |
557 | { | |
558 | ovsdb_base_type_destroy(&type->key); | |
559 | ovsdb_base_type_destroy(&type->value); | |
560 | } | |
561 | ||
562 | bool | |
563 | ovsdb_type_is_valid(const struct ovsdb_type *type) | |
564 | { | |
565 | return (type->key.type != OVSDB_TYPE_VOID | |
566 | && ovsdb_base_type_is_valid(&type->key) | |
567 | && ovsdb_base_type_is_valid(&type->value) | |
568 | && type->n_min <= 1 | |
ae8f13e2 | 569 | && type->n_max >= 1); |
bd76d25d | 570 | } |
f85f8ebb BP |
571 | |
572 | static struct ovsdb_error * | |
573 | n_from_json(const struct json *json, unsigned int *n) | |
574 | { | |
575 | if (!json) { | |
576 | return NULL; | |
577 | } else if (json->type == JSON_INTEGER | |
fa37affa BP |
578 | && json->integer >= 0 && json->integer < UINT_MAX) { |
579 | *n = json->integer; | |
f85f8ebb BP |
580 | return NULL; |
581 | } else { | |
582 | return ovsdb_syntax_error(json, NULL, "bad min or max value"); | |
583 | } | |
584 | } | |
585 | ||
586 | char * | |
587 | ovsdb_type_to_english(const struct ovsdb_type *type) | |
588 | { | |
bd76d25d BP |
589 | const char *key = ovsdb_atomic_type_to_string(type->key.type); |
590 | const char *value = ovsdb_atomic_type_to_string(type->value.type); | |
f85f8ebb BP |
591 | if (ovsdb_type_is_scalar(type)) { |
592 | return xstrdup(key); | |
593 | } else { | |
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) { | |
597 | if (type->n_min) { | |
598 | ds_put_format(&s, " of %u or more", type->n_min); | |
599 | } else { | |
600 | ds_put_cstr(&s, " of"); | |
601 | } | |
602 | } else if (type->n_min) { | |
603 | ds_put_format(&s, " of %u to %u", type->n_min, type->n_max); | |
604 | } else { | |
605 | ds_put_format(&s, " of up to %u", type->n_max); | |
606 | } | |
607 | if (ovsdb_type_is_set(type)) { | |
608 | ds_put_format(&s, " %ss", key); | |
609 | } else { | |
610 | ds_put_format(&s, " (%s, %s) pairs", key, value); | |
611 | } | |
612 | return ds_cstr(&s); | |
613 | } | |
614 | } | |
615 | ||
616 | struct ovsdb_error * | |
617 | ovsdb_type_from_json(struct ovsdb_type *type, const struct json *json) | |
618 | { | |
bfc96d9b | 619 | ovsdb_base_type_init(&type->value, OVSDB_TYPE_VOID); |
f85f8ebb BP |
620 | type->n_min = 1; |
621 | type->n_max = 1; | |
622 | ||
623 | if (json->type == JSON_STRING) { | |
bd76d25d | 624 | return ovsdb_base_type_from_json(&type->key, json); |
f85f8ebb BP |
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; | |
629 | ||
630 | ovsdb_parser_init(&parser, json, "ovsdb type"); | |
bd76d25d BP |
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); | |
f85f8ebb BP |
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); | |
638 | if (error) { | |
639 | return error; | |
640 | } | |
641 | ||
bd76d25d | 642 | error = ovsdb_base_type_from_json(&type->key, key); |
f85f8ebb BP |
643 | if (error) { |
644 | return error; | |
645 | } | |
646 | ||
647 | if (value) { | |
bd76d25d | 648 | error = ovsdb_base_type_from_json(&type->value, value); |
f85f8ebb BP |
649 | if (error) { |
650 | return error; | |
651 | } | |
652 | } | |
653 | ||
654 | error = n_from_json(min, &type->n_min); | |
655 | if (error) { | |
656 | return error; | |
657 | } | |
658 | ||
659 | if (max && max->type == JSON_STRING | |
fa37affa | 660 | && !strcmp(max->string, "unlimited")) { |
f85f8ebb BP |
661 | type->n_max = UINT_MAX; |
662 | } else { | |
663 | error = n_from_json(max, &type->n_max); | |
664 | if (error) { | |
665 | return error; | |
666 | } | |
667 | } | |
668 | ||
669 | if (!ovsdb_type_is_valid(type)) { | |
670 | return ovsdb_syntax_error(json, NULL, | |
671 | "ovsdb type fails constraint checks"); | |
672 | } | |
673 | ||
674 | return NULL; | |
675 | } else { | |
676 | return ovsdb_syntax_error(json, NULL, "ovsdb type expected"); | |
677 | } | |
678 | } | |
679 | ||
680 | struct json * | |
681 | ovsdb_type_to_json(const struct ovsdb_type *type) | |
682 | { | |
bd76d25d BP |
683 | if (ovsdb_type_is_scalar(type) |
684 | && !ovsdb_base_type_has_constraints(&type->key)) { | |
685 | return ovsdb_base_type_to_json(&type->key); | |
f85f8ebb BP |
686 | } else { |
687 | struct json *json = json_object_create(); | |
bd76d25d BP |
688 | json_object_put(json, "key", ovsdb_base_type_to_json(&type->key)); |
689 | if (type->value.type != OVSDB_TYPE_VOID) { | |
f85f8ebb | 690 | json_object_put(json, "value", |
bd76d25d | 691 | ovsdb_base_type_to_json(&type->value)); |
f85f8ebb BP |
692 | } |
693 | if (type->n_min != 1) { | |
694 | json_object_put(json, "min", json_integer_create(type->n_min)); | |
695 | } | |
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)); | |
700 | } | |
701 | return json; | |
702 | } | |
703 | } |