From: Dumitru Ceara <dce...@redhat.com> When monitoring and updating (Linux) neighbor tables through Netlink, the interfaces in question are identified by if-index. It's more CMS-friendly to allow OVN to be configured to track interfaces by name.
In order to achieve that, we introduce a new host-if-monitor module which tracks the if-index <-> if-name mapping for relevant interfaces. NOTE: OVS has the lib/if-notifier.[ch] module already. However, that is not really useful for the OVN use case because it doesn't really pass the struct rtnetlink_change message to its registered callbacks. Signed-off-by: Dumitru Ceara <dce...@redhat.com> --- controller/automake.mk | 5 +- controller/host-if-monitor-stub.c | 43 +++++++++ controller/host-if-monitor.c | 150 ++++++++++++++++++++++++++++++ controller/host-if-monitor.h | 30 ++++++ 4 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 controller/host-if-monitor-stub.c create mode 100644 controller/host-if-monitor.c create mode 100644 controller/host-if-monitor.h diff --git a/controller/automake.mk b/controller/automake.mk index 6af6ee2a9..6eca5e8ed 100644 --- a/controller/automake.mk +++ b/controller/automake.mk @@ -64,10 +64,12 @@ controller_ovn_controller_SOURCES = \ controller/route.c \ controller/garp_rarp.h \ controller/garp_rarp.c \ - controller/neighbor-table-notify.h + controller/neighbor-table-notify.h \ + controller/host-if-monitor.h if HAVE_NETLINK controller_ovn_controller_SOURCES += \ + controller/host-if-monitor.c \ controller/neighbor-exchange-netlink.h \ controller/neighbor-exchange-netlink.c \ controller/neighbor-table-notify.c \ @@ -77,6 +79,7 @@ controller_ovn_controller_SOURCES += \ controller/route-table-notify.c else controller_ovn_controller_SOURCES += \ + controller/host-if-monitor-stub.c \ controller/neighbor-table-notify-stub.c \ controller/route-exchange-stub.c \ controller/route-table-notify-stub.c diff --git a/controller/host-if-monitor-stub.c b/controller/host-if-monitor-stub.c new file mode 100644 index 000000000..b174cf996 --- /dev/null +++ b/controller/host-if-monitor-stub.c @@ -0,0 +1,43 @@ +/* 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 "host-if-monitor.h" + +void +host_if_monitor_wait(void) +{ +} + +bool +host_if_monitor_run(void) +{ + return false; +} + +void +host_if_monitor_update_watches(const struct sset *if_names OVS_UNUSED) +{ +} + +int32_t +host_if_monitor_ifname_toindex(const char *if_name OVS_UNUSED) +{ + return 0; +} diff --git a/controller/host-if-monitor.c b/controller/host-if-monitor.c new file mode 100644 index 000000000..26edb03d0 --- /dev/null +++ b/controller/host-if-monitor.c @@ -0,0 +1,150 @@ +/* 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 "lib/rtnetlink.h" +#include "lib/simap.h" +#include "openvswitch/vlog.h" + +#include "host-if-monitor.h" + +VLOG_DEFINE_THIS_MODULE(host_if_monitor); + +static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1); + +struct host_if_monitor { + struct nln_notifier *link_notifier; + + struct sset watched_interfaces; + struct simap ifname_to_ifindex; + + bool changes_detected; +}; + +static struct host_if_monitor monitor = (struct host_if_monitor) { + .link_notifier = NULL, + .watched_interfaces = SSET_INITIALIZER(&monitor.watched_interfaces), + .ifname_to_ifindex = SIMAP_INITIALIZER(&monitor.ifname_to_ifindex), + .changes_detected = false, +}; + +static void if_notifier_cb(const struct rtnetlink_change *, void *aux); + +void +host_if_monitor_wait(void) +{ + rtnetlink_wait(); +} + +bool +host_if_monitor_run(void) +{ + monitor.changes_detected = false; + + /* If any relevant interface if-index <-> if-name mapping changes are + * dected, monitor.changes_detected will be updated accordingly by the + * if_notifier_cb(). */ + rtnetlink_run(); + + return monitor.changes_detected; +} + +void +host_if_monitor_update_watches(const struct sset *if_names) +{ + struct sset new_if_names = SSET_INITIALIZER(&new_if_names); + const char *if_name; + + /* The notifier only triggers the callback on interface updates. + * For newly added ones we need to fetch the initial if_index ourselves. + */ + SSET_FOR_EACH (if_name, if_names) { + if (!sset_contains(&monitor.watched_interfaces, if_name)) { + sset_add(&new_if_names, if_name); + } + } + + if (!sset_equals(&monitor.watched_interfaces, if_names)) { + sset_destroy(&monitor.watched_interfaces); + sset_clone(&monitor.watched_interfaces, if_names); + } + + if (!sset_is_empty(&monitor.watched_interfaces)) { + if (!monitor.link_notifier) { + VLOG_INFO_RL(&rl, "Enabling host interface monitor"); + monitor.link_notifier = + rtnetlink_notifier_create(if_notifier_cb, &monitor); + } + /* Get initial state for new interfaces. + * + * NOTE: it's important that we have the initial state (if-index) for + * newly watched interfaces because of two reasons: + * - we need to be able to reconcile and preserve still valid learned + * remote FDB entries and remote VTEPs + * - the if_notifier_cb is called only on updates of interfaces + * therefore if existing interfaces don't change the notifier + * callback is not called. + */ + SSET_FOR_EACH (if_name, &new_if_names) { + simap_put(&monitor.ifname_to_ifindex, if_name, + if_nametoindex(if_name)); + } + } else { + if (monitor.link_notifier) { + VLOG_INFO_RL(&rl, "Disabling host interface monitor"); + rtnetlink_notifier_destroy(monitor.link_notifier); + monitor.link_notifier = NULL; + } + } + + sset_destroy(&new_if_names); +} + +int32_t +host_if_monitor_ifname_toindex(const char *if_name) +{ + return simap_get(&monitor.ifname_to_ifindex, if_name); +} + +static void +if_notifier_cb(const struct rtnetlink_change *change, void *aux OVS_UNUSED) +{ + if (!change || change->irrelevant) { + return; + } + + switch (change->nlmsg_type) { + case RTM_NEWLINK: + if ((change->ifi_flags & IFF_UP) + && sset_find(&monitor.watched_interfaces, change->ifname)) { + simap_put(&monitor.ifname_to_ifindex, + change->ifname, change->if_index); + monitor.changes_detected = true; + } + break; + case RTM_DELLINK: + if (sset_find(&monitor.watched_interfaces, change->ifname)) { + simap_find_and_delete(&monitor.ifname_to_ifindex, change->ifname); + monitor.changes_detected = true; + } + break; + default: + break; + } +} diff --git a/controller/host-if-monitor.h b/controller/host-if-monitor.h new file mode 100644 index 000000000..a41c5869c --- /dev/null +++ b/controller/host-if-monitor.h @@ -0,0 +1,30 @@ +/* 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. + */ + +#ifndef HOST_IF_MONITOR_H +#define HOST_IF_MONITOR_H 1 + +#include <stdint.h> +#include "lib/sset.h" +#include "lib/smap.h" + +void host_if_monitor_wait(void); +bool host_if_monitor_run(void); + +void host_if_monitor_update_watches(const struct sset *if_names); + +int32_t host_if_monitor_ifname_toindex(const char *if_name); + +#endif /* HOST_IF_MONITOR_H */ -- 2.50.0 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev