diff --git a/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py b/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py
index c3fa003a4..f1aa3b2da 100644
--- a/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py
+++ b/neutron_lbaas/db/loadbalancer/loadbalancer_dbv2.py
@@ -15,9 +15,11 @@
 
 import re
 
+import netaddr
 from neutron.callbacks import events
 from neutron.callbacks import registry
 from neutron.callbacks import resources
+from neutron.common import ipv6_utils
 from neutron.db import api as db_api
 from neutron.db import common_db_mixin as base_db
 from neutron import manager
@@ -28,7 +30,6 @@ from oslo_db import exception
 from oslo_log import log as logging
 from oslo_utils import excutils
 from oslo_utils import uuidutils
-from sqlalchemy import exc as sqlalchemy_exc
 from sqlalchemy import orm
 from sqlalchemy.orm import exc
 from sqlalchemy.orm import lazyload
@@ -96,33 +97,68 @@ class LoadBalancerPluginDbv2(base_db.CommonDbMixin,
                                            filters=filters)
         return [model_instance for model_instance in query]
 
-    def _create_port_for_load_balancer(self, context, lb_db, ip_address):
-        # resolve subnet and create port
-        subnet = self._core_plugin.get_subnet(context, lb_db.vip_subnet_id)
-        fixed_ip = {'subnet_id': subnet['id']}
-        if ip_address and ip_address != n_const.ATTR_NOT_SPECIFIED:
-            fixed_ip['ip_address'] = ip_address
+    def _create_port_choose_fixed_ip(self, fixed_ips):
+        # Neutron will try to allocate IPv4, IPv6, and IPv6 EUI-64 addresses.
+        # We're most interested in the IPv4 address. An IPv4 vip can be
+        # routable from IPv6. Creating a port by network can be used to manage
+        # the dwindling, fragmented IPv4 address space. IPv6 has enough
+        # addresses that a single subnet can always be created that's big
+        # enough to allocate all vips.
+        for fixed_ip in fixed_ips:
+            ip_address = fixed_ip['ip_address']
+            ip = netaddr.IPAddress(ip_address)
+            if ip.version == 4:
+                return fixed_ip
+        # An EUI-64 address isn't useful as a vip
+        for fixed_ip in fixed_ips:
+            ip_address = fixed_ip['ip_address']
+            ip = netaddr.IPAddress(ip_address)
+            if ip.version == 6 and not ipv6_utils.is_eui64_address(ip_address):
+                return fixed_ip
+        for fixed_ip in fixed_ips:
+            return fixed_ip
+
+    def _create_port_for_load_balancer(self, context, lb_db, ip_address,
+                                       network_id=None):
+        if lb_db.vip_subnet_id:
+            assign_subnet = False
+            # resolve subnet and create port
+            subnet = self._core_plugin.get_subnet(context, lb_db.vip_subnet_id)
+            network_id = subnet['network_id']
+            fixed_ip = {'subnet_id': subnet['id']}
+            if ip_address and ip_address != n_const.ATTR_NOT_SPECIFIED:
+                fixed_ip['ip_address'] = ip_address
+            fixed_ips = [fixed_ip]
+        elif network_id and network_id != n_const.ATTR_NOT_SPECIFIED:
+            assign_subnet = True
+            fixed_ips = n_const.ATTR_NOT_SPECIFIED
+        else:
+            attrs = _("vip_subnet_id or vip_network_id")
+            raise loadbalancerv2.RequiredAttributeNotSpecified(attr_name=attrs)
 
         port_data = {
             'tenant_id': lb_db.tenant_id,
             'name': 'loadbalancer-' + lb_db.id,
-            'network_id': subnet['network_id'],
+            'network_id': network_id,
             'mac_address': n_const.ATTR_NOT_SPECIFIED,
             'admin_state_up': False,
             'device_id': lb_db.id,
             'device_owner': n_const.DEVICE_OWNER_LOADBALANCERV2,
-            'fixed_ips': [fixed_ip]
+            'fixed_ips': fixed_ips
         }
 
         port = self._core_plugin.create_port(context, {'port': port_data})
         lb_db.vip_port_id = port['id']
-        for fixed_ip in port['fixed_ips']:
-            if fixed_ip['subnet_id'] == lb_db.vip_subnet_id:
-                lb_db.vip_address = fixed_ip['ip_address']
-                break
 
-        # explicitly sync session with db
-        context.session.flush()
+        if assign_subnet:
+            fixed_ip = self._create_port_choose_fixed_ip(port['fixed_ips'])
+            lb_db.vip_address = fixed_ip['ip_address']
+            lb_db.vip_subnet_id = fixed_ip['subnet_id']
+        else:
+            for fixed_ip in port['fixed_ips']:
+                if fixed_ip['subnet_id'] == lb_db.vip_subnet_id:
+                    lb_db.vip_address = fixed_ip['ip_address']
+                    break
 
     def _create_loadbalancer_stats(self, context, loadbalancer_id, data=None):
         # This is internal method to add load balancer statistics.  It won't
@@ -278,34 +314,30 @@ class LoadBalancerPluginDbv2(base_db.CommonDbMixin,
         return self.get_loadbalancer(context, lb_db.id)
 
     def create_loadbalancer(self, context, loadbalancer, allocate_vip=True):
+        self._load_id(context, loadbalancer)
+        vip_network_id = loadbalancer.pop('vip_network_id', None)
+        vip_subnet_id = loadbalancer.pop('vip_subnet_id', None)
+        vip_address = loadbalancer.pop('vip_address')
+        if vip_subnet_id and vip_subnet_id != n_const.ATTR_NOT_SPECIFIED:
+            loadbalancer['vip_subnet_id'] = vip_subnet_id
+        loadbalancer['provisioning_status'] = constants.PENDING_CREATE
+        loadbalancer['operating_status'] = lb_const.OFFLINE
+        lb_db = models.LoadBalancer(**loadbalancer)
+
+        # create port outside of lb create transaction since it can sometimes
+        # cause lock wait timeouts
+        if allocate_vip:
+            LOG.debug("Plugin will allocate the vip as a neutron port.")
+            self._create_port_for_load_balancer(context, lb_db,
+                                                vip_address, vip_network_id)
+
         with context.session.begin(subtransactions=True):
-            self._load_id(context, loadbalancer)
-            vip_address = loadbalancer.pop('vip_address')
-            loadbalancer['provisioning_status'] = constants.PENDING_CREATE
-            loadbalancer['operating_status'] = lb_const.OFFLINE
-            lb_db = models.LoadBalancer(**loadbalancer)
             context.session.add(lb_db)
             context.session.flush()
             lb_db.stats = self._create_loadbalancer_stats(
                 context, lb_db.id)
             context.session.add(lb_db)
             context.session.flush()
-
-        # create port outside of lb create transaction since it can sometimes
-        # cause lock wait timeouts
-        if allocate_vip:
-            LOG.debug("Plugin will allocate the vip as a neutron port.")
-            try:
-                self._create_port_for_load_balancer(context, lb_db,
-                                                    vip_address)
-            except Exception:
-                with excutils.save_and_reraise_exception():
-                    try:
-                        context.session.delete(lb_db)
-                    except sqlalchemy_exc.InvalidRequestError:
-                        # Revert already completed.
-                        pass
-                    context.session.flush()
         return data_models.LoadBalancer.from_sqlalchemy_model(lb_db)
 
     def update_loadbalancer(self, context, id, loadbalancer):
diff --git a/neutron_lbaas/extensions/lb_network_vip.py b/neutron_lbaas/extensions/lb_network_vip.py
new file mode 100644
index 000000000..203cce583
--- /dev/null
+++ b/neutron_lbaas/extensions/lb_network_vip.py
@@ -0,0 +1,62 @@
+# Copyright 2016 A10 Networks
+# 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.api import extensions
+from neutron_lib import constants as n_constants
+
+EXTENDED_ATTRIBUTES_2_0 = {
+    'loadbalancers': {
+        'vip_subnet_id': {'allow_post': True, 'allow_put': False,
+                          'validate': {'type:uuid': None},
+                          'is_visible': True,
+                          'default': n_constants.ATTR_NOT_SPECIFIED},
+        'vip_network_id': {'allow_post': True, 'allow_put': False,
+                           'validate': {'type:uuid': None},
+                           'is_visible': False,
+                           'default': n_constants.ATTR_NOT_SPECIFIED}
+    }
+}
+
+
+class Lb_network_vip(extensions.ExtensionDescriptor):
+
+    @classmethod
+    def get_name(cls):
+        return "Create loadbalancer with network_id"
+
+    @classmethod
+    def get_alias(cls):
+        return "lb_network_vip"
+
+    @classmethod
+    def get_description(cls):
+        return "Create loadbalancer with network_id"
+
+    @classmethod
+    def get_namespace(cls):
+        return "http://wiki.openstack.org/neutron/LBaaS/API_2.0"
+
+    @classmethod
+    def get_updated(cls):
+        return "2016-09-09T22:00:00-00:00"
+
+    def get_required_extensions(self):
+        return ["lbaasv2"]
+
+    def get_extended_resources(self, version):
+        if version == "2.0":
+            return EXTENDED_ATTRIBUTES_2_0
+        else:
+            return {}
diff --git a/neutron_lbaas/services/loadbalancer/plugin.py b/neutron_lbaas/services/loadbalancer/plugin.py
index 1b6533c8f..a74d17980 100644
--- a/neutron_lbaas/services/loadbalancer/plugin.py
+++ b/neutron_lbaas/services/loadbalancer/plugin.py
@@ -67,6 +67,7 @@ class LoadBalancerPluginv2(loadbalancerv2.LoadBalancerPluginBaseV2):
                                    "lbaas_agent_schedulerv2",
                                    "service-type",
                                    "lb-graph",
+                                   "lb_network_vip",
                                    "hm_max_retries_down"]
     path_prefix = loadbalancerv2.LOADBALANCERV2_PREFIX
 
diff --git a/neutron_lbaas/tests/unit/db/loadbalancer/test_db_loadbalancerv2.py b/neutron_lbaas/tests/unit/db/loadbalancer/test_db_loadbalancerv2.py
index 6a6bbcb10..e330d8451 100755
--- a/neutron_lbaas/tests/unit/db/loadbalancer/test_db_loadbalancerv2.py
+++ b/neutron_lbaas/tests/unit/db/loadbalancer/test_db_loadbalancerv2.py
@@ -42,6 +42,7 @@ import neutron_lbaas.extensions
 from neutron_lbaas.extensions import healthmonitor_max_retries_down
 from neutron_lbaas.extensions import l7
 from neutron_lbaas.extensions import lb_graph
+from neutron_lbaas.extensions import lb_network_vip
 from neutron_lbaas.extensions import loadbalancerv2
 from neutron_lbaas.extensions import sharedpools
 from neutron_lbaas.services.loadbalancer import constants as lb_const
@@ -66,6 +67,7 @@ class LbaasTestMixin(object):
     resource_keys = list(loadbalancerv2.RESOURCE_ATTRIBUTE_MAP.keys())
     resource_keys.extend(l7.RESOURCE_ATTRIBUTE_MAP.keys())
     resource_keys.extend(lb_graph.RESOURCE_ATTRIBUTE_MAP.keys())
+    resource_keys.extend(lb_network_vip.EXTENDED_ATTRIBUTES_2_0.keys())
     resource_keys.extend(healthmonitor_max_retries_down.
                          EXTENDED_ATTRIBUTES_2_0.keys())
     resource_prefix_map = dict(
@@ -74,7 +76,7 @@ class LbaasTestMixin(object):
 
     def _get_loadbalancer_optional_args(self):
         return ('description', 'vip_address', 'admin_state_up', 'name',
-                'listeners')
+                'listeners', 'vip_network_id', 'vip_subnet_id')
 
     def _create_loadbalancer(self, fmt, subnet_id,
                              expected_res_status=None, **kwargs):
@@ -82,8 +84,11 @@ class LbaasTestMixin(object):
                                  'tenant_id': self._tenant_id}}
         args = self._get_loadbalancer_optional_args()
         for arg in args:
-            if arg in kwargs and kwargs[arg] is not None:
-                data['loadbalancer'][arg] = kwargs[arg]
+            if arg in kwargs:
+                if kwargs[arg] is not None:
+                    data['loadbalancer'][arg] = kwargs[arg]
+                else:
+                    data['loadbalancer'].pop(arg, None)
 
         lb_req = self.new_create_request('loadbalancers', data, fmt)
         lb_res = lb_req.get_response(self.ext_api)
@@ -534,6 +539,8 @@ class ExtendedPluginAwareExtensionManager(object):
             extensions_list.append(l7)
         if 'lb-graph' in self.extension_aliases:
             extensions_list.append(lb_graph)
+        if 'lb_network_vip' in self.extension_aliases:
+            extensions_list.append(lb_network_vip)
         if 'hm_max_retries_down' in self.extension_aliases:
             extensions_list.append(healthmonitor_max_retries_down)
         for extension in extensions_list:
@@ -772,6 +779,47 @@ class LbaasLoadBalancerTests(LbaasPluginDbTestCase):
         with testtools.ExpectedException(webob.exc.HTTPClientError):
             self.test_create_loadbalancer(vip_address='9.9.9.9')
 
+    def test_create_loadbalancer_with_no_vip_network_or_subnet(self):
+        with testtools.ExpectedException(webob.exc.HTTPClientError):
+            self.test_create_loadbalancer(
+                vip_network_id=None,
+                vip_subnet_id=None,
+                expected_res_status=400)
+
+    def test_create_loadbalancer_with_vip_network_id(self):
+        expected = {
+            'name': 'vip1',
+            'description': '',
+            'admin_state_up': True,
+            'provisioning_status': constants.ACTIVE,
+            'operating_status': lb_const.ONLINE,
+            'tenant_id': self._tenant_id,
+            'listeners': [],
+            'pools': [],
+            'provider': 'lbaas'
+        }
+
+        with self.subnet() as subnet:
+            expected['vip_subnet_id'] = subnet['subnet']['id']
+            name = expected['name']
+            extras = {
+                'vip_network_id': subnet['subnet']['network_id'],
+                'vip_subnet_id': None
+            }
+
+            with self.loadbalancer(name=name, subnet=subnet, **extras) as lb:
+                lb_id = lb['loadbalancer']['id']
+                for k in ('id', 'vip_address', 'vip_subnet_id'):
+                    self.assertTrue(lb['loadbalancer'].get(k, None))
+
+                expected['vip_port_id'] = lb['loadbalancer']['vip_port_id']
+                actual = dict((k, v)
+                              for k, v in lb['loadbalancer'].items()
+                              if k in expected)
+                self.assertEqual(expected, actual)
+                self._validate_statuses(lb_id)
+            return lb
+
     def test_update_loadbalancer(self):
         name = 'new_loadbalancer'
         description = 'a crazy loadbalancer'
diff --git a/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py b/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py
index a15cc4700..1ae240c0b 100644
--- a/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py
+++ b/neutron_lbaas/tests/unit/services/loadbalancer/test_loadbalancer_plugin.py
@@ -23,6 +23,7 @@ from oslo_utils import uuidutils
 from webob import exc
 
 from neutron_lbaas.extensions import healthmonitor_max_retries_down as hm_down
+from neutron_lbaas.extensions import lb_network_vip
 from neutron_lbaas.extensions import loadbalancerv2
 from neutron_lbaas.extensions import sharedpools
 from neutron_lbaas.tests import base
@@ -42,6 +43,8 @@ class TestLoadBalancerExtensionV2TestCase(base.ExtensionTestCase):
             resource_map[k].update(sharedpools.EXTENDED_ATTRIBUTES_2_0[k])
         for k in hm_down.EXTENDED_ATTRIBUTES_2_0.keys():
             resource_map[k].update(hm_down.EXTENDED_ATTRIBUTES_2_0[k])
+        for k in lb_network_vip.EXTENDED_ATTRIBUTES_2_0.keys():
+            resource_map[k].update(lb_network_vip.EXTENDED_ATTRIBUTES_2_0[k])
         self._setUpExtension(
             'neutron_lbaas.extensions.loadbalancerv2.LoadBalancerPluginBaseV2',
             constants.LOADBALANCERV2, resource_map,
@@ -68,7 +71,41 @@ class TestLoadBalancerExtensionV2TestCase(base.ExtensionTestCase):
                             content_type='application/{0}'.format(self.fmt))
         data['loadbalancer'].update({
             'provider': n_constants.ATTR_NOT_SPECIFIED,
-            'flavor_id': n_constants.ATTR_NOT_SPECIFIED})
+            'flavor_id': n_constants.ATTR_NOT_SPECIFIED,
+            'vip_network_id': n_constants.ATTR_NOT_SPECIFIED})
+        instance.create_loadbalancer.assert_called_with(mock.ANY,
+                                                        loadbalancer=data)
+
+        self.assertEqual(exc.HTTPCreated.code, res.status_int)
+        res = self.deserialize(res)
+        self.assertIn('loadbalancer', res)
+        self.assertEqual(return_value, res['loadbalancer'])
+
+    def test_loadbalancer_create_with_vip_network_id(self):
+        lb_id = _uuid()
+        project_id = _uuid()
+        vip_subnet_id = _uuid()
+        data = {'loadbalancer': {'name': 'lb1',
+                                 'description': 'descr_lb1',
+                                 'tenant_id': project_id,
+                                 'project_id': project_id,
+                                 'vip_network_id': _uuid(),
+                                 'admin_state_up': True,
+                                 'vip_address': '127.0.0.1'}}
+        return_value = copy.copy(data['loadbalancer'])
+        return_value.update({'id': lb_id, 'vip_subnet_id': vip_subnet_id})
+        del return_value['vip_network_id']
+
+        instance = self.plugin.return_value
+        instance.create_loadbalancer.return_value = return_value
+
+        res = self.api.post(_get_path('lbaas/loadbalancers', fmt=self.fmt),
+                            self.serialize(data),
+                            content_type='application/{0}'.format(self.fmt))
+        data['loadbalancer'].update({
+            'provider': n_constants.ATTR_NOT_SPECIFIED,
+            'flavor_id': n_constants.ATTR_NOT_SPECIFIED,
+            'vip_subnet_id': n_constants.ATTR_NOT_SPECIFIED})
         instance.create_loadbalancer.assert_called_with(mock.ANY,
                                                         loadbalancer=data)
 
diff --git a/releasenotes/notes/create-lb-with-network-id-dba0a71878942af7.yaml b/releasenotes/notes/create-lb-with-network-id-dba0a71878942af7.yaml
new file mode 100644
index 000000000..33ab42471
--- /dev/null
+++ b/releasenotes/notes/create-lb-with-network-id-dba0a71878942af7.yaml
@@ -0,0 +1,14 @@
+---
+features:
+  - |
+    Adds support for creating a loadbalancer with a
+    Neutron network id.
+
+    * Adds an optional ``vip_network_id`` attribute
+      when creating a loadbalancer.
+    * When creating a loadbalancer, ``vip_subnet_id``
+      is optional if a ``vip_network_id`` is proviced.
+    * If ``vip_network_id`` is provided the vip will
+      be allocated on a subnet with an available
+      address. An IPv4 subnet will be chosen if
+      possible.