On 6/11/25 02:53, Ales Musil wrote:


On Fri, Jun 6, 2025 at 8:14 PM Mark Michelson via dev <ovs-dev@openvswitch.org <mailto:ovs-dev@openvswitch.org>> 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 two
    places:

    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 separate
    fields. This way, no matter the type of the datapath, you can find the
    UUID. 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 upcoming
    patches, so instead of making them external-ids, these are now
    full-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 use
    of `grep` was picking up the new "nb_uuid" external-id accidentally. The
    change 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 the
    ovn-sbctl "invalid 0x flow" and "count-flows wrongDatapath" tests. This
    is because db-ctl-base.c is incapable of handling records other than of
    type "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 <mmich...@redhat.com
    <mailto:mmich...@redhat.com>>
    ---


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 using
         new 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.


                      "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 1
    diff --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
    d...@openvswitch.org <mailto:d...@openvswitch.org>
    https://mail.openvswitch.org/mailman/listinfo/ovs-dev
    <https://mail.openvswitch.org/mailman/listinfo/ovs-dev>


Thanks,
Ales

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to