diff --git a/scripts/clmc-service/install-clmc-service.sh b/scripts/clmc-service/install-clmc-service.sh
index a3755cd4ce86d7147381b0d5cfae188b41f03324..a815007293e409e745f9538b394b2f52b6c6d276 100755
--- a/scripts/clmc-service/install-clmc-service.sh
+++ b/scripts/clmc-service/install-clmc-service.sh
@@ -126,6 +126,7 @@ start_script_file="/opt/flame/clmc/start.sh"
 echo "#!/bin/bash" > $start_script_file
 echo "export WORKON_HOME=${HOME}/.virtualenvs" >> $start_script_file
 echo "export SFEMC_FQDN=${SFEMC_FQDN}" >> $start_script_file
+echo "export SDN_CONTROLLER_IP=${SDN_CONTROLLER_IP}" >> $start_script_file
 echo "source /usr/local/bin/virtualenvwrapper.sh" >> $start_script_file
 echo "workon CLMC" >> $start_script_file
 echo "pserve ${REPO_ROOT}/src/service/production.ini &" >> $start_script_file
diff --git a/scripts/test/fixture.sh b/scripts/test/fixture.sh
index 2cfbae5fdf77a33fde8360058158bee569d14140..dc20be92e0b945cde9fed1c3cec247ebc2645979 100755
--- a/scripts/test/fixture.sh
+++ b/scripts/test/fixture.sh
@@ -77,7 +77,7 @@ create() {
         if [ ${service_name} == "clmc-service" ]; then
             cmd="${target_root}/scripts/clmc-service/install.sh"
             echo "Provisioning command ${cmd}"
-            lxc exec ${service_name} --env REPO_ROOT=${target_root} --env SFEMC_FQDN="sfemc.localhost" --env NETWORK_DEPENDENCY="network.target"-- ${cmd}
+            lxc exec ${service_name} --env REPO_ROOT=${target_root} --env SFEMC_FQDN="sfemc.localhost" --env SDN_CONTROLLER_IP="127.0.0.1" --env NETWORK_DEPENDENCY="network.target"-- ${cmd}
             exit_code=$?
             if [ $exit_code != 0 ]; then
                 echo "clmc-service installation failed with exit code ${exit_code}"
diff --git a/src/service/clmcservice/__init__.py b/src/service/clmcservice/__init__.py
index 3d56991b194b5c23f742f7205d35fa003fa60489..c35e2ec20a48d8440e215eef52b0375582b45b17 100644
--- a/src/service/clmcservice/__init__.py
+++ b/src/service/clmcservice/__init__.py
@@ -49,6 +49,7 @@ def main(global_config, **settings):
     Base.metadata.bind = engine  # bind the engine to the Base class metadata
 
     settings['sfemc_fqdn'] = os.environ['SFEMC_FQDN']  # read the SFEMC FQDN from the OS environment
+    settings['sdn_controller_ip'] = os.environ['SDN_CONTROLLER_IP']  # read the SDN controller IP address from the OS environment
 
     settings['influx_port'] = int(settings['influx_port'])  # the influx port setting must be converted to integer instead of a string
     settings['kapacitor_port'] = int(settings['kapacitor_port'])  # the kapacitor port setting must be converted to integer instead of a string
@@ -70,6 +71,7 @@ def main(global_config, **settings):
     config.add_route('graph_build', '/graph/temporal')
     config.add_route('graph_manage', '/graph/temporal/{graph_id}')
     config.add_route('graph_algorithms_rtt', '/graph/temporal/{graph_id}/round-trip-time')
+    config.add_route('graph_network_topology', '/graph/network')
 
     # add routes of the Alerts Configuration API
     config.add_route('alerts_configuration', '/alerts')
diff --git a/src/service/clmcservice/graphapi/conftest.py b/src/service/clmcservice/graphapi/conftest.py
index 63e241deb7ef366d9b40b9d2e80129ecb878d46b..d2b11aa8b0067cfd14686a9d24633fa39d3130f9 100644
--- a/src/service/clmcservice/graphapi/conftest.py
+++ b/src/service/clmcservice/graphapi/conftest.py
@@ -105,7 +105,8 @@ def db_testing_data():
 
     # create the physical infrastructure subgraph
     dbs = influx.get_list_database()
-    build_network_graph(graph, switches, links, clusters)
+    switch_count, cluster_count = build_network_graph(graph, switches, links, clusters)
+    assert switch_count == 6 and cluster_count == 6, "Network graph build failure"
 
     # check if exists ( if so, clear ) or create the test DB in influx
     if test_db_name in dbs:
diff --git a/src/service/clmcservice/graphapi/utilities.py b/src/service/clmcservice/graphapi/utilities.py
index 1459e6905c622da41bf23220cf6c6088bc429a4c..4f4dfe3e2e15cb0184ecbd24d2af3e1e0612bda5 100644
--- a/src/service/clmcservice/graphapi/utilities.py
+++ b/src/service/clmcservice/graphapi/utilities.py
@@ -148,12 +148,13 @@ def validate_graph_rtt_params(params):
     return url_params
 
 
-def find_or_create_node(graph, node_type, **properties):
+def find_or_create_node(graph, node_type, return_created=False, **properties):
     """
     This function checks if a node of the given type with the given properties exists, and if not - creates it.
 
     :param graph: the graph object
     :param node_type: the type of the node to find or create
+    :param return_created: if True the result will contain both the node and a boolean flag if the node was created now
     :param properties: the properties of the node to find or create
     :return: the found or newly created node object
     """
@@ -163,12 +164,17 @@ def find_or_create_node(graph, node_type, **properties):
     else:
         node = graph.nodes.match(node_type, name=properties['name']).first()
 
+    created = False
     if node is None:
         log.info("Creating node of type {0} with properties {1}".format(node_type, properties))
         node = Node(node_type, **properties)
         graph.create(node)
+        created = True
 
-    return node
+    if return_created:
+        return node, created
+    else:
+        return node
 
 
 def find_or_create_edge(graph, edge_type, from_node, to_node, **properties):
@@ -314,6 +320,8 @@ def build_network_graph(graph, switches, links, clusters):
     :param clusters: a collection of all clusters and the IP address of the service router that they are connected to - mapping between an IP address of a service router and a cluster identifier
     """
 
+    new_switches_count = 0
+    new_clusters_count = 0
     for link in links:
         # get the DPID of the source switch
         source = link["src-switch"]
@@ -328,18 +336,33 @@ def build_network_graph(graph, switches, links, clusters):
         # retrieve the latency for this link
         latency = link["latency"]
 
-        from_node = find_or_create_node(graph, "Switch", name=source)
-        to_node = find_or_create_node(graph, "Switch", name=destination)
+        # create or retrieve the from node
+        from_node, created = find_or_create_node(graph, "Switch", return_created=True, name=source)
+        if created:
+            new_switches_count += 1
+
+        # create or retrieve the to node
+        to_node, created = find_or_create_node(graph, "Switch", return_created=True, name=destination)
+        if created:
+            new_switches_count += 1
 
         # create the link between the two nodes
         find_or_create_edge(graph, "linkedTo", from_node, to_node, latency=latency)
 
+        # check whether the source service router connects a particular cluster
         if source in clusters:
             cluster_name = clusters[source]
-            cluster_node = find_or_create_node(graph, "Cluster", name=cluster_name)
+            cluster_node, created = find_or_create_node(graph, "Cluster", return_created=True, name=cluster_name)
+            if created:
+                new_clusters_count += 1
             find_or_create_edge(graph, "linkedTo", cluster_node, from_node, latency=0)
 
+        # check whether the destination service router connects a particular cluster
         if destination in clusters:
             cluster_name = clusters[destination]
-            cluster_node = find_or_create_node(graph, "Cluster", name=cluster_name)
+            cluster_node, created = find_or_create_node(graph, "Cluster", return_created=True, name=cluster_name)
+            if created:
+                new_clusters_count += 1
             find_or_create_edge(graph, "linkedTo", cluster_node, to_node, latency=0)
+
+    return new_switches_count, new_clusters_count
diff --git a/src/service/clmcservice/graphapi/views.py b/src/service/clmcservice/graphapi/views.py
index a208e7ae710b7a67fbe2652cfadf5f9c3763ef05..dfcb38af124786eca9bffe880c34642f35704f86 100644
--- a/src/service/clmcservice/graphapi/views.py
+++ b/src/service/clmcservice/graphapi/views.py
@@ -23,12 +23,14 @@
 """
 
 
-from clmcservice.graphapi.utilities import validate_json_queries_body, validate_graph_url_params, build_temporal_subgraph, delete_temporal_subgraph, validate_graph_rtt_params, RTT_CYPHER_QUERY_TEMPLATE
+from clmcservice.graphapi.utilities import validate_json_queries_body, validate_graph_url_params, \
+    build_network_graph, build_temporal_subgraph, delete_temporal_subgraph, validate_graph_rtt_params, RTT_CYPHER_QUERY_TEMPLATE
 from uuid import uuid4
 from influxdb import InfluxDBClient
 from py2neo import Graph
-from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound
+from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPServiceUnavailable, HTTPNotImplemented
 from pyramid.view import view_defaults, view_config
+from requests import exceptions, get
 import logging
 
 
@@ -206,3 +208,71 @@ class GraphAPI(object):
             forward_data_delay, reverse_data_delay = 0, 0
 
         return forward_latency + forward_data_delay + service_delay + reverse_latency + reverse_data_delay
+
+    @view_config(route_name='graph_network_topology', request_method='POST')
+    def build_network_topology(self):
+        """
+        An API endpoint to build/update the network topology in the neo4j graph.
+
+        :return: A JSON response with the number of switches and clusters that were built.
+        """
+
+        graph = Graph(host=self.request.registry.settings['neo4j_host'], password=self.request.registry.settings['neo4j_password'])  # connect to the neo4j graph db
+
+        sdn_controller_ip = self.request.registry.settings['sdn_controller_ip']
+
+        # retrieve all switches - if SDN controller is unavailable on the given IP address return 503 Service Unavailable
+        try:
+            url = "http://{0}:8080{1}".format(sdn_controller_ip, "/wm/core/controller/switches/json")
+            response = get(url)
+        except exceptions.ConnectionError:
+            msg = "The SDN controller is not available on IP {0} and port 8080.".format(sdn_controller_ip)
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPServiceUnavailable("The SDN controller couldn't be reached when trying to build the network topology.")
+
+        # check if the SDN controller returned the expected response
+        if response.status_code != 200:
+            msg = "The SDN controller returned a response with status code different than 200."
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPNotImplemented("The SDN controller failed to return a successful response when querying for the list of switches.")
+
+        try:
+            content = response.json()
+        except ValueError:  # response not in JSON
+            msg = "The SDN controller returned a response which couldn't be converted to JSON."
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPNotImplemented("The SDN controller failed to return a valid JSON response when querying for the list of switches.")
+
+        # map the DPID of each switch to its IP address
+        switches = {}
+        for switch in content:
+            # map the dpid to the switch IP address, the IP address is in the format '/172.168.23.54:1234'
+            switches[switch["switchDPID"]] = switch["inetAddress"][1:].split(":")[0]
+
+        # retrieve all links - if SDN controller is unavailable on the given IP address return 503 Service Unavailable
+        try:
+            url = "http://{0}:8080{1}".format(sdn_controller_ip, "/wm/topology/external-links/json")
+            response = get(url)
+        except exceptions.ConnectionError:
+            msg = "The SDN controller is not available on IP {0} and port 8080.".format(sdn_controller_ip)
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPServiceUnavailable("The SDN controller couldn't be reached when trying to build the network topology.")
+
+        # check if the SDN controller returned the expected response
+        if response.status_code != 200:
+            msg = "The SDN controller returned a response with status code different than 200."
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPNotImplemented("The SDN controller failed to return a successful response when querying for the network topology.")
+
+        try:
+            links = response.json()
+        except ValueError:  # response not in JSON
+            msg = "The SDN controller returned a response which couldn't be converted to JSON."
+            log.error("Unexpected error: {0}".format(msg))
+            raise HTTPNotImplemented("The SDN controller failed to return a valid JSON response when querying for the network topology.")
+
+        clusters = {}  # TODO this mapping should be retrieved somehow
+        # build the network graph and retrieve the number of switch nodes and cluster nodes that were created
+        switch_count, clusters_count = build_network_graph(graph, switches, links, clusters)
+
+        return {"new_switches_count": switch_count, "new_clusters_count": clusters_count}