On 6/12/25 10:01, Mark Michelson wrote:
On 6/11/25 02:53, Ales Musil wrote:On Fri, Jun 6, 2025 at 8:14 PM Mark Michelson via dev <[email protected] <mailto:[email protected]>> wrote:Prior to this commit, if you wanted to find the corresponding northbound UUID for a southbound Logical Datapath, you could find it in one of twoplaces: For logical switches, it was in external-ids:logical-switch. For logical routers, it was in external-ids:logical-router. With this commit, we are separating the type and UUID into separatefields. This way, no matter the type of the datapath, you can find theUUID. And you can find the type of the datapath without having to potentially check multiple external-ids keys to do so.These fields are going to be used pretty heavily by northd in upcomingpatches, so instead of making them external-ids, these are nowfull-fledged columns on the southbound Datapath_Binding. The UUID of the northbound logical datapath is in a column called "nb_uuid" and the type of the logical datapath is stored in an enumerated column called "type".Note that there is a seemingly-unrelated change in the check packet length test in tests/ovn.at <http://ovn.at>. This test started failing because its useof `grep` was picking up the new "nb_uuid" external-id accidentally. Thechange to the test uses `fetch_column` since it is more precise. Note 2: I attempted to make the new "nb_uuid" column type "UUID" but this caused an assertion in ovs's db-ctl-base.c file when running theovn-sbctl "invalid 0x flow" and "count-flows wrongDatapath" tests. This is because db-ctl-base.c is incapable of handling records other than oftype "int" or "string". The downside is that we have to use uuid_to_string() in order to ensure the UUID is in proper form. Signed-off-by: Mark Michelson <[email protected] <mailto:[email protected]>> --- Hi Mark, thank you for v7. I have a few more comments down below. Also there is a lot of CI failures, could you please take a look at it?It looks like I did not re-run system tests when I made the latest revision. I'll get those straightened out.The other failure I noticed was the "neighbor update on same HV" . This test has been flaky for me lately. I find that there's a about a 50-50 shot the test will succeed or fail.* v7 * Rebased.* Changed from using external-ids for the nb_uuid and type to usingnew columns in the Datapath_Binding table. * v6 * This is the first version of the series to contain this patch. ic/ovn-ic.c | 5 +++-- northd/northd.c | 31 ++++++++++++++++++------------- northd/northd.h | 5 +++-- ovn-sb.ovsschema | 7 +++++-- ovn-sb.xml | 21 +++++++++++---------- tests/ovn-controller.at <http://ovn-controller.at> | 4 ++++ tests/ovn-northd.at <http://ovn-northd.at> | 4 ++-- tests/ovn.at <http://ovn.at> | 6 ++---- utilities/ovn-sbctl.c | 4 ++-- utilities/ovn-trace.c | 3 +-- 10 files changed, 51 insertions(+), 39 deletions(-) diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c index 0dd079c4e..de5a91b23 100644 --- a/ic/ovn-ic.c +++ b/ic/ovn-ic.c @@ -613,8 +613,7 @@ get_router_uuid_by_sb_pb(struct ic_context *ctx, return NULL; } - return smap_get_uuid(&router_pb->datapath->external_ids, "logical-router", - router_uuid);+ return uuid_from_string(router_uuid, router_pb->datapath->nb_uuid);} static void @@ -2391,6 +2390,8 @@ main(int argc, char *argv[]) ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_datapath_binding); ovsdb_idl_add_column(ovnsb_idl_loop.idl, &sbrec_datapath_binding_col_external_ids); + ovsdb_idl_add_column(ovnsb_idl_loop.idl, + &sbrec_datapath_binding_col_nb_uuid); ovsdb_idl_add_table(ovnsb_idl_loop.idl, &sbrec_table_port_binding); ovsdb_idl_add_column(ovnsb_idl_loop.idl, diff --git a/northd/northd.c b/northd/northd.c index 2da94e7e1..c3fa5d3eb 100644 --- a/northd/northd.c +++ b/northd/northd.c @@ -580,14 +580,15 @@ ovn_datapath_from_sbrec(const struct hmap *ls_datapaths, struct uuid key; const struct hmap *dps; - if (smap_get_uuid(&sb->external_ids, "logical-switch", &key)) { + if (!strcmp(sb->type, "logical-switch")) { dps = ls_datapaths; - } else if (smap_get_uuid(&sb->external_ids, "logical-router", &key)) { + } else if (!strcmp(sb->type, "logical-router")) { dps = lr_datapaths; } else { return NULL; } - if (!dps) { + + if (!uuid_from_string(&key, sb->nb_uuid)) { return NULL; } struct ovn_datapath *od = ovn_datapath_find_(dps, &key); @@ -749,11 +750,9 @@ store_mcast_info_for_switch_datapath(const struct sbrec_ip_multicast *sb, static void ovn_datapath_update_external_ids(struct ovn_datapath *od) { - /* Get the logical-switch or logical-router UUID to set in - * external-ids. */ + /* Get the NB UUID to set in external-ids. */ char uuid_s[UUID_LEN + 1]; sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key)); The uuid_s isn't actually used for anything. - const char *key = od->nbs ? "logical-switch" : "logical-router"; /* Get names to set in external-ids. */ const char *name = od->nbs ? od->nbs->name : od->nbr->name; @@ -765,7 +764,6 @@ ovn_datapath_update_external_ids(struct ovn_datapath *od) /* Set external-ids. */ struct smap ids = SMAP_INITIALIZER(&ids); - smap_add(&ids, key, uuid_s); smap_add(&ids, "name", name); if (name2 && name2[0]) { smap_add(&ids, "name2", name2); @@ -893,13 +891,10 @@ join_datapaths(const struct nbrec_logical_switch_table *nbrec_ls_table, const struct sbrec_datapath_binding *sb;SBREC_DATAPATH_BINDING_TABLE_FOR_EACH_SAFE (sb, sbrec_dp_table) {struct uuid key; - if (!smap_get_uuid(&sb->external_ids, "logical-switch", &key) && - !smap_get_uuid(&sb->external_ids, "logical-router", &key)) { + if (!uuid_from_string(&key, sb->nb_uuid)) { ovsdb_idl_txn_add_comment( ovnsb_txn, - "deleting Datapath_Binding "UUID_FMT" that lacks " - "external-ids:logical-switch and " - "external-ids:logical-router", + "deleting Datapath_Binding "UUID_FMT" that lacks nb_uuid", UUID_ARGS(&sb->header_.uuid)); sbrec_datapath_binding_delete(sb); continue; @@ -909,7 +904,7 @@ join_datapaths(const struct nbrec_logical_switch_table *nbrec_ls_table, static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); VLOG_INFO_RL( &rl, "deleting Datapath_Binding "UUID_FMT" with " - "duplicate external-ids:logical-switch/router "UUID_FMT, + "duplicate nb_uuid "UUID_FMT, UUID_ARGS(&sb->header_.uuid), UUID_ARGS(&key)); sbrec_datapath_binding_delete(sb); continue;@@ -1117,11 +1112,21 @@ build_datapaths(struct ovsdb_idl_txn *ovnsb_txn,sbrec_datapath_binding_set_tunnel_key(od->sb, od->tunnel_key); } ovn_datapath_update_external_ids(od); + char uuid_s[UUID_LEN + 1]; + sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key)); + sbrec_datapath_binding_set_nb_uuid(od->sb, uuid_s); + sbrec_datapath_binding_set_type(od->sb, od->nbs ? "logical-switch" : + "logical-router"); } LIST_FOR_EACH (od, list, &nb_only) { od->sb = sbrec_datapath_binding_insert(ovnsb_txn); ovn_datapath_update_external_ids(od);sbrec_datapath_binding_set_tunnel_key(od->sb, od->tunnel_key);+ char uuid_s[UUID_LEN + 1]; + sprintf(uuid_s, UUID_FMT, UUID_ARGS(&od->key)); + sbrec_datapath_binding_set_nb_uuid(od->sb, uuid_s); + sbrec_datapath_binding_set_type(od->sb, od->nbs ? "logical-switch" : + "logical-router"); } ovn_destroy_tnlids(&dp_tnlids); diff --git a/northd/northd.h b/northd/northd.h index fc138aab5..998ee8090 100644 --- a/northd/northd.h +++ b/northd/northd.h @@ -346,7 +346,7 @@ DRR_MODES #undef DRR_MODE /* The 'key' comes from nbs->header_.uuid or nbr->header_.uuid or - * sb->external_ids:logical-switch. */ + * sb->nb_uuid. */ struct ovn_datapath { struct hmap_node key_node; /* Index on 'key'. */ struct uuid key; /* (nbs/nbr)->header_.uuid. */@@ -448,7 +448,8 @@ ovn_datapath_is_stale(const struct ovn_datapath *od)/* The two purposes for which ovn-northd uses OVN logical datapaths. */ enum ovn_datapath_type { DP_SWITCH, /* OVN logical switch. */ - DP_ROUTER /* OVN logical router. */ + DP_ROUTER, /* OVN logical router. */ + DP_MAX, }; /* Returns an "enum ovn_stage" built from the arguments. diff --git a/ovn-sb.ovsschema b/ovn-sb.ovsschema index 4c24f5b51..a020a5c1c 100644 --- a/ovn-sb.ovsschema +++ b/ovn-sb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Southbound", - "version": "21.2.0", - "cksum": "29145795 34859", + "version": "21.3.0", + "cksum": "3112866017 35066", "tables": { "SB_Global": { "columns": { @@ -196,6 +196,9 @@"load_balancers": {"type": {"key": {"type": "uuid"},"min": 0, "max": "unlimited"}}, + "type": {"type": {"key": {"type": "string", + "enum": ["set", ["logical-switch", "logical-router"]]}}}, + "nb_uuid": {"type": "string"}, Why not use the type "uuid" directly? We could avoid the extra parsing.This is addressed in the commit message "note 2" section, but I can go into a bit more detail here.I tried to make the type UUID in the following way: "nb_uuid": {"type": "uuid"},I did it this way since the nb_uuid is required and there can be at most one.This made two tests in ovn-sbctl.at cause crashes due to ovs_asserts(). The two tests each attempt to feed invalid input into `ovn-sbctl lflow-list`. As an example, the "invalid 0x flow" test tries `ovn-sbctl lflow-list 0x12345678` . This is a nonsense hex value that is expected to fail.ovn-sbctl calls ctl_get_row() in OVS's db-ctl-base.c using "0x12345678" as the potential record_id. ctl_get_row() iterates over the rows of Datapath_Binding to try to find a row that matches. When it reaches the "nb_uuid" row, it calls get_row_by_id(). This function then asserts because the "name_type" variable is OVSDB_TYPE_UUID, but the assertion assumes it is OVSDB_TYPE_STRING. The comment above the block where the code asserts even says:/* We only support integer and string names (so far). */So to be able to use a UUID here would require updating OVS to support UUID types in get_row_by_id(). Or it may be possible to get around the assertions using some alternate means of specifying the column, where we use "key" instead of having the type be "uuid" directly. I could experiment with that option to see if it works without causing crashes.
I tried to specify the UUID differently, I tried:
"nb_uuid": {"type": {"key": {"type": "uuid"},
"min": 0,
"max": 1}},
as well as the same thing with "min": 1.
We still hit the same assertion in db-ctl-base.c. The nb_uuid column is
necessary for `ovn-sbctl lflow-list` to function properly when the UUID
of a logical datapath is passed in as the argument. We can't just ignore
this column.
So for now, without a fix in OVS, we'll need to use a string.
"external_ids": { "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}, diff --git a/ovn-sb.xml b/ovn-sb.xml index db5faac66..ad09a472e 100644 --- a/ovn-sb.xml +++ b/ovn-sb.xml @@ -3236,18 +3236,19 @@ tcp.flags = RST; db="OVN_Northbound"/> database. </p> - <column name="external_ids" key="logical-switch" type='{"type": "uuid"}'> - For a logical datapath that represents a logical switch, - <code>ovn-northd</code> stores in this key the UUID of the - corresponding <ref table="Logical_Switch" db="OVN_Northbound"/> row in - the <ref db="OVN_Northbound"/> database. + <column name="type" type='{"type": "string"}'> + This represents the type of the northbound logical datapath that is + represented by this southbound <code>Datapath_Binding</code>. The + possible values for this are: + <ul> + <li><code>logical-switch</code></li> + <li><code>logical-router</code></li> + </ul> </column> - <column name="external_ids" key="logical-router" type='{"type": "uuid"}'> - For a logical datapath that represents a logical router, - <code>ovn-northd</code> stores in this key the UUID of the - corresponding <ref table="Logical_Router" db="OVN_Northbound"/> row in - the <ref db="OVN_Northbound"/> database. + <column name="nb_uuid" type='{"type": "string"}'> + This is the UUID of the corresponding northbound logical datapath+ represented by this southbound <code>Datapath_Binding</code>.</column> <column name="external_ids" key="interconn-ts" type='{"type": "string"}'> diff --git a/tests/ovn-controller.at <http://ovn-controller.at> b/tests/ovn-controller.at <http://ovn-controller.at> index ae7eb6f31..137442262 100644 --- a/tests/ovn-controller.at <http://ovn-controller.at> +++ b/tests/ovn-controller.at <http://ovn-controller.at> @@ -123,6 +123,7 @@ check_patches # another logical port bound to this chassis. check_uuid ovn-sbctl \ -- --id=@dp101 create Datapath_Binding tunnel_key=101 external_ids:name=dp101 \ + type=logical-switch \ -- create Port_Binding datapath=@dp101 logical_port=localnet1 tunnel_key=1 \ type=localnet options:network_name=physnet1 check_patches @@ -131,6 +132,7 @@ check_patches # Now we should get some patch ports created. check_uuid ovn-sbctl \ -- --id=@dp102 create Datapath_Binding tunnel_key=102 external_ids:name=dp102 \ + type=logical-switch \ -- create Port_Binding datapath=@dp102 logical_port=localnet2 tunnel_key=1 \ type=localnet options:network_name=physnet1 \ -- create Port_Binding datapath=@dp102 logical_port=localvif2 tunnel_key=2 @@ -145,7 +147,9 @@ check_patches \ # the set of OVS patch ports doesn't change. AT_CHECK([ovn-sbctl \ -- --id=@dp1 create Datapath_Binding tunnel_key=1 external_ids:name=dp1 \ + type=logical-switch \ -- --id=@dp2 create Datapath_Binding tunnel_key=2 external_ids:name=dp2 \ + type=logical-switch \ -- create Port_Binding datapath=@dp1 logical_port=foo tunnel_key=1 type=patch options:peer=bar \ -- create Port_Binding datapath=@dp2 logical_port=bar tunnel_key=2 type=patch options:peer=foo \ -- create Port_Binding datapath=@dp1 logical_port=dp1vif tunnel_key=3 \ diff --git a/tests/ovn-northd.at <http://ovn-northd.at> b/tests/ovn-northd.at <http://ovn-northd.at> index 97eaa6a40..f334698dd 100644 --- a/tests/ovn-northd.at <http://ovn-northd.at> +++ b/tests/ovn-northd.at <http://ovn-northd.at> @@ -1887,7 +1887,7 @@ check ovn-nbctl --wait=sb \ check_row_count Datapath_Binding 1-nb_uuid=$(ovn-sbctl get Datapath_Binding . external_ids:logical-router)+nb_uuid=$(ovn-sbctl get Datapath_Binding . nb_uuid) lr_uuid=\"$(ovn-nbctl get Logical_Router . _uuid)\" echo nb_uuid="$nb_uuid" lr_uuid="$lr_uuid" AT_CHECK([test "${nb_uuid}" = "${lr_uuid}"])@@ -7574,7 +7574,7 @@ ls1_uuid=$(fetch_column nb:Logical_Switch _uuid)# create a duplicated sb datapath (and an IP_Mulicast record that references # it) on purpose. -AT_CHECK([ovn-sbctl --id=@dp create Datapath_Binding external_ids:logical-switch=$ls1_uuid external_ids:name=ls1 tunnel_key=123 -- create IP_Multicast datapath=@dp], [0], [ignore]) +AT_CHECK([ovn-sbctl --id=@dp create Datapath_Binding nb_uuid=$ls1_uuid type=logical-switch external_ids:name=ls1 tunnel_key=123 -- create IP_Multicast datapath=@dp], [0], [ignore]) # northd should delete one of the datapaths in the end wait_row_count Datapath_Binding 1diff --git a/tests/ovn.at <http://ovn.at> b/tests/ovn.at <http://ovn.at>index b561c69aa..f11dcd1f8 100644 --- a/tests/ovn.at <http://ovn.at> +++ b/tests/ovn.at <http://ovn.at> @@ -22193,8 +22193,7 @@ AT_CAPTURE_FILE([sbflows]) AT_CHECK([as hv1 ovs-ofctl dump-flows br-int \ | grep "check_pkt_larger" | wc -l], [0], [[0 ]]) -dp_uuid=$(ovn-sbctl find datapath_binding | grep lr0 -B2 | grep _uuid | \ -awk '{print $3}') +dp_uuid=$(fetch_column Datapath_Binding _uuid external-ids:name=lr0) check_uuid ovn-sbctl create MAC_Binding ip=172.168.0.3 datapath=$dp_uuid \ logical_port=lr0-public mac="00\:00\:00\:12\:af\:11" @@ -22264,8 +22263,7 @@ check ovn-nbctl lr-nat-add lr1 snat 172.168.0.100 10.0.0.0/24 <http://10.0.0.0/24> check ovn-nbctl lr-nat-add lr1 snat 2000::1 1000::/64 check ovn-nbctl --wait=sb sync -dp_uuid=$(ovn-sbctl find datapath_binding | grep lr1 -B2 | grep _uuid | \ -awk '{print $3}') +dp_uuid=$(fetch_column Datapath_Binding _uuid external-ids:name=lr1) check_uuid ovn-sbctl create MAC_Binding ip=172.168.0.3 datapath=$dp_uuid \ logical_port=lr1-public mac="00\:00\:00\:12\:af\:11" diff --git a/utilities/ovn-sbctl.c b/utilities/ovn-sbctl.c index 60cc39149..9c7be5e57 100644 --- a/utilities/ovn-sbctl.c +++ b/utilities/ovn-sbctl.c @@ -1493,8 +1493,8 @@ static const struct ctl_table_class tables[SBREC_N_TABLES] = { [SBREC_TABLE_DATAPATH_BINDING].row_ids = {{&sbrec_datapath_binding_col_external_ids, "name", NULL}, {&sbrec_datapath_binding_col_external_ids, "name2", NULL}, - {&sbrec_datapath_binding_col_external_ids, "logical-switch", NULL}, - {&sbrec_datapath_binding_col_external_ids, "logical-router", NULL}}, + {&sbrec_datapath_binding_col_nb_uuid, NULL, NULL}, + {&sbrec_datapath_binding_col_type, NULL, NULL}}, [SBREC_TABLE_PORT_BINDING].row_ids = {{&sbrec_port_binding_col_logical_port, NULL, NULL}, diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c index 0331eac21..648a1d43e 100644 --- a/utilities/ovn-trace.c +++ b/utilities/ovn-trace.c @@ -703,8 +703,7 @@ read_datapaths(void) const struct smap *ids = &sbdb->external_ids; dp->sb_uuid = sbdb->header_.uuid; - if (!smap_get_uuid(ids, "logical-switch", &dp->nb_uuid) && - !smap_get_uuid(ids, "logical-router", &dp->nb_uuid)) { + if (!uuid_from_string(&dp->nb_uuid, sbdb->nb_uuid)) { dp->nb_uuid = dp->sb_uuid; } -- 2.47.0 _______________________________________________ dev mailing list [email protected] <mailto:[email protected]> https://mail.openvswitch.org/mailman/listinfo/ovs-dev <https://mail.openvswitch.org/mailman/listinfo/ovs-dev> Thanks, Ales
_______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
