def interfaces(device=None,
               interface=None,
               title=None,
               pattern=None,
               ipnet=None,
               best=True,
               display=_DEFAULT_DISPLAY):
    '''
    Search for interfaces details in the following mine functions:

    - net.interfaces
    - net.ipaddrs

    Optional arguments:

    device
        Return interface data from a certain device only.

    interface
        Return data selecting by interface name.

    pattern
        Return interfaces that contain a certain pattern in their description.

    ipnet
        Return interfaces whose IP networks associated include this IP network.

    best: ``True``
        When ``ipnet`` is specified, this argument says if the runner should return only the best match
        (the output will contain at most one row). Default: ``True`` (return only the best match).

    display: True
        Display on the screen or return structured object? Default: ``True`` (return on the CLI).

    title
        Display a custom title for the table.

    CLI Example:

    .. code-block:: bash

        $ sudo salt-run net.interfaces interface=vt-0/0/10

    Output Example:

    .. code-block:: text

        Details for interface xe-0/0/0
        _________________________________________________________________________________________________________________
        |    Device    | Interface | Interface Description |  UP  | Enabled | Speed [Mbps] | MAC Address | IP Addresses |
        _________________________________________________________________________________________________________________
        | edge01.bjm01 | vt-0/0/10 |                       | True |   True  |     1000     |             |              |
        _________________________________________________________________________________________________________________
        | edge01.flw01 | vt-0/0/10 |                       | True |   True  |     1000     |             |              |
        _________________________________________________________________________________________________________________
        | edge01.pos01 | vt-0/0/10 |                       | True |   True  |     1000     |             |              |
        _________________________________________________________________________________________________________________
        | edge01.oua01 | vt-0/0/10 |                       | True |   True  |     1000     |             |              |
        _________________________________________________________________________________________________________________
    '''

    def _ipnet_belongs(net):
        '''
        Helper to tell if a IP address or network belong to a certain network.
        '''
        if net == '0.0.0.0/0':
            return False
        net_obj = _get_network_obj(net)
        if not net_obj:
            return False
        return ipnet in net_obj or net_obj in ipnet

    labels = {
        'device': 'Device',
        'interface': 'Interface',
        'interface_description': 'Interface Description',
        'is_up': 'UP',
        'is_enabled': 'Enabled',
        'speed': 'Speed [Mbps]',
        'mac': 'MAC Address',
        'ips': 'IP Addresses'
    }
    rows = []

    net_runner_opts = _get_net_runner_opts()

    if pattern:
        title = 'Pattern "{0}" found in the description of the following interfaces'.format(pattern)
    if not title:
        title = 'Details'
        if interface:
            title += ' for interface {0}'.format(interface)
        else:
            title += ' for all interfaces'
        if device:
            title += ' on device {0}'.format(device)
        if ipnet:
            title += ' that include network {net}'.format(net=six.text_type(ipnet))
            if best:
                title += ' - only best match returned'

    all_interfaces = _get_mine('net.interfaces')
    all_ipaddrs = _get_mine('net.ipaddrs')

    if device:
        all_interfaces = {device: all_interfaces.get(device, {})}

    if ipnet and not isinstance(ipnet, IPNetwork):
        ipnet = _get_network_obj(ipnet)

    best_row = {}
    best_net_match = None
    for device, net_interfaces_out in six.iteritems(all_interfaces):  # pylint: disable=too-many-nested-blocks
        if not net_interfaces_out:
            continue
        if not net_interfaces_out.get('result', False):
            continue
        selected_device_interfaces = net_interfaces_out.get('out', {})
        if interface:
            selected_device_interfaces = {interface: selected_device_interfaces.get(interface, {})}
        for interface_name, interface_details in six.iteritems(selected_device_interfaces):
            if not interface_details:
                continue
            if ipnet and interface_name in net_runner_opts.get('ignore_interfaces'):
                continue
            interface_description = (interface_details.get('description', '') or '')
            if pattern:
                if pattern.lower() not in interface_description.lower():
                    continue
            if not all_ipaddrs.get(device, {}).get('result', False):
                continue
            ips = []
            device_entry = {
                'device': device,
                'interface': interface_name,
                'interface_description': interface_description,
                'is_up': (interface_details.get('is_up', '') or ''),
                'is_enabled': (interface_details.get('is_enabled', '') or ''),
                'speed': (interface_details.get('speed', '') or ''),
                'mac': napalm_helpers.convert(napalm_helpers.mac, (interface_details.get('mac_address', '') or '')),
                'ips': []
            }
            intf_entry_found = False
            for intrf, interface_ips in six.iteritems(all_ipaddrs.get(device, {}).get('out', {})):
                if intrf.split('.')[0] == interface_name:
                    ip_addresses = interface_ips.get('ipv4', {})  # all IPv4 addresses
                    ip_addresses.update(interface_ips.get('ipv6', {}))  # and all IPv6 addresses
                    ips = [
                        '{0}/{1}'.format(
                            ip_addr,
                            addr_details.get('prefix_length', '32')
                        ) for ip_addr, addr_details in six.iteritems(ip_addresses)
                    ]
                    interf_entry = {}
                    interf_entry.update(device_entry)
                    interf_entry['ips'] = ips
                    if display:
                        interf_entry['ips'] = '\n'.join(interf_entry['ips'])
                    if ipnet:
                        inet_ips = [
                            six.text_type(ip) for ip in ips if _ipnet_belongs(ip)
                        ]  # filter and get only IP include ipnet
                        if inet_ips:  # if any
                            if best:
                                # determine the global best match
                                compare = [best_net_match]
                                compare.extend(list(map(_get_network_obj, inet_ips)))
                                new_best_net_match = max(compare)
                                if new_best_net_match != best_net_match:
                                    best_net_match = new_best_net_match
                                    best_row = interf_entry
                            else:
                                # or include all
                                intf_entry_found = True
                                rows.append(interf_entry)
                    else:
                        intf_entry_found = True
                        rows.append(interf_entry)
            if not intf_entry_found and not ipnet:
                interf_entry = {}
                interf_entry.update(device_entry)
                if display:
                    interf_entry['ips'] = ''
                rows.append(interf_entry)

    if ipnet and best and best_row:
        rows = [best_row]

    return _display_runner(rows, labels, title, display=display)