]> git.proxmox.com Git - ovs.git/blame - ovsdb/mutation.c
ofproto: Specialize ofproto_send_packet() for uses the callers really want.
[ovs.git] / ovsdb / mutation.c
CommitLineData
2f47998b 1/* Copyright (c) 2009, 2010 Nicira Networks
e9f8f936
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 "mutation.h"
19
20#include <float.h>
21#include <limits.h>
22
23#include "column.h"
24#include "ovsdb-error.h"
25#include "json.h"
26#include "row.h"
27#include "table.h"
28
e9f8f936
BP
29struct ovsdb_error *
30ovsdb_mutator_from_string(const char *name, enum ovsdb_mutator *mutator)
31{
32#define OVSDB_MUTATOR(ENUM, NAME) \
33 if (!strcmp(name, NAME)) { \
34 *mutator = ENUM; \
35 return NULL; \
36 }
37 OVSDB_MUTATORS;
38#undef OVSDB_MUTATOR
39
40 return ovsdb_syntax_error(NULL, "unknown mutator",
41 "No mutator named %s.", name);
42}
43
44const char *
45ovsdb_mutator_to_string(enum ovsdb_mutator mutator)
46{
47 switch (mutator) {
48#define OVSDB_MUTATOR(ENUM, NAME) case ENUM: return NAME;
49 OVSDB_MUTATORS;
50#undef OVSDB_MUTATOR
51 }
52
53 return NULL;
54}
55
56static WARN_UNUSED_RESULT struct ovsdb_error *
57type_mismatch(const struct ovsdb_mutation *m, const struct json *json)
58{
59 struct ovsdb_error *error;
60 char *s;
61
62 s = ovsdb_type_to_english(&m->column->type);
63 error = ovsdb_syntax_error(
64 json, NULL, "Type mismatch: \"%s\" operator may not be "
65 "applied to column %s of type %s.",
66 ovsdb_mutator_to_string(m->mutator), m->column->name, s);
67 free(s);
68
69 return error;
70}
71
72static WARN_UNUSED_RESULT struct ovsdb_error *
73ovsdb_mutation_from_json(const struct ovsdb_table_schema *ts,
74 const struct json *json,
fbf925e4 75 struct ovsdb_symbol_table *symtab,
e9f8f936
BP
76 struct ovsdb_mutation *m)
77{
78 const struct json_array *array;
79 struct ovsdb_error *error;
80 const char *mutator_name;
81 const char *column_name;
82
83 if (json->type != JSON_ARRAY
84 || json->u.array.n != 3
85 || json->u.array.elems[0]->type != JSON_STRING
86 || json->u.array.elems[1]->type != JSON_STRING) {
87 return ovsdb_syntax_error(json, NULL, "Parse error in mutation.");
88 }
89 array = json_array(json);
90
91 column_name = json_string(array->elems[0]);
92 m->column = ovsdb_table_schema_get_column(ts, column_name);
93 if (!m->column) {
94 return ovsdb_syntax_error(json, "unknown column",
95 "No column %s in table %s.",
96 column_name, ts->name);
97 }
bd76d25d 98 ovsdb_type_clone(&m->type, &m->column->type);
e9f8f936
BP
99
100 mutator_name = json_string(array->elems[1]);
101 error = ovsdb_mutator_from_string(mutator_name, &m->mutator);
102 if (error) {
bd76d25d 103 goto exit;
e9f8f936
BP
104 }
105
106 /* Type-check and relax restrictions on 'type' if appropriate. */
107 switch (m->mutator) {
108 case OVSDB_M_ADD:
109 case OVSDB_M_SUB:
110 case OVSDB_M_MUL:
111 case OVSDB_M_DIV:
112 case OVSDB_M_MOD:
113 if ((!ovsdb_type_is_scalar(&m->type) && !ovsdb_type_is_set(&m->type))
bd76d25d
BP
114 || (m->type.key.type != OVSDB_TYPE_INTEGER
115 && m->type.key.type != OVSDB_TYPE_REAL)
e9f8f936 116 || (m->mutator == OVSDB_M_MOD
bd76d25d 117 && m->type.key.type == OVSDB_TYPE_REAL)) {
e9f8f936
BP
118 return type_mismatch(m, json);
119 }
bd76d25d 120 ovsdb_base_type_clear_constraints(&m->type.key);
e9f8f936 121 m->type.n_min = m->type.n_max = 1;
bd76d25d
BP
122 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
123 symtab);
124 break;
e9f8f936
BP
125
126 case OVSDB_M_INSERT:
127 case OVSDB_M_DELETE:
128 if (!ovsdb_type_is_set(&m->type) && !ovsdb_type_is_map(&m->type)) {
129 return type_mismatch(m, json);
130 }
131 m->type.n_min = 0;
132 if (m->mutator == OVSDB_M_DELETE) {
133 m->type.n_max = UINT_MAX;
134 }
135 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
136 symtab);
137 if (error && ovsdb_type_is_map(&m->type)
138 && m->mutator == OVSDB_M_DELETE) {
139 ovsdb_error_destroy(error);
bd76d25d 140 m->type.value.type = OVSDB_TYPE_VOID;
e9f8f936
BP
141 error = ovsdb_datum_from_json(&m->arg, &m->type, array->elems[2],
142 symtab);
143 }
bd76d25d
BP
144 break;
145
146 default:
147 NOT_REACHED();
e9f8f936
BP
148 }
149
bd76d25d
BP
150exit:
151 if (error) {
152 ovsdb_type_destroy(&m->type);
153 }
154 return error;
e9f8f936
BP
155}
156
157static void
158ovsdb_mutation_free(struct ovsdb_mutation *m)
159{
160 ovsdb_datum_destroy(&m->arg, &m->type);
bd76d25d 161 ovsdb_type_destroy(&m->type);
e9f8f936
BP
162}
163
164struct ovsdb_error *
165ovsdb_mutation_set_from_json(const struct ovsdb_table_schema *ts,
166 const struct json *json,
fbf925e4 167 struct ovsdb_symbol_table *symtab,
e9f8f936
BP
168 struct ovsdb_mutation_set *set)
169{
170 const struct json_array *array = json_array(json);
171 size_t i;
172
173 set->mutations = xmalloc(array->n * sizeof *set->mutations);
174 set->n_mutations = 0;
175 for (i = 0; i < array->n; i++) {
176 struct ovsdb_error *error;
177 error = ovsdb_mutation_from_json(ts, array->elems[i], symtab,
178 &set->mutations[i]);
179 if (error) {
180 ovsdb_mutation_set_destroy(set);
181 set->mutations = NULL;
182 set->n_mutations = 0;
183 return error;
184 }
185 set->n_mutations++;
186 }
187
188 return NULL;
189}
190
191static struct json *
192ovsdb_mutation_to_json(const struct ovsdb_mutation *m)
193{
194 return json_array_create_3(
195 json_string_create(m->column->name),
196 json_string_create(ovsdb_mutator_to_string(m->mutator)),
197 ovsdb_datum_to_json(&m->arg, &m->type));
198}
199
200struct json *
201ovsdb_mutation_set_to_json(const struct ovsdb_mutation_set *set)
202{
203 struct json **mutations;
204 size_t i;
205
206 mutations = xmalloc(set->n_mutations * sizeof *mutations);
207 for (i = 0; i < set->n_mutations; i++) {
208 mutations[i] = ovsdb_mutation_to_json(&set->mutations[i]);
209 }
210 return json_array_create(mutations, set->n_mutations);
211}
212
213void
214ovsdb_mutation_set_destroy(struct ovsdb_mutation_set *set)
215{
216 size_t i;
217
218 for (i = 0; i < set->n_mutations; i++) {
219 ovsdb_mutation_free(&set->mutations[i]);
220 }
221 free(set->mutations);
222}
bd76d25d
BP
223\f
224enum ovsdb_mutation_scalar_error {
225 ME_OK,
226 ME_DOM,
227 ME_RANGE
228};
229
230struct ovsdb_scalar_mutation {
231 int (*mutate_integer)(int64_t *x, int64_t y);
232 int (*mutate_real)(double *x, double y);
233 enum ovsdb_mutator mutator;
234};
235
236static const struct ovsdb_scalar_mutation add_mutation;
237static const struct ovsdb_scalar_mutation sub_mutation;
238static const struct ovsdb_scalar_mutation mul_mutation;
239static const struct ovsdb_scalar_mutation div_mutation;
240static const struct ovsdb_scalar_mutation mod_mutation;
241
242static struct ovsdb_error *
243ovsdb_mutation_scalar_error(enum ovsdb_mutation_scalar_error error,
244 enum ovsdb_mutator mutator)
245{
246 switch (error) {
247 case ME_OK:
248 return OVSDB_BUG("unexpected success");
249
250 case ME_DOM:
251 return ovsdb_error("domain error", "Division by zero.");
252
253 case ME_RANGE:
254 return ovsdb_error("range error",
255 "Result of \"%s\" operation is out of range.",
256 ovsdb_mutator_to_string(mutator));
257
258 default:
259 return OVSDB_BUG("unexpected error");
260 }
261}
262
263static int
264check_real_range(double x)
265{
266 return x >= -DBL_MAX && x <= DBL_MAX ? 0 : ME_RANGE;
267}
268
269static struct ovsdb_error *
270mutate_scalar(const struct ovsdb_type *dst_type, struct ovsdb_datum *dst,
271 const union ovsdb_atom *arg,
272 const struct ovsdb_scalar_mutation *mutation)
273{
274 const struct ovsdb_base_type *base = &dst_type->key;
275 struct ovsdb_error *error;
276 unsigned int i;
277
278 if (base->type == OVSDB_TYPE_INTEGER) {
279 int64_t y = arg->integer;
280 for (i = 0; i < dst->n; i++) {
281 enum ovsdb_mutation_scalar_error me;
282
283 me = (mutation->mutate_integer)(&dst->keys[i].integer, y);
284 if (me != ME_OK) {
285 return ovsdb_mutation_scalar_error(me, mutation->mutator);
286 }
287 }
288 } else if (base->type == OVSDB_TYPE_REAL) {
289 double y = arg->real;
290 for (i = 0; i < dst->n; i++) {
291 double *x = &dst->keys[i].real;
292 enum ovsdb_mutation_scalar_error me;
293
294 me = (mutation->mutate_real)(x, y);
295 if (me == ME_OK) {
296 me = check_real_range(*x);
297 }
298 if (me != ME_OK) {
299 return ovsdb_mutation_scalar_error(me, mutation->mutator);
300 }
301 }
302 } else {
303 NOT_REACHED();
304 }
305
306 for (i = 0; i < dst->n; i++) {
307 error = ovsdb_atom_check_constraints(&dst->keys[i], base);
308 if (error) {
309 return error;
310 }
311 }
312
bfc96d9b 313 error = ovsdb_datum_sort(dst, dst_type->key.type);
bd76d25d
BP
314 if (error) {
315 ovsdb_error_destroy(error);
316 return ovsdb_error("constraint violation",
317 "Result of \"%s\" operation contains duplicates.",
318 ovsdb_mutator_to_string(mutation->mutator));
319 }
320 return NULL;
321}
322
323static struct ovsdb_error *
324ovsdb_mutation_check_count(struct ovsdb_datum *dst,
325 const struct ovsdb_type *dst_type)
326{
327 if (!ovsdb_datum_conforms_to_type(dst, dst_type)) {
328 char *s = ovsdb_type_to_english(dst_type);
329 struct ovsdb_error *e = ovsdb_error(
330 "constaint violation",
331 "Attempted to store %u elements in %s.", dst->n, s);
332 free(s);
333 return e;
334 }
335 return NULL;
336}
337
338struct ovsdb_error *
339ovsdb_mutation_set_execute(struct ovsdb_row *row,
340 const struct ovsdb_mutation_set *set)
341{
342 size_t i;
343
344 for (i = 0; i < set->n_mutations; i++) {
345 const struct ovsdb_mutation *m = &set->mutations[i];
346 struct ovsdb_datum *dst = &row->fields[m->column->index];
347 const struct ovsdb_type *dst_type = &m->column->type;
348 const struct ovsdb_datum *arg = &set->mutations[i].arg;
349 const struct ovsdb_type *arg_type = &m->type;
350 struct ovsdb_error *error;
351
352 switch (m->mutator) {
353 case OVSDB_M_ADD:
354 error = mutate_scalar(dst_type, dst, &arg->keys[0], &add_mutation);
355 break;
356
357 case OVSDB_M_SUB:
358 error = mutate_scalar(dst_type, dst, &arg->keys[0], &sub_mutation);
359 break;
360
361 case OVSDB_M_MUL:
362 error = mutate_scalar(dst_type, dst, &arg->keys[0], &mul_mutation);
363 break;
364
365 case OVSDB_M_DIV:
366 error = mutate_scalar(dst_type, dst, &arg->keys[0], &div_mutation);
367 break;
368
369 case OVSDB_M_MOD:
370 error = mutate_scalar(dst_type, dst, &arg->keys[0], &mod_mutation);
371 break;
e9f8f936 372
bd76d25d
BP
373 case OVSDB_M_INSERT:
374 ovsdb_datum_union(dst, arg, dst_type, false);
375 error = ovsdb_mutation_check_count(dst, dst_type);
376 break;
377
378 case OVSDB_M_DELETE:
379 ovsdb_datum_subtract(dst, dst_type, arg, arg_type);
380 error = ovsdb_mutation_check_count(dst, dst_type);
381 break;
8b71367c
BP
382
383 default:
384 NOT_REACHED();
bd76d25d
BP
385 }
386 if (error) {
387 return error;
388 }
389 }
390
391 return NULL;
392}
393\f
e9f8f936
BP
394static int
395add_int(int64_t *x, int64_t y)
396{
397 /* Check for overflow. See _Hacker's Delight_ pp. 27. */
398 int64_t z = ~(*x ^ y) & INT64_MIN;
399 if ((~(*x ^ y) & ~(((*x ^ z) + y) ^ y)) >> 63) {
400 return ME_RANGE;
401 } else {
402 *x += y;
403 return 0;
404 }
405}
406
407static int
408sub_int(int64_t *x, int64_t y)
409{
410 /* Check for overflow. See _Hacker's Delight_ pp. 27. */
411 int64_t z = (*x ^ y) & INT64_MIN;
412 if (((*x ^ y) & (((*x ^ z) - y) ^ y)) >> 63) {
413 return ME_RANGE;
414 } else {
415 *x -= y;
416 return 0;
417 }
418}
419
420static int
421mul_int(int64_t *x, int64_t y)
422{
423 /* Check for overflow. See _Hacker's Delight_ pp. 30. */
424 if (*x > 0
425 ? (y > 0
426 ? *x >= INT64_MAX / y
427 : y < INT64_MIN / *x)
428 : (y > 0
429 ? *x < INT64_MIN / y
430 : *x != 0 && y < INT64_MAX / y)) {
431 return ME_RANGE;
432 } else {
433 *x *= y;
434 return 0;
435 }
436}
437
438static int
439check_int_div(int64_t x, int64_t y)
440{
441 /* Check for overflow. See _Hacker's Delight_ pp. 32. */
442 if (!y) {
443 return ME_DOM;
444 } else if (x == INT64_MIN && y == -1) {
445 return ME_RANGE;
446 } else {
447 return 0;
448 }
449}
450
451static int
452div_int(int64_t *x, int64_t y)
453{
454 int error = check_int_div(*x, y);
455 if (!error) {
456 *x /= y;
457 }
458 return error;
459}
460
461static int
462mod_int(int64_t *x, int64_t y)
463{
464 int error = check_int_div(*x, y);
465 if (!error) {
466 *x %= y;
467 }
468 return error;
469}
470
e9f8f936
BP
471static int
472add_double(double *x, double y)
473{
474 *x += y;
475 return 0;
476}
477
478static int
479sub_double(double *x, double y)
480{
481 *x -= y;
482 return 0;
483}
484
485static int
486mul_double(double *x, double y)
487{
488 *x *= y;
489 return 0;
490}
491
492static int
493div_double(double *x, double y)
494{
495 if (y == 0) {
496 return ME_DOM;
497 } else {
498 *x /= y;
499 return 0;
500 }
501}
502
bd76d25d
BP
503static const struct ovsdb_scalar_mutation add_mutation = {
504 add_int, add_double, OVSDB_M_ADD
505};
e9f8f936 506
bd76d25d
BP
507static const struct ovsdb_scalar_mutation sub_mutation = {
508 sub_int, sub_double, OVSDB_M_SUB
509};
e9f8f936 510
bd76d25d
BP
511static const struct ovsdb_scalar_mutation mul_mutation = {
512 mul_int, mul_double, OVSDB_M_MUL
513};
e9f8f936 514
bd76d25d
BP
515static const struct ovsdb_scalar_mutation div_mutation = {
516 div_int, div_double, OVSDB_M_DIV
517};
e9f8f936 518
bd76d25d
BP
519static const struct ovsdb_scalar_mutation mod_mutation = {
520 mod_int, NULL, OVSDB_M_MOD
521};