]>
git.proxmox.com Git - ovs.git/blob - xenserver/opt_xensource_libexec_InterfaceReconfigureVswitch.py
1 # Copyright (c) 2008,2009 Citrix Systems, Inc.
2 # Copyright (c) 2009,2010 Nicira Networks.
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU Lesser General Public License as published
6 # by the Free Software Foundation; version 2.1 only. with the special
7 # exception on linking described in file LICENSE.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Lesser General Public License for more details.
14 from InterfaceReconfigure
import *
18 # Bare Network Devices -- network devices without IP configuration
21 def netdev_down(netdev
):
22 """Bring down a bare network device"""
23 if not netdev_exists(netdev
):
24 log("netdev: down: device %s does not exist, ignoring" % netdev
)
26 run_command(["/sbin/ifconfig", netdev
, 'down'])
28 def netdev_up(netdev
, mtu
=None):
29 """Bring up a bare network device"""
30 if not netdev_exists(netdev
):
31 raise Error("netdev: up: device %s does not exist" % netdev
)
38 run_command(["/sbin/ifconfig", netdev
, 'up'] + mtu
)
44 def pif_currently_in_use(pif
):
45 """Determine if a PIF is currently in use.
47 A PIF is determined to be currently in use if
48 - PIF.currently-attached is true
49 - Any bond master is currently attached
50 - Any VLAN master is currently attached
52 rec
= db().get_pif_record(pif
)
53 if rec
['currently_attached']:
54 log("configure_datapath: %s is currently attached" % (pif_netdev_name(pif
)))
56 for b
in pif_get_bond_masters(pif
):
57 if pif_currently_in_use(b
):
58 log("configure_datapath: %s is in use by BOND master %s" % (pif_netdev_name(pif
),pif_netdev_name(b
)))
60 for v
in pif_get_vlan_masters(pif
):
61 if pif_currently_in_use(v
):
62 log("configure_datapath: %s is in use by VLAN master %s" % (pif_netdev_name(pif
),pif_netdev_name(v
)))
67 # Datapath Configuration
70 def pif_datapath(pif
):
71 """Return the datapath PIF associated with PIF.
72 A non-VLAN PIF is its own datapath PIF, except that a bridgeless PIF has
73 no datapath PIF at all.
74 A VLAN PIF's datapath PIF is its VLAN slave's datapath PIF.
77 return pif_datapath(pif_get_vlan_slave(pif
))
79 pifrec
= db().get_pif_record(pif
)
80 nwrec
= db().get_network_record(pifrec
['network'])
81 if not nwrec
['bridge']:
86 def datapath_get_physical_pifs(pif
):
87 """Return the PIFs for the physical network device(s) associated with a datapath PIF.
88 For a bond master PIF, these are the bond slave PIFs.
89 For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
91 A VLAN PIF cannot be a datapath PIF.
94 # Seems like overkill...
95 raise Error("get-physical-pifs should not get passed a VLAN")
96 elif pif_is_bond(pif
):
97 return pif_get_bond_slaves(pif
)
101 def datapath_deconfigure_physical(netdev
):
102 return ['--', '--with-iface', '--if-exists', 'del-port', netdev
]
111 raise Error("strings may not contain null bytes")
125 return r
'\x%02x' % ord(c
)
126 return '"' + re
.sub(r
'["\\\000-\037]', escape
, s
) + '"'
128 def datapath_configure_bond(pif
,slaves
):
129 bridge
= pif_bridge_name(pif
)
130 pifrec
= db().get_pif_record(pif
)
131 interface
= pif_netdev_name(pif
)
133 argv
= ['--', '--fake-iface', 'add-bond', bridge
, interface
]
135 argv
+= [pif_netdev_name(slave
)]
139 "mode": "balance-slb",
145 # override defaults with values from other-config whose keys
147 oc
= pifrec
['other_config']
148 overrides
= filter(lambda (key
,val
):
149 key
.startswith("bond-"), oc
.items())
150 overrides
= map(lambda (key
,val
): (key
[5:], val
), overrides
)
151 bond_options
.update(overrides
)
153 argv
+= ['--', 'set', 'Port', interface
]
154 if pifrec
['MAC'] != "":
155 argv
+= ['MAC=%s' % vsctl_escape(pifrec
['MAC'])]
156 for (name
,val
) in bond_options
.items():
157 if name
in ['updelay', 'downdelay']:
158 # updelay and downdelay have dedicated schema columns.
159 # The value must be a nonnegative integer.
165 argv
+= ['bond_%s=%d' % (name
, value
)]
167 log("bridge %s has invalid %s '%s'" % (bridge
, name
, value
))
169 # Pass other bond options into other_config.
170 argv
+= ["other-config:%s=%s" % (vsctl_escape("bond-%s" % name
),
174 def datapath_deconfigure_bond(netdev
):
175 return ['--', '--with-iface', '--if-exists', 'del-port', netdev
]
177 def datapath_deconfigure_ipdev(interface
):
178 return ['--', '--with-iface', '--if-exists', 'del-port', interface
]
180 def datapath_modify_config(commands
):
181 #log("modifying configuration:")
185 rc
= run_command(['/usr/bin/ovs-vsctl'] + ['--timeout=20']
186 + [c
for c
in commands
if not c
.startswith('#')])
188 raise Error("Failed to modify vswitch configuration")
192 # Toplevel Datapath Configuration.
195 def configure_datapath(pif
):
196 """Bring up the configuration for 'pif', which must not be a VLAN PIF, by:
197 - Tearing down other PIFs that use the same physical devices as 'pif'.
198 - Ensuring that 'pif' itself is set up.
199 - *Not* tearing down any PIFs that are stacked on top of 'pif' (i.e. VLANs
202 Returns a tuple containing
203 - A list containing the necessary vsctl command line arguments
204 - A list of additional devices which should be brought up after
205 the configuration is applied.
211 assert not pif_is_vlan(pif
)
212 bridge
= pif_bridge_name(pif
)
214 physical_devices
= datapath_get_physical_pifs(pif
)
216 vsctl_argv
+= ['## configuring datapath %s' % bridge
]
218 # Determine additional devices to deconfigure.
220 # Given all physical devices which are part of this PIF we need to
222 # - any additional bond which a physical device is part of.
223 # - any additional physical devices which are part of an additional bond.
225 # Any of these which are not currently in use should be brought
226 # down and deconfigured.
227 extra_down_bonds
= []
228 extra_down_ports
= []
229 for p
in physical_devices
:
230 for bond
in pif_get_bond_masters(p
):
232 log("configure_datapath: leaving bond %s up" % pif_netdev_name(bond
))
234 if bond
in extra_down_bonds
:
236 if db().get_pif_record(bond
)['currently_attached']:
237 log("configure_datapath: implicitly tearing down currently-attached bond %s" % pif_netdev_name(bond
))
239 extra_down_bonds
+= [bond
]
241 for s
in pif_get_bond_slaves(bond
):
242 if s
in physical_devices
:
244 if s
in extra_down_ports
:
246 if pif_currently_in_use(s
):
248 extra_down_ports
+= [s
]
250 log("configure_datapath: bridge - %s" % bridge
)
251 log("configure_datapath: physical - %s" % [pif_netdev_name(p
) for p
in physical_devices
])
252 log("configure_datapath: extra ports - %s" % [pif_netdev_name(p
) for p
in extra_down_ports
])
253 log("configure_datapath: extra bonds - %s" % [pif_netdev_name(p
) for p
in extra_down_bonds
])
255 # Need to fully deconfigure any bridge which any of the:
260 for brpif
in physical_devices
+ extra_down_ports
+ extra_down_bonds
:
263 b
= pif_bridge_name(brpif
)
267 vsctl_argv
+= ['# remove bridge %s' % b
]
268 vsctl_argv
+= ['--', '--if-exists', 'del-br', b
]
270 for n
in extra_down_ports
:
271 dev
= pif_netdev_name(n
)
272 vsctl_argv
+= ['# deconfigure sibling physical device %s' % dev
]
273 vsctl_argv
+= datapath_deconfigure_physical(dev
)
276 for n
in extra_down_bonds
:
277 dev
= pif_netdev_name(n
)
278 vsctl_argv
+= ['# deconfigure bond device %s' % dev
]
279 vsctl_argv
+= datapath_deconfigure_bond(dev
)
282 for p
in physical_devices
:
283 dev
= pif_netdev_name(p
)
284 vsctl_argv
+= ['# deconfigure physical port %s' % dev
]
285 vsctl_argv
+= datapath_deconfigure_physical(dev
)
287 vsctl_argv
+= ['--', '--may-exist', 'add-br', bridge
]
289 if len(physical_devices
) > 1:
290 vsctl_argv
+= ['# deconfigure bond %s' % pif_netdev_name(pif
)]
291 vsctl_argv
+= datapath_deconfigure_bond(pif_netdev_name(pif
))
292 vsctl_argv
+= ['# configure bond %s' % pif_netdev_name(pif
)]
293 vsctl_argv
+= datapath_configure_bond(pif
, physical_devices
)
294 extra_up_ports
+= [pif_netdev_name(pif
)]
296 iface
= pif_netdev_name(physical_devices
[0])
297 vsctl_argv
+= ['# add physical device %s' % iface
]
298 vsctl_argv
+= ['--', '--may-exist', 'add-port', bridge
, iface
]
300 vsctl_argv
+= ['# configure Bridge MAC']
301 vsctl_argv
+= ['--', 'set', 'Bridge', bridge
,
302 'other-config:hwaddr=%s' % vsctl_escape(db().get_pif_record(pif
)['MAC'])]
304 vsctl_argv
+= set_br_external_ids(pif
)
305 vsctl_argv
+= ['## done configuring datapath %s' % bridge
]
307 return vsctl_argv
,extra_up_ports
309 def deconfigure_bridge(pif
):
312 bridge
= pif_bridge_name(pif
)
314 log("deconfigure_bridge: bridge - %s" % bridge
)
316 vsctl_argv
+= ['# deconfigure bridge %s' % bridge
]
317 vsctl_argv
+= ['--', '--if-exists', 'del-br', bridge
]
321 def set_br_external_ids(pif
):
322 pifrec
= db().get_pif_record(pif
)
323 dp
= pif_datapath(pif
)
324 dprec
= db().get_pif_record(dp
)
326 xs_network_uuids
= []
327 for nwpif
in db().get_pifs_by_device(pifrec
['device']):
328 rec
= db().get_pif_record(nwpif
)
330 # When state is read from dbcache PIF.currently_attached
331 # is always assumed to be false... Err on the side of
332 # listing even detached networks for the time being.
333 #if nwpif != pif and not rec['currently_attached']:
334 # log("Network PIF %s not currently attached (%s)" % (rec['uuid'],pifrec['uuid']))
336 nwrec
= db().get_network_record(rec
['network'])
337 xs_network_uuids
+= [nwrec
['uuid']]
340 vsctl_argv
+= ['# configure network-uuids']
341 vsctl_argv
+= ['--', 'br-set-external-id', pif_bridge_name(pif
),
342 'network-uuids', ';'.join(xs_network_uuids
)]
350 class DatapathVswitch(Datapath
):
351 def __init__(self
, pif
):
352 Datapath
.__init
__(self
, pif
)
353 self
._dp
= pif_datapath(pif
)
354 self
._ipdev
= pif_ipdev_name(pif
)
356 if pif_is_vlan(pif
) and not self
._dp
:
357 raise Error("Unbridged VLAN devices not implemented yet")
359 log("Configured for Vswitch datapath")
361 def configure_ipdev(self
, cfg
):
362 cfg
.write("TYPE=Ethernet\n")
364 def preconfigure(self
, parent
):
368 pifrec
= db().get_pif_record(self
._pif
)
369 dprec
= db().get_pif_record(self
._dp
)
372 c
,e
= configure_datapath(self
._dp
)
373 bridge
= pif_bridge_name(self
._pif
)
377 dpname
= pif_bridge_name(self
._dp
)
379 if pif_is_vlan(self
._pif
):
380 # XXX this is only needed on XS5.5, because XAPI misguidedly
381 # creates the fake bridge (via bridge ioctl) before it calls us.
382 vsctl_argv
+= ['--', '--if-exists', 'del-br', bridge
]
384 # configure_datapath() set up the underlying datapath bridge.
385 # Stack a VLAN bridge on top of it.
386 vsctl_argv
+= ['--', '--may-exist', 'add-br',
387 bridge
, dpname
, pifrec
['VLAN']]
389 vsctl_argv
+= set_br_external_ids(self
._pif
)
392 vsctl_argv
+= ["# deconfigure ipdev %s" % ipdev
]
393 vsctl_argv
+= datapath_deconfigure_ipdev(ipdev
)
394 vsctl_argv
+= ["# reconfigure ipdev %s" % ipdev
]
395 vsctl_argv
+= ['--', 'add-port', bridge
, ipdev
]
398 vsctl_argv
+= ['# configure Interface MAC']
399 vsctl_argv
+= ['--', 'set', 'Interface', pif_ipdev_name(self
._pif
),
400 'MAC=%s' % vsctl_escape(dprec
['MAC'])]
402 self
._vsctl
_argv
= vsctl_argv
403 self
._extra
_ports
= extra_ports
405 def bring_down_existing(self
):
409 # Bring up physical devices. ovs-vswitchd initially enables or
410 # disables bond slaves based on whether carrier is detected
411 # when they are added, and a network device that is down
412 # always reports "no carrier".
413 physical_devices
= datapath_get_physical_pifs(self
._dp
)
415 for p
in physical_devices
:
416 prec
= db().get_pif_record(p
)
417 oc
= prec
['other_config']
419 dev
= pif_netdev_name(p
)
421 mtu
= mtu_setting(prec
['network'], "PIF", oc
)
425 settings
, offload
= ethtool_settings(oc
)
427 run_command(['/sbin/ethtool', '-s', dev
] + settings
)
429 run_command(['/sbin/ethtool', '-K', dev
] + offload
)
431 datapath_modify_config(self
._vsctl
_argv
)
434 for p
in self
._extra
_ports
:
435 log("action_up: bring up %s" % p
)
438 def bring_down(self
):
444 bridge
= pif_bridge_name(dp
)
446 #nw = db().get_pif_record(self._pif)['network']
447 #nwrec = db().get_network_record(nw)
448 #vsctl_argv += ['# deconfigure network-uuids']
449 #vsctl_argv += ['--del-entry=bridge.%s.network-uuids=%s' % (bridge,nwrec['uuid'])]
451 log("deconfigure ipdev %s on %s" % (ipdev
,bridge
))
452 vsctl_argv
+= ["# deconfigure ipdev %s" % ipdev
]
453 vsctl_argv
+= datapath_deconfigure_ipdev(ipdev
)
455 if pif_is_vlan(self
._pif
):
456 # Delete the VLAN bridge.
457 vsctl_argv
+= deconfigure_bridge(self
._pif
)
459 # If the VLAN's slave is attached, leave datapath setup.
460 slave
= pif_get_vlan_slave(self
._pif
)
461 if db().get_pif_record(slave
)['currently_attached']:
462 log("action_down: vlan slave is currently attached")
465 # If the VLAN's slave has other VLANs that are attached, leave datapath setup.
466 for master
in pif_get_vlan_masters(slave
):
467 if master
!= self
._pif
and db().get_pif_record(master
)['currently_attached']:
468 log("action_down: vlan slave has other master: %s" % pif_netdev_name(master
))
471 # Otherwise, take down the datapath too (fall through)
473 log("action_down: no more masters, bring down slave %s" % bridge
)
475 # Stop here if this PIF has attached VLAN masters.
476 masters
= [db().get_pif_record(m
)['VLAN'] for m
in pif_get_vlan_masters(self
._pif
) if db().get_pif_record(m
)['currently_attached']]
478 log("Leaving datapath %s up due to currently attached VLAN masters %s" % (bridge
, masters
))
482 vsctl_argv
+= deconfigure_bridge(dp
)
484 physical_devices
= [pif_netdev_name(p
) for p
in datapath_get_physical_pifs(dp
)]
486 log("action_down: bring down physical devices - %s" % physical_devices
)
488 for p
in physical_devices
:
491 datapath_modify_config(vsctl_argv
)