On Thu, Aug 14, 2025 at 2:13 PM Ilya Maximets <i.maxim...@ovn.org> wrote:

> On 8/12/25 4:56 PM, Ales Musil via dev wrote:
> > In order to get the VTEP setup listeners for each special interface
> > that is dedicated to given VNI. Those interfaces need to be
> > part of the VRF, created by CMS. Once those listeners are in place
> > ovn-controller will receive notifications about remote VTEPs.
> >
> > Create remote VTEP representation based on the data received from
> > netlink neighbor table. There are three key attributes that
> > uniquely identify each remote VTEP:
> > 1) IP of the remote tunnel.
> > 2) Destination port of the remote tunnel.
> > 3) VNI.
> >
> > Create a map of all remote VTEPs based on those three attributes.
> > The map will be used later on to crate the EVPN binding. One
> > thing to note is that all of this is specific to each ovn-controller.
> > This is one of the reasons why those data are local to each
> > ovn-controller, the second reason is scalability as we would have
> > possibly duplicate SB entries differentiated only by residing
> > chassis.
> >
> > Note that there isn't any way to set vni for given LS that will
> > be part of future patch ("dynamic-routing-vni").
> >
> > Signed-off-by: Ales Musil <amu...@redhat.com>
> > Acked-by: Xavier Simonart <xsimo...@redhat.com>
> > ---
> > v3: Rebase on top of latest main.
> >     Add Xavier's ack.
> >
> > v2: Rebase on top of latest main.
> > ---
> >  controller/neighbor-exchange-netlink.c |  12 ++-
> >  controller/neighbor-exchange-netlink.h |   1 +
> >  controller/neighbor-exchange-stub.c    |  12 +++
> >  controller/neighbor-exchange.c         | 109 +++++++++++++++++++++++--
> >  controller/neighbor-exchange.h         |  22 ++++-
> >  controller/neighbor.c                  |  98 +++++++++++++++++++---
> >  controller/neighbor.h                  |  10 +++
> >  controller/ovn-controller.c            | 108 ++++++++++++++++++++++--
> >  lib/ovn-util.c                         |   6 ++
> >  lib/ovn-util.h                         |   2 +
> >  10 files changed, 349 insertions(+), 31 deletions(-)
> >
> > diff --git a/controller/neighbor-exchange-netlink.c
> b/controller/neighbor-exchange-netlink.c
> > index a4e9cf006..593e01dd0 100644
> > --- a/controller/neighbor-exchange-netlink.c
> > +++ b/controller/neighbor-exchange-netlink.c
> > @@ -133,12 +133,20 @@ ne_nl_sync_neigh(uint8_t family, int32_t if_index,
> >  /* OVN expects all static entries added on this ifindex to be OVN-owned.
> >   * Everything else must be learnt. */
> >  bool
> > -ne_is_ovn_owned(const struct ne_nl_received_neigh *nd)
> > -{
> > +ne_is_ovn_owned(const struct ne_nl_received_neigh *nd) {
> >      return !(nd->state & NUD_PERMANENT) && (nd->state & NUD_NOARP)
> >             && !(nd->flags & NTF_EXT_LEARNED);
> >  }
> >
> > +/* OVN expects that the VTEP entry doesn't have any MAC address (zeroed
> out)
> > + * and the entry is marked as "permanent". */
> > +bool
> > +ne_is_valid_remote_vtep(struct ne_nl_received_neigh *ne)
> > +{
> > +    return eth_addr_is_zero(ne->lladdr) && (ne->state & NUD_NOARP) &&
> > +           (ne->state & NUD_PERMANENT);
> > +}
> > +
> >  static bool
> >  ne_table_dump_one_ifindex(unsigned char address_family, int32_t
> if_index,
> >                            ne_table_handle_msg_callback *handle_msg_cb,
> > diff --git a/controller/neighbor-exchange-netlink.h
> b/controller/neighbor-exchange-netlink.h
> > index e154d1b6e..557367fdc 100644
> > --- a/controller/neighbor-exchange-netlink.h
> > +++ b/controller/neighbor-exchange-netlink.h
> > @@ -54,6 +54,7 @@ int ne_nl_sync_neigh(uint8_t family, int32_t if_index,
> >                       struct vector *learned_neighbors);
> >
> >  bool ne_is_ovn_owned(const struct ne_nl_received_neigh *nd);
> > +bool ne_is_valid_remote_vtep(struct ne_nl_received_neigh *ne);
> >
> >  int ne_table_parse(struct ofpbuf *, void *change);
> >
> > diff --git a/controller/neighbor-exchange-stub.c
> b/controller/neighbor-exchange-stub.c
> > index a42df84c2..d314543be 100644
> > --- a/controller/neighbor-exchange-stub.c
> > +++ b/controller/neighbor-exchange-stub.c
> > @@ -28,3 +28,15 @@ neighbor_exchange_status_run(void)
> >  {
> >      return 0;
> >  }
> > +
> > +void
> > +evpn_remote_vteps_clear(struct hmap *remote_vteps OVS_UNUSED)
> > +{
> > +}
> > +
> > +void
> > +evpn_remote_vtep_list(struct unixctl_conn *conn OVS_UNUSED,
> > +                      int argc OVS_UNUSED, const char *argv[]
> OVS_UNUSED,
> > +                      void *data_ OVS_UNUSED)
> > +{
> > +}
> > diff --git a/controller/neighbor-exchange.c
> b/controller/neighbor-exchange.c
> > index 8e3bf3ecb..4d9ca8b3c 100644
> > --- a/controller/neighbor-exchange.c
> > +++ b/controller/neighbor-exchange.c
> > @@ -15,12 +15,29 @@
> >
> >  #include <config.h>
> >
> > +#include <linux/neighbour.h>
> > +
> >  #include "host-if-monitor.h"
> >  #include "neighbor.h"
> >  #include "neighbor-exchange.h"
> >  #include "neighbor-exchange-netlink.h"
> >  #include "neighbor-table-notify.h"
> > +#include "openvswitch/vlog.h"
> > +#include "ovn-util.h"
> > +#include "packets.h"
> >  #include "vec.h"
> > +#include "unixctl.h"
> > +
> > +VLOG_DEFINE_THIS_MODULE(neighbor_exchange);
> > +
> > +static uint32_t evpn_remote_vtep_hash(const struct in6_addr *ip,
> > +                                      uint16_t port, uint32_t vni);
> > +static void evpn_remote_vtep_add(struct hmap *remote_vteps, struct
> in6_addr ip,
> > +                                 uint16_t port, uint32_t vni);
> > +static struct evpn_remote_vtep *evpn_remote_vtep_find(
> > +    const struct hmap *remote_vteps, const struct in6_addr *ip,
> > +    uint16_t port, uint32_t vni);
> > +
> >
> >  /* Last neighbor_exchange netlink operation. */
> >  static int neighbor_exchange_nl_status;
> > @@ -65,12 +82,19 @@ neighbor_exchange_run(const struct
> neighbor_exchange_ctx_in *n_ctx_in,
> >                               &received_neighbors)
> >          );
> >
> > -        /* XXX: TODO GLUE: sync received neighbors to:
> > -         * - SB: for remote vtep entries
> > -         *   https://issues.redhat.com/browse/FDP-1385
> > -         * - in memory table for remote neighbor entries
> > -         *   https://issues.redhat.com/browse/FDP-1387
> > -         */
> > +        if (nim->type == NEIGH_IFACE_VXLAN) {
> > +            struct ne_nl_received_neigh *ne;
> > +            VECTOR_FOR_EACH_PTR (&received_neighbors, ne) {
> > +                if (ne_is_valid_remote_vtep(ne)) {
> > +                    uint16_t port = ne->port ? ne->port :
> DEFAULT_VXLAN_PORT;
> > +                    if (!evpn_remote_vtep_find(n_ctx_out->remote_vteps,
> > +                                               &ne->addr, port,
> nim->vni)) {
> > +                        evpn_remote_vtep_add(n_ctx_out->remote_vteps,
> ne->addr,
> > +                                             port, nim->vni);
> > +                    }
> > +                }
> > +            }
> > +        }
> >
> >
> neighbor_table_add_watch_request(&n_ctx_out->neighbor_table_watches,
> >                                           if_index, nim->if_name);
> > @@ -83,3 +107,76 @@ neighbor_exchange_status_run(void)
> >  {
> >      return neighbor_exchange_nl_status;
> >  }
> > +
> > +void
> > +evpn_remote_vteps_clear(struct hmap *remote_vteps)
> > +{
> > +    struct evpn_remote_vtep *vtep;
> > +    HMAP_FOR_EACH_POP (vtep, hmap_node, remote_vteps) {
> > +        free(vtep);
> > +    }
> > +}
> > +
> > +void
> > +evpn_remote_vtep_list(struct unixctl_conn *conn, int argc OVS_UNUSED,
> > +                      const char *argv[] OVS_UNUSED, void *data_)
> > +{
> > +    struct hmap *remote_vteps = data_;
> > +    struct ds ds = DS_EMPTY_INITIALIZER;
> > +
> > +    struct evpn_remote_vtep *vtep;
> > +    HMAP_FOR_EACH (vtep, hmap_node, remote_vteps) {
> > +        ds_put_cstr(&ds, "IP: ");
> > +        ipv6_format_mapped(&vtep->ip, &ds);
> > +        ds_put_format(&ds, ", port: %"PRIu16", vni: %"PRIu32"\n",
> > +                      vtep->port, vtep->vni);
> > +    }
> > +
> > +    unixctl_command_reply(conn, ds_cstr_ro(&ds));
> > +    ds_destroy(&ds);
> > +}
> > +
> > +static void
> > +evpn_remote_vtep_add(struct hmap *remote_vteps, struct in6_addr ip,
> > +                     uint16_t port, uint32_t vni)
> > +{
> > +    struct evpn_remote_vtep *vtep = xmalloc(sizeof *vtep);
> > +    *vtep = (struct evpn_remote_vtep) {
> > +        .ip = ip,
> > +        .port = port,
> > +        .vni = vni,
> > +    };
> > +
> > +    hmap_insert(remote_vteps, &vtep->hmap_node,
> > +                evpn_remote_vtep_hash(&ip, port, vni));
> > +}
> > +
> > +static struct evpn_remote_vtep *
> > +evpn_remote_vtep_find(const struct hmap *remote_vteps,
> > +                      const struct in6_addr *ip,
> > +                      uint16_t port, uint32_t vni)
> > +{
> > +    uint32_t hash = evpn_remote_vtep_hash(ip, port, vni);
> > +
> > +    struct evpn_remote_vtep *vtep;
> > +    HMAP_FOR_EACH_WITH_HASH (vtep, hmap_node, hash, remote_vteps) {
> > +        if (ipv6_addr_equals(&vtep->ip, ip) &&
> > +            vtep->port == port && vtep->vni == vni) {
> > +            return vtep;
> > +        }
> > +    }
> > +
> > +    return NULL;
> > +}
> > +
> > +static uint32_t
> > +evpn_remote_vtep_hash(const struct in6_addr *ip, uint16_t port,
> > +                      uint32_t vni)
> > +{
> > +    uint32_t hash = 0;
> > +    hash = hash_add_in6_addr(hash, ip);
> > +    hash = hash_add(hash, port);
> > +    hash = hash_add(hash, vni);
> > +
> > +    return hash;
>
> Without calling hash_finish, the resulted value may be suboptimal, i.e.
> may not provide good distribution for hash tables.  This also applies
> to hash functions in the previous patches.
>
> Best regards, Ilya Maximets.
>
>
Hi Ilya,
thank you for the review.

I have addressed this across the series.

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

Reply via email to