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.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to