direct-io.hg

view tools/python/xen/xend/XendPIF.py @ 15001:32b575a311ef

Fix the fix for XendPIF

signed-off-by: Tom Wilkie <tom.wilkie@gmail.com>
author Tom Wilkie <tom.wilkie@gmail.com>
date Wed May 02 16:43:45 2007 +0100 (2007-05-02)
parents da02af7b55b9
children
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (c) 2006 Xensource Inc.
16 #============================================================================
18 import commands
19 import logging
20 import os
21 import re
22 from xen.xend import uuid as genuuid
23 from xen.xend import XendAPIStore
24 from xen.xend.XendBase import XendBase
25 from xen.xend.XendPIFMetrics import XendPIFMetrics
26 from xen.xend.XendError import *
28 log = logging.getLogger("xend.XendPIF")
29 log.setLevel(logging.TRACE)
31 MAC_RE = re.compile(':'.join(['[0-9a-f]{2}'] * 6))
32 IP_IFACE_RE = re.compile(r'^\d+: (\w+):.*mtu (\d+) .* link/\w+ ([0-9a-f:]+)')
34 def linux_phy_to_virt(pif_name):
35 return 'eth' + re.sub(r'^[a-z]+', '', pif_name)
37 def linux_get_phy_ifaces():
38 """Returns a list of physical interfaces.
40 Identifies PIFs as those that have a interface name starting with 'p'
41 and have the fake 'fe:ff:ff:ff:ff:ff' MAC address.
43 See /etc/xen/scripts/network-bridge for how the devices are renamed.
45 @rtype: array of 3-element tuple (name, mtu, mac)
46 """
48 ip_cmd = 'ip -o link show'
49 rc, output = commands.getstatusoutput(ip_cmd)
50 ifaces = {}
51 phy_ifaces = []
52 if rc == 0:
53 # parse all interfaces into (name, mtu, mac)
54 for line in output.split('\n'):
55 has_if = re.search(IP_IFACE_RE, line)
56 if has_if:
57 ifaces[has_if.group(1)] = has_if.groups()
59 # resolve pifs' mac addresses
60 for name, mtu, mac in ifaces.values():
61 if name[0] == 'p' and mac == 'fe:ff:ff:ff:ff:ff':
62 bridged_ifname = linux_phy_to_virt(name)
63 bridged_if = ifaces.get(bridged_ifname)
64 if bridged_if:
65 bridged_mac = bridged_if[2]
66 phy_ifaces.append((name, int(mtu), bridged_mac))
68 return phy_ifaces
70 def linux_set_mac(iface, mac):
71 if not re.search(MAC_RE, mac):
72 return False
74 ip_mac_cmd = 'ip link set %s addr %s' % \
75 (linux_phy_to_virt(iface), mac)
76 rc, output = commands.getstatusoutput(ip_mac_cmd)
77 if rc == 0:
78 return True
80 return False
82 def linux_set_mtu(iface, mtu):
83 try:
84 ip_mtu_cmd = 'ip link set %s mtu %d' % \
85 (linux_phy_to_virt(iface), int(mtu))
86 rc, output = commands.getstatusoutput(ip_mtu_cmd)
87 if rc == 0:
88 return True
89 return False
90 except ValueError:
91 return False
93 def _create_VLAN(dev, vlan):
94 rc, _ = commands.getstatusoutput('vconfig add %s %d' %
95 (dev, vlan))
96 if rc != 0:
97 return False
99 rc, _ = commands.getstatusoutput('ifconfig %s.%d up' %
100 (dev, vlan))
101 return rc == 0
103 def _destroy_VLAN(dev, vlan):
104 rc, _ = commands.getstatusoutput('ifconfig %s.%d down' %
105 (dev, vlan))
106 if rc != 0:
107 return False
109 rc, _ = commands.getstatusoutput('vconfig rem %s.%d' %
110 (dev, vlan))
111 return rc == 0
113 class XendPIF(XendBase):
114 """Representation of a Physical Network Interface."""
116 def getClass(self):
117 return "PIF"
119 def getAttrRO(self):
120 attrRO = ['network',
121 'host',
122 'metrics',
123 'device',
124 'VLAN']
125 return XendBase.getAttrRO() + attrRO
127 def getAttrRW(self):
128 attrRW = ['MAC',
129 'MTU']
130 return XendBase.getAttrRW() + attrRW
132 def getAttrInst(self):
133 attrInst = ['network',
134 'device',
135 'MAC',
136 'MTU',
137 'VLAN']
138 return attrInst
140 def getMethods(self):
141 methods = ['plug',
142 'unplug',
143 'destroy']
144 return XendBase.getMethods() + methods
146 def getFuncs(self):
147 funcs = ['create_VLAN']
148 return XendBase.getFuncs() + funcs
150 getClass = classmethod(getClass)
151 getAttrRO = classmethod(getAttrRO)
152 getAttrRW = classmethod(getAttrRW)
153 getAttrInst = classmethod(getAttrInst)
154 getMethods = classmethod(getMethods)
155 getFuncs = classmethod(getFuncs)
157 def create_phy(self, network_uuid, device,
158 MAC, MTU):
159 """
160 Called when a new physical PIF is found
161 Could be a VLAN...
162 """
163 # Create new uuids
164 pif_uuid = genuuid.createString()
165 metrics_uuid = genuuid.createString()
167 # Create instances
168 metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
170 # Is this a VLAN?
171 VLANdot = device.split(".")
172 VLANcolon = device.split(":")
174 if len(VLANdot) > 1:
175 VLAN = VLANdot[1]
176 device = VLANdot[0]
177 elif len(VLANcolon) > 1:
178 VLAN = VLANcolon[1]
179 device = VLANcolon[0]
180 else:
181 VLAN = -1
183 record = {
184 'network': network_uuid,
185 'device': device,
186 'MAC': MAC,
187 'MTU': MTU,
188 'VLAN': VLAN
189 }
190 pif = XendPIF(record, pif_uuid, metrics_uuid)
192 return pif_uuid
194 def recreate(self, record, uuid):
195 """Called on xend start / restart"""
196 pif_uuid = uuid
197 metrics_uuid = record['metrics']
199 # Create instances
200 metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
201 pif = XendPIF(record, pif_uuid, metrics_uuid)
203 # If physical PIF, check exists
204 # If VLAN, create if not exist
205 ifs = [dev for dev, _1, _2 in linux_get_phy_ifaces()]
206 if pif.get_VLAN() == -1:
207 if pif.get_device() not in ifs:
208 XendBase.destroy(pif)
209 metrics.destroy()
210 return None
211 else:
212 if pif.get_interface_name() not in ifs:
213 _create_VLAN(pif.get_device(), pif.get_VLAN())
214 pif.plug()
216 return pif_uuid
218 def create_VLAN(self, device, network_uuid, host_ref, vlan):
219 """Exposed via API - create a new VLAN from existing VIF"""
221 ifs = [name for name, _, _ in linux_get_phy_ifaces()]
223 vlan = int(vlan)
225 # Check VLAN tag is valid
226 if vlan < 0 or vlan >= 4096:
227 raise VLANTagInvalid(vlan)
229 # Check device exists
230 if device not in ifs:
231 raise InvalidDeviceError(device)
233 # Check VLAN doesn't already exist
234 if "%s.%d" % (device, vlan) in ifs:
235 raise DeviceExistsError("%s.%d" % (device, vlan))
237 # Check network ref is valid
238 from XendNetwork import XendNetwork
239 if network_uuid not in XendNetwork.get_all():
240 raise InvalidHandleError("Network", network_uuid)
242 # Check host_ref is this host
243 import XendNode
244 if host_ref != XendNode.instance().get_uuid():
245 raise InvalidHandleError("Host", host_ref)
247 # Create the VLAN
248 _create_VLAN(device, vlan)
250 # Create new uuids
251 pif_uuid = genuuid.createString()
252 metrics_uuid = genuuid.createString()
254 # Create the record
255 record = {
256 "device": device,
257 "MAC": '',
258 "MTU": '',
259 "network": network_uuid,
260 "VLAN": vlan
261 }
263 # Create instances
264 metrics = XendPIFMetrics(metrics_uuid, pif_uuid)
265 pif = XendPIF(record, pif_uuid, metrics_uuid)
267 # Not sure if they should be created plugged or not...
268 pif.plug()
270 XendNode.instance().save_PIFs()
271 return pif_uuid
273 create_phy = classmethod(create_phy)
274 recreate = classmethod(recreate)
275 create_VLAN = classmethod(create_VLAN)
277 def __init__(self, record, uuid, metrics_uuid):
278 XendBase.__init__(self, uuid, record)
279 self.metrics = metrics_uuid
281 def plug(self):
282 """Plug the PIF into the network"""
283 network = XendAPIStore.get(self.network,
284 "network")
285 bridge_name = network.get_name_label()
287 from xen.util import Brctl
288 Brctl.vif_bridge_add({
289 "bridge": bridge_name,
290 "vif": self.get_interface_name()
291 })
293 def unplug(self):
294 """Unplug the PIF from the network"""
295 network = XendAPIStore.get(self.network,
296 "network")
297 bridge_name = network.get_name_label()
299 from xen.util import Brctl
300 Brctl.vif_bridge_rem({
301 "bridge": bridge_name,
302 "vif": self.get_interface_name()
303 })
305 def destroy(self):
306 # Figure out if this is a physical device
307 if self.get_interface_name() == \
308 self.get_device():
309 raise PIFIsPhysical()
311 self.unplug()
313 if _destroy_VLAN(self.get_device(), self.get_VLAN()):
314 XendBase.destroy(self)
315 import XendNode
316 XendNode.instance().save_PIFs()
317 else:
318 raise NetworkError("Unable to delete VLAN", self.get_uuid())
320 def get_interface_name(self):
321 if self.get_VLAN() == -1:
322 return self.get_device()
323 else:
324 return "%s.%d" % (self.get_device(), self.get_VLAN())
326 def get_device(self):
327 """
328 This is the base interface.
329 For phy if (VLAN == -1) this is same as
330 if name.
331 For VLANs, this it the bit before the period
332 """
333 return self.device
335 def get_network(self):
336 return self.network
338 def get_host(self):
339 from xen.xend import XendNode
340 return XendNode.instance().get_uuid()
342 def get_metrics(self):
343 return self.metrics
345 def get_MAC(self):
346 return self.MAC
348 def set_MAC(self, new_mac):
349 success = linux_set_mac(self.device, new_mac)
350 if success:
351 self.MAC = new_mac
352 import XendNode
353 XendNode.instance().save_PIFs()
354 return success
356 def get_MTU(self):
357 return self.MTU
359 def set_MTU(self, new_mtu):
360 success = linux_set_mtu(self.device, new_mtu)
361 if success:
362 self.MTU = new_mtu
363 import XendNode
364 XendNode.instance().save_PIFs()
365 return success
367 def get_VLAN(self):
368 return self.VLAN