2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-22 01:51:26 +00:00
ovs/ovsdb/ovsdb-util.c
Ilya Maximets 6c48b29f52 json: Always use the json_string() method to access the strings.
We'll be changing the way strings are stored, so the direct access
will not be safe anymore.  Change all the users to use the proper
API as they should have been doing anyway.  This also means splitting
the handling of strings and serialized objects in most cases as
they will be treated differently.

The only code outside of json implementation for which direct access
is preserved is substitute_uuids() in test-ovsdb.c.  It's an unusual
string manipulation that is only needed for the testing, so doesn't
seem worthy adding a new API function.  We could introduce something
like json_string_replace() if this use case will appear somewhere
else in the future.

Acked-by: Mike Pattrick <mkp@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
2025-06-30 16:53:56 +02:00

327 lines
10 KiB
C

/* Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <config.h>
#include "row.h"
#include "sset.h"
#include "table.h"
#include "ovsdb-util.h"
#include "openvswitch/vlog.h"
VLOG_DEFINE_THIS_MODULE(ovsdb_util);
void
ovsdb_util_clear_column(struct ovsdb_row *row, const char *column_name)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
const struct ovsdb_table_schema *schema = row->table->schema;
const struct ovsdb_column *column;
column = ovsdb_table_schema_get_column(schema, column_name);
if (!column) {
VLOG_DBG_RL(&rl, "Table `%s' has no `%s' column",
schema->name, column_name);
return;
}
if (column->type.n_min) {
if (!VLOG_DROP_DBG(&rl)) {
char *type_name = ovsdb_type_to_english(&column->type);
VLOG_DBG("Table `%s' column `%s' has type %s, which requires "
"a value, but an attempt was made to clear it",
schema->name, column_name, type_name);
free(type_name);
}
return;
}
struct ovsdb_datum *datum = &row->fields[column->index];
if (datum->n) {
ovsdb_datum_destroy(datum, &column->type);
ovsdb_datum_init_empty(datum);
}
}
struct ovsdb_datum *
ovsdb_util_get_datum(struct ovsdb_row *row, const char *column_name,
const enum ovsdb_atomic_type key_type,
const enum ovsdb_atomic_type value_type,
const size_t n_max)
{
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
const struct ovsdb_table_schema *schema = row->table->schema;
const struct ovsdb_column *column;
column = ovsdb_table_schema_get_column(schema, column_name);
if (!column) {
VLOG_DBG_RL(&rl, "Table `%s' has no `%s' column",
schema->name, column_name);
return NULL;
}
if (column->type.key.type != key_type
|| column->type.value.type != value_type
|| column->type.n_max != n_max) {
if (!VLOG_DROP_DBG(&rl)) {
char *type_name = ovsdb_type_to_english(&column->type);
VLOG_DBG("Table `%s' column `%s' has type %s, not expected "
"key type %s, value type %s, max elements %"PRIuSIZE".",
schema->name, column_name, type_name,
ovsdb_atomic_type_to_string(key_type),
ovsdb_atomic_type_to_string(value_type),
n_max);
free(type_name);
}
return NULL;
}
return &row->fields[column->index];
}
/* Read string-string key-values from a map. Returns the value associated with
* 'key', if found, or NULL */
const char *
ovsdb_util_read_map_string_column(const struct ovsdb_row *row,
const char *column_name,
const char *key)
{
const struct ovsdb_datum *datum;
union ovsdb_atom *atom_key = NULL, *atom_value = NULL;
size_t i;
datum = ovsdb_util_get_datum(CONST_CAST(struct ovsdb_row *, row),
column_name, OVSDB_TYPE_STRING,
OVSDB_TYPE_STRING, UINT_MAX);
if (!datum) {
return NULL;
}
for (i = 0; i < datum->n; i++) {
atom_key = &datum->keys[i];
if (!strcmp(json_string(atom_key->s), key)) {
atom_value = &datum->values[i];
break;
}
}
return atom_value ? json_string(atom_value->s) : NULL;
}
/* Read string-uuid key-values from a map. Returns the row associated with
* 'key', if found, or NULL */
const struct ovsdb_row *
ovsdb_util_read_map_string_uuid_column(const struct ovsdb_row *row,
const char *column_name,
const char *key)
{
const struct ovsdb_column *column
= ovsdb_table_schema_get_column(row->table->schema, column_name);
if (!column ||
column->type.key.type != OVSDB_TYPE_STRING ||
column->type.value.type != OVSDB_TYPE_UUID) {
return NULL;
}
const struct ovsdb_table *ref_table = column->type.value.uuid.refTable;
if (!ref_table) {
return NULL;
}
const struct ovsdb_datum *datum = &row->fields[column->index];
for (size_t i = 0; i < datum->n; i++) {
union ovsdb_atom *atom_key = &datum->keys[i];
if (!strcmp(json_string(atom_key->s), key)) {
const union ovsdb_atom *atom_value = &datum->values[i];
return ovsdb_table_get_row(ref_table, &atom_value->uuid);
}
}
return NULL;
}
const union ovsdb_atom *
ovsdb_util_read_column(const struct ovsdb_row *row, const char *column_name,
enum ovsdb_atomic_type type)
{
const struct ovsdb_datum *datum;
datum = ovsdb_util_get_datum(CONST_CAST(struct ovsdb_row *, row),
column_name, type, OVSDB_TYPE_VOID, 1);
return datum && datum->n ? datum->keys : NULL;
}
bool
ovsdb_util_read_integer_column(const struct ovsdb_row *row,
const char *column_name,
long long int *integerp)
{
const union ovsdb_atom *atom;
atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_INTEGER);
*integerp = atom ? atom->integer : 0;
return atom != NULL;
}
bool
ovsdb_util_read_string_column(const struct ovsdb_row *row,
const char *column_name, const char **stringp)
{
const union ovsdb_atom *atom;
atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_STRING);
*stringp = atom ? json_string(atom->s) : NULL;
return atom != NULL;
}
bool
ovsdb_util_read_bool_column(const struct ovsdb_row *row,
const char *column_name, bool *boolp)
{
const union ovsdb_atom *atom;
atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_BOOLEAN);
*boolp = atom ? atom->boolean : false;
return atom != NULL;
}
bool
ovsdb_util_read_uuid_column(const struct ovsdb_row *row,
const char *column_name, struct uuid *uuid)
{
const union ovsdb_atom *atom;
atom = ovsdb_util_read_column(row, column_name, OVSDB_TYPE_UUID);
*uuid = atom ? atom->uuid : UUID_ZERO;
return atom != NULL;
}
static void
ovsdb_util_write_singleton(struct ovsdb_row *row, const char *column_name,
const union ovsdb_atom *atom,
enum ovsdb_atomic_type type)
{
const struct ovsdb_column *column;
struct ovsdb_datum *datum;
column = ovsdb_table_schema_get_column(row->table->schema, column_name);
datum = ovsdb_util_get_datum(row, column_name, type, OVSDB_TYPE_VOID, 1);
if (!datum) {
return;
}
ovsdb_datum_unshare(datum, &column->type);
if (datum->n == 1) {
if (ovsdb_atom_equals(&datum->keys[0], atom, type)) {
return;
}
ovsdb_atom_destroy(&datum->keys[0], type);
} else {
ovsdb_datum_destroy(datum, &column->type);
datum->n = 1;
datum->keys = xmalloc(sizeof *datum->keys);
datum->values = NULL;
datum->refcnt = NULL;
}
ovsdb_atom_clone(&datum->keys[0], atom, type);
}
void
ovsdb_util_write_integer_column(struct ovsdb_row *row,
const char *column_name,
long long int integer)
{
const union ovsdb_atom atom = { .integer = integer };
ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_INTEGER);
}
void
ovsdb_util_write_bool_column(struct ovsdb_row *row, const char *column_name,
bool value)
{
const union ovsdb_atom atom = { .boolean = value };
ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_BOOLEAN);
}
void
ovsdb_util_write_uuid_column(struct ovsdb_row *row, const char *column_name,
const struct uuid *uuid)
{
if (uuid) {
const union ovsdb_atom atom = { .uuid = *uuid };
ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_UUID);
} else {
ovsdb_util_clear_column(row, column_name);
}
}
void
ovsdb_util_write_string_column(struct ovsdb_row *row, const char *column_name,
const char *string)
{
if (string) {
union ovsdb_atom atom = {
.s = ovsdb_atom_string_create(CONST_CAST(char *, string)) };
ovsdb_util_write_singleton(row, column_name, &atom, OVSDB_TYPE_STRING);
ovsdb_atom_destroy(&atom, OVSDB_TYPE_STRING);
} else {
ovsdb_util_clear_column(row, column_name);
}
}
void
ovsdb_util_write_string_string_column(struct ovsdb_row *row,
const char *column_name,
char **keys, char **values, size_t n)
{
const struct ovsdb_column *column;
struct ovsdb_datum *datum;
size_t i;
column = ovsdb_table_schema_get_column(row->table->schema, column_name);
if (!column) {
VLOG_WARN("No %s column present in the %s table",
column_name, row->table->schema->name);
goto unwind;
}
datum = ovsdb_util_get_datum(row, column_name, OVSDB_TYPE_STRING,
OVSDB_TYPE_STRING, UINT_MAX);
if (!datum) {
unwind:
for (i = 0; i < n; i++) {
free(keys[i]);
free(values[i]);
}
return;
}
/* Free existing data. */
ovsdb_datum_destroy(datum, &column->type);
/* Allocate space for new values. */
datum->n = n;
datum->keys = xmalloc(n * sizeof *datum->keys);
datum->values = xmalloc(n * sizeof *datum->values);
datum->refcnt = NULL;
for (i = 0; i < n; ++i) {
datum->keys[i].s = ovsdb_atom_string_create_nocopy(keys[i]);
datum->values[i].s = ovsdb_atom_string_create_nocopy(values[i]);
}
/* Sort and check constraints. */
ovsdb_datum_sort_assert(datum, &column->type);
}