else:
return interface_name(pif)
+def fakevlanbridge_name(pif):
+ """Return the name of the network device that xapi *thinks* carries the
+IP configuration associatied with pif, if this is different from the actual
+network device for pif (as returned by ipdev_name).
+Otherwise, returns None.
+
+This is important because xapi will refuse to put the primary management
+interface on a network device that does not have an IP address. For ordinary
+network devices and bonds, this is no problem for us, since the device we
+want to use for the IP address is the same as what xapi expects. But for
+VLANs, xapi expects us to put the IP address on the xapi# device, which is
+a bridge device (datapath local port device, actually), but we can't do that
+because it would have to be added to the xenbr# or xapi# bridge that
+represents the vlan slave, and a bridge port device can only be a member of
+a single bridge.
+
+So, in the latter case, we have to fake out xapi somehow. We choose to do
+so by configuring a dummy 127.x.y.z address on the xapi# device that xapi
+expects. xapi only cares that the interface has an address, not that the
+address is correct, so this is sufficient.
+"""
+
+ pifrec = db.get_pif_record(pif)
+
+ if pifrec['VLAN'] == '-1':
+ return None
+ else:
+ return bridge_name(pif)
+
+
def physdev_names(pif):
"""Return the name(s) of the physical network device(s) associated with pif.
For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
argv += ["--add=bonding.%s.%s=%s" % (interface, name, val)]
return argv
+def get_ifindex(netdev):
+ """Return the ifindex of the given 'netdev'."""
+ return int(open("/sys/class/net/%s/ifindex" % netdev).readline())
+
def action_up(pif):
pifrec = db.get_pif_record(pif)
ipdev = ipdev_name(pif)
datapath = datapath_name(pif)
physdevs = physdev_names(pif)
+ fakevlanbridge = fakevlanbridge_name(pif)
vlan_slave = None
if pifrec['VLAN'] != '-1':
vlan_slave = get_vlan_slave_of_pif(pif)
# "ifconfig down" the network device and delete its IP address, etc.
down_netdev(ipdev)
- #if datapath != ipdev:
- # down_netdev(datapath)
if vlan_slave:
down_netdev(ipdev_name(vlan_slave), False)
+ down_netdev(fakevlanbridge)
for physdev in physdevs:
down_netdev(physdev)
else:
add_ports += [interface_name(bond_master)]
- # What ports do we need to delete first?
+ # What ports do we need to delete?
#
# - All the ports that we add, to avoid duplication and to drop
# them from another datapath in case they're misassigned.
# Bring up VLAN slave and bond slaves.
if vlan_slave:
up_netdev(ipdev_name(vlan_slave))
+
+ # Set up an IP address on the fake VLAN bridge. See the
+ # comments on fakevlanbridge_name for details.
+ up_netdev(fakevlanbridge)
+ fakevlan_ifindex = get_ifindex(fakevlanbridge)
+ fakevlan_ifindex_octets = ((fakevlan_ifindex >> 16) & 0xff,
+ (fakevlan_ifindex >> 8) & 0xff,
+ fakevlan_ifindex & 0xff)
+ run_command(['/sbin/ifconfig', fakevlanbridge,
+ '127.%d.%d.%d' % fakevlan_ifindex_octets,
+ 'netmask', '255.255.255.255'])
for physdev in physdevs:
up_netdev(physdev)
interface = interface_name(pif)
bridge = bridge_name(pif)
ipdev = ipdev_name(pif)
+ fakevlanbridge = fakevlanbridge_name(pif)
argv = []
if rec['VLAN'] != '-1':
# Get rid of the VLAN device itself.
down_netdev(ipdev)
+ down_netdev(fakevlanbridge)
argv += interface_deconfigure_commands(ipdev)
# If the VLAN's slave is attached, stop here.