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)
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)
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)
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)
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
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)
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), )
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
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))
def listNetworks(): _netinfo = NetInfo() print "Networks:", _netinfo.networks.keys() print "Vlans:", _netinfo.vlans.keys() print "Nics:", _netinfo.nics.keys() print "Bondings:", _netinfo.bondings.keys()
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)