diff --git a/SOURCES/1007-ovs-only-keep-bridges-and-ports-with-NM-interfaces-attached-87167.patch b/SOURCES/1007-ovs-only-keep-bridges-and-ports-with-NM-interfaces-attached-87167.patch new file mode 100644 index 0000000..20346af --- /dev/null +++ b/SOURCES/1007-ovs-only-keep-bridges-and-ports-with-NM-interfaces-attached-87167.patch @@ -0,0 +1,223 @@ +From 78a4e5cf3bd2b8cba19c22826c1a4b99d3d7ef0e Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 16 Apr 2025 14:45:41 +0200 +Subject: [PATCH 1/2] ovs: slightly improve _delete_interface() + +Add comments, and move variables inside the block where they are used. +--- + src/core/devices/ovs/nm-ovsdb.c | 33 +++++++++++++++++++++++---------- + 1 file changed, 23 insertions(+), 10 deletions(-) + +diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c +index 60f6209521..39acf1da46 100644 +--- a/src/core/devices/ovs/nm-ovsdb.c ++++ b/src/core/devices/ovs/nm-ovsdb.c +@@ -1363,54 +1363,57 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + nm_auto_decref_json json_t *bridges = NULL; + nm_auto_decref_json json_t *new_bridges = NULL; + gboolean bridges_changed; +- gboolean ports_changed; +- gboolean interfaces_changed; +- int pi; +- int ii; + + bridges = json_array(); + new_bridges = json_array(); + bridges_changed = FALSE; + ++ /* Loop over all bridges */ + g_hash_table_iter_init(&iter, priv->bridges); + while (g_hash_table_iter_next(&iter, (gpointer) &ovs_bridge, NULL)) { +- nm_auto_decref_json json_t *ports = NULL; +- nm_auto_decref_json json_t *new_ports = NULL; ++ nm_auto_decref_json json_t *ports = NULL; ++ nm_auto_decref_json json_t *new_ports = NULL; ++ gboolean ports_changed = FALSE; ++ int pi; + + ports = json_array(); + new_ports = json_array(); +- ports_changed = FALSE; + ++ /* Add the bridge UUID to the list of known bridges for the "expect" condition */ + json_array_append_new(bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid)); + ++ /* Loop over all bridge's ports */ + for (pi = 0; pi < ovs_bridge->ports->len; pi++) { + nm_auto_decref_json json_t *interfaces = NULL; + nm_auto_decref_json json_t *new_interfaces = NULL; ++ gboolean interfaces_changed = FALSE; ++ int ii; + + interfaces = json_array(); + new_interfaces = json_array(); + port_uuid = g_ptr_array_index(ovs_bridge->ports, pi); + ovs_port = g_hash_table_lookup(priv->ports, &port_uuid); + ++ /* Add the port UUID to the list of known bridge port for the "expect" condition */ + json_array_append_new(ports, json_pack("[s,s]", "uuid", port_uuid)); + +- interfaces_changed = FALSE; +- + if (!ovs_port) { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW("Unknown port '%s' in bridge '%s'", port_uuid, ovs_bridge->bridge_uuid); + continue; + } + ++ /* Loop over all port's interfaces */ + for (ii = 0; ii < ovs_port->interfaces->len; ii++) { + interface_uuid = g_ptr_array_index(ovs_port->interfaces, ii); + ovs_interface = g_hash_table_lookup(priv->interfaces, &interface_uuid); + ++ /* Add the interface UUID to the list of known port interfaces for the "expect" condition */ + json_array_append_new(interfaces, json_pack("[s,s]", "uuid", interface_uuid)); + + if (ovs_interface) { + if (nm_streq(ovs_interface->name, ifname)) { +- /* skip the interface */ ++ /* We are deleting this interface, don't count it */ + interfaces_changed = TRUE; + continue; + } +@@ -1419,32 +1422,42 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + _LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); + } + ++ /* Add the interface to the list of new interfaces to set on the port */ + json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid)); + } + + if (json_array_size(new_interfaces) == 0) { ++ /* The port no longer has any interface. Don't add it to "new_ports" and set ++ * ports_changed=TRUE, so that it will be deleted. */ + ports_changed = TRUE; + } else { + if (interfaces_changed) { ++ /* An interface needs to be deleted from this port */ + _expect_port_interfaces(params, ovs_port->name, interfaces); + _set_port_interfaces(params, ovs_port->name, new_interfaces); + } ++ /* The port is still alive */ + json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid)); + } + } + + if (json_array_size(new_ports) == 0) { ++ /* The bridge no longer has any port. Don't add it to "new_bridges" and set ++ * bridges_changed=TRUE, so that it will be deleted. */ + bridges_changed = TRUE; + } else { + if (ports_changed) { ++ /* A port needs to be deleted from this bridge */ + _expect_bridge_ports(params, ovs_bridge->name, ports); + _set_bridge_ports(params, ovs_bridge->name, new_ports); + } ++ /* The bridge is still alive */ + json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid)); + } + } + + if (bridges_changed) { ++ /* A port needs to be deleted from this bridge */ + _expect_ovs_bridges(params, priv->db_uuid, bridges); + _set_ovs_bridges(params, priv->db_uuid, new_bridges); + } +-- +2.50.1 + + +From 476c89b6f2cd514fca8797bdc503eff60dc3db18 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 16 Apr 2025 15:16:13 +0200 +Subject: [PATCH 2/2] ovs: only keep bridges and ports with NM interfaces + attached + +If a OVS bridge created via NM has a port created externally, when the +bridge connections goes down then NM detaches the NM-created +port. However, it finds that the bridge still has a port (the external +one) and so it doesn't remove the bridge from ovsdb. + +This is a problem, because it means that an explicity deactivation of +the bridge leaves the bridge up. To fix this, only track the number of +port in the bridge actually created by NM. Also, leave alone bridges +not created by NM. +--- + src/core/devices/ovs/nm-ovsdb.c | 28 ++++++++++++++++++++-------- + 1 file changed, 20 insertions(+), 8 deletions(-) + +diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c +index 39acf1da46..b36d4bb09b 100644 +--- a/src/core/devices/ovs/nm-ovsdb.c ++++ b/src/core/devices/ovs/nm-ovsdb.c +@@ -1373,19 +1373,27 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + while (g_hash_table_iter_next(&iter, (gpointer) &ovs_bridge, NULL)) { + nm_auto_decref_json json_t *ports = NULL; + nm_auto_decref_json json_t *new_ports = NULL; ++ guint num_nm_ports = 0; + gboolean ports_changed = FALSE; + int pi; + +- ports = json_array(); +- new_ports = json_array(); ++ ports = json_array(); ++ new_ports = json_array(); + + /* Add the bridge UUID to the list of known bridges for the "expect" condition */ + json_array_append_new(bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid)); + ++ if (!ovs_bridge->connection_uuid) { ++ /* Externally created, don't touch it */ ++ json_array_append_new(new_bridges, json_pack("[s,s]", "uuid", ovs_bridge->bridge_uuid)); ++ continue; ++ } ++ + /* Loop over all bridge's ports */ + for (pi = 0; pi < ovs_bridge->ports->len; pi++) { +- nm_auto_decref_json json_t *interfaces = NULL; +- nm_auto_decref_json json_t *new_interfaces = NULL; ++ nm_auto_decref_json json_t *interfaces = NULL; ++ nm_auto_decref_json json_t *new_interfaces = NULL; ++ guint num_nm_interfaces = 0; + gboolean interfaces_changed = FALSE; + int ii; + +@@ -1417,6 +1425,8 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + interfaces_changed = TRUE; + continue; + } ++ if (ovs_interface->connection_uuid) ++ num_nm_interfaces++; + } else { + /* This would be a violation of ovsdb's reference integrity (a bug). */ + _LOGW("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid); +@@ -1426,8 +1436,8 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + json_array_append_new(new_interfaces, json_pack("[s,s]", "uuid", interface_uuid)); + } + +- if (json_array_size(new_interfaces) == 0) { +- /* The port no longer has any interface. Don't add it to "new_ports" and set ++ if (num_nm_interfaces == 0) { ++ /* The port no longer has any NM interface. Don't add it to "new_ports" and set + * ports_changed=TRUE, so that it will be deleted. */ + ports_changed = TRUE; + } else { +@@ -1438,11 +1448,13 @@ _delete_interface(NMOvsdb *self, json_t *params, const char *ifname) + } + /* The port is still alive */ + json_array_append_new(new_ports, json_pack("[s,s]", "uuid", port_uuid)); ++ if (ovs_port->connection_uuid) ++ num_nm_ports++; + } + } + +- if (json_array_size(new_ports) == 0) { +- /* The bridge no longer has any port. Don't add it to "new_bridges" and set ++ if (num_nm_ports == 0) { ++ /* The bridge no longer has any NM port. Don't add it to "new_bridges" and set + * bridges_changed=TRUE, so that it will be deleted. */ + bridges_changed = TRUE; + } else { +-- +2.50.1 + diff --git a/SOURCES/1008-device-update-the-external-down-unmanaged-flag-on-port-attach-release-93183.patch b/SOURCES/1008-device-update-the-external-down-unmanaged-flag-on-port-attach-release-93183.patch new file mode 100644 index 0000000..9d852ff --- /dev/null +++ b/SOURCES/1008-device-update-the-external-down-unmanaged-flag-on-port-attach-release-93183.patch @@ -0,0 +1,64 @@ +From fd3eccfb1612a3bac87232e1cbaabc10da80c302 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 7 May 2025 15:19:03 +0200 +Subject: [PATCH] device: update the external-down unmanaged flag on port + attach/release + +A device has the "external-down" unmanaged flag when: + + !is-created-by-nm AND (!is-up OR (!has-address AND !is-controller)) + +When the "is-up" or the "has-address" conditions change, we properly update +the unmanaged flag by calling _dev_unmanaged_check_external_down() in +_dev_l3_cfg_notify_cb(PLATFORM_CHANGE_ON_IDLE). + +The "is-controller" condition changes when another link indicates the +current device as controller. We currently don't update the unmanaged flag +when that happens and so it's possible that the device stays unmanaged even +if it has a port. This can be easily reproduced by running this commands: + + ip link add veth0 type veth peer name veth1 + ip link add vrf0 type vrf table 10 + ip link set vrf0 up + ip link set veth0 master vrf0 + +Sometimes, the device shows as "unmanaged" instead of "connected +(externally)". + +Fix this by re-evaluating the "external-down" unmanaged flags on the +controller when a port is attached or detached. + +Fixes: c3586ce01a5b ('device: consider a device with slaves configured') + +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2209 +--- + src/core/devices/nm-device.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c +index fc6efb2b3c..793378be88 100644 +--- a/src/core/devices/nm-device.c ++++ b/src/core/devices/nm-device.c +@@ -7158,6 +7158,9 @@ nm_device_controller_release_port(NMDevice *self, + NM_UNMANAGED_IS_PORT, + NM_UNMAN_FLAG_OP_FORGET, + NM_DEVICE_STATE_REASON_REMOVED); ++ ++ /* Once the port is detached, unmanaged-external-down might change */ ++ _dev_unmanaged_check_external_down(self, FALSE, FALSE); + } + + /*****************************************************************************/ +@@ -8852,6 +8855,9 @@ nm_device_controller_add_port(NMDevice *self, NMDevice *port, gboolean configure + } else + g_return_val_if_fail(port_priv->controller == self, FALSE); + ++ /* Once the port is attached, unmanaged-external-down might change */ ++ _dev_unmanaged_check_external_down(self, TRUE, FALSE); ++ + nm_device_queue_recheck_assume(self); + nm_device_queue_recheck_assume(port); + +-- +2.50.1 + diff --git a/SOURCES/1009-ovs-set-the-tun-interface-up-before-stage3-98550.patch b/SOURCES/1009-ovs-set-the-tun-interface-up-before-stage3-98550.patch new file mode 100644 index 0000000..89514f3 --- /dev/null +++ b/SOURCES/1009-ovs-set-the-tun-interface-up-before-stage3-98550.patch @@ -0,0 +1,217 @@ +From 46e0d2b4e4eb5948db12186a3c60d3fd98ae8cd4 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Wed, 4 Jun 2025 10:57:51 +0200 +Subject: [PATCH] ovs: set the tun interface up before stage3 + +When using the netdev datapath, we wait that the tun link appears, we +call nm_device_set_ip_ifindex() (which also brings the link up) and +then we check that the link is ready, i.e. that udev has announced the +link and the MAC address is correct. After that, we schedule stage3 +(ip-config). + +In this, there is a race condition that occurs sometimes in NMCI test +ovs_datapath_type_netdev_with_cloned_mac. In rare conditions, +nm_device_set_ip_ifindex() bring the interface up but then ovs-vswitch +changes again the flags of the interface without IFF_UP. The result is +that the interface stays down, breaking communications. + +To fix this, we need to always call nm_device_bring_up() after the tun +device is ready. The problem is that we can't do it in +_netdev_tun_link_cb() because that function is already invoked +synchronously from platform code. + +Instead, simplify the handling of the netdev datapath. Every +"link-changed" event from platform is handled by +_netdev_tun_link_cb(), which always schedule a delayed function +_netdev_tun_link_cb_in_idle(). This function just assigns the +ip-ifindex to the device if missing, and starts stage3 if the link is +ready. While doing so, it also bring the interface up. + +Fixes: 99a6c6eda6e1 ('ovs, dpdk: fix creating ovs-interface when the ovs-bridge is netdev') + +https://issues.redhat.com/browse/RHEL-17358 + +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2218 +--- + .../devices/ovs/nm-device-ovs-interface.c | 100 ++++++++---------- + 1 file changed, 42 insertions(+), 58 deletions(-) + +diff --git a/src/core/devices/ovs/nm-device-ovs-interface.c b/src/core/devices/ovs/nm-device-ovs-interface.c +index 271dedeab3..922ed34571 100644 +--- a/src/core/devices/ovs/nm-device-ovs-interface.c ++++ b/src/core/devices/ovs/nm-device-ovs-interface.c +@@ -28,16 +28,18 @@ typedef struct { + NMOvsdb *ovsdb; + + struct { +- /* The source for the idle handler to set the TUN ifindex */ +- GSource *tun_set_ifindex_idle_source; +- /* The cloned MAC to set */ +- char *cloned_mac; +- /* The id for the signal watching the TUN link to appear/change */ ++ /* The signal id for the TUN link-changed event */ + gulong tun_link_signal_id; +- /* The TUN ifindex to set in the idle handler */ ++ /* The idle handler source for the TUN link-changed event */ ++ GSource *tun_link_idle_source; ++ /* The ifindex for the TUN link-changed event */ + int tun_ifindex; ++ ++ /* The cloned MAC to set */ ++ char *cloned_mac; + /* Whether we have determined the cloned MAC */ + bool cloned_mac_evaluated : 1; ++ + /* Whether we are waiting for the kernel link */ + bool waiting : 1; + } wait_link; +@@ -263,39 +265,33 @@ ready_for_ip_config(NMDevice *device, gboolean is_manual) + } + + static gboolean +-_set_ip_ifindex_tun(gpointer user_data) ++_netdev_tun_link_cb_in_idle(gpointer user_data) + { + NMDevice *device = user_data; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); + +- _LOGT(LOGD_CORE, +- "ovs-wait-link: setting ip-ifindex %d from tun interface", +- priv->wait_link.tun_ifindex); +- +- nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); +- +- nm_device_set_ip_ifindex(device, priv->wait_link.tun_ifindex); +- +- if (check_waiting_for_link(device, "set-ip-ifindex-tun")) { +- /* If the link is not ready, it means the MAC is not set yet. We don't have +- * a convenient way to monitor for ip-ifindex changes other than listening +- * for platform events again.*/ +- nm_assert(!priv->wait_link.tun_link_signal_id); +- priv->wait_link.tun_link_signal_id = g_signal_connect(nm_device_get_platform(device), +- NM_PLATFORM_SIGNAL_LINK_CHANGED, +- G_CALLBACK(_netdev_tun_link_cb), +- self); +- return G_SOURCE_CONTINUE; ++ if (nm_device_get_ip_ifindex(device) <= 0) { ++ _LOGT(LOGD_CORE, ++ "ovs-wait-link: setting ip-ifindex %d from tun link", ++ priv->wait_link.tun_ifindex); ++ nm_device_set_ip_ifindex(device, priv->wait_link.tun_ifindex); + } + +- _LOGT(LOGD_CORE, "tun link is ready"); ++ if (check_waiting_for_link(device, "tun-link-changed")) { ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); ++ return G_SOURCE_CONTINUE; ++ } + ++ _LOGT(LOGD_CORE, "ovs-wait-link: tun link is ready"); + nm_device_link_properties_set(device, FALSE); ++ nm_device_bring_up(device); + + nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); + nm_device_activate_schedule_stage3_ip_config(device, FALSE); ++ nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + + return G_SOURCE_CONTINUE; + } +@@ -311,40 +307,28 @@ _netdev_tun_link_cb(NMPlatform *platform, + const NMPlatformSignalChangeType change_type = change_type_i; + NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE(device); + NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE(self); +- int ip_ifindex; + +- if (pllink->type != NM_LINK_TYPE_TUN || !nm_streq0(pllink->name, nm_device_get_iface(device))) ++ /* This is the handler for the link-changed platform events. It is triggered for all ++ * link changes. Keep only the ones matching our device. */ ++ if (!NM_IN_SET(change_type, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED)) + return; +- +- ip_ifindex = nm_device_get_ip_ifindex(device); +- if (ip_ifindex > 0) { +- /* When we have an ifindex, we are only waiting for the MAC to settle */ +- if (change_type != NM_PLATFORM_SIGNAL_CHANGED) +- return; +- +- if (!check_waiting_for_link(device, "tun-link-changed")) { +- _LOGT(LOGD_CORE, "ovs-wait-link: tun link is ready, cloned MAC is set"); +- +- nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); +- nm_device_link_properties_set(device, FALSE); +- +- nm_device_devip_set_state(device, AF_INET, NM_DEVICE_IP_STATE_PENDING, NULL); +- nm_device_devip_set_state(device, AF_INET6, NM_DEVICE_IP_STATE_PENDING, NULL); +- nm_device_activate_schedule_stage3_ip_config(device, FALSE); +- } +- return; +- } +- +- /* No ip-ifindex on the device, set it when the link appears */ +- if (change_type != NM_PLATFORM_SIGNAL_ADDED) ++ if (pllink->type != NM_LINK_TYPE_TUN || !nm_streq0(pllink->name, nm_device_get_iface(device))) + return; + + _LOGT(LOGD_CORE, +- "ovs-wait-link: found matching tun interface, schedule set-ip-ifindex(%d)", ++ "ovs-wait-link: got platform event \'%s\' for ifindex %d, scheduling idle handler", ++ change_type == NM_PLATFORM_SIGNAL_ADDED ? "added" : "changed", + ifindex); +- nm_clear_g_signal_handler(platform, &priv->wait_link.tun_link_signal_id); +- priv->wait_link.tun_ifindex = ifindex; +- priv->wait_link.tun_set_ifindex_idle_source = nm_g_idle_add_source(_set_ip_ifindex_tun, device); ++ ++ /* The handler is invoked by the platform synchronously in the netlink receive loop. ++ * We can't perform other platform operations (like bringing the interface up) since ++ * the code there is not re-entrant. Schedule an idle handler. */ ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); ++ priv->wait_link.tun_link_idle_source = ++ nm_g_idle_add_source(_netdev_tun_link_cb_in_idle, device); ++ priv->wait_link.tun_ifindex = ifindex; ++ ++ return; + } + + static gboolean +@@ -466,7 +450,7 @@ act_stage3_ip_config(NMDevice *device, int addr_family) + nm_device_activate_schedule_stage3_ip_config(device, TRUE); + return; + } +- nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); + + nm_device_link_properties_set(device, FALSE); +@@ -490,7 +474,7 @@ deactivate(NMDevice *device) + priv->wait_link.cloned_mac_evaluated = FALSE; + nm_clear_g_free(&priv->wait_link.cloned_mac); + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); +- nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + } + + typedef struct { +@@ -583,7 +567,7 @@ deactivate_async(NMDevice *device, + _LOGT(LOGD_CORE, "deactivate: start async"); + + nm_clear_g_signal_handler(nm_device_get_platform(device), &priv->wait_link.tun_link_signal_id); +- nm_clear_g_source_inst(&priv->wait_link.tun_set_ifindex_idle_source); ++ nm_clear_g_source_inst(&priv->wait_link.tun_link_idle_source); + priv->wait_link.tun_ifindex = -1; + priv->wait_link.cloned_mac_evaluated = FALSE; + nm_clear_g_free(&priv->wait_link.cloned_mac); +@@ -706,7 +690,7 @@ dispose(GObject *object) + + nm_assert(!priv->wait_link.waiting); + nm_assert(priv->wait_link.tun_link_signal_id == 0); +- nm_assert(!priv->wait_link.tun_set_ifindex_idle_source); ++ nm_assert(!priv->wait_link.tun_link_idle_source); + + if (priv->ovsdb) { + g_signal_handlers_disconnect_by_func(priv->ovsdb, G_CALLBACK(ovsdb_ready), self); +-- +2.50.1 + diff --git a/SOURCES/1010-bridge-fix-reapplying-port-VLANs-102742.patch b/SOURCES/1010-bridge-fix-reapplying-port-VLANs-102742.patch new file mode 100644 index 0000000..ac4b5fe --- /dev/null +++ b/SOURCES/1010-bridge-fix-reapplying-port-VLANs-102742.patch @@ -0,0 +1,82 @@ +From 1489f9d0e32ac1e9f5f86f5fc940a3c8ed6fc17e Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Tue, 8 Jul 2025 15:09:25 +0200 +Subject: [PATCH 1/2] bridge: fix reapplying port VLANs + +If the bridge default-pvid is zero, it means that the default PVID is +disabled. That is, the bridge PVID is not propagated to ports. + +Currently NM tries to merge the existing bridge VLANs on the port with +the default PVID from the bridge, even when the PVID is zero. This +causes an error when setting the new VLAN list in the kernel, because +it rejects VLAN zero. + +Skip the merge of the default PVID when zero. + +Fixes: c5d1e35f993e ('device: support reapplying bridge-port VLANs') +(cherry picked from commit bf79fbd6780fd38ca29c12a137951c8729379767) +(cherry picked from commit 956f9ba365c18bf00d91ffd0842c09932dd9a5ec) +--- + src/core/devices/nm-device-bridge.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c +index 7c34fde07f..45cdd83f07 100644 +--- a/src/core/devices/nm-device-bridge.c ++++ b/src/core/devices/nm-device-bridge.c +@@ -735,6 +735,11 @@ merge_bridge_vlan_default_pvid(NMPlatformBridgeVlan *vlans, guint *num_vlans, gu + gboolean has_pvid = FALSE; + guint i; + ++ if (default_pvid == 0) { ++ /* default_pvid=0 means that the default PVID is disabled. No need to merge it. */ ++ return vlans; ++ } ++ + for (i = 0; i < *num_vlans; i++) { + if (vlans[i].pvid) { + has_pvid = TRUE; +-- +2.50.1 + + +From 0135379ac48b71f5029c72f368b44d9e1244ef80 Mon Sep 17 00:00:00 2001 +From: Beniamino Galvani +Date: Tue, 8 Jul 2025 17:16:25 +0200 +Subject: [PATCH 2/2] device: accept changes to the bond-port.vlans during + reapply + +Commit c5d1e35f993e ('device: support reapplying bridge-port VLANs') +didn't update can_reapply_change() to accept the "bridge-port.vlans" +property during a reapply. So, it was only possible to change the +bridge port VLANs by updating the "bridge.vlan-default-pvid" property +and doing a reapply. Fix that. + +Fixes: c5d1e35f993e ('device: support reapplying bridge-port VLANs') +(cherry picked from commit 261fa8db336e0571479567e2bda10dbf5d171b0a) +(cherry picked from commit c647c060d6dabefeb05f6be6c4af8778437d9a1e) +--- + src/core/devices/nm-device.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c +index 2f2f25a5b8..dee160ed90 100644 +--- a/src/core/devices/nm-device.c ++++ b/src/core/devices/nm-device.c +@@ -14003,6 +14003,13 @@ can_reapply_change(NMDevice *self, + return TRUE; + } + ++ if (nm_streq(setting_name, NM_SETTING_BRIDGE_PORT_SETTING_NAME)) { ++ return nm_device_hash_check_invalid_keys(diffs, ++ NM_SETTING_BRIDGE_PORT_SETTING_NAME, ++ error, ++ NM_SETTING_BRIDGE_PORT_VLANS); ++ } ++ + out_fail: + g_set_error(error, + NM_DEVICE_ERROR, +-- +2.50.1 + diff --git a/SOURCES/1011-device-dont-disable-IPv6-in-stage3-on-reapply-102771.patch b/SOURCES/1011-device-dont-disable-IPv6-in-stage3-on-reapply-102771.patch new file mode 100644 index 0000000..b05b14a --- /dev/null +++ b/SOURCES/1011-device-dont-disable-IPv6-in-stage3-on-reapply-102771.patch @@ -0,0 +1,54 @@ +From 9bbb1139872b6a3cb21e1c08c7853057b4ee2674 Mon Sep 17 00:00:00 2001 +From: Lubomir Rintel +Date: Mon, 30 Jun 2025 15:50:44 +0200 +Subject: [PATCH] device: don't disable IPv6 in stage3 on reapply + +Currently, when a call to Reapply() results in stage3 being re-run, IPv6 +ends up messed up. Like this: + + $ nmcli device modify eth0 ipv4.address '' + $ nmcli device modify eth0 ipv4.address 172.31.13.37/24 + $ + + NetworkManager[666]: [1751286095.2070] device[c95ca04a69467d81] (eth0): ip4: reapply... + ... + NetworkManager[666]: [1751286095.2104] device[c95ca04a69467d81] (eth0): ip6: addrgenmode6: set none (already set) + NetworkManager[666]: [1751286095.2105] device[c95ca04a69467d81] (eth0): ip6: addrgenmode6: toggle disable_ipv6 sysctl after disabling addr-gen-mode + NetworkManager[666]: [1751286095.2105] platform-linux: sysctl: setting '/proc/sys/net/ipv6/conf/eth0/disable_ipv6' to '1' (current value is '0') + NetworkManager[666]: [1751286095.2106] platform-linux: sysctl: setting '/proc/sys/net/ipv6/conf/eth0/disable_ipv6' to '0' (current value is '1') + NetworkManager[666]: [1751286095.2106] platform-linux: sysctl: setting '/proc/sys/net/ipv6/conf/eth0/accept_ra' to '0' (current value is identical) + NetworkManager[666]: [1751286095.2106] platform-linux: sysctl: setting '/proc/sys/net/ipv6/conf/eth0/disable_ipv6' to '0' (current value is identical) + +Not only is this unnecessary because addr-gen-mode already has the +desired value (as is logged), but also wipes off all IPv6 configuration. +This is fine on initial configuration, but not on Reapply(). + +Let's look at the device state first: if we've progressed past ip-config +state, then we can't possibly ever touch the offending sysctls. It's +okay -- we don't need to: addr-gen-mode is going to be set right if we +went through ip-config before. + +Resolves: https://issues.redhat.com/browse/NMT-1681 + +https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2232 +--- + src/core/devices/nm-device.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c +index 7aaf4d78ed..9e0a53cd32 100644 +--- a/src/core/devices/nm-device.c ++++ b/src/core/devices/nm-device.c +@@ -13437,7 +13437,8 @@ activate_stage3_ip_config(NMDevice *self) + * IPv6LL if this is not an assumed connection, since assumed connections + * will already have IPv6 set up. + */ +- if (!nm_device_managed_type_is_external_or_assume(self)) ++ if ((priv->state <= NM_DEVICE_STATE_IP_CONFIG || priv->ip_data_6.do_reapply) ++ && !nm_device_managed_type_is_external_or_assume(self)) + _dev_addrgenmode6_set(self, NM_IN6_ADDR_GEN_MODE_NONE); + + /* Re-enable IPv6 on the interface */ +-- +2.50.1 + diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec index f6b5756..12b9d54 100644 --- a/SPECS/NetworkManager.spec +++ b/SPECS/NetworkManager.spec @@ -7,7 +7,7 @@ %global real_version 1.52.0 %global git_tag_version_suffix %{nil} %global rpm_version %{real_version} -%global release_version 5 +%global release_version 7 %global snapshot %{nil} %global git_sha %{nil} %global bcond_default_debug 0 @@ -196,6 +196,11 @@ Patch1003: 1003-dns-Fix-invalid-memory-access-on-Dnsconfd-DBUS-error-84692.patch Patch1004: 1004-ovs-allow-reapplying-ovs-bridge-and-ovs-port-properties-87595.patch Patch1005: 1005-core-ovs-fix-NULL-pointer-dereference-in-ovsdb-read-timeout-callback-87347.patch Patch1006: 1006-fix-crash-in-dns-options-rhel-92313.patch +Patch1007: 1007-ovs-only-keep-bridges-and-ports-with-NM-interfaces-attached-87167.patch +Patch1008: 1008-device-update-the-external-down-unmanaged-flag-on-port-attach-release-93183.patch +Patch1009: 1009-ovs-set-the-tun-interface-up-before-stage3-98550.patch +Patch1010: 1010-bridge-fix-reapplying-port-VLANs-102742.patch +Patch1011: 1011-device-dont-disable-IPv6-in-stage3-on-reapply-102771.patch Requires(post): systemd Requires(post): systemd-udev @@ -1087,6 +1092,16 @@ fi %changelog +* Wed Aug 13 2025 Vladimír Beneš - 1:1.52.0-7 +- ovs: only keep bridges and ports with NM interfaces attached #2 (RHEL-87167) + +* Tue Aug 12 2025 Vladimír Beneš - 1:1.52.0-6 +- ovs: only keep bridges and ports with NM interfaces attached (RHEL-87167) +- device: update the external-down unmanaged flag on port attach/release (RHEL-93183) +- ovs: set the tun interface up before stage3 (RHEL-98550) +- bridge: fix reapplying port VLANs (RHEL-102742) +- device: don't disable IPv6 in stage3 on reapply (RHEL-102771) + * Fri Jul 18 2025 Íñigo Huguet - 1:1.52.0-5 - Fix crash in DNS options evaluation (RHEL-92313) @@ -1107,7 +1122,7 @@ fi - Always reset retries when unblocking children or ports (RHEL-78122) - Prevent the activation of unavailable OVS interfaces (RHEL-79997) -* Mon Fed 17 2025 Beniamino Galvani - 1:1.51.90-2 +* Mon Feb 17 2025 Beniamino Galvani - 1:1.51.90-2 - Fix state handling in the dnsconfd DNS plugin (RHEL-79693) * Wed Feb 12 2025 Filip Pokryvka - 1:1.51.90-1