diff --git a/SOURCES/1001-ovs-fixes-rh1852106-rh1820052.patch b/SOURCES/1001-ovs-fixes-rh1852106-rh1820052.patch
new file mode 100644
index 0000000..bcc2544
--- /dev/null
+++ b/SOURCES/1001-ovs-fixes-rh1852106-rh1820052.patch
@@ -0,0 +1,2543 @@
+From 00b62f66a30dcbf2821f5ed2113a246ea42bdf33 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Sun, 28 Jul 2019 14:37:44 +0200
+Subject: [PATCH 01/25] libnm: add internal _nm_connection_get_setting()
+ accessor
+
+nm_connection_get_setting() returns a pointer of type NMSetting.
+That is very inconvenient, because most callers will need the
+the result pointer as a setting subtype (like NMSettingConnection).
+
+That would be like g_object_new() returning a "GObject *" pointer,
+which is technically correct but annoying.
+
+In the past that problem was avoided by having countless accessors
+like nm_connection_get_setting_ip4_config(), etc. But that just blows
+up the API and also is not generic. Meaning: the type is not a function
+argument but the function itself. That makes composing the code harder
+as the setting type cannot be treated generically (as a function argument).
+
+Anyway. Add an internal wrapper that returns a void pointer.
+
+(cherry picked from commit c4788e611edfa897860494398de394c4a6254d6e)
+(cherry picked from commit 9e32b33d05c58c0224028d80d25580ce7cbdaad6)
+---
+ libnm-core/nm-core-internal.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
+index 825355821345..039e2c29820d 100644
+--- a/libnm-core/nm-core-internal.h
++++ b/libnm-core/nm-core-internal.h
+@@ -443,6 +443,13 @@ gboolean _nm_utils_generate_mac_address_mask_parse (const char *value,
+ 
+ /*****************************************************************************/
+ 
++static inline gpointer
++_nm_connection_get_setting (NMConnection *connection,
++                            GType type)
++{
++	return (gpointer) nm_connection_get_setting (connection, type);
++}
++
+ NMSettingIPConfig *nm_connection_get_setting_ip_config (NMConnection *connection,
+                                                         int addr_family);
+ 
+-- 
+2.26.2
+
+
+From bcf293b0074826e7ed3de44d2ed50292910a9f4d Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Tue, 23 Jul 2019 23:25:03 +0200
+Subject: [PATCH 02/25] shared: add nm_g_slice_free() helper
+
+How odd that such a macro does not exist yet. It seems like
+the majorities of calls to g_slice_free() could be replaced
+by this.
+
+(cherry picked from commit dcdbe984065ed06753a0ce542c1aaaa9336d8424)
+(cherry picked from commit 8f644537a4c4d001ec219c82cc906dcd610f08a5)
+---
+ shared/nm-glib-aux/nm-macros-internal.h | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h
+index 1ca89787a693..ec78ef585424 100644
+--- a/shared/nm-glib-aux/nm-macros-internal.h
++++ b/shared/nm-glib-aux/nm-macros-internal.h
+@@ -1500,6 +1500,11 @@ nm_strcmp_p (gconstpointer a, gconstpointer b)
+ 
+ /*****************************************************************************/
+ 
++#define nm_g_slice_free(ptr) \
++	g_slice_free (typeof (*(ptr)), ptr)
++
++/*****************************************************************************/
++
+ /* like g_memdup(). The difference is that the @size argument is of type
+  * gsize, while g_memdup() has type guint. Since, the size of container types
+  * like GArray is guint as well, this means trying to g_memdup() an
+-- 
+2.26.2
+
+
+From 285790e0dd450c817bda9f2ed576335f9a9644dc Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Sun, 7 Jun 2020 15:10:36 +0200
+Subject: [PATCH 03/25] tests: suppress valgrind warning about unsupported
+ syscall for "test-config"
+
+(cherry picked from commit d507563a80d3e171017700f7b268940b63f5708d)
+(cherry picked from commit 4036bc48e4a5b4989a789c74b124e76ae0286ea8)
+(cherry picked from commit 9ff160d155da29b02890ce6ae433b2f2a39c579e)
+(cherry picked from commit 1b9da1869382185fe4f03c17fd7612ce1809e0f3)
+(cherry picked from commit a1f4bcd6111adb026dc010fbd1071822e4248bb3)
+---
+ tools/run-nm-test.sh | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh
+index e8af231883a0..09c735c129bf 100755
+--- a/tools/run-nm-test.sh
++++ b/tools/run-nm-test.sh
+@@ -297,6 +297,7 @@ if [ $HAS_ERRORS -eq 0 ]; then
+     # valgrind doesn't support setns syscall and spams the logfile.
+     # hack around it...
+     case "$TEST_NAME" in
++        'test-config' | \
+         'test-link-linux' | \
+         'test-acd' | \
+         'test-service-providers' | \
+-- 
+2.26.2
+
+
+From 6c5b3350527f2d358ed107f4f3943eb26eb5357d Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Wed, 12 Jun 2019 17:58:49 +0200
+Subject: [PATCH 04/25] ovs/ovsdb: guard against OVSDB integrity issues
+
+Don't crash in situations, where the bridge or a port has a child with
+UUID we don't know. This could happen if we mess up the parsing of
+messages from OVSDB, but could also theoretically happen in OVSDB sends
+us bad data.
+
+(cherry picked from commit 99c7adc1e12862f22026bb8f806c9223db9a78ec)
+(cherry picked from commit 3455c30a58ff14952acf86f8ea068ef8f3b6d889)
+---
+ src/devices/ovs/nm-ovsdb.c | 40 +++++++++++++++++++++++++++++---------
+ 1 file changed, 31 insertions(+), 9 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 82e25f396ccf..5f46c23a260b 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -584,9 +584,14 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 
+ 			json_array_append_new (ports, json_pack ("[s, s]", "uuid", port_uuid));
+ 
+-			if (   g_strcmp0 (ovs_port->name, nm_connection_get_interface_name (port)) != 0
+-			    || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0)
++			if (!ovs_port) {
++				/* This would be a violation of ovsdb's reference integrity (a bug). */
++				_LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid);
+ 				continue;
++			} else if (   strcmp (ovs_port->name, nm_connection_get_interface_name (port)) != 0
++			           || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) {
++				continue;
++			}
+ 
+ 			for (ii = 0; ii < ovs_port->interfaces->len; ii++) {
+ 				interface_uuid = g_ptr_array_index (ovs_port->interfaces, ii);
+@@ -594,9 +599,13 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 
+ 				json_array_append_new (interfaces, json_pack ("[s, s]", "uuid", interface_uuid));
+ 
+-				if (   g_strcmp0 (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0
+-				    && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0)
++				if (!ovs_interface) {
++					/* This would be a violation of ovsdb's reference integrity (a bug). */
++					_LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid);
++				} else if (   strcmp (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0
++				           && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) {
+ 					has_interface = TRUE;
++				}
+ 			}
+ 
+ 			break;
+@@ -692,16 +701,27 @@ _delete_interface (NMOvsdb *self, json_t *params, const char *ifname)
+ 
+ 			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, bridge_uuid);
++				continue;
++			}
++
+ 			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);
+ 
+ 				json_array_append_new (interfaces, json_pack ("[s,s]", "uuid", interface_uuid));
+ 
+-				if (strcmp (ovs_interface->name, ifname) == 0) {
+-					/* skip the interface */
+-					interfaces_changed = TRUE;
+-					continue;
++				if (ovs_interface) {
++					if (strcmp (ovs_interface->name, ifname) == 0) {
++						/* skip the interface */
++						interfaces_changed = TRUE;
++						continue;
++					}
++				} else {
++					/* This would be a violation of ovsdb's reference integrity (a bug). */
++					_LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid);
+ 				}
+ 
+ 				json_array_append_new (new_interfaces, json_pack ("[s,s]", "uuid", interface_uuid));
+@@ -929,7 +949,9 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 
+ 		if (old) {
+ 			ovs_interface = g_hash_table_lookup (priv->interfaces, key);
+-			if (!new || g_strcmp0 (ovs_interface->name, name) != 0) {
++			if (!ovs_interface) {
++				_LOGW ("Interface '%s' was not seen", key);
++			} else if (!new || strcmp (ovs_interface->name, name) != 0) {
+ 				old = FALSE;
+ 				_LOGT ("removed an '%s' interface: %s%s%s",
+ 				       ovs_interface->type, ovs_interface->name,
+-- 
+2.26.2
+
+
+From 22903209fe8d1a3e9e3b6c9fa8c0178c9e6d2551 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Wed, 12 Jun 2019 17:10:09 +0200
+Subject: [PATCH 05/25] ovs/ovsdb: remove the device-changes signal
+
+It doesn't communicate anything about the nature of the change and
+indeed nothing uses it.
+
+(cherry picked from commit b1feebc43aafd5e40c371c2a971cdefd5f8acae6)
+(cherry picked from commit 7448ad84679188157eda4ad3ba0289af4918d384)
+---
+ src/devices/ovs/nm-ovsdb.c | 14 --------------
+ src/devices/ovs/nm-ovsdb.h |  1 -
+ 2 files changed, 15 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 5f46c23a260b..9ea78a39b9b8 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -59,7 +59,6 @@ typedef struct {
+ enum {
+ 	DEVICE_ADDED,
+ 	DEVICE_REMOVED,
+-	DEVICE_CHANGED,
+ 	LAST_SIGNAL
+ };
+ 
+@@ -976,8 +975,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				_LOGT ("changed an '%s' interface: %s%s%s", type, ovs_interface->name,
+ 				       ovs_interface->connection_uuid ? ", " : "",
+ 				       ovs_interface->connection_uuid ?: "");
+-				g_signal_emit (self, signals[DEVICE_CHANGED], 0,
+-				               "ovs-interface", ovs_interface->name);
+ 			} else {
+ 				_LOGT ("added an '%s' interface: %s%s%s",
+ 				       ovs_interface->type, ovs_interface->name,
+@@ -1031,8 +1028,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				_LOGT ("changed a port: %s%s%s", ovs_port->name,
+ 				       ovs_port->connection_uuid ? ", " : "",
+ 				       ovs_port->connection_uuid ?: "");
+-				g_signal_emit (self, signals[DEVICE_CHANGED], 0,
+-				               NM_SETTING_OVS_PORT_SETTING_NAME, ovs_port->name);
+ 			} else {
+ 				_LOGT ("added a port: %s%s%s", ovs_port->name,
+ 				       ovs_port->connection_uuid ? ", " : "",
+@@ -1081,8 +1076,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				_LOGT ("changed a bridge: %s%s%s", ovs_bridge->name,
+ 				       ovs_bridge->connection_uuid ? ", " : "",
+ 				       ovs_bridge->connection_uuid ?: "");
+-				g_signal_emit (self, signals[DEVICE_CHANGED], 0,
+-				               NM_SETTING_OVS_BRIDGE_SETTING_NAME, ovs_bridge->name);
+ 			} else {
+ 				_LOGT ("added a bridge: %s%s%s", ovs_bridge->name,
+ 				       ovs_bridge->connection_uuid ? ", " : "",
+@@ -1648,11 +1641,4 @@ nm_ovsdb_class_init (NMOvsdbClass *klass)
+ 		              G_SIGNAL_RUN_LAST,
+ 		              0, NULL, NULL, NULL,
+ 		              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
+-
+-	signals[DEVICE_CHANGED] =
+-		g_signal_new (NM_OVSDB_DEVICE_CHANGED,
+-		              G_OBJECT_CLASS_TYPE (object_class),
+-		              G_SIGNAL_RUN_LAST,
+-		              0, NULL, NULL, NULL,
+-		              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
+ }
+diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h
+index f9dbabbb7ad8..e403b0e447c1 100644
+--- a/src/devices/ovs/nm-ovsdb.h
++++ b/src/devices/ovs/nm-ovsdb.h
+@@ -29,7 +29,6 @@
+ 
+ #define NM_OVSDB_DEVICE_ADDED   "device-added"
+ #define NM_OVSDB_DEVICE_REMOVED "device-removed"
+-#define NM_OVSDB_DEVICE_CHANGED "device-changed"
+ 
+ typedef struct _NMOvsdb NMOvsdb;
+ typedef struct _NMOvsdbClass NMOvsdbClass;
+-- 
+2.26.2
+
+
+From a7b2da1d28c725143a0c5370d2836f17e84194e7 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Fri, 14 Jun 2019 10:31:15 +0200
+Subject: [PATCH 06/25] ovs/ovsdb: fix signal handler argument types
+
+(cherry picked from commit dedc0cba23b5d51773f88d8bc06424eb589083cd)
+(cherry picked from commit 4107490c892ee90e87d6231557a01501cf340bd1)
+---
+ src/devices/ovs/nm-ovsdb.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 9ea78a39b9b8..a9c209a2f408 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -1633,12 +1633,12 @@ nm_ovsdb_class_init (NMOvsdbClass *klass)
+ 		              G_OBJECT_CLASS_TYPE (object_class),
+ 		              G_SIGNAL_RUN_LAST,
+ 		              0, NULL, NULL, NULL,
+-		              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
++		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
+ 
+ 	signals[DEVICE_REMOVED] =
+ 		g_signal_new (NM_OVSDB_DEVICE_REMOVED,
+ 		              G_OBJECT_CLASS_TYPE (object_class),
+ 		              G_SIGNAL_RUN_LAST,
+ 		              0, NULL, NULL, NULL,
+-		              G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
++		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
+ }
+-- 
+2.26.2
+
+
+From 65b6544d76aac604fe8259fa78161dc23e08e5f3 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Wed, 12 Jun 2019 17:15:13 +0200
+Subject: [PATCH 07/25] ovs/ovsdb: signal a failure when an error column is set
+
+When an interface (other OVS device types can not fail)  encounters an error
+it indicates it by changing the error column. Watch for those changes so
+that we can eventually communicate them to the OVS factory to deal with
+them.
+
+(cherry picked from commit f2c066e1046cc8da5a277b1528a59bf2653e17c8)
+(cherry picked from commit cb19680d342d30043b6c7534cab4c8a12d3e797f)
+---
+ src/devices/ovs/nm-ovsdb.c | 24 +++++++++++++++++++++---
+ src/devices/ovs/nm-ovsdb.h |  5 +++--
+ 2 files changed, 24 insertions(+), 5 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index a9c209a2f408..a9644ce9e13c 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -59,6 +59,7 @@ typedef struct {
+ enum {
+ 	DEVICE_ADDED,
+ 	DEVICE_REMOVED,
++	INTERFACE_FAILED,
+ 	LAST_SIGNAL
+ };
+ 
+@@ -787,14 +788,14 @@ ovsdb_next_command (NMOvsdb *self)
+ 		msg = json_pack ("{s:i, s:s, s:[s, n, {"
+ 		                 "  s:[{s:[s, s, s]}],"
+ 		                 "  s:[{s:[s, s, s]}],"
+-		                 "  s:[{s:[s, s, s]}],"
++		                 "  s:[{s:[s, s, s, s]}],"
+ 		                 "  s:[{s:[]}]"
+ 		                 "}]}",
+ 		                 "id", call->id,
+ 		                 "method", "monitor", "params", "Open_vSwitch",
+ 		                 "Bridge", "columns", "name", "ports", "external_ids",
+ 		                 "Port", "columns", "name", "interfaces", "external_ids",
+-		                 "Interface", "columns", "name", "type", "external_ids",
++		                 "Interface", "columns", "name", "type", "external_ids", "error",
+ 		                 "Open_vSwitch", "columns");
+ 		break;
+ 	case OVSDB_ADD_INTERFACE:
+@@ -934,15 +935,17 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 
+ 	/* Interfaces */
+ 	json_object_foreach (interface, key, value) {
++		json_t *error = NULL;
+ 		gboolean old = FALSE;
+ 		gboolean new = FALSE;
+ 
+ 		if (json_unpack (value, "{s:{}}", "old") == 0)
+ 			old = TRUE;
+ 
+-		if (json_unpack (value, "{s:{s:s, s:s, s:o}}", "new",
++		if (json_unpack (value, "{s:{s:s, s:s, s?:o, s:o}}", "new",
+ 		                 "name", &name,
+ 		                 "type", &type,
++		                 "error", &error,
+ 		                 "external_ids", &external_ids) == 0)
+ 			new = TRUE;
+ 
+@@ -987,6 +990,14 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 					               ovs_interface->name, NM_DEVICE_TYPE_OVS_INTERFACE);
+ 				}
+ 			}
++			/* The error is a string. No error is indicated by an empty set,
++			 * because why the fuck not: [ "set": [] ] */
++			if (error && json_is_string (error)) {
++				g_signal_emit (self, signals[INTERFACE_FAILED], 0,
++				               ovs_interface->name,
++				               ovs_interface->connection_uuid,
++				               json_string_value (error));
++			}
+ 			g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface);
+ 		}
+ 	}
+@@ -1641,4 +1652,11 @@ nm_ovsdb_class_init (NMOvsdbClass *klass)
+ 		              G_SIGNAL_RUN_LAST,
+ 		              0, NULL, NULL, NULL,
+ 		              G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_UINT);
++
++	signals[INTERFACE_FAILED] =
++		g_signal_new (NM_OVSDB_INTERFACE_FAILED,
++		              G_OBJECT_CLASS_TYPE (object_class),
++		              G_SIGNAL_RUN_LAST,
++		              0, NULL, NULL, NULL,
++		              G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+ }
+diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h
+index e403b0e447c1..e7f9d71984c2 100644
+--- a/src/devices/ovs/nm-ovsdb.h
++++ b/src/devices/ovs/nm-ovsdb.h
+@@ -27,8 +27,9 @@
+ #define NM_IS_OVSDB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_OVSDB))
+ #define NM_OVSDB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OVSDB, NMOvsdbClass))
+ 
+-#define NM_OVSDB_DEVICE_ADDED   "device-added"
+-#define NM_OVSDB_DEVICE_REMOVED "device-removed"
++#define NM_OVSDB_DEVICE_ADDED      "device-added"
++#define NM_OVSDB_DEVICE_REMOVED    "device-removed"
++#define NM_OVSDB_INTERFACE_FAILED  "interface-failed"
+ 
+ typedef struct _NMOvsdb NMOvsdb;
+ typedef struct _NMOvsdbClass NMOvsdbClass;
+-- 
+2.26.2
+
+
+From 358db39dc1e0d9b29dd4e6d39dbb5b8ab8f45de6 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Wed, 12 Jun 2019 18:30:36 +0200
+Subject: [PATCH 08/25] ovs/ovsdb: track the devices before we signal addition
+
+This doesn't make any difference in practice, but it seems more correct.
+It would cause issues if we decided to remove an interface from the
+signal handler.
+
+(cherry picked from commit e948ce7debb4f2da2db9c19ab4f980eac5415b9d)
+(cherry picked from commit 83a42ef8ad8a3edd95eceff1a3ea69989d78baa4)
+---
+ src/devices/ovs/nm-ovsdb.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index a9644ce9e13c..c85115201eac 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -974,6 +974,7 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 			ovs_interface->name = g_strdup (name);
+ 			ovs_interface->type = g_strdup (type);
+ 			ovs_interface->connection_uuid = _connection_uuid_from_external_ids (external_ids);
++			g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface);
+ 			if (old) {
+ 				_LOGT ("changed an '%s' interface: %s%s%s", type, ovs_interface->name,
+ 				       ovs_interface->connection_uuid ? ", " : "",
+@@ -998,7 +999,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				               ovs_interface->connection_uuid,
+ 				               json_string_value (error));
+ 			}
+-			g_hash_table_insert (priv->interfaces, g_strdup (key), ovs_interface);
+ 		}
+ 	}
+ 
+@@ -1035,6 +1035,7 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 			ovs_port->connection_uuid = _connection_uuid_from_external_ids (external_ids);
+ 			ovs_port->interfaces = g_ptr_array_new_with_free_func (g_free);
+ 			_uuids_to_array (ovs_port->interfaces, items);
++			g_hash_table_insert (priv->ports, g_strdup (key), ovs_port);
+ 			if (old) {
+ 				_LOGT ("changed a port: %s%s%s", ovs_port->name,
+ 				       ovs_port->connection_uuid ? ", " : "",
+@@ -1046,7 +1047,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				g_signal_emit (self, signals[DEVICE_ADDED], 0,
+ 				               ovs_port->name, NM_DEVICE_TYPE_OVS_PORT);
+ 			}
+-			g_hash_table_insert (priv->ports, g_strdup (key), ovs_port);
+ 		}
+ 	}
+ 
+@@ -1083,6 +1083,7 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 			ovs_bridge->connection_uuid = _connection_uuid_from_external_ids (external_ids);
+ 			ovs_bridge->ports = g_ptr_array_new_with_free_func (g_free);
+ 			_uuids_to_array (ovs_bridge->ports, items);
++			g_hash_table_insert (priv->bridges, g_strdup (key), ovs_bridge);
+ 			if (old) {
+ 				_LOGT ("changed a bridge: %s%s%s", ovs_bridge->name,
+ 				       ovs_bridge->connection_uuid ? ", " : "",
+@@ -1094,7 +1095,6 @@ ovsdb_got_update (NMOvsdb *self, json_t *msg)
+ 				g_signal_emit (self, signals[DEVICE_ADDED], 0,
+ 				               ovs_bridge->name, NM_DEVICE_TYPE_OVS_BRIDGE);
+ 			}
+-			g_hash_table_insert (priv->bridges, g_strdup (key), ovs_bridge);
+ 		}
+ 	}
+ 
+-- 
+2.26.2
+
+
+From 1e056bd5efc42fa753e61bfad5e5f1d88177bb46 Mon Sep 17 00:00:00 2001
+From: Lubomir Rintel <lkundrak@v3.sk>
+Date: Wed, 12 Jun 2019 18:38:58 +0200
+Subject: [PATCH 09/25] ovs/factory: fail the NMDevice if there's an error in
+ OVSDB
+
+(cherry picked from commit 02950ec600d07647dadabdf08b151d5c4f5f8985)
+(cherry picked from commit ba2c71a01db83a786ec4d1fe10b42574cd45e2c2)
+---
+ src/devices/ovs/nm-ovs-factory.c | 41 +++++++++++++++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c
+index 2124b2a0b1cd..fdf07bd3750a 100644
+--- a/src/devices/ovs/nm-ovs-factory.c
++++ b/src/devices/ovs/nm-ovs-factory.c
+@@ -26,7 +26,9 @@
+ #include "nm-device-ovs-bridge.h"
+ #include "platform/nm-platform.h"
+ #include "nm-core-internal.h"
++#include "settings/nm-settings.h"
+ #include "devices/nm-device-factory.h"
++#include "devices/nm-device-private.h"
+ 
+ /*****************************************************************************/
+ 
+@@ -51,7 +53,13 @@ G_DEFINE_TYPE (NMOvsFactory, nm_ovs_factory, NM_TYPE_DEVICE_FACTORY)
+ /*****************************************************************************/
+ 
+ #define _NMLOG_DOMAIN      LOGD_DEVICE
+-#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "ovs", __VA_ARGS__)
++#define _NMLOG(level, ifname, con_uuid, ...) \
++        G_STMT_START { \
++                nm_log ((level), _NMLOG_DOMAIN, (ifname), (con_uuid), \
++                        "ovs: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__) \
++                        _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
++        } G_STMT_END
++
+ 
+ /*****************************************************************************/
+ 
+@@ -138,6 +146,36 @@ ovsdb_device_removed (NMOvsdb *ovsdb, const char *name, NMDeviceType device_type
+ 	}
+ }
+ 
++static void
++ovsdb_interface_failed (NMOvsdb *ovsdb,
++                        const char *name,
++                        const char *connection_uuid,
++                        const char *error,
++                        NMDeviceFactory *self)
++{
++	NMDevice *device = NULL;
++	NMSettingsConnection *connection = NULL;
++
++	_LOGI (name, connection_uuid, "ovs interface \"%s\" (%s) failed: %s", name, connection_uuid, error);
++
++	device = nm_manager_get_device (nm_manager_get (), name, NM_DEVICE_TYPE_OVS_INTERFACE);
++	if (!device)
++		return;
++
++	if (connection_uuid)
++		connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (device), connection_uuid);
++
++	if (connection) {
++		nm_settings_connection_autoconnect_blocked_reason_set (connection,
++		                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
++		                                                       TRUE);
++	}
++
++	nm_device_state_changed (device,
++	                         NM_DEVICE_STATE_FAILED,
++	                         NM_DEVICE_STATE_REASON_OVSDB_FAILED);
++}
++
+ static void
+ start (NMDeviceFactory *self)
+ {
+@@ -147,6 +185,7 @@ start (NMDeviceFactory *self)
+ 
+ 	g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_ADDED, G_CALLBACK (ovsdb_device_added), self, (GConnectFlags) 0);
+ 	g_signal_connect_object (ovsdb, NM_OVSDB_DEVICE_REMOVED, G_CALLBACK (ovsdb_device_removed), self, (GConnectFlags) 0);
++	g_signal_connect_object (ovsdb, NM_OVSDB_INTERFACE_FAILED, G_CALLBACK (ovsdb_interface_failed), self, (GConnectFlags) 0);
+ }
+ 
+ static NMDevice *
+-- 
+2.26.2
+
+
+From 8c9716c53e232a18249d9d07b52f0d06084660b8 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Wed, 15 Jan 2020 18:30:17 +0100
+Subject: [PATCH 10/25] ovs: wait that link disappears before continuing with
+ deactivation
+
+When we deactivate a virtual device, we usually schedule the deletion
+of the link in an idle handler. That action will be executed at a
+later time when the device is already in the disconnected state.
+
+Similarly, for ovs interfaces we send the deletion command to the
+ovsdb and then proceed to the disconnected state.
+
+However, in the first case there is the guarantee that the link will
+be deleted at some point, while for ovs interfaces it may happen that
+ovs decides to reuse the same link if there is an addition
+queued. Since reusing the same link confuses NM, let's implement
+deactivate_async() for ovs-interfaces and wait that the link actually
+goes away before proceeding.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1782701
+https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/402
+(cherry picked from commit 623a1e1f993b3166509202bc580c30e3daf9c67b)
+(cherry picked from commit a1b0edd24b078294cd3959044a7ae35287d55f87)
+(cherry picked from commit cb7c7c29bdde6654b3a5d498c592033772592ad0)
+(cherry picked from commit b0aad945b4a1e6bdcf72a3a799f55cf5c72f411a)
+---
+ src/devices/ovs/nm-device-ovs-interface.c | 115 ++++++++++++++++++++++
+ 1 file changed, 115 insertions(+)
+
+diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
+index 86d0b8fbd19c..a6fc2656ce7a 100644
+--- a/src/devices/ovs/nm-device-ovs-interface.c
++++ b/src/devices/ovs/nm-device-ovs-interface.c
+@@ -35,6 +35,7 @@ _LOG_DECLARE_SELF(NMDeviceOvsInterface);
+ 
+ typedef struct {
+ 	bool waiting_for_interface:1;
++	int link_ifindex;
+ } NMDeviceOvsInterfacePrivate;
+ 
+ struct _NMDeviceOvsInterface {
+@@ -111,6 +112,9 @@ link_changed (NMDevice *device,
+ {
+ 	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device);
+ 
++	if (pllink)
++		priv->link_ifindex = pllink->ifindex;
++
+ 	if (   pllink
+ 	    && priv->waiting_for_interface
+ 	    && nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
+@@ -166,6 +170,116 @@ deactivate (NMDevice *device)
+ 	priv->waiting_for_interface = FALSE;
+ }
+ 
++typedef struct {
++	NMDeviceOvsInterface *self;
++	GCancellable *cancellable;
++	NMDeviceDeactivateCallback callback;
++	gpointer callback_user_data;
++	gulong link_changed_id;
++	gulong cancelled_id;
++} DeactivateData;
++
++static void
++deactivate_invoke_cb (DeactivateData *data, GError *error)
++{
++	data->callback (NM_DEVICE (data->self),
++	                error,
++	                data->callback_user_data);
++
++	nm_clear_g_signal_handler (nm_device_get_platform (NM_DEVICE (data->self)),
++	                           &data->link_changed_id);
++	nm_clear_g_signal_handler (data->cancellable,
++	                           &data->cancelled_id);
++	g_object_unref (data->self);
++	g_object_unref (data->cancellable);
++	nm_g_slice_free (data);
++}
++
++static void
++link_changed_cb (NMPlatform *platform,
++                 int obj_type_i,
++                 int ifindex,
++                 NMPlatformLink *info,
++                 int change_type_i,
++                 DeactivateData *data)
++{
++	NMDeviceOvsInterface *self = data->self;
++	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
++	const NMPlatformSignalChangeType change_type = change_type_i;
++
++	if (   change_type == NM_PLATFORM_SIGNAL_REMOVED
++	    && ifindex == priv->link_ifindex) {
++		_LOGT (LOGD_DEVICE,
++		       "link %d gone, proceeding with deactivation",
++		       priv->link_ifindex);
++		priv->link_ifindex = 0;
++		deactivate_invoke_cb (data, NULL);
++		return;
++	}
++}
++
++static void
++deactivate_cancelled_cb (GCancellable *cancellable,
++                         gpointer user_data)
++{
++	gs_free_error GError *error = NULL;
++
++	nm_utils_error_set_cancelled (&error, FALSE, NULL);
++	deactivate_invoke_cb ((DeactivateData *) user_data, error);
++}
++
++static void
++deactivate_cb_on_idle (gpointer user_data,
++                       GCancellable *cancellable)
++{
++	DeactivateData *data = user_data;
++	gs_free_error GError *cancelled_error = NULL;
++
++	g_cancellable_set_error_if_cancelled (data->cancellable, &cancelled_error);
++	deactivate_invoke_cb (data, cancelled_error);
++}
++
++static void
++deactivate_async (NMDevice *device,
++                  GCancellable *cancellable,
++                  NMDeviceDeactivateCallback callback,
++                  gpointer callback_user_data) {
++
++	NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE (device);
++	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
++	DeactivateData *data;
++
++	priv->waiting_for_interface = FALSE;
++
++	data = g_slice_new (DeactivateData);
++	*data = (DeactivateData) {
++		.self = g_object_ref (self),
++		.cancellable = g_object_ref (cancellable),
++		.callback = callback,
++		.callback_user_data = callback_user_data,
++	};
++
++	if (   !priv->link_ifindex
++	    || !nm_platform_link_get (nm_device_get_platform (device), priv->link_ifindex)) {
++		priv->link_ifindex = 0;
++		nm_utils_invoke_on_idle (deactivate_cb_on_idle, data, cancellable);
++		return;
++	}
++
++	_LOGT (LOGD_DEVICE,
++	       "async deactivation: waiting for link %d to disappear",
++	       priv->link_ifindex);
++
++	data->cancelled_id = g_cancellable_connect (cancellable,
++	                                            G_CALLBACK (deactivate_cancelled_cb),
++	                                            data,
++	                                            NULL);
++	data->link_changed_id = g_signal_connect (nm_device_get_platform (device),
++	                                          NM_PLATFORM_SIGNAL_LINK_CHANGED,
++	                                          G_CALLBACK (link_changed_cb),
++	                                          data);
++}
++
+ /*****************************************************************************/
+ 
+ static void
+@@ -196,6 +310,7 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass)
+ 	device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH);
+ 
+ 	device_class->deactivate = deactivate;
++	device_class->deactivate_async = deactivate_async;
+ 	device_class->get_type_description = get_type_description;
+ 	device_class->create_and_realize = create_and_realize;
+ 	device_class->get_generic_capabilities = get_generic_capabilities;
+-- 
+2.26.2
+
+
+From 91149efd8f6cecbc56e4c76c81c11db73f48b00c Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 13 Feb 2020 14:52:11 +0100
+Subject: [PATCH 11/25] ovs: rework asynchronous deactivation of ovs interfaces
+
+Tracking the deletion of link by ifindex is difficult because the
+ifindex of the device is updated through delayed (idle) calls in
+NMDevice and so there is the possibility that at a certain time the
+device ifindex is not in sync with platform state. It seems simpler to
+watch instead the interface name. The ugly thing is that the interface
+name can be changed externally, but if users do that on an activating
+device they are looking for trouble.
+
+Also change the deactivate code to deal with the scenario where we
+already created the interface in the ovsdb but the link didn't show up
+yet. To ensure a proper cleanup we must wait that the link appears and
+then goes away; however the link may never appear if vswitchd sees
+only the last state in ovsdb, and so we must use a ugly timeout to
+avoid waiting forever.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1787989
+(cherry picked from commit 9c49f8a87962d8009dc18973845a1c46aba38d00)
+(cherry picked from commit 2e5e409bf2cf825af46c46d110b0502050adcb3c)
+(cherry picked from commit 628706fab592f6c5611438a21742391ea1a2e8cc)
+(cherry picked from commit 296d4e392649250e08735418e9e9d2cd416d0fe1)
+---
+ src/devices/ovs/nm-device-ovs-interface.c | 86 ++++++++++++++++-------
+ 1 file changed, 59 insertions(+), 27 deletions(-)
+
+diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
+index a6fc2656ce7a..726637864e69 100644
+--- a/src/devices/ovs/nm-device-ovs-interface.c
++++ b/src/devices/ovs/nm-device-ovs-interface.c
+@@ -35,7 +35,6 @@ _LOG_DECLARE_SELF(NMDeviceOvsInterface);
+ 
+ typedef struct {
+ 	bool waiting_for_interface:1;
+-	int link_ifindex;
+ } NMDeviceOvsInterfacePrivate;
+ 
+ struct _NMDeviceOvsInterface {
+@@ -112,13 +111,12 @@ link_changed (NMDevice *device,
+ {
+ 	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device);
+ 
+-	if (pllink)
+-		priv->link_ifindex = pllink->ifindex;
++	if (!pllink || !priv->waiting_for_interface)
++		return;
++
++	priv->waiting_for_interface = FALSE;
+ 
+-	if (   pllink
+-	    && priv->waiting_for_interface
+-	    && nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
+-		priv->waiting_for_interface = FALSE;
++	if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
+ 		nm_device_bring_up (device, TRUE, NULL);
+ 		nm_device_activate_schedule_stage3_ip_config_start (device);
+ 	}
+@@ -142,12 +140,14 @@ act_stage3_ip_config_start (NMDevice *device,
+                             gpointer *out_config,
+                             NMDeviceStateReason *out_failure_reason)
+ {
++	NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE (device);
+ 	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (device);
+ 
+ 	if (!_is_internal_interface (device))
+ 		return NM_ACT_STAGE_RETURN_IP_FAIL;
+ 
+ 	if (nm_device_get_ip_ifindex (device) <= 0) {
++		_LOGT (LOGD_DEVICE, "waiting for link to appear");
+ 		priv->waiting_for_interface = TRUE;
+ 		return NM_ACT_STAGE_RETURN_POSTPONE;
+ 	}
+@@ -177,11 +177,17 @@ typedef struct {
+ 	gpointer callback_user_data;
+ 	gulong link_changed_id;
+ 	gulong cancelled_id;
++	guint link_timeout_id;
+ } DeactivateData;
+ 
+ static void
+ deactivate_invoke_cb (DeactivateData *data, GError *error)
+ {
++	NMDeviceOvsInterface *self = data->self;
++
++	_LOGT (LOGD_CORE,
++	       "deactivate: async callback (%s)",
++	       error ? error->message : "success");
+ 	data->callback (NM_DEVICE (data->self),
+ 	                error,
+ 	                data->callback_user_data);
+@@ -190,34 +196,43 @@ deactivate_invoke_cb (DeactivateData *data, GError *error)
+ 	                           &data->link_changed_id);
+ 	nm_clear_g_signal_handler (data->cancellable,
+ 	                           &data->cancelled_id);
++	nm_clear_g_source (&data->link_timeout_id);
+ 	g_object_unref (data->self);
+ 	g_object_unref (data->cancellable);
+ 	nm_g_slice_free (data);
+ }
+ 
+ static void
+-link_changed_cb (NMPlatform *platform,
+-                 int obj_type_i,
+-                 int ifindex,
+-                 NMPlatformLink *info,
+-                 int change_type_i,
+-                 DeactivateData *data)
++deactivate_link_changed_cb (NMPlatform *platform,
++                            int obj_type_i,
++                            int ifindex,
++                            NMPlatformLink *info,
++                            int change_type_i,
++                            DeactivateData *data)
+ {
+ 	NMDeviceOvsInterface *self = data->self;
+-	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
+ 	const NMPlatformSignalChangeType change_type = change_type_i;
+ 
+ 	if (   change_type == NM_PLATFORM_SIGNAL_REMOVED
+-	    && ifindex == priv->link_ifindex) {
+-		_LOGT (LOGD_DEVICE,
+-		       "link %d gone, proceeding with deactivation",
+-		       priv->link_ifindex);
+-		priv->link_ifindex = 0;
++	    && nm_streq0 (info->name, nm_device_get_iface (NM_DEVICE (self)))) {
++		_LOGT (LOGD_DEVICE, "deactivate: link removed, proceeding");
++		nm_device_update_from_platform_link (NM_DEVICE (self), NULL);
+ 		deactivate_invoke_cb (data, NULL);
+ 		return;
+ 	}
+ }
+ 
++static gboolean
++deactivate_link_timeout (gpointer user_data)
++{
++	DeactivateData *data = user_data;
++	NMDeviceOvsInterface *self = data->self;
++
++	_LOGT (LOGD_DEVICE, "deactivate: timeout waiting link removal");
++	deactivate_invoke_cb (data, NULL);
++	return G_SOURCE_REMOVE;
++}
++
+ static void
+ deactivate_cancelled_cb (GCancellable *cancellable,
+                          gpointer user_data)
+@@ -249,7 +264,14 @@ deactivate_async (NMDevice *device,
+ 	NMDeviceOvsInterfacePrivate *priv = NM_DEVICE_OVS_INTERFACE_GET_PRIVATE (self);
+ 	DeactivateData *data;
+ 
+-	priv->waiting_for_interface = FALSE;
++	_LOGT (LOGD_CORE, "deactivate: start async");
++
++	/* We want to ensure that the kernel link for this device is
++	 * removed upon disconnection so that it will not interfere with
++	 * later activations of the same device. Unfortunately there is
++	 * no synchronization mechanism with vswitchd, we only update
++	 * ovsdb and wait that changes are picked up.
++	 */
+ 
+ 	data = g_slice_new (DeactivateData);
+ 	*data = (DeactivateData) {
+@@ -259,16 +281,26 @@ deactivate_async (NMDevice *device,
+ 		.callback_user_data = callback_user_data,
+ 	};
+ 
+-	if (   !priv->link_ifindex
+-	    || !nm_platform_link_get (nm_device_get_platform (device), priv->link_ifindex)) {
+-		priv->link_ifindex = 0;
++	if (   !priv->waiting_for_interface
++	    && !nm_platform_link_get_by_ifname (nm_device_get_platform (device),
++	                                        nm_device_get_iface (device))) {
++		_LOGT (LOGD_CORE, "deactivate: link not present, proceeding");
++		nm_device_update_from_platform_link (NM_DEVICE (self), NULL);
+ 		nm_utils_invoke_on_idle (deactivate_cb_on_idle, data, cancellable);
+ 		return;
+ 	}
+ 
+-	_LOGT (LOGD_DEVICE,
+-	       "async deactivation: waiting for link %d to disappear",
+-	       priv->link_ifindex);
++	if (priv->waiting_for_interface) {
++		/* At this point we have issued an INSERT and a DELETE
++		 * command for the interface to ovsdb. We don't know if
++		 * vswitchd will see the two updates or only one. We
++		 * must add a timeout to avoid waiting forever in case
++		 * the link doesn't appear.
++		 */
++		data->link_timeout_id = g_timeout_add (6000, deactivate_link_timeout, data);
++		_LOGT (LOGD_DEVICE, "deactivate: waiting for link to disappear in 6 seconds");
++	} else
++		_LOGT (LOGD_DEVICE, "deactivate: waiting for link to disappear");
+ 
+ 	data->cancelled_id = g_cancellable_connect (cancellable,
+ 	                                            G_CALLBACK (deactivate_cancelled_cb),
+@@ -276,7 +308,7 @@ deactivate_async (NMDevice *device,
+ 	                                            NULL);
+ 	data->link_changed_id = g_signal_connect (nm_device_get_platform (device),
+ 	                                          NM_PLATFORM_SIGNAL_LINK_CHANGED,
+-	                                          G_CALLBACK (link_changed_cb),
++	                                          G_CALLBACK (deactivate_link_changed_cb),
+ 	                                          data);
+ }
+ 
+-- 
+2.26.2
+
+
+From e9e1736dfc0c829074b90982ce44e6beb7266b4e Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Fri, 14 Feb 2020 17:46:31 +0100
+Subject: [PATCH 12/25] ovs: discard link updates when deactivating
+
+When the ovs interface gets deactivated, it is released from the
+master port and we call nm_device_update_from_platform_link (dev,
+NULL) to ignore any later event for the interface. This is important
+especially because it sets a zero ifindex on the interface and so,
+later when the link disappears, we don't unmanage the device but
+directly remove it.
+
+However, since ovs commands are queued, the link could appear during
+the deactivation and we need to ignore such events. Add a new device
+method can_update_from_platform_link() for such purpose.
+
+(cherry picked from commit e9fc1dea437a3f78212143e8d2b14bcea8926f90)
+(cherry picked from commit c4eb0c6852d96b82081babe2c16a54df75717aba)
+(cherry picked from commit 34a9247a640504b15daeab578f569a4a151bfa7d)
+(cherry picked from commit b22a20880e697febc3000de60321106a227a64bf)
+---
+ src/devices/nm-device.c                   | 10 ++++++++++
+ src/devices/nm-device.h                   |  2 ++
+ src/devices/ovs/nm-device-ovs-interface.c | 13 +++++++++++++
+ 3 files changed, 25 insertions(+)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 08ee2aef33a4..4bd93a510ee4 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -4142,6 +4142,12 @@ nm_device_create_and_realize (NMDevice *self,
+ 	return TRUE;
+ }
+ 
++static gboolean
++can_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
++{
++	return TRUE;
++}
++
+ void
+ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink)
+ {
+@@ -4150,6 +4156,9 @@ nm_device_update_from_platform_link (NMDevice *self, const NMPlatformLink *plink
+ 	int ifindex;
+ 	guint32 mtu;
+ 
++	if (!NM_DEVICE_GET_CLASS (self)->can_update_from_platform_link (self, plink))
++		return;
++
+ 	g_return_if_fail (plink == NULL || link_type_compatible (self, plink->type, NULL, NULL));
+ 
+ 	str = plink ? nm_platform_link_get_udi (nm_device_get_platform (self), plink->ifindex) : NULL;
+@@ -16974,6 +16983,7 @@ nm_device_class_init (NMDeviceClass *klass)
+ 
+ 	klass->get_type_description = get_type_description;
+ 	klass->can_auto_connect = can_auto_connect;
++	klass->can_update_from_platform_link = can_update_from_platform_link;
+ 	klass->check_connection_compatible = check_connection_compatible;
+ 	klass->check_connection_available = check_connection_available;
+ 	klass->can_unmanaged_external_down = can_unmanaged_external_down;
+diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
+index bcbc00bbedfa..0eab3aca19db 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -460,6 +460,8 @@ typedef struct _NMDeviceClass {
+ 	guint32         (* get_dhcp_timeout) (NMDevice *self,
+ 	                                      int addr_family);
+ 
++	gboolean        (* can_update_from_platform_link) (NMDevice *self, const NMPlatformLink *plink);
++
+ 	/* Controls, whether to call act_stage2_config() callback also for assuming
+ 	 * a device or for external activations. In this case, act_stage2_config() must
+ 	 * take care not to touch the device's configuration. */
+diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
+index 726637864e69..9c74ffd1c22f 100644
+--- a/src/devices/ovs/nm-device-ovs-interface.c
++++ b/src/devices/ovs/nm-device-ovs-interface.c
+@@ -312,6 +312,18 @@ deactivate_async (NMDevice *device,
+ 	                                          data);
+ }
+ 
++static gboolean
++can_update_from_platform_link (NMDevice *device, const NMPlatformLink *plink)
++{
++	/* If the device is deactivating, we already sent the
++	 * deletion command to ovsdb and we don't want to deal
++	 * with any new link appearing from the previous
++	 * activation.
++	 */
++	return    !plink
++	       || nm_device_get_state (device) != NM_DEVICE_STATE_DEACTIVATING;
++}
++
+ /*****************************************************************************/
+ 
+ static void
+@@ -341,6 +353,7 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass)
+ 	device_class->connection_type_check_compatible = NM_SETTING_OVS_INTERFACE_SETTING_NAME;
+ 	device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES (NM_LINK_TYPE_OPENVSWITCH);
+ 
++	device_class->can_update_from_platform_link = can_update_from_platform_link;
+ 	device_class->deactivate = deactivate;
+ 	device_class->deactivate_async = deactivate_async;
+ 	device_class->get_type_description = get_type_description;
+-- 
+2.26.2
+
+
+From 6bf0d9d596d04c37ffa03d634f844a770d120454 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Mon, 9 Mar 2020 11:19:47 +0100
+Subject: [PATCH 13/25] ovs/ovsdb: support changing the MTU of an ovs interface
+
+Introduce a nm_ovsdb_set_interface_mtu() function to update the MTU of
+an ovs interface in the ovsdb.
+
+(cherry picked from commit a4c2c1a843ff1492c1bfae2455a334b0d1c8389c)
+(cherry picked from commit c1be15a66edf1ef1e7de1cc7a0f6e134b8dbdcb7)
+(cherry picked from commit 990f46505d6d9bd4de40db458978b6c94664de13)
+(cherry picked from commit 021141481e3cb7f747111dad67323f5d1a608bf6)
+---
+ src/devices/ovs/nm-ovsdb.c | 77 ++++++++++++++++++++++++++++++--------
+ src/devices/ovs/nm-ovsdb.h |  3 ++
+ 2 files changed, 64 insertions(+), 16 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index c85115201eac..9ed8e06f5259 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -118,6 +118,7 @@ typedef enum {
+ 	OVSDB_MONITOR,
+ 	OVSDB_ADD_INTERFACE,
+ 	OVSDB_DEL_INTERFACE,
++	OVSDB_SET_INTERFACE_MTU,
+ } OvsdbCommand;
+ 
+ typedef struct {
+@@ -127,7 +128,10 @@ typedef struct {
+ 	OvsdbMethodCallback callback;
+ 	gpointer user_data;
+ 	union {
+-		char *ifname;
++		struct {
++			char *ifname;
++			guint32 mtu;
++		};
+ 		struct {
+ 			NMConnection *bridge;
+ 			NMConnection *port;
+@@ -169,6 +173,13 @@ _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg)
+ 		       msg ? ": " : "",
+ 		       msg ? str : "");
+ 		break;
++	case OVSDB_SET_INTERFACE_MTU:
++		_LOGT ("%s: set-iface-mtu interface=%s%s%s mtu=%u",
++		       comment, call->ifname,
++		       msg ? ": " : "",
++		       msg ? str : "",
++		       call->mtu);
++		break;
+ 	}
+ 
+ 	if (msg)
+@@ -187,7 +198,7 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command,
+                    const char *ifname,
+                    NMConnection *bridge, NMConnection *port, NMConnection *interface,
+                    NMDevice *bridge_device, NMDevice *interface_device,
+-                   OvsdbMethodCallback callback, gpointer user_data)
++                   guint32 mtu, OvsdbMethodCallback callback, gpointer user_data)
+ {
+ 	NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self);
+ 	OvsdbMethodCall *call;
+@@ -215,6 +226,10 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command,
+ 	case OVSDB_DEL_INTERFACE:
+ 		call->ifname = g_strdup (ifname);
+ 		break;
++	case OVSDB_SET_INTERFACE_MTU:
++		call->ifname = g_strdup (ifname);
++		call->mtu = mtu;
++		break;
+ 	}
+ 
+ 	_call_trace ("enqueue", call, NULL);
+@@ -817,6 +832,22 @@ ovsdb_next_command (NMOvsdb *self)
+ 
+ 		_delete_interface (self, params, call->ifname);
+ 
++		msg = json_pack ("{s:i, s:s, s:o}",
++		                 "id", call->id,
++		                 "method", "transact", "params", params);
++		break;
++	case OVSDB_SET_INTERFACE_MTU:
++		params = json_array ();
++		json_array_append_new (params, json_string ("Open_vSwitch"));
++		json_array_append_new (params, _inc_next_cfg (priv->db_uuid));
++
++		json_array_append_new (params,
++		                       json_pack ("{s:s, s:s, s:{s: i}, s:[[s, s, s]]}",
++		                                  "op", "update",
++		                                  "table", "Interface",
++		                                  "row", "mtu_request", call->mtu,
++		                                  "where", "name", "==", call->ifname));
++
+ 		msg = json_pack ("{s:i, s:s, s:o}",
+ 		                 "id", call->id,
+ 		                 "method", "transact", "params", params);
+@@ -1462,7 +1493,7 @@ ovsdb_try_connect (NMOvsdb *self)
+ 	/* Queue a monitor call before any other command, ensuring that we have an up
+ 	 * to date view of existing bridged that we need for add and remove ops. */
+ 	ovsdb_call_method (self, OVSDB_MONITOR, NULL,
+-	                   NULL, NULL, NULL, NULL, NULL, _monitor_bridges_cb, NULL);
++	                   NULL, NULL, NULL, NULL, NULL, 0, _monitor_bridges_cb, NULL);
+ }
+ 
+ /*****************************************************************************/
+@@ -1500,11 +1531,8 @@ out:
+ 	g_slice_free (OvsdbCall, call);
+ }
+ 
+-void
+-nm_ovsdb_add_interface (NMOvsdb *self,
+-                        NMConnection *bridge, NMConnection *port, NMConnection *interface,
+-                        NMDevice *bridge_device, NMDevice *interface_device,
+-                        NMOvsdbCallback callback, gpointer user_data)
++static OvsdbCall *
++ovsdb_call_new (NMOvsdbCallback callback, gpointer user_data)
+ {
+ 	OvsdbCall *call;
+ 
+@@ -1512,24 +1540,40 @@ nm_ovsdb_add_interface (NMOvsdb *self,
+ 	call->callback = callback;
+ 	call->user_data = user_data;
+ 
++	return call;
++}
++
++void
++nm_ovsdb_add_interface (NMOvsdb *self,
++                        NMConnection *bridge, NMConnection *port, NMConnection *interface,
++                        NMDevice *bridge_device, NMDevice *interface_device,
++                        NMOvsdbCallback callback, gpointer user_data)
++{
+ 	ovsdb_call_method (self, OVSDB_ADD_INTERFACE, NULL,
+ 	                   bridge, port, interface,
+ 	                   bridge_device, interface_device,
+-	                   _transact_cb, call);
++	                   0,
++	                   _transact_cb,
++	                   ovsdb_call_new (callback, user_data));
+ }
+ 
+ void
+ nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname,
+                         NMOvsdbCallback callback, gpointer user_data)
+ {
+-	OvsdbCall *call;
+-
+-	call = g_slice_new (OvsdbCall);
+-	call->callback = callback;
+-	call->user_data = user_data;
+-
+ 	ovsdb_call_method (self, OVSDB_DEL_INTERFACE, ifname,
+-	                   NULL, NULL, NULL, NULL, NULL, _transact_cb, call);
++	                   NULL, NULL, NULL, NULL, NULL, 0,
++	                   _transact_cb,
++	                   ovsdb_call_new (callback, user_data));
++}
++
++void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu,
++                                 NMOvsdbCallback callback, gpointer user_data)
++{
++	ovsdb_call_method (self, OVSDB_SET_INTERFACE_MTU, ifname,
++	                   NULL, NULL, NULL, NULL, NULL, mtu,
++	                   _transact_cb,
++	                   ovsdb_call_new (callback, user_data));
+ }
+ 
+ /*****************************************************************************/
+@@ -1550,6 +1594,7 @@ _clear_call (gpointer data)
+ 		g_clear_object (&call->interface_device);
+ 		break;
+ 	case OVSDB_DEL_INTERFACE:
++	case OVSDB_SET_INTERFACE_MTU:
+ 		g_clear_pointer (&call->ifname, g_free);
+ 		break;
+ 	}
+diff --git a/src/devices/ovs/nm-ovsdb.h b/src/devices/ovs/nm-ovsdb.h
+index e7f9d71984c2..9552dcca3226 100644
+--- a/src/devices/ovs/nm-ovsdb.h
++++ b/src/devices/ovs/nm-ovsdb.h
+@@ -48,4 +48,7 @@ void nm_ovsdb_add_interface (NMOvsdb *self,
+ void nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname,
+                              NMOvsdbCallback callback, gpointer user_data);
+ 
++void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu,
++                                 NMOvsdbCallback callback, gpointer user_data);
++
+ #endif /* __NETWORKMANAGER_OVSDB_H__ */
+-- 
+2.26.2
+
+
+From 449dd37015d890ddf9385ad062dc4204974179ac Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 27 Feb 2020 13:54:43 +0100
+Subject: [PATCH 14/25] ovs: set MTU from connection when creating an internal
+ interface
+
+The ovs-vswitchd.conf.db(5) man page says about the the mtu_request
+column in the Interface table:
+
+  "Requested MTU (Maximum Transmission Unit) for the interface. A
+   client can fill this column to change the MTU of an
+   interface [...] If this is not set and if the interface has
+   internal type, Open vSwitch will change the MTU to match the
+   minimum of the other interfaces in the bridge."
+
+Therefore, if the connection specifies a MTU, set it early when adding
+the interface to the ovsdb so that it will not be changed to the
+minimum of other interfaces.
+
+(cherry picked from commit ad12f26312bb4ccc73076f39bd2a618094af6e7e)
+(cherry picked from commit 7311d5e2943931a70fb427096ea934072aed63b3)
+(cherry picked from commit b81370f70b538688a62ad4a29482dbf9b34c69bc)
+(cherry picked from commit 59787018c983e433da6172944e60246961c38d71)
+---
+ src/devices/ovs/nm-ovsdb.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 9ed8e06f5259..753f5f172a09 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -367,11 +367,20 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_
+ 	gs_free char *cloned_mac = NULL;
+ 	gs_free_error GError *error = NULL;
+ 	json_t *row;
++	guint32 mtu = 0;
+ 
+ 	s_ovs_iface = nm_connection_get_setting_ovs_interface (interface);
+ 	if (s_ovs_iface)
+ 		type = nm_setting_ovs_interface_get_interface_type (s_ovs_iface);
+ 
++	if (nm_streq0 (type, "internal")) {
++		NMSettingWired *s_wired;
++
++		s_wired = _nm_connection_get_setting (interface, NM_TYPE_SETTING_WIRED);
++		if (s_wired)
++			mtu = nm_setting_wired_get_mtu (s_wired);
++	}
++
+ 	if (!nm_device_hw_addr_get_cloned (interface_device,
+ 	                                   interface,
+ 	                                   FALSE,
+@@ -404,6 +413,9 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_
+ 	if (cloned_mac)
+ 		json_object_set_new (row, "mac", json_string (cloned_mac));
+ 
++	if (mtu != 0)
++		json_object_set_new (row, "mtu_request", json_integer (mtu));
++
+ 	json_array_append_new (params,
+ 	        json_pack ("{s:s, s:s, s:o, s:s}",
+ 	                   "op", "insert",
+-- 
+2.26.2
+
+
+From a337a7d144b2bc25f75a838042e540a3f7518105 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Mon, 16 Mar 2020 10:53:06 +0100
+Subject: [PATCH 15/25] ovs: set the MTU in ovsdb when changing platform MTU of
+ ovs-interface
+
+If we change the the MTU of an ovs interface only through netlink, the
+change could be overridden by ovs-vswitchd at any time when other
+interfaces change. Set the MTU also in the ovsdb to prevent such
+changes.
+
+Note that if the MTU comes from the connection, we already set the
+ovsdb MTU at creation time and so this other update becomes
+useless. But it is needed when changing the MTU at runtime (reapply)
+or when the MTU comes from a different source (e.g. DHCP).
+
+(cherry picked from commit c2a97129453c49f86976b42c29b793a87d9d2e41)
+(cherry picked from commit e27a59c69e956961efe99f83068b760380b77066)
+(cherry picked from commit 99ef891db6a561d6b3dcaec9ead2b2158b43ae8d)
+(cherry picked from commit 04264be151f323a78dea23e58311c90d9928bd9e)
+---
+ src/devices/nm-device.c                   | 17 +++++++---
+ src/devices/nm-device.h                   |  2 ++
+ src/devices/ovs/nm-device-ovs-interface.c | 39 +++++++++++++++++++++++
+ 3 files changed, 54 insertions(+), 4 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 4bd93a510ee4..9bfd3704edc9 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -9152,6 +9152,17 @@ _set_mtu (NMDevice *self, guint32 mtu)
+ 	}
+ }
+ 
++static gboolean
++set_platform_mtu (NMDevice *self, guint32 mtu)
++{
++	int r;
++
++	r = nm_platform_link_set_mtu (nm_device_get_platform (self),
++	                              nm_device_get_ip_ifindex (self),
++	                              mtu);
++	return (r != -NME_PL_CANT_SET_MTU);
++}
++
+ static void
+ _commit_mtu (NMDevice *self, const NMIP4Config *config)
+ {
+@@ -9310,10 +9321,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
+ 		}
+ 
+ 		if (mtu_desired && mtu_desired != mtu_plat) {
+-			int r;
+-
+-			r = nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired);
+-			if (r == -NME_PL_CANT_SET_MTU) {
++			if (!NM_DEVICE_GET_CLASS (self)->set_platform_mtu (self, mtu_desired)) {
+ 				anticipated_failure = TRUE;
+ 				success = FALSE;
+ 				_LOGW (LOGD_DEVICE, "mtu: failure to set MTU. %s",
+@@ -16996,6 +17004,7 @@ nm_device_class_init (NMDeviceClass *klass)
+ 	klass->parent_changed_notify = parent_changed_notify;
+ 	klass->can_reapply_change = can_reapply_change;
+ 	klass->reapply_connection = reapply_connection;
++	klass->set_platform_mtu = set_platform_mtu;
+ 
+ 	obj_properties[PROP_UDI] =
+ 	    g_param_spec_string (NM_DEVICE_UDI, "", "",
+diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
+index 0eab3aca19db..5a9339d03d1d 100644
+--- a/src/devices/nm-device.h
++++ b/src/devices/nm-device.h
+@@ -462,6 +462,8 @@ typedef struct _NMDeviceClass {
+ 
+ 	gboolean        (* can_update_from_platform_link) (NMDevice *self, const NMPlatformLink *plink);
+ 
++	gboolean        (* set_platform_mtu) (NMDevice *self, guint32 mtu);
++
+ 	/* Controls, whether to call act_stage2_config() callback also for assuming
+ 	 * a device or for external activations. In this case, act_stage2_config() must
+ 	 * take care not to touch the device's configuration. */
+diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
+index 9c74ffd1c22f..f2919b488190 100644
+--- a/src/devices/ovs/nm-device-ovs-interface.c
++++ b/src/devices/ovs/nm-device-ovs-interface.c
+@@ -134,6 +134,43 @@ _is_internal_interface (NMDevice *device)
+ 	return nm_streq (nm_setting_ovs_interface_get_interface_type (s_ovs_iface), "internal");
+ }
+ 
++static void
++set_platform_mtu_cb (GError *error, gpointer user_data)
++{
++	NMDevice *device = user_data;
++	NMDeviceOvsInterface *self = NM_DEVICE_OVS_INTERFACE (device);
++
++	if (   error
++	    && !g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) {
++		_LOGW (LOGD_DEVICE, "could not change mtu of '%s': %s",
++		       nm_device_get_iface (device), error->message);
++	}
++
++	g_object_unref (device);
++}
++
++static gboolean
++set_platform_mtu (NMDevice *device, guint32 mtu)
++{
++	/*
++	 * If the MTU is not set in ovsdb, Open vSwitch will change
++	 * the MTU of an internal interface to match the minimum of
++	 * the other interfaces in the bridge.
++	 */
++	/* FIXME(shutdown): the function should become cancellable so
++	 * that it doesn't need to hold a reference to the device, and
++	 * it can be stopped during shutdown.
++	 */
++	if (_is_internal_interface (device)) {
++		nm_ovsdb_set_interface_mtu (nm_ovsdb_get (),
++		                            nm_device_get_ip_iface (device),
++		                            mtu, set_platform_mtu_cb,
++		                            g_object_ref (device));
++	}
++
++	return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->set_platform_mtu (device, mtu);
++}
++
+ static NMActStageReturn
+ act_stage3_ip_config_start (NMDevice *device,
+                             int addr_family,
+@@ -364,4 +401,6 @@ nm_device_ovs_interface_class_init (NMDeviceOvsInterfaceClass *klass)
+ 	device_class->link_changed = link_changed;
+ 	device_class->act_stage3_ip_config_start = act_stage3_ip_config_start;
+ 	device_class->can_unmanaged_external_down = can_unmanaged_external_down;
++	device_class->set_platform_mtu = set_platform_mtu;
++	device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
+ }
+-- 
+2.26.2
+
+
+From 8d3cd486012fdd04a1f9d2e976b7cf9f869b0205 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Fri, 3 Apr 2020 09:13:51 +0200
+Subject: [PATCH 16/25] ovsdb: retry calls in case of communication error with
+ server
+
+When the server is restarted the write to unix socket fails with
+EPIPE. In such case, don't fail all the calls in queue; instead, after
+a sync of the ovsdb state (through a monitor call), start processing
+the queue again, including the call that previously failed.
+
+Add a retry counter to avoid that calls are stuck in the queue forever
+in a hypothetical scenario in which the write always fails.
+
+https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/459
+(cherry picked from commit db37e530e8f03b7882997194bb325a206555c44d)
+(cherry picked from commit 54254bf6fe869b83189f43cdf13652c165d5aa71)
+(cherry picked from commit 166ad887f9d2fa361dcc6e0926e21e25c7a4ce2d)
+(cherry picked from commit b2d597695073866aa646e76df99170bc14a47cbe)
+---
+ src/devices/ovs/nm-ovsdb.c | 81 ++++++++++++++++++++++++++------------
+ 1 file changed, 55 insertions(+), 26 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 753f5f172a09..7e9214e8676c 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -79,6 +79,7 @@ typedef struct {
+ 	GHashTable *ports;              /* port uuid => OpenvswitchPort */
+ 	GHashTable *bridges;            /* bridge uuid => OpenvswitchBridge */
+ 	char *db_uuid;
++	guint num_failures;
+ } NMOvsdbPrivate;
+ 
+ struct _NMOvsdb {
+@@ -102,7 +103,7 @@ NM_DEFINE_SINGLETON_GETTER (NMOvsdb, nm_ovsdb_get, NM_TYPE_OVSDB);
+ /*****************************************************************************/
+ 
+ static void ovsdb_try_connect (NMOvsdb *self);
+-static void ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing);
++static void ovsdb_disconnect (NMOvsdb *self, gboolean retry, gboolean is_disposing);
+ static void ovsdb_read (NMOvsdb *self);
+ static void ovsdb_write (NMOvsdb *self);
+ static void ovsdb_next_command (NMOvsdb *self);
+@@ -142,6 +143,8 @@ typedef struct {
+ 	};
+ } OvsdbMethodCall;
+ 
++#define OVSDB_MAX_FAILURES    3
++
+ static void
+ _call_trace (const char *comment, OvsdbMethodCall *call, json_t *msg)
+ {
+@@ -198,7 +201,8 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command,
+                    const char *ifname,
+                    NMConnection *bridge, NMConnection *port, NMConnection *interface,
+                    NMDevice *bridge_device, NMDevice *interface_device,
+-                   guint32 mtu, OvsdbMethodCallback callback, gpointer user_data)
++                   guint32 mtu, OvsdbMethodCallback callback, gpointer user_data,
++                   gboolean add_first)
+ {
+ 	NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self);
+ 	OvsdbMethodCall *call;
+@@ -206,8 +210,13 @@ ovsdb_call_method (NMOvsdb *self, OvsdbCommand command,
+ 	/* Ensure we're not unsynchronized before we queue the method call. */
+ 	ovsdb_try_connect (self);
+ 
+-	g_array_set_size (priv->calls, priv->calls->len + 1);
+-	call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1);
++	if (add_first) {
++		g_array_prepend_val (priv->calls, (OvsdbMethodCall) {});
++		call = &g_array_index (priv->calls, OvsdbMethodCall, 0);
++	} else {
++		g_array_set_size (priv->calls, priv->calls->len + 1);
++		call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1);
++	}
+ 	call->id = COMMAND_PENDING;
+ 	call->command = command;
+ 	call->callback = callback;
+@@ -1197,7 +1206,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg)
+ 	                    "result", &result,
+ 	                    "error", &error) == -1) {
+ 		_LOGW ("couldn't grok the message: %s", json_error.text);
+-		ovsdb_disconnect (self, FALSE);
++		ovsdb_disconnect (self, FALSE, FALSE);
+ 		return;
+ 	}
+ 
+@@ -1208,7 +1217,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg)
+ 		/* It's a method call! */
+ 		if (!params) {
+ 			_LOGW ("a method call with no params: '%s'", method);
+-			ovsdb_disconnect (self, FALSE);
++			ovsdb_disconnect (self, FALSE, FALSE);
+ 			return;
+ 		}
+ 
+@@ -1228,13 +1237,13 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg)
+ 		/* This is a response to a method call. */
+ 		if (!priv->calls->len) {
+ 			_LOGE ("there are no queued calls expecting response %" G_GUINT64_FORMAT, id);
+-			ovsdb_disconnect (self, FALSE);
++			ovsdb_disconnect (self, FALSE, FALSE);
+ 			return;
+ 		}
+ 		call = &g_array_index (priv->calls, OvsdbMethodCall, 0);
+ 		if (call->id != id) {
+ 			_LOGE ("expected a response to call %" G_GUINT64_FORMAT ", not %" G_GUINT64_FORMAT, call->id, id);
+-			ovsdb_disconnect (self, FALSE);
++			ovsdb_disconnect (self, FALSE, FALSE);
+ 			return;
+ 		}
+ 		/* Cool, we found a corresponding call. Finish it. */
+@@ -1252,6 +1261,7 @@ ovsdb_got_msg (NMOvsdb *self, json_t *msg)
+ 		user_data = call->user_data;
+ 		g_array_remove_index (priv->calls, 0);
+ 		callback (self, result, local, user_data);
++		priv->num_failures = 0;
+ 
+ 		/* Don't progress further commands in case the callback hit an error
+ 		 * and disconnected us. */
+@@ -1310,9 +1320,11 @@ ovsdb_read_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+ 
+ 	size = g_input_stream_read_finish (stream, res, &error);
+ 	if (size == -1) {
++		/* ovsdb-server was possibly restarted */
+ 		_LOGW ("short read from ovsdb: %s", error->message);
++		priv->num_failures++;
+ 		g_clear_error (&error);
+-		ovsdb_disconnect (self, FALSE);
++		ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
+ 		return;
+ 	}
+ 
+@@ -1358,9 +1370,11 @@ ovsdb_write_cb (GObject *source_object, GAsyncResult *res, gpointer user_data)
+ 
+ 	size = g_output_stream_write_finish (stream, res, &error);
+ 	if (size == -1) {
++		/* ovsdb-server was possibly restarted */
+ 		_LOGW ("short write to ovsdb: %s", error->message);
++		priv->num_failures++;
+ 		g_clear_error (&error);
+-		ovsdb_disconnect (self, FALSE);
++		ovsdb_disconnect (self, priv->num_failures <= OVSDB_MAX_FAILURES, FALSE);
+ 		return;
+ 	}
+ 
+@@ -1403,7 +1417,7 @@ ovsdb_write (NMOvsdb *self)
+  * puts us back in sync.
+  */
+ static void
+-ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing)
++ovsdb_disconnect (NMOvsdb *self, gboolean retry, gboolean is_disposing)
+ {
+ 	NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self);
+ 	OvsdbMethodCall *call;
+@@ -1411,18 +1425,26 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing)
+ 	gpointer user_data;
+ 	gs_free_error GError *error = NULL;
+ 
++	nm_assert (!retry || !is_disposing);
++
+ 	if (!priv->client)
+ 		return;
+ 
+-	_LOGD ("disconnecting from ovsdb");
+-	nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb");
++	_LOGD ("disconnecting from ovsdb, retry %d", retry);
+ 
+-	while (priv->calls->len) {
+-		call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1);
+-		callback = call->callback;
+-		user_data = call->user_data;
+-		g_array_remove_index (priv->calls, priv->calls->len - 1);
+-		callback (self, NULL, error, user_data);
++	if (retry) {
++		if (priv->calls->len != 0)
++			g_array_index (priv->calls, OvsdbMethodCall, 0).id = COMMAND_PENDING;
++	} else {
++		nm_utils_error_set_cancelled (&error, is_disposing, "NMOvsdb");
++
++		while (priv->calls->len) {
++			call = &g_array_index (priv->calls, OvsdbMethodCall, priv->calls->len - 1);
++			callback = call->callback;
++			user_data = call->user_data;
++			g_array_remove_index (priv->calls, priv->calls->len - 1);
++			callback (self, NULL, error, user_data);
++		}
+ 	}
+ 
+ 	priv->bufp = 0;
+@@ -1432,6 +1454,9 @@ ovsdb_disconnect (NMOvsdb *self, gboolean is_disposing)
+ 	g_clear_object (&priv->conn);
+ 	g_clear_pointer (&priv->db_uuid, g_free);
+ 	nm_clear_g_cancellable (&priv->cancellable);
++
++	if (retry)
++		ovsdb_try_connect (self);
+ }
+ 
+ static void
+@@ -1440,7 +1465,7 @@ _monitor_bridges_cb (NMOvsdb *self, json_t *result, GError *error, gpointer user
+ 	if (error) {
+ 		if (!nm_utils_error_is_cancelled (error, TRUE)) {
+ 			_LOGI ("%s", error->message);
+-			ovsdb_disconnect (self, FALSE);
++			ovsdb_disconnect (self, FALSE, FALSE);
+ 		}
+ 		return;
+ 	}
+@@ -1464,7 +1489,7 @@ _client_connect_cb (GObject *source_object, GAsyncResult *res, gpointer user_dat
+ 		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ 			_LOGI ("%s", error->message);
+ 
+-		ovsdb_disconnect (self, FALSE);
++		ovsdb_disconnect (self, FALSE, FALSE);
+ 		g_clear_error (&error);
+ 		return;
+ 	}
+@@ -1505,7 +1530,8 @@ ovsdb_try_connect (NMOvsdb *self)
+ 	/* Queue a monitor call before any other command, ensuring that we have an up
+ 	 * to date view of existing bridged that we need for add and remove ops. */
+ 	ovsdb_call_method (self, OVSDB_MONITOR, NULL,
+-	                   NULL, NULL, NULL, NULL, NULL, 0, _monitor_bridges_cb, NULL);
++	                   NULL, NULL, NULL, NULL, NULL, 0,
++	                   _monitor_bridges_cb, NULL, TRUE);
+ }
+ 
+ /*****************************************************************************/
+@@ -1566,7 +1592,8 @@ nm_ovsdb_add_interface (NMOvsdb *self,
+ 	                   bridge_device, interface_device,
+ 	                   0,
+ 	                   _transact_cb,
+-	                   ovsdb_call_new (callback, user_data));
++	                   ovsdb_call_new (callback, user_data),
++	                   FALSE);
+ }
+ 
+ void
+@@ -1576,7 +1603,8 @@ nm_ovsdb_del_interface (NMOvsdb *self, const char *ifname,
+ 	ovsdb_call_method (self, OVSDB_DEL_INTERFACE, ifname,
+ 	                   NULL, NULL, NULL, NULL, NULL, 0,
+ 	                   _transact_cb,
+-	                   ovsdb_call_new (callback, user_data));
++	                   ovsdb_call_new (callback, user_data),
++	                   FALSE);
+ }
+ 
+ void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu,
+@@ -1585,7 +1613,8 @@ void nm_ovsdb_set_interface_mtu (NMOvsdb *self, const char *ifname, guint32 mtu,
+ 	ovsdb_call_method (self, OVSDB_SET_INTERFACE_MTU, ifname,
+ 	                   NULL, NULL, NULL, NULL, NULL, mtu,
+ 	                   _transact_cb,
+-	                   ovsdb_call_new (callback, user_data));
++	                   ovsdb_call_new (callback, user_data),
++	                   FALSE);
+ }
+ 
+ /*****************************************************************************/
+@@ -1667,7 +1696,7 @@ dispose (GObject *object)
+ 	NMOvsdb *self = NM_OVSDB (object);
+ 	NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE (self);
+ 
+-	ovsdb_disconnect (self, TRUE);
++	ovsdb_disconnect (self, FALSE, TRUE);
+ 
+ 	if (priv->input) {
+ 		g_string_free (priv->input, TRUE);
+-- 
+2.26.2
+
+
+From f6be05697997595cc844b827d0ad11c66b7482ed Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Tue, 9 Jun 2020 10:44:01 +0200
+Subject: [PATCH 17/25] ovs: ignore failures of patch interfaces
+
+When there are two patch ports connected, each of them must reference
+the other; however they can't be created in a single transaction
+because they are part of different bridges (so, different
+connections). Therefore, the first patch that gets activated will
+always fail with "No usable peer $x exists in 'system' datapath" until
+the second patch exists.
+
+In theory we could also match the error message, however this doesn't
+seem very robust as the message may slightly change in the future.
+
+(cherry picked from commit ffeac35f0409516aa2302189cca3f0b72518466a)
+(cherry picked from commit 75cbf2173862a00ff44342a4a676aa1f6f9ac78d)
+(cherry picked from commit 399aad15bf53420cc015c7a920856f88d5584dfc)
+(cherry picked from commit 692689ead8aaf4f1441a82e546649d996bd812d4)
+(cherry picked from commit 4c8edaedc7a1cf6af91edb56c8b7f8db1b28c704)
+---
+ src/devices/ovs/nm-ovs-factory.c | 37 ++++++++++++++++++++++++++------
+ 1 file changed, 31 insertions(+), 6 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovs-factory.c b/src/devices/ovs/nm-ovs-factory.c
+index fdf07bd3750a..f83c9e582730 100644
+--- a/src/devices/ovs/nm-ovs-factory.c
++++ b/src/devices/ovs/nm-ovs-factory.c
+@@ -155,15 +155,40 @@ ovsdb_interface_failed (NMOvsdb *ovsdb,
+ {
+ 	NMDevice *device = NULL;
+ 	NMSettingsConnection *connection = NULL;
+-
+-	_LOGI (name, connection_uuid, "ovs interface \"%s\" (%s) failed: %s", name, connection_uuid, error);
++	NMConnection *c;
++	const char *type;
++	NMSettingOvsInterface *s_ovs_int;
++	gboolean is_patch = FALSE;
++	gboolean ignore;
+ 
+ 	device = nm_manager_get_device (nm_manager_get (), name, NM_DEVICE_TYPE_OVS_INTERFACE);
+-	if (!device)
+-		return;
++	if (device && connection_uuid) {
++		connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (device),
++		                                                 connection_uuid);
++	}
+ 
+-	if (connection_uuid)
+-		connection = nm_settings_get_connection_by_uuid (nm_device_get_settings (device), connection_uuid);
++	/* The patch interface which gets created first is expected to
++	 * fail because the second patch doesn't exist yet. Ignore all
++	 * failures of patch interfaces. */
++	if (   connection
++	    && (c = nm_settings_connection_get_connection (connection))
++	    && (type = nm_connection_get_connection_type (c))
++	    && nm_streq0 (type, NM_SETTING_OVS_INTERFACE_SETTING_NAME)
++	    && (s_ovs_int = nm_connection_get_setting_ovs_interface (c))
++	    && nm_streq0 (nm_setting_ovs_interface_get_interface_type (s_ovs_int), "patch"))
++		is_patch = TRUE;
++
++	ignore = !device || is_patch;
++
++	_NMLOG (ignore ? LOGL_DEBUG : LOGL_INFO,
++	        name, connection_uuid,
++	        "ovs interface \"%s\" (%s) failed%s: %s",
++	        name, connection_uuid,
++	        ignore ? " (ignored)" : "",
++	        error);
++
++	if (ignore)
++		return;
+ 
+ 	if (connection) {
+ 		nm_settings_connection_autoconnect_blocked_reason_set (connection,
+-- 
+2.26.2
+
+
+From ceaeab87773f830f91ef2de84be9e1d12bce76a8 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 2 Jul 2020 17:38:10 +0200
+Subject: [PATCH 18/25] device: restart DHCP only for devices that are active
+ or activating
+
+do_sleep_wake() tries to restart DHCP for all devices, even ones that
+are disconnecting. When a device is disconnecting, it still has a DHCP
+client instance but we shouldn't restart it because it makes no sense;
+and especially, the device could be already removed.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1852612
+https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/561
+(cherry picked from commit 2c50438987527a30d99c07601b8f1d1c9557cdaf)
+(cherry picked from commit 53214901800ebcd1e1fabf98442983939af979bc)
+(cherry picked from commit ef755588ad55261c6ade4ba0278d51d777022183)
+(cherry picked from commit da54b35af3b0a5120b4703060ee0b95cbc4fd0bd)
+(cherry picked from commit b0be1285cceff5de2eef44a56abda6a98d51c91a)
+(cherry picked from commit 03b963451952435b9607c2335b24d9da6fd73745)
+---
+ src/devices/nm-device.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index 9bfd3704edc9..c2eb815b3b3a 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -3412,6 +3412,10 @@ nm_device_update_dynamic_ip_setup (NMDevice *self)
+ 
+ 	priv = NM_DEVICE_GET_PRIVATE (self);
+ 
++	if (   priv->state < NM_DEVICE_STATE_IP_CONFIG
++	    || priv->state > NM_DEVICE_STATE_ACTIVATED)
++		return;
++
+ 	g_hash_table_remove_all (priv->ip6_saved_properties);
+ 
+ 	if (priv->dhcp4.client) {
+-- 
+2.26.2
+
+
+From 7f44570ee67d33450f55402120682ae4d1a9a314 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 16 Jul 2020 11:57:14 +0200
+Subject: [PATCH 19/25] manager: fix race condition when resuming from sleep
+
+If the device state change (to disconnected or unmanaged) triggered by
+a sleep event happens after the wake, the devices becomes wrongly
+unmanaged and it's necessary to manually manage it again, or restart
+NM.
+
+During the wake event we should disconnect the device_sleep_cb()
+callback for all devices because we don't want to react to state
+changes anymore; in particular we don't need to detect when the device
+becomes disconnected to unmanage it.
+
+(cherry picked from commit fe2d93980bd5b61c55a8b65a55f7aad35042e691)
+(cherry picked from commit 971897195a8218cb0ec08ae95a7210fce73f0b03)
+(cherry picked from commit 7913275b02c60803f21609168f9c16d2f2a4be2f)
+(cherry picked from commit 6d0e8a2acfa6b7b6a2af1834d8873fc18fc2c55a)
+(cherry picked from commit 61c44dad91733bc09e20752915476a7678a73b90)
+(cherry picked from commit b3ec3fa5abecdffadaaef59e1f8401cf90caf884)
+---
+ src/nm-manager.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/src/nm-manager.c b/src/nm-manager.c
+index 68eff1e466c0..e702fd90a55a 100644
+--- a/src/nm-manager.c
++++ b/src/nm-manager.c
+@@ -5904,8 +5904,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed)
+ 	} else {
+ 		_LOGD (LOGD_SUSPEND, "sleep: %s...", waking_from_suspend ? "waking up" : "re-enabling");
+ 
++		sleep_devices_clear (self);
++
+ 		if (waking_from_suspend) {
+-			sleep_devices_clear (self);
+ 			c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
+ 				if (nm_device_is_software (device))
+ 					continue;
+-- 
+2.26.2
+
+
+From ab2b474f7feefd61da5ee5f2cfc5623e07e48300 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 16 Jul 2020 11:58:20 +0200
+Subject: [PATCH 20/25] policy: block connection from autoconnect in case of
+ failed dependency
+
+A connection that fails due to dependency-failed is not able to
+reconnect until the master connection activates again; when this
+happens, the master clears the blocked reason for all its slaves in
+activate_slave_connections() and tries to reconnect them. For this to
+work, the slave should be marked as blocked when it fails with
+dependency-failed.
+
+(cherry picked from commit 725fed01cf7c8508cf426897340b2a4113406aab)
+(cherry picked from commit e1755048e35aca682c7d0d233122d4ddaf3bb089)
+(cherry picked from commit ecb134ac349a0bf6582833253b6d453d6bf997de)
+(cherry picked from commit bb4781cc581a3c9fcefbfc1ea0be5e95aa3e287b)
+(cherry picked from commit 70c642325f90f767954aa86079b1bc6a4946f15f)
+(cherry picked from commit 8d87f752db68652b4be1d1e3e4f03f82a0b14e83)
+---
+ src/nm-policy.c | 33 +++++++++++++++++++++++++--------
+ 1 file changed, 25 insertions(+), 8 deletions(-)
+
+diff --git a/src/nm-policy.c b/src/nm-policy.c
+index 1faba5c7be04..5625986d1d85 100644
+--- a/src/nm-policy.c
++++ b/src/nm-policy.c
+@@ -1807,7 +1807,7 @@ device_state_changed (NMDevice *device,
+ 		if (   sett_conn
+ 		    && old_state >= NM_DEVICE_STATE_PREPARE
+ 		    && old_state <= NM_DEVICE_STATE_ACTIVATED) {
+-			gboolean block_no_secrets = FALSE;
++			gboolean blocked = FALSE;
+ 			int tries;
+ 			guint64 con_v;
+ 
+@@ -1827,15 +1827,32 @@ device_state_changed (NMDevice *device,
+ 				 */
+ 				con_v = nm_settings_connection_get_last_secret_agent_version_id (sett_conn);
+ 				if (   con_v == 0
+-				    || con_v == nm_agent_manager_get_agent_version_id (priv->agent_mgr))
+-					block_no_secrets = TRUE;
++				    || con_v == nm_agent_manager_get_agent_version_id (priv->agent_mgr)) {
++					_LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets",
++					       nm_settings_connection_get_id (sett_conn));
++					nm_settings_connection_autoconnect_blocked_reason_set (sett_conn,
++					                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS,
++					                                                       TRUE);
++					blocked = TRUE;
++				}
++			} else if (nm_device_state_reason_check (reason) == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) {
++				/* A connection that fails due to dependency-failed is not
++				 * able to reconnect until the master connection activates
++				 * again; when this happens, the master clears the blocked
++				 * reason for all its slaves in activate_slave_connections()
++				 * and tries to reconnect them. For this to work, the slave
++				 * should be marked as blocked when it fails with
++				 * dependency-failed.
++				 */
++				_LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to failed dependency",
++				       nm_settings_connection_get_id (sett_conn));
++				nm_settings_connection_autoconnect_blocked_reason_set (sett_conn,
++				                                                       NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED,
++				                                                       TRUE);
++				blocked = TRUE;
+ 			}
+ 
+-			if (block_no_secrets) {
+-				_LOGD (LOGD_DEVICE, "connection '%s' now blocked from autoconnect due to no secrets",
+-				       nm_settings_connection_get_id (sett_conn));
+-				nm_settings_connection_autoconnect_blocked_reason_set (sett_conn, NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, TRUE);
+-			} else {
++			if (!blocked) {
+ 				tries = nm_settings_connection_autoconnect_retries_get (sett_conn);
+ 				if (tries > 0) {
+ 					_LOGD (LOGD_DEVICE, "connection '%s' failed to autoconnect; %d tries left",
+-- 
+2.26.2
+
+
+From a19fe2332ad4c9344c6c880ec7fa65318bedd50c Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Wed, 1 Jul 2020 10:55:01 +0200
+Subject: [PATCH 21/25] ovs: set MAC address on the bridge for local interfaces
+
+When a user creates a ovs-interface with the same name of the parent
+ovs-bridge, openvswitch considers the interface as the "local
+interface" [1] and assigns the MAC address of the bridge to the
+interface [2].
+
+This is confusing for users, as the cloned MAC property is ignored in
+some cases, depending on the ovs-interface name.
+
+Instead, detect when the interface is local and set the MAC from the
+ovs-interface connection in the bridge table.
+
+[1] https://github.com/openvswitch/ovs/blob/v2.13.0/vswitchd/vswitch.xml#L2546
+[2] https://github.com/openvswitch/ovs/blob/v2.13.0/vswitchd/bridge.c#L4744
+
+(cherry picked from commit 5d4c8521a38c166a9a0aafe5be2bd0545084e154)
+(cherry picked from commit 7548c29a89e12349fdfe196e96d65a6abae74cb5)
+(cherry picked from commit 127294babc23782781c17192c52a2d57f7916170)
+(cherry picked from commit f54c5400c8e43e71fb7c4e1e705866862af69ccd)
+(cherry picked from commit 1a08885080855c3ee14f181c7bd236680663c97f)
+(cherry picked from commit 9493f1f151cb7647f69af790d31086748f98424e)
+---
+ src/devices/ovs/nm-ovsdb.c | 114 +++++++++++++++++++++++++------------
+ 1 file changed, 77 insertions(+), 37 deletions(-)
+
+diff --git a/src/devices/ovs/nm-ovsdb.c b/src/devices/ovs/nm-ovsdb.c
+index 7e9214e8676c..cedcb1d9af9b 100644
+--- a/src/devices/ovs/nm-ovsdb.c
++++ b/src/devices/ovs/nm-ovsdb.c
+@@ -324,6 +324,18 @@ _set_bridge_ports (json_t *params, const char *ifname, json_t *new_ports)
+ 	);
+ }
+ 
++static void
++_set_bridge_mac (json_t *params, const char *ifname, const char *mac)
++{
++	json_array_append_new (params,
++		json_pack ("{s:s, s:s, s:{s:[s, [[s, s]]]}, s:[[s, s, s]]}",
++		           "op", "update", "table", "Bridge",
++		           "row", "other_config", "map",
++		           "hwaddr", mac,
++		           "where", "name", "==", ifname)
++	);
++}
++
+ /**
+  * _expect_port_interfaces:
+  *
+@@ -367,14 +379,15 @@ _set_port_interfaces (json_t *params, const char *ifname, json_t *new_interfaces
+  * Returns an commands that adds new interface from a given connection.
+  */
+ static void
+-_insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_device)
++_insert_interface (json_t *params,
++                   NMConnection *interface,
++                   NMDevice *interface_device,
++                   const char *cloned_mac)
+ {
+ 	const char *type = NULL;
+ 	NMSettingOvsInterface *s_ovs_iface;
+ 	NMSettingOvsPatch *s_ovs_patch;
+ 	json_t *options = json_array ();
+-	gs_free char *cloned_mac = NULL;
+-	gs_free_error GError *error = NULL;
+ 	json_t *row;
+ 	guint32 mtu = 0;
+ 
+@@ -390,18 +403,6 @@ _insert_interface (json_t *params, NMConnection *interface, NMDevice *interface_
+ 			mtu = nm_setting_wired_get_mtu (s_wired);
+ 	}
+ 
+-	if (!nm_device_hw_addr_get_cloned (interface_device,
+-	                                   interface,
+-	                                   FALSE,
+-	                                   &cloned_mac,
+-	                                   NULL,
+-	                                   &error)) {
+-		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
+-		       "interface",
+-		       nm_connection_get_interface_name (interface),
+-		       error->message);
+-	}
+-
+ 	json_array_append_new (options, json_string ("map"));
+ 	s_ovs_patch = nm_connection_get_setting_ovs_patch (interface);
+ 	if (s_ovs_patch) {
+@@ -494,7 +495,11 @@ _insert_port (json_t *params, NMConnection *port, json_t *new_interfaces)
+  * Returns an commands that adds new bridge from a given connection.
+  */
+ static void
+-_insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, json_t *new_ports)
++_insert_bridge (json_t *params,
++                NMConnection *bridge,
++                NMDevice *bridge_device,
++                json_t *new_ports,
++                const char *cloned_mac)
+ {
+ 	NMSettingOvsBridge *s_ovs_bridge;
+ 	const char *fail_mode = NULL;
+@@ -502,23 +507,9 @@ _insert_bridge (json_t *params, NMConnection *bridge, NMDevice *bridge_device, j
+ 	gboolean rstp_enable = FALSE;
+ 	gboolean stp_enable = FALSE;
+ 	json_t *row;
+-	gs_free_error GError *error = NULL;
+-	gs_free char *cloned_mac = NULL;
+ 
+ 	s_ovs_bridge = nm_connection_get_setting_ovs_bridge (bridge);
+ 
+-	if (!nm_device_hw_addr_get_cloned (bridge_device,
+-	                                   bridge,
+-	                                   FALSE,
+-	                                   &cloned_mac,
+-	                                   NULL,
+-	                                   &error)) {
+-		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
+-		       "bridge",
+-		       nm_connection_get_interface_name (bridge),
+-		       error->message);
+-	}
+-
+ 	row = json_object ();
+ 
+ 	if (s_ovs_bridge) {
+@@ -586,6 +577,9 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 	const char *bridge_uuid;
+ 	const char *port_uuid;
+ 	const char *interface_uuid;
++	const char *bridge_name;
++	const char *port_name;
++	const char *interface_name;
+ 	OpenvswitchBridge *ovs_bridge = NULL;
+ 	OpenvswitchPort *ovs_port = NULL;
+ 	OpenvswitchInterface *ovs_interface = NULL;
+@@ -596,6 +590,10 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 	nm_auto_decref_json json_t *interfaces = NULL;
+ 	nm_auto_decref_json json_t *new_interfaces = NULL;
+ 	gboolean has_interface = FALSE;
++	gboolean interface_is_internal;
++	gs_free char *bridge_cloned_mac = NULL;
++	gs_free char *interface_cloned_mac = NULL;
++	GError *error = NULL;
+ 	int pi;
+ 	int ii;
+ 
+@@ -606,11 +604,51 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 	new_ports = json_array ();
+ 	new_interfaces = json_array ();
+ 
++	bridge_name = nm_connection_get_interface_name (bridge);
++	port_name = nm_connection_get_interface_name (port);
++	interface_name = nm_connection_get_interface_name (interface);
++	interface_is_internal = nm_streq0 (bridge_name, interface_name);
++
++	/* Determine cloned MAC addresses */
++	if (!nm_device_hw_addr_get_cloned (bridge_device,
++	                                   bridge,
++	                                   FALSE,
++	                                   &bridge_cloned_mac,
++	                                   NULL,
++	                                   &error)) {
++		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
++		       "bridge",
++		       bridge_name,
++		       error->message);
++		g_clear_error (&error);
++	}
++
++	if (!nm_device_hw_addr_get_cloned (interface_device,
++	                                   interface,
++	                                   FALSE,
++	                                   &interface_cloned_mac,
++	                                   NULL,
++	                                   &error)) {
++		_LOGW ("Cannot determine cloned mac for OVS %s '%s': %s",
++		       "interface",
++		       interface_name,
++		       error->message);
++		g_clear_error (&error);
++	}
++
++	if (   interface_is_internal
++	    && !bridge_cloned_mac
++	    && interface_cloned_mac) {
++		_LOGT ("'%s' is a local ovs-interface, the MAC will be set on ovs-bridge '%s'",
++		       interface_name, bridge_name);
++		bridge_cloned_mac = g_steal_pointer (&interface_cloned_mac);
++	}
++
+ 	g_hash_table_iter_init (&iter, priv->bridges);
+ 	while (g_hash_table_iter_next (&iter, (gpointer) &bridge_uuid, (gpointer) &ovs_bridge)) {
+ 		json_array_append_new (bridges, json_pack ("[s, s]", "uuid", bridge_uuid));
+ 
+-		if (   g_strcmp0 (ovs_bridge->name, nm_connection_get_interface_name (bridge)) != 0
++		if (   g_strcmp0 (ovs_bridge->name, bridge_name) != 0
+ 		    || g_strcmp0 (ovs_bridge->connection_uuid, nm_connection_get_uuid (bridge)) != 0)
+ 			continue;
+ 
+@@ -624,7 +662,7 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 				/* This would be a violation of ovsdb's reference integrity (a bug). */
+ 				_LOGW ("Unknown port '%s' in bridge '%s'", port_uuid, bridge_uuid);
+ 				continue;
+-			} else if (   strcmp (ovs_port->name, nm_connection_get_interface_name (port)) != 0
++			} else if (   strcmp (ovs_port->name, port_name) != 0
+ 			           || g_strcmp0 (ovs_port->connection_uuid, nm_connection_get_uuid (port)) != 0) {
+ 				continue;
+ 			}
+@@ -638,7 +676,7 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 				if (!ovs_interface) {
+ 					/* This would be a violation of ovsdb's reference integrity (a bug). */
+ 					_LOGW ("Unknown interface '%s' in port '%s'", interface_uuid, port_uuid);
+-				} else if (   strcmp (ovs_interface->name, nm_connection_get_interface_name (interface)) == 0
++				} else if (   strcmp (ovs_interface->name, interface_name) == 0
+ 				           && g_strcmp0 (ovs_interface->connection_uuid, nm_connection_get_uuid (interface)) == 0) {
+ 					has_interface = TRUE;
+ 				}
+@@ -661,12 +699,14 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 			_expect_ovs_bridges (params, priv->db_uuid, bridges);
+ 			json_array_append_new (new_bridges, json_pack ("[s, s]", "named-uuid", "rowBridge"));
+ 			_set_ovs_bridges (params, priv->db_uuid, new_bridges);
+-			_insert_bridge (params, bridge, bridge_device, new_ports);
++			_insert_bridge (params, bridge, bridge_device, new_ports, bridge_cloned_mac);
+ 		} else {
+ 			/* Bridge already exists. */
+ 			g_return_if_fail (ovs_bridge);
+ 			_expect_bridge_ports (params, ovs_bridge->name, ports);
+-			_set_bridge_ports (params, nm_connection_get_interface_name (bridge), new_ports);
++			_set_bridge_ports (params, bridge_name, new_ports);
++			if (bridge_cloned_mac && interface_is_internal)
++				_set_bridge_mac (params, bridge_name, bridge_cloned_mac);
+ 		}
+ 
+ 		json_array_append_new (new_ports, json_pack ("[s, s]", "named-uuid", "rowPort"));
+@@ -675,11 +715,11 @@ _add_interface (NMOvsdb *self, json_t *params,
+ 		/* Port already exists */
+ 		g_return_if_fail (ovs_port);
+ 		_expect_port_interfaces (params, ovs_port->name, interfaces);
+-		_set_port_interfaces (params, nm_connection_get_interface_name (port), new_interfaces);
++		_set_port_interfaces (params, port_name, new_interfaces);
+ 	}
+ 
+ 	if (!has_interface) {
+-		_insert_interface (params, interface, interface_device);
++		_insert_interface (params, interface, interface_device, interface_cloned_mac);
+ 		json_array_append_new (new_interfaces, json_pack ("[s, s]", "named-uuid", "rowInterface"));
+ 	}
+ }
+-- 
+2.26.2
+
+
+From c31781abf41bc3be2f81d3a164522ae17251a9d5 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Wed, 1 Jul 2020 09:01:10 +0200
+Subject: [PATCH 22/25] ovs: also set cloned MAC address via netlink
+
+We already set the MAC of OVS interfaces in the ovsdb. Unfortunately,
+vswitchd doesn't create the interface with the given MAC from the
+beginning, but first creates it with a random MAC and then changes it.
+
+This causes a race condition: as soon as NM sees the new link, it
+starts IP configuration on it and (possibly later) vswitchd will
+change the MAC.
+
+To avoid this, also set the desired MAC via netlink before starting IP
+configuration.
+
+https://bugzilla.redhat.com/show_bug.cgi?id=1852106
+https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/483
+(cherry picked from commit 47ec3d14d49eb9e9db956b3efd495d5d696da996)
+(cherry picked from commit 60d10b146d57290f146536705d744e67925de90e)
+(cherry picked from commit 01399955906aa1b1e52998e8daf487b30fa6eb81)
+(cherry picked from commit 69c5c5e7670e8199829df308316d055be049c978)
+(cherry picked from commit 91d2b0fd5ae4960420da0321dd1b11f8333f7d4d)
+(cherry picked from commit 037ff2870842e7aa4d2d763134015a8e9abb6327)
+---
+ src/devices/ovs/nm-device-ovs-interface.c | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/src/devices/ovs/nm-device-ovs-interface.c b/src/devices/ovs/nm-device-ovs-interface.c
+index f2919b488190..5d103c16fec9 100644
+--- a/src/devices/ovs/nm-device-ovs-interface.c
++++ b/src/devices/ovs/nm-device-ovs-interface.c
+@@ -117,6 +117,14 @@ link_changed (NMDevice *device,
+ 	priv->waiting_for_interface = FALSE;
+ 
+ 	if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) {
++		if (!nm_device_hw_addr_set_cloned (device,
++		                                   nm_device_get_applied_connection (device),
++		                                   FALSE)) {
++			nm_device_state_changed (device,
++			                         NM_DEVICE_STATE_FAILED,
++			                         NM_DEVICE_STATE_REASON_CONFIG_FAILED);
++			return;
++		}
+ 		nm_device_bring_up (device, TRUE, NULL);
+ 		nm_device_activate_schedule_stage3_ip_config_start (device);
+ 	}
+@@ -189,6 +197,13 @@ act_stage3_ip_config_start (NMDevice *device,
+ 		return NM_ACT_STAGE_RETURN_POSTPONE;
+ 	}
+ 
++	if (!nm_device_hw_addr_set_cloned (device,
++	                                   nm_device_get_applied_connection (device),
++	                                   FALSE)) {
++		*out_failure_reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
++		return NM_ACT_STAGE_RETURN_FAILURE;
++	}
++
+ 	return NM_DEVICE_CLASS (nm_device_ovs_interface_parent_class)->act_stage3_ip_config_start (device, addr_family, out_config, out_failure_reason);
+ }
+ 
+-- 
+2.26.2
+
+
+From b7a6efed8e5c35527f9a4d9ccb4e871202e9dbd6 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Thu, 2 Jul 2020 13:47:22 +0200
+Subject: [PATCH 23/25] device: don't reset the MAC without ifindex
+
+nm_device_cleanup() can be called when the device no longer has an
+ifindex. In such case, don't try to reset the MAC address as that
+would lead to an assertion failure.
+
+(cherry picked from commit 77b6ce7d04f6c88e78fb7f1972549956e00e1f4b)
+(cherry picked from commit 791a888cad3d260675781c0ed30acf13cc1194f7)
+(cherry picked from commit e1f76e70447049487b2d8240ce12007624ab3c29)
+(cherry picked from commit 5f22c06c53d9ae9003cd17603d6d6ff3e16f195b)
+(cherry picked from commit 6beaa83d32d4c2784771b114725c34056f7083bf)
+(cherry picked from commit baf91970b3954eb229cb8c980295ef273b0a2b31)
+---
+ src/devices/nm-device.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
+index c2eb815b3b3a..346b8e743299 100644
+--- a/src/devices/nm-device.c
++++ b/src/devices/nm-device.c
+@@ -14649,17 +14649,19 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
+ 
+ 	nm_device_update_metered (self);
+ 
+-	/* during device cleanup, we want to reset the MAC address of the device
+-	 * to the initial state.
+-	 *
+-	 * We certainly want to do that when reaching the UNMANAGED state... */
+-	if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED)
+-		nm_device_hw_addr_reset (self, "unmanage");
+-	else {
+-		/* for other device states (UNAVAILABLE, DISCONNECTED), allow the
+-		 * device to overwrite the reset behavior, so that Wi-Fi can set
+-		 * a randomized MAC address used during scanning. */
+-		NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self);
++	if (ifindex > 0) {
++		/* during device cleanup, we want to reset the MAC address of the device
++		 * to the initial state.
++		 *
++		 * We certainly want to do that when reaching the UNMANAGED state... */
++		if (nm_device_get_state (self) <= NM_DEVICE_STATE_UNMANAGED)
++			nm_device_hw_addr_reset (self, "unmanage");
++		else {
++			/* for other device states (UNAVAILABLE, DISCONNECTED), allow the
++			 * device to overwrite the reset behavior, so that Wi-Fi can set
++			 * a randomized MAC address used during scanning. */
++			NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self);
++		}
+ 	}
+ 
+ 	priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE;
+-- 
+2.26.2
+
+
+From 4a4ad9bbd9393b3ef21911ea801d14d3d157dc08 Mon Sep 17 00:00:00 2001
+From: Beniamino Galvani <bgalvani@redhat.com>
+Date: Tue, 9 Jun 2020 10:36:03 +0200
+Subject: [PATCH 24/25] libnm-core: interpret ovs-patch.peer as an interface
+ name
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+The 'peer' property of ovs-patch is inserted into the 'options' column
+of the ovsdb 'Interface' table. The ovs-vswitchd.conf.db man page says
+about it:
+
+  options : peer: optional string
+    The name of the Interface for the other side of the patch. The
+    named Interface’s own peer option must specify this Interface’s
+    name. That is, the two patch interfaces must have reversed name
+    and peer values.
+
+Therefore, it is wrong to validate the peer property as an IP address
+and document it as such.
+
+Backport: note that on nm-1-22, we have nm_utils_ifname_valid() function
+for validating OVS interface names. We don't have that here, so we
+re-implement the name validation differently.
+
+Fixes: d4a7fe46797b ('libnm-core: add ovs-patch setting')
+(cherry picked from commit beb1dba8c145be0971a488dcabac241e1c3a363b)
+(cherry picked from commit 5598c039e4557510b567f12418601f5983fe5357)
+(cherry picked from commit 9b82c62f33d53192cd89ae9c62f67ddad2c2df1f)
+(cherry picked from commit 87e79d214e45cee4e19455724ebf5485149dd6cf)
+(cherry picked from commit 3b51a05187250ee62a1f9379058f138f95c97529)
+---
+ clients/common/settings-docs.h.in |  2 +-
+ libnm-core/nm-setting-ovs-patch.c | 28 +++++++++++++++++++---------
+ 2 files changed, 20 insertions(+), 10 deletions(-)
+
+diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
+index a571d2f697a8..111e324d043f 100644
+--- a/clients/common/settings-docs.h.in
++++ b/clients/common/settings-docs.h.in
+@@ -260,7 +260,7 @@
+ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.")
+-#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote Open vSwitch bridge port to connect to.")
++#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_MODE N_("Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\".")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_UPDELAY N_("The time port must be active before it starts forwarding traffic.")
+diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c
+index 2a46810c3290..6a320b7e61fc 100644
+--- a/libnm-core/nm-setting-ovs-patch.c
++++ b/libnm-core/nm-setting-ovs-patch.c
+@@ -96,13 +96,23 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
+ 		return FALSE;
+ 	}
+ 
+-	if (   !nm_utils_ipaddr_valid (AF_INET, self->peer)
+-	    && !nm_utils_ipaddr_valid (AF_INET6, self->peer)) {
+-		g_set_error (error,
+-		             NM_CONNECTION_ERROR,
+-		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+-		             _("'%s' is not a valid IP address"),
+-		             self->peer);
++	if (!nm_utils_is_valid_iface_name (self->peer, error)) {
++		g_prefix_error (error, "%s.%s: ",
++		                NM_SETTING_OVS_PATCH_SETTING_NAME,
++		                NM_SETTING_OVS_PATCH_PEER);
++		return FALSE;
++	}
++
++	/* on nm-1-22, we use here nm_utils_ifname_valid(). This change was not backported to
++	 * nm-1-20, hence reimplement the check here. We don't want to accept values, that
++	 * would be rejected on newer versions of NetworkManager. */
++	if (!NM_STRCHAR_ALL (self->peer,
++	                     ch,
++	                        !NM_IN_SET (ch, '\\', '/')
++	                     && g_ascii_isgraph (ch))) {
++		g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
++		                     _("interface name must be alphanumerical with "
++		                     "no forward or backward slashes"));
+ 		g_prefix_error (error, "%s.%s: ",
+ 		                NM_SETTING_OVS_PATCH_SETTING_NAME,
+ 		                NM_SETTING_OVS_PATCH_PEER);
+@@ -194,8 +204,8 @@ nm_setting_ovs_patch_class_init (NMSettingOvsPatchClass *klass)
+ 	/**
+ 	 * NMSettingOvsPatch:peer:
+ 	 *
+-	 * Specifies the unicast destination IP address of a remote Open vSwitch
+-	 * bridge port to connect to.
++	 * Specifies the name of the interface for the other side of the patch.
++	 * The patch on the other side must also set this interface as peer.
+ 	 *
+ 	 * Since: 1.10
+ 	 **/
+-- 
+2.26.2
+
+
+From b2be7659d79856e7b60e71b4ea13e4834c1e5b11 Mon Sep 17 00:00:00 2001
+From: Thomas Haller <thaller@redhat.com>
+Date: Wed, 30 Sep 2020 10:36:11 +0200
+Subject: [PATCH 25/25] libnm: revert changes to translated strings for
+ ovs-patch (rhel-7.9-only)
+
+For rhel-7.9, we don't want to change translated strings. Revert that
+part from upstream in this downstream-only patch.
+---
+ clients/common/settings-docs.h.in | 2 +-
+ libnm-core/nm-setting-ovs-patch.c | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
+index 111e324d043f..a571d2f697a8 100644
+--- a/clients/common/settings-docs.h.in
++++ b/clients/common/settings-docs.h.in
+@@ -260,7 +260,7 @@
+ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_RSTP_ENABLE N_("Enable or disable RSTP.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_BRIDGE_STP_ENABLE N_("Enable or disable STP.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_INTERFACE_TYPE N_("The interface type. Either \"internal\", or empty.")
+-#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the name of the interface for the other side of the patch. The patch on the other side must also set this interface as peer.")
++#define DESCRIBE_DOC_NM_SETTING_OVS_PATCH_PEER N_("Specifies the unicast destination IP address of a remote Open vSwitch bridge port to connect to.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_DOWNDELAY N_("The time port must be inactive in order to be considered down.")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_MODE N_("Bonding mode. One of \"active-backup\", \"balance-slb\", or \"balance-tcp\".")
+ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_UPDELAY N_("The time port must be active before it starts forwarding traffic.")
+diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c
+index 6a320b7e61fc..613a4c1da859 100644
+--- a/libnm-core/nm-setting-ovs-patch.c
++++ b/libnm-core/nm-setting-ovs-patch.c
+@@ -204,8 +204,8 @@ nm_setting_ovs_patch_class_init (NMSettingOvsPatchClass *klass)
+ 	/**
+ 	 * NMSettingOvsPatch:peer:
+ 	 *
+-	 * Specifies the name of the interface for the other side of the patch.
+-	 * The patch on the other side must also set this interface as peer.
++	 * Specifies the unicast destination IP address of a remote Open vSwitch
++	 * bridge port to connect to.
+ 	 *
+ 	 * Since: 1.10
+ 	 **/
+-- 
+2.26.2
+
diff --git a/SPECS/NetworkManager.spec b/SPECS/NetworkManager.spec
index b96a5a0..ebaa2a9 100644
--- a/SPECS/NetworkManager.spec
+++ b/SPECS/NetworkManager.spec
@@ -8,7 +8,7 @@
 %global epoch_version 1
 %global rpm_version 1.18.8
 %global real_version 1.18.8
-%global release_version 1
+%global release_version 2
 %global snapshot %{nil}
 %global git_sha %{nil}
 
@@ -160,6 +160,7 @@ Patch6: 0006-no-keyfile-file-name-extension-rh1697858.patch
 # Bugfixes
 # Patch1000: 1000-subject-rh#.patch
 Patch1000: 1000-po-RHEL-7.9-translations.patch
+Patch1001: 1001-ovs-fixes-rh1852106-rh1820052.patch
 
 # The pregenerated docs contain default values and paths that depend
 # on the configure options when creating the source tarball.
@@ -1097,6 +1098,11 @@ fi
 
 
 %changelog
+* Wed Sep 30 2020 Thomas Haller <thaller@redhat.com> - 1:1.18.8-2
+- Backport OVS related fixes (rh #1871935)
+- ovs: support changing the MTU of ovs interfaces (rh #1820052)
+- ovs: fix race condition in setting MAC address (rh #1852106)
+
 * Fri May 29 2020 Thomas Haller <thaller@redhat.com> - 1:1.18.8-1
 - Update to 1.18.8 relase
 - ifcfg-rh: handle "802-1x.{,phase2-}ca-path" (rh #1841397, CVE-2020-10754)