aboutsummaryrefslogtreecommitdiffstats
path: root/tools/python/xen/xend/server/netif.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/python/xen/xend/server/netif.py')
-rwxr-xr-xtools/python/xen/xend/server/netif.py316
1 files changed, 316 insertions, 0 deletions
diff --git a/tools/python/xen/xend/server/netif.py b/tools/python/xen/xend/server/netif.py
new file mode 100755
index 0000000000..2b01805be6
--- /dev/null
+++ b/tools/python/xen/xend/server/netif.py
@@ -0,0 +1,316 @@
+import random
+
+from twisted.internet import defer
+
+from xen.xend import sxp
+from xen.xend import PrettyPrint
+from xen.xend import Vifctl
+
+import channel
+import controller
+from messages import *
+
+class NetifControllerFactory(controller.ControllerFactory):
+ """Factory for creating network interface controllers.
+ Also handles the 'back-end' channel to the device driver domain.
+ """
+
+ def __init__(self):
+ controller.ControllerFactory.__init__(self)
+
+ self.majorTypes = [ CMSG_NETIF_BE ]
+
+ self.subTypes = {
+ CMSG_NETIF_BE_CREATE : self.recv_be_create,
+ CMSG_NETIF_BE_CONNECT: self.recv_be_connect,
+ CMSG_NETIF_BE_DRIVER_STATUS_CHANGED: self.recv_be_driver_status_changed,
+ }
+ self.attached = 1
+ self.registerChannel()
+
+ def createInstance(self, dom, recreate=0):
+ """Create or find the network interface controller for a domain.
+ """
+ #print 'netif>createInstance> dom=', dom
+ netif = self.getInstanceByDom(dom)
+ if netif is None:
+ netif = NetifController(self, dom)
+ self.addInstance(netif)
+ return netif
+
+ def getDomainDevices(self, dom):
+ netif = self.getInstanceByDom(dom)
+ return (netif and netif.getDevices()) or []
+
+ def getDomainDevice(self, dom, vif):
+ netif = self.getInstanceByDom(dom)
+ return (netif and netif.getDevice(vif)) or None
+
+ def setControlDomain(self, dom, recreate=0):
+ """Set the 'back-end' device driver domain.
+ """
+ if self.dom == dom: return
+ self.deregisterChannel()
+ if not recreate:
+ self.attached = 0
+ self.dom = dom
+ self.registerChannel()
+ #
+ #if xend.netif.be_port.remote_dom != 0:
+ # xend.netif.recovery = True
+ # xend.netif.be_port = xend.main.port_from_dom(dom)
+ #
+
+ def getControlDomain(self):
+ return self.dom
+
+ def recv_be_create(self, msg, req):
+ self.callDeferred(0)
+
+ def recv_be_connect(self, msg, req):
+ val = unpackMsg('netif_be_connect_t', msg)
+ dom = val['domid']
+ vif = val['netif_handle']
+ netif = self.getInstanceByDom(dom)
+ if netif:
+ netif.send_interface_connected(vif)
+ else:
+ print "recv_be_connect> unknown vif=", vif
+ pass
+
+ def recv_be_driver_status_changed(self, msg, req):
+ val = unpackMsg('netif_be_driver_status_changed_t', msg)
+ status = val['status']
+ if status == NETIF_DRIVER_STATUS_UP and not self.attached:
+ # If we are not attached the driver domain was changed, and
+ # this signals the new driver domain is ready.
+ for netif in self.getInstances():
+ netif.reattach_devices()
+ self.attached = 1
+
+## pl = msg.get_payload()
+## status = pl['status']
+## if status == NETIF_DRIVER_STATUS_UP:
+## if xend.netif.recovery:
+## print "New netif backend now UP, notifying guests:"
+## for netif_key in interface.list.keys():
+## netif = interface.list[netif_key]
+## netif.create()
+## print " Notifying %d" % netif.dom
+## msg = xu.message(
+## CMSG_NETIF_FE,
+## CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, 0,
+## { 'handle' : 0, 'status' : 1 })
+## netif.ctrlif_tx_req(xend.main.port_from_dom(netif.dom),msg)
+## print "Done notifying guests"
+## recovery = False
+
+class NetDev(controller.Dev):
+ """Info record for a network device.
+ """
+
+ def __init__(self, ctrl, vif, mac):
+ controller.Dev.__init__(self, ctrl)
+ self.vif = vif
+ self.mac = mac
+ self.evtchn = None
+ self.bridge = None
+ self.ipaddr = []
+
+ def sxpr(self):
+ vif = str(self.vif)
+ mac = self.get_mac()
+ val = ['netdev', ['vif', vif], ['mac', mac]]
+ if self.bridge:
+ val.append(['bridge', self.bridge])
+ if self.evtchn:
+ val.append(['evtchn',
+ self.evtchn['port1'],
+ self.evtchn['port2']])
+ return val
+
+ def get_vifname(self):
+ return "vif%d.%d" % (self.controller.dom, self.vif)
+
+ def get_mac(self):
+ return ':'.join(map(lambda x: "%x" % x, self.mac))
+
+ def vifctl_params(self):
+ return { 'mac' : self.get_mac(),
+ 'bridge': self.bridge,
+ 'ipaddr': self.ipaddr }
+
+ def up(self, bridge=None, ipaddr=[]):
+ self.bridge = bridge
+ self.ipaddr = ipaddr
+ Vifctl.up(self.get_vifname(), **self.vifctl_params())
+
+ def down(self):
+ Vifctl.down(self.get_vifname(), **self.vifctl_params())
+
+ def destroy(self):
+ def cb_destroy(val):
+ self.controller.send_be_destroy(self.vif)
+ print 'NetDev>destroy>', 'vif=', self.vif
+ PrettyPrint.prettyprint(self.sxpr())
+ self.down()
+ d = self.controller.factory.addDeferred()
+ d.addCallback(cb_destroy)
+ self.controller.send_be_disconnect(self.vif)
+ #self.controller.send_be_destroy(self.vif)
+
+
+class NetifController(controller.Controller):
+ """Network interface controller. Handles all network devices for a domain.
+ """
+
+ def __init__(self, factory, dom):
+ #print 'NetifController> dom=', dom
+ controller.Controller.__init__(self, factory, dom)
+ self.devices = {}
+
+ self.majorTypes = [ CMSG_NETIF_FE ]
+
+ self.subTypes = {
+ CMSG_NETIF_FE_DRIVER_STATUS_CHANGED:
+ self.recv_fe_driver_status_changed,
+ CMSG_NETIF_FE_INTERFACE_CONNECT :
+ self.recv_fe_interface_connect,
+ }
+ self.registerChannel()
+ #print 'NetifController<', 'dom=', self.dom, 'idx=', self.idx
+
+ def sxpr(self):
+ val = ['netif', ['dom', self.dom]]
+ return val
+
+ def randomMAC(self):
+ # VIFs get a random MAC address with a "special" vendor id.
+ #
+ # NB. The vendor is currently an "obsolete" one that used to belong
+ # to DEC (AA-00-00). Using it is probably a bit rude :-)
+ #
+ # NB2. The first bit of the first random octet is set to zero for
+ # all dynamic MAC addresses. This may allow us to manually specify
+ # MAC addresses for some VIFs with no fear of clashes.
+ mac = [ 0xaa, 0x00, 0x00,
+ random.randint(0x00, 0x7f),
+ random.randint(0x00, 0xff),
+ random.randint(0x00, 0xff) ]
+ return mac
+
+ def lostChannel(self):
+ print 'NetifController>lostChannel>', 'dom=', self.dom
+ #self.destroyDevices()
+ controller.Controller.lostChannel(self)
+
+ def getDevices(self):
+ return self.devices.values()
+
+ def getDevice(self, vif):
+ return self.devices.get(vif)
+
+ def addDevice(self, vif, vmac):
+ if vmac is None:
+ mac = self.randomMAC()
+ else:
+ mac = [ int(x, 16) for x in vmac.split(':') ]
+ if len(mac) != 6: raise ValueError("invalid mac")
+ #print "attach_device>", "vif=", vif, "mac=", mac
+ dev = NetDev(self, vif, mac)
+ self.devices[vif] = dev
+ return dev
+
+ def destroy(self):
+ print 'NetifController>destroy>', 'dom=', self.dom
+ self.destroyDevices()
+
+ def destroyDevices(self):
+ for dev in self.getDevices():
+ dev.destroy()
+
+ def attachDevice(self, vif, vmac, recreate=0):
+ """Attach a network device.
+ If vmac is None a random mac address is assigned.
+
+ @param vif interface index
+ @param vmac mac address (string)
+ """
+ self.addDevice(vif, vmac)
+ if recreate:
+ d = defer.Deferred()
+ d.callback(self)
+ else:
+ d = self.factory.addDeferred()
+ self.send_be_create(vif)
+ return d
+
+ def reattach_devices(self):
+ """Reattach all devices when the back-end control domain has changed.
+ """
+ d = self.factory.addDeferred()
+ self.send_be_create(vif)
+ self.attach_fe_devices(0)
+
+ def attach_fe_devices(self):
+ for dev in self.devices.values():
+ msg = packMsg('netif_fe_interface_status_changed_t',
+ { 'handle' : dev.vif,
+ 'status' : NETIF_INTERFACE_STATUS_DISCONNECTED,
+ 'evtchn' : 0,
+ 'mac' : dev.mac })
+ self.writeRequest(msg)
+
+ def recv_fe_driver_status_changed(self, msg, req):
+ if not req: return
+ msg = packMsg('netif_fe_driver_status_changed_t',
+ { 'status' : NETIF_DRIVER_STATUS_UP,
+ 'nr_interfaces' : len(self.devices) })
+ self.writeRequest(msg)
+ self.attach_fe_devices()
+
+ def recv_fe_interface_connect(self, msg, req):
+ val = unpackMsg('netif_fe_interface_connect_t', msg)
+ dev = self.devices[val['handle']]
+ dev.evtchn = channel.eventChannel(0, self.dom)
+ msg = packMsg('netif_be_connect_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif,
+ 'evtchn' : dev.evtchn['port1'],
+ 'tx_shmem_frame' : val['tx_shmem_frame'],
+ 'rx_shmem_frame' : val['rx_shmem_frame'] })
+ self.factory.writeRequest(msg)
+
+ def send_interface_connected(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_fe_interface_status_changed_t',
+ { 'handle' : dev.vif,
+ 'status' : NETIF_INTERFACE_STATUS_CONNECTED,
+ 'evtchn' : dev.evtchn['port2'],
+ 'mac' : dev.mac })
+ self.writeRequest(msg)
+
+ def send_be_create(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_be_create_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif,
+ 'mac' : dev.mac })
+ self.factory.writeRequest(msg)
+
+ def send_be_disconnect(self, vif):
+ dev = self.devices[vif]
+ msg = packMsg('netif_be_disconnect_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : dev.vif })
+ self.factory.writeRequest(msg)
+
+ def send_be_destroy(self, vif):
+ print 'NetifController>send_be_destroy>', 'dom=', self.dom, 'vif=', vif
+ PrettyPrint.prettyprint(self.sxpr())
+ dev = self.devices[vif]
+ del self.devices[vif]
+ msg = packMsg('netif_be_destroy_t',
+ { 'domid' : self.dom,
+ 'netif_handle' : vif })
+ self.factory.writeRequest(msg)