]>
git.proxmox.com Git - ovs.git/blob - xenserver/opt_xensource_libexec_InterfaceReconfigureBridge.py
1 # Copyright (c) 2008,2009 Citrix Systems, Inc.
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU Lesser General Public License as published
5 # by the Free Software Foundation; version 2.1 only. with the special
6 # exception on linking described in file LICENSE.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU Lesser General Public License for more details.
13 from InterfaceReconfigure
import *
18 sysfs_bonding_masters
= root_prefix() + "/sys/class/net/bonding_masters"
20 def open_pif_ifcfg(pif
):
21 pifrec
= db().get_pif_record(pif
)
23 interface
= pif_netdev_name(pif
)
24 log("Configuring %s (%s)" % (interface
, pifrec
['MAC']))
26 f
= ConfigurationFile("%s/etc/sysconfig/network-scripts/ifcfg-%s" % (root_prefix(), interface
))
28 f
.write("# DO NOT EDIT: This file (%s) was autogenerated by %s\n" % \
29 (os
.path
.basename(f
.path()), os
.path
.basename(sys
.argv
[0])))
30 f
.write("XEMANAGED=yes\n")
31 f
.write("DEVICE=%s\n" % interface
)
32 f
.write("ONBOOT=no\n")
37 # Bare Network Devices -- network devices without IP configuration
40 def netdev_down(netdev
):
41 """Bring down a bare network device"""
42 if not netdev_exists(netdev
):
43 log("netdev: down: device %s does not exist, ignoring" % netdev
)
45 run_command(["/sbin/ifdown", netdev
])
47 def netdev_up(netdev
, mtu
=None):
48 """Bring up a bare network device"""
49 #if not netdev_exists(netdev):
50 # raise Error("netdev: up: device %s does not exist" % netdev)
52 run_command(["/sbin/ifup", netdev
])
58 def load_bonding_driver():
59 log("Loading bonding driver")
60 run_command(["/sbin/modprobe", "bonding"])
62 # bond_device_exists() uses the contents of sysfs_bonding_masters to work out which devices
63 # have already been created. Unfortunately the driver creates "bond0" automatically at
64 # modprobe init. Get rid of this now or our accounting will go wrong.
65 f
= open(sysfs_bonding_masters
, "w")
69 log("Failed to load bonding driver: %s" % e
)
71 def bonding_driver_loaded():
72 lines
= open(root_prefix() + "/proc/modules").read().split("\n")
73 modules
= [line
.split(" ")[0] for line
in lines
]
74 return "bonding" in modules
76 def bond_device_exists(name
):
77 f
= open(sysfs_bonding_masters
, "r")
78 bonds
= f
.readline().split()
82 def __create_bond_device(name
):
84 if not bonding_driver_loaded():
87 if bond_device_exists(name
):
88 log("bond master %s already exists, not creating" % name
)
90 log("Creating bond master %s" % name
)
92 f
= open(sysfs_bonding_masters
, "w")
96 log("Failed to create %s: %s" % (name
, e
))
98 def create_bond_device(pif
):
99 """Ensures that a bond master device exists in the kernel."""
101 if not pif_is_bond(pif
):
104 __create_bond_device(pif_netdev_name(pif
))
106 def __destroy_bond_device(name
):
107 if bond_device_exists(name
):
108 retries
= 10 # 10 * 0.5 seconds
110 retries
= retries
- 1
111 log("Destroying bond master %s (%d attempts remain)" % (name
,retries
))
113 f
= open(sysfs_bonding_masters
, "w")
120 log("bond master %s does not exist, not destroying" % name
)
122 def destroy_bond_device(pif
):
123 """No, Mr. Bond, I expect you to die."""
125 pifrec
= db().get_pif_record(pif
)
127 if not pif_is_bond(pif
):
130 # If the bonding module isn't loaded then do nothing.
131 if not os
.access(sysfs_bonding_masters
, os
.F_OK
):
134 name
= pif_netdev_name(pif
)
136 __destroy_bond_device(name
)
139 # Bring Interface up/down.
142 def bring_down_interface(pif
, destroy
=False):
143 """Bring down the interface associated with PIF.
145 Brings down the given interface as well as any physical interfaces
146 which are bond slaves of this one. This is because they will be
147 required when the bond is brought up."""
149 def destroy_bridge(pif
):
150 """Bring down the bridge associated with a PIF."""
151 #if not pif_is_bridged(pif):
153 bridge
= pif_bridge_name(pif
)
154 if not netdev_exists(bridge
):
155 log("destroy_bridge: bridge %s does not exist, ignoring" % bridge
)
157 log("Destroy bridge %s" % bridge
)
159 run_command(["/usr/sbin/brctl", "delbr", bridge
])
161 def destroy_vlan(pif
):
162 vlan
= pif_netdev_name(pif
)
163 if not netdev_exists(vlan
):
164 log("vconfig del: vlan %s does not exist, ignoring" % vlan
)
166 log("Destroy vlan device %s" % vlan
)
167 run_command(["/sbin/vconfig", "rem", vlan
])
170 interface
= pif_netdev_name(pif
)
171 log("bring_down_interface: %s is a VLAN" % interface
)
172 netdev_down(interface
)
180 slave
= pif_get_vlan_slave(pif
)
181 if db().get_pif_record(slave
)['currently_attached']:
182 log("bring_down_interface: vlan slave is currently attached")
185 masters
= pif_get_vlan_masters(slave
)
186 masters
= [m
for m
in masters
if m
!= pif
and db().get_pif_record(m
)['currently_attached']]
188 log("bring_down_interface: vlan slave has other masters")
191 log("bring_down_interface: no more masters, bring down vlan slave %s" % pif_netdev_name(slave
))
194 vlan_masters
= pif_get_vlan_masters(pif
)
195 log("vlan masters of %s - %s" % (db().get_pif_record(pif
)['device'], [pif_netdev_name(m
) for m
in vlan_masters
]))
196 if len([m
for m
in vlan_masters
if db().get_pif_record(m
)['currently_attached']]) > 0:
197 log("Leaving %s up due to currently attached VLAN masters" % pif_netdev_name(pif
))
200 # pif is now either a bond or a physical device which needs to be brought down
202 # Need to bring down bond slaves first since the bond device
203 # must be up to enslave/unenslave.
204 bond_slaves
= pif_get_bond_slaves_sorted(pif
)
205 log("bond slaves of %s - %s" % (db().get_pif_record(pif
)['device'], [pif_netdev_name(s
) for s
in bond_slaves
]))
206 for slave
in bond_slaves
:
207 slave_interface
= pif_netdev_name(slave
)
208 if db().get_pif_record(slave
)['currently_attached']:
209 log("leave bond slave %s up (currently attached)" % slave_interface
)
211 log("bring down bond slave %s" % slave_interface
)
212 netdev_down(slave_interface
)
213 # Also destroy the bridge associated with the slave, since
214 # it will carry the MAC address and possibly an IP address
215 # leading to confusion.
216 destroy_bridge(slave
)
218 interface
= pif_netdev_name(pif
)
219 log("Bring interface %s down" % interface
)
220 netdev_down(interface
)
223 destroy_bond_device(pif
)
226 def interface_is_up(pif
):
228 interface
= pif_netdev_name(pif
)
229 state
= open("%s/sys/class/net/%s/operstate" % (root_prefix(), interface
)).read().strip()
232 return False # interface prolly doesn't exist
234 def bring_up_interface(pif
):
235 """Bring up the interface associated with a PIF.
237 Also bring up the interfaces listed in additional.
240 # VLAN on bond seems to need bond brought up explicitly, but VLAN
241 # on normal device does not. Might as well always bring it up.
243 slave
= pif_get_vlan_slave(pif
)
244 if not interface_is_up(slave
):
245 bring_up_interface(slave
)
247 interface
= pif_netdev_name(pif
)
249 create_bond_device(pif
)
251 log("Bring interface %s up" % interface
)
256 # Datapath topology configuration.
259 def _configure_physical_interface(pif
):
260 """Write the configuration for a physical interface.
262 Writes the configuration file for the physical interface described by
265 Returns the open file handle for the interface configuration file.
268 pifrec
= db().get_pif_record(pif
)
270 log("Configuring physical interface %s" % pifrec
['device'])
272 f
= open_pif_ifcfg(pif
)
274 f
.write("TYPE=Ethernet\n")
275 f
.write("HWADDR=%(MAC)s\n" % pifrec
)
277 settings
,offload
= ethtool_settings(pifrec
['other_config'])
279 f
.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings
))
281 f
.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload
))
283 mtu
= mtu_setting(pifrec
['network'], "PIF", pifrec
['other_config'])
285 f
.write("MTU=%s\n" % mtu
)
289 def pif_get_bond_slaves_sorted(pif
):
290 pifrec
= db().get_pif_record(pif
)
292 # build a list of slave's pifs
293 slave_pifs
= pif_get_bond_slaves(pif
)
295 # Ensure any currently attached slaves are listed in the opposite order to the order in
296 # which they were attached. The first slave attached must be the last detached since
297 # the bond is using its MAC address.
299 attached_slaves
= open("%s/sys/class/net/%s/bonding/slaves" % (root_prefix(), pifrec
['device'])).readline().split()
300 for slave
in attached_slaves
:
301 pifs
= [p
for p
in db().get_pifs_by_device(slave
) if not pif_is_vlan(p
)]
303 slave_pifs
.remove(slave_pif
)
304 slave_pifs
.insert(0, slave_pif
)
310 def _configure_bond_interface(pif
):
311 """Write the configuration for a bond interface.
313 Writes the configuration file for the bond interface described by
314 the pif object. Handles writing the configuration for the slave
317 Returns the open file handle for the bond interface configuration
321 pifrec
= db().get_pif_record(pif
)
323 f
= open_pif_ifcfg(pif
)
325 if pifrec
['MAC'] != "":
326 f
.write("MACADDR=%s\n" % pifrec
['MAC'])
328 for slave
in pif_get_bond_slaves(pif
):
329 s
= _configure_physical_interface(slave
)
330 s
.write("MASTER=%(device)s\n" % pifrec
)
331 s
.write("SLAVE=yes\n")
335 settings
,offload
= ethtool_settings(pifrec
['other_config'])
337 f
.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings
))
339 f
.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload
))
341 mtu
= mtu_setting(pifrec
['network'], "VLAN-PIF", pifrec
['other_config'])
343 f
.write("MTU=%s\n" % mtu
)
345 # The bond option defaults
347 "mode": "balance-slb",
354 # override defaults with values from other-config whose keys being with "bond-"
355 oc
= pifrec
['other_config']
356 overrides
= filter(lambda (key
,val
): key
.startswith("bond-"), oc
.items())
357 overrides
= map(lambda (key
,val
): (key
[5:], val
), overrides
)
358 bond_options
.update(overrides
)
360 # write the bond options to ifcfg-bondX
361 f
.write('BONDING_OPTS="')
362 for (name
,val
) in bond_options
.items():
363 f
.write("%s=%s " % (name
,val
))
367 def _configure_vlan_interface(pif
):
368 """Write the configuration for a VLAN interface.
370 Writes the configuration file for the VLAN interface described by
371 the pif object. Handles writing the configuration for the master
372 interface if necessary.
374 Returns the open file handle for the VLAN interface configuration
378 slave
= _configure_pif(pif_get_vlan_slave(pif
))
380 pifrec
= db().get_pif_record(pif
)
382 f
= open_pif_ifcfg(pif
)
383 f
.write("VLAN=yes\n")
385 settings
,offload
= ethtool_settings(pifrec
['other_config'])
387 f
.write("ETHTOOL_OPTS=\"%s\"\n" % str.join(" ", settings
))
389 f
.write("ETHTOOL_OFFLOAD_OPTS=\"%s\"\n" % str.join(" ", offload
))
391 mtu
= mtu_setting(pifrec
['network'], "Bond-PIF", pifrec
['other_config'])
393 f
.write("MTU=%s\n" % mtu
)
395 f
.attach_child(slave
)
399 def _configure_pif(pif
):
400 """Write the configuration for a PIF object.
402 Writes the configuration file the PIF and all dependent
403 interfaces (bond slaves and VLAN masters etc).
405 Returns the open file handle for the interface configuration file.
409 f
= _configure_vlan_interface(pif
)
410 elif pif_is_bond(pif
):
411 f
= _configure_bond_interface(pif
)
413 f
= _configure_physical_interface(pif
)
415 f
.write("BRIDGE=%s\n" % pif_bridge_name(pif
))
424 class DatapathBridge(Datapath
):
425 def __init__(self
, pif
):
426 if pif_is_tunnel(pif
):
427 raise Error("Tunnel PIFs are not supported in Bridge mode")
429 Datapath
.__init
__(self
, pif
)
430 log("Configured for Bridge datapath")
432 def configure_ipdev(self
, cfg
):
433 if pif_is_bridged(self
._pif
):
434 cfg
.write("TYPE=Bridge\n")
435 cfg
.write("DELAY=0\n")
436 cfg
.write("STP=off\n")
437 cfg
.write("PIFDEV=%s\n" % pif_netdev_name(self
._pif
))
439 cfg
.write("TYPE=Ethernet\n")
441 def preconfigure(self
, parent
):
442 pf
= _configure_pif(self
._pif
)
443 parent
.attach_child(pf
)
445 def bring_down_existing(self
):
446 # Bring down any VLAN masters so that we can reconfigure the slave.
447 for master
in pif_get_vlan_masters(self
._pif
):
448 name
= pif_netdev_name(master
)
449 log("action_up: bring down vlan master %s" % (name
))
452 # interface-reconfigure is never explicitly called to down a bond master.
453 # However, when we are called to up a slave it is implicit that we are destroying the master.
454 bond_masters
= pif_get_bond_masters(self
._pif
)
455 for master
in bond_masters
:
456 log("action_up: bring down bond master %s" % (pif_netdev_name(master
)))
458 bring_down_interface(master
, destroy
=True)
460 # No masters left - now its safe to reconfigure the slave.
461 bring_down_interface(self
._pif
)
464 bring_up_interface(self
._pif
)
467 # Bring back any currently-attached VLAN masters
468 for master
in [v
for v
in pif_get_vlan_masters(self
._pif
) if db().get_pif_record(v
)['currently_attached']]:
469 name
= pif_netdev_name(master
)
470 log("action_up: bring up %s" % (name
))
473 def bring_down(self
):
474 bring_down_interface(self
._pif
, destroy
=True)