diff -r a623336112b9 src/virtManager/connection.py --- a/src/virtManager/connection.py Sun Feb 03 12:42:21 2008 -0500 +++ b/src/virtManager/connection.py Mon Feb 18 16:18:25 2008 +0900 @@ -22,6 +22,7 @@ import libvirt import libvirt import logging import os, sys +import glob import traceback from time import time import logging @@ -29,6 +30,7 @@ import dbus import dbus import threading import gtk +import string from virtManager.domain import vmmDomain from virtManager.network import vmmNetwork @@ -134,9 +136,7 @@ class vmmConnection(gobject.GObject): self.record = [] self.hostinfo = None - self.detect_network_devices() - - def detect_network_devices(self): + # Probe for network devices try: # Get a connection to the SYSTEM bus self.bus = dbus.SystemBus() @@ -145,12 +145,23 @@ class vmmConnection(gobject.GObject): self.hal_iface = dbus.Interface(hal_object, 'org.freedesktop.Hal.Manager') # Track device add/removes so we can detect newly inserted CD media - self.hal_iface.connect_to_signal("DeviceAdded", self._device_added) - self.hal_iface.connect_to_signal("DeviceRemoved", self._device_removed) - - # Find info about all current present media + self.hal_iface.connect_to_signal("DeviceAdded", self._net_phys_device_added) + self.hal_iface.connect_to_signal("DeviceRemoved", self._net_phys_device_removed) + + # find all bonding master devices and register them + # XXX bonding stuff is linux specific + bondMasters = self._net_get_bonding_masters() + for bond in bondMasters: + sysfspath = "/sys/class/net/" + bond + mac = self._net_get_mac_address(bond, sysfspath) + self._net_device_added(bond, mac, sysfspath) + # Add any associated VLANs + self._net_tag_device_added(bond, sysfspath) + + # Find info about all current present physical net devices + # This is OS portable... for path in self.hal_iface.FindDeviceByCapability("net"): - self._device_added(path) + self._net_phys_device_added(path) except: (type, value, stacktrace) = sys.exc_info () logging.error("Unable to connect to HAL to list network devices: '%s'" + \ @@ -159,56 +170,73 @@ class vmmConnection(gobject.GObject): self.bus = None self.hal_iface = None - def _device_added(self, path): + def _net_phys_device_added(self, path): + logging.debug("Got physical device %s" % path) obj = self.bus.get_object("org.freedesktop.Hal", path) if obj.QueryCapability("net"): name = obj.GetPropertyString("net.interface") + # XXX ...but this is Linux specific again - patches welcomed + #sysfspath = obj.GetPropertyString("linux.sysfs_path") + # XXX hal gives back paths to /sys/devices/pci0000:00/0000:00:1e.0/0000:01:00.0/net/eth0 + # which doesnt' work so well - we want this: + sysfspath = "/sys/class/net/" + name + + # If running a device in bridged mode, there's a reasonable + # chance that the actual ethernet device has been renamed to + # something else. ethN -> pethN + psysfspath = sysfspath[0:len(sysfspath)-len(name)] + "p" + name + if os.path.exists(psysfspath): + logging.debug("Device %s named to p%s" % (name, name)) + name = "p" + name + sysfspath = psysfspath + + # Ignore devices that are slaves of a bond + if self._net_is_bonding_slave(name, sysfspath): + logging.debug("Skipping device %s in bonding slave" % name) + return + mac = obj.GetPropertyString("net.address") - # Now magic to determine if the device is part of a bridge - shared = False - bridge = None - try: - # XXX Linux specific - needs porting for other OS - patches - # welcomed... - sysfspath = obj.GetPropertyString("linux.sysfs_path") - - # If running a device in bridged mode, there's a reasonable - # chance that the actual ethernet device has been renamed to - # something else. ethN -> pethN - psysfspath = sysfspath[0:len(sysfspath)-len(name)] + "p" + name - if os.path.exists(psysfspath): - name = "p" + name - sysfspath = psysfspath - - brportpath = os.path.join(sysfspath, "brport") - - if os.path.exists(brportpath): - shared = True - brlinkpath = os.path.join(brportpath, "bridge") - dest = os.readlink(brlinkpath) - (head,tail) = os.path.split(dest) - bridge = tail - except: - (type, value, stacktrace) = sys.exc_info () - logging.error("Unable to determine if device is shared:" + - str(type) + " " + str(value) + "\n" + \ - traceback.format_exc (stacktrace)) - - if self.netdevs.has_key(path): - currDev = self.netdevs[path] - if currDev.get_info() == (name, mac, shared, bridge): - return - del self.netdevs[path] - dev = vmmNetDevice(self.config, self, name, mac, shared, bridge) - self.netdevs[path] = dev - self.emit("netdev-added", dev.get_name()) - - def _device_removed(self, path): - if self.netdevs.has_key(path): - dev = self.netdevs[path] + # Add the main NIC + self._net_device_added(name, mac, sysfspath) + + # Add any associated VLANs + self._net_tag_device_added(name, sysfspath) + + def _net_tag_device_added(self, name, sysfspath): + logging.debug("Checking for VLANs on %s" % sysfspath) + for vlanpath in glob.glob(sysfspath + ".*"): + if os.path.exists(vlanpath): + logging.debug("Process VLAN %s" % vlanpath) + vlanmac = self._net_get_mac_address(name, vlanpath) + (ignore,vlanname) = os.path.split(vlanpath) + self._net_device_added(vlanname, vlanmac, vlanpath) + + def _net_device_added(self, name, mac, sysfspath): + # Race conditions mean we can occassionally see device twice + if self.netdevs.has_key(name): + return + + bridge = self._net_get_bridge_owner(name, sysfspath) + shared = False + if bridge is not None: + shared = True + + logging.debug("Adding net device %s %s %s bridge %s" % (name, mac, sysfspath, str(bridge))) + + dev = vmmNetDevice(self.config, self, name, mac, shared, bridge) + self.netdevs[name] = dev + self.emit("netdev-added", dev.get_name()) + + def _net_phys_device_removed(self, path): + obj = self.bus.get_object("org.freedesktop.Hal", path) + if obj.QueryCapability("net"): + name = obj.GetPropertyString("net.interface") + + if self.netdevs.has_key(name): + dev = self.netdevs[name] self.emit("netdev-removed", dev.get_name()) - del self.netdevs[path] + del self.netdevs[name] def is_read_only(self): return self.readOnly @@ -545,13 +573,6 @@ class vmmConnection(gobject.GObject): newInactiveNetNames = self.vmm.listDefinedNetworks() except: logging.warn("Unable to list inactive networks") - - # check of net devices - newPaths = [] - if self.hal_iface: - newPaths = self.hal_iface.FindDeviceByCapability("net") - for newPath in newPaths: - self._device_added(newPath) for name in newActiveNetNames: net = self.vmm.networkLookupByName(name) @@ -847,5 +868,48 @@ class vmmConnection(gobject.GObject): else: return _("Unknown") + def _net_get_bridge_owner(self, name, sysfspath): + # Now magic to determine if the device is part of a bridge + brportpath = os.path.join(sysfspath, "brport") + try: + if os.path.exists(brportpath): + brlinkpath = os.path.join(brportpath, "bridge") + dest = os.readlink(brlinkpath) + (ignore,bridge) = os.path.split(dest) + return bridge + except: + (type, value, stacktrace) = sys.exc_info () + logging.error("Unable to determine if device is shared:" + + str(type) + " " + str(value) + "\n" + \ + traceback.format_exc (stacktrace)) + + return None + + def _net_get_mac_address(self, name, sysfspath): + mac = None + addrpath = sysfspath + "/address" + if os.path.exists(addrpath): + df = open(addrpath, 'r') + mac = df.readline() + df.close() + return mac.strip(" \n\t") + + def _net_get_bonding_masters(self): + masters = [] + f = open("/sys/class/net/bonding_masters") + while True: + rline = f.readline() + if not rline: break + if rline == "\x00": continue + rline = rline.strip("\n\t") + masters = rline[:-1].split(' ') + return masters + + def _net_is_bonding_slave(self, name, sysfspath): + masterpath = sysfspath + "/master" + if os.path.exists(masterpath): + return True + return False + gobject.type_register(vmmConnection)