Mark Wu has uploaded a new change for review.
Change subject: WIP: Add netcf support ......................................................................
WIP: Add netcf support
Change-Id: I0070ea45de9d75570168410913a0aef62bcd940a Signed-off-by: Mark Wu wudxw@linux.vnet.ibm.com --- M vdsm/configNetwork.py 1 file changed, 314 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/18/8618/1
diff --git a/vdsm/configNetwork.py b/vdsm/configNetwork.py index 0f6de37..abf4e1f 100755 --- a/vdsm/configNetwork.py +++ b/vdsm/configNetwork.py @@ -26,6 +26,7 @@ import time import logging import threading +import xml.dom.minidom from xml.sax.saxutils import escape import glob import shutil @@ -1299,6 +1300,319 @@ raise
+class Netcf(object): + + def __init__(self): + self.doc = xml.dom.minidom.Document() + self.conn = libvirtconnection.get() + + def addIfaceType(self, ifaceType, name): + interface = self.doc.createElement('interface') + interface.setAttribute('type', ifaceType) + interface.setAttribute('name', name) + return interface + + def addTopIfaceAttrs(self, topIface, ipaddr=None, netmask=None, + gateway=None, mtu=None, dhcp=False, onboot=True): + + def toNetmaskBits(netmask): + num = int(''.join('%02x' % int(i) for i in netmask.split('.')), 16) + bits = 32 + while num / 2 != 0: + if num % 2 == 0: + bits -= 1 + num /= 2 + return bits + + firstChild = topIface.firstChild + + if onboot: + start = self.doc.createElement('start') + start.setAttribute('mode', 'onboot') + topIface.insertBefore(start, firstChild) + + if mtu != None: + mtuChild = self.doc.createElement('mtu') + mtuChild.setAttribute('size', str(mtu)) + topIface.insertBefore(mtuChild, firstChild) + + protocol = self.doc.createElement('protocol') + protocol.setAttribute('family', "ipv4") + if ipaddr: + ip = self.doc.createElement('ip') + ip.setAttribute('address', (pipes.quote(ipaddr))) + prefix = str(toNetmaskBits(pipes.quote(netmask))) + ip.setAttribute('prefix', prefix) + protocol.appendChild(ip) + if gateway: + route = self.doc.createElement('route') + route.setAttribute('gateway', (pipes.quote(gateway))) + protocol.appendChild(ip) + elif dhcp: + dhcp = self.doc.createElement('dhcp') + protocol.appendChild(dhcp) + topIface.insertBefore(protocol, firstChild) + return topIface + + def addBridge(self, name, port, ipaddr=None, netmask=None, mtu=None, + gateway=None, bootproto=None, delay='0', onboot='yes', **kwargs): + """ + <interface type="bridge" name="br0"> + <start mode="onboot"/> + <mtu size="1500"/> + <protocol family="ipv4"> + <ip address="192.168.0.5" prefix="24"/> + <route gateway="192.168.0.1"/> + </protocol> + <bridge stp="off" delay="0.01"> + <interface type="ethernet" name="eth0"> + <mac address="ab:bb:cc:dd:ee:ff"/> + </interface> + <interface type="ethernet" name="eth1"/> + </bridge> + </interface> + """ + + brIface = self.addIfaceType('bridge', pipes.quote(name)) + self.addTopIfaceAttrs(brIface, ipaddr, netmask, mtu, gateway) + bridge = self.doc.createElement('bridge') + bridge.setAttribute('delay', pipes.quote(delay)) + # fix me need send a patch to allow set 'NM_CONTROLLED=no\n' + bridge.appendChild(port) + brIface.appendChild(bridge) + return brIface + + """ + <start mode="onboot"/> + <protocol family="ipv4"> + <dhcp peerdns="no"/> + </protocol> + """ + def addBareVlan(self, vlanId, iface): + """ + <interface type="vlan" name="eth0.42"> + <vlan tag="42"> + <interface name="eth0"/> + </vlan> + </interface> + """ + ifaceName = iface.getAttribute('name') + vlanIface = self.addIfaceType("vlan", ifaceName + '.' + vlanId) + vlanDev = self.doc.createElement("vlan") + vlanDev.setAttribute("tag", vlanId) + nicIface = self.doc.createElement("interface") + nicIface.setAttribute("name", ifaceName) + vlanDev.appendChild(nicIface) + vlanIface.appendChild(vlanDev) + return vlanIface + + def addBareBonding(self, bonding, slaves, bondingOptions=None): + """ + <interface type="bond" name="bond0"> + <bond mode="active-backup"> + <arpmon interval="10" target="192.168.122.1"/> + <interface type="ethernet" name="eth0"> + <mac address="ab:bb:cc:dd:ee:ff"/> + </interface> + <interface type="ethernet" name="eth1"/> + </bond> + </interface> + """ + bondIface = self.addIfaceType("bond", bonding) + bond = self.doc.createElement('bond') + # Todo: parse bonding options + # the default options is bondingOptions = 'mode=802.3ad miimon=150' + bond.setAttribute('mode', "802.3ad") + for slave in slaves: + bond.appendChild(slave) + bondIface.appendChild(bond) + return bondIface + + def addBareNic(self, nic): + """ + <interface type="ethernet" name="eth0"> + <mac address="ab:bb:cc:dd:ee:ff"/> + </interface> + """ + _netinfo = netinfo.NetInfo() + hwaddr = _netinfo.nics[nic].get('permhwaddr') or \ + _netinfo.nics[nic]['hwaddr'] + + nicIface = self.addIfaceType('ethernet', nic) + mac = self.doc.createElement('mac') + mac.setAttribute('address', hwaddr) + nicIface.appendChild(mac) + return nicIface + + def netcfDefineIface(self, xmlstr): + try: + self.conn.interfaceDefineXML(xmlstr, 0) + except: + logging.error('Failed to define interface', exc_info=True) + + def netcfCreateIface(self, ifaceName): + iface = self.conn.interfaceLookupByName(ifaceName) + iface.create(0) + + def netcfUndefineIface(self, ifaceName): + iface = self.conn.interfaceLookupByName(ifaceName) + if iface.isActive(): + iface.destroy(0) + #Todo implement configuration rollback + #self.conn.changeBegin(0) + iface.undefine() + + #self.conn.changeCommit(0) + #self.conn.changeRollback(0) + + def _createNetwork(self, netXml): + conn = libvirtconnection.get() + net = conn.networkDefineXML(netXml) + net.create() + net.setAutostart(1) + + def createLibvirtNetwork(self, network, bridged=True, iface=None, + skipBackup=False): + netName = netinfo.LIBVIRT_NET_PREFIX + network + if bridged: + netXml = '''<network><name>%s</name><forward mode='bridge'/> + <bridge name='%s'/></network>''' % (escape(netName), + escape(network)) + else: + netXml = '''<network><name>%s</name><forward mode='passthrough'> + <interface dev='%s'/></forward></network>''' % \ + (escape(netName), escape(iface)) + if not skipBackup: + self._networkBackup(network) + self._createNetwork(netXml) + + def _removeNetwork(self, network): + netName = netinfo.LIBVIRT_NET_PREFIX + network + conn = libvirtconnection.get() + + net = conn.networkLookupByName(netName) + if net.isActive(): + net.destroy() + if net.isPersistent(): + net.undefine() + + def removeLibvirtNetwork(self, network, skipBackup=False): + if not skipBackup: + self._networkBackup(network) + self._removeNetwork(network) + + def _networkBackup(self, network): + """Not impolemented now""" + + pass + + +class NetcfConfigurator(): + + def __init__(self): + self.configWriter = Netcf() + + def addNetwork(self, network, vlan=None, bonding=None, nics=None, + ipaddr=None, netmask=None, mtu=None, gateway=None, + force=False, configWriter=None, bondingOptions=None, + bridged=True, **options): + nics = nics or () + _netinfo = netinfo.NetInfo() + bridged = utils.tobool(bridged) + + if mtu: + mtu = int(mtu) + + # Validation + if not utils.tobool(force): + logging.debug('validating network...') + _addNetworkValidation(_netinfo, network=network, + vlan=vlan, bonding=bonding, nics=nics, ipaddr=ipaddr, + netmask=netmask, gateway=gateway, + bondingOptions=bondingOptions, bridged=bridged, **options) + + logging.info("Adding network %s with vlan=%s, bonding=%s, nics=%s," + " bondingOptions=%s, mtu=%s, bridged=%s, options=%s", + network, vlan, bonding, nics, bondingOptions, + mtu, bridged, options) + + # Todo, consider mtu support for multiple vlans + + nic = nics[0] if nics else None + iface = bonding or nic + + # 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) + + if bridged: + ifdown(network) + + slaves = [] + for nic in nics: + topIface = self.configWriter.addBareNic(nic) + slaves.append(topIface) + if bonding: + topIface = self.configWriter.addBareBonding(bonding, slaves, + bondingOptions) + if vlan: + # netcf doesn't allow create the underlying device together with + # vlan. So create the underlying device before vlan. + topIface = self.configWriter.addTopIfaceAttrs(topIface) + topIfaceXml = topIface.toprettyxml(encoding='utf-8') + self.configWriter.netcfDefineIface(topIfaceXml) + topIface = self.configWriter.addBareVlan(vlan, topIface) + if bridged: + topIface = self.configWriter.addBridge( + network, port=topIface, ipaddr=ipaddr, netmask=netmask, + mtu=mtu, gateway=gateway, **options) + else: + topIface = self.configWriter.addTopIfaceAttrs( + topIface, ipaddr=ipaddr, netmask=netmask, mtu=mtu, + gateway=gateway) + + self.configWriter.netcfDefineIface( + topIface.toprettyxml(encoding='utf-8')) + + # Todo consider dhcp block issue + ifaceName = topIface.getAttribute('name') + self.configWriter.netcfCreateIface(ifaceName) + # add libvirt network + self.configWriter.createLibvirtNetwork(network, bridged, iface) + + def delNetworkNetcf(self, network, vlan=None, bonding=None, nics=None, + force=False, configWriter=None, implicitBonding=True, + **options): + _netinfo = netinfo.NetInfo() + + if network not in _netinfo.networks: + logging.info("Network %r: doesn't exist in libvirt database", + network) + if network in netinfo.bridges(): + self.configWriter.removeBridge(network) + else: + raise ConfigNetworkError(ne.ERR_BAD_BRIDGE, + "Cannot delete network %r: It doesn't exist " + "in the system" % network) + + if vlan: + self.configWriter.removeVlan(vlan, bonding or nics[0]) + + return + + self.configWriter.removeLibvirtNetwork(network, log=False) + # We need to gather NetInfo again to refresh networks info from + # libvirt. The deleted bridge should never be up at this stage. + if network in netinfo.NetInfo().networks: + raise ConfigNetworkError(ne.ERR_USED_BRIDGE, + "delNetwork: bridge %s still exists" % network) + + self.configWriter.netcfUndefineIface(network) + + configurator = NativeConfigurator()
-- To view, visit http://gerrit.ovirt.org/8618 To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange Gerrit-Change-Id: I0070ea45de9d75570168410913a0aef62bcd940a Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Mark Wu wudxw@linux.vnet.ibm.com