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