On 8/14/25 7:36 PM, Ales Musil via dev wrote:
> From: Dumitru Ceara <dce...@redhat.com>
> 
> For each (Linux) interface that's interesting for the OVN control plane,
> watch for neighbor (fdb/arp) changes.  This allows us to reconcile on
> changed neighbor entries from outside routing agents (e.g., FRR).
> 
> This is the neighbor equivalent of the support added for route tables in
> 673d90f1173f ("controller: Watch for route changes.").
> 
> Acked-by: Xavier Simonart <xsimo...@redhat.com>
> Signed-off-by: Dumitru Ceara <dce...@redhat.com>
> ---
> V4:
> - Addressed Ilya's comments:
>   - sizeof, VLOG_DBG, typo
> 
> V3:
> - renamed fdb_table_change() to neighbor_table_change()
> - added tests
> 
> Changes in V2:
> - fixed up log messages
> - changed code to make OVN only manage neighbor entries with VLAN 0
> - added advertise_neigh_find() helper
> ---
>  Makefile.am                             |   5 +-
>  controller/automake.mk                  |   5 +-
>  controller/neighbor-table-notify-stub.c |  57 ++++++
>  controller/neighbor-table-notify.c      | 244 ++++++++++++++++++++++++
>  controller/neighbor-table-notify.h      |  45 +++++
>  tests/automake.mk                       |   2 +
>  tests/system-ovn-netlink.at             |  55 ++++++
>  tests/test-ovn-netlink.c                |  41 ++++
>  8 files changed, 452 insertions(+), 2 deletions(-)
>  create mode 100644 controller/neighbor-table-notify-stub.c
>  create mode 100644 controller/neighbor-table-notify.c
>  create mode 100644 controller/neighbor-table-notify.h
> 
> diff --git a/Makefile.am b/Makefile.am
> index ea98fb5fb..6119ef510 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -350,13 +350,16 @@ check-tabs:
>       fi
>  .PHONY: check-tabs
>  
> +# NOTE: test-ovn-netlink.c excluded due to use of system() to execute
> +#       ip neigh / bridge fdb commands provided as arguments by test suite.
>  ALL_LOCAL += thread-safety-check
>  thread-safety-check:
>       @cd $(srcdir); \
>       if test -e .git && (git --version) >/dev/null 2>&1 && \
>         grep -n -f build-aux/thread-safety-blacklist \
>           `git ls-files | grep -v $(submodules) | grep '\.[ch]$$'` /dev/null \
> -           | $(EGREP) -v ':[         ]*/?\*'; \
> +           | $(EGREP) -v ':[         ]*/?\*' \
> +           | $(EGREP) -v '^tests/test-ovn-netlink.c'; \
>       then \
>         echo "See above for list of calls to functions that are"; \
>         echo "blacklisted due to thread safety issues"; \
> diff --git a/controller/automake.mk b/controller/automake.mk
> index 3eb45475c..6af6ee2a9 100644
> --- a/controller/automake.mk
> +++ b/controller/automake.mk
> @@ -63,18 +63,21 @@ controller_ovn_controller_SOURCES = \
>       controller/route.h \
>       controller/route.c \
>       controller/garp_rarp.h \
> -     controller/garp_rarp.c
> +     controller/garp_rarp.c \
> +     controller/neighbor-table-notify.h
>  
>  if HAVE_NETLINK
>  controller_ovn_controller_SOURCES += \
>       controller/neighbor-exchange-netlink.h \
>       controller/neighbor-exchange-netlink.c \
> +     controller/neighbor-table-notify.c \
>       controller/route-exchange-netlink.h \
>       controller/route-exchange-netlink.c \
>       controller/route-exchange.c \
>       controller/route-table-notify.c
>  else
>  controller_ovn_controller_SOURCES += \
> +     controller/neighbor-table-notify-stub.c \
>       controller/route-exchange-stub.c \
>       controller/route-table-notify-stub.c
>  endif
> diff --git a/controller/neighbor-table-notify-stub.c 
> b/controller/neighbor-table-notify-stub.c
> new file mode 100644
> index 000000000..bb4fe5991
> --- /dev/null
> +++ b/controller/neighbor-table-notify-stub.c
> @@ -0,0 +1,57 @@
> +/* Copyright (c) 2025, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +
> +#include <stdbool.h>
> +
> +#include "openvswitch/compiler.h"
> +#include "neighbor-table-notify.h"
> +
> +bool
> +neighbor_table_notify_run(void)
> +{
> +    return false;
> +}
> +
> +void
> +neighbor_table_notify_wait(void)
> +{
> +}
> +
> +void
> +neighbor_table_add_watch_request(
> +    struct hmap *neighbor_table_watches OVS_UNUSED,
> +    int32_t if_index OVS_UNUSED,
> +    const char *if_name OVS_UNUSED)
> +{
> +}
> +
> +void
> +neighbor_table_watch_request_cleanup(
> +    struct hmap *neighbor_table_watches OVS_UNUSED)
> +{
> +}
> +
> +void
> +neighbor_table_notify_update_watches(
> +    const struct hmap *neighbor_table_watches OVS_UNUSED)
> +{
> +}
> +
> +void
> +neighbor_table_notify_destroy(void)
> +{
> +}
> diff --git a/controller/neighbor-table-notify.c 
> b/controller/neighbor-table-notify.c
> new file mode 100644
> index 000000000..0f0c96ac6
> --- /dev/null
> +++ b/controller/neighbor-table-notify.c
> @@ -0,0 +1,244 @@
> +/* Copyright (c) 2025, Red Hat, Inc.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at:
> + *
> + *     http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#include <config.h>
> +
> +#include <linux/rtnetlink.h>
> +#include <net/if.h>
> +
> +#include "hash.h"
> +#include "hmapx.h"
> +#include "lib/util.h"
> +#include "netlink-notifier.h"
> +#include "openvswitch/vlog.h"
> +
> +#include "neighbor-exchange-netlink.h"
> +#include "neighbor-table-notify.h"
> +
> +VLOG_DEFINE_THIS_MODULE(neighbor_table_notify);
> +
> +struct neighbor_table_watch_request {
> +    struct hmap_node node;
> +    int32_t if_index;
> +    char if_name[IFNAMSIZ + 1];
> +};
> +
> +struct neighbor_table_watch_entry {
> +    struct hmap_node node;
> +    int32_t if_index;
> +    char if_name[IFNAMSIZ + 1];
> +};
> +
> +static struct hmap watches = HMAP_INITIALIZER(&watches);
> +static bool any_neighbor_table_changed;
> +static struct ne_table_msg nln_nmsg_change;
> +
> +static struct nln *nl_neighbor_handle;
> +static struct nln_notifier *nl_neighbor_notifier;
> +
> +static void neighbor_table_change(const void *change_, void *aux);
> +
> +static void
> +neighbor_table_register_notifiers(void)
> +{
> +    VLOG_INFO("Adding neighbor table watchers.");
> +    ovs_assert(!nl_neighbor_handle);
> +
> +    nl_neighbor_handle = nln_create(NETLINK_ROUTE, ne_table_parse,
> +                                    &nln_nmsg_change);
> +    ovs_assert(nl_neighbor_handle);
> +
> +    nl_neighbor_notifier =
> +        nln_notifier_create(nl_neighbor_handle, RTNLGRP_NEIGH,
> +                            neighbor_table_change, NULL);
> +    if (!nl_neighbor_notifier) {
> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> +        VLOG_WARN_RL(&rl, "Failed to create neighbor table watcher.");
> +    }
> +}
> +
> +static void
> +neighbor_table_deregister_notifiers(void)
> +{
> +    VLOG_INFO("Removing neighbor table watchers.");
> +    ovs_assert(nl_neighbor_handle);
> +
> +    nln_notifier_destroy(nl_neighbor_notifier);
> +    nln_destroy(nl_neighbor_handle);
> +    nl_neighbor_notifier = NULL;
> +    nl_neighbor_handle = NULL;
> +}
> +
> +static uint32_t
> +neighbor_table_notify_hash_watch(int32_t if_index)
> +{
> +    /* To allow lookups triggered by netlink messages, don't include the
> +     * if_name in the hash.  The netlink updates only include if_index. */
> +    return hash_int(if_index, 0);
> +}
> +
> +static void
> +add_watch_entry(int32_t if_index, const char *if_name)
> +{
> +   VLOG_DBG("Registering new neighbor table watcher "
> +            "for if_index %s (%"PRId32").",
> +            if_name, if_index);

s/if_index/interface/ or swap places of the name and the index.

> +
> +    struct neighbor_table_watch_entry *we;
> +    uint32_t hash = neighbor_table_notify_hash_watch(if_index);
> +    we = xzalloc(sizeof *we);
> +    we->if_index = if_index;
> +    ovs_strzcpy(we->if_name, if_name, sizeof we->if_name);
> +    hmap_insert(&watches, &we->node, hash);
> +
> +    if (!nl_neighbor_handle) {
> +        neighbor_table_register_notifiers();
> +    }
> +}
> +
> +static void
> +remove_watch_entry(struct neighbor_table_watch_entry *we)
> +{
> +    VLOG_DBG("Removing neighbor table watcher for if_index %s (%"PRId32").",

s/if_index/interface/ or swap places of the name and the index.

Best regards, Ilya Maximets.
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to