static struct ovsdb_error * parse_optional_uint(struct ovsdb_parser *parser, const char *member, unsigned int *uint) { const struct json *json; json = ovsdb_parser_member(parser, member, OP_INTEGER | OP_OPTIONAL); if (json) { if (json->u.integer < 0 || json->u.integer > UINT_MAX) { return ovsdb_syntax_error(json, NULL, "%s out of valid range 0 to %u", member, UINT_MAX); } *uint = json->u.integer; } return NULL; }
struct json * ovsdb_execute(struct ovsdb *db, const struct ovsdb_session *session, const struct json *params, long long int elapsed_msec, long long int *timeout_msec) { struct ovsdb_execution x; struct ovsdb_error *error; struct json *results; size_t n_operations; size_t i; if (params->type != JSON_ARRAY || !params->u.array.n || params->u.array.elems[0]->type != JSON_STRING || strcmp(params->u.array.elems[0]->u.string, db->schema->name)) { if (params->type != JSON_ARRAY) { error = ovsdb_syntax_error(params, NULL, "array expected"); } else { error = ovsdb_syntax_error(params, NULL, "database name expected " "as first parameter"); } results = ovsdb_error_to_json(error); ovsdb_error_destroy(error); return results; } x.db = db; x.session = session; x.txn = ovsdb_txn_create(db); x.symtab = ovsdb_symbol_table_create(); x.durable = false; x.elapsed_msec = elapsed_msec; x.timeout_msec = LLONG_MAX; results = NULL; results = json_array_create_empty(); n_operations = params->u.array.n - 1; error = NULL; for (i = 1; i <= n_operations; i++) { struct json *operation = params->u.array.elems[i]; struct ovsdb_error *parse_error; struct ovsdb_parser parser; struct json *result; const struct json *op; /* Parse and execute operation. */ ovsdb_parser_init(&parser, operation, "ovsdb operation %"PRIuSIZE" of %"PRIuSIZE, i, n_operations); op = ovsdb_parser_member(&parser, "op", OP_ID); result = json_object_create(); if (op) { const char *op_name = json_string(op); ovsdb_operation_executor *executor = lookup_executor(op_name); if (executor) { error = executor(&x, &parser, result); } else { ovsdb_parser_raise_error(&parser, "No operation \"%s\"", op_name); } } else { ovs_assert(ovsdb_parser_has_error(&parser)); } /* A parse error overrides any other error. * An error overrides any other result. */ parse_error = ovsdb_parser_finish(&parser); if (parse_error) { ovsdb_error_destroy(error); error = parse_error; } if (error) { json_destroy(result); result = ovsdb_error_to_json(error); } if (error && !strcmp(ovsdb_error_get_tag(error), "not supported") && timeout_msec) { ovsdb_txn_abort(x.txn); *timeout_msec = x.timeout_msec; json_destroy(result); json_destroy(results); results = NULL; goto exit; } /* Add result to array. */ json_array_add(results, result); if (error) { break; } } if (!error) { error = ovsdb_txn_commit(x.txn, x.durable); if (error) { json_array_add(results, ovsdb_error_to_json(error)); } } else { ovsdb_txn_abort(x.txn); } while (json_array(results)->n < n_operations) { json_array_add(results, json_null_create()); } exit: ovsdb_error_destroy(error); ovsdb_symbol_table_destroy(x.symtab); return results; }
} exit: ovsdb_error_destroy(error); ovsdb_symbol_table_destroy(x.symtab); return results; } static struct ovsdb_error * ovsdb_execute_commit(struct ovsdb_execution *x, struct ovsdb_parser *parser, struct json *result OVS_UNUSED) { const struct json *durable; durable = ovsdb_parser_member(parser, "durable", OP_BOOLEAN); if (durable && json_boolean(durable)) { x->durable = true; } return NULL; } static struct ovsdb_error * ovsdb_execute_abort(struct ovsdb_execution *x OVS_UNUSED, struct ovsdb_parser *parser OVS_UNUSED, struct json *result OVS_UNUSED) { return ovsdb_error("aborted", "aborted by request"); } static struct ovsdb_table *
struct ovsdb_error * ovsdb_type_from_json(struct ovsdb_type *type, const struct json *json) { ovsdb_base_type_init(&type->value, OVSDB_TYPE_VOID); type->n_min = 1; type->n_max = 1; if (json->type == JSON_STRING) { return ovsdb_base_type_from_json(&type->key, json); } else if (json->type == JSON_OBJECT) { const struct json *key, *value, *min, *max; struct ovsdb_error *error; struct ovsdb_parser parser; ovsdb_parser_init(&parser, json, "ovsdb type"); key = ovsdb_parser_member(&parser, "key", OP_STRING | OP_OBJECT); value = ovsdb_parser_member(&parser, "value", OP_STRING | OP_OBJECT | OP_OPTIONAL); min = ovsdb_parser_member(&parser, "min", OP_INTEGER | OP_OPTIONAL); max = ovsdb_parser_member(&parser, "max", OP_INTEGER | OP_STRING | OP_OPTIONAL); error = ovsdb_parser_finish(&parser); if (error) { return error; } error = ovsdb_base_type_from_json(&type->key, key); if (error) { return error; } if (value) { error = ovsdb_base_type_from_json(&type->value, value); if (error) { return error; } } error = n_from_json(min, &type->n_min); if (error) { return error; } if (max && max->type == JSON_STRING && !strcmp(max->u.string, "unlimited")) { type->n_max = UINT_MAX; } else { error = n_from_json(max, &type->n_max); if (error) { return error; } } if (!ovsdb_type_is_valid(type)) { return ovsdb_syntax_error(json, NULL, "ovsdb type fails constraint checks"); } return NULL; } else { return ovsdb_syntax_error(json, NULL, "ovsdb type expected"); } }
struct ovsdb_error * ovsdb_base_type_from_json(struct ovsdb_base_type *base, const struct json *json) { struct ovsdb_parser parser; struct ovsdb_error *error; const struct json *type, *enum_; if (json->type == JSON_STRING) { error = ovsdb_atomic_type_from_json(&base->type, json); if (error) { return error; } ovsdb_base_type_init(base, base->type); return NULL; } ovsdb_parser_init(&parser, json, "ovsdb type"); type = ovsdb_parser_member(&parser, "type", OP_STRING); if (ovsdb_parser_has_error(&parser)) { base->type = OVSDB_TYPE_VOID; return ovsdb_parser_finish(&parser); } error = ovsdb_atomic_type_from_json(&base->type, type); if (error) { return error; } ovsdb_base_type_init(base, base->type); enum_ = ovsdb_parser_member(&parser, "enum", OP_ANY | OP_OPTIONAL); if (enum_) { base->enum_ = xmalloc(sizeof *base->enum_); error = ovsdb_datum_from_json( base->enum_, ovsdb_base_type_get_enum_type(base->type), enum_, NULL); if (error) { free(base->enum_); base->enum_ = NULL; } } else if (base->type == OVSDB_TYPE_INTEGER) { const struct json *min, *max; min = ovsdb_parser_member(&parser, "minInteger", OP_INTEGER | OP_OPTIONAL); max = ovsdb_parser_member(&parser, "maxInteger", OP_INTEGER | OP_OPTIONAL); base->u.integer.min = min ? min->u.integer : INT64_MIN; base->u.integer.max = max ? max->u.integer : INT64_MAX; if (base->u.integer.min > base->u.integer.max) { error = ovsdb_syntax_error(json, NULL, "minInteger exceeds maxInteger"); } } else if (base->type == OVSDB_TYPE_REAL) { const struct json *min, *max; min = ovsdb_parser_member(&parser, "minReal", OP_NUMBER | OP_OPTIONAL); max = ovsdb_parser_member(&parser, "maxReal", OP_NUMBER | OP_OPTIONAL); base->u.real.min = min ? json_real(min) : -DBL_MAX; base->u.real.max = max ? json_real(max) : DBL_MAX; if (base->u.real.min > base->u.real.max) { error = ovsdb_syntax_error(json, NULL, "minReal exceeds maxReal"); } } else if (base->type == OVSDB_TYPE_STRING) { if (!error) { error = parse_optional_uint(&parser, "minLength", &base->u.string.minLen); } if (!error) { error = parse_optional_uint(&parser, "maxLength", &base->u.string.maxLen); } if (!error && base->u.string.minLen > base->u.string.maxLen) { error = ovsdb_syntax_error(json, NULL, "minLength exceeds maxLength"); } } else if (base->type == OVSDB_TYPE_UUID) { const struct json *refTable; refTable = ovsdb_parser_member(&parser, "refTable", OP_ID | OP_OPTIONAL); if (refTable) { const struct json *refType; base->u.uuid.refTableName = xstrdup(refTable->u.string); /* We can't set base->u.uuid.refTable here because we don't have * enough context (we might not even be running in ovsdb-server). * ovsdb_create() will set refTable later. */ refType = ovsdb_parser_member(&parser, "refType", OP_ID | OP_OPTIONAL); if (refType) { const char *refType_s = json_string(refType); if (!strcmp(refType_s, "strong")) { base->u.uuid.refType = OVSDB_REF_STRONG; } else if (!strcmp(refType_s, "weak")) { base->u.uuid.refType = OVSDB_REF_WEAK; } else { error = ovsdb_syntax_error(json, NULL, "refType must be " "\"strong\" or \"weak\" (not " "\"%s\")", refType_s); } } else { base->u.uuid.refType = OVSDB_REF_STRONG; } } } if (error) { ovsdb_error_destroy(ovsdb_parser_finish(&parser)); } else { error = ovsdb_parser_finish(&parser); } if (error) { ovsdb_base_type_destroy(base); base->type = OVSDB_TYPE_VOID; } return error; }