[ovs-dev] ovn-northd: ovsdb idl question
Lance Richardson
lrichard at redhat.com
Tue Dec 20 21:24:25 UTC 2016
> From: "Lance Richardson" <lrichard at redhat.com>
> To: "ovs dev" <dev at openvswitch.org>
> Sent: Tuesday, December 20, 2016 1:59:02 PM
> Subject: [ovs-dev] ovn-northd: ovsdb idl question
>
> I've been investigating a crash in ovn-northd. This is very easy to
> reproduce by inserting a row into the NB Logical_Switch_Port table
> without setting the "name" column, e.g.:
>
> ovn-nbctl ls-add ls0
> ovn-nbctl --id=@foo create logical_switch_port type='localnet' -- add
> logical_switch ls0 ports @foo
>
> This leads to a null pointer dereference when sb->logical_port is
> dereferenced in update_logical_port_status().
>
> The reason sb->logical_port is NULL is somewhat interesting.
> In build_ports(), the sb port binding record is created via:
>
> op->sb = sbrec_port_binding_insert(ctx->ovnsb_txn);
> sbrec_port_binding_set_logical_port(op->sb, op->key);
>
> After which op->sb->logical_port is NULL (since op->key
> is an empty string (""), not NULL, I would have expected
> op->sb->logical_port to also be non-NULL, however ovsdb_idl_txn_write__()
> (called by sbrec_port_binding_set_logical_port()) returns
> without having modified op->sb->logical port because of this optimization:
>
> if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
> datum, &column->type)) {
> goto discard_datum;
> }
>
> In this case, write_only is true (mode for the column is OVSDB_IDL_MONITOR),
> and ovsdb_datum_equals() is true because datum->key is "", which
> is compared against "" because the column is uninitialized
> (ovsdb_atom_default()
> is "" for string type), so ovsdb_idl_txn_write__() returns without
> having updated the local_port field, and it remains set to NULL.
>
>
> Hopefully the above makes sense... now for the question I'm struggling
> with: what is the best way to address the ovn-northd crash in this
> scenario. Some options seem to be:
>
> 1) Simply document that NB Logical_Switch_Port records have
> to be created with the "name" field initialized. This seems
> like a poor option unless there's some way to enforce this
> requirement.
> 2) Sprinkle checks for sb->local_port == NULL where necessary
> to avoid the crash. This also seems like a non-ideal
> solution, particularly since there may be other tables/columns
> where this issue can be hit.
> 3) Have ovsdb_idl_txn_write__() distinguish between NULL and empty
> string where ovsdb_datum_equal() is used.
> 4) Maybe there's another option? (Quite possible, I'm far from
> being able to claim a good understanding of the IDL).
>
> Any advice appreciated!
>
> Thanks,
>
> Lance
Thinking about (3) a little more, how about this:
diff --git a/lib/ovsdb-idl.c b/lib/ovsdb-idl.c
index 8ce228d..784e5cc 100644
--- a/lib/ovsdb-idl.c
+++ b/lib/ovsdb-idl.c
@@ -3242,8 +3242,10 @@ ovsdb_idl_txn_write__(const struct ovsdb_idl_row *row_,
* transaction only does writes of existing values, without making any real
* changes, we will drop the whole transaction later in
* ovsdb_idl_txn_commit().) */
- if (write_only && ovsdb_datum_equals(ovsdb_idl_read(row, column),
- datum, &column->type)) {
+ if (write_only && ((row->written && bitmap_is_set(row->written,
+ column_idx)) || row->old) &&
+ ovsdb_datum_equals(ovsdb_idl_read(row, column),
+ datum, &column->type)) {
goto discard_datum;
}
More information about the dev
mailing list