diff --git a/gso/services/_ipam.py b/gso/services/_ipam.py
index d6a620cb0a689c2591fbc3c997dea1aff737ea6e..64d6c6b8b0d74e5d325ca38f558fb69639269d8f 100644
--- a/gso/services/_ipam.py
+++ b/gso/services/_ipam.py
@@ -38,6 +38,8 @@ class HostAddresses(BaseSettings):
 class IPAMErrors(Enum):
     # HTTP error code, match in error message
     CONTAINER_FULL = 400, "Can not find requested number of networks"
+    EXTATTR_UNKNOWN = 400, "Unknown extensible attribute"
+    EXTATTR_BADVALUE = 400, "Bad value for extensible attribute"
 
 
 # TODO: remove this!
@@ -144,7 +146,8 @@ def _get_network_capacity(network=None):
 def _allocate_network(
     infoblox_params: settings.InfoBloxParams,
     network_params: Union[settings.V4NetworkParams, settings.V6NetworkParams],
-    ip_version=4
+    ip_version=4,
+    extattrs={}
 ) -> Union[V4ServiceNetwork, V6ServiceNetwork]:
     assert ip_version in [4, 6]
     endpoint = 'network' if ip_version == 4 else 'ipv6network'
@@ -152,6 +155,7 @@ def _allocate_network(
         'ipv6networkcontainer'
 
     # only return in the response the allocated network, not all available
+    # TODO: any validation needed for extrattrs wherever it's used?
     req_payload = {
         "network": {
             "_object_function": "next_available_network",
@@ -163,7 +167,8 @@ def _allocate_network(
                 "network": str(network_params.containers[0])
             },
             "_result_field": "networks",
-        }
+        },
+        "extattrs": extattrs
     }
 
     container_index = 0
@@ -198,7 +203,7 @@ def _allocate_network(
         return V6ServiceNetwork(v6=allocated_network)
 
 
-def allocate_service_ipv4_network(service_type) -> V4ServiceNetwork:
+def allocate_service_ipv4_network(service_type, extattrs) -> V4ServiceNetwork:
     """
     Allocate IPv4 network within the container of the specified service type.
     """
@@ -209,10 +214,11 @@ def allocate_service_ipv4_network(service_type) -> V4ServiceNetwork:
         and service_type != 'INFOBLOX', "Invalid service type."
     return _allocate_network(ipam_params.INFOBLOX,
                              getattr(ipam_params, service_type).V4,
-                             4)
+                             4,
+                             extattrs)
 
 
-def allocate_service_ipv6_network(service_type) -> V6ServiceNetwork:
+def allocate_service_ipv6_network(service_type, extattrs) -> V6ServiceNetwork:
     """
     Allocate IPv6 network within the container of the specified service type.
     """
@@ -223,7 +229,8 @@ def allocate_service_ipv6_network(service_type) -> V6ServiceNetwork:
         and service_type != 'INFOBLOX', "Invalid service type."
     return _allocate_network(ipam_params.INFOBLOX,
                              getattr(ipam_params, service_type).V6,
-                             6)
+                             6,
+                             extattrs)
 
 
 def _find_next_available_ip(infoblox_params, network_ref):
@@ -242,7 +249,7 @@ def _find_next_available_ip(infoblox_params, network_ref):
     return received_ip[0]
 
 
-def _allocate_host(hostname=None, addr=None, network=None
+def _allocate_host(hostname=None, addr=None, network=None, extattrs={}
                    ) -> Union[V4HostAddress, V6HostAddress]:
     """
     If network is not None, allocate host in that network.
@@ -278,7 +285,8 @@ def _allocate_host(hostname=None, addr=None, network=None
         ],
         "name": hostname,
         "configure_for_dns": False,
-        "view": "default"
+        "view": "default",
+        "extattrs": extattrs
     }
 
     r = requests.post(
@@ -296,7 +304,8 @@ def _allocate_host(hostname=None, addr=None, network=None
     dns_req_payload = {
         f"ipv{ip_version}addr": addr,
         "name": hostname,
-        "view": "default"
+        "view": "default",
+        "extattrs": extattrs
     }
 
     endpoint = 'record:a' if ip_version == 4 else 'record:aaaa'
@@ -322,7 +331,8 @@ def _allocate_host(hostname=None, addr=None, network=None
 def allocate_service_host(hostname=None,
                           service_type=None,
                           service_networks: ServiceNetworks = None,
-                          host_addresses: HostAddresses = None
+                          host_addresses: HostAddresses = None,
+                          extattrs={}
                           ) -> HostAddresses:
     """
     Allocate host with both IPv4 and IPv6 address (and respective DNS
@@ -370,19 +380,22 @@ def allocate_service_host(hostname=None,
         assert first_nonfull_ipv4_network, \
             "No available IPv4 addresses for this service type."
         v4_host = _allocate_host(hostname=hostname+domain_name,
-                                 network=first_nonfull_ipv4_network)
+                                 network=first_nonfull_ipv4_network,
+                                 extattrs=extattrs)
     elif service_networks:
         network = service_networks.v4
         assert any(network.subnet_of(ipv4_container)
                    for ipv4_container in ipv4_containers)
         v4_host = _allocate_host(hostname=hostname+domain_name,
-                                 network=str(network))
+                                 network=str(network),
+                                 extattrs=extattrs)
     elif host_addresses:
         addr = host_addresses.v4
         assert any(addr in ipv4_container
                    for ipv4_container in ipv4_containers)
         v4_host = _allocate_host(hostname=hostname+domain_name,
-                                 addr=str(addr))
+                                 addr=str(addr),
+                                 extattrs=extattrs)
 
     # IPv6
     if not service_networks and not host_addresses:
@@ -396,19 +409,22 @@ def allocate_service_host(hostname=None,
         assert 'network' in ipv6_networks_info[0]
         # TODO: if "no available IP" error, create a new network?
         v6_host = _allocate_host(hostname=hostname+domain_name,
-                                 network=ipv6_networks_info[0]['network'])
+                                 network=ipv6_networks_info[0]['network'],
+                                 extattrs=extattrs)
     elif service_networks:
         network = service_networks.v6
         assert any(network.subnet_of(ipv6_container)
                    for ipv6_container in ipv6_containers)
         v6_host = _allocate_host(hostname=hostname+domain_name,
-                                 network=str(network))
+                                 network=str(network),
+                                 extattrs=extattrs)
     elif host_addresses:
         addr = host_addresses.v6
         assert any(addr in ipv6_container
                    for ipv6_container in ipv6_containers)
         v6_host = _allocate_host(hostname=hostname+domain_name,
-                                 addr=str(addr))
+                                 addr=str(addr),
+                                 extattrs=extattrs)
 
     return HostAddresses(v4=v4_host.v4, v6=v6_host.v6)
 
diff --git a/gso/services/ipam.py b/gso/services/ipam.py
index 5777d1d6405f82c47e1a3c7b4beecfa2d823fe45..1c846be89f60668448b247c34b0e77b7d738a843 100644
--- a/gso/services/ipam.py
+++ b/gso/services/ipam.py
@@ -30,11 +30,11 @@ class HostAddresses(BaseSettings):
     v6: ipaddress.IPv6Address
 
 
-def new_service_networks(service_type) -> ServiceNetworks:
+def new_service_networks(service_type, extattrs={}) -> ServiceNetworks:
     v4_service_network = _ipam.allocate_service_ipv4_network(
-        service_type=service_type)
+        service_type=service_type, extattrs=extattrs)
     v6_service_network = _ipam.allocate_service_ipv6_network(
-        service_type=service_type)
+        service_type=service_type, extattrs=extattrs)
     return ServiceNetworks(
         v4=v4_service_network.v4,
         v6=v6_service_network.v6)
@@ -42,32 +42,58 @@ def new_service_networks(service_type) -> ServiceNetworks:
 
 def new_service_host(hostname,
                      service_type,
-                     service_networks: ServiceNetworks) -> HostAddresses:
+                     service_networks: ServiceNetworks = None,
+                     host_addresses: HostAddresses = None,
+                     extattrs={}) -> HostAddresses:
     return _ipam.allocate_service_host(
         hostname=hostname,
         service_type=service_type,
-        service_networks=service_networks)
+        service_networks=service_networks,
+        host_addresses=host_addresses,
+        extattrs=extattrs)
 
 
 if __name__ == '__main__':
     # sample call flow to allocate two loopback interfaces and a trunk service
     # new_service_host can be called passing networks or addresses
-    # - the first time is called by passing a specific ipv4/ipv6 address pair
-    # - the rest are called by passing the ipv4/ipv6 network pair
+    # - host h1 for service LO uses a specific ipv4/ipv6 address pair
+    # - the rest use the ipv4/ipv6 network pair
+    # networks and hosts can be allocated with extensible attributes
+    # - host h2 for service LO uses extattrs for both network and address/DNS
+    # - the rest don't use extattrs
 
-    hostname_A = 'newhost1'
-    hostname_B = 'newhost2'
-    # h1 loopback
-    lo1_service_networks = new_service_networks('LO')
+    hostname_A = 'h1'
+    hostname_B = 'h2'
+
+    # h1 LO (loopback)
+    lo1_service_networks = new_service_networks(service_type='LO')
     lo1_v4_host_address = lo1_service_networks.v4.network_address
     lo1_v6_host_address = lo1_service_networks.v6.network_address
     lo1_host_addresses = HostAddresses(v4=lo1_v4_host_address,
                                        v6=lo1_v6_host_address)
-    new_service_host(hostname_A, 'LO', lo1_service_networks)
-    # h2 loopback
-    lo2_service_networks = new_service_networks('LO')
-    new_service_host(hostname_B, 'LO', lo2_service_networks)
-    # h1-h2 trunk
-    trunk12_service_networks = new_service_networks('TRUNK')
-    new_service_host(hostname_A, 'TRUNK', trunk12_service_networks)
-    new_service_host(hostname_B, 'TRUNK', trunk12_service_networks)
+    new_service_host(hostname=hostname_A,
+                     service_type='LO',
+                     host_addresses=lo1_host_addresses)
+
+    # h2 LO (loopback)
+    lo2_network_extattrs = {
+        "vrf_name": {"value": "dummy_vrf"},
+    }
+    lo2_host_extattrs = {
+        "Site": {"value": "dummy_site"},
+    }
+    lo2_service_networks = \
+        new_service_networks(service_type='LO', extattrs=lo2_network_extattrs)
+    new_service_host(hostname=hostname_B,
+                     service_type='LO',
+                     service_networks=lo2_service_networks,
+                     extattrs=lo2_host_extattrs)
+
+    # h1-h2 TRUNK
+    trunk12_service_networks = new_service_networks(service_type='TRUNK')
+    new_service_host(hostname=hostname_A,
+                     service_type='TRUNK',
+                     service_networks=trunk12_service_networks)
+    new_service_host(hostname=hostname_B,
+                     service_type='TRUNK',
+                     service_networks=trunk12_service_networks)