datapath: remove flow_dissector
[cascardo/ovs.git] / lib / ovsdb-types.c
1 /* Copyright (c) 2009, 2010, 2011, 2013 Nicira, Inc.
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
20 #include <float.h>
21 #include <limits.h>
22
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"
29 #include "util.h"
30
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);
41 \f
42 /* ovsdb_atomic_type */
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
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 }
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;
121     base->enum_ = NULL;
122
123     switch (base->type) {
124     case OVSDB_TYPE_VOID:
125         break;
126
127     case OVSDB_TYPE_INTEGER:
128         base->u.integer.min = INT64_MIN;
129         base->u.integer.max = INT64_MAX;
130         break;
131
132     case OVSDB_TYPE_REAL:
133         base->u.real.min = -DBL_MAX;
134         base->u.real.max = DBL_MAX;
135         break;
136
137     case OVSDB_TYPE_BOOLEAN:
138         break;
139
140     case OVSDB_TYPE_STRING:
141         base->u.string.minLen = 0;
142         base->u.string.maxLen = UINT_MAX;
143         break;
144
145     case OVSDB_TYPE_UUID:
146         base->u.uuid.refTableName = NULL;
147         base->u.uuid.refTable = NULL;
148         break;
149
150     case OVSDB_N_TYPES:
151         OVS_NOT_REACHED();
152
153     default:
154         OVS_NOT_REACHED();
155     }
156 }
157
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 {
163     static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER;
164     static struct ovsdb_type *types[OVSDB_N_TYPES];
165
166     if (ovsthread_once_start(&once)) {
167         enum ovsdb_atomic_type i;
168
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);
180     }
181     return types[atomic_type];
182 }
183
184 void
185 ovsdb_base_type_clone(struct ovsdb_base_type *dst,
186                       const struct ovsdb_base_type *src)
187 {
188     *dst = *src;
189
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
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:
204         break;
205
206     case OVSDB_TYPE_UUID:
207         if (dst->u.uuid.refTableName) {
208             dst->u.uuid.refTableName = xstrdup(dst->u.uuid.refTableName);
209         }
210         break;
211
212     case OVSDB_N_TYPES:
213     default:
214         OVS_NOT_REACHED();
215     }
216 }
217
218 void
219 ovsdb_base_type_destroy(struct ovsdb_base_type *base)
220 {
221     if (base) {
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
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:
236             break;
237
238         case OVSDB_TYPE_UUID:
239             free(base->u.uuid.refTableName);
240             break;
241
242         case OVSDB_N_TYPES:
243             OVS_NOT_REACHED();
244
245         default:
246             OVS_NOT_REACHED();
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:
259         return base->u.integer.min <= base->u.integer.max;
260
261     case OVSDB_TYPE_REAL:
262         return base->u.real.min <= base->u.real.max;
263
264     case OVSDB_TYPE_BOOLEAN:
265         return true;
266
267     case OVSDB_TYPE_STRING:
268         return base->u.string.minLen <= base->u.string.maxLen;
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 {
282     if (base->enum_) {
283         return true;
284     }
285
286     switch (base->type) {
287     case OVSDB_TYPE_VOID:
288         OVS_NOT_REACHED();
289
290     case OVSDB_TYPE_INTEGER:
291         return (base->u.integer.min != INT64_MIN
292                 || base->u.integer.max != INT64_MAX);
293
294     case OVSDB_TYPE_REAL:
295         return (base->u.real.min != -DBL_MAX
296                 || base->u.real.max != DBL_MAX);
297
298     case OVSDB_TYPE_BOOLEAN:
299         return false;
300
301     case OVSDB_TYPE_STRING:
302         return base->u.string.minLen != 0 || base->u.string.maxLen != UINT_MAX;
303
304     case OVSDB_TYPE_UUID:
305         return base->u.uuid.refTableName != NULL;
306
307     case OVSDB_N_TYPES:
308         OVS_NOT_REACHED();
309
310     default:
311         OVS_NOT_REACHED();
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
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) {
331         if (json->u.integer < 0 || json->u.integer > UINT_MAX) {
332             return ovsdb_syntax_error(json, NULL,
333                                       "%s out of valid range 0 to %u",
334                                       member, UINT_MAX);
335         }
336         *uint = json->u.integer;
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;
347     const struct json *type, *enum_;
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) {
367         return error;
368     }
369
370     ovsdb_base_type_init(base, base->type);
371
372     enum_ = ovsdb_parser_member(&parser, "enum", OP_ANY | OP_OPTIONAL);
373     if (enum_) {
374         base->enum_ = xmalloc(sizeof *base->enum_);
375         error = ovsdb_datum_from_json(
376             base->enum_, ovsdb_base_type_get_enum_type(base->type),
377             enum_, NULL);
378         if (error) {
379             free(base->enum_);
380             base->enum_ = NULL;
381         }
382     } else if (base->type == OVSDB_TYPE_INTEGER) {
383         const struct json *min, *max;
384
385         min = ovsdb_parser_member(&parser, "minInteger",
386                                   OP_INTEGER | OP_OPTIONAL);
387         max = ovsdb_parser_member(&parser, "maxInteger",
388                                   OP_INTEGER | OP_OPTIONAL);
389         base->u.integer.min = min ? min->u.integer : INT64_MIN;
390         base->u.integer.max = max ? max->u.integer : INT64_MAX;
391         if (base->u.integer.min > base->u.integer.max) {
392             error = ovsdb_syntax_error(json, NULL,
393                                        "minInteger exceeds maxInteger");
394         }
395     } else if (base->type == OVSDB_TYPE_REAL) {
396         const struct json *min, *max;
397
398         min = ovsdb_parser_member(&parser, "minReal", OP_NUMBER | OP_OPTIONAL);
399         max = ovsdb_parser_member(&parser, "maxReal", OP_NUMBER | OP_OPTIONAL);
400         base->u.real.min = min ? json_real(min) : -DBL_MAX;
401         base->u.real.max = max ? json_real(max) : DBL_MAX;
402         if (base->u.real.min > base->u.real.max) {
403             error = ovsdb_syntax_error(json, NULL, "minReal exceeds maxReal");
404         }
405     } else if (base->type == OVSDB_TYPE_STRING) {
406         if (!error) {
407             error = parse_optional_uint(&parser, "minLength",
408                                         &base->u.string.minLen);
409         }
410         if (!error) {
411             error = parse_optional_uint(&parser, "maxLength",
412                                         &base->u.string.maxLen);
413         }
414         if (!error && base->u.string.minLen > base->u.string.maxLen) {
415             error = ovsdb_syntax_error(json, NULL,
416                                        "minLength exceeds maxLength");
417         }
418     } else if (base->type == OVSDB_TYPE_UUID) {
419         const struct json *refTable;
420
421         refTable = ovsdb_parser_member(&parser, "refTable",
422                                        OP_ID | OP_OPTIONAL);
423         if (refTable) {
424             const struct json *refType;
425
426             base->u.uuid.refTableName = xstrdup(refTable->u.string);
427
428             /* We can't set base->u.uuid.refTable here because we don't have
429              * enough context (we might not even be running in ovsdb-server).
430              * ovsdb_create() will set refTable later. */
431
432             refType = ovsdb_parser_member(&parser, "refType",
433                                           OP_ID | OP_OPTIONAL);
434             if (refType) {
435                 const char *refType_s = json_string(refType);
436                 if (!strcmp(refType_s, "strong")) {
437                     base->u.uuid.refType = OVSDB_REF_STRONG;
438                 } else if (!strcmp(refType_s, "weak")) {
439                     base->u.uuid.refType = OVSDB_REF_WEAK;
440                 } else {
441                     error = ovsdb_syntax_error(json, NULL, "refType must be "
442                                                "\"strong\" or \"weak\" (not "
443                                                "\"%s\")", refType_s);
444                 }
445             } else {
446                 base->u.uuid.refType = OVSDB_REF_STRONG;
447             }
448         }
449     }
450
451     if (error) {
452         ovsdb_error_destroy(ovsdb_parser_finish(&parser));
453     } else {
454         error = ovsdb_parser_finish(&parser);
455     }
456     if (error) {
457         ovsdb_base_type_destroy(base);
458         base->type = OVSDB_TYPE_VOID;
459     }
460     return error;
461 }
462
463 struct json *
464 ovsdb_base_type_to_json(const struct ovsdb_base_type *base)
465 {
466     struct json *json;
467
468     if (!ovsdb_base_type_has_constraints(base)) {
469         return json_string_create(ovsdb_atomic_type_to_string(base->type));
470     }
471
472     json = json_object_create();
473     json_object_put_string(json, "type",
474                            ovsdb_atomic_type_to_string(base->type));
475
476     if (base->enum_) {
477         const struct ovsdb_type *type;
478
479         type = ovsdb_base_type_get_enum_type(base->type);
480         json_object_put(json, "enum", ovsdb_datum_to_json(base->enum_, type));
481     }
482
483     switch (base->type) {
484     case OVSDB_TYPE_VOID:
485         OVS_NOT_REACHED();
486
487     case OVSDB_TYPE_INTEGER:
488         if (base->u.integer.min != INT64_MIN) {
489             json_object_put(json, "minInteger",
490                             json_integer_create(base->u.integer.min));
491         }
492         if (base->u.integer.max != INT64_MAX) {
493             json_object_put(json, "maxInteger",
494                             json_integer_create(base->u.integer.max));
495         }
496         break;
497
498     case OVSDB_TYPE_REAL:
499         if (base->u.real.min != -DBL_MAX) {
500             json_object_put(json, "minReal",
501                             json_real_create(base->u.real.min));
502         }
503         if (base->u.real.max != DBL_MAX) {
504             json_object_put(json, "maxReal",
505                             json_real_create(base->u.real.max));
506         }
507         break;
508
509     case OVSDB_TYPE_BOOLEAN:
510         break;
511
512     case OVSDB_TYPE_STRING:
513         if (base->u.string.minLen != 0) {
514             json_object_put(json, "minLength",
515                             json_integer_create(base->u.string.minLen));
516         }
517         if (base->u.string.maxLen != UINT_MAX) {
518             json_object_put(json, "maxLength",
519                             json_integer_create(base->u.string.maxLen));
520         }
521         break;
522
523     case OVSDB_TYPE_UUID:
524         if (base->u.uuid.refTableName) {
525             json_object_put_string(json, "refTable",
526                                    base->u.uuid.refTableName);
527             if (base->u.uuid.refType == OVSDB_REF_WEAK) {
528                 json_object_put_string(json, "refType", "weak");
529             }
530         }
531         break;
532
533     case OVSDB_N_TYPES:
534         OVS_NOT_REACHED();
535
536     default:
537         OVS_NOT_REACHED();
538     }
539
540     return json;
541 }
542 \f
543 /* ovsdb_type */
544
545 void
546 ovsdb_type_clone(struct ovsdb_type *dst, const struct ovsdb_type *src)
547 {
548     ovsdb_base_type_clone(&dst->key, &src->key);
549     ovsdb_base_type_clone(&dst->value, &src->value);
550     dst->n_min = src->n_min;
551     dst->n_max = src->n_max;
552 }
553
554 void
555 ovsdb_type_destroy(struct ovsdb_type *type)
556 {
557     ovsdb_base_type_destroy(&type->key);
558     ovsdb_base_type_destroy(&type->value);
559 }
560
561 bool
562 ovsdb_type_is_valid(const struct ovsdb_type *type)
563 {
564     return (type->key.type != OVSDB_TYPE_VOID
565             && ovsdb_base_type_is_valid(&type->key)
566             && ovsdb_base_type_is_valid(&type->value)
567             && type->n_min <= 1
568             && type->n_max >= 1);
569 }
570
571 static struct ovsdb_error *
572 n_from_json(const struct json *json, unsigned int *n)
573 {
574     if (!json) {
575         return NULL;
576     } else if (json->type == JSON_INTEGER
577                && json->u.integer >= 0 && json->u.integer < UINT_MAX) {
578         *n = json->u.integer;
579         return NULL;
580     } else {
581         return ovsdb_syntax_error(json, NULL, "bad min or max value");
582     }
583 }
584
585 char *
586 ovsdb_type_to_english(const struct ovsdb_type *type)
587 {
588     const char *key = ovsdb_atomic_type_to_string(type->key.type);
589     const char *value = ovsdb_atomic_type_to_string(type->value.type);
590     if (ovsdb_type_is_scalar(type)) {
591         return xstrdup(key);
592     } else {
593         struct ds s = DS_EMPTY_INITIALIZER;
594         ds_put_cstr(&s, ovsdb_type_is_set(type) ? "set" : "map");
595         if (type->n_max == UINT_MAX) {
596             if (type->n_min) {
597                 ds_put_format(&s, " of %u or more", type->n_min);
598             } else {
599                 ds_put_cstr(&s, " of");
600             }
601         } else if (type->n_min) {
602             ds_put_format(&s, " of %u to %u", type->n_min, type->n_max);
603         } else {
604             ds_put_format(&s, " of up to %u", type->n_max);
605         }
606         if (ovsdb_type_is_set(type)) {
607             ds_put_format(&s, " %ss", key);
608         } else {
609             ds_put_format(&s, " (%s, %s) pairs", key, value);
610         }
611         return ds_cstr(&s);
612     }
613 }
614
615 struct ovsdb_error *
616 ovsdb_type_from_json(struct ovsdb_type *type, const struct json *json)
617 {
618     ovsdb_base_type_init(&type->value, OVSDB_TYPE_VOID);
619     type->n_min = 1;
620     type->n_max = 1;
621
622     if (json->type == JSON_STRING) {
623         return ovsdb_base_type_from_json(&type->key, json);
624     } else if (json->type == JSON_OBJECT) {
625         const struct json *key, *value, *min, *max;
626         struct ovsdb_error *error;
627         struct ovsdb_parser parser;
628
629         ovsdb_parser_init(&parser, json, "ovsdb type");
630         key = ovsdb_parser_member(&parser, "key", OP_STRING | OP_OBJECT);
631         value = ovsdb_parser_member(&parser, "value",
632                                     OP_STRING | OP_OBJECT | OP_OPTIONAL);
633         min = ovsdb_parser_member(&parser, "min", OP_INTEGER | OP_OPTIONAL);
634         max = ovsdb_parser_member(&parser, "max",
635                                   OP_INTEGER | OP_STRING | OP_OPTIONAL);
636         error = ovsdb_parser_finish(&parser);
637         if (error) {
638             return error;
639         }
640
641         error = ovsdb_base_type_from_json(&type->key, key);
642         if (error) {
643             return error;
644         }
645
646         if (value) {
647             error = ovsdb_base_type_from_json(&type->value, value);
648             if (error) {
649                 return error;
650             }
651         }
652
653         error = n_from_json(min, &type->n_min);
654         if (error) {
655             return error;
656         }
657
658         if (max && max->type == JSON_STRING
659             && !strcmp(max->u.string, "unlimited")) {
660             type->n_max = UINT_MAX;
661         } else {
662             error = n_from_json(max, &type->n_max);
663             if (error) {
664                 return error;
665             }
666         }
667
668         if (!ovsdb_type_is_valid(type)) {
669             return ovsdb_syntax_error(json, NULL,
670                                       "ovsdb type fails constraint checks");
671         }
672
673         return NULL;
674     } else {
675         return ovsdb_syntax_error(json, NULL, "ovsdb type expected");
676     }
677 }
678
679 struct json *
680 ovsdb_type_to_json(const struct ovsdb_type *type)
681 {
682     if (ovsdb_type_is_scalar(type)
683         && !ovsdb_base_type_has_constraints(&type->key)) {
684         return ovsdb_base_type_to_json(&type->key);
685     } else {
686         struct json *json = json_object_create();
687         json_object_put(json, "key", ovsdb_base_type_to_json(&type->key));
688         if (type->value.type != OVSDB_TYPE_VOID) {
689             json_object_put(json, "value",
690                             ovsdb_base_type_to_json(&type->value));
691         }
692         if (type->n_min != 1) {
693             json_object_put(json, "min", json_integer_create(type->n_min));
694         }
695         if (type->n_max == UINT_MAX) {
696             json_object_put_string(json, "max", "unlimited");
697         } else if (type->n_max != 1) {
698             json_object_put(json, "max", json_integer_create(type->n_max));
699         }
700         return json;
701     }
702 }