Skip to content

Commit

Permalink
ovsdb-idl: Add the support to specify the uuid for row insert.
Browse files Browse the repository at this point in the history
ovsdb-server allows the OVSDB clients to specify the uuid for
the row inserts [1].  Both the C IDL client library and Python
IDL are missing this feature.  This patch adds this support.

In C IDL, for each schema table, a new function is generated -
<schema_table>insert_persistent_uuid(txn, uuid) which can
be used the clients to persist the uuid.

ovs-vsctl and other derivatives of ctl now supports the same
in the generic 'create' command with the option "--id=<UUID>".

In Python IDL, the uuid to persist can be specified in
the Transaction.insert() function.

[1] - a529e3c("ovsdb-server: Allow OVSDB clients to specify the UUID for inserted rows.:)

Acked-by: Adrian Moreno <[email protected]>
Acked-by: Han Zhou <[email protected]>
Acked-by: Terry Wilson <[email protected]>
Signed-off-by: Numan Siddique <[email protected]>
Signed-off-by: Ilya Maximets <[email protected]>
  • Loading branch information
numansiddique authored and igsilya committed Nov 30, 2022
1 parent 954ae38 commit 55b9507
Show file tree
Hide file tree
Showing 13 changed files with 263 additions and 50 deletions.
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Post-v3.0.0
- ovs-appctl:
* "ovs-appctl ofproto/trace" command can now display port names with the
"--names" option.
- OVSDB-IDL:
* Add the support to specify the persistent uuid for row insert in both
C and Python IDLs.
- Windows:
* Conntrack IPv6 fragment support.
- DPDK:
Expand Down
38 changes: 26 additions & 12 deletions lib/db-ctl-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -1731,29 +1731,43 @@ cmd_create(struct ctl_context *ctx)
const struct ovsdb_idl_table_class *table;
const struct ovsdb_idl_row *row;
const struct uuid *uuid = NULL;
bool persist_uuid = false;
struct uuid uuid_;
int i;

ctx->error = get_table(table_name, &table);
if (ctx->error) {
return;
}

if (id) {
struct ovsdb_symbol *symbol = NULL;
if (uuid_from_string(&uuid_, id)) {
uuid = &uuid_;
persist_uuid = true;
} else {
struct ovsdb_symbol *symbol = NULL;

ctx->error = create_symbol(ctx->symtab, id, &symbol, NULL);
if (ctx->error) {
return;
}
if (table->is_root) {
/* This table is in the root set, meaning that rows created in it
* won't disappear even if they are unreferenced, so disable
* warnings about that by pretending that there is a reference. */
symbol->strong_ref = true;
ctx->error = create_symbol(ctx->symtab, id, &symbol, NULL);
if (ctx->error) {
return;
}
if (table->is_root) {
/* This table is in the root set, meaning that rows created in
* it won't disappear even if they are unreferenced, so disable
* warnings about that by pretending that there is a
* reference. */
symbol->strong_ref = true;
}
uuid = &symbol->uuid;
}
uuid = &symbol->uuid;
}

row = ovsdb_idl_txn_insert(ctx->txn, table, uuid);
if (persist_uuid) {
row = ovsdb_idl_txn_insert_persist_uuid(ctx->txn, table, uuid);
} else {
row = ovsdb_idl_txn_insert(ctx->txn, table, uuid);
}

for (i = 2; i < ctx->argc; i++) {
ctx->error = set_column(table, row, ctx->argv[i], ctx->symtab);
if (ctx->error) {
Expand Down
5 changes: 4 additions & 1 deletion lib/db-ctl-base.man
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ Without \fB\-\-if-exists\fR, it is an error if \fIrecord\fR does not
exist. With \fB\-\-if-exists\fR, this command does nothing if
\fIrecord\fR does not exist.
.
.IP "[\fB\-\-id=@\fIname\fR] \fBcreate\fR \fItable column\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR..."
.IP "[\fB\-\-id=(@\fIname\fR | \fIuuid\fR] \fBcreate\fR \fItable column\fR[\fB:\fIkey\fR]\fB=\fIvalue\fR..."
Creates a new record in \fItable\fR and sets the initial values of
each \fIcolumn\fR. Columns not explicitly set will receive their
default values. Outputs the UUID of the new row.
Expand All @@ -212,6 +212,9 @@ If \fB@\fIname\fR is specified, then the UUID for the new row may be
referred to by that name elsewhere in the same \fB\*(PN\fR
invocation in contexts where a UUID is expected. Such references may
precede or follow the \fBcreate\fR command.
.IP
If a valid \fIuuid\fR is specified, then it is used as the UUID
of the new row.
.
.RS
.IP "Caution (ovs-vsctl as example)"
Expand Down
6 changes: 5 additions & 1 deletion lib/db-ctl-base.xml
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@
</p>
</dd>

<dt>[<code>--id=@</code><var>name</var>] <code>create</code> <var>table column</var>[<code>:</code><var>key</var>]<code>=</code><var>value</var>...</dt>
<dt>[<code>--id=(@</code><var>name</var>|<var>uuid</var>)] <code>create</code> <var>table column</var>[<code>:</code><var>key</var>]<code>=</code><var>value</var>...</dt>
<dd>
<p>
Creates a new record in <var>table</var> and sets the initial values of
Expand All @@ -323,6 +323,10 @@
invocation in contexts where a UUID is expected. Such references may
precede or follow the <code>create</code> command.
</p>
<p>
If a valid <var>uuid</var> is specified, then it is used as the
UUID of the new row.
</p>
<dl>
<dt>Caution (ovs-vsctl as example)</dt>
<dd>
Expand Down
1 change: 1 addition & 0 deletions lib/ovsdb-idl-provider.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ struct ovsdb_idl_row {
struct ovs_list dst_arcs; /* Backward arcs (ovsdb_idl_arc.dst_node). */
struct ovsdb_idl_table *table; /* Containing table. */
struct ovsdb_datum *old_datum; /* Committed data (null if orphaned). */
bool persist_uuid; /* Persist 'uuid' during insert txn if set. */
bool parsed; /* Whether the row is parsed. */
struct ovs_list reparse_node; /* Rows that needs to be re-parsed due to
* insertion of a referenced row. */
Expand Down
85 changes: 62 additions & 23 deletions lib/ovsdb-idl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2855,11 +2855,14 @@ substitute_uuids(struct json *json, const struct ovsdb_idl_txn *txn)

row = ovsdb_idl_txn_get_row(txn, &uuid);
if (row && !row->old_datum && row->new_datum) {
json_destroy(json);

return json_array_create_2(
json_string_create("named-uuid"),
json_string_create_nocopy(ovsdb_data_row_name(&uuid)));
if (row->persist_uuid) {
return json;
} else {
json_destroy(json);
return json_array_create_2(
json_string_create("named-uuid"),
json_string_create_nocopy(ovsdb_data_row_name(&uuid)));
}
}
}

Expand Down Expand Up @@ -3284,9 +3287,19 @@ ovsdb_idl_txn_commit(struct ovsdb_idl_txn *txn)

any_updates = true;

json_object_put(op, "uuid-name",
json_string_create_nocopy(
ovsdb_data_row_name(&row->uuid)));
char *uuid_json;
struct json *value;
if (row->persist_uuid) {
uuid_json = "uuid";
value = json_string_create_nocopy(
xasprintf(UUID_FMT, UUID_ARGS(&row->uuid)));
} else {
uuid_json = "uuid-name";
value = json_string_create_nocopy(
ovsdb_data_row_name(&row->uuid));
}

json_object_put(op, uuid_json, value);

insert = xmalloc(sizeof *insert);
insert->dummy = row->uuid;
Expand Down Expand Up @@ -3770,6 +3783,31 @@ ovsdb_idl_txn_delete(const struct ovsdb_idl_row *row_)
row->new_datum = NULL;
}

static const struct ovsdb_idl_row *
ovsdb_idl_txn_insert__(struct ovsdb_idl_txn *txn,
const struct ovsdb_idl_table_class *class,
const struct uuid *uuid,
bool persist_uuid)
{
struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);

ovs_assert(uuid || !persist_uuid);
if (uuid) {
ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
row->uuid = *uuid;
} else {
uuid_generate(&row->uuid);
}
row->persist_uuid = persist_uuid;
row->table = ovsdb_idl_table_from_class(txn->idl, class);
row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
ovsdb_idl_add_to_indexes(row);

return row;
}

/* Inserts and returns a new row in the table with the specified 'class' in the
* database with open transaction 'txn'.
*
Expand All @@ -3787,22 +3825,23 @@ ovsdb_idl_txn_insert(struct ovsdb_idl_txn *txn,
const struct ovsdb_idl_table_class *class,
const struct uuid *uuid)
{
struct ovsdb_idl_row *row = ovsdb_idl_row_create__(class);

if (uuid) {
ovs_assert(!ovsdb_idl_txn_get_row(txn, uuid));
row->uuid = *uuid;
} else {
uuid_generate(&row->uuid);
}

row->table = ovsdb_idl_table_from_class(txn->idl, class);
row->new_datum = xmalloc(class->n_columns * sizeof *row->new_datum);
hmap_insert(&row->table->rows, &row->hmap_node, uuid_hash(&row->uuid));
hmap_insert(&txn->txn_rows, &row->txn_node, uuid_hash(&row->uuid));
ovsdb_idl_add_to_indexes(row);
return ovsdb_idl_txn_insert__(txn, class, uuid, false);
}

return row;
/* Inserts and returns a new row in the table with the specified 'class' in the
* database with open transaction 'txn'.
*
* The new row is assigned the specified UUID (which cannot be null).
*
* Usually this function is used indirectly through one of the
* "insert_persist_uuid" functions generated by ovsdb-idlc. */
const struct ovsdb_idl_row *
ovsdb_idl_txn_insert_persist_uuid(struct ovsdb_idl_txn *txn,
const struct ovsdb_idl_table_class *class,
const struct uuid *uuid)
{
ovs_assert(uuid);
return ovsdb_idl_txn_insert__(txn, class, uuid, true);
}

static void
Expand Down
3 changes: 3 additions & 0 deletions lib/ovsdb-idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,9 @@ void ovsdb_idl_txn_delete(const struct ovsdb_idl_row *);
const struct ovsdb_idl_row *ovsdb_idl_txn_insert(
struct ovsdb_idl_txn *, const struct ovsdb_idl_table_class *,
const struct uuid *);
const struct ovsdb_idl_row *ovsdb_idl_txn_insert_persist_uuid(
struct ovsdb_idl_txn *txn, const struct ovsdb_idl_table_class *class,
const struct uuid *uuid);

struct ovsdb_idl *ovsdb_idl_txn_get_idl (struct ovsdb_idl_txn *);
void ovsdb_idl_get_initial_snapshot(struct ovsdb_idl *);
Expand Down
15 changes: 15 additions & 0 deletions ovsdb/ovsdb-idlc.in
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,8 @@ struct %(s)s *%(s)s_cursor_data(struct ovsdb_idl_cursor *);
void %(s)s_init(struct %(s)s *);
void %(s)s_delete(const struct %(s)s *);
struct %(s)s *%(s)s_insert(struct ovsdb_idl_txn *);
struct %(s)s *%(s)s_insert_persist_uuid(
struct ovsdb_idl_txn *txn, const struct uuid *uuid);

/* Returns true if the tracked column referenced by 'enum %(s)s_column_id' of
* the row referenced by 'struct %(s)s *' was updated since the last change
Expand Down Expand Up @@ -809,6 +811,19 @@ struct %(s)s *
return %(s)s_cast(ovsdb_idl_txn_insert(txn, &%(p)stable_%(tl)s, NULL));
}

/* Inserts and returns a new row in the table "%(t)s" in the database
* with open transaction 'txn'.
*
* The new row is assigned the UUID specified in the 'uuid' parameter
* (which cannot be null). ovsdb-server will try to assign the same
* UUID when 'txn' is committed. */
struct %(s)s *
%(s)s_insert_persist_uuid(struct ovsdb_idl_txn *txn, const struct uuid *uuid)
{
return %(s)s_cast(ovsdb_idl_txn_insert_persist_uuid(
txn, &%(p)stable_%(tl)s, uuid));
}

bool
%(s)s_is_updated(const struct %(s)s *row, enum %(s)s_column_id column)
{
Expand Down
26 changes: 18 additions & 8 deletions python/ovs/db/idl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ class Row(object):
d["a"] = "b"
row.mycolumn = d
"""
def __init__(self, idl, table, uuid, data):
def __init__(self, idl, table, uuid, data, persist_uuid=False):
# All of the explicit references to self.__dict__ below are required
# to set real attributes with invoking self.__getattr__().
self.__dict__["uuid"] = uuid
Expand Down Expand Up @@ -1278,6 +1278,10 @@ def __init__(self, idl, table, uuid, data):
# in the dictionary are all None.
self.__dict__["_prereqs"] = {}

# Indicates if the specified 'uuid' should be used as the row uuid
# or let the server generate it.
self.__dict__["_persist_uuid"] = persist_uuid

def __lt__(self, other):
if not isinstance(other, Row):
return NotImplemented
Expand Down Expand Up @@ -1816,7 +1820,11 @@ def commit(self):
op = {"table": row._table.name}
if row._data is None:
op["op"] = "insert"
op["uuid-name"] = _uuid_name_from_uuid(row.uuid)
if row._persist_uuid:
op["uuid"] = row.uuid
else:
op["uuid-name"] = _uuid_name_from_uuid(row.uuid)

any_updates = True

op_index = len(operations) - 1
Expand Down Expand Up @@ -2056,20 +2064,22 @@ def _write(self, row, column, datum):
row._mutations['_removes'].pop(column.name, None)
row._changes[column.name] = datum.copy()

def insert(self, table, new_uuid=None):
def insert(self, table, new_uuid=None, persist_uuid=False):
"""Inserts and returns a new row in 'table', which must be one of the
ovs.db.schema.TableSchema objects in the Idl's 'tables' dict.
The new row is assigned a provisional UUID. If 'uuid' is None then one
is randomly generated; otherwise 'uuid' should specify a randomly
generated uuid.UUID not otherwise in use. ovsdb-server will assign a
different UUID when 'txn' is committed, but the IDL will replace any
uses of the provisional UUID in the data to be to be committed by the
UUID assigned by ovsdb-server."""
generated uuid.UUID not otherwise in use. If 'persist_uuid' is true
and 'new_uuid' is specified, IDL requests the ovsdb-server to assign
the same UUID, otherwise ovsdb-server will assign a different UUID when
'txn' is committed and the IDL will replace any uses of the provisional
UUID in the data to be committed by the UUID assigned by
ovsdb-server."""
assert self._status == Transaction.UNCOMMITTED
if new_uuid is None:
new_uuid = uuid.uuid4()
row = Row(self.idl, table, new_uuid, None)
row = Row(self.idl, table, new_uuid, None, persist_uuid=persist_uuid)
table.rows[row.uuid] = row
self._txn_rows[row.uuid] = row
return row
Expand Down
25 changes: 25 additions & 0 deletions tests/ovs-vsctl.at
Original file line number Diff line number Diff line change
Expand Up @@ -1710,3 +1710,28 @@ ingress_policing_kpkts_rate: 100
])
OVS_VSCTL_CLEANUP
AT_CLEANUP

AT_SETUP([ovs-vsctl create bridge with uuid])
AT_KEYWORDS([create bridge with uuid])
OVS_VSCTL_SETUP

AT_CHECK([ovs-vsctl --no-wait --id=c5cc12f8-eaa1-43a7-8a73-bccd18df1111 create bridge \
name=tst0 -- add open . bridges c5cc12f8-eaa1-43a7-8a73-bccd18df1111], [0],[dnl
c5cc12f8-eaa1-43a7-8a73-bccd18df1111
])

AT_CHECK([ovs-vsctl --no-wait --id=c5cc12f8-eaa1-43a7-8a73-bccd18df1111 create bridge \
name=tst1 -- add open . bridges c5cc12f8-eaa1-43a7-8a73-bccd18df1111], [1], [ignore], [ignore])

AT_CHECK([ovs-vsctl --no-wait --bare --columns _uuid,name list bridge], [0], [dnl
c5cc12f8-eaa1-43a7-8a73-bccd18df1111
tst0
])

ovs-vsctl --no-wait --id=@a create bridge \
name=tst1 -- add open . bridges @a

AT_CHECK([ovs-vsctl --no-wait --bare --columns _uuid,name list bridge tst1], [0], [ignore])

OVS_VSCTL_CLEANUP
AT_CLEANUP
Loading

0 comments on commit 55b9507

Please sign in to comment.