mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
g/c unused control message code.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
This commit is contained in:
1 parent
7a36d2e972
commit
78552ee77c
11 files changed
+10
-1599
No files matched your search
@@ -36,7 +36,6 @@ from xen.xend import EventServer; eserver = EventServer.instance()
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend import scheduler
|
||||
from xen.xend.server import channel
|
||||
from xen.xend.server import relocate
|
||||
from xen.xend.uuid import getUuid
|
||||
from xen.xend.xenstore import XenNode, DBMap
|
||||
|
||||
@@ -34,8 +34,7 @@ from xen.util.blkif import blkdev_uname_to_file
|
||||
|
||||
from xen.xend.server import controller
|
||||
from xen.xend.server import SrvDaemon; xend = SrvDaemon.instance()
|
||||
from xen.xend.server import messages
|
||||
from xen.xend.server.channel import EventChannel, channelFactory
|
||||
from xen.xend.server.channel import EventChannel
|
||||
from xen.util.blkif import blkdev_name_to_number, expand_dev_name
|
||||
|
||||
from xen.xend import sxp
|
||||
@@ -258,7 +257,6 @@ class XendDomainInfo:
|
||||
|
||||
self.target = None
|
||||
|
||||
self.channel = None
|
||||
self.store_channel = None
|
||||
self.store_mfn = None
|
||||
self.console_channel = None
|
||||
@@ -296,8 +294,6 @@ class XendDomainInfo:
|
||||
self.db.saveDB(save=save, sync=sync)
|
||||
|
||||
def exportToDB(self, save=False, sync=False):
|
||||
if self.channel:
|
||||
self.channel.saveToDB(self.db.addChild("channel"), save=save)
|
||||
if self.store_channel:
|
||||
self.store_channel.saveToDB(self.db.addChild("store_channel"),
|
||||
save=save)
|
||||
@@ -330,9 +326,6 @@ class XendDomainInfo:
|
||||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def getChannel(self):
|
||||
return self.channel
|
||||
|
||||
def getStoreChannel(self):
|
||||
return self.store_channel
|
||||
|
||||
@@ -569,8 +562,6 @@ class XendDomainInfo:
|
||||
sxpr.append(['up_time', str(up_time) ])
|
||||
sxpr.append(['start_time', str(self.start_time) ])
|
||||
|
||||
if self.channel:
|
||||
sxpr.append(self.channel.sxpr())
|
||||
if self.store_channel:
|
||||
sxpr.append(self.store_channel.sxpr())
|
||||
if self.store_mfn:
|
||||
@@ -761,12 +752,6 @@ class XendDomainInfo:
|
||||
"""
|
||||
self.state = STATE_VM_TERMINATED
|
||||
self.release_devices()
|
||||
if self.channel:
|
||||
try:
|
||||
self.channel.close()
|
||||
self.channel = None
|
||||
except:
|
||||
pass
|
||||
if self.store_channel:
|
||||
try:
|
||||
self.store_channel.close()
|
||||
@@ -858,20 +843,6 @@ class XendDomainInfo:
|
||||
id, self.name, self.memory)
|
||||
self.setdom(id)
|
||||
|
||||
def openChannel(self, key, local, remote):
|
||||
"""Create a control channel to the domain.
|
||||
If saved info is available recreate the channel.
|
||||
|
||||
@param key db key for the saved data (if any)
|
||||
@param local default local port
|
||||
@param remote default remote port
|
||||
"""
|
||||
db = self.db.addChild(key)
|
||||
chan = channelFactory().restoreFromDB(db, self.id, local, remote)
|
||||
#todo: save here?
|
||||
#chan.saveToDB(db)
|
||||
return chan
|
||||
|
||||
def eventChannel(self, key):
|
||||
"""Create an event channel to the domain.
|
||||
If saved info is available recreate the channel.
|
||||
@@ -884,7 +855,6 @@ class XendDomainInfo:
|
||||
def create_channel(self):
|
||||
"""Create the channels to the domain.
|
||||
"""
|
||||
self.channel = self.openChannel("channel", 0, 1)
|
||||
self.store_channel = self.eventChannel("store_channel")
|
||||
self.console_channel = self.eventChannel("console/console_channel")
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ import traceback
|
||||
import time
|
||||
import glob
|
||||
|
||||
from xen.lowlevel import xu
|
||||
|
||||
from xen.xend import sxp
|
||||
from xen.xend import PrettyPrint
|
||||
from xen.xend import EventServer; eserver = EventServer.instance()
|
||||
@@ -27,7 +25,6 @@ from xen.xend.server import SrvServer
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend import XendRoot; xroot = XendRoot.instance()
|
||||
|
||||
import channel
|
||||
import controller
|
||||
import event
|
||||
import relocate
|
||||
@@ -37,7 +34,6 @@ class Daemon:
|
||||
"""The xend daemon.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.channelF = None
|
||||
self.shutdown = 0
|
||||
self.traceon = 0
|
||||
self.tracefile = None
|
||||
@@ -298,10 +294,8 @@ class Daemon:
|
||||
_enforce_dom0_cpus()
|
||||
try:
|
||||
log.info("Xend Daemon started")
|
||||
self.createFactories()
|
||||
event.listenEvent(self)
|
||||
relocate.listenRelocation()
|
||||
self.listenChannels()
|
||||
servers = SrvServer.create()
|
||||
self.daemonize()
|
||||
servers.start()
|
||||
@@ -312,15 +306,7 @@ class Daemon:
|
||||
log.exception("Exception starting xend (%s)" % ex)
|
||||
self.exit(1)
|
||||
|
||||
def createFactories(self):
|
||||
self.channelF = channel.channelFactory()
|
||||
|
||||
def listenChannels(self):
|
||||
self.channelF.start()
|
||||
|
||||
def exit(self, rc=0):
|
||||
if self.channelF:
|
||||
self.channelF.stop()
|
||||
# Calling sys.exit() raises a SystemExit exception, which only
|
||||
# kills the current thread. Calling os._exit() makes the whole
|
||||
# Python process exit immediately. There doesn't seem to be another
|
||||
|
||||
@@ -27,9 +27,7 @@ from xen.xend import sxp
|
||||
from xen.xend import Blkctl
|
||||
from xen.xend.xenstore import DBVar
|
||||
|
||||
from xen.xend.server import channel
|
||||
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
|
||||
from xen.xend.server.messages import *
|
||||
from xen.xend.server.controller import Dev, DevController
|
||||
|
||||
class BlkifBackend:
|
||||
""" Handler for the 'back-end' channel to a block device driver domain
|
||||
@@ -41,21 +39,15 @@ class BlkifBackend:
|
||||
self.controller = controller
|
||||
self.id = id
|
||||
self.frontendDomain = self.controller.getDomain()
|
||||
self.frontendChannel = None
|
||||
self.backendDomain = dom
|
||||
self.backendChannel = None
|
||||
self.destroyed = False
|
||||
self.connected = False
|
||||
self.evtchn = None
|
||||
self.status = None
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
|
||||
self.frontendDomain = self.controller.getDomain()
|
||||
self.frontendChannel = self.controller.getChannel()
|
||||
cf = channel.channelFactory()
|
||||
self.backendChannel = cf.openChannel(self.backendDomain)
|
||||
|
||||
def __str__(self):
|
||||
return ('<BlkifBackend frontend=%d backend=%d id=%d>'
|
||||
@@ -66,29 +58,6 @@ class BlkifBackend:
|
||||
def getId(self):
|
||||
return self.id
|
||||
|
||||
def getEvtchn(self):
|
||||
return self.evtchn
|
||||
|
||||
def closeEvtchn(self):
|
||||
if self.evtchn:
|
||||
channel.eventChannelClose(self.evtchn)
|
||||
self.evtchn = None
|
||||
|
||||
def openEvtchn(self):
|
||||
self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
|
||||
|
||||
def getEventChannelBackend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port1']
|
||||
return val
|
||||
|
||||
def getEventChannelFrontend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port2']
|
||||
return val
|
||||
|
||||
def connect(self, recreate=False):
|
||||
"""Connect to the blkif control interface.
|
||||
|
||||
@@ -98,83 +67,19 @@ class BlkifBackend:
|
||||
if recreate or self.connected:
|
||||
self.connected = True
|
||||
pass
|
||||
else:
|
||||
self.send_be_create()
|
||||
|
||||
def send_be_create(self):
|
||||
log.debug("send_be_create %s", str(self))
|
||||
msg = packMsg('blkif_be_create_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.id })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
self.connected = True
|
||||
|
||||
def destroy(self, change=False, reboot=False):
|
||||
"""Disconnect from the blkif control interface and destroy it.
|
||||
"""
|
||||
self.send_be_disconnect()
|
||||
self.send_be_destroy()
|
||||
self.closeEvtchn()
|
||||
self.destroyed = True
|
||||
# For change true need to notify front-end, or back-end will do it?
|
||||
|
||||
def send_be_disconnect(self):
|
||||
msg = packMsg('blkif_be_disconnect_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.id })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
self.connected = False
|
||||
|
||||
def send_be_destroy(self):
|
||||
msg = packMsg('blkif_be_destroy_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.id })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
|
||||
def connectInterface(self, val):
|
||||
self.openEvtchn()
|
||||
log.debug("Connecting blkif to event channel %s ports=%d:%d",
|
||||
str(self), self.evtchn['port1'], self.evtchn['port2'])
|
||||
msg = packMsg('blkif_be_connect_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.id,
|
||||
'evtchn' : self.getEventChannelBackend(),
|
||||
'shmem_frame' : val['shmem_frame'],
|
||||
'shmem_ref' : val['shmem_ref'] })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
val = unpackMsg('blkif_be_connect_t', msg)
|
||||
self.status = BLKIF_INTERFACE_STATUS_CONNECTED
|
||||
self.send_fe_interface_status()
|
||||
|
||||
def send_fe_interface_status(self):
|
||||
msg = packMsg('blkif_fe_interface_status_t',
|
||||
{ 'handle' : self.id,
|
||||
'status' : self.status,
|
||||
'domid' : self.backendDomain,
|
||||
'evtchn' : self.getEventChannelFrontend() })
|
||||
self.frontendChannel.writeRequest(msg)
|
||||
|
||||
def interfaceDisconnected(self):
|
||||
self.status = BLKIF_INTERFACE_STATUS_DISCONNECTED
|
||||
#todo?: Close evtchn:
|
||||
#self.closeEvtchn()
|
||||
self.send_fe_interface_status()
|
||||
|
||||
def interfaceChanged(self):
|
||||
"""Notify the front-end that devices have been added or removed.
|
||||
The front-end should then probe for devices.
|
||||
"""
|
||||
msg = packMsg('blkif_fe_interface_status_t',
|
||||
{ 'handle' : self.id,
|
||||
'status' : BLKIF_INTERFACE_STATUS_CHANGED,
|
||||
'domid' : self.backendDomain,
|
||||
'evtchn' : 0 })
|
||||
self.frontendChannel.writeRequest(msg)
|
||||
|
||||
class BlkDev(Dev):
|
||||
"""Info record for a block device.
|
||||
"""
|
||||
@@ -207,24 +112,17 @@ class BlkDev(Dev):
|
||||
self.nr_sectors = None
|
||||
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = None
|
||||
self.backendDomain = None
|
||||
self.backendChannel = None
|
||||
self.backendId = 0
|
||||
self.configure(self.config, recreate=recreate)
|
||||
|
||||
def exportToDB(self, save=False):
|
||||
Dev.exportToDB(self, save=save)
|
||||
backend = self.getBackend()
|
||||
if backend and backend.evtchn:
|
||||
db = self.db.addChild("evtchn")
|
||||
backend.evtchn.saveToDB(db, save=save)
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = self.getChannel()
|
||||
backend = self.getBackend()
|
||||
self.backendChannel = backend.backendChannel
|
||||
self.backendId = backend.id
|
||||
|
||||
def configure(self, config, change=False, recreate=False):
|
||||
@@ -351,7 +249,6 @@ class BlkDev(Dev):
|
||||
self.destroyed = True
|
||||
log.debug("Destroying vbd domain=%d id=%s", self.frontendDomain,
|
||||
self.id)
|
||||
self.send_be_vbd_destroy()
|
||||
if change:
|
||||
self.interfaceChanged()
|
||||
self.unbind()
|
||||
@@ -367,30 +264,6 @@ class BlkDev(Dev):
|
||||
|
||||
"""
|
||||
self.getBackend().connect()
|
||||
self.send_be_vbd_create()
|
||||
|
||||
def send_be_vbd_create(self):
|
||||
msg = packMsg('blkif_be_vbd_create_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.backendId,
|
||||
'pdevice' : self.device,
|
||||
'dev_handle' : self.dev_handle,
|
||||
'vdevice' : self.vdev,
|
||||
'readonly' : self.readonly() })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
|
||||
val = unpackMsg('blkif_be_vbd_create_t', msg)
|
||||
status = val['status']
|
||||
if status != BLKIF_BE_STATUS_OKAY:
|
||||
raise XendError("Creating vbd failed: device %s, error %d"
|
||||
% (sxp.to_string(self.config), status))
|
||||
|
||||
def send_be_vbd_destroy(self):
|
||||
msg = packMsg('blkif_be_vbd_destroy_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'blkif_handle' : self.backendId,
|
||||
'vdevice' : self.vdev })
|
||||
return self.backendChannel.writeRequest(msg)
|
||||
|
||||
class BlkifController(DevController):
|
||||
"""Block device interface controller. Handles all block devices
|
||||
@@ -403,19 +276,9 @@ class BlkifController(DevController):
|
||||
DevController.__init__(self, vm, recreate=recreate)
|
||||
self.backends = {}
|
||||
self.backendId = 0
|
||||
self.rcvr = None
|
||||
|
||||
def initController(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
# Add our handlers for incoming requests.
|
||||
self.rcvr = CtrlMsgRcvr(self.getChannel())
|
||||
self.rcvr.addHandler(CMSG_BLKIF_FE,
|
||||
CMSG_BLKIF_FE_DRIVER_STATUS,
|
||||
self.recv_fe_driver_status)
|
||||
self.rcvr.addHandler(CMSG_BLKIF_FE,
|
||||
CMSG_BLKIF_FE_INTERFACE_CONNECT,
|
||||
self.recv_fe_interface_connect)
|
||||
self.rcvr.registerChannel()
|
||||
if reboot:
|
||||
self.rebootBackends()
|
||||
self.rebootDevices()
|
||||
@@ -465,26 +328,7 @@ class BlkifController(DevController):
|
||||
log.debug("Destroying blkif domain=%d", self.getDomain())
|
||||
self.destroyDevices(reboot=reboot)
|
||||
self.destroyBackends(reboot=reboot)
|
||||
self.rcvr.deregisterChannel()
|
||||
|
||||
def destroyBackends(self, reboot=False):
|
||||
for backend in self.backends.values():
|
||||
backend.destroy(reboot=reboot)
|
||||
|
||||
def recv_fe_driver_status(self, msg):
|
||||
val = unpackMsg('blkif_fe_driver_status_t', msg)
|
||||
for backend in self.backends.values():
|
||||
backend.interfaceDisconnected()
|
||||
|
||||
def recv_fe_interface_connect(self, msg):
|
||||
val = unpackMsg('blkif_fe_interface_connect_t', msg)
|
||||
id = val['handle']
|
||||
backend = self.getBackendById(id)
|
||||
if backend:
|
||||
try:
|
||||
backend.connectInterface(val)
|
||||
except IOError, ex:
|
||||
log.error("Exception connecting backend: %s", ex)
|
||||
else:
|
||||
log.error('interface connect on unknown interface: id=%d', id)
|
||||
|
||||
@@ -23,8 +23,6 @@ from xen.lowlevel import xu
|
||||
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
from messages import *
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
RESPONSE_TIMEOUT = 20.0
|
||||
@@ -132,473 +130,3 @@ def eventChannelClose(evtchn):
|
||||
"""
|
||||
if not evtchn: return
|
||||
evtchn.close()
|
||||
|
||||
class ChannelFactory:
|
||||
"""Factory for creating control channels.
|
||||
Maintains a table of channels.
|
||||
"""
|
||||
|
||||
""" Channels indexed by index. """
|
||||
channels = None
|
||||
|
||||
thread = None
|
||||
|
||||
notifier = None
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor - do not use. Use the channelFactory function."""
|
||||
self.channels = {}
|
||||
self.notifier = xu.notifier()
|
||||
|
||||
def start(self):
|
||||
"""Fork a thread to read messages.
|
||||
"""
|
||||
if self.thread: return
|
||||
self.thread = threading.Thread(name="ChannelFactory",
|
||||
target=self.main)
|
||||
self.thread.setDaemon(True)
|
||||
self.thread.start()
|
||||
|
||||
def stop(self):
|
||||
"""Signal the thread to stop.
|
||||
"""
|
||||
self.thread = None
|
||||
|
||||
def main(self):
|
||||
"""Main routine for the thread.
|
||||
Reads the notifier and dispatches to channels.
|
||||
"""
|
||||
while True:
|
||||
if self.thread == None: return
|
||||
port = self.notifier.read()
|
||||
if port:
|
||||
self.msgReceived(port)
|
||||
else:
|
||||
select.select([self.notifier], [], [], 1.0)
|
||||
|
||||
def msgReceived(self, port):
|
||||
# We run the message handlers in their own threads.
|
||||
# Note we use keyword args to lambda to save the values -
|
||||
# otherwise lambda will use the variables, which will get
|
||||
# assigned by the loop and the lambda will get the changed values.
|
||||
received = 0
|
||||
for chan in self.channels.values():
|
||||
if self.thread == None: return
|
||||
msg = chan.readResponse()
|
||||
if msg:
|
||||
received += 1
|
||||
chan.responseReceived(msg)
|
||||
for chan in self.channels.values():
|
||||
if self.thread == None: return
|
||||
msg = chan.readRequest()
|
||||
if msg:
|
||||
received += 1
|
||||
self.runInThread(lambda chan=chan, msg=msg: chan.requestReceived(msg))
|
||||
if port and received == 0:
|
||||
log.warning("Port %s notified, but no messages found", port)
|
||||
|
||||
def runInThread(self, thunk):
|
||||
thread = threading.Thread(target = thunk)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
|
||||
def newChannel(self, dom, local_port, remote_port):
|
||||
"""Create a new channel.
|
||||
"""
|
||||
return self.addChannel(Channel(self, dom, local_port, remote_port))
|
||||
|
||||
def addChannel(self, channel):
|
||||
"""Add a channel.
|
||||
"""
|
||||
self.channels[channel.getKey()] = channel
|
||||
return channel
|
||||
|
||||
def delChannel(self, channel):
|
||||
"""Remove the channel.
|
||||
"""
|
||||
key = channel.getKey()
|
||||
if key in self.channels:
|
||||
del self.channels[key]
|
||||
|
||||
def getChannel(self, dom, local_port, remote_port):
|
||||
"""Get the channel with the given domain and ports (if any).
|
||||
"""
|
||||
key = (dom, local_port, remote_port)
|
||||
return self.channels.get(key)
|
||||
|
||||
def findChannel(self, dom, local_port=0, remote_port=0):
|
||||
"""Find a channel. Ports given as zero are wildcards.
|
||||
|
||||
dom domain
|
||||
|
||||
returns channel
|
||||
"""
|
||||
chan = self.getChannel(dom, local_port, remote_port)
|
||||
if chan: return chan
|
||||
if local_port and remote_port:
|
||||
return None
|
||||
for c in self.channels.values():
|
||||
if c.dom != dom: continue
|
||||
if local_port and local_port != c.getLocalPort(): continue
|
||||
if remote_port and remote_port != c.getRemotePort(): continue
|
||||
return c
|
||||
return None
|
||||
|
||||
def openChannel(self, dom, local_port=0, remote_port=0):
|
||||
chan = self.findChannel(dom, local_port=local_port,
|
||||
remote_port=remote_port)
|
||||
if chan:
|
||||
return chan
|
||||
chan = self.newChannel(dom, local_port, remote_port)
|
||||
return chan
|
||||
|
||||
|
||||
def createPort(self, dom, local_port=0, remote_port=0):
|
||||
"""Create a port for a channel to the given domain.
|
||||
If only the domain is specified, a new channel with new port ids is
|
||||
created. If one port id is specified and the given port id is in use,
|
||||
the other port id is filled. If one port id is specified and the
|
||||
given port id is not in use, a new channel is created with one port
|
||||
id equal to the given id and a new id for the other end. If both
|
||||
port ids are specified, a port is reconnected using the given port
|
||||
ids.
|
||||
|
||||
@param dom: domain
|
||||
@param local: local port id to use
|
||||
@type local: int
|
||||
@param remote: remote port id to use
|
||||
@type remote: int
|
||||
@return: port object
|
||||
"""
|
||||
return xu.port(dom, local_port=local_port, remote_port=remote_port)
|
||||
|
||||
def restoreFromDB(self, db, dom, local, remote):
|
||||
"""Create a channel using ports restored from the db (if available).
|
||||
Otherwise use the given ports. This is the inverse operation to
|
||||
saveToDB() on a channel.
|
||||
|
||||
@param db db
|
||||
@param dom domain the channel connects to
|
||||
@param local default local port
|
||||
@param remote default remote port
|
||||
"""
|
||||
try:
|
||||
local_port = int(db['local_port'])
|
||||
except:
|
||||
local_port = local
|
||||
try:
|
||||
remote_port = int(db['remote_port'])
|
||||
except:
|
||||
remote_port = remote
|
||||
try:
|
||||
chan = self.openChannel(dom, local_port, remote_port)
|
||||
except:
|
||||
return None
|
||||
return chan
|
||||
|
||||
def channelFactory():
|
||||
"""Singleton constructor for the channel factory.
|
||||
Use this instead of the class constructor.
|
||||
"""
|
||||
global inst
|
||||
try:
|
||||
inst
|
||||
except:
|
||||
inst = ChannelFactory()
|
||||
return inst
|
||||
|
||||
class Channel:
|
||||
"""Control channel to a domain.
|
||||
Maintains a list of device handlers to dispatch requests to, based
|
||||
on the request type.
|
||||
"""
|
||||
|
||||
def __init__(self, factory, dom, local_port, remote_port):
|
||||
self.factory = factory
|
||||
self.dom = int(dom)
|
||||
# Registered device handlers.
|
||||
self.devs = []
|
||||
# Handlers indexed by the message types they handle.
|
||||
self.devs_by_type = {}
|
||||
self.port = self.factory.createPort(self.dom,
|
||||
local_port=local_port,
|
||||
remote_port=remote_port)
|
||||
self.closed = False
|
||||
# Queue of waiters for responses to requests.
|
||||
self.queue = ResponseQueue(self)
|
||||
# Make sure the port will deliver all the messages.
|
||||
self.port.register(TYPE_WILDCARD)
|
||||
|
||||
def saveToDB(self, db, save=False):
|
||||
"""Save the channel ports to the db so the channel can be restored later,
|
||||
using restoreFromDB() on the factory.
|
||||
|
||||
@param db db
|
||||
"""
|
||||
if self.closed: return
|
||||
db['local_port'] = str(self.getLocalPort())
|
||||
db['remote_port'] = str(self.getRemotePort())
|
||||
db.saveDB(save=save)
|
||||
|
||||
def getKey(self):
|
||||
"""Get the channel key.
|
||||
"""
|
||||
return (self.dom, self.getLocalPort(), self.getRemotePort())
|
||||
|
||||
def sxpr(self):
|
||||
val = ['channel']
|
||||
val.append(['domain', self.dom])
|
||||
if self.port:
|
||||
val.append(['local_port', self.port.local_port])
|
||||
val.append(['remote_port', self.port.remote_port])
|
||||
return val
|
||||
|
||||
def close(self):
|
||||
"""Close the channel.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'Channel>close>', self
|
||||
if self.closed: return
|
||||
self.closed = True
|
||||
self.factory.delChannel(self)
|
||||
for d in self.devs[:]:
|
||||
d.lostChannel(self)
|
||||
self.devs = []
|
||||
self.devs_by_type = {}
|
||||
if self.port:
|
||||
self.port.close()
|
||||
#self.port = None
|
||||
|
||||
def getDomain(self):
|
||||
return self.dom
|
||||
|
||||
def getLocalPort(self):
|
||||
"""Get the local port.
|
||||
|
||||
@return: local port
|
||||
@rtype: int
|
||||
"""
|
||||
if self.closed: return -1
|
||||
return self.port.local_port
|
||||
|
||||
def getRemotePort(self):
|
||||
"""Get the remote port.
|
||||
|
||||
@return: remote port
|
||||
@rtype: int
|
||||
"""
|
||||
if self.closed: return -1
|
||||
return self.port.remote_port
|
||||
|
||||
def __repr__(self):
|
||||
return ('<Channel dom=%d ports=%d:%d>'
|
||||
% (self.dom,
|
||||
self.getLocalPort(),
|
||||
self.getRemotePort()))
|
||||
|
||||
|
||||
def registerDevice(self, types, dev):
|
||||
"""Register a device message handler.
|
||||
|
||||
@param types: message types handled
|
||||
@type types: array of ints
|
||||
@param dev: device handler
|
||||
"""
|
||||
if self.closed: return
|
||||
self.devs.append(dev)
|
||||
for ty in types:
|
||||
self.devs_by_type[ty] = dev
|
||||
|
||||
def deregisterDevice(self, dev):
|
||||
"""Remove the registration for a device handler.
|
||||
|
||||
@param dev: device handler
|
||||
"""
|
||||
if dev in self.devs:
|
||||
self.devs.remove(dev)
|
||||
types = [ ty for (ty, d) in self.devs_by_type.items() if d == dev ]
|
||||
for ty in types:
|
||||
del self.devs_by_type[ty]
|
||||
|
||||
def getDevice(self, type):
|
||||
"""Get the handler for a message type.
|
||||
|
||||
@param type: message type
|
||||
@type type: int
|
||||
@return: controller or None
|
||||
@rtype: device handler
|
||||
"""
|
||||
return self.devs_by_type.get(type)
|
||||
|
||||
def requestReceived(self, msg):
|
||||
"""A request has been received on the channel.
|
||||
Disptach it to the device handlers.
|
||||
Called from the channel factory thread.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'Channel>requestReceived>', self,
|
||||
printMsg(msg)
|
||||
(ty, subty) = getMessageType(msg)
|
||||
responded = False
|
||||
dev = self.getDevice(ty)
|
||||
if dev:
|
||||
responded = dev.requestReceived(msg, ty, subty)
|
||||
elif DEBUG:
|
||||
print "Channel>requestReceived> No device handler", self,
|
||||
printMsg(msg)
|
||||
else:
|
||||
pass
|
||||
if not responded:
|
||||
self.writeResponse(msg)
|
||||
|
||||
def writeRequest(self, msg):
|
||||
"""Write a request to the channel.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'Channel>writeRequest>', self,
|
||||
printMsg(msg, all=True)
|
||||
if self.closed: return -1
|
||||
self.port.write_request(msg)
|
||||
return 1
|
||||
|
||||
def writeResponse(self, msg):
|
||||
"""Write a response to the channel.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'Channel>writeResponse>', self,
|
||||
printMsg(msg, all=True)
|
||||
if self.port:
|
||||
self.port.write_response(msg)
|
||||
return 1
|
||||
|
||||
def readRequest(self):
|
||||
"""Read a request from the channel.
|
||||
Called internally.
|
||||
"""
|
||||
if self.closed:
|
||||
val = None
|
||||
else:
|
||||
val = self.port.read_request()
|
||||
return val
|
||||
|
||||
def readResponse(self):
|
||||
"""Read a response from the channel.
|
||||
Called internally.
|
||||
"""
|
||||
if self.closed:
|
||||
val = None
|
||||
else:
|
||||
val = self.port.read_response()
|
||||
if DEBUG and val:
|
||||
print 'Channel>readResponse>', self,
|
||||
printMsg(val, all=True)
|
||||
return val
|
||||
|
||||
def requestResponse(self, msg, timeout=None):
|
||||
"""Write a request and wait for a response.
|
||||
Raises IOError on timeout.
|
||||
|
||||
@param msg request message
|
||||
@param timeout timeout (0 is forever)
|
||||
@return response message
|
||||
"""
|
||||
if self.closed:
|
||||
raise IOError("closed")
|
||||
if self.closed:
|
||||
return None
|
||||
if timeout is None:
|
||||
timeout = RESPONSE_TIMEOUT
|
||||
elif timeout <= 0:
|
||||
timeout = None
|
||||
return self.queue.call(msg, timeout)
|
||||
|
||||
def responseReceived(self, msg):
|
||||
"""A response has been received, look for a waiter to
|
||||
give it to.
|
||||
Called internally.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'Channel>responseReceived>', self,
|
||||
printMsg(msg)
|
||||
self.queue.response(getMessageId(msg), msg)
|
||||
|
||||
class Response:
|
||||
"""Entry in the response queue.
|
||||
Used to signal a response to a message.
|
||||
"""
|
||||
|
||||
def __init__(self, mid):
|
||||
self.mid = mid
|
||||
self.msg = None
|
||||
self.ready = threading.Event()
|
||||
|
||||
def response(self, msg):
|
||||
"""Signal arrival of a response to a waiting thread.
|
||||
Passing msg None cancels the wait with an IOError.
|
||||
"""
|
||||
if msg:
|
||||
self.msg = msg
|
||||
else:
|
||||
self.mid = -1
|
||||
self.ready.set()
|
||||
|
||||
def wait(self, timeout):
|
||||
"""Wait up to 'timeout' seconds for a response.
|
||||
Returns the response or raises an IOError.
|
||||
"""
|
||||
self.ready.wait(timeout)
|
||||
if self.mid < 0:
|
||||
raise IOError("wait canceled")
|
||||
if self.msg is None:
|
||||
raise IOError("response timeout")
|
||||
return self.msg
|
||||
|
||||
class ResponseQueue:
|
||||
"""Response queue. Manages waiters for responses to messages.
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
self.channel = channel
|
||||
self.lock = threading.Lock()
|
||||
self.responses = {}
|
||||
|
||||
def add(self, mid):
|
||||
r = Response(mid)
|
||||
self.responses[mid] = r
|
||||
return r
|
||||
|
||||
def get(self, mid):
|
||||
return self.responses.get(mid)
|
||||
|
||||
def remove(self, mid):
|
||||
r = self.responses.get(mid)
|
||||
if r:
|
||||
del self.responses[mid]
|
||||
return r
|
||||
|
||||
def response(self, mid, msg):
|
||||
"""Process a response - signals any waiter that a response
|
||||
has arrived.
|
||||
"""
|
||||
try:
|
||||
self.lock.acquire()
|
||||
r = self.remove(mid)
|
||||
finally:
|
||||
self.lock.release()
|
||||
if r:
|
||||
r.response(msg)
|
||||
|
||||
def call(self, msg, timeout):
|
||||
"""Send the message and wait for 'timeout' seconds for a response.
|
||||
Returns the response.
|
||||
Raises IOError on timeout.
|
||||
"""
|
||||
mid = getMessageId(msg)
|
||||
try:
|
||||
self.lock.acquire()
|
||||
r = self.add(mid)
|
||||
finally:
|
||||
self.lock.release()
|
||||
self.channel.writeRequest(msg)
|
||||
return r.wait(timeout)
|
||||
|
||||
@@ -21,107 +21,9 @@ for a domain.
|
||||
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend.xenstore import DBVar
|
||||
from xen.xend.server.messages import msgTypeName, printMsg, getMessageType
|
||||
|
||||
DEBUG = 0
|
||||
|
||||
class CtrlMsgRcvr:
|
||||
"""Utility class to dispatch messages on a control channel.
|
||||
Once I{registerChannel} has been called, our message types are registered
|
||||
with the channel. The channel will call I{requestReceived}
|
||||
when a request arrives if it has one of our message types.
|
||||
|
||||
@ivar channel: channel to a domain
|
||||
@type channel: Channel
|
||||
@ivar majorTypes: major message types we are interested in
|
||||
@type majorTypes: {int:{int:method}}
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
self.majorTypes = {}
|
||||
self.channel = channel
|
||||
|
||||
def getHandler(self, type, subtype):
|
||||
"""Get the method for a type and subtype.
|
||||
|
||||
@param type: major message type
|
||||
@param subtype: minor message type
|
||||
@return: method or None
|
||||
"""
|
||||
method = None
|
||||
subtypes = self.majorTypes.get(type)
|
||||
if subtypes:
|
||||
method = subtypes.get(subtype)
|
||||
return method
|
||||
|
||||
def addHandler(self, type, subtype, method):
|
||||
"""Add a method to handle a message type and subtype.
|
||||
|
||||
@param type: major message type
|
||||
@param subtype: minor message type
|
||||
@param method: method
|
||||
"""
|
||||
subtypes = self.majorTypes.get(type)
|
||||
if not subtypes:
|
||||
subtypes = {}
|
||||
self.majorTypes[type] = subtypes
|
||||
subtypes[subtype] = method
|
||||
|
||||
def getMajorTypes(self):
|
||||
"""Get the list of major message types handled.
|
||||
"""
|
||||
return self.majorTypes.keys()
|
||||
|
||||
def requestReceived(self, msg, type, subtype):
|
||||
"""Dispatch a request message to handlers.
|
||||
Called by the channel for requests with one of our types.
|
||||
|
||||
@param msg: message
|
||||
@type msg: xu message
|
||||
@param type: major message type
|
||||
@type type: int
|
||||
@param subtype: minor message type
|
||||
@type subtype: int
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'requestReceived>',
|
||||
printMsg(msg, all=True)
|
||||
responded = 0
|
||||
method = self.getHandler(type, subtype)
|
||||
if method:
|
||||
responded = method(msg)
|
||||
elif DEBUG:
|
||||
print ('requestReceived> No handler: Message type %s %d:%d'
|
||||
% (msgTypeName(type, subtype), type, subtype)), self
|
||||
return responded
|
||||
|
||||
|
||||
def lostChannel(self):
|
||||
"""Called when the channel to the domain is lost.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'CtrlMsgRcvr>lostChannel>',
|
||||
self.channel = None
|
||||
|
||||
def registerChannel(self):
|
||||
"""Register interest in our major message types with the
|
||||
channel to our domain. Once we have registered, the channel
|
||||
will call requestReceived for our messages.
|
||||
"""
|
||||
if DEBUG:
|
||||
print 'CtrlMsgRcvr>registerChannel>', self.channel, self.getMajorTypes()
|
||||
if self.channel:
|
||||
self.channel.registerDevice(self.getMajorTypes(), self)
|
||||
|
||||
def deregisterChannel(self):
|
||||
"""Deregister interest in our major message types with the
|
||||
channel to our domain. After this the channel won't call
|
||||
us any more.
|
||||
"""
|
||||
if self.channel:
|
||||
self.channel.deregisterDevice(self)
|
||||
|
||||
class DevControllerTable:
|
||||
"""Table of device controller classes, indexed by type name.
|
||||
"""
|
||||
@@ -232,10 +134,6 @@ class DevController:
|
||||
def getDomainName(self):
|
||||
return self.vm.getName()
|
||||
|
||||
def getChannel(self):
|
||||
chan = self.vm.getChannel()
|
||||
return chan
|
||||
|
||||
def getDomainInfo(self):
|
||||
return self.vm
|
||||
|
||||
@@ -433,9 +331,6 @@ class Dev:
|
||||
def getDomainName(self):
|
||||
return self.controller.getDomainName()
|
||||
|
||||
def getChannel(self):
|
||||
return self.controller.getChannel()
|
||||
|
||||
def getDomainInfo(self):
|
||||
return self.controller.getDomainInfo()
|
||||
|
||||
|
||||
@@ -174,11 +174,6 @@ class EventProtocol(protocol.Protocol):
|
||||
else:
|
||||
logging.removeLogStderr()
|
||||
|
||||
def op_debug_msg(self, name, v):
|
||||
mode = v[1]
|
||||
import messages
|
||||
messages.DEBUG = (mode == 'on')
|
||||
|
||||
def op_debug_controller(self, name, v):
|
||||
mode = v[1]
|
||||
import controller
|
||||
|
||||
@@ -1,462 +0,0 @@
|
||||
#============================================================================
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of version 2.1 of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#============================================================================
|
||||
# Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
|
||||
#============================================================================
|
||||
|
||||
import sys
|
||||
import struct
|
||||
import types
|
||||
|
||||
from xen.lowlevel import xu
|
||||
|
||||
DEBUG = False
|
||||
|
||||
#PORT_WILDCARD = 0xefffffff
|
||||
|
||||
"""Wildcard for the control message types."""
|
||||
TYPE_WILDCARD = 0xffff
|
||||
|
||||
""" All message formats.
|
||||
Added to incrementally for the various message types.
|
||||
See below.
|
||||
"""
|
||||
msg_formats = {}
|
||||
|
||||
#============================================================================
|
||||
# Block interface message types.
|
||||
#============================================================================
|
||||
|
||||
CMSG_BLKIF_BE = 1
|
||||
CMSG_BLKIF_FE = 2
|
||||
|
||||
CMSG_BLKIF_FE_INTERFACE_STATUS = 0
|
||||
CMSG_BLKIF_FE_DRIVER_STATUS = 32
|
||||
CMSG_BLKIF_FE_INTERFACE_CONNECT = 33
|
||||
CMSG_BLKIF_FE_INTERFACE_DISCONNECT = 34
|
||||
CMSG_BLKIF_FE_INTERFACE_QUERY = 35
|
||||
|
||||
CMSG_BLKIF_BE_CREATE = 0
|
||||
CMSG_BLKIF_BE_DESTROY = 1
|
||||
CMSG_BLKIF_BE_CONNECT = 2
|
||||
CMSG_BLKIF_BE_DISCONNECT = 3
|
||||
CMSG_BLKIF_BE_VBD_CREATE = 4
|
||||
CMSG_BLKIF_BE_VBD_DESTROY = 5
|
||||
CMSG_BLKIF_BE_DRIVER_STATUS = 32
|
||||
|
||||
BLKIF_DRIVER_STATUS_DOWN = 0
|
||||
BLKIF_DRIVER_STATUS_UP = 1
|
||||
|
||||
BLKIF_INTERFACE_STATUS_CLOSED = 0 #/* Interface doesn't exist. */
|
||||
BLKIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
|
||||
BLKIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
|
||||
BLKIF_INTERFACE_STATUS_CHANGED = 3 #/* A device has been added or removed. */
|
||||
|
||||
BLKIF_BE_STATUS_OKAY = 0
|
||||
BLKIF_BE_STATUS_ERROR = 1
|
||||
BLKIF_BE_STATUS_INTERFACE_EXISTS = 2
|
||||
BLKIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
|
||||
BLKIF_BE_STATUS_INTERFACE_CONNECTED = 4
|
||||
BLKIF_BE_STATUS_VBD_EXISTS = 5
|
||||
BLKIF_BE_STATUS_VBD_NOT_FOUND = 6
|
||||
BLKIF_BE_STATUS_OUT_OF_MEMORY = 7
|
||||
BLKIF_BE_STATUS_PHYSDEV_NOT_FOUND = 8
|
||||
BLKIF_BE_STATUS_MAPPING_ERROR = 9
|
||||
|
||||
blkif_formats = {
|
||||
'blkif_be_connect_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT),
|
||||
# Connect be to fe (in response to blkif_fe_interface_connect_t).
|
||||
|
||||
'blkif_be_create_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE),
|
||||
# Create be.
|
||||
|
||||
'blkif_be_disconnect_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DISCONNECT),
|
||||
# Disconnect be from fe.
|
||||
|
||||
'blkif_be_destroy_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY),
|
||||
# Destroy be (after disconnect).
|
||||
# Make be do this even if no disconnect (and destroy all vbd too).
|
||||
|
||||
'blkif_be_vbd_create_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE),
|
||||
# Create a vbd device.
|
||||
|
||||
'blkif_be_vbd_destroy_t':
|
||||
(CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_DESTROY),
|
||||
# Destroy a vbd.
|
||||
|
||||
# Add message to query be for state and vbds.
|
||||
|
||||
'blkif_fe_interface_status_t':
|
||||
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS),
|
||||
# Notify device status to fe.
|
||||
# Also used to notify 'any' device change with status BLKIF_INTERFACE_STATUS_CHANGED.
|
||||
|
||||
'blkif_fe_driver_status_t':
|
||||
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS),
|
||||
# Comes from fe, treated as notifying that fe has come up/changed.
|
||||
# Xend sets be(s) to BLKIF_INTERFACE_STATUS_DISCONNECTED,
|
||||
# sends blkif_fe_interface_status_t to fe (from each be).
|
||||
#
|
||||
# Reply with i/f count.
|
||||
# The i/f sends probes (using -ve trick), we reply with the info.
|
||||
|
||||
'blkif_fe_interface_connect_t':
|
||||
(CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT),
|
||||
# Comes from fe, passing shmem frame to use for be.
|
||||
# fe sends when gets blkif_fe_interface_status_t with state NETIF_INTERFACE_STATUS_DISCONNECTED.
|
||||
# Xend creates event channel and notifies be.
|
||||
# Then notifies fe of event channel with blkif_fe_interface_status_t.
|
||||
|
||||
# Add message to kick fe to probe for devices.
|
||||
# Just report new devices to fe?
|
||||
|
||||
#
|
||||
# Add message for fe to probe a device.
|
||||
# And probing with id -1 should return first.
|
||||
# And probing with id -n should return first device with id > n.
|
||||
|
||||
# Add message to query fe for state and vbds.
|
||||
}
|
||||
|
||||
msg_formats.update(blkif_formats)
|
||||
|
||||
#============================================================================
|
||||
# Network interface message types.
|
||||
#============================================================================
|
||||
|
||||
CMSG_NETIF_BE = 3
|
||||
CMSG_NETIF_FE = 4
|
||||
|
||||
CMSG_NETIF_FE_INTERFACE_STATUS = 0
|
||||
CMSG_NETIF_FE_DRIVER_STATUS = 32
|
||||
CMSG_NETIF_FE_INTERFACE_CONNECT = 33
|
||||
CMSG_NETIF_FE_INTERFACE_DISCONNECT = 34
|
||||
CMSG_NETIF_FE_INTERFACE_QUERY = 35
|
||||
|
||||
CMSG_NETIF_BE_CREATE = 0
|
||||
CMSG_NETIF_BE_DESTROY = 1
|
||||
CMSG_NETIF_BE_CONNECT = 2
|
||||
CMSG_NETIF_BE_DISCONNECT = 3
|
||||
CMSG_NETIF_BE_CREDITLIMIT = 4
|
||||
CMSG_NETIF_BE_DRIVER_STATUS = 32
|
||||
|
||||
NETIF_INTERFACE_STATUS_CLOSED = 0 #/* Interface doesn't exist. */
|
||||
NETIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
|
||||
NETIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
|
||||
NETIF_INTERFACE_STATUS_CHANGED = 3 #/* A device has been added or removed. */
|
||||
|
||||
NETIF_DRIVER_STATUS_DOWN = 0
|
||||
NETIF_DRIVER_STATUS_UP = 1
|
||||
|
||||
netif_formats = {
|
||||
'netif_be_connect_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT),
|
||||
|
||||
'netif_be_create_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE),
|
||||
|
||||
'netif_be_disconnect_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT),
|
||||
|
||||
'netif_be_destroy_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY),
|
||||
|
||||
'netif_be_creditlimit_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_CREDITLIMIT),
|
||||
|
||||
'netif_be_driver_status_t':
|
||||
(CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS),
|
||||
|
||||
'netif_fe_driver_status_t':
|
||||
(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS),
|
||||
|
||||
'netif_fe_interface_connect_t':
|
||||
(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT),
|
||||
|
||||
'netif_fe_interface_status_t':
|
||||
(CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS),
|
||||
}
|
||||
|
||||
msg_formats.update(netif_formats)
|
||||
|
||||
#============================================================================
|
||||
# USB interface message types.
|
||||
#============================================================================
|
||||
|
||||
CMSG_USBIF_BE = 8
|
||||
CMSG_USBIF_FE = 9
|
||||
|
||||
CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED = 0
|
||||
|
||||
CMSG_USBIF_FE_DRIVER_STATUS_CHANGED = 32
|
||||
CMSG_USBIF_FE_INTERFACE_CONNECT = 33
|
||||
CMSG_USBIF_FE_INTERFACE_DISCONNECT = 34
|
||||
|
||||
USBIF_DRIVER_STATUS_DOWN = 0
|
||||
USBIF_DRIVER_STATUS_UP = 1
|
||||
|
||||
USBIF_INTERFACE_STATUS_DESTROYED = 0 #/* Interface doesn't exist. */
|
||||
USBIF_INTERFACE_STATUS_DISCONNECTED = 1 #/* Exists but is disconnected. */
|
||||
USBIF_INTERFACE_STATUS_CONNECTED = 2 #/* Exists and is connected. */
|
||||
|
||||
CMSG_USBIF_BE_CREATE = 0
|
||||
CMSG_USBIF_BE_DESTROY = 1
|
||||
CMSG_USBIF_BE_CONNECT = 2
|
||||
|
||||
CMSG_USBIF_BE_DISCONNECT = 3
|
||||
CMSG_USBIF_BE_CLAIM_PORT = 4
|
||||
CMSG_USBIF_BE_RELEASE_PORT = 5
|
||||
|
||||
CMSG_USBIF_BE_DRIVER_STATUS_CHANGED = 32
|
||||
|
||||
USBIF_BE_STATUS_OKAY = 0
|
||||
USBIF_BE_STATUS_ERROR = 1
|
||||
|
||||
USBIF_BE_STATUS_INTERFACE_EXISTS = 2
|
||||
USBIF_BE_STATUS_INTERFACE_NOT_FOUND = 3
|
||||
USBIF_BE_STATUS_INTERFACE_CONNECTED = 4
|
||||
USBIF_BE_STATUS_OUT_OF_MEMORY = 7
|
||||
USBIF_BE_STATUS_MAPPING_ERROR = 9
|
||||
|
||||
usbif_formats = {
|
||||
'usbif_be_create_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_CREATE),
|
||||
|
||||
'usbif_be_destroy_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_DESTROY),
|
||||
|
||||
'usbif_be_connect_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_CONNECT),
|
||||
|
||||
'usbif_be_disconnect_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_DISCONNECT),
|
||||
|
||||
'usbif_be_claim_port_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_CLAIM_PORT),
|
||||
|
||||
'usbif_be_release_port_t':
|
||||
(CMSG_USBIF_BE, CMSG_USBIF_BE_RELEASE_PORT),
|
||||
|
||||
'usbif_fe_interface_status_changed_t':
|
||||
(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_STATUS_CHANGED),
|
||||
|
||||
'usbif_fe_driver_status_changed_t':
|
||||
(CMSG_USBIF_FE, CMSG_USBIF_FE_DRIVER_STATUS_CHANGED),
|
||||
|
||||
'usbif_fe_interface_connect_t':
|
||||
(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_CONNECT),
|
||||
|
||||
'usbif_fe_interface_disconnect_t':
|
||||
(CMSG_USBIF_FE, CMSG_USBIF_FE_INTERFACE_DISCONNECT),
|
||||
|
||||
}
|
||||
|
||||
msg_formats.update(usbif_formats)
|
||||
|
||||
#============================================================================
|
||||
# Domain shutdown message types.
|
||||
#============================================================================
|
||||
|
||||
CMSG_SHUTDOWN = 6
|
||||
|
||||
CMSG_SHUTDOWN_POWEROFF = 0
|
||||
CMSG_SHUTDOWN_REBOOT = 1
|
||||
CMSG_SHUTDOWN_SUSPEND = 2
|
||||
CMSG_SHUTDOWN_SYSRQ = 3
|
||||
|
||||
STOPCODE_shutdown = 0
|
||||
STOPCODE_reboot = 1
|
||||
STOPCODE_suspend = 2
|
||||
STOPCODE_sysrq = 3
|
||||
|
||||
shutdown_formats = {
|
||||
'shutdown_poweroff_t':
|
||||
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF),
|
||||
|
||||
'shutdown_reboot_t':
|
||||
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT),
|
||||
|
||||
'shutdown_suspend_t':
|
||||
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND),
|
||||
|
||||
'shutdown_sysrq_t':
|
||||
(CMSG_SHUTDOWN, CMSG_SHUTDOWN_SYSRQ)
|
||||
}
|
||||
|
||||
msg_formats.update(shutdown_formats)
|
||||
|
||||
#============================================================================
|
||||
# Domain memory reservation message.
|
||||
#============================================================================
|
||||
|
||||
CMSG_MEM_REQUEST = 7
|
||||
CMSG_MEM_REQUEST_SET = 0
|
||||
|
||||
mem_request_formats = {
|
||||
'mem_request_t':
|
||||
(CMSG_MEM_REQUEST, CMSG_MEM_REQUEST_SET)
|
||||
}
|
||||
|
||||
msg_formats.update(mem_request_formats)
|
||||
|
||||
#============================================================================
|
||||
# Domain vcpu hotplug message.
|
||||
#============================================================================
|
||||
|
||||
CMSG_VCPU_HOTPLUG = 10
|
||||
CMSG_VCPU_HOTPLUG_OFF = 0
|
||||
CMSG_VCPU_HOTPLUG_ON = 1
|
||||
|
||||
vcpu_hotplug_formats = {
|
||||
'vcpu_hotplug_off_t':
|
||||
(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_OFF),
|
||||
|
||||
'vcpu_hotplug_on_t':
|
||||
(CMSG_VCPU_HOTPLUG, CMSG_VCPU_HOTPLUG_ON)
|
||||
}
|
||||
|
||||
msg_formats.update(vcpu_hotplug_formats)
|
||||
|
||||
#============================================================================
|
||||
class Msg:
|
||||
pass
|
||||
|
||||
_next_msgid = 0
|
||||
|
||||
def nextid():
|
||||
"""Generate the next message id.
|
||||
|
||||
@return: message id
|
||||
@rtype: int
|
||||
"""
|
||||
global _next_msgid
|
||||
_next_msgid += 1
|
||||
return _next_msgid
|
||||
|
||||
def packMsg(ty, params):
|
||||
"""Pack a message.
|
||||
Any I{mac} parameter is passed in as an int[6] array and converted.
|
||||
|
||||
@param ty: message type name
|
||||
@type ty: string
|
||||
@param params: message parameters
|
||||
@type params: dicy
|
||||
@return: message
|
||||
@rtype: xu message
|
||||
"""
|
||||
msgid = nextid()
|
||||
if DEBUG: print '>packMsg', msgid, ty, params
|
||||
(major, minor) = msg_formats[ty]
|
||||
args = {}
|
||||
for (k, v) in params.items():
|
||||
if k in ['mac', 'be_mac']:
|
||||
for i in range(0, 6):
|
||||
args['%s[%d]' % (k, i)] = v[i]
|
||||
else:
|
||||
args[k] = v
|
||||
msg = xu.message(major, minor, msgid, args)
|
||||
if DEBUG: print '<packMsg', msg.get_header()['id'], ty, args
|
||||
return msg
|
||||
|
||||
def unpackMsg(ty, msg):
|
||||
"""Unpack a message.
|
||||
Any mac addresses in the message are converted to int[6] array
|
||||
in the return dict.
|
||||
|
||||
@param ty: message type
|
||||
@type ty: string
|
||||
@param msg: message
|
||||
@type msg: xu message
|
||||
@return: parameters
|
||||
@rtype: dict
|
||||
"""
|
||||
args = msg.get_payload()
|
||||
if DEBUG: print '>unpackMsg', args
|
||||
if isinstance(args, types.StringType):
|
||||
args = {'value': args}
|
||||
else:
|
||||
mac = [0, 0, 0, 0, 0, 0]
|
||||
macs = []
|
||||
for (k, v) in args.items():
|
||||
if k.startswith('mac['):
|
||||
macs.append(k)
|
||||
i = int(k[4:5])
|
||||
mac[i] = v
|
||||
else:
|
||||
pass
|
||||
if macs:
|
||||
args['mac'] = mac
|
||||
#print 'macs=', macs
|
||||
#print 'args=', args
|
||||
for k in macs:
|
||||
del args[k]
|
||||
if DEBUG:
|
||||
msgid = msg.get_header()['id']
|
||||
print '<unpackMsg', msgid, ty, args
|
||||
return args
|
||||
|
||||
def msgTypeName(ty, subty):
|
||||
"""Convert a message type, subtype pair to a message type name.
|
||||
|
||||
@param ty: message type
|
||||
@type ty: int
|
||||
@param subty: message subtype
|
||||
@type ty: int
|
||||
@return: message type name (or None)
|
||||
@rtype: string or None
|
||||
"""
|
||||
for (name, info) in msg_formats.items():
|
||||
if info[0] == ty and info[1] == subty:
|
||||
return name
|
||||
return None
|
||||
|
||||
def printMsg(msg, out=sys.stdout, all=False):
|
||||
"""Print a message.
|
||||
|
||||
@param msg: message
|
||||
@type msg: xu message
|
||||
@param out: where to print to
|
||||
@type out: stream
|
||||
@param all: print payload if true
|
||||
@type all: bool
|
||||
"""
|
||||
hdr = msg.get_header()
|
||||
major = hdr['type']
|
||||
minor = hdr['subtype']
|
||||
msgid = hdr['id']
|
||||
ty = msgTypeName(major, minor)
|
||||
print >>out, 'message:', 'type=', ty, '%d:%d' % (major, minor), 'id=%d' % msgid
|
||||
if all:
|
||||
print >>out, 'payload=', msg.get_payload()
|
||||
|
||||
|
||||
def getMessageType(msg):
|
||||
"""Get a 2-tuple of the message type and subtype.
|
||||
|
||||
@param msg: message
|
||||
@type msg: xu message
|
||||
@return: type info
|
||||
@rtype: (int, int)
|
||||
"""
|
||||
hdr = msg.get_header()
|
||||
return (hdr['type'], hdr.get('subtype'))
|
||||
|
||||
def getMessageId(msg):
|
||||
hdr = msg.get_header()
|
||||
return hdr['id']
|
||||
@@ -30,9 +30,7 @@ from xen.xend import XendVnet
|
||||
from xen.xend.XendRoot import get_component
|
||||
from xen.xend.xenstore import DBVar
|
||||
|
||||
from xen.xend.server import channel
|
||||
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
|
||||
from xen.xend.server.messages import *
|
||||
from xen.xend.server.controller import Dev, DevController
|
||||
|
||||
class NetDev(Dev):
|
||||
"""A network device.
|
||||
@@ -90,12 +88,9 @@ class NetDev(Dev):
|
||||
def __init__(self, controller, id, config, recreate=False):
|
||||
Dev.__init__(self, controller, id, config, recreate=recreate)
|
||||
self.vif = int(self.id)
|
||||
self.evtchn = None
|
||||
self.status = None
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = None
|
||||
self.backendDomain = None
|
||||
self.backendChannel = None
|
||||
self.credit = None
|
||||
self.period = None
|
||||
self.mac = None
|
||||
@@ -109,17 +104,11 @@ class NetDev(Dev):
|
||||
|
||||
def exportToDB(self, save=False):
|
||||
Dev.exportToDB(self, save=save)
|
||||
if self.evtchn:
|
||||
db = self.db.addChild("evtchn")
|
||||
self.evtchn.saveToDB(db, save=save)
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = self.getChannel()
|
||||
cf = channel.channelFactory()
|
||||
self.backendChannel = cf.openChannel(self.backendDomain)
|
||||
|
||||
def _get_config_mac(self, config):
|
||||
vmac = sxp.child_value(config, 'mac')
|
||||
@@ -287,10 +276,6 @@ class NetDev(Dev):
|
||||
val.append(['credit', self.credit])
|
||||
if self.period:
|
||||
val.append(['period', self.period])
|
||||
if self.evtchn:
|
||||
val.append(['evtchn',
|
||||
self.evtchn['port1'],
|
||||
self.evtchn['port2']])
|
||||
return val
|
||||
|
||||
def get_vifname(self):
|
||||
@@ -348,42 +333,11 @@ class NetDev(Dev):
|
||||
if recreate:
|
||||
pass
|
||||
else:
|
||||
self.send_be_create()
|
||||
if self.credit and self.period:
|
||||
self.send_be_creditlimit(self.credit, self.period)
|
||||
#self.send_be_creditlimit(self.credit, self.period)
|
||||
pass
|
||||
self.vifctl('up', vmname=self.getDomainName())
|
||||
|
||||
def closeEvtchn(self):
|
||||
if self.evtchn:
|
||||
channel.eventChannelClose(self.evtchn)
|
||||
self.evtchn = None
|
||||
|
||||
def openEvtchn(self):
|
||||
self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
|
||||
|
||||
def getEventChannelBackend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port1']
|
||||
return val
|
||||
|
||||
def getEventChannelFrontend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port2']
|
||||
return val
|
||||
|
||||
def send_be_create(self):
|
||||
msg = packMsg('netif_be_create_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'netif_handle' : self.vif,
|
||||
'be_mac' : self.be_mac or [0, 0, 0, 0, 0, 0],
|
||||
'mac' : self.mac,
|
||||
#'vifname' : self.vifname
|
||||
})
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
# todo: check return status
|
||||
|
||||
def destroy(self, change=False, reboot=False):
|
||||
"""Destroy the device's resources and disconnect from the back-end
|
||||
device controller. If 'change' is true notify the front-end interface.
|
||||
@@ -393,47 +347,14 @@ class NetDev(Dev):
|
||||
self.destroyed = True
|
||||
self.status = NETIF_INTERFACE_STATUS_CLOSED
|
||||
log.debug("Destroying vif domain=%d vif=%d", self.frontendDomain, self.vif)
|
||||
self.closeEvtchn()
|
||||
self.vifctl('down')
|
||||
self.send_be_disconnect()
|
||||
self.send_be_destroy()
|
||||
if change:
|
||||
self.reportStatus()
|
||||
|
||||
def send_be_disconnect(self):
|
||||
msg = packMsg('netif_be_disconnect_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'netif_handle' : self.vif })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
|
||||
def send_be_destroy(self, response=None):
|
||||
msg = packMsg('netif_be_destroy_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'netif_handle' : self.vif })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
|
||||
def recv_fe_interface_connect(self, val):
|
||||
self.openEvtchn()
|
||||
msg = packMsg('netif_be_connect_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'netif_handle' : self.vif,
|
||||
'evtchn' : self.getEventChannelBackend(),
|
||||
'tx_shmem_frame' : val['tx_shmem_frame'],
|
||||
'tx_shmem_ref' : val['tx_shmem_ref'],
|
||||
'rx_shmem_frame' : val['rx_shmem_frame'],
|
||||
'rx_shmem_ref' : val['rx_shmem_ref'] })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
self.status = NETIF_INTERFACE_STATUS_CONNECTED
|
||||
self.reportStatus()
|
||||
|
||||
def setCreditLimit(self, credit, period):
|
||||
#todo: these params should be in sxpr and vif config.
|
||||
self.credit = credit
|
||||
self.period = period
|
||||
self.send_be_creditlimit(credit, period)
|
||||
|
||||
def getCredit(self):
|
||||
return self.credit
|
||||
@@ -441,31 +362,10 @@ class NetDev(Dev):
|
||||
def getPeriod(self):
|
||||
return self.period
|
||||
|
||||
def send_be_creditlimit(self, credit, period):
|
||||
msg = packMsg('netif_be_creditlimit_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'netif_handle' : self.vif,
|
||||
'credit_bytes' : credit,
|
||||
'period_usec' : period })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
# todo: check return status
|
||||
|
||||
def reportStatus(self, resp=False):
|
||||
msg = packMsg('netif_fe_interface_status_t',
|
||||
{ 'handle' : self.vif,
|
||||
'status' : self.status,
|
||||
'evtchn' : self.getEventChannelFrontend(),
|
||||
'domid' : self.backendDomain,
|
||||
'mac' : self.mac })
|
||||
if resp:
|
||||
self.frontendChannel.writeResponse(msg)
|
||||
else:
|
||||
self.frontendChannel.writeRequest(msg)
|
||||
|
||||
def interfaceChanged(self):
|
||||
"""Notify the front-end that a device has been added or removed.
|
||||
"""
|
||||
self.reportStatus()
|
||||
pass
|
||||
|
||||
class NetifController(DevController):
|
||||
"""Network interface controller. Handles all network devices for a domain.
|
||||
@@ -473,25 +373,9 @@ class NetifController(DevController):
|
||||
|
||||
def __init__(self, vm, recreate=False):
|
||||
DevController.__init__(self, vm, recreate=recreate)
|
||||
self.channel = None
|
||||
self.rcvr = None
|
||||
self.channel = None
|
||||
|
||||
def initController(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.channel = self.getChannel()
|
||||
# Register our handlers for incoming requests.
|
||||
self.rcvr = CtrlMsgRcvr(self.channel)
|
||||
self.rcvr.addHandler(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_DRIVER_STATUS,
|
||||
self.recv_fe_driver_status)
|
||||
self.rcvr.addHandler(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_INTERFACE_STATUS,
|
||||
self.recv_fe_interface_status)
|
||||
self.rcvr.addHandler(CMSG_NETIF_FE,
|
||||
CMSG_NETIF_FE_INTERFACE_CONNECT,
|
||||
self.recv_fe_interface_connect)
|
||||
self.rcvr.registerChannel()
|
||||
if reboot:
|
||||
self.rebootDevices()
|
||||
|
||||
@@ -501,8 +385,6 @@ class NetifController(DevController):
|
||||
self.destroyed = True
|
||||
log.debug("Destroying netif domain=%d", self.getDomain())
|
||||
self.destroyDevices(reboot=reboot)
|
||||
if self.rcvr:
|
||||
self.rcvr.deregisterChannel()
|
||||
|
||||
def sxpr(self):
|
||||
val = ['netif', ['dom', self.getDomain()]]
|
||||
@@ -524,57 +406,3 @@ class NetifController(DevController):
|
||||
|
||||
dev = self.devices[vif]
|
||||
return dev.setCreditLimit(credit, period)
|
||||
|
||||
def recv_fe_driver_status(self, msg):
|
||||
msg = packMsg('netif_fe_driver_status_t',
|
||||
{ 'status' : NETIF_DRIVER_STATUS_UP,
|
||||
## FIXME: max_handle should be max active interface id
|
||||
'max_handle' : self.getDeviceCount()
|
||||
#'max_handle' : self.getMaxDeviceId()
|
||||
})
|
||||
# Two ways of doing it:
|
||||
# 1) front-end requests driver status, we reply with the interface count,
|
||||
# front-end polls the interfaces,
|
||||
# front-end checks they are all up
|
||||
# 2) front-end requests driver status, we reply (with anything),
|
||||
# we notify the interfaces,
|
||||
# we notify driver status up with the count
|
||||
# front-end checks they are all up
|
||||
#
|
||||
# We really want to use 1), but at the moment the xenU kernel panics
|
||||
# in that mode, so we're sticking to 2) for now.
|
||||
resp = False
|
||||
if resp:
|
||||
self.channel.writeResponse(msg)
|
||||
else:
|
||||
for dev in self.devices.values():
|
||||
dev.reportStatus()
|
||||
self.channel.writeRequest(msg)
|
||||
return resp
|
||||
|
||||
def recv_fe_interface_status(self, msg):
|
||||
val = unpackMsg('netif_fe_interface_status_t', msg)
|
||||
vif = val['handle']
|
||||
dev = self.findDevice(vif)
|
||||
if dev:
|
||||
dev.reportStatus(resp=True)
|
||||
else:
|
||||
log.error('Received netif_fe_interface_status for unknown vif: dom=%d vif=%d',
|
||||
self.getDomain(), vif)
|
||||
msg = packMsg('netif_fe_interface_status_t',
|
||||
{ 'handle' : -1,
|
||||
'status' : NETIF_INTERFACE_STATUS_CLOSED,
|
||||
});
|
||||
self.channel.writeResponse(msg)
|
||||
return True
|
||||
|
||||
def recv_fe_interface_connect(self, msg):
|
||||
val = unpackMsg('netif_fe_interface_connect_t', msg)
|
||||
vif = val['handle']
|
||||
dev = self.getDevice(vif)
|
||||
if dev:
|
||||
dev.recv_fe_interface_connect(val)
|
||||
else:
|
||||
log.error('Received netif_fe_interface_connect for unknown vif: dom=%d vif=%d',
|
||||
self.getDomain(), vif)
|
||||
|
||||
@@ -13,9 +13,7 @@ from xen.xend.XendLogging import log
|
||||
from xen.xend.XendRoot import get_component
|
||||
from xen.xend.xenstore import DBVar
|
||||
|
||||
from xen.xend.server import channel
|
||||
from xen.xend.server.controller import CtrlMsgRcvr, Dev, DevController
|
||||
from xen.xend.server.messages import *
|
||||
from xen.xend.server.controller import Dev, DevController
|
||||
|
||||
class TPMifController(DevController):
|
||||
"""TPM interface controller. Handles all TPM devices for a domain.
|
||||
@@ -23,20 +21,15 @@ class TPMifController(DevController):
|
||||
|
||||
def __init__(self, vm, recreate=False):
|
||||
DevController.__init__(self, vm, recreate=recreate)
|
||||
self.rcvr = None
|
||||
self.channel = None
|
||||
|
||||
def initController(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.channel = self.getChannel()
|
||||
|
||||
def destroyController(self, reboot=False):
|
||||
"""Destroy the controller and all devices.
|
||||
"""
|
||||
self.destroyed = True
|
||||
self.destroyDevices(reboot=reboot)
|
||||
if self.rcvr:
|
||||
self.rcvr.deregisterChannel()
|
||||
|
||||
def sxpr(self):
|
||||
val = ['tpmif', ['dom', self.getDomain()]]
|
||||
|
||||
@@ -9,9 +9,7 @@ from xen.xend.XendLogging import log
|
||||
from xen.xend.XendError import XendError
|
||||
from xen.xend.xenstore import DBVar
|
||||
|
||||
from xen.xend.server import channel
|
||||
from xen.xend.server.controller import Dev, DevController
|
||||
from xen.xend.server.messages import *
|
||||
|
||||
class UsbBackend:
|
||||
"""Handler for the 'back-end' channel to a USB device driver domain
|
||||
@@ -25,40 +23,16 @@ class UsbBackend:
|
||||
self.connecting = False
|
||||
self.frontendDomain = self.controller.getDomain()
|
||||
self.backendDomain = dom
|
||||
self.frontendChannel = None
|
||||
self.backendChannel = None
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.frontendChannel = self.controller.getChannel()
|
||||
cf = channel.channelFactory()
|
||||
self.backendChannel = cf.openChannel(self.backendDomain)
|
||||
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return ('<UsbifBackend frontend=%d backend=%d id=%d>'
|
||||
% (self.frontendDomain,
|
||||
self.backendDomain,
|
||||
self.id))
|
||||
|
||||
def closeEvtchn(self):
|
||||
if self.evtchn:
|
||||
channel.eventChannelClose(self.evtchn)
|
||||
self.evtchn = None
|
||||
|
||||
def openEvtchn(self):
|
||||
self.evtchn = channel.eventChannel(self.backendDomain, self.frontendDomain)
|
||||
|
||||
def getEventChannelBackend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port1']
|
||||
return val
|
||||
|
||||
def getEventChannelFrontend(self):
|
||||
val = 0
|
||||
if self.evtchn:
|
||||
val = self.evtchn['port2']
|
||||
return val
|
||||
|
||||
def connect(self, recreate=False):
|
||||
"""Connect the controller to the usbif control interface.
|
||||
|
||||
@@ -67,78 +41,14 @@ class UsbBackend:
|
||||
log.debug("Connecting usbif %s", str(self))
|
||||
if recreate or self.connected or self.connecting:
|
||||
pass
|
||||
else:
|
||||
self.send_be_create()
|
||||
|
||||
def send_be_create(self):
|
||||
msg = packMsg('usbif_be_create_t',
|
||||
{ 'domid' : self.frontendDomain })
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
val = unpackMsg('usbif_be_create_t', msg)
|
||||
log.debug('>UsbifBackendController>respond_be_create> %s', str(val))
|
||||
self.connected = True
|
||||
|
||||
def destroy(self, reboot=False):
|
||||
"""Disconnect from the usbif control interface and destroy it.
|
||||
"""
|
||||
self.destroyed = True
|
||||
self.send_be_disconnect()
|
||||
self.send_be_destroy()
|
||||
self.closeEvtchn()
|
||||
|
||||
def send_be_disconnect(self):
|
||||
log.debug('>UsbifBackendController>send_be_disconnect> %s', str(self))
|
||||
msg = packMsg('usbif_be_disconnect_t',
|
||||
{ 'domid' : self.frontendDomain })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
|
||||
def send_be_destroy(self, response=None):
|
||||
log.debug('>UsbifBackendController>send_be_destroy> %s', str(self))
|
||||
msg = packMsg('usbif_be_destroy_t',
|
||||
{ 'domid' : self.frontendDomain })
|
||||
self.backendChannel.requestResponse(msg)
|
||||
#todo: check return status
|
||||
|
||||
|
||||
def connectInterface(self, val):
|
||||
self.openEvtchn()
|
||||
log.debug(">UsbifBackendController>connectInterface> connecting usbif to event channel %s ports=%d:%d",
|
||||
str(self),
|
||||
self.getEventChannelBackend(),
|
||||
self.getEventChannelFrontend())
|
||||
msg = packMsg('usbif_be_connect_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'evtchn' : self.getEventChannelBackend(),
|
||||
'shmem_frame' : val['shmem_frame'],
|
||||
'bandwidth' : 500 # XXX fix bandwidth!
|
||||
})
|
||||
msg = self.backendChannel.requestResponse(msg)
|
||||
self.respond_be_connect(msg)
|
||||
|
||||
def respond_be_connect(self, msg):
|
||||
"""Response handler for a be_connect message.
|
||||
|
||||
@param msg: message
|
||||
@type msg: xu message
|
||||
"""
|
||||
val = unpackMsg('usbif_be_connect_t', msg)
|
||||
log.debug('>UsbifBackendController>respond_be_connect> %s, %s', str(self), str(val))
|
||||
self.send_fe_interface_status_changed()
|
||||
log.debug(">UsbifBackendController> Successfully connected USB interface for domain %d" % self.frontendDomain)
|
||||
self.controller.claim_ports()
|
||||
|
||||
def send_fe_interface_status_changed(self):
|
||||
msg = packMsg('usbif_fe_interface_status_changed_t',
|
||||
{ 'status' : USBIF_INTERFACE_STATUS_CONNECTED,
|
||||
'domid' : self.backendDomain,
|
||||
'evtchn' : self.getEventChannelFrontend(),
|
||||
'bandwidth' : 500,
|
||||
'num_ports' : len(self.controller.devices)
|
||||
})
|
||||
self.frontendChannel.writeRequest(msg)
|
||||
|
||||
def interfaceChanged(self):
|
||||
self.send_fe_interface_status_changed()
|
||||
pass
|
||||
|
||||
|
||||
class UsbDev(Dev):
|
||||
@@ -153,17 +63,12 @@ class UsbDev(Dev):
|
||||
self.port = id
|
||||
self.path = None
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = None
|
||||
self.backendDomain = 0
|
||||
self.backendChannel = None
|
||||
self.configure(self.config, recreate=recreate)
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.frontendDomain = self.getDomain()
|
||||
self.frontendChannel = self.getChannel()
|
||||
backend = self.getBackend()
|
||||
self.backendChannel = backend.backendChannel
|
||||
|
||||
def configure(self, config, change=False, recreate=False):
|
||||
if change:
|
||||
@@ -204,7 +109,6 @@ class UsbDev(Dev):
|
||||
"""
|
||||
self.destroyed = True
|
||||
log.debug("Destroying usb domain=%d id=%s", self.frontendDomain, self.id)
|
||||
self.send_be_release_port()
|
||||
if change:
|
||||
self.interfaceChanged()
|
||||
|
||||
@@ -220,27 +124,6 @@ class UsbDev(Dev):
|
||||
"""
|
||||
self.getBackend().connect()
|
||||
|
||||
def send_be_claim_port(self):
|
||||
log.debug(">UsbifBackendController>send_be_claim_port> about to claim port %s" % self.path)
|
||||
msg = packMsg('usbif_be_claim_port_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'path' : self.path,
|
||||
'usbif_port' : self.port,
|
||||
'status' : 0})
|
||||
self.backendChannel.writeRequest(msg)
|
||||
log.debug(">UsbifBackendController> Claim port completed")
|
||||
# No need to add any callbacks, since the guest polls its virtual ports
|
||||
# anyhow, somewhat like a UHCI controller ;-)
|
||||
|
||||
def send_be_release_port(self):
|
||||
msg = packMsg('usbif_be_release_port_t',
|
||||
{ 'domid' : self.frontendDomain,
|
||||
'path' : self.path })
|
||||
self.backendChannel.writeRequest(msg)
|
||||
log.debug(">UsbifBackendController> Release port completed")
|
||||
# No need to add any callbacks, since the guest polls its virtual ports
|
||||
# anyhow, somewhat like a UHCI controller ;-)
|
||||
|
||||
class UsbifController(DevController):
|
||||
"""USB device interface controller. Handles all USB devices
|
||||
for a domain.
|
||||
@@ -252,18 +135,9 @@ class UsbifController(DevController):
|
||||
DevController.__init__(self, vm, recreate=recreate)
|
||||
self.backends = {}
|
||||
self.backendId = 0
|
||||
self.rcvr = None
|
||||
|
||||
def init(self, recreate=False, reboot=False):
|
||||
self.destroyed = False
|
||||
self.rcvr = CtrlMsgRcvr(self.getChannel())
|
||||
self.rcvr.addHandler(CMSG_USBIF_FE,
|
||||
CMSG_USBIF_FE_DRIVER_STATUS_CHANGED,
|
||||
self.recv_fe_driver_status_changed)
|
||||
self.rcvr.addHandler(CMSG_USBIF_FE,
|
||||
CMSG_USBIF_FE_INTERFACE_CONNECT,
|
||||
self.recv_fe_interface_connect)
|
||||
self.rcvr.registerChannel()
|
||||
if reboot:
|
||||
self.rebootBackends()
|
||||
self.rebootDevices()
|
||||
@@ -283,8 +157,6 @@ class UsbifController(DevController):
|
||||
log.debug("Destroying blkif domain=%d", self.getDomain())
|
||||
self.destroyDevices(reboot=reboot)
|
||||
self.destroyBackends(reboot=reboot)
|
||||
if self.rcvr:
|
||||
self.rcvr.deregisterChannel()
|
||||
|
||||
def rebootBackends(self):
|
||||
for backend in self.backends.values():
|
||||
@@ -311,40 +183,3 @@ class UsbifController(DevController):
|
||||
def destroyBackends(self, reboot=False):
|
||||
for backend in self.backends.values():
|
||||
backend.destroy(reboot=reboot)
|
||||
|
||||
def recv_fe_driver_status_changed(self, msg):
|
||||
val = unpackMsg('usbif_fe_driver_status_changed_t', msg)
|
||||
log.debug('>UsbifController>recv_fe_driver_status_changed> %s', str(val))
|
||||
#todo: FIXME: For each backend?
|
||||
msg = packMsg('usbif_fe_interface_status_changed_t',
|
||||
{ 'status' : USBIF_INTERFACE_STATUS_DISCONNECTED,
|
||||
'domid' : 0, #todo: FIXME: should be domid of backend
|
||||
'evtchn' : 0 })
|
||||
msg = self.getChannel().requestResponse(msg)
|
||||
self.disconnected_resp(msg)
|
||||
|
||||
def disconnected_resp(self, msg):
|
||||
val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
|
||||
if val['status'] != USBIF_INTERFACE_STATUS_DISCONNECTED:
|
||||
log.error(">UsbifController>disconnected_resp> unexpected status change")
|
||||
else:
|
||||
log.debug(">UsbifController>disconnected_resp> interface disconnected OK")
|
||||
|
||||
def recv_fe_interface_connect(self, msg):
|
||||
val = unpackMsg('usbif_fe_interface_status_changed_t', msg)
|
||||
log.debug(">UsbifController>recv_fe_interface_connect> notifying backend")
|
||||
#todo: FIXME: generalise to more than one backend.
|
||||
id = 0
|
||||
backend = self.getBackendById(id)
|
||||
if backend:
|
||||
try:
|
||||
backend.connectInterface(val)
|
||||
except IOError, ex:
|
||||
log.error("Exception connecting backend: %s", ex)
|
||||
else:
|
||||
log.error('interface connect on unknown interface: id=%d', id)
|
||||
|
||||
def claim_ports(self):
|
||||
for dev in self.devices.values():
|
||||
dev.send_be_claim_port()
|
||||
|
||||