Change in vdsm[master]: net: during boot, restore only networks that were actually c...

ibarkan at redhat.com ibarkan at redhat.com
Mon Jun 15 08:31:36 UTC 2015


Ido Barkan has uploaded a new change for review.

Change subject: net: during boot, restore only networks that were actually changed.
......................................................................

net: during boot, restore only networks that were actually changed.

This is an optimization that will shorten boot time when there are many networks. If also, all persisted networks will be persisted with onboot=true, then in most case, all the hard of restorattion will be done by network service and vdsm will only interfere to fix the changed networks and bonds.

Change-Id: I66307a7cf6b0f7269a1ae04aa7c1748dde768144
Signed-off-by: Ido Barkan <ibarkan at redhat.com>
---
M lib/vdsm/netconfpersistence.py
M tests/functional/networkTests.py
M vdsm/vdsm-restore-net-config
3 files changed, 146 insertions(+), 22 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/55/42355/1

diff --git a/lib/vdsm/netconfpersistence.py b/lib/vdsm/netconfpersistence.py
index 9df9117..340de9d 100644
--- a/lib/vdsm/netconfpersistence.py
+++ b/lib/vdsm/netconfpersistence.py
@@ -196,7 +196,7 @@
             self.setBonding(bond, bond_attr)
 
     def __eq__(self, other):
-        normalized_other = self._normalize(other)
+        normalized_other = self.normalize(other)
         return (self.networks == normalized_other.networks
                 and self.bonds == normalized_other.bonds)
 
@@ -273,7 +273,7 @@
         }
         return _unicodize(attributes)
 
-    def _normalize(self, running_config):
+    def normalize(self, running_config):
         config_copy = copy.deepcopy(running_config)
 
         self._normalize_bridge(config_copy)
diff --git a/tests/functional/networkTests.py b/tests/functional/networkTests.py
index 906bc74..e04489b 100644
--- a/tests/functional/networkTests.py
+++ b/tests/functional/networkTests.py
@@ -29,8 +29,8 @@
 from vdsm.constants import EXT_BRCTL, EXT_IFUP, EXT_IFDOWN
 from vdsm import ipwrapper
 from vdsm.ipwrapper import (routeExists, ruleExists, addrFlush, LinkType,
-                            getLinks, routeShowTable)
-from vdsm.netconfpersistence import KernelConfig
+                            getLinks, routeShowTable, linkDel, linkSet)
+from vdsm.netconfpersistence import KernelConfig, RunningConfig
 from vdsm.netinfo import (bridges, operstate, getRouteDeviceTo,
                           _get_dhclient_ifaces, BONDING_SLAVES,
                           BONDING_MASTERS, NET_CONF_PREF)
@@ -196,7 +196,7 @@
         return wrapper
 
     def assertNetworkExists(self, networkName, bridged=None, bridgeOpts=None,
-                            hostQos=None):
+                            hostQos=None, assert_in_running_conf=True):
         netinfo = self.vdsm_net.netinfo
         config = self.vdsm_net.config
         self.assertIn(networkName, netinfo.networks)
@@ -214,7 +214,7 @@
             reported_qos = netinfo.networks[networkName]['hostQos']
             _cleanup_qos_definition(reported_qos)
             self.assertEqual(reported_qos, hostQos)
-        if config is not None:
+        if assert_in_running_conf and config is not None:
             self.assertIn(networkName, config.networks)
             if bridged is not None:
                 self.assertEqual(config.networks[networkName].get('bridged'),
@@ -235,14 +235,15 @@
         netinfo = self.vdsm_net.netinfo
         self.assertNotIn(bridgeName, netinfo.bridges)
 
-    def assertBondExists(self, bondName, nics=None, options=None):
+    def assertBondExists(self, bondName, nics=None, options=None,
+                         assert_in_running_conf=True):
         netinfo = self.vdsm_net.netinfo
         config = self.vdsm_net.config
         self.assertIn(bondName, netinfo.bondings)
         if nics is not None:
             self.assertEqual(set(nics),
                              set(netinfo.bondings[bondName]['slaves']))
-        if config is not None:
+        if assert_in_running_conf and config is not None:
             self.assertIn(bondName, config.bonds)
             self.assertEqual(set(nics),
                              set(config.bonds[bondName].get('nics')))
@@ -1464,6 +1465,88 @@
             self.assertEquals(status, SUCCESS, msg)
 
     @cleanupNet
+    def testRestoreNetworksOnlyRestoreUnchangedDevices(self):
+        BOND_UNCHANGED = 'bond100'
+        BOND_MISSING = 'bond102'
+        IP_ADD_UNCHANGED = '240.0.0.100'
+        VLAN_UNCHAGED = 100
+        NET_UNCHANGED = NETWORK_NAME + '100'
+        NET_CHANGED = NETWORK_NAME + '101'
+        NET_MISSING = NETWORK_NAME + '102'
+        IP_ADDR_NET_CHANGED = '240.0.0.101'
+        IP_ADDR_MISSING = '204.0.0.102'
+        nets = {
+            NET_UNCHANGED:
+                {'bootproto': 'none', 'ipaddr': IP_ADD_UNCHANGED,
+                 'vlan': str(VLAN_UNCHAGED), 'netmask': IP_MASK,
+                 'bonding': BOND_UNCHANGED},
+            NET_CHANGED:
+                {'bootproto': 'none',
+                 'ipaddr': IP_ADDR_NET_CHANGED,
+                 'vlan': str(VLAN_UNCHAGED + 1),
+                 'netmask': IP_MASK, 'bonding': BOND_UNCHANGED},
+            NET_MISSING:
+                {'bootproto': 'none',
+                 'ipaddr': IP_ADDR_MISSING,
+                 'vlan': str(VLAN_UNCHAGED + 2),
+                 'netmask': IP_MASK, 'bonding': BOND_MISSING},
+        }
+
+        def _assert_all_nets_exist(in_running_conf=True):
+            self.vdsm_net.refreshNetinfo()
+            self.assertNetworkExists(
+                NET_UNCHANGED, assert_in_running_conf=in_running_conf)
+            self.assertNetworkExists(
+                NET_CHANGED, assert_in_running_conf=in_running_conf)
+            self.assertNetworkExists(
+                NET_MISSING, assert_in_running_conf=in_running_conf)
+            self.assertBondExists(
+                BOND_UNCHANGED, [nic_a],
+                assert_in_running_conf=in_running_conf)
+            self.assertBondExists(
+                BOND_MISSING, [nic_b],
+                assert_in_running_conf=in_running_conf)
+
+        with dummyIf(2) as nics:
+            try:
+                nic_a, nic_b = nics
+                bonds = {BOND_UNCHANGED: {'nics': [nic_a]},
+                         BOND_MISSING: {'nics': [nic_b]}
+                         }
+                status, msg = self.setupNetworks(nets, bonds, NOCHK)
+                self.assertEquals(status, SUCCESS, msg)
+                _assert_all_nets_exist()
+
+                self.vdsm_net.save_config()
+
+                addrFlush(NET_CHANGED)
+                linkSet(NET_MISSING, ['down'])
+                execCmd([EXT_BRCTL, 'delbr', NET_MISSING])
+                linkDel(BOND_MISSING)
+                self.vdsm_net.refreshNetinfo()
+                self.assertNotEqual(
+                    self.vdsm_net.netinfo.networks[NET_CHANGED]['addr'],
+                    IP_ADDR_NET_CHANGED
+                )
+                self.assertNotIn(NET_MISSING, self.vdsm_net.netinfo.networks)
+                self.assertNotIn(BOND_MISSING, self.vdsm_net.netinfo.bondings)
+
+                RunningConfig().delete()
+                with nonChangingOperstate(NET_UNCHANGED):
+                    self.vdsm_net.restoreNetConfig()
+
+                _assert_all_nets_exist(False)
+            finally:
+                self.setupNetworks(
+                    {NET_UNCHANGED: {'remove': True},
+                     NET_CHANGED: {'remove': True},
+                     NET_MISSING: {'remove': True}},
+                    {BOND_MISSING: {'remove': True},
+                     BOND_UNCHANGED: {'remove': True}},
+                    NOCHK)
+                self.vdsm_net.save_config()
+
+    @cleanupNet
     @permutations([[True], [False]])
     def testVolatileConfig(self, bridged):
         """
diff --git a/vdsm/vdsm-restore-net-config b/vdsm/vdsm-restore-net-config
index e6010ad..33e2c23 100755
--- a/vdsm/vdsm-restore-net-config
+++ b/vdsm/vdsm-restore-net-config
@@ -29,7 +29,7 @@
 from vdsm import netinfo
 from vdsm.constants import P_VDSM_RUN
 from vdsm.netconfpersistence import RunningConfig, PersistentConfig, \
-    CONF_PERSIST_DIR
+    KernelConfig, CONF_PERSIST_DIR, BaseConfig
 import hostdev
 
 # Ifcfg persistence restoration
@@ -101,13 +101,11 @@
     """
     _remove_networks_in_running_config()
 
-    _flush_configurators_leftovers()
+    # _flush_configurators_leftovers()
 
     _restore_non_vdsm_net_devices()
 
-    persistentConfig = PersistentConfig()
-    nets, bonds = _filter_nets_bonds(persistentConfig.networks,
-                                     persistentConfig.bonds)
+    nets, bonds = _filter_nets_bonds()
     if nets or bonds:
         _convert_to_blocking_dhcp(nets)
         logging.debug('Calling setupNetworks with networks (%s) '
@@ -161,18 +159,61 @@
             net_attr['blockingdhcp'] = True
 
 
-def _filter_nets_bonds(persisted_nets, persisted_bonds):
-    """Returns only nets and bonds that can be configured with the devices
-    present in the system"""
+def _filter_nets_bonds():
+    """First, only consider bonds and network that were untouched. Then
+    filter out nets and bonds that cannot be configured because their devices
+    are not present in the system.
+    Second, filter out the networks which were unchanged since last time they
+    were persisted"""
+    persistent_config = PersistentConfig()
+
     available_nics = netinfo.nics()
     available_bonds = _find_bonds_with_available_nics(available_nics,
-                                                      persisted_bonds)
+                                                      persistent_config.bonds)
 
-    available_nets = _find_nets_with_available_devices(available_bonds,
-                                                       available_nics,
-                                                       persisted_bonds,
-                                                       persisted_nets)
-    return available_nets, available_bonds
+    available_nets = _find_nets_with_available_devices(
+        available_bonds, available_nics, persistent_config.bonds,
+        persistent_config.networks)
+
+    changed_persisted_bonds, changed_persisted_nets = _filter_non_changed(
+        BaseConfig(available_nets, available_bonds))
+
+    return changed_persisted_nets, changed_persisted_bonds
+
+
+def _filter_non_changed(persistent_config):
+    """Create a KernelConfig instance that holds the current network kernel
+    state. Then normalize the PersistentConfig instance so it would be
+    comparable to a KernelConfig. We would like to restore only those networks
+    and bonds which were changed since the last time they were persisted."""
+    kernel_config = KernelConfig(netinfo.NetInfo())
+    normalized_config = kernel_config.normalize(persistent_config)
+
+    changed_bonds_names = _find_changed_or_missing(normalized_config.bonds,
+                                                   kernel_config.bonds)
+    changed_nets_names = _find_changed_or_missing(normalized_config.networks,
+                                                  kernel_config.networks)
+    changed_nets = dict((net, persistent_config.networks[net])
+                        for net in changed_nets_names)
+    changed_bonds = dict((bond, persistent_config.bonds[bond])
+                         for bond in changed_bonds_names)
+
+    return changed_bonds, changed_nets
+
+
+def _find_changed_or_missing(persisted, current):
+    changed_or_missing = []
+    for name, persisted_attrs in persisted.iteritems():
+        current_attrs = current.get(name)
+        if current_attrs != persisted_attrs:
+            logging.info("%s is different or missing from persistent "
+                         "configuration. current: %s, persisted: %s",
+                         name, current_attrs, persisted_attrs)
+            changed_or_missing.append(name)
+        else:
+            logging.info("%s was not changed since last time it was persisted,"
+                         " skipping restoration.", name)
+    return changed_or_missing
 
 
 def _find_nets_with_available_devices(available_bonds,  available_nics,


-- 
To view, visit https://gerrit.ovirt.org/42355
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I66307a7cf6b0f7269a1ae04aa7c1748dde768144
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Ido Barkan <ibarkan at redhat.com>


More information about the vdsm-patches mailing list