<s> import copy <EOL> from oslo_config import cfg <EOL> from oslo_log import log as logging <EOL> import six <EOL> from nova import exception <EOL> from nova . i18n import _LE <EOL> from nova import objects <EOL> from nova . objects import fields <EOL> from nova . objects import pci_device_pool <EOL> from nova . pci import utils <EOL> from nova . pci import whitelist <EOL> CONF = cfg . CONF <EOL> LOG = logging . getLogger ( __name__ ) <EOL> class PciDeviceStats ( object ) : <EOL> """<STR_LIT>""" <EOL> pool_keys = [ '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' , '<STR_LIT>' ] <EOL> def __init__ ( self , stats = None , dev_filter = None ) : <EOL> super ( PciDeviceStats , self ) . __init__ ( ) <EOL> self . pools = [ pci_pool . to_dict ( ) <EOL> for pci_pool in stats ] if stats else [ ] <EOL> self . pools . sort ( key = lambda item : len ( item ) ) <EOL> self . dev_filter = dev_filter or whitelist . Whitelist ( <EOL> CONF . pci_passthrough_whitelist ) <EOL> def _equal_properties ( self , dev , entry , matching_keys ) : <EOL> return all ( dev . get ( prop ) == entry . get ( prop ) <EOL> for prop in matching_keys ) <EOL> def _find_pool ( self , dev_pool ) : <EOL> """<STR_LIT>""" <EOL> for pool in self . pools : <EOL> pool_keys = pool . copy ( ) <EOL> del pool_keys [ '<STR_LIT:count>' ] <EOL> del pool_keys [ '<STR_LIT>' ] <EOL> if ( len ( pool_keys . keys ( ) ) == len ( dev_pool . keys ( ) ) and <EOL> self . _equal_properties ( dev_pool , pool_keys , dev_pool . keys ( ) ) ) : <EOL> return pool <EOL> def _create_pool_keys_from_dev ( self , dev ) : <EOL> """<STR_LIT>""" <EOL> devspec = self . dev_filter . get_devspec ( dev ) <EOL> if not devspec : <EOL> return <EOL> tags = devspec . get_tags ( ) <EOL> pool = { k : getattr ( dev , k ) for k in self . pool_keys } <EOL> if tags : <EOL> pool . update ( tags ) <EOL> return pool <EOL> def add_device ( self , dev ) : <EOL> """<STR_LIT>""" <EOL> dev_pool = self . _create_pool_keys_from_dev ( dev ) <EOL> if dev_pool : <EOL> pool = self . _find_pool ( dev_pool ) <EOL> if not pool : <EOL> dev_pool [ '<STR_LIT:count>' ] = <NUM_LIT:0> <EOL> dev_pool [ '<STR_LIT>' ] = [ ] <EOL> self . pools . append ( dev_pool ) <EOL> self . pools . sort ( key = lambda item : len ( item ) ) <EOL> pool = dev_pool <EOL> pool [ '<STR_LIT:count>' ] += <NUM_LIT:1> <EOL> pool [ '<STR_LIT>' ] . append ( dev ) <EOL> @ staticmethod <EOL> def _decrease_pool_count ( pool_list , pool , count = <NUM_LIT:1> ) : <EOL> """<STR_LIT>""" <EOL> if pool [ '<STR_LIT:count>' ] > count : <EOL> pool [ '<STR_LIT:count>' ] -= count <EOL> count = <NUM_LIT:0> <EOL> else : <EOL> count -= pool [ '<STR_LIT:count>' ] <EOL> pool_list . remove ( pool ) <EOL> return count <EOL> def remove_device ( self , dev ) : <EOL> """<STR_LIT>""" <EOL> dev_pool = self . _create_pool_keys_from_dev ( dev ) <EOL> if dev_pool : <EOL> pool = self . _find_pool ( dev_pool ) <EOL> if not pool : <EOL> raise exception . PciDevicePoolEmpty ( <EOL> compute_node_id = dev . compute_node_id , address = dev . address ) <EOL> pool [ '<STR_LIT>' ] . remove ( dev ) <EOL> self . _decrease_pool_count ( self . pools , pool ) <EOL> def get_free_devs ( self ) : <EOL> free_devs = [ ] <EOL> for pool in self . pools : <EOL> free_devs . extend ( pool [ '<STR_LIT>' ] ) <EOL> return free_devs <EOL> def consume_requests ( self , pci_requests , numa_cells = None ) : <EOL> alloc_devices = [ ] <EOL> for request in pci_requests : <EOL> count = request . count <EOL> spec = request . spec <EOL> pools = self . _filter_pools_for_spec ( self . pools , spec ) <EOL> if numa_cells : <EOL> pools = self . _filter_pools_for_numa_cells ( pools , numa_cells ) <EOL> pools = self . _filter_non_requested_pfs ( request , pools ) <EOL> if sum ( [ pool [ '<STR_LIT:count>' ] for pool in pools ] ) < count : <EOL> LOG . error ( _LE ( "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" <EOL> "<STR_LIT>" ) ) <EOL> for d in range ( len ( alloc_devices ) ) : <EOL> self . add_device ( alloc_devices . pop ( ) ) <EOL> return None <EOL> for pool in pools : <EOL> if pool [ '<STR_LIT:count>' ] >= count : <EOL> num_alloc = count <EOL> else : <EOL> num_alloc = pool [ '<STR_LIT:count>' ] <EOL> count -= num_alloc <EOL> pool [ '<STR_LIT:count>' ] -= num_alloc <EOL> for d in range ( num_alloc ) : <EOL> pci_dev = pool [ '<STR_LIT>' ] . pop ( ) <EOL> self . _handle_device_dependents ( pci_dev ) <EOL> pci_dev . request_id = request . request_id <EOL> alloc_devices . append ( pci_dev ) <EOL> if count == <NUM_LIT:0> : <EOL> break <EOL> return alloc_devices <EOL> def _handle_device_dependents ( self , pci_dev ) : <EOL> """<STR_LIT>""" <EOL> if pci_dev . dev_type == fields . PciDeviceType . SRIOV_PF : <EOL> vfs_list = objects . PciDeviceList . get_by_parent_address ( <EOL> pci_dev . _context , <EOL> pci_dev . compute_node_id , <EOL> pci_dev . address ) <EOL> if vfs_list : <EOL> for vf in vfs_list : <EOL> self . remove_device ( vf ) <EOL> elif pci_dev . dev_type == fields . PciDeviceType . SRIOV_VF : <EOL> try : <EOL> parent = pci_dev . get_by_dev_addr ( pci_dev . _context , <EOL> pci_dev . compute_node_id , <EOL> pci_dev . parent_addr ) <EOL> if parent in self . get_free_devs ( ) : <EOL> self . remove_device ( parent ) <EOL> except exception . PciDeviceNotFound : <EOL> return <EOL> @ staticmethod <EOL> def _filter_pools_for_spec ( pools , request_specs ) : <EOL> return [ pool for pool in pools <EOL> if utils . pci_device_prop_match ( pool , request_specs ) ] <EOL> @ staticmethod <EOL> def _filter_pools_for_numa_cells ( pools , numa_cells ) : <EOL> numa_cells = [ None ] + [ cell . id for cell in numa_cells ] <EOL> return [ pool for pool in pools if any ( utils . pci_device_prop_match ( <EOL> pool , [ { '<STR_LIT>' : cell } ] ) <EOL> for cell in numa_cells ) ] <EOL> def _filter_non_requested_pfs ( self , request , matching_pools ) : <EOL> if all ( spec . get ( '<STR_LIT>' ) != fields . PciDeviceType . SRIOV_PF for <EOL> spec in request . spec ) : <EOL> matching_pools = self . _filter_pools_for_pfs ( matching_pools ) <EOL> return matching_pools <EOL> @ staticmethod <EOL> def _filter_pools_for_pfs ( pools ) : <EOL> return [ pool for pool in pools <EOL> if not pool . get ( '<STR_LIT>' ) == fields . PciDeviceType . SRIOV_PF ] <EOL> def _apply_request ( self , pools , request , numa_cells = None ) : <EOL> count = request . count <EOL> matching_pools = self . _filter_pools_for_spec ( pools , request . spec ) <EOL> if numa_cells : <EOL> matching_pools = self . _filter_pools_for_numa_cells ( matching_pools , <EOL> numa_cells ) <EOL> matching_pools = self . _filter_non_requested_pfs ( request , <EOL> matching_pools ) <EOL> if sum ( [ pool [ '<STR_LIT:count>' ] for pool in matching_pools ] ) < count : <EOL> return False <EOL> else : <EOL> for pool in matching_pools : <EOL> count = self . _decrease_pool_count ( pools , pool , count ) <EOL> if not count : <EOL> break <EOL> return True <EOL> def support_requests ( self , requests , numa_cells = None ) : <EOL> """<STR_LIT>""" <EOL> pools = copy . deepcopy ( self . pools ) <EOL> return all ( [ self . _apply_request ( pools , r , numa_cells ) <EOL> for r in requests ] ) <EOL> def apply_requests ( self , requests , numa_cells = None ) : <EOL> """<STR_LIT>""" <EOL> if not all ( [ self . _apply_request ( self . pools , r , numa_cells ) <EOL> for r in requests ] ) : <EOL> raise exception . PciDeviceRequestFailed ( requests = requests ) <EOL> def __iter__ ( self ) : <EOL> pools = [ ] <EOL> for pool in self . pools : <EOL> tmp = { k : v for k , v in six . iteritems ( pool ) if k != '<STR_LIT>' } <EOL> pools . append ( tmp ) <EOL> return iter ( pools ) <EOL> def clear ( self ) : <EOL> """<STR_LIT>""" <EOL> self . pools = [ ] <EOL> def __eq__ ( self , other ) : <EOL> return cmp ( self . pools , other . pools ) == <NUM_LIT:0> <EOL> def __ne__ ( self , other ) : <EOL> return not ( self == other ) <EOL> def to_device_pools_obj ( self ) : <EOL> """<STR_LIT>""" <EOL> stats = [ x for x in self ] <EOL> return pci_device_pool . from_pci_stats ( stats ) </s>
