diff --git a/gso/oss-params-example.json b/gso/oss-params-example.json
index 4c9f4c580f3bc23e0f5a2514125cfa7f7c2e4d86..73b7a6302bb3bd971af17b051d64f10888797fca 100644
--- a/gso/oss-params-example.json
+++ b/gso/oss-params-example.json
@@ -8,13 +8,20 @@
       "username": "robot-user",
       "password": "robot-user-password"
     },
-    "TRUNK": {
+    "LO": {
       "V4": {"container": "1.1.0.0/24", "mask": 31},
-      "V6": {"container": "dead:beef::/64", "mask": 96}
+      "V6": {"container": "dead:beef::/64", "mask": 126},
+      "domain_name": ".lo"
+	},
+    "TRUNK": {
+      "V4": {"container": "1.1.1.0/24", "mask": 31},
+      "V6": {"container": "dead:beef::/64", "mask": 126},
+      "domain_name": ".trunk"
     },
     "GEANT_IP": {
-      "V4": {"container": "1.1.8.0/24", "mask": 31},
-      "V6": {"container": "dead:beef::/64", "mask": 96}
+      "V4": {"container": "1.1.2.0/24", "mask": 31},
+      "V6": {"container": "dead:beef::/64", "mask": 126},
+      "domain_name": ".geantip"
     }
   }
 }
\ No newline at end of file
diff --git a/gso/services/_ipam.py b/gso/services/_ipam.py
index 58715aedc705e5e5fef538ed3228dbb5a26a1e76..1c9f7d4c1e667694b78a8a1ee4bb7ed36fc14fde 100644
--- a/gso/services/_ipam.py
+++ b/gso/services/_ipam.py
@@ -66,6 +66,10 @@ def _ip_network_version(network):
     return ip_version
 
 def find_containers(network=None, ip_version=4):
+    """
+    If network is not None, find the container that contains specified network.
+    Otherwise find all containers.
+    """
     assert ip_version in [4, 6]
     oss = settings.load_oss_params()
     assert oss.IPAM.INFOBLOX
@@ -75,24 +79,62 @@ def find_containers(network=None, ip_version=4):
         f'{_wapi(infoblox_params)}/{endpoint}',
         params={'network': network} if network else None,
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
     return r.json()
 
-def find_networks(network=None, ip_version=4):
+def find_networks(network_container=None, network=None, ip_version=4):
+    """
+    If network_container is not None, find all networks within the specified container.
+    Otherwise if network is not None, find the specified network.
+    Otherwise find all networks.
+    """
     assert ip_version in [4, 6]
     oss = settings.load_oss_params()
     assert oss.IPAM.INFOBLOX
     infoblox_params = oss.IPAM.INFOBLOX
     endpoint = 'network' if ip_version == 4 else 'ipv6network'
+    params = None
+    if network_container:
+        params={'network_container': network_container}
+    elif network:
+        params={'network': network}
     r = requests.get(
         f'{_wapi(infoblox_params)}/{endpoint}',
-        params={'network': network} if network else None,
+        params=params,
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
     return r.json()
 
+def get_network_capacity(network=None):
+    """
+    Get utilization of a IPv4 network in a fraction of 1000.
+    """
+    oss = settings.load_oss_params()
+    assert oss.IPAM.INFOBLOX
+    infoblox_params = oss.IPAM.INFOBLOX
+
+    ip_version = _ip_network_version(network)
+    assert ip_version == 4, "Utilization is only available for IPv4 networks."
+    params={'network': network, '_return_fields': 'network,total_hosts,utilization'}
+
+    r = requests.get(
+        f'{_wapi(infoblox_params)}/network',
+        params=params,
+        auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
+        verify=False
+    )
+    assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
+    capacity_info = r.json()
+    assert len(capacity_info) == 1, "Requested IPv4 network doesn't exist."
+    assert 'utilization' in capacity_info[0]
+    utilization = capacity_info[0]['utilization']
+    return utilization
+
+
 def _allocate_network(infoblox_params: settings.InfoBloxParams, network_params: Union[settings.V4NetworkParams, settings.V6NetworkParams], ip_version=4):
     assert ip_version in [4, 6]
     endpoint = 'network' if ip_version == 4 else 'ipv6network'
@@ -133,7 +175,8 @@ def _allocate_network(infoblox_params: settings.InfoBloxParams, network_params:
         json=req_payload,
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
         headers={'content-type': "application/json"},
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
 
     allocated_network = r.json()['network']
@@ -143,6 +186,9 @@ def _allocate_network(infoblox_params: settings.InfoBloxParams, network_params:
         return V6ServiceNetwork(v6=allocated_network)
 
 def allocate_service_ipv4_network(service_type):
+    """
+    Allocate IPv4 network within the container of the specified service type.
+    """
     oss = settings.load_oss_params()
     assert oss.IPAM
     ipam_params = oss.IPAM
@@ -150,6 +196,9 @@ def allocate_service_ipv4_network(service_type):
     return _allocate_network(ipam_params.INFOBLOX, getattr(ipam_params, service_type).V4, 4)
 
 def allocate_service_ipv6_network(service_type):
+    """
+    Allocate IPv6 network within the container of the specified service type.
+    """
     oss = settings.load_oss_params()
     assert oss.IPAM
     ipam_params = oss.IPAM
@@ -157,6 +206,9 @@ def allocate_service_ipv6_network(service_type):
     return _allocate_network(ipam_params.INFOBLOX, getattr(ipam_params, service_type).V6, 6)
 
 def delete_network(network):
+    """
+    Delete IPv4 or IPv6 network by CIDR.
+    """
     oss = settings.load_oss_params()
     assert oss.IPAM.INFOBLOX
     infoblox_params = oss.IPAM.INFOBLOX
@@ -170,7 +222,8 @@ def delete_network(network):
     r = requests.delete(
         f'{_wapi(infoblox_params)}/{network_info[0]["_ref"]}',
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
 
     # Extract ipv4/ipv6 address from the network reference obtained in the response
@@ -185,14 +238,20 @@ def _find_next_available_ip(infoblox_params, network_ref):
     r = requests.post(
         f'{_wapi(infoblox_params)}/{network_ref}?_function=next_available_ip&num=1',
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
     assert 'ips' in r.json()
     received_ip = r.json()['ips']
     assert len(received_ip) == 1
     return received_ip[0]
 
-def allocate_host(mac=None, hostname=None, addr=None, network=None, service_type=None):
+def allocate_host(hostname=None, addr=None, network=None):
+    """
+    If network is not None, allocate host in that network.
+    Otherwise if addr is not None, allocate host with that address.
+    """
+    assert addr or network, "You must specify either the host address or the network CIDR."
     oss = settings.load_oss_params()
     assert oss.IPAM.INFOBLOX
     infoblox_params = oss.IPAM.INFOBLOX
@@ -208,11 +267,12 @@ def allocate_host(mac=None, hostname=None, addr=None, network=None, service_type
     else:
         ip_version = _ip_addr_version(addr)
 
+    # TODO: use same request for both IP and DNS records
+
     ipv4_req_payload = {
         "ipv4addrs": [
             {
-                "ipv4addr": addr,
-                "mac": mac
+                "ipv4addr": addr
             }
         ],
         "name": hostname,
@@ -237,7 +297,8 @@ def allocate_host(mac=None, hostname=None, addr=None, network=None, service_type
         f'{_wapi(infoblox_params)}/record:host',
         json=ip_req_payload,
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
     assert isinstance(r.json(), str)
     assert r.json().startswith("record:host/")
@@ -261,7 +322,8 @@ def allocate_host(mac=None, hostname=None, addr=None, network=None, service_type
         f'{_wapi(infoblox_params)}/{endpoint}',
         json=dns_req_payload,
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
     assert isinstance(r.json(), str)
     assert r.json().startswith(f"{endpoint}/")
@@ -271,7 +333,49 @@ def allocate_host(mac=None, hostname=None, addr=None, network=None, service_type
     else:
         return V6HostAddress(v6=addr)
 
+def allocate_host_by_service_type(hostname=None, service_type=None):
+    """
+    Allocate host with both IPv4 and IPv6 address (and respective DNS records).
+    The first network with available space for this service type is used.
+    The domain name is also taken from the service type and appended to specified hostname.
+    """
+    oss = settings.load_oss_params()
+    assert oss.IPAM
+    ipam_params = oss.IPAM
+    assert ipam_params.INFOBLOX
+    infoblox_params = ipam_params.INFOBLOX
+
+    assert hasattr(ipam_params, service_type) and service_type != 'INFOBLOX', "Invalid service type."
+    ipv4_container = getattr(ipam_params, service_type).V4.container
+    ipv6_container = getattr(ipam_params, service_type).V6.container
+    domain_name = getattr(ipam_params, service_type).domain_name
+
+    ipv4_networks_info = find_networks(network_container=str(ipv4_container), ip_version=4)
+    assert len(ipv4_networks_info) >= 1, "No IPv4 network exists in the container for this service type."
+    first_nonfull_ipv4_network = None
+    for ipv4_network_info in ipv4_networks_info:
+        assert 'network' in ipv4_network_info
+        capacity = get_network_capacity(ipv4_network_info["network"])
+        if capacity < 1000:
+            first_nonfull_ipv4_network = ipv4_network_info["network"]
+            break
+    # TODO: create a new network if available space in the container.
+    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)
+
+    # ipv6 does not support capacity fetching (not even the GUI displays it).
+    # Maybe it's assumed that there is always available space?
+    ipv6_networks_info = find_networks(network_container=str(ipv6_container), ip_version=6)
+    assert len(ipv6_networks_info) >= 1, "No IPv6 network exists in the container for this service type."
+    assert 'network' in ipv6_networks_info[0]
+    v6_host = allocate_host(hostname=hostname+domain_name, network=ipv6_networks_info[0]['network'])
+
+    return HostAddresses(v4=v4_host,v6=v6_host)
+
 def delete_host_by_ip(addr):
+    """
+    Delete IPv4 or IPv6 host by its address.
+    """
     oss = settings.load_oss_params()
     assert oss.IPAM.INFOBLOX
     infoblox_params = oss.IPAM.INFOBLOX
@@ -284,7 +388,8 @@ def delete_host_by_ip(addr):
         f'{_wapi(infoblox_params)}/record:host',
         params={ip_param: addr},
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     host_data = r.json()
     assert len(host_data) == 1, "Host does not exist."
     assert '_ref' in host_data[0]
@@ -294,7 +399,8 @@ def delete_host_by_ip(addr):
     r = requests.delete(
         f'{_wapi(infoblox_params)}/{host_ref}',
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
 
     # Also find and delete the associated dns a/aaaa record
@@ -304,7 +410,8 @@ def delete_host_by_ip(addr):
         f'{_wapi(infoblox_params)}/{endpoint}',
         params={ip_param: addr},
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     dns_data = r.json()
     assert len(dns_data) == 1, "DNS record does not exist."
     assert '_ref' in dns_data[0]
@@ -313,7 +420,8 @@ def delete_host_by_ip(addr):
     r = requests.delete(
         f'{_wapi(infoblox_params)}/{dns_ref}',
         auth=HTTPBasicAuth(infoblox_params.username, infoblox_params.password),
-        verify=False)
+        verify=False
+    )
     assert r.status_code >= 200 and r.status_code < 300, f"HTTP error {r.status_code}: {r.reason}\n\n{r.text}"
 
     if ip_version == 4:
@@ -325,13 +433,14 @@ if __name__ == '__main__':
     while True:
         print("1. Find all containers")
         print("2. Find all networks")
-        print("3. Create new network")
-        print("4. Delete network")
-        print("5. Allocate host by IP")
-        print("6. Allocate host by network CIDR")
-        print("7. Allocate host by service type")
-        print("8. Delete host by IP")
-        print("9. Exit")
+        print("3. Get network capacity")
+        print("4. Create new network")
+        print("5. Delete network")
+        print("6. Allocate host by IP")
+        print("7. Allocate host by network CIDR")
+        print("8. Allocate host by service type")
+        print("9. Delete host by IP")
+        print("10. Exit")
 
         choice = input("Enter your choice: ")
 
@@ -342,10 +451,15 @@ if __name__ == '__main__':
 
         elif choice == '2':
             ip_version = int(input("Enter IP version (4 or 6): "))
-            networks = find_networks(ip_version=ip_version)
+            networks = find_networks(ip_version=ip_version) #, network_container="10.255.255.0/24"
             print(json.dumps(networks, indent=2))
 
         elif choice == '3':
+            network = input("Enter network (in CIDR notation): ")
+            network_capacity = get_network_capacity(network=network)
+            print(json.dumps(network_capacity, indent=2))
+
+        elif choice == '4':
             service_type = input("Enter service type: ")
             ip_version = int(input("Enter IP version (4 or 6): "))
             if ip_version == 4:
@@ -357,40 +471,35 @@ if __name__ == '__main__':
                 continue
             print(json.dumps(str(new_network), indent=2))
 
-        elif choice == '4':
+        elif choice == '5':
             network = input("Enter network to delete (in CIDR notation): ")
             deleted_network = delete_network(network=network)
             print(json.dumps(str(deleted_network), indent=2))
 
-        elif choice == '5':
+        elif choice == '6':
             hostname = input("Enter host name: ")
             addr = input("Enter IP address to allocate: ")
-            mac = ":".join(["{:02x}".format(random.randint(0x00, 0xff)) for i in range(6)]) #input("Enter MAC address (you can leave empty if IPv6): ")
-            alloc_ip = allocate_host(hostname=hostname, addr=addr, mac=mac)
+            alloc_ip = allocate_host(hostname=hostname, addr=addr)
             print(json.dumps(str(alloc_ip), indent=2))
 
-        elif choice == '6':
+        elif choice == '7':
             hostname = input("Enter host name: ")
             network = input("Enter an existing network to allocate from (in CIDR notation): ")
-            mac = ":".join(["{:02x}".format(random.randint(0x00, 0xff)) for i in range(6)]) #input("Enter MAC address (you can leave empty if IPv6): ")
-            alloc_ip = allocate_host(hostname=hostname, network=network, mac=mac)
+            alloc_ip = allocate_host(hostname=hostname, network=network)
             print(json.dumps(str(alloc_ip), indent=2))
 
-        elif choice == '7':
-            print("Not implemented.")
-            continue
+        elif choice == '8':
             hostname = input("Enter host name: ")
             service_type = input("Enter service type: ")
-            mac = ":".join(["{:02x}".format(random.randint(0x00, 0xff)) for i in range(6)]) #input("Enter MAC address (you can leave empty if IPv6): ")
-            alloc_ip = allocate_host(hostname=hostname, service_type=service_type, mac=mac)
+            alloc_ip = allocate_host_by_service_type(hostname=hostname, service_type=service_type)
             print(json.dumps(str(alloc_ip), indent=2))
 
-        elif choice == '8':
+        elif choice == '9':
             addr = input("Enter IP address of host to delete: ")
             deleted_host = delete_host_by_ip(addr=addr)
             print(json.dumps(str(deleted_host), indent=2))
 
-        elif choice == '9':
+        elif choice == '10':
             print("Exiting...")
             break
 
diff --git a/gso/services/ipam.py b/gso/services/ipam.py
index bea4dee9afd76cf94c3a2cc26574fb53eaad9d8d..14c80ce782c1920e9e3ca3ac5b85cf7e3468fe57 100644
--- a/gso/services/ipam.py
+++ b/gso/services/ipam.py
@@ -39,14 +39,10 @@ def new_service_networks(service_type) -> ServiceNetworks:
         v6=v6_service_network)
 
 
-def new_device_lo_address() -> HostAddresses:
-    oss = settings.load_oss_params()
-    assert oss.IPAM.INFOBLOX
-    # TODO: load from ipam
-    return HostAddresses(
-        v4=ipaddress.IPv4Address('10.10.10.10'),
-        v6=ipaddress.IPv6Address('fc00:798:aa:1::10'))
+def new_device_lo_address(hostname) -> HostAddresses:
+    return _ipam.allocate_host_by_service_type(hostname=hostname, service_type='LO')
 
 
 if __name__ == '__main__':
-    new_service_networks('TRUNK')
\ No newline at end of file
+    #new_service_networks('TRUNK')
+    new_device_lo_address('newhost1')
\ No newline at end of file
diff --git a/gso/settings.py b/gso/settings.py
index 0846e5f2ae2f983f7216666df34a8388e0697853..91c1251538fec86151b5582b5ec4b44a40aa682b 100644
--- a/gso/settings.py
+++ b/gso/settings.py
@@ -25,10 +25,12 @@ class V6NetworkParams(BaseSettings):
 class ServiceNetworkParams(BaseSettings):
     V4: V4NetworkParams
     V6: V6NetworkParams
+    domain_name: str
 
 
 class IPAMParams(BaseSettings):
     INFOBLOX: InfoBloxParams
+    LO: ServiceNetworkParams
     TRUNK: ServiceNetworkParams
     GEANT_IP: ServiceNetworkParams