<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:

def describe_subnets(subnet_ids=None, subnet_names=None, vpc_id=None, cidr=None,
                     region=None, key=None, keyid=None, profile=None):
    '''
    Given a VPC ID or subnet CIDR, returns a list of associated subnets and
    their details. Return all subnets if VPC ID or CIDR are not provided.
    If a subnet id or CIDR is provided, only its associated subnet details will be
    returned.

    .. versionadded:: 2015.8.0

    CLI Examples:

    .. code-block:: bash

        salt myminion boto_vpc.describe_subnets

    .. code-block:: bash

        salt myminion boto_vpc.describe_subnets subnet_ids=['subnet-ba1987ab', 'subnet-ba1987cd']

    .. code-block:: bash

        salt myminion boto_vpc.describe_subnets vpc_id=vpc-123456

    .. code-block:: bash

        salt myminion boto_vpc.describe_subnets cidr=10.0.0.0/21

    '''

    try:
        conn = _get_conn(region=region, key=key, keyid=keyid, profile=profile)
        filter_parameters = {'filters': {}}

        if vpc_id:
            filter_parameters['filters']['vpcId'] = vpc_id

        if cidr:
            filter_parameters['filters']['cidrBlock'] = cidr

        if subnet_names:
            filter_parameters['filters']['tag:Name'] = subnet_names

        subnets = conn.get_all_subnets(subnet_ids=subnet_ids, **filter_parameters)
        log.debug('The filters criteria %s matched the following subnets: %s',
                  filter_parameters, subnets)

        if not subnets:
            return {'subnets': None}

        subnets_list = []
        keys = ('id', 'cidr_block', 'availability_zone', 'tags', 'vpc_id')
        for item in subnets:
            subnet = {}
            for key in keys:
                if hasattr(item, key):
                    subnet[key] = getattr(item, key)
            explicit_route_table_assoc = _get_subnet_explicit_route_table(subnet['id'], subnet['vpc_id'], conn=conn)
            if explicit_route_table_assoc:
                subnet['explicit_route_table_association_id'] = explicit_route_table_assoc
            subnets_list.append(subnet)
        return {'subnets': subnets_list}

    except BotoServerError as e:
        return {'error': __utils__['boto.get_error'](e)}