diff --git a/etc/policy.json b/etc/policy.json
index a1cc26efe98..c517996149e 100644
--- a/etc/policy.json
+++ b/etc/policy.json
@@ -150,6 +150,7 @@
     "create_floatingip": "rule:regular_user",
     "create_floatingip:floating_ip_address": "rule:admin_only",
     "get_floatingip": "rule:admin_or_owner",
+    "get_floatingip_pool": "rule:regular_user",
     "update_floatingip": "rule:admin_or_owner",
     "delete_floatingip": "rule:admin_or_owner",
 
diff --git a/neutron/db/l3_fip_pools_db.py b/neutron/db/l3_fip_pools_db.py
new file mode 100644
index 00000000000..035f867fa56
--- /dev/null
+++ b/neutron/db/l3_fip_pools_db.py
@@ -0,0 +1,77 @@
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from neutron_lib.api.definitions import fip64
+from neutron_lib.api import extensions
+from neutron_lib import constants as lib_const
+from neutron_lib.db import utils as lib_db_utils
+from neutron_lib.plugins import directory
+
+from neutron.extensions import floatingip_pools as fip_pools_ext
+from neutron.objects import base as base_obj
+from neutron.objects import network as net_obj
+from neutron.objects import subnet as subnet_obj
+
+
+class FloatingIPPoolsDbMixin(object):
+    """Class to support floating IP pool."""
+
+    _is_v6_supported = None
+
+    @staticmethod
+    def _make_floatingip_pool_dict(context, subnet, fields=None):
+        res = {'subnet_id': subnet.id,
+               'subnet_name': subnet.name,
+               'tenant_id': context.tenant_id,
+               'network_id': subnet.network_id,
+               'cidr': str(subnet.cidr)}
+
+        return lib_db_utils.resource_fields(res, fields)
+
+    def get_floatingip_pools(self, context, filters=None, fields=None,
+                             sorts=None, limit=None, marker=None,
+                             page_reverse=False):
+        """Return information for available floating IP pools"""
+        pager = base_obj.Pager(sorts, limit, page_reverse, marker)
+        net_ids = [n.network_id
+                   for n in net_obj.ExternalNetwork.get_objects(context)]
+        # NOTE(hongbin): Use elevated context to make sure we have enough
+        # permission to retrieve subnets that are not in current tenant
+        # but belongs to external networks shared with current tenant.
+        admin_context = context.elevated()
+        subnet_objs = subnet_obj.Subnet.get_objects(admin_context,
+                                                    _pager=pager,
+                                                    network_id=net_ids)
+        return [self._make_floatingip_pool_dict(context, obj, fields)
+                for obj in subnet_objs
+                if (obj.ip_version == lib_const.IP_VERSION_4 or
+                    self.is_v6_supported)]
+
+    @property
+    def is_v6_supported(self):
+        supported = self._is_v6_supported
+        if supported is None:
+            supported = False
+            for plugin in directory.get_plugins().values():
+                if extensions.is_extension_supported(plugin, fip64.ALIAS):
+                    supported = True
+                    break
+        self._is_v6_supported = supported
+
+        return supported
+
+
+class FloatingIPPoolsMixin(FloatingIPPoolsDbMixin,
+                           fip_pools_ext.FloatingIPPoolPluginBase):
+    pass
diff --git a/neutron/extensions/floatingip_pools.py b/neutron/extensions/floatingip_pools.py
new file mode 100644
index 00000000000..6c965ee2ce4
--- /dev/null
+++ b/neutron/extensions/floatingip_pools.py
@@ -0,0 +1,53 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import abc
+import itertools
+
+from neutron_lib.api.definitions import floatingip_pools as apidef
+from neutron_lib.api import extensions as api_extensions
+from neutron_lib.plugins import constants
+import six
+
+from neutron.api.v2 import resource_helper
+
+
+class Floatingip_pools(api_extensions.APIExtensionDescriptor):
+    """Neutron floating IP pool api extension."""
+
+    api_definition = apidef
+
+    @classmethod
+    def get_resources(cls):
+        """Returns Ext Resources."""
+        plural_mappings = resource_helper.build_plural_mappings(
+            {}, itertools.chain(apidef.RESOURCE_ATTRIBUTE_MAP))
+
+        resources = resource_helper.build_resource_info(
+                                                plural_mappings,
+                                                apidef.RESOURCE_ATTRIBUTE_MAP,
+                                                constants.L3,
+                                                translate_name=True,
+                                                allow_bulk=True)
+
+        return resources
+
+
+@six.add_metaclass(abc.ABCMeta)
+class FloatingIPPoolPluginBase(object):
+
+    @abc.abstractmethod
+    def get_floatingip_pools(self, context, filters=None, fields=None,
+                             sorts=None, limit=None, marker=None,
+                             page_reverse=False):
+        """List all floating ip pools."""
+        pass
diff --git a/neutron/services/l3_router/l3_router_plugin.py b/neutron/services/l3_router/l3_router_plugin.py
index ba56aa6718b..2c518663709 100644
--- a/neutron/services/l3_router/l3_router_plugin.py
+++ b/neutron/services/l3_router/l3_router_plugin.py
@@ -32,6 +32,7 @@ from neutron.db import dns_db
 from neutron.db import extraroute_db
 from neutron.db import l3_dvr_ha_scheduler_db
 from neutron.db import l3_dvrscheduler_db
+from neutron.db import l3_fip_pools_db
 from neutron.db import l3_fip_port_details
 from neutron.db import l3_fip_qos
 from neutron.db import l3_gwmode_db
@@ -69,7 +70,8 @@ class L3RouterPlugin(service_base.ServicePluginBase,
                      l3_dvr_ha_scheduler_db.L3_DVR_HA_scheduler_db_mixin,
                      dns_db.DNSDbMixin,
                      l3_fip_qos.FloatingQoSDbMixin,
-                     l3_fip_port_details.Fip_port_details_db_mixin):
+                     l3_fip_port_details.Fip_port_details_db_mixin,
+                     l3_fip_pools_db.FloatingIPPoolsMixin):
 
     """Implementation of the Neutron L3 Router Service Plugin.
 
@@ -84,7 +86,7 @@ class L3RouterPlugin(service_base.ServicePluginBase,
                                     "extraroute", "l3_agent_scheduler",
                                     "l3-ha", "router_availability_zone",
                                     "l3-flavors", "qos-fip",
-                                    "fip-port-details"]
+                                    "fip-port-details", "floatingip-pools"]
 
     __native_pagination_support = True
     __native_sorting_support = True
diff --git a/neutron/tests/contrib/hooks/api_all_extensions b/neutron/tests/contrib/hooks/api_all_extensions
index 10cddd9c8eb..43a7efa1640 100644
--- a/neutron/tests/contrib/hooks/api_all_extensions
+++ b/neutron/tests/contrib/hooks/api_all_extensions
@@ -20,6 +20,7 @@ NETWORK_API_EXTENSIONS+=",extraroute"
 NETWORK_API_EXTENSIONS+=",filter-validation"
 NETWORK_API_EXTENSIONS+=",fip-port-details"
 NETWORK_API_EXTENSIONS+=",flavors"
+NETWORK_API_EXTENSIONS+=",floatingip-pools"
 NETWORK_API_EXTENSIONS+=",ip-substring-filtering"
 NETWORK_API_EXTENSIONS+=",l3-flavors"
 NETWORK_API_EXTENSIONS+=",l3-ha"
diff --git a/neutron/tests/etc/policy.json b/neutron/tests/etc/policy.json
index a1cc26efe98..c517996149e 100644
--- a/neutron/tests/etc/policy.json
+++ b/neutron/tests/etc/policy.json
@@ -150,6 +150,7 @@
     "create_floatingip": "rule:regular_user",
     "create_floatingip:floating_ip_address": "rule:admin_only",
     "get_floatingip": "rule:admin_or_owner",
+    "get_floatingip_pool": "rule:regular_user",
     "update_floatingip": "rule:admin_or_owner",
     "delete_floatingip": "rule:admin_or_owner",
 
diff --git a/neutron/tests/unit/extensions/test_floatingip_pools.py b/neutron/tests/unit/extensions/test_floatingip_pools.py
new file mode 100644
index 00000000000..9995527bb4f
--- /dev/null
+++ b/neutron/tests/unit/extensions/test_floatingip_pools.py
@@ -0,0 +1,155 @@
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#
+
+import ddt
+import mock
+
+from neutron_lib.api.definitions import floatingip_pools as apidef
+from neutron_lib import constants as lib_const
+from neutron_lib import context
+from neutron_lib.plugins import constants as plugin_constants
+from neutron_lib.plugins import directory
+from oslo_config import cfg
+from oslo_utils import uuidutils
+
+from neutron.db import l3_fip_pools_db
+from neutron.extensions import l3
+from neutron.objects import network as net_obj
+from neutron.objects import subnet as subnet_obj
+from neutron.tests.unit.extensions import test_l3
+
+
+class FloatingIPPoolsTestExtensionManager(object):
+
+    def get_resources(self):
+        return l3.L3.get_resources()
+
+    def get_actions(self):
+        return []
+
+    def get_request_extensions(self):
+        return []
+
+
+class TestFloatingIPPoolsIntPlugin(
+        test_l3.TestL3NatIntPlugin,
+        l3_fip_pools_db.FloatingIPPoolsDbMixin):
+    supported_extension_aliases = ["external-net", "router",
+                                   apidef.ALIAS]
+
+
+class TestFloatingIPPoolsL3NatServicePlugin(
+        test_l3.TestL3NatServicePlugin,
+        l3_fip_pools_db.FloatingIPPoolsDbMixin):
+    supported_extension_aliases = ["router", apidef.ALIAS]
+
+
+@ddt.ddt
+class FloatingIPPoolsDBTestCaseBase(test_l3.L3NatTestCaseMixin):
+
+    def test_get_floatingip_pools_ipv4(self):
+        self._test_get_floatingip_pools(lib_const.IP_VERSION_4, False)
+
+    @ddt.data(True, False)
+    def test_get_floatingip_pools_ipv6(self, fake_is_v6_supported):
+        self._test_get_floatingip_pools(lib_const.IP_VERSION_6,
+                                        fake_is_v6_supported)
+
+    def _test_get_floatingip_pools(self, ip_version, is_v6_supported):
+        fake_network_id = uuidutils.generate_uuid()
+        fake_subnet_id = uuidutils.generate_uuid()
+        fake_ext_network = mock.Mock(network_id=fake_network_id)
+        if ip_version == lib_const.IP_VERSION_4:
+            fake_cidr = '10.0.0.0/24'
+        else:
+            fake_cidr = 'fe80:cafe::/64'
+        fake_subnet = mock.Mock(id=fake_subnet_id,
+                                network_id=fake_network_id,
+                                cidr=fake_cidr,
+                                ip_version=ip_version,
+                                tenant_id='fake_tenant',
+                                project_id='fake_tenant')
+        fake_subnet.name = 'fake_subnet'
+        self.plugin._is_v6_supported = is_v6_supported
+        with mock.patch.object(
+            subnet_obj.Subnet, 'get_objects',
+            return_value=[fake_subnet]
+        ) as mock_subnet_get_objects, mock.patch.object(
+            net_obj.ExternalNetwork, 'get_objects',
+            return_value=[fake_ext_network]
+        ) as mock_extnet_get_objects, mock.patch.object(
+            self.ctxt, 'elevated',
+            return_value=self.admin_ctxt
+        ) as mock_context_elevated:
+            fip_pools = self.plugin.get_floatingip_pools(self.ctxt)
+
+        expected_fip_pools = []
+        if ip_version == lib_const.IP_VERSION_4 or is_v6_supported:
+            expected_fip_pools = [{'cidr': fake_cidr,
+                                   'subnet_id': fake_subnet_id,
+                                   'subnet_name': 'fake_subnet',
+                                   'network_id': fake_network_id,
+                                   'project_id': 'fake_tenant',
+                                   'tenant_id': 'fake_tenant'}]
+        self.assertEqual(expected_fip_pools, fip_pools)
+        mock_subnet_get_objects.assert_called_once_with(
+            self.admin_ctxt, _pager=mock.ANY, network_id=[fake_network_id])
+        mock_extnet_get_objects.assert_called_once_with(self.ctxt)
+        mock_context_elevated.assert_called_once_with()
+
+
+class FloatingIPPoolsDBIntTestCase(test_l3.L3BaseForIntTests,
+                                   FloatingIPPoolsDBTestCaseBase):
+
+    def setUp(self, plugin=None):
+        if not plugin:
+            plugin = ('neutron.tests.unit.extensions.test_floatingip_pools.'
+                      'TestFloatingIPPoolsIntPlugin')
+        # for these tests we need to enable overlapping ips
+        cfg.CONF.set_default('allow_overlapping_ips', True)
+        cfg.CONF.set_default('max_routes', 3)
+        ext_mgr = FloatingIPPoolsTestExtensionManager()
+        super(test_l3.L3BaseForIntTests, self).setUp(
+            plugin=plugin,
+            ext_mgr=ext_mgr)
+
+        self.setup_notification_driver()
+        self.ctxt = context.Context('fake_user', 'fake_tenant')
+        self.admin_ctxt = self.ctxt.elevated()
+
+
+class FloatingIPPoolsDBSepTestCase(test_l3.L3BaseForSepTests,
+                                   FloatingIPPoolsDBTestCaseBase):
+
+    def setUp(self):
+        # the plugin without L3 support
+        plugin = 'neutron.tests.unit.extensions.test_l3.TestNoL3NatPlugin'
+        # the L3 service plugin
+        l3_plugin = ('neutron.tests.unit.extensions.test_floatingip_pools.'
+                     'TestFloatingIPPoolsL3NatServicePlugin')
+        service_plugins = {'l3_plugin_name': l3_plugin}
+
+        # for these tests we need to enable overlapping ips
+        cfg.CONF.set_default('allow_overlapping_ips', True)
+        cfg.CONF.set_default('max_routes', 3)
+        ext_mgr = FloatingIPPoolsTestExtensionManager()
+        super(test_l3.L3BaseForSepTests, self).setUp(
+            plugin=plugin,
+            ext_mgr=ext_mgr,
+            service_plugins=service_plugins)
+
+        self.setup_notification_driver()
+        self.plugin = directory.get_plugin(plugin_constants.L3)
+        self.ctxt = context.Context('fake_user', 'fake_tenant')
+        self.admin_ctxt = self.ctxt.elevated()
diff --git a/releasenotes/notes/add-floatingip-pool-api-6927362ef87fdbe5.yaml b/releasenotes/notes/add-floatingip-pool-api-6927362ef87fdbe5.yaml
new file mode 100644
index 00000000000..07c3a9622b6
--- /dev/null
+++ b/releasenotes/notes/add-floatingip-pool-api-6927362ef87fdbe5.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Add support for listing floating ip pools (subnets) in L3 plugin.
+    A new API resource ``floatingip-pools`` is introduced.
+    This API endpoint can return a list of floating ip pools which are
+    essentially mappings between network UUIDs and subnet CIDRs.
+    Users can use this API to find out the pool to create the floating IPs.