Blob Blame History Raw
From fb2f233d5156a3516b309336a310570c368c7a89 Mon Sep 17 00:00:00 2001
From: Miguel Duarte Barroso <mdbarroso@redhat.com>
Date: Thu, 22 Aug 2019 10:39:10 +0200
Subject: [PATCH] nm.applier: Prioritize master interfaces activaction

The master interfaces - that are not slaves themselves - must be
activated first, otherwise NetworkManager fails with errors such
as:

"""
NetworkManager[858]: <debug>
[1565960861.2223] manager: Activation of <slave> requires master
device <master device>
"""

The supplied test fails roughly >= 50% of the times without this
patch - it all comes to the timing.

Signed-off-by: Miguel Duarte Barroso <mdbarroso@redhat.com>
Signed-off-by: Gris Ge <fge@redhat.com>
---
 libnmstate/nm/applier.py               | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/libnmstate/nm/applier.py b/libnmstate/nm/applier.py
index 750ca3d..974460b 100644
--- a/libnmstate/nm/applier.py
+++ b/libnmstate/nm/applier.py
@@ -41,6 +41,7 @@ from . import wired
 
 MASTER_METADATA = '_master'
 MASTER_TYPE_METADATA = '_master_type'
+MASTER_IFACE_TYPES = ovs.BRIDGE_TYPE, bond.BOND_TYPE, LB.TYPE
 
 BRPORT_OPTIONS_METADATA = '_brport_options'
 
@@ -111,6 +112,7 @@ def set_ifaces_admin_state(ifaces_desired_state, con_profiles=()):
     leaving it to choose the correct profile.
 
     In order to activate correctly the interfaces, the order is significant:
+    - Master-less master interfaces.
     - New interfaces (virtual interfaces, but not OVS ones).
     - Master interfaces.
     - OVS ports.
@@ -123,6 +125,7 @@ def set_ifaces_admin_state(ifaces_desired_state, con_profiles=()):
     new_vlan_ifaces_to_activate = set()
     new_ovs_interface_to_activate = set()
     new_ovs_port_to_activate = set()
+    new_master_not_enslaved_ifaces = set()
     master_ifaces_to_edit = set()
     ifaces_to_edit = set()
     remove_devs_actions = {}
@@ -132,7 +135,13 @@ def set_ifaces_admin_state(ifaces_desired_state, con_profiles=()):
         nmdev = device.get_device_by_name(ifname)
         if not nmdev:
             if ifname in new_ifaces and iface_desired_state['state'] == 'up':
-                if iface_desired_state['type'] == ovs.INTERNAL_INTERFACE_TYPE:
+                if _is_master_iface(
+                    iface_desired_state
+                ) and not _is_slave_iface(iface_desired_state):
+                    new_master_not_enslaved_ifaces.add(ifname)
+                elif (
+                    iface_desired_state['type'] == ovs.INTERNAL_INTERFACE_TYPE
+                ):
                     new_ovs_interface_to_activate.add(ifname)
                 elif iface_desired_state['type'] == ovs.PORT_TYPE:
                     new_ovs_port_to_activate.add(ifname)
@@ -142,8 +151,7 @@ def set_ifaces_admin_state(ifaces_desired_state, con_profiles=()):
                     new_ifaces_to_activate.add(ifname)
         else:
             if iface_desired_state['state'] == 'up':
-                master_iface_types = ovs.BRIDGE_TYPE, bond.BOND_TYPE, LB.TYPE
-                if iface_desired_state['type'] in master_iface_types:
+                if _is_master_iface(iface_desired_state):
                     master_ifaces_to_edit.add(
                         (nmdev, con_profiles_by_devname[ifname].profile)
                     )
@@ -176,6 +184,9 @@ def set_ifaces_admin_state(ifaces_desired_state, con_profiles=()):
     for dev, _ in itertools.chain(master_ifaces_to_edit, ifaces_to_edit):
         remove_devs_actions.pop(dev, None)
 
+    for ifname in new_master_not_enslaved_ifaces:
+        device.activate(dev=None, connection_id=ifname)
+
     for ifname in new_ifaces_to_activate:
         device.activate(dev=None, connection_id=ifname)
 
@@ -213,6 +224,14 @@ def _get_new_ifaces(con_profiles):
     return ifaces_without_device
 
 
+def _is_master_iface(iface_state):
+    return iface_state[Interface.TYPE] in MASTER_IFACE_TYPES
+
+
+def _is_slave_iface(iface_state):
+    return iface_state.get(MASTER_METADATA)
+
+
 def _get_affected_devices(iface_state):
     nmdev = device.get_device_by_name(iface_state['name'])
     devs = []
-- 
2.23.0