diff --git a/hooks/infoblox-neutron-relation-broken b/hooks/infoblox-neutron-relation-broken
new file mode 120000
index 00000000..1fb10fd5
--- /dev/null
+++ b/hooks/infoblox-neutron-relation-broken
@@ -0,0 +1 @@
+neutron_api_hooks.py
\ No newline at end of file
diff --git a/hooks/infoblox-neutron-relation-changed b/hooks/infoblox-neutron-relation-changed
new file mode 120000
index 00000000..1fb10fd5
--- /dev/null
+++ b/hooks/infoblox-neutron-relation-changed
@@ -0,0 +1 @@
+neutron_api_hooks.py
\ No newline at end of file
diff --git a/hooks/infoblox-neutron-relation-departed b/hooks/infoblox-neutron-relation-departed
new file mode 120000
index 00000000..1fb10fd5
--- /dev/null
+++ b/hooks/infoblox-neutron-relation-departed
@@ -0,0 +1 @@
+neutron_api_hooks.py
\ No newline at end of file
diff --git a/hooks/neutron_api_context.py b/hooks/neutron_api_context.py
index 13888ec6..46e99441 100644
--- a/hooks/neutron_api_context.py
+++ b/hooks/neutron_api_context.py
@@ -879,3 +879,43 @@ class DesignateContext(context.OSContextGenerator):
                 ctxt['ipv6_ptr_zone_prefix_size'] = (
                     config('ipv6-ptr-zone-prefix-size'))
         return ctxt
+
+
+class NeutronInfobloxContext(context.OSContextGenerator):
+    '''Infoblox IPAM context for Neutron API'''
+    interfaces = ['infoblox-neutron']
+
+    def __call__(self):
+        ctxt = {}
+        rdata = {}
+        for rid in relation_ids('infoblox-neutron'):
+            if related_units(rid) and not rdata:
+                for unit in related_units(rid):
+                    rdata = relation_get(rid=rid, unit=unit)
+                    ctxt['cloud_data_center_id'] = rdata.get('dc_id')
+                    break
+        if ctxt.get('cloud_data_center_id') is not None:
+            if not self.check_requirements(rdata):
+                log('Missing Infoblox connection information, passing.')
+                return {}
+            ctxt['enable_infoblox'] = True
+            ctxt['cloud_data_center_id'] = rdata.get('dc_id')
+            ctxt['grid_master_host'] = rdata.get('grid_master_host')
+            ctxt['grid_master_name'] = rdata.get('grid_master_name')
+            ctxt['infoblox_admin_user_name'] = rdata.get('admin_user_name')
+            ctxt['infoblox_admin_password'] = rdata.get('admin_password')
+            # the next three values are non-critical and may accept defaults
+            ctxt['wapi_version'] = rdata.get('wapi_version', '2.3')
+            ctxt['wapi_max_results'] = rdata.get('wapi_max_results', '-50000')
+            ctxt['wapi_paging'] = rdata.get('wapi_paging', True)
+        return ctxt
+
+    def check_requirements(self, rdata):
+        required = [
+            'grid_master_name',
+            'grid_master_host',
+            'admin_user_name',
+            'admin_password',
+        ]
+        return len(set(p for p, v in rdata.items() if v).
+                   intersection(required)) == len(required)
diff --git a/hooks/neutron_api_hooks.py b/hooks/neutron_api_hooks.py
index 6ee4d2bf..10c3b582 100755
--- a/hooks/neutron_api_hooks.py
+++ b/hooks/neutron_api_hooks.py
@@ -35,6 +35,7 @@ from charmhelpers.core.hookenv import (
     open_port,
     unit_get,
     related_units,
+    is_leader,
 )
 
 from charmhelpers.core.host import (
@@ -86,6 +87,7 @@ from neutron_api_utils import (
     pause_unit_helper,
     resume_unit_helper,
     remove_old_packages,
+    is_db_initialised,
 )
 from neutron_api_context import (
     get_dns_domain,
@@ -294,6 +296,7 @@ def config_changed():
     packages_removed = remove_old_packages()
     configure_https()
     update_nrpe_config()
+    infoblox_changed()
     CONFIGS.write_all()
     if packages_removed and not is_unit_paused_set():
         log("Package purge detected, restarting services", "INFO")
@@ -359,7 +362,7 @@ def db_changed():
         return
     CONFIGS.write_all()
     conditional_neutron_migration()
-
+    infoblox_changed()
     for r_id in relation_ids('neutron-plugin-api-subordinate'):
         neutron_plugin_api_subordinate_relation_joined(relid=r_id)
 
@@ -415,6 +418,7 @@ def identity_changed():
     for r_id in relation_ids('neutron-plugin-api-subordinate'):
         neutron_plugin_api_subordinate_relation_joined(relid=r_id)
     configure_https()
+    infoblox_changed()
 
 
 @hooks.hook('neutron-api-relation-joined')
@@ -655,6 +659,34 @@ def designate_changed():
     CONFIGS.write_all()
 
 
+@hooks.hook('infoblox-neutron-relation-changed')
+@restart_on_change(restart_map)
+def infoblox_changed():
+    # The neutron DB upgrade will add new tables to
+    # neutron db related to infoblox service.
+    # Please take a look to charm-infoblox docs.
+    if 'infoblox-neutron' not in CONFIGS.complete_contexts():
+        log('infoblox-neutron relation incomplete. Peer not ready?')
+        return
+
+    CONFIGS.write(NEUTRON_CONF)
+
+    if is_leader():
+        ready = False
+        if is_db_initialised() and neutron_ready():
+            migrate_neutron_database(upgrade=True)
+            ready = True
+        for rid in relation_ids('infoblox-neutron'):
+            relation_set(relation_id=rid, neutron_api_ready=ready)
+
+
+@hooks.hook('infoblox-neutron-relation-departed',
+            'infoblox-neutron-relation-broken')
+@restart_on_change(restart_map)
+def infoblox_departed():
+    CONFIGS.write_all()
+
+
 @hooks.hook('update-status')
 @harden()
 @harden()
diff --git a/hooks/neutron_api_utils.py b/hooks/neutron_api_utils.py
index 665c1e5e..6b63d3dd 100755
--- a/hooks/neutron_api_utils.py
+++ b/hooks/neutron_api_utils.py
@@ -173,7 +173,8 @@ BASE_RESOURCE_MAP = OrderedDict([
                      context.WorkerConfigContext(),
                      context.InternalEndpointContext(),
                      context.MemcacheContext(),
-                     neutron_api_context.DesignateContext()],
+                     neutron_api_context.DesignateContext(),
+                     neutron_api_context.NeutronInfobloxContext()],
     }),
     (NEUTRON_DEFAULT, {
         'services': ['neutron-server'],
diff --git a/metadata.yaml b/metadata.yaml
index 187ed960..666f5ac4 100644
--- a/metadata.yaml
+++ b/metadata.yaml
@@ -55,6 +55,9 @@ requires:
     interface: midonet
   external-dns:
     interface: designate
+  infoblox-neutron:
+    interface: infoblox
+    scope: container
   certificates:
     interface: tls-certificates
 peers:
diff --git a/templates/mitaka/neutron.conf b/templates/mitaka/neutron.conf
index 79fabf20..c59e7407 100644
--- a/templates/mitaka/neutron.conf
+++ b/templates/mitaka/neutron.conf
@@ -75,6 +75,10 @@ global_physnet_mtu = {{ global_physnet_mtu }}
 external_dns_driver = designate
 {% endif -%}
 
+{% if enable_infoblox -%}
+ipam_driver = infoblox
+{% endif -%}
+
 {% include "section-zeromq" %}
 
 [quotas]
@@ -121,3 +125,7 @@ lock_path = $state_path/lock
 {% endif -%}
 
 {% include "section-oslo-middleware" %}
+
+{% if enable_infoblox -%}
+{% include "parts/section-infoblox" %}
+{% endif -%}
diff --git a/templates/newton/neutron.conf b/templates/newton/neutron.conf
index c07e31f6..4aa662bb 100644
--- a/templates/newton/neutron.conf
+++ b/templates/newton/neutron.conf
@@ -75,6 +75,10 @@ global_physnet_mtu = {{ global_physnet_mtu }}
 external_dns_driver = designate
 {% endif -%}
 
+{% if enable_infoblox -%}
+ipam_driver = infoblox
+{% endif -%}
+
 {% include "section-zeromq" %}
 
 [quotas]
@@ -120,6 +124,10 @@ lock_path = $state_path/lock
 {% include "parts/section-designate" %}
 {% endif -%}
 
+{% if enable_infoblox -%}
+{% include "parts/section-infoblox" %}
+{% endif -%}
+
 [service_providers]
 service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
 service_provider = VPN:strongswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
diff --git a/templates/ocata/neutron.conf b/templates/ocata/neutron.conf
index f572756a..cc2f75b5 100644
--- a/templates/ocata/neutron.conf
+++ b/templates/ocata/neutron.conf
@@ -78,6 +78,10 @@ global_physnet_mtu = {{ global_physnet_mtu }}
 external_dns_driver = designate
 {% endif -%}
 
+{% if enable_infoblox -%}
+ipam_driver = infoblox
+{% endif -%}
+
 {% include "parts/section-placement" %}
 
 {% include "section-zeromq" %}
@@ -125,6 +129,10 @@ lock_path = $state_path/lock
 {% include "parts/section-designate" %}
 {% endif -%}
 
+{% if enable_infoblox -%}
+{% include "parts/section-infoblox" %}
+{% endif -%}
+
 [service_providers]
 service_provider = LOADBALANCERV2:Haproxy:neutron_lbaas.drivers.haproxy.plugin_driver.HaproxyOnHostPluginDriver:default
 service_provider = VPN:strongswan:neutron_vpnaas.services.vpn.service_drivers.ipsec.IPsecVPNDriver:default
diff --git a/templates/parts/section-infoblox b/templates/parts/section-infoblox
new file mode 100644
index 00000000..ac2a4709
--- /dev/null
+++ b/templates/parts/section-infoblox
@@ -0,0 +1,11 @@
+[infoblox]
+cloud_data_center_id = {{ cloud_data_center_id }}
+
+[infoblox-dc:{{ cloud_data_center_id }}]
+grid_master_host = {{ grid_master_host }}
+grid_master_name = {{ grid_master_name }}
+admin_user_name = {{ infoblox_admin_user_name }}
+admin_password = {{ infoblox_admin_password }}
+wapi_version = {{ wapi_version }}
+wapi_max_results = {{ wapi_max_results }}
+wapi_paging = {{ wapi_paging }}
diff --git a/templates/parts/section-nova b/templates/parts/section-nova
index 4a0e4eae..65f3b474 100644
--- a/templates/parts/section-nova
+++ b/templates/parts/section-nova
@@ -1,5 +1,31 @@
 [nova]
+{% if enable_infoblox -%}
+# TODO - Exceptionally we added the content of [keystone_authtoken] due to an
+# internal mechanism of Infoblox plugin lp-1688039.
+{% if auth_host -%}
+auth_type = password
+{% if api_version == "3" -%}
+auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}/v3
+auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}/v3
+project_domain_name = {{ admin_domain_name }}
+user_domain_name = {{ admin_domain_name }}
+{% else -%}
+auth_uri = {{ service_protocol }}://{{ service_host }}:{{ service_port }}
+auth_url = {{ auth_protocol }}://{{ auth_host }}:{{ auth_port }}
+project_domain_name = default
+user_domain_name = default
+{% endif -%}
+project_name = {{ admin_tenant_name }}
+username = {{ admin_user }}
+password = {{ admin_password }}
+signing_dir = {{ signing_dir }}
+{% if use_memcache == true %}
+memcached_servers = {{ memcache_url }}
+{% endif -%}
+{% endif -%}
+{% else %}
 auth_section = keystone_authtoken
+{% endif %}
 region_name = {{ region }}
 {% if use_internal_endpoints -%}
 endpoint_type = internal
diff --git a/templates/pike/neutron.conf b/templates/pike/neutron.conf
index 09a795fa..291b1ad0 100644
--- a/templates/pike/neutron.conf
+++ b/templates/pike/neutron.conf
@@ -78,6 +78,10 @@ global_physnet_mtu = {{ global_physnet_mtu }}
 external_dns_driver = designate
 {% endif -%}
 
+{% if enable_infoblox -%}
+ipam_driver = infoblox
+{% endif -%}
+
 {% include "section-zeromq" %}
 
 [quotas]
@@ -123,6 +127,10 @@ lock_path = $state_path/lock
 {% include "parts/section-designate" %}
 {% endif -%}
 
+{% if enable_infoblox -%}
+{% include "parts/section-infoblox" %}
+{% endif -%}
+
 {% include "parts/section-placement" %}
 
 [service_providers]
diff --git a/templates/queens/neutron.conf b/templates/queens/neutron.conf
index 4fb19b43..8328cacb 100644
--- a/templates/queens/neutron.conf
+++ b/templates/queens/neutron.conf
@@ -78,6 +78,10 @@ global_physnet_mtu = {{ global_physnet_mtu }}
 external_dns_driver = designate
 {% endif -%}
 
+{% if enable_infoblox -%}
+ipam_driver = infoblox
+{% endif -%}
+
 {% include "section-zeromq" %}
 
 [quotas]
@@ -123,6 +127,10 @@ lock_path = $state_path/lock
 {% include "parts/section-designate" %}
 {% endif -%}
 
+{% if enable_infoblox -%}
+{% include "parts/section-infoblox" %}
+{% endif -%}
+
 {% include "parts/section-placement" %}
 
 [service_providers]
diff --git a/unit_tests/test_neutron_api_context.py b/unit_tests/test_neutron_api_context.py
index 4f103a61..a7ec3553 100644
--- a/unit_tests/test_neutron_api_context.py
+++ b/unit_tests/test_neutron_api_context.py
@@ -1398,3 +1398,54 @@ class NeutronLoadBalancerContextTest(CharmTestCase):
                                 'base_url': 'http://1.2.3.4:1234'})
         with self.assertRaises(ValueError):
             context.NeutronLoadBalancerContext()()
+
+
+class NeutronInfobloxContextTest(CharmTestCase):
+
+    def setUp(self):
+        super(NeutronInfobloxContextTest, self).setUp(context, TO_PATCH)
+        self.relation_get.side_effect = self.test_relation.get
+        self.config.side_effect = self.test_config.get
+
+    def tearDown(self):
+        super(NeutronInfobloxContextTest, self).tearDown()
+
+    def test_infoblox_no_related_units(self):
+        self.related_units.return_value = []
+        ctxt = context.NeutronInfobloxContext()()
+        expect = {}
+
+        self.assertEqual(expect, ctxt)
+
+    def test_infoblox_related_units(self):
+        self.related_units.return_value = ['unit1']
+        self.relation_ids.return_value = ['rid1']
+        self.test_relation.set(
+            {'dc_id': '0',
+             'grid_master_host': 'foo',
+             'grid_master_name': 'bar',
+             'admin_user_name': 'faz',
+             'admin_password': 'baz'})
+        ctxt = context.NeutronInfobloxContext()()
+        expect = {'enable_infoblox': True,
+                  'cloud_data_center_id': '0',
+                  'grid_master_host': 'foo',
+                  'grid_master_name': 'bar',
+                  'infoblox_admin_user_name': 'faz',
+                  'infoblox_admin_password': 'baz',
+                  'wapi_version': '2.3',
+                  'wapi_max_results': '-50000',
+                  'wapi_paging': True}
+
+        self.assertEqual(expect, ctxt)
+
+    def test_infoblox_related_units_missing_data(self):
+        self.related_units.return_value = ['unit1']
+        self.relation_ids.return_value = ['rid1']
+        self.test_relation.set(
+            {'dc_id': '0',
+             'grid_master_host': 'foo'})
+        ctxt = context.NeutronInfobloxContext()()
+        expect = {}
+
+        self.assertEqual(expect, ctxt)
diff --git a/unit_tests/test_neutron_api_hooks.py b/unit_tests/test_neutron_api_hooks.py
index f59d6e98..ce150fb0 100644
--- a/unit_tests/test_neutron_api_hooks.py
+++ b/unit_tests/test_neutron_api_hooks.py
@@ -64,6 +64,7 @@ TO_PATCH = [
     'get_l2population',
     'get_overlay_network_type',
     'is_clustered',
+    'is_leader',
     'is_elected_leader',
     'is_qos_requested_and_valid',
     'is_vlan_trunking_requested_and_valid',
@@ -90,7 +91,7 @@ TO_PATCH = [
     'remove_old_packages',
     'services',
     'service_restart',
-    'generate_ha_relation_data',
+    'is_db_initialised',
 ]
 NEUTRON_CONF_DIR = "/etc/neutron"
 
@@ -814,7 +815,7 @@ class NeutronAPIHooksTests(CharmTestCase):
         self.is_elected_leader.return_value = True
         self.os_release.return_value = 'kilo'
         hooks.conditional_neutron_migration()
-        self.migrate_neutron_database.assert_called_with()
+        self.migrate_neutron_database.assert_called()
 
     def test_conditional_neutron_migration_leader_icehouse(self):
         self.test_relation.set({
@@ -849,3 +850,17 @@ class NeutronAPIHooksTests(CharmTestCase):
     def test_designate_peer_departed(self):
         self._call_hook('external-dns-relation-departed')
         self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
+
+    def test_infoblox_peer_changed(self):
+        self.is_db_initialised.return_value = True
+        self.test_relation.set({
+            'dc_id': '0',
+        })
+        self.os_release.return_value = 'queens'
+        self.relation_ids.side_effect = self._fake_relids
+        self._call_hook('infoblox-neutron-relation-changed')
+        self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))
+
+    def test_infoblox_peer_departed(self):
+        self._call_hook('infoblox-neutron-relation-departed')
+        self.assertTrue(self.CONFIGS.write.called_with(NEUTRON_CONF))