code: def port_list_with_trunk_types(request, **params):
      
      LOG.debug("port_list_with_trunk_types(): params=%s", params)
  
      # When trunk feature is disabled in neutron, we have no need to fetch
      # trunk information and port_list() is enough.
      if not is_extension_supported(request, 'trunk'):
          return port_list(request, **params)
  
      ports = neutronclient(request).list_ports(**params)['ports']
      trunk_filters = {}
      if 'tenant_id' in params:
          trunk_filters['tenant_id'] = params['tenant_id']
      trunks = neutronclient(request).list_trunks(**trunk_filters)['trunks']
      parent_ports = set(t['port_id'] for t in trunks)
      # Create a dict map for child ports (port ID to trunk info)
      child_ports = dict((s['port_id'],
                          {'trunk_id': t['id'],
                           'segmentation_type': s['segmentation_type'],
                           'segmentation_id': s['segmentation_id']})
                         for t in trunks
                         for s in t['sub_ports'])
  
      def _get_port_info(port):
          if port['id'] in parent_ports:
              return PortTrunkParent(port)
          elif port['id'] in child_ports:
              return PortTrunkSubport(port, child_ports[port['id']])
          else:
              return Port(port)
  
      return [_get_port_info(p) for p in ports]
docs: List neutron Ports for this tenant with possible TrunkPort indicated
  
      :param request: request context
  
      NOTE Performing two API calls is not atomic, but this is not worse
           than the original idea when we call port_list repeatedly for
           each network to perform identification run-time. We should
           handle the inconsistencies caused by non-atomic API requests
           gracefully.