Blame SOURCES/1002-ovs-fix-setting-mac-rh1852106.patch

b35f49
From 3b29cd7eee7ba07f0f4750382819a9a53502124c Mon Sep 17 00:00:00 2001
b35f49
From: Beniamino Galvani <bgalvani@redhat.com>
b35f49
Date: Wed, 1 Jul 2020 10:55:01 +0200
b35f49
Subject: [PATCH 1/3] ovs: set MAC address on the bridge for local interfaces
b35f49
b35f49
When a user creates a ovs-interface with the same name of the parent
b35f49
ovs-bridge, openvswitch considers the interface as the "local
b35f49
interface" [1] and assigns the MAC address of the bridge to the
b35f49
interface [2].
b35f49
b35f49
This is confusing for users, as the cloned MAC property is ignored in
b35f49
some cases, depending on the ovs-interface name.
b35f49
b35f49
Instead, detect when the interface is local and set the MAC from the
b35f49
ovs-interface connection in the bridge table.
b35f49
b35f49
[1] https://github.com/openvswitch/ovs/blob/v2.13.0/vswitchd/vswitch.xml#L2546
b35f49
[2] https://github.com/openvswitch/ovs/blob/v2.13.0/vswitchd/bridge.c#L4744
b35f49
b35f49
(cherry picked from commit 5d4c8521a38c166a9a0aafe5be2bd0545084e154)
b35f49
(cherry picked from commit 7548c29a89e12349fdfe196e96d65a6abae74cb5)
b35f49
---
b35f49
 src/devices/ovs/nm-ovsdb.c | 114 +++++++++++++++++++++++++------------
b35f49
 1 file changed, 77 insertions(+), 37 deletions(-)
b35f49
b35f49
diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
b35f49
index e1865f9de..0b3fa3fdb 100644
b35f49
--- a/src/devices/ovs/nm-ovsdb.c
b35f49
+++ b/src/devices/ovs/nm-ovsdb.c
b35f49
@@ -310,6 +310,18 @@ _set_bridge_ports (json_t *params, const char *ifname, json_t *new_ports)
b35f49
 	);
b35f49
 }
b35f49
 
b35f49
+static void
b35f49
+_set_bridge_mac (json_t *params, const char *ifname, const char *mac)
b35f49
+{
b35f49
+	json_array_append_new (params,
b35f49
+		json_pack ("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}",
b35f49
+		           "op", "update", "table", "Bridge",
b35f49
+		           "row", "other_config", "map",
b35f49
+		           "hwaddr", mac,
b35f49
+		           "where", "name", "==", ifname)
b35f49
+	);
b35f49
+}
b35f49
+
b35f49
 /**
b35f49
  * _expect_port_interfaces:
b35f49
  *
b35f49
@@ -353,15 +365,16 @@ _set_port_interfaces (json_t *params, const char *ifname, json_t *new_interfaces
b35f49
  * Returns an commands that adds new interface from a given connection.
b35f49
  */
b35f49
 static void
b35f49
-_insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_device)
b35f49
+_insert_interface (json_t *params,
b35f49
+                   NMConnection *interface,
b35f49
+                   NMDevice *interface_device,
b35f49
+                   const char *cloned_mac)
b35f49
 {
b35f49
 	const char *type = NULL;
b35f49
 	NMSettingOvsInterface *s_ovs_iface;
b35f49
 	NMSettingOvsDpdk *s_ovs_dpdk;
b35f49
 	NMSettingOvsPatch *s_ovs_patch;
b35f49
 	json_t *options = json_array ();
b35f49
-	gs_free char *cloned_mac = NULL;
b35f49
-	gs_free_error GError *error = NULL;
b35f49
 	json_t *row;
b35f49
 	guint32 mtu = 0;
b35f49
 
b35f49
@@ -377,18 +390,6 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_
b35f49
 			mtu = nm_setting_wired_get_mtu (s_wired);
b35f49
 	}
b35f49
 
b35f49
-	if (!nm_device_hw_addr_get_cloned (interface_device,
b35f49
-	                                   interface,
b35f49
-	                                   FALSE,
b35f49
-	                                   &cloned_mac,
b35f49
-	                                   NULL,
b35f49
-	                                   &error)) {
b35f49
-		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
b35f49
-		       "interface",
b35f49
-		       nm_connection_get_interface_name (interface),
b35f49
-		       error->message);
b35f49
-	}
b35f49
-
b35f49
 	json_array_append_new (options, json_string ("map"));
b35f49
 
b35f49
 	s_ovs_dpdk = (NMSettingOvsDpdk *) nm_connection_get_setting (interface,
b35f49
@@ -490,7 +491,11 @@ _insert_port (json_t *params, NMConnection *port, json_t *new_interfaces)
b35f49
  * Returns an commands that adds new bridge from a given connection.
b35f49
  */
b35f49
 static void
b35f49
-_insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, json_t *new_ports)
b35f49
+_insert_bridge (json_t *params,
b35f49
+                NMConnection *bridge,
b35f49
+                NMDevice *bridge_device,
b35f49
+                json_t *new_ports,
b35f49
+                const char *cloned_mac)
b35f49
 {
b35f49
 	NMSettingOvsBridge *s_ovs_bridge;
b35f49
 	const char *fail_mode = NULL;
b35f49
@@ -499,23 +504,9 @@ _insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, j
b35f49
 	gboolean stp_enable = FALSE;
b35f49
 	const char *datapath_type = NULL;
b35f49
 	json_t *row;
b35f49
-	gs_free_error GError *error = NULL;
b35f49
-	gs_free char *cloned_mac = NULL;
b35f49
 
b35f49
 	s_ovs_bridge = nm_connection_get_setting_ovs_bridge (bridge);
b35f49
 
b35f49
-	if (!nm_device_hw_addr_get_cloned (bridge_device,
b35f49
-	                                   bridge,
b35f49
-	                                   FALSE,
b35f49
-	                                   &cloned_mac,
b35f49
-	                                   NULL,
b35f49
-	                                   &error)) {
b35f49
-		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
b35f49
-		       "bridge",
b35f49
-		       nm_connection_get_interface_name (bridge),
b35f49
-		       error->message);
b35f49
-	}
b35f49
-
b35f49
 	row = json_object ();
b35f49
 
b35f49
 	if (s_ovs_bridge) {
b35f49
@@ -586,6 +577,9 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 	const char *bridge_uuid;
b35f49
 	const char *port_uuid;
b35f49
 	const char *interface_uuid;
b35f49
+	const char *bridge_name;
b35f49
+	const char *port_name;
b35f49
+	const char *interface_name;
b35f49
 	OpenvswitchBridge *ovs_bridge = NULL;
b35f49
 	OpenvswitchPort *ovs_port = NULL;
b35f49
 	OpenvswitchInterface *ovs_interface = NULL;
b35f49
@@ -596,6 +590,10 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 	nm_auto_decref_json json_t *interfaces = NULL;
b35f49
 	nm_auto_decref_json json_t *new_interfaces = NULL;
b35f49
 	gboolean has_interface = FALSE;
b35f49
+	gboolean interface_is_internal;
b35f49
+	gs_free char *bridge_cloned_mac = NULL;
b35f49
+	gs_free char *interface_cloned_mac = NULL;
b35f49
+	GError *error = NULL;
b35f49
 	int pi;
b35f49
 	int ii;
b35f49
 
b35f49
@@ -606,11 +604,51 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 	new_ports = json_array ();
b35f49
 	new_interfaces = json_array ();
b35f49
 
b35f49
+	bridge_name = nm_connection_get_interface_name (bridge);
b35f49
+	port_name = nm_connection_get_interface_name (port);
b35f49
+	interface_name = nm_connection_get_interface_name (interface);
b35f49
+	interface_is_internal = nm_streq0 (bridge_name, interface_name);
b35f49
+
b35f49
+	/* Determine cloned MAC addresses */
b35f49
+	if (!nm_device_hw_addr_get_cloned (bridge_device,
b35f49
+	                                   bridge,
b35f49
+	                                   FALSE,
b35f49
+	                                   &bridge_cloned_mac,
b35f49
+	                                   NULL,
b35f49
+	                                   &error)) {
b35f49
+		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
b35f49
+		       "bridge",
b35f49
+		       bridge_name,
b35f49
+		       error->message);
b35f49
+		g_clear_error (&error);
b35f49
+	}
b35f49
+
b35f49
+	if (!nm_device_hw_addr_get_cloned (interface_device,
b35f49
+	                                   interface,
b35f49
+	                                   FALSE,
b35f49
+	                                   &interface_cloned_mac,
b35f49
+	                                   NULL,
b35f49
+	                                   &error)) {
b35f49
+		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
b35f49
+		       "interface",
b35f49
+		       interface_name,
b35f49
+		       error->message);
b35f49
+		g_clear_error (&error);
b35f49
+	}
b35f49
+
b35f49
+	if (   interface_is_internal
b35f49
+	    && !bridge_cloned_mac
b35f49
+	    && interface_cloned_mac) {
b35f49
+		_LOGT ("'%s' is a local ovs-interface, the MAC will be set on ovs-bridge '%s'",
b35f49
+		       interface_name, bridge_name);
b35f49
+		bridge_cloned_mac = g_steal_pointer (&interface_cloned_mac);
b35f49
+	}
b35f49
+
b35f49
 	g_hash_table_iter_init (&iter, priv->bridges);
b35f49
 	while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) {
b35f49
 		json_array_append_new (bridges, json_pack ("[s, s]", "uuid", bridge_uuid));
b35f49
 
b35f49
-		if (   g_strcmp0 (ovs_bridge->name, nm_connection_get_interface_name (bridge)) != 0
b35f49
+		if (   g_strcmp0 (ovs_bridge->name, bridge_name) != 0
b35f49
 		    || g_strcmp0 (ovs_bridge->connection_uuid, nm_connection_get_uuid (bridge)) != 0)
b35f49
 			continue;
b35f49
 
b35f49
@@ -624,7 +662,7 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 				/* This would be a violation of ovsdb's reference integrity (a bug). */
b35f49
 				_LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid);
b35f49
 				continue;
b35f49
-			} else if (   strcmp (ovs_port->name, nm_connection_get_interface_name (port)) != 0
b35f49
+			} else if (   strcmp (ovs_port->name, port_name) != 0
b35f49
 			           || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) {
b35f49
 				continue;
b35f49
 			}
b35f49
@@ -638,7 +676,7 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 				if (!ovs_interface) {
b35f49
 					/* This would be a violation of ovsdb's reference integrity (a bug). */
b35f49
 					_LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid);
b35f49
-				} else if (   strcmp (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0
b35f49
+				} else if (   strcmp (ovs_interface->name, interface_name) == 0
b35f49
 				           && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) {
b35f49
 					has_interface = TRUE;
b35f49
 				}
b35f49
@@ -661,12 +699,14 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 			_expect_ovs_bridges (params, priv->db_uuid, bridges);
b35f49
 			json_array_append_new (new_bridges, json_pack ("[s, s]", "named-uuid", "rowBridge"));
b35f49
 			_set_ovs_bridges (params, priv->db_uuid, new_bridges);
b35f49
-			_insert_bridge (params, bridge, bridge_device, new_ports);
b35f49
+			_insert_bridge (params, bridge, bridge_device, new_ports, bridge_cloned_mac);
b35f49
 		} else {
b35f49
 			/* Bridge already exists. */
b35f49
 			g_return_if_fail (ovs_bridge);
b35f49
 			_expect_bridge_ports (params, ovs_bridge->name, ports);
b35f49
-			_set_bridge_ports (params, nm_connection_get_interface_name (bridge), new_ports);
b35f49
+			_set_bridge_ports (params, bridge_name, new_ports);
b35f49
+			if (bridge_cloned_mac && interface_is_internal)
b35f49
+				_set_bridge_mac (params, bridge_name, bridge_cloned_mac);
b35f49
 		}
b35f49
 
b35f49
 		json_array_append_new (new_ports, json_pack ("[s, s]", "named-uuid", "rowPort"));
b35f49
@@ -675,11 +715,11 @@ _add_interface (NMOvsdb *self, json_t *params,
b35f49
 		/* Port already exists */
b35f49
 		g_return_if_fail (ovs_port);
b35f49
 		_expect_port_interfaces (params, ovs_port->name, interfaces);
b35f49
-		_set_port_interfaces (params, nm_connection_get_interface_name (port), new_interfaces);
b35f49
+		_set_port_interfaces (params, port_name, new_interfaces);
b35f49
 	}
b35f49
 
b35f49
 	if (!has_interface) {
b35f49
-		_insert_interface (params, interface, interface_device);
b35f49
+		_insert_interface (params, interface, interface_device, interface_cloned_mac);
b35f49
 		json_array_append_new (new_interfaces, json_pack ("[s, s]", "named-uuid", "rowInterface"));
b35f49
 	}
b35f49
 }
b35f49
-- 
b35f49
2.26.2
b35f49
b35f49
From 3df555a42166f0f1ec50e6bdb38f1719d1fe2eef Mon Sep 17 00:00:00 2001
b35f49
From: Beniamino Galvani <bgalvani@redhat.com>
b35f49
Date: Wed, 1 Jul 2020 09:01:10 +0200
b35f49
Subject: [PATCH 2/3] ovs: also set cloned MAC address via netlink
b35f49
b35f49
We already set the MAC of OVS interfaces in the ovsdb. Unfortunately,
b35f49
vswitchd doesn't create the interface with the given MAC from the
b35f49
beginning, but first creates it with a random MAC and then changes it.
b35f49
b35f49
This causes a race condition: as soon as NM sees the new link, it
b35f49
starts IP configuration on it and (possibly later) vswitchd will
b35f49
change the MAC.
b35f49
b35f49
To avoid this, also set the desired MAC via netlink before starting IP
b35f49
configuration.
b35f49
b35f49
https://bugzilla.redhat.com/show_bug.cgi?id=1852106
b35f49
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/483
b35f49
(cherry picked from commit 47ec3d14d49eb9e9db956b3efd495d5d696da996)
b35f49
(cherry picked from commit 60d10b146d57290f146536705d744e67925de90e)
b35f49
---
b35f49
 src/devices/ovs/nm-device-ovs-interface.c | 15 +++++++++++++++
b35f49
 1 file changed, 15 insertions(+)
b35f49
b35f49
diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
b35f49
index 10f9fa943..83954cf07 100644
b35f49
--- a/src/devices/ovs/nm-device-ovs-interface.c
b35f49
+++ b/src/devices/ovs/nm-device-ovs-interface.c
b35f49
@@ -104,6 +104,14 @@ link_changed (NMDevice *device,
b35f49
 	priv->waiting_for_interface = FALSE;
b35f49
 
b35f49
 	if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
b35f49
+		if (!nm_device_hw_addr_set_cloned (device,
b35f49
+		                                   nm_device_get_applied_connection (device),
b35f49
+		                                   FALSE)) {
b35f49
+			nm_device_state_changed (device,
b35f49
+			                         NM_DEVICE_STATE_FAILED,
b35f49
+			                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
b35f49
+			return;
b35f49
+		}
b35f49
 		nm_device_bring_up (device, TRUE, NULL);
b35f49
 		nm_device_activate_schedule_stage3_ip_config_start (device);
b35f49
 	}
b35f49
@@ -176,6 +184,13 @@ act_stage3_ip_config_start (NMDevice *device,
b35f49
 		return NM_ACT_STAGE_RETURN_POSTPONE;
b35f49
 	}
b35f49
 
b35f49
+	if (!nm_device_hw_addr_set_cloned (device,
b35f49
+	                                   nm_device_get_applied_connection (device),
b35f49
+	                                   FALSE)) {
b35f49
+		*out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
b35f49
+		return NM_ACT_STAGE_RETURN_FAILURE;
b35f49
+	}
b35f49
+
b35f49
 	return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason);
b35f49
 }
b35f49
 
b35f49
-- 
b35f49
2.26.2
b35f49
b35f49
From 73a99046f02f82705b0cf7da8c06ce53ddcbedba Mon Sep 17 00:00:00 2001
b35f49
From: Beniamino Galvani <bgalvani@redhat.com>
b35f49
Date: Thu, 2 Jul 2020 13:47:22 +0200
b35f49
Subject: [PATCH 3/3] device: don't reset the MAC without ifindex
b35f49
b35f49
nm_device_cleanup() can be called when the device no longer has an
b35f49
ifindex. In such case, don't try to reset the MAC address as that
b35f49
would lead to an assertion failure.
b35f49
b35f49
(cherry picked from commit 77b6ce7d04f6c88e78fb7f1972549956e00e1f4b)
b35f49
(cherry picked from commit 791a888cad3d260675781c0ed30acf13cc1194f7)
b35f49
---
b35f49
 src/devices/nm-device.c | 24 +++++++++++++-----------
b35f49
 1 file changed, 13 insertions(+), 11 deletions(-)
b35f49
b35f49
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
b35f49
index a6c3e6680..980cd3a06 100644
b35f49
--- a/src/devices/nm-device.c
b35f49
+++ b/src/devices/nm-device.c
b35f49
@@ -15606,17 +15606,19 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
b35f49
 
b35f49
 	nm_device_update_metered (self);
b35f49
 
b35f49
-	/* during device cleanup, we want to reset the MAC address of the device
b35f49
-	 * to the initial state.
b35f49
-	 *
b35f49
-	 * We certainly want to do that when reaching the UNMANAGED state... */
b35f49
-	if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED)
b35f49
-		nm_device_hw_addr_reset (self, "unmanage");
b35f49
-	else {
b35f49
-		/* for other device states (UNAVAILABLE, DISCONNECTED), allow the
b35f49
-		 * device to overwrite the reset behavior, so that Wi-Fi can set
b35f49
-		 * a randomized MAC address used during scanning. */
b35f49
-		NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self);
b35f49
+	if (ifindex > 0) {
b35f49
+		/* during device cleanup, we want to reset the MAC address of the device
b35f49
+		 * to the initial state.
b35f49
+		 *
b35f49
+		 * We certainly want to do that when reaching the UNMANAGED state... */
b35f49
+		if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED)
b35f49
+			nm_device_hw_addr_reset (self, "unmanage");
b35f49
+		else {
b35f49
+			/* for other device states (UNAVAILABLE, DISCONNECTED), allow the
b35f49
+			 * device to overwrite the reset behavior, so that Wi-Fi can set
b35f49
+			 * a randomized MAC address used during scanning. */
b35f49
+			NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self);
b35f49
+		}
b35f49
 	}
b35f49
 
b35f49
 	priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE;
b35f49
-- 
b35f49
2.26.2
b35f49