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 <[email protected]>
---
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 <[email protected]>
_______________________________________________
vdsm-patches mailing list
[email protected]
https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches

Reply via email to