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 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 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 _report_state(self): # How many devices are likely used by a VM self.agent_state.get("configurations")["devices"] = self.int_br_device_count try: self.state_rpc.report_state(self.context, self.agent_state) self.agent_state.pop("start_flag", None) except Exception: LOG.exception(_LE("Failed reporting state!"))
def _report_state(self): # How many devices are likely used by a VM self.agent_state.get('configurations')['devices'] = ( self.int_br_device_count) try: self.state_rpc.report_state(self.context, self.agent_state) self.agent_state.pop('start_flag', None) except Exception: LOG.exception(_LE("Failed reporting state!"))
def get_datapath(self, retry_max=cfg.CONF.AGENT.get_datapath_retry_times): retry = 0 while self.datapath is None: self.datapath = ryu_api.get_datapath(self.ryuapp, int(self.datapath_id, 16)) retry += 1 if retry >= retry_max: LOG.error(_LE("Agent terminated!: Failed to get a datapath.")) raise SystemExit(1) time.sleep(1) self.set_dp(self.datapath)
def get_datapath(self, retry_max=cfg.CONF.AGENT.get_datapath_retry_times): retry = 0 while self.datapath is None: self.datapath = ryu_api.get_datapath(self.ryuapp, int(self.datapath_id, 16)) retry += 1 if retry >= retry_max: LOG.error(_LE('Agent terminated!: Failed to get a datapath.')) raise SystemExit(1) time.sleep(1) self.set_dp(self.datapath)
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 _setup_tunnel_port(self, br, port_name, tunnel_type): # NOTE(yamamoto): Ideally we can specify self.local_ip instead of # "0" here. However, Open vSwitch v2.0.2 doesn't support the # specific combination of flow/non-flow parameters we want to use # here. The limitation was removed for Open vSwitch>=v2.3. # TODO(yamamoto): Revisit when that version gets available for # relevant platforms. ofport = br.add_tunnel_port(port_name, "flow", "0", tunnel_type, self.vxlan_udp_port, self.dont_fragment) if ofport == ovs_lib.INVALID_OFPORT: LOG.error(_LE("Failed to set-up %(type)s tunnel port"), {"type": tunnel_type}) return 0 ofport = int(ofport) self.tun_ofports[tunnel_type] = ofport # NOTE(yamamoto): We include local_ip in the match here because # our tunnel port is with local_ip=0. See the above comment. br.check_in_port_add_tunnel_port(tunnel_type, ofport, self.local_ip) return ofport
def setup_ofp( self, controller_names=None, protocols="OpenFlow13", retry_max=cfg.CONF.AGENT.get_datapath_retry_times ): if not controller_names: host = ryu_cfg.CONF.ofp_listen_host if not host: # 127.0.0.1 is a default for agent style of controller host = "127.0.0.1" controller_names = ["tcp:%s:%d" % (host, ryu_cfg.CONF.ofp_tcp_listen_port)] try: self.set_protocols(protocols) self.set_controller(controller_names) except RuntimeError: LOG.exception(_LE("Agent terminated")) raise SystemExit(1) self.find_datapath_id() self.get_datapath(retry_max)
def _setup_tunnel_port(self, br, port_name, tunnel_type): # NOTE(yamamoto): Ideally we can specify self.local_ip instead of # "0" here. However, Open vSwitch v2.0.2 doesn't support the # specific combination of flow/non-flow parameters we want to use # here. The limitation was removed for Open vSwitch>=v2.3. # TODO(yamamoto): Revisit when that version gets available for # relevant platforms. ofport = br.add_tunnel_port(port_name, "flow", "0", tunnel_type, self.vxlan_udp_port, self.dont_fragment) if ofport == ovs_lib.INVALID_OFPORT: LOG.error(_LE("Failed to set-up %(type)s tunnel port"), {'type': tunnel_type}) return 0 ofport = int(ofport) self.tun_ofports[tunnel_type] = ofport # NOTE(yamamoto): We include local_ip in the match here because # our tunnel port is with local_ip=0. See the above comment. br.check_in_port_add_tunnel_port(tunnel_type, ofport, self.local_ip) return ofport
def setup_ofp(self, controller_names=None, protocols='OpenFlow13', retry_max=cfg.CONF.AGENT.get_datapath_retry_times): if not controller_names: host = ryu_cfg.CONF.ofp_listen_host if not host: # 127.0.0.1 is a default for agent style of controller host = '127.0.0.1' controller_names = [ "tcp:%s:%d" % (host, ryu_cfg.CONF.ofp_tcp_listen_port) ] try: self.set_protocols(protocols) self.set_controller(controller_names) except RuntimeError: LOG.exception(_LE("Agent terminated")) raise SystemExit(1) self.find_datapath_id() self.get_datapath(retry_max)
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