文件名:linuxbridge_neutron_agent.py
主要走读LinuxBridgeManager类。
class LinuxBridgeManager: def __init__(self, interface_mappings, root_helper): self.interface_mappings = interface_mappings self.root_helper = root_helper self.ip = ip_lib.IPWrapper(self.root_helper) # VXLAN related parameters: self.local_ip = cfg.CONF.VXLAN.local_ip self.vxlan_mode = lconst.VXLAN_NONE if cfg.CONF.VXLAN.enable_vxlan: self.local_int = self.get_interface_by_ip(self.local_ip) if self.local_int: self.check_vxlan_support() else: LOG.warning(_('VXLAN is enabled, a valid local_ip ' 'must be provided')) # Store network mapping to segments self.network_map = {} ##其中interface_mappings为读取 etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini文件中physical_interface_mappings的值,如physnet1:eth1,__init__方法主要给linuxbridgeManager初始化一些信息。包含上述interface_mappings,vxlan,network相关信息。 def interface_exists_on_bridge(self, bridge, interface): directory = '/sys/class/net/%s/brif' % bridge for filename in os.listdir(directory): if filename == interface: return True return False ##判断网口是否存在于网桥上,可以看到判断方法是在网桥目录下的brif目录下是否存在接口文件。 def get_bridge_name(self, network_id): if not network_id: LOG.warning(_("Invalid Network ID, will lead to incorrect bridge" "name")) bridge_name = BRIDGE_NAME_PREFIX + network_id[0:11] return bridge_name ##BRIDGE_NAME_PREFIX = "brq",也就是说network对应的bridge的名称为"brq+network_id的前12位" 此处的network是neutron里面的network? def get_subinterface_name(self, physical_interface, vlan_id): if not vlan_id: LOG.warning(_("Invalid VLAN ID, will lead to incorrect " "subinterface name")) subinterface_name = '%s.%s' % (physical_interface, vlan_id) return subinterface_name ##获取(准确来讲应该叫生成吧)子接口名称,子接口名称为物理接口+vlanId生成。 def get_tap_device_name(self, interface_id): if not interface_id: LOG.warning(_("Invalid Interface ID, will lead to incorrect " "tap device name")) tap_device_name = TAP_INTERFACE_PREFIX + interface_id[0:11] return tap_device_name ##TAP_INTERFACE_PREFIX = "tap",于虚拟机port相连的tap口的名称为,"tap+port的前12位" def get_vxlan_device_name(self, segmentation_id): if 0 <= int(segmentation_id) <= constants.MAX_VXLAN_VNI: return VXLAN_INTERFACE_PREFIX + str(segmentation_id) else: LOG.warning(_("Invalid Segmentation ID: %s, will lead to " "incorrect vxlan device name"), segmentation_id) ##VXLAN_INTERFACE_PREFIX = "vxlan-",vxlan设备名为"vxlan-segmentation_id" def get_all_neutron_bridges(self): neutron_bridge_list = [] bridge_list = os.listdir(BRIDGE_FS) for bridge in bridge_list: if bridge.startswith(BRIDGE_NAME_PREFIX): neutron_bridge_list.append(bridge) return neutron_bridge_list ##BRIDGE_FS = "/sys/devices/virtual/net/",查询"/sys/devices/virtual/net/"目录下的"brq"设备 def get_interfaces_on_bridge(self, bridge_name): if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): bridge_interface_path = BRIDGE_INTERFACES_FS.replace( BRIDGE_NAME_PLACEHOLDER, bridge_name) return os.listdir(bridge_interface_path) else: return [] ##查询指定网桥brif目录下的所有接口设备。 def get_tap_devices_count(self, bridge_name): bridge_interface_path = BRIDGE_INTERFACES_FS.replace( BRIDGE_NAME_PLACEHOLDER, bridge_name) try: if_list = os.listdir(bridge_interface_path) return len([interface for interface in if_list if interface.startswith(TAP_INTERFACE_PREFIX)]) except OSError: return 0 ##获取网桥下所有tap设备 def get_interface_by_ip(self, ip): for device in self.ip.get_devices(): if device.addr.list(to=ip): return device.name def get_bridge_for_tap_device(self, tap_device_name): bridges = self.get_all_neutron_bridges() for bridge in bridges: interfaces = self.get_interfaces_on_bridge(bridge) if tap_device_name in interfaces: return bridge return None def is_device_on_bridge(self, device_name): if not device_name: return False else: bridge_port_path = BRIDGE_PORT_FS_FOR_DEVICE.replace( DEVICE_NAME_PLACEHOLDER, device_name) return os.path.exists(bridge_port_path) def ensure_vlan_bridge(self, network_id, physical_interface, vlan_id): """Create a vlan and bridge unless they already exist.""" interface = self.ensure_vlan(physical_interface, vlan_id) bridge_name = self.get_bridge_name(network_id) ips, gateway = self.get_interface_details(interface) if self.ensure_bridge(bridge_name, interface, ips, gateway): return interface ##核心: ##1、 ip link add link <physical_interface> name <physical_interface.vlanId> type vlan id <vlanId> ##2、brctl addbr <bridge_name> ##3、brctl setfd <bridge_name> ##4、brctl stp <bridge_name> off ##5、ip link set <bridge_name> up 未完待续.... def ensure_vxlan_bridge(self, network_id, segmentation_id): """Create a vxlan and bridge unless they already exist.""" interface = self.ensure_vxlan(segmentation_id) if not interface: LOG.error(_("Failed creating vxlan interface for " "%(segmentation_id)s"), {segmentation_id: segmentation_id}) return bridge_name = self.get_bridge_name(network_id) self.ensure_bridge(bridge_name, interface) return interface def get_interface_details(self, interface): device = self.ip.device(interface) ips = device.addr.list(scope='global') # Update default gateway if necessary gateway = device.route.get_gateway(scope='global') return ips, gateway def ensure_flat_bridge(self, network_id, physical_interface): """Create a non-vlan bridge unless it already exists.""" bridge_name = self.get_bridge_name(network_id) ips, gateway = self.get_interface_details(physical_interface) if self.ensure_bridge(bridge_name, physical_interface, ips, gateway): return physical_interface def ensure_local_bridge(self, network_id): """Create a local bridge unless it already exists.""" bridge_name = self.get_bridge_name(network_id) return self.ensure_bridge(bridge_name) def ensure_vlan(self, physical_interface, vlan_id): """Create a vlan unless it already exists.""" interface = self.get_subinterface_name(physical_interface, vlan_id) if not ip_lib.device_exists(interface, root_helper=self.root_helper): LOG.debug(_("Creating subinterface %(interface)s for " "VLAN %(vlan_id)s on interface " "%(physical_interface)s"), {'interface': interface, 'vlan_id': vlan_id, 'physical_interface': physical_interface}) if utils.execute(['ip', 'link', 'add', 'link', physical_interface, 'name', interface, 'type', 'vlan', 'id', vlan_id], root_helper=self.root_helper): return if utils.execute(['ip', 'link', 'set', interface, 'up'], root_helper=self.root_helper): return LOG.debug(_("Done creating subinterface %s"), interface) return interface def ensure_vxlan(self, segmentation_id): """Create a vxlan unless it already exists.""" interface = self.get_vxlan_device_name(segmentation_id) if not ip_lib.device_exists(interface, root_helper=self.root_helper): LOG.debug(_("Creating vxlan interface %(interface)s for " "VNI %(segmentation_id)s"), {'interface': interface, 'segmentation_id': segmentation_id}) args = {'dev': self.local_int} if self.vxlan_mode == lconst.VXLAN_MCAST: args['group'] = cfg.CONF.VXLAN.vxlan_group if cfg.CONF.VXLAN.ttl: args['ttl'] = cfg.CONF.VXLAN.ttl if cfg.CONF.VXLAN.tos: args['tos'] = cfg.CONF.VXLAN.tos if cfg.CONF.VXLAN.l2_population: args['proxy'] = True int_vxlan = self.ip.add_vxlan(interface, segmentation_id, **args) int_vxlan.link.set_up() LOG.debug(_("Done creating vxlan interface %s"), interface) return interface def update_interface_ip_details(self, destination, source, ips, gateway): if ips or gateway: dst_device = self.ip.device(destination) src_device = self.ip.device(source) # Append IP's to bridge if necessary if ips: for ip in ips: dst_device.addr.add(ip_version=ip['ip_version'], cidr=ip['cidr'], broadcast=ip['broadcast']) if gateway: # Ensure that the gateway can be updated by changing the metric metric = 100 if 'metric' in gateway: metric = gateway['metric'] - 1 dst_device.route.add_gateway(gateway=gateway['gateway'], metric=metric) src_device.route.delete_gateway(gateway=gateway['gateway']) # Remove IP's from interface if ips: for ip in ips: src_device.addr.delete(ip_version=ip['ip_version'], cidr=ip['cidr']) def _bridge_exists_and_ensure_up(self, bridge_name): """Check if the bridge exists and make sure it is up.""" br = ip_lib.IPDevice(bridge_name, self.root_helper) try: # If the device doesn't exist this will throw a RuntimeError br.link.set_up() except RuntimeError: return False return True def ensure_bridge(self, bridge_name, interface=None, ips=None, gateway=None): """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}) if utils.execute(['brctl', 'addbr', bridge_name], root_helper=self.root_helper): return if utils.execute(['brctl', 'setfd', bridge_name, str(0)], root_helper=self.root_helper): return if utils.execute(['brctl', 'stp', bridge_name, 'off'], root_helper=self.root_helper): return if utils.execute(['ip', 'link', 'set', bridge_name, 'up'], root_helper=self.root_helper): return LOG.debug(_("Done starting bridge %(bridge_name)s for " "subinterface %(interface)s"), {'bridge_name': bridge_name, 'interface': interface}) if not interface: return bridge_name # Update IP info if necessary self.update_interface_ip_details(bridge_name, interface, ips, gateway) # Check if the interface is part of the bridge if not self.interface_exists_on_bridge(bridge_name, interface): try: # Check if the interface is not enslaved in another bridge if self.is_device_on_bridge(interface): bridge = self.get_bridge_for_tap_device(interface) utils.execute(['brctl', 'delif', bridge, interface], root_helper=self.root_helper) utils.execute(['brctl', 'addif', bridge_name, interface], root_helper=self.root_helper) 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 ensure_physical_in_bridge(self, network_id, network_type, physical_network, segmentation_id): if network_type == p_const.TYPE_VXLAN: if self.vxlan_mode == lconst.VXLAN_NONE: LOG.error(_("Unable to add vxlan interface for network %s"), network_id) return return self.ensure_vxlan_bridge(network_id, segmentation_id) physical_interface = self.interface_mappings.get(physical_network) if not physical_interface: LOG.error(_("No mapping for physical network %s"), physical_network) return if network_type == p_const.TYPE_FLAT: return self.ensure_flat_bridge(network_id, physical_interface) elif network_type == p_const.TYPE_VLAN: return self.ensure_vlan_bridge(network_id, physical_interface, segmentation_id) else: LOG.error(_("Unknown network_type %(network_type)s for network " "%(network_id)s."), {network_type: network_type, network_id: network_id}) 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, root_helper=self.root_helper): LOG.debug(_("Tap device: %s does not exist on " "this host, skipped"), tap_device_name) return False bridge_name = self.get_bridge_name(network_id) if network_type == p_const.TYPE_LOCAL: self.ensure_local_bridge(network_id) elif not self.ensure_physical_in_bridge(network_id, network_type, physical_network, segmentation_id): return False # 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} msg = _("Adding device %(tap_device_name)s to bridge " "%(bridge_name)s") % data LOG.debug(msg) if utils.execute(['brctl', 'addif', bridge_name, tap_device_name], root_helper=self.root_helper): return False else: data = {'tap_device_name': tap_device_name, 'bridge_name': bridge_name} msg = _("%(tap_device_name)s already exists on bridge " "%(bridge_name)s") % data LOG.debug(msg) return True def add_interface(self, network_id, network_type, physical_network, segmentation_id, port_id): self.network_map[network_id] = NetworkSegment(network_type, physical_network, segmentation_id) tap_device_name = self.get_tap_device_name(port_id) return self.add_tap_interface(network_id, network_type, physical_network, segmentation_id, tap_device_name) def delete_vlan_bridge(self, bridge_name): if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): interfaces_on_bridge = self.get_interfaces_on_bridge(bridge_name) for interface in interfaces_on_bridge: self.remove_interface(bridge_name, interface) if interface.startswith(VXLAN_INTERFACE_PREFIX): self.delete_vxlan(interface) continue for physical_interface in self.interface_mappings.itervalues(): if (interface.startswith(physical_interface)): ips, gateway = self.get_interface_details(bridge_name) if ips: # This is a flat network or a VLAN interface that # was setup outside of neutron => return IP's from # bridge to interface self.update_interface_ip_details(interface, bridge_name, ips, gateway) elif physical_interface != interface: self.delete_vlan(interface) LOG.debug(_("Deleting bridge %s"), bridge_name) if utils.execute(['ip', 'link', 'set', bridge_name, 'down'], root_helper=self.root_helper): return if utils.execute(['brctl', 'delbr', bridge_name], root_helper=self.root_helper): return LOG.debug(_("Done deleting bridge %s"), bridge_name) else: LOG.error(_("Cannot delete bridge %s, does not exist"), bridge_name) def remove_empty_bridges(self): for network_id in self.network_map.keys(): bridge_name = self.get_bridge_name(network_id) if not self.get_tap_devices_count(bridge_name): self.delete_vlan_bridge(bridge_name) del self.network_map[network_id] def remove_interface(self, bridge_name, interface_name): if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): if not self.is_device_on_bridge(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 utils.execute(['brctl', 'delif', bridge_name, interface_name], root_helper=self.root_helper): 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 delete_vlan(self, interface): if ip_lib.device_exists(interface, root_helper=self.root_helper): LOG.debug(_("Deleting subinterface %s for vlan"), interface) if utils.execute(['ip', 'link', 'set', interface, 'down'], root_helper=self.root_helper): return if utils.execute(['ip', 'link', 'delete', interface], root_helper=self.root_helper): return LOG.debug(_("Done deleting subinterface %s"), interface) def delete_vxlan(self, interface): if ip_lib.device_exists(interface, root_helper=self.root_helper): LOG.debug(_("Deleting vxlan interface %s for vlan"), interface) int_vxlan = self.ip.device(interface) int_vxlan.link.set_down() int_vxlan.link.delete() LOG.debug(_("Done deleting vxlan interface %s"), interface) def update_devices(self, registered_devices): devices = self.get_tap_devices() if devices == registered_devices: return added = devices - registered_devices removed = registered_devices - devices return {'current': devices, 'added': added, 'removed': removed} def get_tap_devices(self): devices = set() for device in os.listdir(BRIDGE_FS): if device.startswith(TAP_INTERFACE_PREFIX): devices.add(device) return devices def vxlan_ucast_supported(self): if not cfg.CONF.VXLAN.l2_population: return False if not ip_lib.iproute_arg_supported( ['bridge', 'fdb'], 'append', self.root_helper): LOG.warning(_('Option "%(option)s" must be supported by command ' '"%(command)s" to enable %(mode)s mode') % {'option': 'append', 'command': 'bridge fdb', 'mode': 'VXLAN UCAST'}) return False for segmentation_id in range(1, constants.MAX_VXLAN_VNI + 1): if not ip_lib.device_exists( self.get_vxlan_device_name(segmentation_id), root_helper=self.root_helper): break else: LOG.error(_('No valid Segmentation ID to perform UCAST test.')) return False test_iface = self.ensure_vxlan(segmentation_id) try: utils.execute( cmd=['bridge', 'fdb', 'append', constants.FLOODING_ENTRY[0], 'dev', test_iface, 'dst', '1.1.1.1'], root_helper=self.root_helper) return True except RuntimeError: return False finally: self.delete_vxlan(test_iface) def vxlan_mcast_supported(self): if not cfg.CONF.VXLAN.vxlan_group: LOG.warning(_('VXLAN muticast group must be provided in ' 'vxlan_group option to enable VXLAN MCAST mode')) return False if not ip_lib.iproute_arg_supported( ['ip', 'link', 'add', 'type', 'vxlan'], 'proxy', self.root_helper): LOG.warning(_('Option "%(option)s" must be supported by command ' '"%(command)s" to enable %(mode)s mode') % {'option': 'proxy', 'command': 'ip link add type vxlan', 'mode': 'VXLAN MCAST'}) return False return True def vxlan_module_supported(self): try: utils.execute(cmd=['modinfo', 'vxlan']) return True except RuntimeError: return False def check_vxlan_support(self): self.vxlan_mode = lconst.VXLAN_NONE if not self.vxlan_module_supported(): LOG.error(_('Linux kernel vxlan module and iproute2 3.8 or above ' 'are required to enable VXLAN.')) raise exceptions.VxlanNetworkUnsupported() if self.vxlan_ucast_supported(): self.vxlan_mode = lconst.VXLAN_UCAST elif self.vxlan_mcast_supported(): self.vxlan_mode = lconst.VXLAN_MCAST else: raise exceptions.VxlanNetworkUnsupported() LOG.debug(_('Using %s VXLAN mode'), self.vxlan_mode) def fdb_ip_entry_exists(self, mac, ip, interface): entries = utils.execute(['ip', 'neigh', 'show', 'to', ip, 'dev', interface], root_helper=self.root_helper) return mac in entries def fdb_bridge_entry_exists(self, mac, interface, agent_ip=None): entries = utils.execute(['bridge', 'fdb', 'show', 'dev', interface], root_helper=self.root_helper) if not agent_ip: return mac in entries return (agent_ip in entries and mac in entries) def add_fdb_ip_entry(self, mac, ip, interface): utils.execute(['ip', 'neigh', 'replace', ip, 'lladdr', mac, 'dev', interface, 'nud', 'permanent'], root_helper=self.root_helper, check_exit_code=False) def remove_fdb_ip_entry(self, mac, ip, interface): utils.execute(['ip', 'neigh', 'del', ip, 'lladdr', mac, 'dev', interface], root_helper=self.root_helper, check_exit_code=False) def add_fdb_bridge_entry(self, mac, agent_ip, interface, operation="add"): utils.execute(['bridge', 'fdb', operation, mac, 'dev', interface, 'dst', agent_ip], root_helper=self.root_helper, check_exit_code=False) def remove_fdb_bridge_entry(self, mac, agent_ip, interface): utils.execute(['bridge', 'fdb', 'del', mac, 'dev', interface, 'dst', agent_ip], root_helper=self.root_helper, check_exit_code=False) def add_fdb_entries(self, agent_ip, ports, interface): for mac, ip in ports: if mac != constants.FLOODING_ENTRY[0]: self.add_fdb_ip_entry(mac, ip, interface) self.add_fdb_bridge_entry(mac, agent_ip, interface) elif self.vxlan_mode == lconst.VXLAN_UCAST: if self.fdb_bridge_entry_exists(mac, interface): self.add_fdb_bridge_entry(mac, agent_ip, interface, "append") else: self.add_fdb_bridge_entry(mac, agent_ip, interface) def remove_fdb_entries(self, agent_ip, ports, interface): for mac, ip in ports: if mac != constants.FLOODING_ENTRY[0]: self.remove_fdb_ip_entry(mac, ip, interface) self.remove_fdb_bridge_entry(mac, agent_ip, interface) elif self.vxlan_mode == lconst.VXLAN_UCAST: self.remove_fdb_bridge_entry(mac, agent_ip, interface)
相关推荐
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,亲测可用
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装