return False
return True
+def read_first_line_of_file(name):
+ file = None
+ try:
+ file = open(name, 'r')
+ return file.readline().rstrip('\n')
+ finally:
+ if file != None:
+ file.close()
+
def down_netdev(interface, deconfigure=True):
if not interface_exists(interface):
log("down_netdev: interface %s does not exist, ignoring" % interface)
return
- argv = ["/sbin/ifconfig", interface, 'down']
if deconfigure:
- argv += ['0.0.0.0']
-
# Kill dhclient.
pidfile_name = '/var/run/dhclient-%s.pid' % interface
- pidfile = None
try:
- pidfile = open(pidfile_name, 'r')
- os.kill(int(pidfile.readline()), signal.SIGTERM)
+ os.kill(int(read_first_line_of_file(pidfile_name)), signal.SIGTERM)
except:
pass
- if pidfile != None:
- pidfile.close()
# Remove dhclient pidfile.
try:
os.remove(pidfile_name)
except:
pass
- run_command(argv)
+
+ run_command(["/sbin/ifconfig", interface, '0.0.0.0'])
+
+ run_command(["/sbin/ifconfig", interface, 'down'])
def up_netdev(interface):
run_command(["/sbin/ifconfig", interface, 'up'])
argv += ["--add=bonding.%s.slave=%s" % (interface, slave)
for slave in physdevs]
+ if pifrec['MAC'] != "":
+ argv += ['--add=port.%s.mac=%s' % (interface, pifrec['MAC'])]
+
# Bonding options.
bond_options = {
"mode": "balance-slb",
bond_master = pif
else:
bond_master = None
+ if bond_master:
+ bond_slaves = get_bond_slaves_of_pif(bond_master)
+ else:
+ bond_slaves = []
bond_masters = get_bond_masters_of_pif(pif)
# Support "rpm -e vswitch" gracefully by keeping Centos configuration
for physdev in physdevs:
down_netdev(physdev)
+ # If we are bringing up a bond, remove IP addresses from the
+ # slaves (because we are implicitly being asked to take them down).
+ #
+ # Conversely, if we are bringing up an interface that has bond
+ # masters, remove IP addresses from the bond master (because we
+ # are implicitly being asked to take it down).
+ for bond_pif in bond_slaves + bond_masters:
+ run_command(["/sbin/ifconfig", ipdev_name(bond_pif), '0.0.0.0'])
+
# Remove all keys related to pif and any bond masters linked to PIF.
del_ports = [ipdev] + physdevs + bond_masters
if vlan_slave and bond_master:
net = db.get_pif_record(nwpif)['network']
network_uuids += [db.get_network_record(net)['uuid']]
+ # Bring up bond slaves early, because ovs-vswitchd initially
+ # enables or disables bond slaves based on whether carrier is
+ # detected when they are added, and a network device that is down
+ # always reports "no carrier".
+ bond_slave_physdevs = []
+ for slave in bond_slaves:
+ bond_slave_physdevs += physdev_names(slave)
+ for slave_physdev in bond_slave_physdevs:
+ up_netdev(slave_physdev)
+
# Now modify the ovs-vswitchd config file.
argv = []
for port in set(del_ports):
# Configure network devices.
configure_netdev(pif)
- # Bring up VLAN slave and bond slaves.
+ # Bring up VLAN slave, plus physical devices other than bond
+ # slaves (which we brought up earlier).
if vlan_slave:
up_netdev(ipdev_name(vlan_slave))
- for physdev in physdevs:
+ for physdev in set(physdevs) - set(bond_slave_physdevs):
up_netdev(physdev)
# Update /etc/issue (which contains the IP address of the management interface)
os.system("/sbin/update-issue")
+
+ if bond_slaves:
+ # There seems to be a race somewhere: without this sleep, using
+ # XenCenter to create a bond that becomes the management interface
+ # fails with "The underlying connection was closed: A connection that
+ # was expected to be kept alive was closed by the server." on every
+ # second or third try, even though /var/log/messages doesn't show
+ # anything unusual.
+ #
+ # The race is probably present even without vswitch, but bringing up a
+ # bond without vswitch involves a built-in pause of 10 seconds or more
+ # to wait for the bond to transition from learning to forwarding state.
+ time.sleep(5)
def action_down(pif):
rec = db.get_pif_record(pif)