def treat_devices_added_or_updated(self, devices, check_ports): resync = False all_ports = dict((p.normalized_port_name(), p) for p in self._get_ports(self.int_br) if p.is_neutron_port()) for device in devices: LOG.debug("Processing port %s", device) if device not in all_ports: # The port has disappeared and should not be processed # There is no need to put the port DOWN in the plugin as # it never went up in the first place LOG.info( _LI("Port %s was not found on the integration bridge " "and will therefore not be processed"), device, ) continue port = all_ports[device] try: details = self.plugin_rpc.get_device_details(self.context, device, self.agent_id) except Exception as e: LOG.debug("Unable to get port details for %(device)s: %(e)s", {"device": device, "e": e}) resync = True continue if device in check_ports: ps = check_ports[device] if port.ofport != ps.port.ofport: ps.port.vif_mac = details.get("mac_address") LOG.debug( "Repair ofport changed old port " "ofport: %(ofport)s vif_mac: %(mac)s", {"ofport": ps.port.ofport, "mac": ps.port.vif_mac}, ) LOG.debug( "Repair ofport changed new port " "ofport: %(ofport)s vif_mac: %(mac)s", {"ofport": port.ofport, "mac": port.vif_mac}, ) self._repair_ofport_change(ps.port, details["network_id"]) if "port_id" in details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), {"device": device, "details": details}) port.vif_mac = details.get("mac_address") self.treat_vif_port( port, details["port_id"], details["network_id"], details["network_type"], details["physical_network"], details["segmentation_id"], details["admin_state_up"], ) # update plugin about port status if details.get("admin_state_up"): LOG.debug("Setting status for %s to UP", device) self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: LOG.debug("Setting status for %s to DOWN", device) self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) LOG.info(_LI("Configuration for device %s completed."), device) else: LOG.warn(_LW("Device %s not defined on plugin"), device) if port and port.ofport != -1: self.port_dead(port) return resync
def treat_devices_added_or_updated(self, devices): resync = False all_ports = dict((p.normalized_port_name(), p) for p in self._get_ports(self.int_br) if p.is_neutron_port()) for device in devices: LOG.debug("Processing port %s", device) if device not in all_ports: # The port has disappeared and should not be processed # There is no need to put the port DOWN in the plugin as # it never went up in the first place LOG.info( _LI("Port %s was not found on the integration bridge " "and will therefore not be processed"), device) continue port = all_ports[device] try: details = self.plugin_rpc.get_device_details( self.context, device, self.agent_id) except Exception as e: LOG.debug("Unable to get port details for %(device)s: %(e)s", { 'device': device, 'e': e }) resync = True continue if 'port_id' in details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), { 'device': device, 'details': details }) port.vif_mac = details.get('mac_address') self.treat_vif_port(port, details['port_id'], details['network_id'], details['network_type'], details['physical_network'], details['segmentation_id'], details['admin_state_up']) # update plugin about port status if details.get('admin_state_up'): LOG.debug("Setting status for %s to UP", device) self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: LOG.debug("Setting status for %s to DOWN", device) self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) LOG.info(_LI("Configuration for device %s completed."), device) else: LOG.warn(_LW("Device %s not defined on plugin"), device) if (port and port.ofport != -1): self.port_dead(port) return resync
def port_unbound(self, vif_id, net_uuid=None): """Unbind port. Removes corresponding local vlan mapping object if this is its last VIF. :param vif_id: the id of the vif :param net_uuid: the net_uuid this port is associated with. """ net_uuid = net_uuid or self.get_net_uuid(vif_id) if not self.local_vlan_map.get(net_uuid): LOG.info(_LI('port_unbound() net_uuid %s not in local_vlan_map'), net_uuid) return lvm = self.local_vlan_map[net_uuid] port = lvm.vif_ports.pop(vif_id, None) self.int_br.check_in_port_delete_port(port.ofport) if not lvm.vif_ports: self.reclaim_local_vlan(net_uuid) if port.vif_mac is None: return self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
def reclaim_local_vlan(self, net_uuid): """Reclaim a local VLAN. :param net_uuid: the network uuid associated with this vlan. :param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id, vif_ids) mapping. """ lvm = self.local_vlan_map.pop(net_uuid, None) if lvm is None: LOG.debug("Network %s not used on agent.", net_uuid) return LOG.info(_LI("Reclaiming vlan = %(vlan_id)s from " "net-id = %(net_uuid)s"), {'vlan_id': lvm.vlan, 'net_uuid': net_uuid}) if lvm.network_type in constants.TUNNEL_NETWORK_TYPES: if self.enable_tunneling: self.int_br.reclaim_tenant_tunnel(lvm.network_type, lvm.vlan, lvm.segmentation_id) elif lvm.network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN]: phys_port = self.int_ofports[lvm.physical_network] self.int_br.reclaim_tenant_physnet(lvm.network_type, lvm.vlan, lvm.segmentation_id, phys_port) elif lvm.network_type == p_const.TYPE_LOCAL: # no flows needed for local networks pass else: LOG.error(_LE("Cannot reclaim unknown network type " "%(network_type)s for net-id=%(net_uuid)s"), {'network_type': lvm.network_type, 'net_uuid': net_uuid}) self.available_local_vlans.add(lvm.vlan)
def provision_local_vlan(self, net_uuid, network_type, physical_network, segmentation_id): """Provisions a local VLAN. :param net_uuid: the uuid of the network associated with this vlan. :param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat', 'local') :param physical_network: the physical network for 'vlan' or 'flat' :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel' """ if not self.available_local_vlans: LOG.error(_LE("No local VLAN available for net-id=%s"), net_uuid) return lvid = self.available_local_vlans.pop() LOG.info( _LI("Assigning %(vlan_id)s as local vlan for " "net-id=%(net_uuid)s"), { 'vlan_id': lvid, 'net_uuid': net_uuid }) self.local_vlan_map[net_uuid] = LocalVLANMapping( lvid, network_type, physical_network, segmentation_id) if network_type in constants.TUNNEL_NETWORK_TYPES: if self.enable_tunneling: self.int_br.provision_tenant_tunnel(network_type, lvid, segmentation_id) else: LOG.error( _LE("Cannot provision %(network_type)s network for " "net-id=%(net_uuid)s - tunneling disabled"), { 'network_type': network_type, 'net_uuid': net_uuid }) elif network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]: if physical_network in self.int_ofports: phys_port = self.int_ofports[physical_network] self.int_br.provision_tenant_physnet(network_type, lvid, segmentation_id, phys_port) else: LOG.error( _LE("Cannot provision %(network_type)s network for " "net-id=%(net_uuid)s - no bridge for " "physical_network %(physical_network)s"), { 'network_type': network_type, 'net_uuid': net_uuid, 'physical_network': physical_network }) elif network_type == p_const.TYPE_LOCAL: # no flows needed for local networks pass else: LOG.error( _LE("Cannot provision unknown network type " "%(network_type)s for net-id=%(net_uuid)s"), { 'network_type': network_type, 'net_uuid': net_uuid })
def _repair_ofport_change(self, port, net_uuid): if net_uuid not in self.local_vlan_map: LOG.info(_LI("_repair_ofport_change() net_uuid %s not in " "local_vlan_map"), net_uuid) return lvm = self.local_vlan_map[net_uuid] self.int_br.check_in_port_delete_port(port.ofport) if port.vif_mac is None: return self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
def _repair_ofport_change(self, port, net_uuid): if net_uuid not in self.local_vlan_map: LOG.info( _LI("_repair_ofport_change() net_uuid %s not in " "local_vlan_map"), net_uuid) return lvm = self.local_vlan_map[net_uuid] self.int_br.check_in_port_delete_port(port.ofport) if port.vif_mac is None: return self.int_br.local_out_delete_port(lvm.vlan, port.vif_mac)
def provision_local_vlan(self, net_uuid, network_type, physical_network, segmentation_id): """Provisions a local VLAN. :param net_uuid: the uuid of the network associated with this vlan. :param network_type: the network type ('gre', 'vxlan', 'vlan', 'flat', 'local') :param physical_network: the physical network for 'vlan' or 'flat' :param segmentation_id: the VID for 'vlan' or tunnel ID for 'tunnel' """ if not self.available_local_vlans: LOG.error(_LE("No local VLAN available for net-id=%s"), net_uuid) return lvid = self.available_local_vlans.pop() LOG.info(_LI("Assigning %(vlan_id)s as local vlan for " "net-id=%(net_uuid)s"), {'vlan_id': lvid, 'net_uuid': net_uuid}) self.local_vlan_map[net_uuid] = LocalVLANMapping(lvid, network_type, physical_network, segmentation_id) if network_type in constants.TUNNEL_NETWORK_TYPES: if self.enable_tunneling: self.int_br.provision_tenant_tunnel(network_type, lvid, segmentation_id) else: LOG.error(_LE("Cannot provision %(network_type)s network for " "net-id=%(net_uuid)s - tunneling disabled"), {'network_type': network_type, 'net_uuid': net_uuid}) elif network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]: if physical_network in self.int_ofports: phys_port = self.int_ofports[physical_network] self.int_br.provision_tenant_physnet(network_type, lvid, segmentation_id, phys_port) else: LOG.error(_LE("Cannot provision %(network_type)s network for " "net-id=%(net_uuid)s - no bridge for " "physical_network %(physical_network)s"), {'network_type': network_type, 'net_uuid': net_uuid, 'physical_network': physical_network}) elif network_type == p_const.TYPE_LOCAL: # no flows needed for local networks pass else: LOG.error(_LE("Cannot provision unknown network type " "%(network_type)s for net-id=%(net_uuid)s"), {'network_type': network_type, 'net_uuid': net_uuid})
def treat_devices_removed(self, devices): resync = False self.sg_agent.remove_devices_filter(devices) for device in devices: LOG.info(_LI("Attachment %s removed"), device) try: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) except Exception as e: LOG.debug("port_removed failed for %(device)s: %(e)s", {"device": device, "e": e}) resync = True continue self.port_unbound(device) return resync
def _agent_main(self, ryuapp): cfg.CONF.register_opts(ip_lib.OPTS) n_utils.log_opt_values(LOG) try: agent_config = create_agent_config_map(cfg.CONF) except ValueError: LOG.exception(_LE("Agent failed to create agent config map")) raise SystemExit(1) agent = OFANeutronAgent(ryuapp, **agent_config) self.arplib.set_bridge(agent.int_br) # Start everything. LOG.info(_LI("Agent initialized successfully, now running... ")) agent.daemon_loop()
def treat_devices_removed(self, devices): resync = False self.sg_agent.remove_devices_filter(devices) for device in devices: LOG.info(_LI("Attachment %s removed"), device) try: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) except Exception as e: LOG.debug("port_removed failed for %(device)s: %(e)s", { 'device': device, 'e': e }) resync = True continue self.port_unbound(device) return resync
def reclaim_local_vlan(self, net_uuid): """Reclaim a local VLAN. :param net_uuid: the network uuid associated with this vlan. :param lvm: a LocalVLANMapping object that tracks (vlan, lsw_id, vif_ids) mapping. """ lvm = self.local_vlan_map.pop(net_uuid, None) if lvm is None: LOG.debug("Network %s not used on agent.", net_uuid) return LOG.info( _LI("Reclaiming vlan = %(vlan_id)s from " "net-id = %(net_uuid)s"), { 'vlan_id': lvm.vlan, 'net_uuid': net_uuid }) if lvm.network_type in constants.TUNNEL_NETWORK_TYPES: if self.enable_tunneling: self.int_br.reclaim_tenant_tunnel(lvm.network_type, lvm.vlan, lvm.segmentation_id) elif lvm.network_type in [p_const.TYPE_FLAT, p_const.TYPE_VLAN]: phys_port = self.int_ofports[lvm.physical_network] self.int_br.reclaim_tenant_physnet(lvm.network_type, lvm.vlan, lvm.segmentation_id, phys_port) elif lvm.network_type == p_const.TYPE_LOCAL: # no flows needed for local networks pass else: LOG.error( _LE("Cannot reclaim unknown network type " "%(network_type)s for net-id=%(net_uuid)s"), { 'network_type': lvm.network_type, 'net_uuid': net_uuid }) self.available_local_vlans.add(lvm.vlan)
def daemon_loop(self): # TODO(yamamoto): # It might be better to monitor port status async messages sync = True ports = set() tunnel_sync = True while True: start = time.time() port_stats = {'regular': {'added': 0, 'updated': 0, 'removed': 0}} LOG.debug("Agent daemon_loop - iteration:%d started", self.iter_num) if sync: LOG.info(_LI("Agent out of sync with plugin!")) ports.clear() sync = False # Notify the plugin of tunnel IP if self.enable_tunneling and tunnel_sync: LOG.info(_LI("Agent tunnel out of sync with plugin!")) try: tunnel_sync = self.tunnel_sync() except Exception: LOG.exception(_LE("Error while synchronizing tunnels")) tunnel_sync = True LOG.debug("Agent daemon_loop - iteration:%(iter_num)d - " "starting polling. Elapsed:%(elapsed).3f", {'iter_num': self.iter_num, 'elapsed': time.time() - start}) try: # Save updated ports dict to perform rollback in # case resync would be needed, and then clear # self.updated_ports. As the greenthread should not yield # between these two statements, this will be thread-safe updated_ports_copy = self.updated_ports self.updated_ports = set() port_info = self.scan_ports(ports, updated_ports_copy) ports = port_info['current'] # In the following calling port_info may be updated port_status_list = self.ryuapp.get_port_status_list() check_ports = self._check_port_status_list(port_status_list, port_info) LOG.debug("Agent daemon_loop - iteration:%(iter_num)d - " "port information retrieved. " "Elapsed:%(elapsed).3f", {'iter_num': self.iter_num, 'elapsed': time.time() - start}) # Secure and wire/unwire VIFs and update their status # on Neutron server if (self._port_info_has_changes(port_info) or self.sg_agent.firewall_refresh_needed()): LOG.debug("Starting to process devices in:%s", port_info) # If treat devices fails - must resync with plugin sync = self.process_network_ports(port_info, check_ports) LOG.debug("Agent daemon_loop - " "iteration:%(iter_num)d - " "ports processed. Elapsed:%(elapsed).3f", {'iter_num': self.iter_num, 'elapsed': time.time() - start}) port_stats['regular']['added'] = ( len(port_info.get('added', []))) port_stats['regular']['updated'] = ( len(port_info.get('updated', []))) port_stats['regular']['removed'] = ( len(port_info.get('removed', []))) except Exception: LOG.exception(_LE("Error while processing VIF ports")) # Put the ports back in self.updated_port self.updated_ports |= updated_ports_copy sync = True # sleep till end of polling interval elapsed = (time.time() - start) LOG.debug("Agent daemon_loop - iteration:%(iter_num)d " "completed. Processed ports statistics:" "%(port_stats)s. Elapsed:%(elapsed).3f", {'iter_num': self.iter_num, 'port_stats': port_stats, 'elapsed': elapsed}) if (elapsed < self.polling_interval): time.sleep(self.polling_interval - elapsed) else: LOG.debug("Loop iteration exceeded interval " "(%(polling_interval)s vs. %(elapsed)s)!", {'polling_interval': self.polling_interval, 'elapsed': elapsed}) self.iter_num = self.iter_num + 1
def daemon_loop(self): # TODO(yamamoto): # It might be better to monitor port status async messages sync = True ports = set() tunnel_sync = True while True: start = time.time() port_stats = {'regular': {'added': 0, 'updated': 0, 'removed': 0}} LOG.debug("Agent daemon_loop - iteration:%d started", self.iter_num) if sync: LOG.info(_LI("Agent out of sync with plugin!")) ports.clear() sync = False # Notify the plugin of tunnel IP if self.enable_tunneling and tunnel_sync: LOG.info(_LI("Agent tunnel out of sync with plugin!")) try: tunnel_sync = self.tunnel_sync() except Exception: LOG.exception(_LE("Error while synchronizing tunnels")) tunnel_sync = True LOG.debug( "Agent daemon_loop - iteration:%(iter_num)d - " "starting polling. Elapsed:%(elapsed).3f", { 'iter_num': self.iter_num, 'elapsed': time.time() - start }) try: # Save updated ports dict to perform rollback in # case resync would be needed, and then clear # self.updated_ports. As the greenthread should not yield # between these two statements, this will be thread-safe updated_ports_copy = self.updated_ports self.updated_ports = set() port_info = self.scan_ports(ports, updated_ports_copy) ports = port_info['current'] # In the following calling port_info may be updated port_status_list = self.ryuapp.get_port_status_list() check_ports = self._check_port_status_list( port_status_list, port_info) LOG.debug( "Agent daemon_loop - iteration:%(iter_num)d - " "port information retrieved. " "Elapsed:%(elapsed).3f", { 'iter_num': self.iter_num, 'elapsed': time.time() - start }) # Secure and wire/unwire VIFs and update their status # on Neutron server if (self._port_info_has_changes(port_info) or self.sg_agent.firewall_refresh_needed()): LOG.debug("Starting to process devices in:%s", port_info) # If treat devices fails - must resync with plugin sync = self.process_network_ports(port_info, check_ports) LOG.debug( "Agent daemon_loop - " "iteration:%(iter_num)d - " "ports processed. Elapsed:%(elapsed).3f", { 'iter_num': self.iter_num, 'elapsed': time.time() - start }) port_stats['regular']['added'] = (len( port_info.get('added', []))) port_stats['regular']['updated'] = (len( port_info.get('updated', []))) port_stats['regular']['removed'] = (len( port_info.get('removed', []))) except Exception: LOG.exception(_LE("Error while processing VIF ports")) # Put the ports back in self.updated_port self.updated_ports |= updated_ports_copy sync = True # sleep till end of polling interval elapsed = (time.time() - start) LOG.debug( "Agent daemon_loop - iteration:%(iter_num)d " "completed. Processed ports statistics:" "%(port_stats)s. Elapsed:%(elapsed).3f", { 'iter_num': self.iter_num, 'port_stats': port_stats, 'elapsed': elapsed }) if (elapsed < self.polling_interval): time.sleep(self.polling_interval - elapsed) else: LOG.debug( "Loop iteration exceeded interval " "(%(polling_interval)s vs. %(elapsed)s)!", { 'polling_interval': self.polling_interval, 'elapsed': elapsed }) self.iter_num = self.iter_num + 1