diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py
index 5313f2fb4cfd..0202d954e5a0 100644
--- a/nova/db/sqlalchemy/api.py
+++ b/nova/db/sqlalchemy/api.py
@@ -1357,8 +1357,17 @@ def fixed_ip_get_by_instance(context, instance_uuid):
     if not uuidutils.is_uuid_like(instance_uuid):
         raise exception.InvalidUUID(uuid=instance_uuid)
 
+    vif_and = and_(models.VirtualInterface.id ==
+                   models.FixedIp.virtual_interface_id,
+                   models.VirtualInterface.deleted == 0)
     result = model_query(context, models.FixedIp, read_deleted="no").\
                  filter_by(instance_uuid=instance_uuid).\
+                 outerjoin(models.VirtualInterface, vif_and).\
+                 options(contains_eager("virtual_interface")).\
+                 options(joinedload('network')).\
+                 options(joinedload('floating_ips')).\
+                 order_by(asc(models.VirtualInterface.created_at),
+                          asc(models.VirtualInterface.id)).\
                  all()
 
     if not result:
@@ -1398,6 +1407,8 @@ def fixed_ip_get_by_network_host(context, network_id, host):
 def fixed_ips_by_virtual_interface(context, vif_id):
     result = model_query(context, models.FixedIp, read_deleted="no").\
                  filter_by(virtual_interface_id=vif_id).\
+                 options(joinedload('network')).\
+                 options(joinedload('floating_ips')).\
                  all()
 
     return result
diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py
index 6eaa21eda78d..3ae0ac36a577 100644
--- a/nova/db/sqlalchemy/models.py
+++ b/nova/db/sqlalchemy/models.py
@@ -891,6 +891,14 @@ class FixedIp(BASE, NovaBase):
                                 'FixedIp.instance_uuid == Instance.uuid,'
                                 'FixedIp.deleted == 0,'
                                 'Instance.deleted == 0)')
+    virtual_interface = orm.relationship(VirtualInterface,
+                           backref=orm.backref('fixed_ips'),
+                           foreign_keys=virtual_interface_id,
+                           primaryjoin='and_('
+                                'FixedIp.virtual_interface_id == '
+                                'VirtualInterface.id,'
+                                'FixedIp.deleted == 0,'
+                                'VirtualInterface.deleted == 0)')
 
 
 class FloatingIp(BASE, NovaBase):
diff --git a/nova/objects/fixed_ip.py b/nova/objects/fixed_ip.py
index 2482b635e5a5..f3d42ed6a694 100644
--- a/nova/objects/fixed_ip.py
+++ b/nova/objects/fixed_ip.py
@@ -21,7 +21,8 @@ from nova.openstack.common import timeutils
 from nova import utils
 
 
-FIXED_IP_OPTIONAL_ATTRS = ['instance', 'network']
+FIXED_IP_OPTIONAL_ATTRS = ['instance', 'network', 'virtual_interface',
+                           'floating_ips']
 
 
 class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
@@ -30,7 +31,8 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
     # Version 1.2: Instance version 1.14
     # Version 1.3: Instance 1.15
     # Version 1.4: Added default_route field
-    VERSION = '1.4'
+    # Version 1.5: Added floating_ips field
+    VERSION = '1.5'
 
     fields = {
         'id': fields.IntegerField(),
@@ -47,10 +49,16 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
         'network': fields.ObjectField('Network', nullable=True),
         'virtual_interface': fields.ObjectField('VirtualInterface',
                                                 nullable=True),
+        # NOTE(danms): This should not ever be made lazy-loadable
+        # because it would create a bit of a loop between FixedIP
+        # and FloatingIP
+        'floating_ips': fields.ObjectField('FloatingIPList'),
         }
 
     def obj_make_compatible(self, primitive, target_version):
         target_version = utils.convert_version_to_tuple(target_version)
+        if target_version < (1, 5) and 'floating_ips' in primitive:
+            del primitive['floating_ips']
         if target_version < (1, 4) and 'default_route' in primitive:
             del primitive['default_route']
         if target_version < (1, 3) and 'instance' in primitive:
@@ -62,20 +70,15 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
                     primitive['instance']['nova_object.data'], '1.13')
             primitive['instance']['nova_object.version'] = '1.13'
 
-    @property
-    def floating_ips(self):
-        return objects.FloatingIPList.get_by_fixed_ip_id(self._context,
-                                                         self.id)
-
     @staticmethod
     def _from_db_object(context, fixedip, db_fixedip, expected_attrs=None):
         if expected_attrs is None:
             expected_attrs = []
         for field in fixedip.fields:
-            if field in ('virtual_interface', 'default_route'):
-                # NOTE(danms): These fields are only set when doing a
+            if field == 'default_route':
+                # NOTE(danms): This field is only set when doing a
                 # FixedIPList.get_by_network() because it's a relatively
-                # special-case thing, so skip them here
+                # special-case thing, so skip it here
                 continue
             if field not in FIXED_IP_OPTIONAL_ATTRS:
                 fixedip[field] = db_fixedip[field]
@@ -87,7 +90,20 @@ class FixedIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
                 db_fixedip['instance']) if db_fixedip['instance'] else None
         if 'network' in expected_attrs:
             fixedip.network = objects.Network._from_db_object(
-                context, objects.Network(context), db_fixedip['network'])
+                context,
+                objects.Network(context),
+                db_fixedip['network']) if db_fixedip['network'] else None
+        if 'virtual_interface' in expected_attrs:
+            db_vif = db_fixedip['virtual_interface']
+            vif = objects.VirtualInterface._from_db_object(
+                context,
+                objects.VirtualInterface(context),
+                db_fixedip['virtual_interface']) if db_vif else None
+            fixedip.virtual_interface = vif
+        if 'floating_ips' in expected_attrs:
+            fixedip.floating_ips = obj_base.obj_make_list(
+                    context, objects.FloatingIPList(context),
+                    objects.FloatingIP, db_fixedip['floating_ips'])
         fixedip._context = context
         fixedip.obj_reset_changes()
         return fixedip
@@ -185,7 +201,8 @@ class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject):
     # Version 1.2: FixedIP <= version 1.2
     # Version 1.3: FixedIP <= version 1.3
     # Version 1.4: FixedIP <= version 1.4
-    VERSION = '1.4'
+    # Version 1.5: FixedIP <= version 1.5, added expected attrs to gets
+    VERSION = '1.5'
 
     fields = {
         'objects': fields.ListOfObjectsField('FixedIP'),
@@ -196,6 +213,7 @@ class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject):
         '1.2': '1.2',
         '1.3': '1.3',
         '1.4': '1.4',
+        '1.5': '1.5',
         }
 
     @obj_base.remotable_classmethod
@@ -206,9 +224,11 @@ class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject):
 
     @obj_base.remotable_classmethod
     def get_by_instance_uuid(cls, context, instance_uuid):
+        expected_attrs = ['network', 'virtual_interface', 'floating_ips']
         db_fixedips = db.fixed_ip_get_by_instance(context, instance_uuid)
         return obj_base.obj_make_list(context, cls(context),
-                                      objects.FixedIP, db_fixedips)
+                                      objects.FixedIP, db_fixedips,
+                                      expected_attrs=expected_attrs)
 
     @obj_base.remotable_classmethod
     def get_by_host(cls, context, host):
@@ -218,9 +238,11 @@ class FixedIPList(obj_base.ObjectListBase, obj_base.NovaObject):
 
     @obj_base.remotable_classmethod
     def get_by_virtual_interface_id(cls, context, vif_id):
+        expected_attrs = ['network', 'floating_ips']
         db_fixedips = db.fixed_ips_by_virtual_interface(context, vif_id)
         return obj_base.obj_make_list(context, cls(context),
-                                      objects.FixedIP, db_fixedips)
+                                      objects.FixedIP, db_fixedips,
+                                      expected_attrs=expected_attrs)
 
     @obj_base.remotable_classmethod
     def get_by_network(cls, context, network, host=None):
diff --git a/nova/objects/floating_ip.py b/nova/objects/floating_ip.py
index 173bc5209d32..39b06725bcc8 100644
--- a/nova/objects/floating_ip.py
+++ b/nova/objects/floating_ip.py
@@ -28,7 +28,8 @@ class FloatingIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
     # Version 1.2: FixedIP <= version 1.2
     # Version 1.3: FixedIP <= version 1.3
     # Version 1.4: FixedIP <= version 1.4
-    VERSION = '1.4'
+    # Version 1.5: FixedIP <= version 1.5
+    VERSION = '1.5'
     fields = {
         'id': fields.IntegerField(),
         'address': fields.IPAddressField(),
@@ -55,6 +56,10 @@ class FloatingIP(obj_base.NovaPersistentObject, obj_base.NovaObject):
             self.fixed_ip.obj_make_compatible(
                     primitive['fixed_ip']['nova_object.data'], '1.3')
             primitive['fixed_ip']['nova_object.version'] = '1.3'
+        elif target_version < (1, 5) and self.obj_attr_is_set('fixed_ip'):
+            self.fixed_ip.obj_make_compatible(
+                    primitive['fixed_ip']['nova_object.data'], '1.4')
+            primitive['fixed_ip']['nova_object.version'] = '1.4'
 
     @staticmethod
     def _from_db_object(context, floatingip, db_floatingip,
@@ -173,6 +178,7 @@ class FloatingIPList(obj_base.ObjectListBase, obj_base.NovaObject):
     # Version 1.3: FloatingIP 1.2
     # Version 1.4: FloatingIP 1.3
     # Version 1.5: FloatingIP 1.4
+    # Version 1.6: FloatingIP 1.5
     fields = {
         'objects': fields.ListOfObjectsField('FloatingIP'),
         }
@@ -183,8 +189,9 @@ class FloatingIPList(obj_base.ObjectListBase, obj_base.NovaObject):
         '1.3': '1.2',
         '1.4': '1.3',
         '1.5': '1.4',
+        '1.6': '1.5',
         }
-    VERSION = '1.5'
+    VERSION = '1.6'
 
     @obj_base.remotable_classmethod
     def get_all(cls, context):
diff --git a/nova/tests/db/test_db_api.py b/nova/tests/db/test_db_api.py
index 9da6be3548ff..b06dcda1d583 100644
--- a/nova/tests/db/test_db_api.py
+++ b/nova/tests/db/test_db_api.py
@@ -3610,7 +3610,8 @@ class FixedIPTestCase(BaseInstanceTypeTestCase):
         ]
 
         db.fixed_ip_bulk_create(self.ctxt, params)
-        ignored_keys = ['created_at', 'id', 'deleted_at', 'updated_at']
+        ignored_keys = ['created_at', 'id', 'deleted_at', 'updated_at',
+                        'virtual_interface', 'network', 'floating_ips']
         fixed_ip_data = db.fixed_ip_get_by_instance(self.ctxt, instance_uuid)
 
         # we have no `id` in incoming data so we can not use
diff --git a/nova/tests/objects/test_fixed_ip.py b/nova/tests/objects/test_fixed_ip.py
index e30459a124d4..19b8b187afc2 100644
--- a/nova/tests/objects/test_fixed_ip.py
+++ b/nova/tests/objects/test_fixed_ip.py
@@ -40,13 +40,16 @@ fake_fixed_ip = {
     'leased': False,
     'reserved': False,
     'host': None,
+    'network': None,
+    'virtual_interface': None,
+    'floating_ips': [],
     }
 
 
 class _TestFixedIPObject(object):
     def _compare(self, obj, db_obj):
         for field in obj.fields:
-            if field in ('virtual_interface', 'default_route'):
+            if field in ('default_route', 'floating_ips'):
                 continue
             if field in fixed_ip.FIXED_IP_OPTIONAL_ATTRS:
                 if obj.obj_attr_is_set(field) and db_obj[field] is not None:
@@ -257,6 +260,10 @@ class _TestFixedIPObject(object):
         get.assert_called_once_with(self.context, 123)
         self._compare(fixedips[0], fake_fixed_ip)
 
+    def test_floating_ips_do_not_lazy_load(self):
+        fixedip = fixed_ip.FixedIP()
+        self.assertRaises(NotImplementedError, lambda: fixedip.floating_ips)
+
     @mock.patch('nova.db.fixed_ip_bulk_create')
     def test_bulk_create(self, bulk):
         fixed_ips = [fixed_ip.FixedIP(address='192.168.1.1'),
diff --git a/nova/tests/objects/test_objects.py b/nova/tests/objects/test_objects.py
index 35fc5d9407b5..06ec4c1fc908 100644
--- a/nova/tests/objects/test_objects.py
+++ b/nova/tests/objects/test_objects.py
@@ -944,12 +944,12 @@ object_data = {
     'EC2InstanceMapping': '1.0-627baaf4b12c9067200979bdc4558a99',
     'EC2SnapshotMapping': '1.0-26cf315be1f8abab4289d4147671c836',
     'EC2VolumeMapping': '1.0-2f8c3bf077c65a425294ec2b361c9143',
-    'FixedIP': '1.4-c86389e85d762b7857db084b0dad0f24',
-    'FixedIPList': '1.4-663f3790a8783daede3d56748329361e',
+    'FixedIP': '1.5-2472964d39e50da67202109eb85cd173',
+    'FixedIPList': '1.5-b150167937c905b207769a17e7201d15',
     'Flavor': '1.1-096cfd023c35d07542cf732fb29b45e4',
     'FlavorList': '1.1-a3d5551267cb8f62ff38ded125900721',
-    'FloatingIP': '1.4-27eb68b7c9c620dd5f0561b5a3be0e82',
-    'FloatingIPList': '1.5-28f21c9c8a12afd51535b3f17900667d',
+    'FloatingIP': '1.5-27eb68b7c9c620dd5f0561b5a3be0e82',
+    'FloatingIPList': '1.6-6b50a8954fbd03b2bdd01df088210e86',
     'Instance': '1.15-1154dc29398bc3c57f053b8e449bb03d',
     'InstanceAction': '1.1-6b1d0a6dbd522b5a83c20757ec659663',
     'InstanceActionEvent': '1.1-42dbdba74bd06e0619ca75cd3397cd1b',
@@ -996,8 +996,9 @@ object_data = {
 object_relationships = {
     'BlockDeviceMapping': {'Instance': '1.15'},
     'FixedIP': {'Instance': '1.15', 'Network': '1.2',
-                'VirtualInterface': '1.0'},
-    'FloatingIP': {'FixedIP': '1.4'},
+                'VirtualInterface': '1.0',
+                'FloatingIPList': '1.6'},
+    'FloatingIP': {'FixedIP': '1.5'},
     'Instance': {'InstanceFault': '1.2',
                  'InstanceInfoCache': '1.5',
                  'InstanceNUMATopology': '1.0',