def ensure_bridge(self, bridge_name, interface=None, update_interface=True): """Create a bridge unless it already exists.""" # ensure_device_is_ready instead of device_exists is used here # because there are cases where the bridge exists but it's not UP, # for example: # 1) A greenthread was executing this function and had not yet executed # "ip link set bridge_name up" before eventlet switched to this # thread running the same function # 2) The Nova VIF driver was running concurrently and had just created # the bridge, but had not yet put it UP if not ip_lib.ensure_device_is_ready(bridge_name): LOG.debug("Starting bridge %(bridge_name)s for subinterface " "%(interface)s", {'bridge_name': bridge_name, 'interface': interface}) bridge_device = bridge_lib.BridgeDevice.addbr(bridge_name) if bridge_device.setfd(0): return if bridge_device.disable_stp(): return if bridge_device.link.set_up(): return LOG.debug("Done starting bridge %(bridge_name)s for " "subinterface %(interface)s", {'bridge_name': bridge_name, 'interface': interface}) else: bridge_device = bridge_lib.BridgeDevice(bridge_name) if not interface: return bridge_name # Update IP info if necessary if update_interface: self.update_interface_ip_details(bridge_name, interface) # Check if the interface is part of the bridge if not bridge_device.owns_interface(interface): try: # Check if the interface is not enslaved in another bridge bridge = bridge_lib.BridgeDevice.get_interface_bridge( interface) if bridge: bridge.delif(interface) bridge_device.addif(interface) except Exception as e: LOG.error("Unable to add %(interface)s to %(bridge_name)s" "! Exception: %(e)s", {'interface': interface, 'bridge_name': bridge_name, 'e': e}) return return bridge_name
def _add_tap_interface(self, network_id, network_type, physical_network, segmentation_id, tap_device_name, device_owner, mtu): """Add tap interface. If a VIF has been plugged into a network, this function will add the corresponding tap device to the relevant bridge. """ if not ip_lib.device_exists(tap_device_name): LOG.debug("Tap device: %s does not exist on " "this host, skipped", tap_device_name) return False bridge_name = self.bridge_mappings.get(physical_network) if not bridge_name: bridge_name = self.get_bridge_name(network_id) if network_type == constants.TYPE_LOCAL: self.ensure_local_bridge(network_id, bridge_name) elif not self.ensure_physical_in_bridge(network_id, network_type, physical_network, segmentation_id, mtu): return False if mtu: # <-None with device_details from older neutron servers. # we ensure the MTU here because libvirt does not set the # MTU of a bridge it creates and the tap device it creates will # inherit from the bridge its plugged into, which will be 1500 # at the time. See bug/1684326 for details. self._set_tap_mtu(tap_device_name, mtu) # Avoid messing with plugging devices into a bridge that the agent # does not own if not device_owner.startswith(constants.DEVICE_OWNER_COMPUTE_PREFIX): # Check if device needs to be added to bridge if not bridge_lib.BridgeDevice.get_interface_bridge( tap_device_name): data = {'tap_device_name': tap_device_name, 'bridge_name': bridge_name} LOG.debug("Adding device %(tap_device_name)s to bridge " "%(bridge_name)s", data) if bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name): return False else: data = {'tap_device_name': tap_device_name, 'device_owner': device_owner, 'bridge_name': bridge_name} LOG.debug("Skip adding device %(tap_device_name)s to " "%(bridge_name)s. It is owned by %(device_owner)s and " "thus added elsewhere.", data) return True
def _delete_bridge(self, bridge_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): try: LOG.debug("Deleting bridge %s", bridge_name) if bridge_device.link.set_down(): return if bridge_device.delbr(): return LOG.debug("Done deleting bridge %s", bridge_name) return except RuntimeError: pass LOG.debug("Cannot delete bridge %s; it does not exist", bridge_name)
def _add_tap_interface(self, network_id, network_type, physical_network, segmentation_id, tap_device_name, device_owner): """Add tap interface. If a VIF has been plugged into a network, this function will add the corresponding tap device to the relevant bridge. """ if not ip_lib.device_exists(tap_device_name): LOG.debug("Tap device: %s does not exist on " "this host, skipped", tap_device_name) return False bridge_name = self.get_existing_bridge_name(physical_network) if not bridge_name: bridge_name = self.get_bridge_name(network_id) if network_type == p_const.TYPE_LOCAL: self.ensure_local_bridge(network_id, bridge_name) else: phy_dev_name = self.ensure_physical_in_bridge( network_id, network_type, physical_network, segmentation_id) if not phy_dev_name: return False self.ensure_tap_mtu(tap_device_name, phy_dev_name) # Avoid messing with plugging devices into a bridge that the agent # does not own if device_owner.startswith(constants.DEVICE_OWNER_PREFIXES): # Check if device needs to be added to bridge if not bridge_lib.BridgeDevice.get_interface_bridge( tap_device_name): data = { 'tap_device_name': tap_device_name, 'bridge_name': bridge_name } LOG.debug( "Adding device %(tap_device_name)s to bridge " "%(bridge_name)s", data) if bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name): return False else: data = { 'tap_device_name': tap_device_name, 'device_owner': device_owner, 'bridge_name': bridge_name } LOG.debug( "Skip adding device %(tap_device_name)s to " "%(bridge_name)s. It is owned by %(device_owner)s and " "thus added elsewhere.", data) return True
def add_tap_interface(self, network_id, network_type, physical_network, segmentation_id, tap_device_name): """Add tap interface. If a VIF has been plugged into a network, this function will add the corresponding tap device to the relevant bridge. """ if not ip_lib.device_exists(tap_device_name): LOG.debug("Tap device: %s does not exist on " "this host, skipped", tap_device_name) return False if physical_network: bridge_name = self.get_existing_bridge_name(physical_network) else: bridge_name = self.get_bridge_name(network_id) if network_type == p_const.TYPE_LOCAL: self.ensure_local_bridge(network_id, bridge_name) else: phy_dev_name = self.ensure_physical_in_bridge( network_id, network_type, physical_network, segmentation_id) if not phy_dev_name: return False self.ensure_tap_mtu(tap_device_name, phy_dev_name) # Check if device needs to be added to bridge tap_device_in_bridge = self.get_bridge_for_tap_device(tap_device_name) if not tap_device_in_bridge: data = { 'tap_device_name': tap_device_name, 'bridge_name': bridge_name } LOG.debug( "Adding device %(tap_device_name)s to bridge " "%(bridge_name)s", data) if bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name): return False else: data = { 'tap_device_name': tap_device_name, 'bridge_name': bridge_name } LOG.debug( "%(tap_device_name)s already exists on bridge " "%(bridge_name)s", data) return True
def ensure_bridge(self, bridge_name, interface=None, ips=None, gateway=None, physical=False): """Create a bridge unless it already exists.""" # _bridge_exists_and_ensure_up instead of device_exists is used here # because there are cases where the bridge exists but it's not UP, # for example: # 1) A greenthread was executing this function and had not yet executed # "ip link set bridge_name up" before eventlet switched to this # thread running the same function # 2) The Nova VIF driver was running concurrently and had just created # the bridge, but had not yet put it UP if not self._bridge_exists_and_ensure_up(bridge_name): LOG.debug("Starting bridge %(bridge_name)s for subinterface " "%(interface)s", {'bridge_name': bridge_name, 'interface': interface}) bridge_device = bridge_lib.BridgeDevice.addbr(bridge_name) if bridge_device.setfd(0): return if bridge_device.disable_ipv6(): return if bridge_device.link.set_up(): return LOG.debug("Done starting bridge %(bridge_name)s for " "subinterface %(interface)s", {'bridge_name': bridge_name, 'interface': interface}) else: bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_name not in self.known_bridges: bridge_device.set_group_fwd_mask() bridge_device.set_ageing(cfg.CONF.network_bridge_ageing, cfg.CONF.network_physical_ageing, physical) bridge_device.set_multicast_snooping(cfg.CONF.network_bridge_multicast_snooping) bridge_device.disable_stp() self.known_bridges.add(bridge_name) if not interface: return bridge_name # Update IP info if necessary self.update_interface_ip_details(bridge_name, interface, ips, gateway) # Ensure interface is in bridge ip_lib.IPDevice(interface).link.set_master(bridge_name) return bridge_name
def remove_interface(bridge_name, interface_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): if not bridge_device.owns_interface(interface_name): return True LOG.debug( "Removing device %(interface_name)s from bridge " "%(bridge_name)s", { 'interface_name': interface_name, 'bridge_name': bridge_name }) if bridge_device.delif(interface_name): LOG.debug( "Done removing device %(interface_name)s from " "bridge %(bridge_name)s", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return True else: if not bridge_device.owns_interface(interface_name): LOG.debug( "Cannot remove %(interface_name)s from " "%(bridge_name)s. It is not on the bridge.", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return False msg = _("Error deleting %(interface_name)s from bridge " "%(bridge_name)s") % { 'interface_name': interface_name, 'bridge_name': bridge_name } raise RuntimeError(msg) else: LOG.debug( "Cannot remove device %(interface_name)s bridge " "%(bridge_name)s does not exist", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return False
def delete_bridge(self, bridge_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): physical_interfaces = set(self.interface_mappings.values()) interfaces_on_bridge = bridge_device.get_interfaces() for interface in interfaces_on_bridge: self.remove_interface(bridge_name, interface) if interface.startswith(VXLAN_INTERFACE_PREFIX): self.delete_interface(interface) else: # Match the vlan/flat interface in the bridge. # If the bridge has an IP, it mean that this IP was moved # from the current interface, which also mean that this # interface was not created by the agent. ips, gateway = self.get_interface_details(bridge_name) if ips: self.update_interface_ip_details(interface, bridge_name, ips, gateway) elif interface not in physical_interfaces: self.delete_interface(interface) try: LOG.debug("Deleting bridge %s", bridge_name) if bridge_device.link.set_down(): return if bridge_device.delbr(): return LOG.debug("Done deleting bridge %s", bridge_name) except RuntimeError: with excutils.save_and_reraise_exception() as ctxt: if not bridge_device.exists(): # the exception was likely a side effect of the bridge # being removed by nova during handling, # so we just return ctxt.reraise = False LOG.debug("Cannot delete bridge %s; it does not exist", bridge_name) return else: LOG.debug("Cannot delete bridge %s; it does not exist", bridge_name)
def setup_isoflat_bridges(self): for physical_network in self.iso_bridge_mappings: phy_br_name = self.iso_bridge_mappings[physical_network] if physical_network not in self.ovs_bridge_mappings: self._bridge_mappings_changed = True if not bridge_lib.BridgeDevice(phy_br_name).exists(): LOG.error( "Linux bridge %(bridge)s for physical network " "%(physical_network)s does not exist. Isoflat agent " "terminated!", { 'physical_network': physical_network, 'bridge': phy_br_name }) sys.exit(1) iso_br_name = self._allocate_bridge_name() self.ovs_bridge_mappings[physical_network] = iso_br_name else: iso_br_name = self.ovs_bridge_mappings[physical_network] self._setup_isoflat_bridge(phy_br_name, iso_br_name)
def unbind_interface_on_host(self, uuid): if uuid not in self.interfaces: LOG.debug('unknown port %s unbinding request - ignored' % uuid) else: props = self.interfaces[uuid] iface_idx = props['iface_idx'] LOG.debug('unbinding port %s, recorded as type %s' % (uuid, props['bind_type'])) # We no longer need this interface. Specifically if it's # a vhostuser interface it's annoying to have it around # because the VM's memory (hugepages) will not be # released. So, here, we destroy it. if props['bind_type'] == 'vhostuser': # remove port from bridge (sets to l3 mode) prior to deletion self.vpp.delete_from_bridge(iface_idx) self.vpp.delete_vhostuser(iface_idx) elif props['bind_type'] in ['maketap', 'plugtap']: # remove port from bridge (sets to l3 mode) prior to deletion self.vpp.delete_from_bridge(iface_idx) self.vpp.delete_tap(iface_idx) if props['bind_type'] == 'plugtap': name = uuid[0:11] bridge_name = 'br-' + name bridge = bridge_lib.BridgeDevice(bridge_name) if bridge.exists(): # These may fail, don't care much try: if bridge.owns_interface(props['int_tap_name']): bridge.delif(props['int_tap_name']) if bridge.owns_interface(props['ext_tap_name']): bridge.delif(props['ext_tap_name']) bridge.link.set_down() bridge.delbr() except Exception as exc: LOG.debug(exc) else: LOG.error('Unknown port type %s during unbind' % props['bind_type'])
def remove_interface(self, bridge_name, interface_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): if not bridge_device.owns_interface(interface_name): return True LOG.debug( "Removing device %(interface_name)s from bridge " "%(bridge_name)s", { 'interface_name': interface_name, 'bridge_name': bridge_name }) try: bridge_device.delif(interface_name) LOG.debug( "Done removing device %(interface_name)s from " "bridge %(bridge_name)s", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return True except RuntimeError: with excutils.save_and_reraise_exception() as ctxt: if not bridge_device.owns_interface(interface_name): # the exception was likely a side effect of the tap # being deleted by some other agent during handling ctxt.reraise = False LOG.debug( "Cannot remove %(interface_name)s from " "%(bridge_name)s. It is not on the bridge.", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return False else: LOG.debug( "Cannot remove device %(interface_name)s bridge " "%(bridge_name)s does not exist", { 'interface_name': interface_name, 'bridge_name': bridge_name }) return False
def remove_interface(self, bridge_name, interface_name): bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): if not bridge_lib.is_bridged_interface(interface_name): return True LOG.debug("Removing device %(interface_name)s from bridge " "%(bridge_name)s", {'interface_name': interface_name, 'bridge_name': bridge_name}) if bridge_device.delif(interface_name): return False LOG.debug("Done removing device %(interface_name)s from bridge " "%(bridge_name)s", {'interface_name': interface_name, 'bridge_name': bridge_name}) return True else: LOG.debug("Cannot remove device %(interface_name)s bridge " "%(bridge_name)s does not exist", {'interface_name': interface_name, 'bridge_name': bridge_name}) return False
def _add_tap_interface(self, network_id, network_type, physical_network, segmentation_id, tap_device_name, device_owner, mtu): """Add tap interface. If a VIF has been plugged into a network, this function will add the corresponding tap device to the relevant bridge. """ if not ip_lib.device_exists(tap_device_name): LOG.debug("Tap device: %s does not exist on " "this host, skipped", tap_device_name) return False bridge_name = self.get_existing_bridge_name(physical_network) if not bridge_name: bridge_name = self.get_bridge_name(network_id) if network_type == p_const.TYPE_LOCAL: self.ensure_local_bridge(network_id, bridge_name) elif not self.ensure_physical_in_bridge(network_id, network_type, physical_network, segmentation_id): return False if mtu: # <-None with device_details from older neutron servers. # we ensure the MTU here because libvirt does not set the # MTU of a bridge it creates and the tap device it creates will # inherit from the bridge its plugged into, which will be 1500 # at the time. See bug/1684326 for details. self._set_tap_mtu(tap_device_name, mtu) # Check if device needs to be added to bridge if not bridge_lib.BridgeDevice.get_interface_bridge( tap_device_name): data = {'tap_device_name': tap_device_name, 'bridge_name': bridge_name} LOG.debug("Adding device %(tap_device_name)s to bridge " "%(bridge_name)s", data) if bridge_lib.BridgeDevice(bridge_name).addif(tap_device_name): return False return True
def ensure_bridge(self, bridge_name): """Create a bridge unless it already exists.""" # _bridge_exists_and_ensure_up instead of device_exists is used here # because there are cases where the bridge exists but it's not UP, # for example: # 1) A greenthread was executing this function and had not yet executed # "ip link set bridge_name up" before eventlet switched to this # thread running the same function # 2) The Nova VIF driver was running concurrently and had just created # the bridge, but had not yet put it UP if not self._bridge_exists_and_ensure_up(bridge_name): bridge_device = bridge_lib.BridgeDevice.addbr(bridge_name) if bridge_device.setfd(0): return if bridge_device.disable_stp(): return if bridge_device.disable_ipv6(): return if bridge_device.link.set_up(): return else: bridge_device = bridge_lib.BridgeDevice(bridge_name) return bridge_device
def remove_interface(self, bridge_name, interface_name, down=False): return not ip_lib.IPDevice(interface).link.set_master(None, down=down) # Ignore the rest bridge_device = bridge_lib.BridgeDevice(bridge_name) if bridge_device.exists(): if not bridge_lib.is_bridged_interface(interface_name): return True LOG.debug("Removing device %(interface_name)s from bridge " "%(bridge_name)s", {'interface_name': interface_name, 'bridge_name': bridge_name}) if bridge_device.delif(interface_name): return False LOG.debug("Done removing device %(interface_name)s from bridge " "%(bridge_name)s", {'interface_name': interface_name, 'bridge_name': bridge_name}) return True else: LOG.debug("Cannot remove device %(interface_name)s bridge " "%(bridge_name)s does not exist", {'interface_name': interface_name, 'bridge_name': bridge_name}) return False
def test_set_forward_delay(self): bridge = bridge_lib.BridgeDevice(self.bridge.name) for fd in (10, 200, 3000, 40000): bridge.setfd(fd) br_info = self._get_bridge_info() self.assertEqual(fd, br_info['forward_delay'])
def get_tap_devices_count(self, bridge_name): if_list = bridge_lib.BridgeDevice(bridge_name).get_interfaces() return len([ interface for interface in if_list if interface.startswith(constants.TAP_DEVICE_PREFIX) ])
def _if_bridge_exists(bridge_name): ovs = ovs_lib.BaseOVS() if bridge_name in ovs.get_bridges() or bridge_lib.BridgeDevice( bridge_name).exists(): return True return False
def test_get_interfaces_no_bridge(self): bridge = bridge_lib.BridgeDevice('--fake--') self.assertEqual([], bridge.get_interfaces())
def test_owns_interface(self): br = bridge_lib.BridgeDevice('br-int') exists = lambda path: path == "/sys/class/net/br-int/brif/abc" with mock.patch('os.path.exists', side_effect=exists): self.assertTrue(br.owns_interface("abc")) self.assertFalse(br.owns_interface("def"))
def test_get_interfaces(self): br = bridge_lib.BridgeDevice('br-int') interfaces = ["tap1", "tap2"] with mock.patch('os.listdir', side_effect=[interfaces, OSError()]): self.assertEqual(interfaces, br.get_interfaces()) self.assertEqual([], br.get_interfaces())
def test_is_bridged_interface_and_remove(self): bridge = bridge_lib.BridgeDevice(self.bridge.name) bridge_port = self.port_fixture.br_port.name self.assertTrue(bridge_lib.is_bridged_interface(bridge_port)) bridge.delif(bridge_port) self.assertFalse(bridge_lib.is_bridged_interface(bridge_port))
def test_delete_bridge(self): bridge = bridge_lib.BridgeDevice(self.bridge.name) self.assertTrue(bridge.exists()) bridge.delbr() self.assertFalse(bridge.exists())