On 8/13/25 10:27 AM, Dumitru Ceara wrote:
> Hi Mark,
> 
> On 8/12/25 8:33 PM, Mark Michelson via dev wrote:
>> On 8/11/25 12:00 PM, Numan Siddique wrote:
>>> On Mon, Aug 11, 2025 at 8:29 PM Mark Michelson via dev
>>> <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. This test started failing because its use
>>>> of `grep` was picking up the new "nb_uuid" column accidentally. The
>>>> change to the test uses `fetch_column` since it is more precise.
>>>>
>>>> Signed-off-by: Mark Michelson <mmich...@redhat.com>
>>>> Acked-by: Ales Musil <amu...@redhat.com>
>>>
>>> Hi Mark,
>>>
>>> Thanks for this series.  I had a very quick look into some of the
>>> patches of this series.
>>> I like the approach taken in this series.
>>>
>>> I've a couple of small comments in this first patch.
>>>
>>> 1.  Is it possible to add a test case in ovn-northd.at which checks
>>> that the datapath type and uuid
>>> in the SB DB is created properly by ovn-northd when the NB logical
>>> switches and routers are created ?
>>>
>>> (Please see below for the 2nd comment)
>>>
>>>
>>>> ---
>>>> v14
>>>>   * Rebased.
>>>>
>>>> v13
>>>>   * Rebased.
>>>>
>>>> v12
>>>>   * Rebased.
>>>>   * Added Ales Musil's ack.
>>>>
>>>> v11
>>>>   * Rebased.
>>>>
>>>> v10
>>>>   * Rebased.
>>>>   * Maintained backwards-compatibility with external_ids method of
>>>>     storing NB UUID and type. It was recommended to continue setting
>>>>     the external-ids in addition to the new fields. This patch does not
>>>>     do that because that code would get immediately wiped out by the
>>>>     next patch in the series. The next patch in the series does write
>>>>     the old external_ids values, though.
>>>>
>>>> v9
>>>>   * Rebased.
>>>>
>>>> v8
>>>>   * Rebased.
>>>>   * Changed the types of the new columns. The nb_uuid is type "uuid" and
>>>>     the type is an enum.
>>>>
>>>> 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.
>>>> ---
>>>>   controller/local_data.c |  2 +-
>>>>   ic/ovn-ic.c             |  5 +++--
>>>>   lib/ovn-util.c          | 45 +++++++++++++++++++++++++++++++++++++++++
>>>>   lib/ovn-util.h          |  8 ++++++++
>>>>   northd/northd.c         | 38 +++++++++++++++++-----------------
>>>>   northd/northd.h         |  5 +++--
>>>>   ovn-sb.ovsschema        | 11 ++++++++--
>>>>   ovn-sb.xml              | 21 ++++++++++---------
>>>>   tests/ovn-controller.at |  4 ++++
>>>>   tests/ovn-northd.at     |  6 +++---
>>>>   tests/ovn.at            |  6 ++----
>>>>   utilities/ovn-sbctl.c   |  4 ++--
>>>>   utilities/ovn-trace.c   |  3 +--
>>>>   13 files changed, 112 insertions(+), 46 deletions(-)
>>>>
>>>> diff --git a/controller/local_data.c b/controller/local_data.c
>>>> index 00383d091..a35d3fa5a 100644
>>>> --- a/controller/local_data.c
>>>> +++ b/controller/local_data.c
>>>> @@ -708,7 +708,7 @@ local_datapath_peer_port_add(struct
>>>> local_datapath *ld,
>>>>   static bool
>>>>   datapath_is_switch(const struct sbrec_datapath_binding *ldp)
>>>>   {
>>>> -    return smap_get(&ldp->external_ids, "logical-switch") != NULL;
>>>> +    return strcmp(datapath_get_nb_type(ldp), "logical-switch") == 0;
>>>>   }
>>>>
>>>>   static bool
>>>> diff --git a/ic/ovn-ic.c b/ic/ovn-ic.c
>>>> index caffa6fe0..0cd78e720 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 datapath_get_nb_uuid(router_pb->datapath, router_uuid);
>>>>   }
>>>>
>>>>   static void
>>>> @@ -2582,6 +2581,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/lib/ovn-util.c b/lib/ovn-util.c
>>>> index ab5c4fc47..44a1082d4 100644
>>>> --- a/lib/ovn-util.c
>>>> +++ b/lib/ovn-util.c
>>>> @@ -1503,3 +1503,48 @@ put_load(uint64_t value, enum mf_field_id dst,
>>>> size_t ofs, size_t n_bits,
>>>>       ovs_be64 n_value = htonll(value);
>>>>       put_load_bytes(&n_value, 8, dst, ofs, n_bits, ofpacts);
>>>>   }
>>>> +
>>>> +bool
>>>> +datapath_get_nb_uuid_and_type(const struct sbrec_datapath_binding *sb,
>>>> +                              struct uuid *nb_uuid, const char **type)
>>>> +{
>>>> +    if (sb->nb_uuid) {
>>>> +        /* New style. The UUID and type are direct columns, so use
>>>> those. */
>>>> +        *nb_uuid = *sb->nb_uuid;
>>>> +        *type = sb->type;
>>>> +        return true;
>>>> +    }
>>>> +
>>>> +    /* Old style. The UUID is stored in external_ids, and the key
>>>> +     * corresponds to the datapath type. This only works with
>>>> +     * logical switches and logical routers.
>>>> +     */
>>>> +    *type = "logical-switch";
>>>> +    if (smap_get_uuid(&sb->external_ids, *type, nb_uuid)) {
>>>> +        return true;
>>>> +    }
>>>> +    *type = "logical-router";
>>>> +    if (smap_get_uuid(&sb->external_ids, *type, nb_uuid)) {
>>>> +        return true;
>>>> +    }
>>>> +    *type = "";
>>>> +    *nb_uuid = UUID_ZERO;
>>>> +    return false;
>>>> +}
>>>> +
>>>> +bool
>>>> +datapath_get_nb_uuid(const struct sbrec_datapath_binding *sb,
>>>> +                     struct uuid *nb_uuid)
>>>> +{
>>>> +    const char *type;
>>>> +    return datapath_get_nb_uuid_and_type(sb, nb_uuid, &type);
>>>> +}
>>>> +
>>>> +const char *
>>>> +datapath_get_nb_type(const struct sbrec_datapath_binding *sb)
>>>> +{
>>>> +    const char *type;
>>>> +    struct uuid nb_uuid;
>>>> +    datapath_get_nb_uuid_and_type(sb, &nb_uuid, &type);
>>>> +    return type;
>>>> +}
>>>> diff --git a/lib/ovn-util.h b/lib/ovn-util.h
>>>> index bde40666a..18ebea912 100644
>>>> --- a/lib/ovn-util.h
>>>> +++ b/lib/ovn-util.h
>>>> @@ -546,4 +546,12 @@ void put_load(uint64_t value, enum mf_field_id
>>>> dst, size_t ofs, size_t n_bits,
>>>>   #define _VFUNC(name, n) _VFUNC_(name, n)
>>>>   #define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__))
>>>> (__VA_ARGS__)
>>>>
>>>> +bool datapath_get_nb_uuid_and_type(const struct
>>>> sbrec_datapath_binding *sb,
>>>> +                                   struct uuid *nb_uuid, const char
>>>> **type);
>>>> +
>>>> +bool datapath_get_nb_uuid(const struct sbrec_datapath_binding *sb,
>>>> +                          struct uuid *nb_uuid);
>>>> +
>>>> +const char *datapath_get_nb_type(const struct sbrec_datapath_binding
>>>> *sb);
>>>> +
>>>>   #endif /* OVN_UTIL_H */
>>>> diff --git a/northd/northd.c b/northd/northd.c
>>>> index 2cb69f9aa..241af1d3c 100644
>>>> --- a/northd/northd.c
>>>> +++ b/northd/northd.c
>>>> @@ -608,19 +608,21 @@ ovn_datapath_from_sbrec(const struct hmap
>>>> *ls_datapaths,
>>>>                           const struct hmap *lr_datapaths,
>>>>                           const struct sbrec_datapath_binding *sb)
>>>>   {
>>>> -    struct uuid key;
>>>>       const struct hmap *dps;
>>>> +    struct uuid key;
>>>> +    const char *type;
>>>> +    if (!datapath_get_nb_uuid_and_type(sb, &key, &type)) {
>>>> +        return NULL;
>>>> +    }
>>>>
>>>> -    if (smap_get_uuid(&sb->external_ids, "logical-switch", &key)) {
>>>> +    if (!strcmp(type, "logical-switch")) {
>>>>           dps = ls_datapaths;
>>>> -    } else if (smap_get_uuid(&sb->external_ids, "logical-router",
>>>> &key)) {
>>>> +    } else if (!strcmp(type, "logical-router")) {
>>>>           dps = lr_datapaths;
>>>>       } else {
>>>>           return NULL;
>>>>       }
>>>> -    if (!dps) {
>>>> -        return NULL;
>>>> -    }
>>>> +
>>>>       struct ovn_datapath *od = ovn_datapath_find_(dps, &key);
>>>>       if (od && (od->sb == sb)) {
>>>>           return od;
>>>> @@ -768,11 +770,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));
>>>> -    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;
>>>> @@ -784,7 +784,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);
>>>> @@ -912,13 +911,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 (!datapath_get_nb_uuid(sb, &key)) {
>>>>               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;
>>>> @@ -928,13 +924,13 @@ 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,
>>>> -                UUID_ARGS(&sb->header_.uuid), UUID_ARGS(&key));
>>>> +                "duplicate nb_uuid "UUID_FMT,
>>>> +                UUID_ARGS(&sb->header_.uuid), UUID_ARGS(sb->nb_uuid));
>>>>               sbrec_datapath_binding_delete(sb);
>>>>               continue;
>>>>           }
>>>>
>>>> -        struct ovn_datapath *od = ovn_datapath_create(datapaths, &key,
>>>> +        struct ovn_datapath *od = ovn_datapath_create(datapaths, sb-
>>>>> nb_uuid,
>>>>                                                         NULL, NULL, sb);
>>>>           ovs_list_push_back(sb_only, &od->list);
>>>>       }
>>>> @@ -1140,11 +1136,17 @@ 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);
>>>> +        sbrec_datapath_binding_set_nb_uuid(od->sb, &od->key, 1);
>>>> +        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);
>>>> +        sbrec_datapath_binding_set_nb_uuid(od->sb, &od->key, 1);
>>>> +        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 1108793d7..d3b268129 100644
>>>> --- a/northd/northd.h
>>>> +++ b/northd/northd.h
>>>> @@ -351,7 +351,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. */
>>>> @@ -454,7 +454,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..8bc7bbba3 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": "3179330761 35286",
>>>>       "tables": {
>>>>           "SB_Global": {
>>>>               "columns": {
>>>> @@ -196,6 +196,13 @@
>>>>                   "load_balancers": {"type": {"key": {"type": "uuid"},
>>>>                                               "min": 0,
>>>>                                               "max": "unlimited"}},
>>>> +                "type": {"type": {"key": {"type": "string",
>>>> +                                          "enum": ["set",
>>>> +                                                      ["logical-
>>>> switch",
>>>> +                                                       "logical-
>>>> router"]]}}},
>>>
>>> 2.  Instead of using type string here for the "type",  how about we
>>> use "integer" something like ?
>>>
>>> ---
>>> "type": {"type": {"key": {"type": "integer",
>>>                                            "enum": ["set",
>>>                                                      [1, 2]]}}},
>>>
>>> ----
>>>
>>> This way we can avoid using "strcmp" in the code base.  type = 1 is
>>> for logical switch and 2 for router.
>>>
>>> What do you think ?
>>>
>>> Thanks
>>> Numan
>>
>> I like that. What I'd probably do is align this with the existing enum
>> ovn_datapath_type.
>>
>>   enum ovn_datapath_type {
>>       DP_SWITCH,                  /* OVN logical switch. */
>>       DP_ROUTER                   /* OVN logical router. */
>>   };
>>
>> Therefore, logical switch would be 0, and logical router would be 1.
>>
> 
> This is a bit unfortunate, but the change to '"enum": ["set", [1, 2]]'
> breaks ovn-kubernetes builds:
> 
> https://patchwork.ozlabs.org/project/ovn/patch/20250812230233.63769-9-mmich...@redhat.com/
> 
> https://mail.openvswitch.org/pipermail/ovs-build/2025-August/048140.html
> 
> https://github.com/ovsrobot/ovn/actions/runs/16923415749/job/47954327716#step:7:9386
> 
>  modelgen: template: :174:27: executing "enums" at <.>: wrong type for
> value; expected string; got float64
> 
> This is a bug in ovn-kubernetes' modelgen but has the annoying side
> effect that we cannot run any ovn-kubernetes CI tests with ovn code
> until that's fixed.
> 

I opened a new usptream libovsdb issue for this:
https://github.com/ovn-kubernetes/libovsdb/issues/436

> IMO it's fine to leave enum value as "string" as it was in v14, the
> strcmps we do in northd should not matter too much performance-wise.  In
> my eyes, another advantage of using strings is that it makes it easier
> for humans looking at the database contents directly to figure out what
> that value means.
> 
> Regards,
> Dumitru

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

Reply via email to