Exemple #1
0
def showNetwork(bridge):
    _netinfo = NetInfo()
    if bridge not in _netinfo.networks:
        print "Bridge %r doesn't exist" % bridge
        return

    nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(bridge)
    print "Bridge %s: vlan=%s, bonding=%s, nics=%s" % (bridge, vlan, bonding, nics)
Exemple #2
0
def showNetwork(bridge):
    _netinfo = NetInfo()
    if bridge not in _netinfo.networks:
        print "Bridge %r doesn't exist" % bridge
        return

    nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(bridge)
    print "Bridge %s: vlan=%s, bonding=%s, nics=%s" % (bridge, vlan, bonding,
                                                       nics)
Exemple #3
0
def delNetwork(bridge, force=False, configWriter=None, **options):
    _netinfo = NetInfo()

    validateBridgeName(bridge)
    if bridge not in _netinfo.networks:
        raise ConfigNetworkError(
            ne.ERR_BAD_BRIDGE,
            "Cannot delete bridge %r: It doesn't exist" % bridge)

    nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(bridge)

    logging.info(
        "Removing bridge %s with vlan=%s, bonding=%s, nics=%s. options=%s" %
        (bridge, vlan, bonding, nics, options))

    if not _isTrue(force):
        if bonding:
            validateBondingName(bonding)
            if set(nics) != set(_netinfo.bondings[bonding]["slaves"]):
                raise ConfigNetworkError(
                    ne.ERR_BAD_NIC,
                    'delNetwork: %s are not all nics enslaved to %s' %
                    (nics, bonding))
        if vlan:
            #assertVlan(vlan)
            validateVlanId(vlan)
        assertBridgeClean(bridge, vlan, bonding, nics)

    if configWriter is None:
        configWriter = ConfigWriter()

    if bridge:
        ifdown(bridge)
        subprocess.call([constants.EXT_BRCTL, 'delbr', bridge])
    if vlan:
        vlandev = (bonding or nics[0]) + '.' + vlan
        ifdown(vlandev)
        subprocess.call([constants.EXT_VCONFIG, 'rem', vlandev],
                        stderr=subprocess.PIPE)
    if bonding:
        if not bondingOtherUsers(bridge, vlan, bonding):
            ifdown(bonding)
    for nic in nics:
        if not nicOtherUsers(bridge, vlan, bonding, nic):
            ifdown(nic)
    for nic in nics:
        if nicOtherUsers(bridge, vlan, bonding, nic):
            continue

        configWriter.removeNic(nic)
    if bonding:
        if not bondingOtherUsers(bridge, vlan, bonding):
            configWriter.removeBonding(bonding)
    if vlan:
        configWriter.removeVlan(vlan, bonding or nics[0])
    if bridge:
        configWriter.removeBridge(bridge)
Exemple #4
0
def delNetwork(bridge, force=False, configWriter=None, **options):
    _netinfo = NetInfo()

    validateBridgeName(bridge)
    if bridge not in _netinfo.networks:
        raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, "Cannot delete bridge %r: It doesn't exist" % bridge)

    nics, vlan, bonding = _netinfo.getNicsVlanAndBondingForNetwork(bridge)

    logging.info(
        "Removing bridge %s with vlan=%s, bonding=%s, nics=%s. options=%s" % (bridge, vlan, bonding, nics, options)
    )

    if not _isTrue(force):
        if bonding:
            validateBondingName(bonding)
            if set(nics) != set(_netinfo.bondings[bonding]["slaves"]):
                raise ConfigNetworkError(
                    ne.ERR_BAD_NIC, "delNetwork: %s are not all nics enslaved to %s" % (nics, bonding)
                )
        if vlan:
            # assertVlan(vlan)
            validateVlanId(vlan)
        assertBridgeClean(bridge, vlan, bonding, nics)

    if configWriter is None:
        configWriter = ConfigWriter()

    if bridge:
        ifdown(bridge)
        subprocess.call([constants.EXT_BRCTL, "delbr", bridge])
    if vlan:
        vlandev = (bonding or nics[0]) + "." + vlan
        ifdown(vlandev)
        subprocess.call([constants.EXT_VCONFIG, "rem", vlandev], stderr=subprocess.PIPE)
    if bonding:
        if not bondingOtherUsers(bridge, vlan, bonding):
            ifdown(bonding)
    for nic in nics:
        if not nicOtherUsers(bridge, vlan, bonding, nic):
            ifdown(nic)
    for nic in nics:
        if nicOtherUsers(bridge, vlan, bonding, nic):
            continue

        configWriter.removeNic(nic)
    if bonding:
        if not bondingOtherUsers(bridge, vlan, bonding):
            configWriter.removeBonding(bonding)
    if vlan:
        configWriter.removeVlan(vlan, bonding or nics[0])
    if bridge:
        configWriter.removeBridge(bridge)
Exemple #5
0
 def removeBridge(self, bridge):
     self._backup(self.NET_CONF_PREF + bridge)
     self._removeFile(self.NET_CONF_PREF + bridge)
     # the deleted bridge should never be up at this stage.
     if bridge in NetInfo().networks:
         raise ConfigNetworkError(
             ne.ERR_USED_BRIDGE,
             'delNetwork: bridge %s still exists' % bridge)
Exemple #6
0
def ifaceUsers(iface):
    "Returns a list of entities using the interface"
    _netinfo = NetInfo()
    users = set()
    for b, bdict in _netinfo.networks.iteritems():
        if iface in bdict['ports']:
            users.add(b)
    for b, bdict in _netinfo.bondings.iteritems():
        if iface in bdict['slaves']:
            users.add(b)
    for v, vdict in _netinfo.vlans.iteritems():
        if iface == vdict['iface']:
            users.add(v)
    return users
Exemple #7
0
 def addNic(self, nic, bonding=None, bridge=None):
     "Based on addNetwork"
     conffile = self.NET_CONF_PREF + nic
     self._backup(conffile)
     _netinfo = NetInfo()
     hwaddr = _netinfo.nics[nic].get('permhwaddr') or \
              _netinfo.nics[nic]['hwaddr']
     with open(conffile, 'w') as f:
         f.write('DEVICE=%s\nONBOOT=yes\nBOOTPROTO=none\nHWADDR=%s\n' %
                 (pipes.quote(nic), pipes.quote(hwaddr)))
         if bridge:
             f.write('BRIDGE=%s\n' % pipes.quote(bridge))
         if bonding:
             f.write('MASTER=%s\n' % pipes.quote(bonding))
             f.write('SLAVE=yes\n')
     os.chmod(conffile, 0664)
Exemple #8
0
def _validateNetworkSetup(networks={}, bondings={}, explicitBonding=False):
    _netinfo = NetInfo()

    # Step 1: Initial validation (validate names, existence of params, etc.)
    for network, networkAttrs in networks.iteritems():
        validateBridgeName(network)

        if networkAttrs.get("remove", False):
            if set(networkAttrs) - set(["remove"]):
                raise ConfigNetworkError(ne.ERR_BAD_PARAMS, "Cannot specify any attribute when removing")
            if network not in _netinfo.networks:
                raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, "Cannot remove bridge %s: Doesn't exist" % network)
            continue

        vlan = networkAttrs.get("vlan", None)
        ipaddr = networkAttrs.get("ipaddr", None)
        netmask = networkAttrs.get("netmask", None)
        gateway = networkAttrs.get("gateway", None)
        if vlan:
            validateVlanId(vlan)

        # Check ip, netmask, gateway
        if ipaddr:
            if not netmask:
                raise ConfigNetworkError(ne.ERR_BAD_ADDR, "Must specify netmask to configure ip for bridge")
            validateIpAddress(ipaddr)
            validateNetmask(netmask)
            if gateway:
                validateGateway(gateway)
        else:
            if netmask or gateway:
                raise ConfigNetworkError(ne.ERR_BAD_ADDR, "Specified netmask or gateway but not ip")

        # check nic or bonding
        nic = networkAttrs.get("nic", None)
        bonding = networkAttrs.get("bonding", None)

        if nic and bonding:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS, "Don't specify both nic and bonding")
        if not nic and not bonding:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS, "Must specify either nic or bonding")

        if nic and nic not in _netinfo.nics:
            raise ConfigNetworkError(ne.ERR_BAD_NIC, "unknown nic: %r" % nic)

    for bonding, bondingAttrs in bondings.iteritems():
        validateBondingName(bonding)
        if "options" in bondingAttrs:
            validateBondingOptions(bonding, bondingAttrs["options"])

        if bondingAttrs.get("remove", False):
            if bonding not in _netinfo.bondings:
                raise ConfigNetworkError(ne.ERR_BAD_BONDING, "Cannot remove bonding %s: Doesn't exist" % bonding)
            continue

        nics = bondingAttrs.get("nics", None)
        if not nics:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS, "Must specify nics for bonding")
        if not set(nics).issubset(set(_netinfo.nics)):
            raise ConfigNetworkError(ne.ERR_BAD_NIC, "Unknown nics in: %r" % list(nics))

    # Step 2: Make sure we have complete information about the Setup, more validation
    # (if explicitBonding==False we complete the missing information ourselves, else we raise an exception)
    nics = defaultdict(lambda: {"networks": [], "bonding": None})
    for network, networkAttrs in networks.iteritems():
        if networkAttrs.get("remove", False):
            continue

        if "bonding" in networkAttrs:
            assert "nic" not in networkAttrs

            bonding = networkAttrs["bonding"]
            if bonding not in bondings:
                if explicitBonding:
                    raise ConfigNetworkError(
                        ne.ERR_BAD_PARAMS, "Network %s requires unspecified bonding %s" % (network, bonding)
                    )

                # fill in bonding info
                bondings[bonding] = {"nics": _netinfo.bondings[bonding]["slaves"]}

            if "_networks" not in bondings[bonding]:
                bondings[bonding]["_networks"] = []
            bondings[bonding]["_networks"].append(network)
        else:
            assert "nic" in networkAttrs

            nics[networkAttrs["nic"]]["networks"].append(network)

    for bonding, bondingAttrs in bondings.iteritems():
        if bondingAttrs.get("remove", False):
            continue
        connectedNetworks = _netinfo.getNetworksForNic(bonding)

        for network in connectedNetworks:
            if network not in networks:
                if explicitBonding:
                    raise ConfigNetworkError(
                        ne.ERR_BAD_PARAMS, "Bonding %s is associated with unspecified network %s" % (bonding, network)
                    )
                # fill in network info
                _, vlan, bonding2 = _netinfo.getNicsVlanAndBondingForNetwork(network)
                assert bonding == bonding2
                networks[network] = {"bonding": bonding, "vlan": vlan}

        for nic in bondingAttrs["nics"]:
            if nics[nic]["bonding"]:
                raise ConfigNetworkError(
                    ne.ERR_BAD_BONDING,
                    "Nic %s is attached to two different bondings in setup: %s, %s"
                    % (nic, bonding, nics[nic]["bonding"]),
                )
            nics[nic]["bonding"] = bonding

    # At this point the state may be contradictory.

    # Step 3: Apply removals (We're not iterating because we change the dictionary size)
    queue = []
    for network, networkAttrs in networks.items():
        if networkAttrs.get("remove", False):
            del networks[network]
        else:
            queue.append(("network", network, networkAttrs))
    for bonding, bondingAttrs in bondings.items():
        if bondingAttrs.get("remove", False):
            del bondings[bonding]
        else:
            queue.append(("bonding", bonding, bondingAttrs))

    # Step 4: Verify Setup
    for nic, nicAttrs in nics.iteritems():
        if nicAttrs["networks"] and nicAttrs["bonding"]:
            raise ConfigNetworkError(ne.ERR_USED_NIC, "Setup attached both network and bonding to nic %s" % (nic))
        if len(networks) > 1:
            for network, networkAttrs in networks.iteritems():
                if not networkAttrs.get("vlan", None):
                    raise ConfigNetworkError(
                        ne.ERR_USED_NIC,
                        "Setup attached more than one network to nic %s, some of which aren't vlans" % (nic),
                    )

    for bonding, bondingAttrs in bondings.iteritems():
        networks = bondingAttrs["_networks"]
        if len(networks) > 1:
            for network, networkAttrs in networks.iteritems():
                if not networkAttrs.get("vlan", None):
                    raise ConfigNetworkError(
                        ne.ERR_BAD_BONDING,
                        "Setup attached more than one network to bonding %s, some of which aren't vlans" % (bonding),
                    )
Exemple #9
0
def setupNetworks(networks={}, bondings={}, **options):
    """Add/Edit/Remove configuration for networks and bondings.

    Params:
        networks - dict of key=network, value=attributes
                   where 'attributes' is a dict with the following optional items:
                        vlan=<id>
                        bonding="<name>" | nic="<name>"
                        (bonding and nics are mutually exclusive)
                        ipaddr="<ip>"
                        netmask="<ip>"
                        gateway="<ip>"
                        bootproto="..."
                        delay="..."
                        onboot="yes"|"no"
                        (other options will be passed to the config file AS-IS)
                        -- OR --
                        remove=True (other attributes can't be specified)

        bondings - dict of key=bonding, value=attributes
                   where 'attributes' is a dict with the following optional items:
                        nics=["<nic1>" , "<nic2>", ...]
                        options="<bonding-options>"
                        -- OR --
                        remove=True (other attributes can't be specified)

        options - dict of options, such as:
                        force=0|1
                        connectivityCheck=0|1
                        connectivityTimeout=<int>
                        explicitBonding=0|1


    Notes:
        Bondings are removed when they change state from 'used' to 'unused'.

        By default, if you edit a network that is attached to a bonding, it's not
        necessary to re-specify the bonding (you need only to note the attachement
        in the network's attributes). Similarly, if you edit a bonding, it's not
        necessary to specify its networks.
        However, if you specify the 'explicitBonding' option as true, the function
        will expect you to specify all networks that are attached to a specified
        bonding, and vice-versa, the bonding attached to a specified network.

    """
    logger = logging.getLogger("setupNetworks")

    try:
        _netinfo = NetInfo()
        configWriter = ConfigWriter()
        networksAdded = []
        #bondingNetworks = {}   # Reminder TODO

        logger.info("Setting up network")
        logger.debug(
            "Setting up network according to configuration: networks:%r, bondings:%r, options:%r"
            % (networks, bondings, options))

        force = options.get('force', False)
        if not _isTrue(force):
            logging.debug("Validating configuration")
            _validateNetworkSetup(dict(networks),
                                  dict(bondings),
                                  explicitBonding=options.get(
                                      'explicitBonding', False))

        logger.debug("Applying...")
        try:
            for network, networkAttrs in networks.items():
                if networkAttrs.pop('remove', False):
                    assert not networkAttrs

                    logger.debug('Removing network %r' % network)
                    delNetwork(network, force=force)
                    continue

                if network in _netinfo.networks:
                    delNetwork(network, force=force)
                else:
                    networksAdded.append(network)
                d = dict(networkAttrs)
                if 'bonding' in d:
                    d['nics'] = bondings[d['bonding']]['nics']
                    d['bondingOptions'] = bondings[d['bonding']].get(
                        'options', None)
                else:
                    d['nics'] = [d.pop('nic')]
                d['force'] = force

                logger.debug('Adding network %r' % network)
                addNetwork(network, **d)

        except:
            configWriter.restoreAtomicBackup()
            raise
        if utils.tobool(options.get('connectivityCheck', True)):
            logger.debug('Checking connectivity...')
            if not clientSeen(
                    int(
                        options.get('connectivityTimeout',
                                    CONNECTIVITY_TIMEOUT_DEFAULT))):
                logger.info('Connectivity check failed, rolling back')
                for bridge in networksAdded:
                    delNetwork(bridge, force=True)
                configWriter.restoreAtomicBackup()
                raise ConfigNetworkError(ne.ERR_LOST_CONNECTION,
                                         'connectivity check failed')

    except Exception, e:
        # SuperVdsm eats the error, so let's print it ourselves
        logger.error(e, exc_info=True)
        raise
Exemple #10
0
def _validateNetworkSetup(networks={}, bondings={}, explicitBonding=False):
    _netinfo = NetInfo()

    # Step 1: Initial validation (validate names, existence of params, etc.)
    for network, networkAttrs in networks.iteritems():
        validateBridgeName(network)

        if networkAttrs.get('remove', False):
            if set(networkAttrs) - set(['remove']):
                raise ConfigNetworkError(
                    ne.ERR_BAD_PARAMS,
                    "Cannot specify any attribute when removing")
            if network not in _netinfo.networks:
                raise ConfigNetworkError(
                    ne.ERR_BAD_BRIDGE,
                    'Cannot remove bridge %s: Doesn\'t exist' % network)
            continue

        vlan = networkAttrs.get('vlan', None)
        ipaddr = networkAttrs.get('ipaddr', None)
        netmask = networkAttrs.get('netmask', None)
        gateway = networkAttrs.get('gateway', None)
        if vlan:
            validateVlanId(vlan)

        # Check ip, netmask, gateway
        if ipaddr:
            if not netmask:
                raise ConfigNetworkError(
                    ne.ERR_BAD_ADDR,
                    "Must specify netmask to configure ip for bridge")
            validateIpAddress(ipaddr)
            validateNetmask(netmask)
            if gateway:
                validateGateway(gateway)
        else:
            if netmask or gateway:
                raise ConfigNetworkError(
                    ne.ERR_BAD_ADDR, "Specified netmask or gateway but not ip")

        # check nic or bonding
        nic = networkAttrs.get('nic', None)
        bonding = networkAttrs.get('bonding', None)

        if nic and bonding:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS,
                                     "Don't specify both nic and bonding")
        if not nic and not bonding:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS,
                                     "Must specify either nic or bonding")

        if nic and nic not in _netinfo.nics:
            raise ConfigNetworkError(ne.ERR_BAD_NIC, "unknown nic: %r" % nic)

    for bonding, bondingAttrs in bondings.iteritems():
        validateBondingName(bonding)
        if 'options' in bondingAttrs:
            validateBondingOptions(bonding, bondingAttrs['options'])

        if bondingAttrs.get('remove', False):
            if bonding not in _netinfo.bondings:
                raise ConfigNetworkError(
                    ne.ERR_BAD_BONDING,
                    'Cannot remove bonding %s: Doesn\'t exist' % bonding)
            continue

        nics = bondingAttrs.get('nics', None)
        if not nics:
            raise ConfigNetworkError(ne.ERR_BAD_PARAMS,
                                     "Must specify nics for bonding")
        if not set(nics).issubset(set(_netinfo.nics)):
            raise ConfigNetworkError(ne.ERR_BAD_NIC,
                                     "Unknown nics in: %r" % list(nics))

    # Step 2: Make sure we have complete information about the Setup, more validation
    # (if explicitBonding==False we complete the missing information ourselves, else we raise an exception)
    nics = defaultdict(lambda: {'networks': [], 'bonding': None})
    for network, networkAttrs in networks.iteritems():
        if networkAttrs.get('remove', False):
            continue

        if 'bonding' in networkAttrs:
            assert 'nic' not in networkAttrs

            bonding = networkAttrs['bonding']
            if bonding not in bondings:
                if explicitBonding:
                    raise ConfigNetworkError(
                        ne.ERR_BAD_PARAMS,
                        "Network %s requires unspecified bonding %s" %
                        (network, bonding))

                # fill in bonding info
                bondings[bonding] = {
                    'nics': _netinfo.bondings[bonding]['slaves']
                }

            if '_networks' not in bondings[bonding]:
                bondings[bonding]['_networks'] = []
            bondings[bonding]['_networks'].append(network)
        else:
            assert 'nic' in networkAttrs

            nics[networkAttrs['nic']]['networks'].append(network)

    for bonding, bondingAttrs in bondings.iteritems():
        if bondingAttrs.get('remove', False):
            continue
        connectedNetworks = _netinfo.getNetworksForNic(bonding)

        for network in connectedNetworks:
            if network not in networks:
                if explicitBonding:
                    raise ConfigNetworkError(
                        ne.ERR_BAD_PARAMS,
                        "Bonding %s is associated with unspecified network %s"
                        % (bonding, network))
                # fill in network info
                _, vlan, bonding2 = _netinfo.getNicsVlanAndBondingForNetwork(
                    network)
                assert bonding == bonding2
                networks[network] = {'bonding': bonding, 'vlan': vlan}

        for nic in bondingAttrs['nics']:
            if nics[nic]['bonding']:
                raise ConfigNetworkError(
                    ne.ERR_BAD_BONDING,
                    "Nic %s is attached to two different bondings in setup: %s, %s"
                    % (nic, bonding, nics[nic]['bonding']))
            nics[nic]['bonding'] = bonding

    # At this point the state may be contradictory.

    # Step 3: Apply removals (We're not iterating because we change the dictionary size)
    queue = []
    for network, networkAttrs in networks.items():
        if networkAttrs.get('remove', False):
            del networks[network]
        else:
            queue.append(('network', network, networkAttrs))
    for bonding, bondingAttrs in bondings.items():
        if bondingAttrs.get('remove', False):
            del bondings[bonding]
        else:
            queue.append(('bonding', bonding, bondingAttrs))

    # Step 4: Verify Setup
    for nic, nicAttrs in nics.iteritems():
        if nicAttrs['networks'] and nicAttrs['bonding']:
            raise ConfigNetworkError(
                ne.ERR_USED_NIC,
                "Setup attached both network and bonding to nic %s" % (nic))
        if len(networks) > 1:
            for network, networkAttrs in networks.iteritems():
                if not networkAttrs.get('vlan', None):
                    raise ConfigNetworkError(
                        ne.ERR_USED_NIC,
                        "Setup attached more than one network to nic %s, some of which aren't vlans"
                        % (nic))

    for bonding, bondingAttrs in bondings.iteritems():
        networks = bondingAttrs['_networks']
        if len(networks) > 1:
            for network, networkAttrs in networks.iteritems():
                if not networkAttrs.get('vlan', None):
                    raise ConfigNetworkError(
                        ne.ERR_BAD_BONDING,
                        "Setup attached more than one network to bonding %s, some of which aren't vlans"
                        % (bonding))
Exemple #11
0
def listNetworks():
    _netinfo = NetInfo()
    print "Networks:", _netinfo.networks.keys()
    print "Vlans:", _netinfo.vlans.keys()
    print "Nics:", _netinfo.nics.keys()
    print "Bondings:", _netinfo.bondings.keys()
Exemple #12
0
def addNetwork(bridge,
               vlan=None,
               bonding=None,
               nics=None,
               ipaddr=None,
               netmask=None,
               gateway=None,
               force=False,
               configWriter=None,
               bondingOptions=None,
               **options):
    nics = nics or ()
    _netinfo = NetInfo()

    # Validation
    if not _isTrue(force):
        logging.debug('validating bridge...')
        _addNetworkValidation(_netinfo,
                              bridge,
                              vlan=vlan,
                              bonding=bonding,
                              nics=nics,
                              ipaddr=ipaddr,
                              netmask=netmask,
                              gateway=gateway,
                              bondingOptions=bondingOptions)
    logging.info(
        "Adding bridge %s with vlan=%s, bonding=%s, nics=%s. bondingOptions=%s, options=%s"
        % (bridge, vlan, bonding, nics, bondingOptions, options))

    if configWriter is None:
        configWriter = ConfigWriter()

    configWriter.addBridge(bridge,
                           ipaddr=ipaddr,
                           netmask=netmask,
                           gateway=gateway,
                           **options)
    ifaceBridge = bridge
    if vlan:
        configWriter.addVlan(vlan, bonding or nics[0], bridge)
        # since we have vlan device, it is connected to the bridge. other
        # interfaces should be connected to the bridge through vlan, and not
        # directly.
        ifaceBridge = None

    if bonding:
        configWriter.addBonding(bonding,
                                ifaceBridge,
                                bondingOptions=bondingOptions)
        for nic in nics:
            configWriter.addNic(nic, bonding=bonding)
    else:
        for nic in nics:
            configWriter.addNic(nic, bridge=ifaceBridge)

    # take down nics that need to be changed
    vlanedIfaces = [v['iface'] for v in _netinfo.vlans.values()]
    if bonding not in vlanedIfaces:
        for nic in nics:
            if nic not in vlanedIfaces:
                ifdown(nic)
    ifdown(bridge)
    # nics must be activated in the same order of boot time to expose the correct
    # MAC address.
    for nic in nicSort(nics):
        ifup(nic)
    if bonding:
        ifup(bonding)
    if vlan:
        ifup((bonding or nics[0]) + '.' + vlan)
    if options.get('bootproto') == 'dhcp' and not utils.tobool(
            options.get('blockingdhcp')):
        # wait for dhcp in another thread, so vdsm won't get stuck (BZ#498940)
        t = threading.Thread(target=ifup,
                             name='ifup-waiting-on-dhcp',
                             args=(bridge, ))
        t.daemon = True
        t.start()
    else:
        ifup(bridge)