debuggers.hg

view tools/python/xen/xend/server/netif.py @ 3603:30ee9c427a5b

bitkeeper revision 1.1159.212.46 (41f952dcjUM7tDOqBgJxR2_d9qUROA)

Merge
author mwilli2@equilibrium.research
date Thu Jan 27 20:45:16 2005 +0000 (2005-01-27)
parents f5a6b3a8c9b9 2e60786262c4
children ef59b38283a5 bbe8541361dd
line source
1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
2 """Support for virtual network interfaces.
3 """
5 import random
7 from twisted.internet import defer
9 from xen.xend import sxp
10 from xen.xend import Vifctl
11 from xen.xend.XendError import XendError
12 from xen.xend.XendLogging import log
13 from xen.xend import XendVnet
14 from xen.xend.XendRoot import get_component
16 import channel
17 import controller
18 from messages import *
20 class NetifBackendController(controller.BackendController):
21 """Handler for the 'back-end' channel to a network device driver domain.
22 """
24 def __init__(self, ctrl, dom):
25 controller.BackendController.__init__(self, ctrl, dom)
26 self.addMethod(CMSG_NETIF_BE,
27 CMSG_NETIF_BE_DRIVER_STATUS,
28 self.recv_be_driver_status)
29 self.registerChannel()
31 def recv_be_driver_status(self, msg, req):
32 val = unpackMsg('netif_be_driver_status_t', msg)
33 status = val['status']
35 class NetifBackendInterface(controller.BackendInterface):
36 """Handler for the 'back-end' channel to a network device driver domain
37 on behalf of a front-end domain.
39 Each network device is handled separately, so we add no functionality
40 here.
41 """
43 pass
45 class NetifControllerFactory(controller.SplitControllerFactory):
46 """Factory for creating network interface controllers.
47 """
49 def __init__(self):
50 controller.SplitControllerFactory.__init__(self)
52 def createController(self, dom):
53 """Create a network interface controller for a domain.
55 @param dom: domain
56 @return: netif controller
57 """
58 return NetifController(self, dom)
60 def createBackendController(self, dom):
61 """Create a network device backend controller.
63 @param dom: backend domain
64 @return: backend controller
65 """
66 return NetifBackendController(self, dom)
68 def createBackendInterface(self, ctrl, dom, handle):
69 """Create a network device backend interface.
71 @param ctrl: controller
72 @param dom: backend domain
73 @param handle: interface handle
74 @return: backend interface
75 """
76 return NetifBackendInterface(ctrl, dom, handle)
78 def getDomainDevices(self, dom):
79 """Get the network devices for a domain.
81 @param dom: domain
82 @return: netif controller list
83 """
84 netif = self.getControllerByDom(dom)
85 return (netif and netif.getDevices()) or []
87 def getDomainDevice(self, dom, vif):
88 """Get a virtual network interface device for a domain.
90 @param dom: domain
91 @param vif: virtual interface index
92 @return: NetDev
93 """
94 netif = self.getControllerByDom(dom)
95 return (netif and netif.getDevice(vif)) or None
97 class NetDev(controller.SplitDev):
98 """Info record for a network device.
99 """
101 def __init__(self, vif, ctrl, config):
102 controller.SplitDev.__init__(self, vif, ctrl)
103 self.vif = vif
104 self.evtchn = None
105 self.configure(config)
106 self.status = NETIF_INTERFACE_STATUS_DISCONNECTED
108 def _get_config_mac(self, config):
109 vmac = sxp.child_value(config, 'mac')
110 if not vmac: return None
111 mac = [ int(x, 16) for x in vmac.split(':') ]
112 if len(mac) != 6: raise XendError("invalid mac")
113 return mac
115 def _get_config_ipaddr(self, config):
116 ips = sxp.children(config, elt='ip')
117 if ips:
118 val = []
119 for ipaddr in ips:
120 val.append(sxp.child0(ipaddr))
121 else:
122 val = None
123 return val
125 def configure(self, config, change=0):
126 if change:
127 return self.reconfigure(config)
128 self.config = config
129 self.mac = None
130 self.bridge = None
131 self.script = None
132 self.ipaddr = []
134 mac = self._get_config_mac(config)
135 if mac is None:
136 raise XendError("invalid mac")
137 self.mac = mac
138 self.bridge = sxp.child_value(config, 'bridge')
139 self.script = sxp.child_value(config, 'script')
140 self.ipaddr = self._get_config_ipaddr(config) or []
142 try:
143 xd = get_component('xen.xend.XendDomain')
144 self.backendDomain = int(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
145 except:
146 raise XendError('invalid backend domain')
148 def reconfigure(self, config):
149 """Reconfigure the interface with new values.
150 Not all configuration parameters can be changed:
151 bridge, script and ip addresses can,
152 backend and mac cannot.
154 To leave a parameter unchanged, omit it from the changes.
156 @param config configuration changes
157 @return updated interface configuration
158 @raise XendError on errors
159 """
160 changes = {}
161 mac = self._get_config_mac(config)
162 bridge = sxp.child_value(config, 'bridge')
163 script = sxp.child_value(config, 'script')
164 ipaddr = self._get_config_ipaddr(config)
165 xd = get_component('xen.xend.XendDomain')
166 backendDomain = str(xd.domain_lookup(sxp.child_value(config, 'backend', '0')).id)
167 if (mac is not None) and (mac != self.mac):
168 raise XendError("cannot change mac")
169 if (backendDomain is not None) and (backendDomain != str(self.backendDomain)):
170 raise XendError("cannot change backend")
171 if (bridge is not None) and (bridge != self.bridge):
172 changes['bridge'] = bridge
173 if (script is not None) and (script != self.script):
174 changes['script'] = script
175 if (ipaddr is not None) and (ipaddr != self.ipaddr):
176 changes['ipaddr'] = ipaddr
178 if changes:
179 self.vifctl("down")
180 for (k, v) in changes.items():
181 setattr(self, k, v)
182 self.config = sxp.merge(config, self.config)
183 self.vifctl("up")
184 return self.config
186 def sxpr(self):
187 vif = str(self.vif)
188 mac = self.get_mac()
189 val = ['vif',
190 ['idx', self.idx],
191 ['vif', vif],
192 ['mac', mac]]
193 if self.bridge:
194 val.append(['bridge', self.bridge])
195 if self.script:
196 val.append(['script', self.script])
197 for ip in self.ipaddr:
198 val.append(['ip', ip])
199 if self.evtchn:
200 val.append(['evtchn',
201 self.evtchn['port1'],
202 self.evtchn['port2']])
203 if self.index is not None:
204 val.append(['index', self.index])
205 return val
207 def get_vifname(self):
208 """Get the virtual interface device name.
209 """
210 return "vif%d.%d" % (self.controller.dom, self.vif)
212 def get_mac(self):
213 """Get the MAC address as a string.
214 """
215 return ':'.join(map(lambda x: "%02x" % x, self.mac))
217 def vifctl_params(self, vmname=None):
218 """Get the parameters to pass to vifctl.
219 """
220 dom = self.controller.dom
221 if vmname is None:
222 xd = get_component('xen.xend.XendDomain')
223 try:
224 vm = xd.domain_lookup(dom)
225 vmname = vm.name
226 except:
227 vmname = 'DOM%d' % dom
228 return { 'domain': vmname,
229 'vif' : self.get_vifname(),
230 'mac' : self.get_mac(),
231 'bridge': self.bridge,
232 'script': self.script,
233 'ipaddr': self.ipaddr, }
235 def vifctl(self, op, vmname=None):
236 """Bring the device up or down.
237 The vmname is needed when bringing a device up for a new domain because
238 the domain is not yet in the table so we can't look its name up.
240 @param op: operation name (up, down)
241 @param vmname: vmname
242 """
243 Vifctl.vifctl(op, **self.vifctl_params(vmname=vmname))
244 vnet = XendVnet.instance().vnet_of_bridge(self.bridge)
245 if vnet:
246 vnet.vifctl(op, self.get_vifname(), self.get_mac())
248 def attach(self):
249 d = self.send_be_create()
250 d.addCallback(self.respond_be_create)
251 return d
253 def getEventChannelBackend(self):
254 val = 0
255 if self.evtchn:
256 val = self.evtchn['port1']
257 return val
259 def getEventChannelFrontend(self):
260 val = 0
261 if self.evtchn:
262 val = self.evtchn['port2']
263 return val
265 def send_be_create(self):
266 d = defer.Deferred()
267 msg = packMsg('netif_be_create_t',
268 { 'domid' : self.controller.dom,
269 'netif_handle' : self.vif,
270 'mac' : self.mac })
271 self.getBackendInterface().writeRequest(msg, response=d)
272 return d
274 def respond_be_create(self, msg):
275 val = unpackMsg('netif_be_create_t', msg)
276 return self
278 def destroy(self, change=0):
279 """Destroy the device's resources and disconnect from the back-end
280 device controller. If 'change' is true notify the front-end interface.
282 @param change: change flag
283 """
284 self.status = NETIF_INTERFACE_STATUS_CLOSED
285 def cb_destroy(val):
286 self.send_be_destroy()
287 self.getBackendInterface().close()
288 if change:
289 self.reportStatus()
290 log.debug("Destroying vif domain=%d vif=%d", self.controller.dom, self.vif)
291 self.vifctl('down')
292 d = self.send_be_disconnect()
293 d.addCallback(cb_destroy)
295 def send_be_disconnect(self):
296 d = defer.Deferred()
297 msg = packMsg('netif_be_disconnect_t',
298 { 'domid' : self.controller.dom,
299 'netif_handle' : self.vif })
300 self.getBackendInterface().writeRequest(msg, response=d)
301 return d
303 def send_be_destroy(self, response=None):
304 msg = packMsg('netif_be_destroy_t',
305 { 'domid' : self.controller.dom,
306 'netif_handle' : self.vif })
307 self.controller.delDevice(self.vif)
308 self.getBackendInterface().writeRequest(msg, response=response)
310 def recv_fe_interface_connect(self, val, req):
311 if not req: return
312 self.evtchn = channel.eventChannel(self.backendDomain, self.controller.dom)
313 msg = packMsg('netif_be_connect_t',
314 { 'domid' : self.controller.dom,
315 'netif_handle' : self.vif,
316 'evtchn' : self.getEventChannelBackend(),
317 'tx_shmem_frame' : val['tx_shmem_frame'],
318 'rx_shmem_frame' : val['rx_shmem_frame'] })
319 d = defer.Deferred()
320 d.addCallback(self.respond_be_connect)
321 self.getBackendInterface().writeRequest(msg, response=d)
323 def respond_be_connect(self, msg):
324 val = unpackMsg('netif_be_connect_t', msg)
325 dom = val['domid']
326 vif = val['netif_handle']
327 self.status = NETIF_INTERFACE_STATUS_CONNECTED
328 self.reportStatus()
330 def reportStatus(self, resp=0):
331 msg = packMsg('netif_fe_interface_status_t',
332 { 'handle' : self.vif,
333 'status' : self.status,
334 'evtchn' : self.getEventChannelFrontend(),
335 'domid' : self.backendDomain,
336 'mac' : self.mac })
337 if resp:
338 self.controller.writeResponse(msg)
339 else:
340 self.controller.writeRequest(msg)
342 def interfaceChanged(self):
343 """Notify the font-end that a device has been added or removed.
344 """
345 self.reportStatus()
347 class NetifController(controller.SplitController):
348 """Network interface controller. Handles all network devices for a domain.
349 """
351 def __init__(self, factory, dom):
352 controller.SplitController.__init__(self, factory, dom)
353 self.devices = {}
354 self.addMethod(CMSG_NETIF_FE,
355 CMSG_NETIF_FE_DRIVER_STATUS,
356 self.recv_fe_driver_status)
357 self.addMethod(CMSG_NETIF_FE,
358 CMSG_NETIF_FE_INTERFACE_STATUS,
359 self.recv_fe_interface_status)
360 self.addMethod(CMSG_NETIF_FE,
361 CMSG_NETIF_FE_INTERFACE_CONNECT,
362 self.recv_fe_interface_connect)
363 self.registerChannel()
365 def sxpr(self):
366 val = ['netif', ['dom', self.dom]]
367 return val
369 def lostChannel(self):
370 """Method called when the channel has been lost.
371 """
372 controller.Controller.lostChannel(self)
374 def addDevice(self, vif, config):
375 """Add a network interface.
377 @param vif: device index
378 @param config: device configuration
379 @return: device
380 """
381 if vif in self.devices:
382 raise XendError('device exists:' + str(vif))
383 dev = NetDev(vif, self, config)
384 self.devices[vif] = dev
385 return dev
387 def destroy(self):
388 """Destroy the controller and all devices.
389 """
390 self.destroyDevices()
392 def destroyDevices(self):
393 """Destroy all devices.
394 """
395 for dev in self.getDevices():
396 dev.destroy()
398 def attachDevice(self, vif, config, recreate=0):
399 """Attach a network device.
401 @param vif: interface index
402 @param config: device configuration
403 @param recreate: recreate flag (true after xend restart)
404 @return: deferred
405 """
406 dev = self.addDevice(vif, config)
407 if recreate:
408 d = defer.succeed(dev)
409 else:
410 d = dev.attach()
411 return d
413 def recv_fe_driver_status(self, msg, req):
414 if not req: return
415 print
416 print 'recv_fe_driver_status>'
417 msg = packMsg('netif_fe_driver_status_t',
418 { 'status' : NETIF_DRIVER_STATUS_UP,
419 ## FIXME: max_handle should be max active interface id
420 'max_handle' : len(self.devices)
421 #'max_handle' : self.getMaxDeviceIdx()
422 })
423 # Two ways of doing it:
424 # 1) front-end requests driver status, we reply with the interface count,
425 # front-end polls the interfaces,
426 # front-end checks they are all up
427 # 2) front-end requests driver status, we reply (with anything),
428 # we notify the interfaces,
429 # we notify driver status up with the count
430 # front-end checks they are all up
431 #
432 # We really want to use 1), but at the moment the xenU kernel panics
433 # in that mode, so we're sticking to 2) for now.
434 resp = 0
435 if resp:
436 self.writeResponse(msg)
437 else:
438 for dev in self.devices.values():
439 dev.reportStatus()
440 self.writeRequest(msg)
441 return resp
443 def recv_fe_interface_status(self, msg, req):
444 if not req: return
445 print
446 val = unpackMsg('netif_fe_interface_status_t', msg)
447 print "recv_fe_interface_status>", val
448 vif = val['handle']
449 dev = self.findDevice(vif)
450 if dev:
451 print 'recv_fe_interface_status>', 'dev=', dev
452 dev.reportStatus(resp=1)
453 else:
454 msg = packMsg('netif_fe_interface_status_t',
455 { 'handle' : -1,
456 'status' : NETIF_INTERFACE_STATUS_CLOSED,
457 });
458 print 'recv_fe_interface_status>', 'no dev, returning -1'
459 self.writeResponse(msg)
460 return 1
463 def recv_fe_interface_connect(self, msg, req):
464 val = unpackMsg('netif_fe_interface_connect_t', msg)
465 vif = val['handle']
466 print
467 print "recv_fe_interface_connect", val
468 dev = self.getDevice(vif)
469 if dev:
470 dev.recv_fe_interface_connect(val, req)
471 else:
472 log.error('Received netif_fe_interface_connect for unknown vif: dom=%d vif=%d',
473 self.dom, vif)