diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
deleted file mode 100644
index ec70a1bd1d504f2770f92b4316a7b016964148c1..0000000000000000000000000000000000000000
--- a/.gitlab-ci.yml
+++ /dev/null
@@ -1,91 +0,0 @@
-include:
-  - project: piacere/private/t23-ci-setup
-    ref: main
-    file:
-      - gitlab-ci-scripts/utils.gitlab-ci.yml
-
-      # Image tag variables generation job -------------
-      # Stage: variable-generation ---------------------
-      - gitlab-ci-scripts/generate-variables.gitlab-ci.yml
-      
-      # Downstream t23-ci-setup pipeline trigger job ---
-      # Stage: integration-tests-publish-deploy --------
-      - gitlab-ci-scripts/trigger-downstream.gitlab-ci.yml
-
-variables:
-  # ------------------------
-  # Component image tag data
-  # ------------------------
-  COMPONENT_WP: wp4
-  DMC_IMAGE_NAME: dmc
-
-  # ------------------------------------------
-  # Space-separated component image abbreviation list
-  # used to generate image tags and related variables.
-  # It is also passed to the downstream integration tests,
-  # publication and deployment pipeline
-  # ------------------------------------------
-  IMAGE_NAMES: "$DMC_IMAGE_NAME"
-
-stages:
-  - variable-generation
-  - build
-  - security
-  - functional-tests
-  - integration-tests-publish-deploy
-
-# Build jobs ----------------------
-
-build-temp-dmc:
-  stage: build
-  variables:
-    TMP_IMAGE: "$TMP_IMAGE_DMC"
-    DOCKERFILE_PATH: "."
-  trigger: !reference [.trigger-build]
-  rules:
-    - if: $CI_COMMIT_BRANCH =~ /^y3/
-
-# Security job ------------------------
-
-security-trivy-dmc:
-  stage: security
-  variables:
-    TMP_IMAGE: "$TMP_IMAGE_DMC"
-  trigger: !reference [.trigger-security-trivy]
-  needs:
-    - job: build-temp-dmc
-    - job: generate-variables
-      artifacts: true
-  rules:
-    - if: $CI_COMMIT_BRANCH =~ /^y3/
-
-# functional tests job ------------------------
-
-run-functional-tests:
-  image: $DOCKER_IMAGE
-  stage: functional-tests
-  services:
-    - $DOCKER_DIND_IMAGE
-  variables:
-    TESTS_CONTAINER_NAME: functional-tester
-  before_script:
-    - !reference [.artifactory-login]
-  script:
-    # Tests assume port 8080, while the Dockerfile CMD runs the server on port 80.
-    # Thus, we need to override the command so that the server is run on port 8080.
-    - docker run --name $TESTS_CONTAINER_NAME -d -e "UVICORN_PORT=8080" $TMP_IMAGE_DMC
-    # Install everything required for the tests.
-    - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c
-        "pip install -r requirements.txt"
-    # Run the tests.
-    - docker exec -i $TESTS_CONTAINER_NAME /bin/bash -c "python -m pytest tests/test_mc_openapi.py -n auto"
-    # Stop the tests container.
-    - docker stop $TESTS_CONTAINER_NAME
-  needs:
-    - job: build-temp-dmc
-    - job: generate-variables
-      artifacts: true
-  tags:
-    - docker
-  rules:
-    - if: $CI_COMMIT_BRANCH =~ /^y3/
diff --git a/.python-version b/.python-version
new file mode 100644
index 0000000000000000000000000000000000000000..cc65e73eb882dcfc036c5cda2f27f06747bb1254
--- /dev/null
+++ b/.python-version
@@ -0,0 +1,2 @@
+piacere-dmc
+3.11.6
\ No newline at end of file
diff --git a/docs/reference_index.rst b/docs/reference_index.rst
index 78cb54ba0472be1c76f7ac94a5382137c34e2793..2d27fe271987ba543e7a96d578911e3e3fe54f89 100644
--- a/docs/reference_index.rst
+++ b/docs/reference_index.rst
@@ -15,3 +15,5 @@ For a comprehensive list of all the classes, attributes and associations support
 -----------------------------------------------
 :doc:`Reference for DOML v3.0 <reference_v3.0>`
 -----------------------------------------------
+:doc:`Reference for DOML v3.1 <reference_v3.1>`
+-----------------------------------------------
diff --git a/docs/reference_v3.1.rst b/docs/reference_v3.1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..5fcd3814cd7eb584c3ce417cee2d80ca39d517b2
--- /dev/null
+++ b/docs/reference_v3.1.rst
@@ -0,0 +1,696 @@
+DOML v3.1 Reference
+=============================
+
+
+commons
+^^^^^^^
+
+.. _v3.1_commons_BProperty:
+
+BProperty
+"""""""""
+*Inherits from* :ref:`Property <v3.1_commons_Property>`
+
+* Attributes:
+	* ``value`` [Boolean]
+
+.. _v3.1_commons_Configuration:
+
+Configuration
+"""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``deployments`` → Deployment [0..*]
+
+.. _v3.1_commons_Credentials:
+
+Credentials
+"""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+
+.. _v3.1_commons_DOMLElement:
+
+DOMLElement
+"""""""""""
+* Associations:
+	* ``annotations`` → Property [0..*]
+* Attributes:
+	* ``name`` [String]
+	* ``description`` [String]
+
+.. _v3.1_commons_DeployableElement:
+
+DeployableElement
+"""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+
+.. _v3.1_commons_Deployment:
+
+Deployment
+""""""""""
+* Associations:
+	* ``component`` → DeployableElement [1..1]
+	* ``node`` → InfrastructureElement [1..1]
+
+.. _v3.1_commons_FProperty:
+
+FProperty
+"""""""""
+*Inherits from* :ref:`Property <v3.1_commons_Property>`
+
+* Attributes:
+	* ``value`` [String]
+
+.. _v3.1_commons_IProperty:
+
+IProperty
+"""""""""
+*Inherits from* :ref:`Property <v3.1_commons_Property>`
+
+* Attributes:
+	* ``value`` [Integer]
+
+.. _v3.1_commons_KeyPair:
+
+KeyPair
+"""""""
+*Inherits from* :ref:`Credentials <v3.1_commons_Credentials>`
+
+* Attributes:
+	* ``user`` [String]
+	* ``key`` [String]
+	* ``algorithm`` [String]
+	* ``bits`` [Integer]
+
+.. _v3.1_commons_ListProperty:
+
+ListProperty
+""""""""""""
+*Inherits from* :ref:`Property <v3.1_commons_Property>`
+
+* Associations:
+	* ``values`` → Property [0..*]
+
+.. _v3.1_commons_Property:
+
+Property
+""""""""
+* Associations:
+	* ``reference`` → DOMLElement [0..1]
+* Attributes:
+	* ``key`` [String]
+
+.. _v3.1_commons_SProperty:
+
+SProperty
+"""""""""
+*Inherits from* :ref:`Property <v3.1_commons_Property>`
+
+* Attributes:
+	* ``value`` [String]
+
+.. _v3.1_commons_Source:
+
+Source
+""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``entry`` [String]
+	* ``inventory`` [String]
+	* ``backend`` [String]
+
+.. _v3.1_commons_UserPass:
+
+UserPass
+""""""""
+*Inherits from* :ref:`Credentials <v3.1_commons_Credentials>`
+
+* Attributes:
+	* ``username`` [String]
+	* ``password`` [String]
+
+application
+^^^^^^^^^^^
+
+.. _v3.1_application_ApplicationComponent:
+
+ApplicationComponent
+""""""""""""""""""""
+*Inherits from* :ref:`DeployableElement <v3.1_commons_DeployableElement>`
+
+
+.. _v3.1_application_ApplicationLayer:
+
+ApplicationLayer
+""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``components`` → ApplicationComponent [0..*]
+
+.. _v3.1_application_DBMS:
+
+DBMS
+""""
+*Inherits from* :ref:`SoftwareComponent <v3.1_application_SoftwareComponent>`
+
+
+.. _v3.1_application_SaaS:
+
+SaaS
+""""
+*Inherits from* :ref:`ApplicationComponent <v3.1_application_ApplicationComponent>`
+
+* Associations:
+	* ``exposedInterfaces`` → SoftwareInterface [0..*]
+* Attributes:
+	* ``licenseCost`` [String]
+
+.. _v3.1_application_SaaSDBMS:
+
+SaaSDBMS
+""""""""
+*Inherits from* :ref:`SaaS <v3.1_application_SaaS>`
+
+* Attributes:
+	* ``databaseName`` [String]
+	* ``engine`` [String]
+	* ``engineVersion`` [String]
+
+.. _v3.1_application_SoftwareComponent:
+
+SoftwareComponent
+"""""""""""""""""
+*Inherits from* :ref:`ApplicationComponent <v3.1_application_ApplicationComponent>`
+
+* Associations:
+	* ``exposedInterfaces`` → SoftwareInterface [0..*]
+	* ``consumedInterfaces`` → SoftwareInterface [0..*]
+	* ``src`` → Source [0..1]
+* Attributes:
+	* ``isPersistent`` [Boolean]
+	* ``licenseCost`` [String]
+
+.. _v3.1_application_SoftwareInterface:
+
+SoftwareInterface
+"""""""""""""""""
+*Inherits from* :ref:`ApplicationComponent <v3.1_application_ApplicationComponent>`
+
+* Attributes:
+	* ``endPoint`` [String]
+
+infrastructure
+^^^^^^^^^^^^^^
+
+.. _v3.1_infrastructure_AutoScalingGroup:
+
+AutoScalingGroup
+""""""""""""""""
+*Inherits from* :ref:`ComputingGroup <v3.1_infrastructure_ComputingGroup>`
+
+* Associations:
+	* ``machineDefinition`` → VirtualMachine [1..1]
+* Attributes:
+	* ``min`` [Integer]
+	* ``max`` [Integer]
+	* ``loadBalancer`` [String]
+
+.. _v3.1_infrastructure_ComputingGroup:
+
+ComputingGroup
+""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``groupedNodes`` → ComputingNode [0..*]
+
+.. _v3.1_infrastructure_ComputingNode:
+
+ComputingNode
+"""""""""""""
+*Inherits from* :ref:`Node <v3.1_infrastructure_Node>`
+
+* Associations:
+	* ``location`` → Location [0..1]
+	* ``credentials`` → Credentials [0..1]
+	* ``group`` → ComputingGroup [0..1]
+	* ``nodeSpecificMonitoring`` → MonitoringRule [0..1]
+* Attributes:
+	* ``architecture`` [String]
+	* ``os`` [String]
+	* ``memory_mb`` [Integer]
+	* ``memory_kb`` [Integer]
+	* ``storage`` [Integer]
+	* ``cpu_count`` [Integer]
+	* ``cost`` [Integer]
+	* ``disabledMonitorings`` [String]
+
+.. _v3.1_infrastructure_ComputingNodeGenerator:
+
+ComputingNodeGenerator
+""""""""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``uri`` [String]
+	* ``kind`` [GeneratorKind]
+
+.. _v3.1_infrastructure_Container:
+
+Container
+"""""""""
+*Inherits from* :ref:`ComputingNode <v3.1_infrastructure_ComputingNode>`
+
+* Associations:
+	* ``generatedFrom`` → ContainerImage [0..1]
+	* ``hostConfigs`` → ContainerHostConfig [0..*]
+	* ``networks`` → ContainerNetwork [0..*]
+	* ``volumes`` → ContainerVolume [0..*]
+	* ``dependsOn`` → Container [0..*]
+
+.. _v3.1_infrastructure_ContainerConfig:
+
+ContainerConfig
+"""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``iface`` → NetworkInterface [0..1]
+* Attributes:
+	* ``container_port`` [Integer]
+	* ``vm_port`` [Integer]
+
+.. _v3.1_infrastructure_ContainerGroup:
+
+ContainerGroup
+""""""""""""""
+*Inherits from* :ref:`ComputingGroup <v3.1_infrastructure_ComputingGroup>`
+
+* Associations:
+	* ``services`` → Container [1..*]
+	* ``networks`` → ContainerNetwork [0..*]
+	* ``volumes`` → ContainerVolume [0..*]
+
+.. _v3.1_infrastructure_ContainerHostConfig:
+
+ContainerHostConfig
+"""""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``environment_variables`` → SProperty [0..*]
+	* ``host`` → ComputingNode [0..1]
+	* ``configurations`` → ContainerConfig [0..*]
+
+.. _v3.1_infrastructure_ContainerImage:
+
+ContainerImage
+""""""""""""""
+*Inherits from* :ref:`ComputingNodeGenerator <v3.1_infrastructure_ComputingNodeGenerator>`
+
+* Associations:
+	* ``generatedContainers`` → Container [0..*]
+
+.. _v3.1_infrastructure_ContainerNetwork:
+
+ContainerNetwork
+""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``containerNetworkName`` [String]
+
+.. _v3.1_infrastructure_ContainerVolume:
+
+ContainerVolume
+"""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``containerVolumeName`` [String]
+	* ``path`` [String]
+
+.. _v3.1_infrastructure_ExecutionEnvironment:
+
+ExecutionEnvironment
+""""""""""""""""""""
+*Inherits from* :ref:`InfrastructureElement <v3.1_infrastructure_InfrastructureElement>`
+
+* Associations:
+	* ``location`` → Location [0..1]
+	* ``network`` → Network [0..1]
+	* ``securityGroups`` → SecurityGroup [0..*]
+* Attributes:
+	* ``size`` [Integer]
+	* ``maxSize`` [Integer]
+
+.. _v3.1_infrastructure_ExtInfrastructureElement:
+
+ExtInfrastructureElement
+""""""""""""""""""""""""
+*Inherits from* :ref:`InfrastructureElement <v3.1_infrastructure_InfrastructureElement>`
+
+
+.. _v3.1_infrastructure_FunctionAsAService:
+
+FunctionAsAService
+""""""""""""""""""
+*Inherits from* :ref:`InfrastructureElement <v3.1_infrastructure_InfrastructureElement>`
+
+* Attributes:
+	* ``cost`` [Integer]
+
+.. _v3.1_infrastructure_InfrastructureElement:
+
+InfrastructureElement
+"""""""""""""""""""""
+*Inherits from* :ref:`DeployableElement <v3.1_commons_DeployableElement>`
+
+
+.. _v3.1_infrastructure_InfrastructureLayer:
+
+InfrastructureLayer
+"""""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``nodes`` → ComputingNode [0..*]
+	* ``generators`` → ComputingNodeGenerator [0..*]
+	* ``storages`` → Storage [0..*]
+	* ``faas`` → FunctionAsAService [0..*]
+	* ``credentials`` → Credentials [0..*]
+	* ``groups`` → ComputingGroup [0..*]
+	* ``securityGroups`` → SecurityGroup [0..*]
+	* ``networks`` → Network [0..*]
+	* ``rules`` → MonitoringRule [0..*]
+	* ``executionEnvironments`` → ExecutionEnvironment [0..*]
+
+.. _v3.1_infrastructure_InternetGateway:
+
+InternetGateway
+"""""""""""""""
+*Inherits from* :ref:`Node <v3.1_infrastructure_Node>`
+
+* Attributes:
+	* ``address`` [String]
+
+.. _v3.1_infrastructure_Location:
+
+Location
+""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``region`` [String]
+	* ``zone`` [String]
+
+.. _v3.1_infrastructure_MonitoringRule:
+
+MonitoringRule
+""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``condition`` [String]
+	* ``strategy`` [String]
+	* ``strategyConfigurationString`` [String]
+
+.. _v3.1_infrastructure_Network:
+
+Network
+"""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``connectedIfaces`` → NetworkInterface [0..*]
+	* ``gateways`` → InternetGateway [0..*]
+	* ``subnets`` → Subnet [0..*]
+* Attributes:
+	* ``protocol`` [String]
+	* ``cidr`` [Integer]
+
+.. _v3.1_infrastructure_NetworkInterface:
+
+NetworkInterface
+""""""""""""""""
+*Inherits from* :ref:`InfrastructureElement <v3.1_infrastructure_InfrastructureElement>`
+
+* Associations:
+	* ``belongsTo`` → Network [0..1]
+	* ``associated`` → SecurityGroup [0..1]
+* Attributes:
+	* ``endPoint`` [Integer]
+	* ``speed`` [String]
+
+.. _v3.1_infrastructure_Node:
+
+Node
+""""
+*Inherits from* :ref:`InfrastructureElement <v3.1_infrastructure_InfrastructureElement>`
+
+* Associations:
+	* ``ifaces`` → NetworkInterface [0..*]
+
+.. _v3.1_infrastructure_PhysicalComputingNode:
+
+PhysicalComputingNode
+"""""""""""""""""""""
+*Inherits from* :ref:`ComputingNode <v3.1_infrastructure_ComputingNode>`
+
+* Associations:
+	* ``configInterface`` → NetworkInterface [0..1]
+
+.. _v3.1_infrastructure_Rule:
+
+Rule
+""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Attributes:
+	* ``kind`` [String]
+	* ``protocol`` [String]
+	* ``fromPort`` [Integer]
+	* ``toPort`` [Integer]
+	* ``cidr`` [String]
+
+.. _v3.1_infrastructure_SecurityGroup:
+
+SecurityGroup
+"""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``rules`` → Rule [0..*]
+	* ``ifaces`` → NetworkInterface [0..*]
+
+.. _v3.1_infrastructure_Storage:
+
+Storage
+"""""""
+*Inherits from* :ref:`Node <v3.1_infrastructure_Node>`
+
+* Attributes:
+	* ``label`` [String]
+	* ``size_gb`` [Integer]
+	* ``cost`` [Integer]
+
+.. _v3.1_infrastructure_Subnet:
+
+Subnet
+""""""
+*Inherits from* :ref:`Network <v3.1_infrastructure_Network>`
+
+* Associations:
+	* ``connectedTo`` → Network [0..*]
+
+.. _v3.1_infrastructure_Swarm:
+
+Swarm
+"""""
+*Inherits from* :ref:`ComputingGroup <v3.1_infrastructure_ComputingGroup>`
+
+* Associations:
+	* ``roles`` → SwarmRole [0..*]
+
+.. _v3.1_infrastructure_SwarmRole:
+
+SwarmRole
+"""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``nodes`` → ComputingNode [0..*]
+* Attributes:
+	* ``kind`` [String]
+
+.. _v3.1_infrastructure_VMImage:
+
+VMImage
+"""""""
+*Inherits from* :ref:`ComputingNodeGenerator <v3.1_infrastructure_ComputingNodeGenerator>`
+
+* Associations:
+	* ``generatedVMs`` → VirtualMachine [0..*]
+
+.. _v3.1_infrastructure_VirtualMachine:
+
+VirtualMachine
+""""""""""""""
+*Inherits from* :ref:`ComputingNode <v3.1_infrastructure_ComputingNode>`
+
+* Associations:
+	* ``generatedFrom`` → VMImage [0..1]
+	* ``configInterface`` → NetworkInterface [0..1]
+* Attributes:
+	* ``sizeDescription`` [String]
+
+concrete
+^^^^^^^^
+
+.. _v3.1_concrete_AutoScalingGroup:
+
+AutoScalingGroup
+""""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → AutoScalingGroup [0..1]
+* Attributes:
+	* ``vm_type`` [String]
+
+.. _v3.1_concrete_ConcreteElement:
+
+ConcreteElement
+"""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``refs`` → ConcreteElement [0..*]
+* Attributes:
+	* ``resourceName`` [String]
+	* ``configurationScript`` [String]
+	* ``preexisting`` [Boolean]
+
+.. _v3.1_concrete_ConcreteInfrastructure:
+
+ConcreteInfrastructure
+""""""""""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``providers`` → RuntimeProvider [0..*]
+
+.. _v3.1_concrete_ContainerImage:
+
+ContainerImage
+""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → ContainerImage [0..1]
+
+.. _v3.1_concrete_ExecutionEnvironment:
+
+ExecutionEnvironment
+""""""""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → ExecutionEnvironment [0..1]
+* Attributes:
+	* ``instance_type`` [String]
+	* ``storage_type`` [String]
+
+.. _v3.1_concrete_FunctionAsAService:
+
+FunctionAsAService
+""""""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → FunctionAsAService [0..1]
+
+.. _v3.1_concrete_GenericResource:
+
+GenericResource
+"""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Attributes:
+	* ``type`` [String]
+
+.. _v3.1_concrete_Network:
+
+Network
+"""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``subnets`` → Subnet [0..*]
+	* ``maps`` → Network [0..1]
+* Attributes:
+	* ``protocol`` [String]
+	* ``addressRange`` [String]
+
+.. _v3.1_concrete_RuntimeProvider:
+
+RuntimeProvider
+"""""""""""""""
+*Inherits from* :ref:`DOMLElement <v3.1_commons_DOMLElement>`
+
+* Associations:
+	* ``resources`` → GenericResource [0..*]
+	* ``vms`` → VirtualMachine [0..*]
+	* ``executionEnvironments`` → ExecutionEnvironment [0..*]
+	* ``vmImages`` → VMImage [0..*]
+	* ``containerImages`` → ContainerImage [0..*]
+	* ``networks`` → Network [0..*]
+	* ``storages`` → Storage [0..*]
+	* ``faas`` → FunctionAsAService [0..*]
+	* ``autoScalingGroups`` → AutoScalingGroup [0..*]
+
+.. _v3.1_concrete_Storage:
+
+Storage
+"""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → Storage [0..1]
+
+.. _v3.1_concrete_Subnet:
+
+Subnet
+""""""
+*Inherits from* :ref:`Network <v3.1_concrete_Network>`
+
+
+.. _v3.1_concrete_VMImage:
+
+VMImage
+"""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → VMImage [0..1]
+* Attributes:
+	* ``image_name`` [String]
+
+.. _v3.1_concrete_VirtualMachine:
+
+VirtualMachine
+""""""""""""""
+*Inherits from* :ref:`ConcreteElement <v3.1_concrete_ConcreteElement>`
+
+* Associations:
+	* ``maps`` → VirtualMachine [0..1]
+* Attributes:
+	* ``vm_type`` [String]
+
+
+
diff --git a/mc_openapi/__init__.py b/mc_openapi/__init__.py
index 41566c9ed937ae6860dbedce2f23f01db5039b8c..dc0a25b72c93dd2fc3e20ee0638423e5037c330a 100644
--- a/mc_openapi/__init__.py
+++ b/mc_openapi/__init__.py
@@ -1 +1 @@
-__version__ = '2.6.2'
+__version__ = '3.1.3'
diff --git a/mc_openapi/__main__.py b/mc_openapi/__main__.py
index 3c7a2e811cd96c2d9ea11229ae6e7830ffe55787..7b91937b4b38b5b12bc986b33eae6790d7e13528 100644
--- a/mc_openapi/__main__.py
+++ b/mc_openapi/__main__.py
@@ -3,6 +3,7 @@ import argparse
 import logging
 from logging.config import dictConfig
 import re
+import traceback
 
 from tabulate import tabulate
 import uvicorn
@@ -83,42 +84,56 @@ else:
         # Read DOML file from path
         doml_xmi = xmif.read()
 
-    # Read DOMLR from path
-    domlr_src = None
-    if domlr_path:
-        with open(domlr_path, "r") as domlr_file:
-        # Read the user requirements written in DSL
-            domlr_src = domlr_file.read()
-
-    # Config the model checker
-    dmc = init_model(doml_xmi, doml_ver)
-
-    ####### END OF INIT STEP #######
-    if not args.synth: # Verify Model/CSP Compatibility
-
-        # Check CSP Compatibility
-        if args.csp:
-            csp = verify_csp_compatibility(dmc)
-            print_csp_results(csp)
-        else:
-            res = verify_model(dmc, domlr_src, args.threads, args.consistency, args.skip_builtin)
-
-            print("[RESULT]")
-            if res['result'] == MCResult.sat.name:
-                print(res['description'])
+    try:
+        # Read DOMLR from path
+        domlr_src = None
+        if domlr_path:
+            with open(domlr_path, "r") as domlr_file:
+            # Read the user requirements written in DSL
+                domlr_src = domlr_file.read()
+
+        # Config the model checker
+        dmc = init_model(doml_xmi, doml_ver)
+        ####### END OF INIT STEP #######
+        if not args.synth: # Verify Model/CSP Compatibility
+
+            # Check CSP Compatibility
+            if args.csp:
+                csp = verify_csp_compatibility(dmc)
+                print_csp_results(csp)
             else:
-                print(res['result'])
-                print("[ERRORS]")
-                print("\033[91m{}\033[00m".format(res['description']))
-            
-            csp_res = res.get('csp')
-            if csp_res:
-                print("[CSP COMPATIBILITY RESULTS]")
-                print_csp_results(csp_res)
-
-
-
-    else: # Synthesis
-        synthesize_model(dmc, domlr_src, args.tries)
-        # TODO: Do something with the results
+                
+                    res = verify_model(dmc, domlr_src, args.threads, args.consistency, args.skip_builtin)
+
+                    print("[RESULT]")
+                    if res['result'] == MCResult.sat.name:
+                        print(res['description'])
+
+                        print("[STATS]")
+                        for result in res['all_reqs']:
+                            print(f"\t{result['id']} - {result['time']} - {result['result']}")
+                    else:
+                        print(res['result'])
+                        print("[ERRORS]")
+                        print("\033[91m{}\033[00m".format(res['description']))
+
+                        print("[STATS]")
+                        for result in res['all_reqs']:
+                            print(f"\t{result['id']} - {result['time']} - {result['result']}")
+
+                    csp_res = res.get('csp')
+                    if csp_res:
+                        print("[CSP COMPATIBILITY RESULTS]")
+                        print_csp_results(csp_res)
+        else: # Synthesis
+            synthesize_model(dmc, domlr_src, args.tries)
+            # TODO: Do something with the results
         
+    except Exception as e:
+        MSG_ERR_GENERIC = "An unknown error has occurred!\nTry with '-t 1' to get more detailed logs!\n\n"
+        err_msg = (e.message 
+                    if hasattr(e, 'message') 
+                    else MSG_ERR_GENERIC + traceback.format_exc())
+        print(f"\033[91m[ERROR]\n{err_msg}\033[00m")
+
+       
\ No newline at end of file
diff --git a/mc_openapi/api.py b/mc_openapi/api.py
index f08700a05527b6107179eec9964971e48fe28b77..435f36a480fa4ade358d4988ba84bb2f6e328e5f 100644
--- a/mc_openapi/api.py
+++ b/mc_openapi/api.py
@@ -1,5 +1,7 @@
 import logging
+from logging.config import dictConfig
 import os
+import sys
 import traceback
 from importlib.resources import files
 
@@ -8,6 +10,7 @@ from fastapi.responses import HTMLResponse, JSONResponse
 from fastapi.staticfiles import StaticFiles
 from fastapi.templating import Jinja2Templates
 from fastapi.encoders import jsonable_encoder
+from fastapi.logger import logger
 
 import mc_openapi.assets as ASSETS
 from mc_openapi.doml_mc import (init_model, verify_csp_compatibility,
@@ -15,12 +18,16 @@ from mc_openapi.doml_mc import (init_model, verify_csp_compatibility,
 from mc_openapi.doml_mc.exceptions import *
 from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion
 from mc_openapi.doml_mc.mc import ModelChecker
+import time
 
 assets = files(ASSETS)
 static_path = assets / "static"
 templates_path = assets / "templates"
 app = FastAPI()
 
+print(">>> FastAPI+Uvicorn is incredibly asinine when it comes to logs, so lines prefixed with '>>>' are actually print(...)")
+print(">>> API starting up...")
+
 app.mount("/static", StaticFiles(directory=static_path), name="static")
 
 templates = Jinja2Templates(directory=templates_path)
@@ -32,26 +39,42 @@ async def root(request: Request):
 def handleDOMLX(doml_xmi: bytes, callback) -> dict:
     doml_version_str: str = None
     doml_version: DOMLVersion = None
+    start_time = time.time()
+    
+    print(">>> Received DOMLX. Beginning validation...")
+
     try:
         # First try to infer DOML version from ENV, then query params
         doml_version_str = os.environ.get("DOML_VERSION")
         
         if doml_version_str:
             doml_version = DOMLVersion.get(doml_version_str)
-            logging.info(f"Forcing DOML {doml_version.value}")
+            print(f">>> Forcing DOML {doml_version.value}")
 
         dmc = init_model(doml_xmi, doml_version)
 
         res = callback(dmc)
 
-        return res
+        elapsed_time_in_seconds = f"{time.time() - start_time:.4f}"
+
+        print(f">>> Validation complete. It took {elapsed_time_in_seconds}s.")
+        res['elapsed_time'] = elapsed_time_in_seconds
 
+        return res
+    except KeyError as e:
+        ERR_MSG = f"Error: Key '{e.args[0]}' not found.\nVery likely, in the Model Checker requirements, the relationship '{e.args[0]}' is unknown.\nPerhaps this was parsed with the wrong DOML version, otherwise the DOML version you're using is currently unsupported."
+        logging.exception(e)
+        return {
+            "type": "error",
+            "message": ERR_MSG,
+            "debug_message": traceback.format_exc()
+        }
     except (RuntimeError, Exception) as e:
         ERR_MSG = "An error has occurred.\nIt could be an error within your DOML file.\nIf it persist, try specifying DOML version manually."
         logging.exception(e)
         return {
             "type": "error",
-            "message": e.message or ERR_MSG,
+            "message": e.message if hasattr(e, 'message') else ERR_MSG,
             "debug_message": traceback.format_exc()
         }
 
diff --git a/mc_openapi/assets/csp/arch.yml b/mc_openapi/assets/csp/arch.yml
index 41ae12f44a1c13755477aa1dddc50acf36f64c57..bfdc5f2611d9b7d1676fad1d337a398df10c38a8 100644
--- a/mc_openapi/assets/csp/arch.yml
+++ b/mc_openapi/assets/csp/arch.yml
@@ -12,5 +12,5 @@ azure:
   - x86
   - ARM
 
-bad_csp:
-  - PowerPC
+# bad_csp:
+#   - PowerPC
diff --git a/mc_openapi/assets/csp/keypair.yml b/mc_openapi/assets/csp/keypair.yml
index 151293ed41ddff6e51f5cee3fa8c9d2b698d868c..b9083df88b50130dc3bd1362223cb0e50f4db2a5 100644
--- a/mc_openapi/assets/csp/keypair.yml
+++ b/mc_openapi/assets/csp/keypair.yml
@@ -7,10 +7,18 @@ aws:
 
 azure:
   - RSA
-
+  - RSA1_5
+  - RSA-OAEP
+  - RSA-OAEP-256
+  - EC
+  - P-256
+  - P-256K
+  - P-384
+  - P-521
 gcp: 
   - Elliptic Curve
   - RSA
+  - ECDSA
 
-bad_csp:
-  - OLD_ALGO
+# bad_csp:
+#   - OLD_ALGO
diff --git a/mc_openapi/assets/csp/minimum_setup.yml b/mc_openapi/assets/csp/minimum_setup.yml
index 64e591c690ab151807cb54f5301241363159b632..05448f3eb52dace7f685f17d2a57cc53a80dc360 100644
--- a/mc_openapi/assets/csp/minimum_setup.yml
+++ b/mc_openapi/assets/csp/minimum_setup.yml
@@ -1,15 +1,16 @@
 aws:
   - infrastructure_ComputingNode::os # AMI
   # - an Instance Type
-  - [infrastructure_ComputingNode::ifaces, infrastructure_NetworkInterface::associated] # NetworkInterface
+  # - [infrastructure_Node::ifaces, infrastructure_NetworkInterface::associated] # NetworkInterface
+  - [infrastructure_Node::ifaces, infrastructure_NetworkInterface::belongsTo] # NetworkInterface
   - infrastructure_ComputingNode::credentials # KeyPair
 
 azure:
   - infrastructure_ComputingNode::os # OS Image
-  - [infrastructure_ComputingNode::ifaces, infrastructure_NetworkInterface::belongsTo] # NetworkInterface
+  - [infrastructure_Node::ifaces, infrastructure_NetworkInterface::belongsTo] # NetworkInterface
   - infrastructure_ComputingNode::storage # Storage/VMSize
 
 gcp:
-  - infrastructure_ComputingNode::location
+  # - infrastructure_ComputingNode::location
   - infrastructure_ComputingNode::os # OS Image
   - infrastructure_ComputingNode::architecture
\ No newline at end of file
diff --git a/mc_openapi/assets/metamodels/doml_meta_v3.1.yaml b/mc_openapi/assets/metamodels/doml_meta_v3.1.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..c2dd82b4935821cb9d105ca2a249726a4bcc4b3f
--- /dev/null
+++ b/mc_openapi/assets/metamodels/doml_meta_v3.1.yaml
@@ -0,0 +1,677 @@
+commons:
+    DOMLElement:
+        attributes:
+            name:
+                type: String
+                multiplicity: "0..1"
+            description:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            annotations:
+                class: commons_Property
+                multiplicity: "0..*"
+    Property:
+        attributes:
+            key:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            reference:
+                class: commons_DOMLElement
+                multiplicity: "0..1"
+    ListProperty:
+        superclass: commons_Property
+        associations:
+            values:
+                class: commons_Property
+                multiplicity: "0..*"
+    IProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Integer
+                multiplicity: "0..1"
+    SProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    FProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: String
+                multiplicity: "0..1"
+    BProperty:
+        superclass: commons_Property
+        attributes:
+            value:
+                type: Boolean
+                multiplicity: "0..1"
+    Configuration:
+        superclass: commons_DOMLElement
+        associations:
+            deployments:
+                class: commons_Deployment
+                multiplicity: "0..*"
+    Credentials:
+        abstract: true
+        superclass: commons_DOMLElement
+    DeployableElement:
+        abstract: true
+        superclass: commons_DOMLElement # It's not present in the ECore, but without it breaks.
+    Deployment:
+        associations:
+            component:
+                class: commons_DeployableElement
+                multiplicity: "1"
+            node:
+                class: infrastructure_InfrastructureElement
+                multiplicity: "1"
+    KeyPair:
+        superclass: commons_Credentials
+        attributes:
+            user:
+                type: String
+                multiplicity: "0..1"
+            key:
+                type: String
+                multiplicity: "0..1"
+            algorithm:
+                type: String
+                multiplicity: "0..1"
+            bits:
+                type: Integer
+                multiplicity: "0..1"
+    UserPass:
+        superclass: commons_Credentials
+        attributes:
+            username:
+                type: String
+                multiplicity: "0..1"
+            password:
+                type: String
+                multiplicity: "0..1"
+    Source:
+        superclass: commons_DOMLElement
+        attributes:
+            entry:
+                type: String
+                multiplicity: "0..1"
+            inventory:
+                type: String
+                multiplicity: "0..1"
+            backend:
+                type: String
+                multiplicity: "0..1"
+application:
+    ApplicationLayer:
+        superclass: commons_DOMLElement
+        associations:
+            components:
+                class: application_ApplicationComponent
+                multiplicity: "0..*"
+    ApplicationComponent:
+        superclass: commons_DeployableElement # and commons_DOMLElement too, but that's definitely wrong; keeping discarding DOMLElement since DeplElem inherits it.
+    SoftwareComponent:
+        superclass: application_ApplicationComponent
+        attributes:
+            isPersistent:
+                type: Boolean
+                multiplicity: "1"
+                default: false
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            consumedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+            src:
+                class: commons_Source
+                multiplicity: "0..1"
+    SaaS:
+        superclass: application_ApplicationComponent
+        attributes:
+            licenseCost:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            exposedInterfaces:
+                class: application_SoftwareInterface
+                multiplicity: "0..*"
+    SoftwareInterface:
+        superclass: application_ApplicationComponent
+        attributes:
+            endPoint:
+                type: String
+                multiplicity: "0..1"
+    DBMS:
+        superclass: application_SoftwareComponent
+    SaaSDBMS:
+        superclass: application_SaaS
+        attributes:
+            databaseName:
+                type: String
+                multiplicity: "0..1"
+            engine:
+                type: String
+                multiplicity: "0..1"
+            engineVersion:
+                type: String
+                multiplicity: "0..1"
+infrastructure:
+    InfrastructureLayer:
+        superclass: commons_DOMLElement
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+            generators:
+                class: infrastructure_ComputingNodeGenerator
+                multiplicity: "0..*"
+            storages:
+                class: infrastructure_Storage
+                multiplicity: "0..*"
+            faas:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..*"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..*"
+            groups:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..*"
+            securityGroups:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..*"
+            networks:
+                class: infrastructure_Network
+                multiplicity: "0..*"
+            rules:
+                class: infrastructure_MonitoringRule
+                multiplicity: "0..*"
+            executionEnvironments:
+                class: infrastructure_ExecutionEnvironment
+                multiplicity: "0..*"
+    MonitoringRule:
+        superclass: commons_DOMLElement
+        attributes:
+            condition:
+                type: String 
+                multiplicity: "1"
+            strategy:
+                type: String 
+                multiplicity: "1"
+            strategyConfigurationString:
+                type: String 
+                multiplicity: "0..1"
+    InfrastructureElement:
+        superclass: commons_DeployableElement
+    Node:
+        superclass: infrastructure_InfrastructureElement
+        associations:
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+    ComputingNode:
+        superclass: infrastructure_Node
+        attributes:
+            architecture: 
+                type: String 
+                multiplicity: "0..1"
+            os: 
+                type: String 
+                multiplicity: "0..1"
+            memory_mb:
+                type: Integer 
+                multiplicity: "0..1"
+            memory_kb:  # Missing in official Ecore, added by parser
+                type: Integer 
+                multiplicity: "0..1"
+            storage: 
+                type: Integer 
+                multiplicity: "0..1"
+            cpu_count: 
+                type: Integer 
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+            disabledMonitorings:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+            credentials:
+                class: commons_Credentials
+                multiplicity: "0..1"
+            group:
+                class: infrastructure_ComputingGroup
+                multiplicity: "0..1"
+                inverse_of: infrastructure_ComputingGroup::groupedNodes
+            nodeSpecificMonitoring:
+                class: infrastructure_MonitoringRule
+                multiplicity: "0..1"
+    PhysicalComputingNode:
+        superclass: infrastructure_ComputingNode
+        associations:
+            configInterface:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    VirtualMachine:
+        superclass: infrastructure_ComputingNode
+        attributes:
+            sizeDescription:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            generatedFrom:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+            configInterface:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    Location:
+        superclass: commons_DOMLElement
+        attributes:
+            region:
+                type: String
+                multiplicity: "0..1"
+            zone:
+                type: String
+                multiplicity: "0..1"
+    ContainerConfig:
+        superclass: commons_DOMLElement
+        attributes:
+            container_port:
+                type: Integer
+                multiplicity: "0..1"
+            vm_port:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            iface:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..1"
+    ContainerHostConfig:
+        superclass: commons_DOMLElement
+        associations:
+            environment_variables:
+                class: commons_SProperty
+                multiplicity: "0..*"
+            host:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..1"
+            configurations:
+                class: infrastructure_ContainerConfig
+                multiplicity: "0..*"
+    Container:
+        superclass: infrastructure_ComputingNode
+        associations:
+            generatedFrom:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+            hostConfigs:
+                class: infrastructure_ContainerHostConfig
+                multiplicity: "0..*"
+            networks:
+                class: infrastructure_ContainerNetwork
+                multiplicity: "0..*"
+            volumes:
+                class: infrastructure_ContainerVolume
+                multiplicity: "0..*"
+            dependsOn:
+                class: infrastructure_Container
+                multiplicity: "0..*"
+    ContainerGroup:
+        superclass: infrastructure_ComputingGroup
+        associations:
+            services:
+                class: infrastructure_Container
+                multiplicity: "1..*"
+            networks:
+                class: infrastructure_ContainerNetwork
+                multiplicity: "0..*"
+            volumes:
+                class: infrastructure_ContainerVolume
+                multiplicity: "0..*"
+    ContainerNetwork:
+        superclass: commons_DOMLElement
+        attributes:
+            containerNetworkName:
+                type: String
+                multiplicity: "0..1"
+    ContainerVolume:
+        superclass: commons_DOMLElement
+        attributes:
+            containerVolumeName:
+                type: String
+                multiplicity: "0..1"
+            path:
+                type: String
+                multiplicity: "0..1"
+    ExecutionEnvironment:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            size:
+                type: Integer
+                multiplicity: "0..1"
+            maxSize:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            location:
+                class: infrastructure_Location
+                multiplicity: "0..1"
+            network:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+            securityGroups:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..*"
+    ComputingNodeGenerator:
+        superclass: commons_DOMLElement
+        attributes:
+            uri:
+                type: String
+                multiplicity: "0..1"
+            kind:
+                type: GeneratorKind  # enum { SCRIPT, IMAGE }
+    VMImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedVMs:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..*"
+                inverse_of: infrastructure_VirtualMachine::generatedFrom
+    ContainerImage:
+        superclass: infrastructure_ComputingNodeGenerator
+        associations:
+            generatedContainers:
+                class: infrastructure_Container
+                multiplicity: "0..*"
+                inverse_of: infrastructure_Container::generatedFrom
+    AutoScalingGroup:
+        superclass: infrastructure_ComputingGroup
+        attributes:
+            min:
+                type: Integer
+                multiplicity: "0..1"
+            max:
+                type: Integer
+                multiplicity: "0..1"
+            loadBalancer:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            machineDefinition:
+                class: infrastructure_VirtualMachine
+                multiplicity: "1"
+    Storage:
+        superclass: infrastructure_Node
+        attributes:
+            label:
+                type: String
+                multiplicity: "0..1"
+            size_gb:
+                type: Integer  # in GBs
+                multiplicity: "0..1"
+            cost: 
+                type: Integer  # in cents 
+                multiplicity: "0..1"
+    FunctionAsAService:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            cost:
+                type: Integer  # in cents
+                multiplicity: "0..1"
+    Network:
+        superclass: commons_DOMLElement
+        attributes:
+            protocol:
+                type: String
+                multiplicity: "0..1"
+                default: "TCP/IP"
+            cidr:
+                type: Integer
+                multiplicity: "0..1"
+        associations:
+            connectedIfaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::belongsTo
+            gateways:
+                class: infrastructure_InternetGateway
+                multiplicity: "0..*"
+            subnets:
+                class: infrastructure_Subnet
+                multiplicity: "0..*"
+    Subnet:
+        superclass: infrastructure_Network
+        associations:
+            connectedTo:
+                class: infrastructure_Network
+                multiplicity: "0..*"
+    NetworkInterface:
+        superclass: infrastructure_InfrastructureElement
+        attributes:
+            endPoint:
+                type: Integer
+                multiplicity: "0..1"
+            speed:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            belongsTo:
+                class: infrastructure_Network
+                multiplicity: "0..1" # This should be "1", but it would break InternetGateway
+            associated:
+                class: infrastructure_SecurityGroup
+                multiplicity: "0..1"
+    InternetGateway:
+        superclass: infrastructure_Node
+        attributes:
+            address:
+                type: String
+                multiplicity: "1"
+    ComputingGroup:
+        superclass: commons_DOMLElement
+        associations:
+            groupedNodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+                inverse_of: infrastructure_ComputingNode::group
+    SecurityGroup:
+        superclass: commons_DOMLElement
+        associations:
+            rules:
+                class: infrastructure_Rule
+                multiplicity: "0..*"
+            ifaces:
+                class: infrastructure_NetworkInterface
+                multiplicity: "0..*"
+                inverse_of: infrastructure_NetworkInterface::associated
+    Rule:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+            protocol:
+                type: String
+                multiplicity: "1"
+            fromPort:
+                type: Integer
+                multiplicity: "1"
+            toPort:
+                type: Integer
+                multiplicity: "1"
+            cidr:
+                type: String
+                multiplicity: "0..*"
+    SwarmRole:
+        superclass: commons_DOMLElement
+        attributes:
+            kind:
+                type: String
+                multiplicity: "1"
+        associations:
+            nodes:
+                class: infrastructure_ComputingNode
+                multiplicity: "0..*"
+    Swarm:
+        superclass: infrastructure_ComputingGroup
+        associations:
+            roles:
+                class: infrastructure_SwarmRole
+                multiplicity: "0..*"
+    ExtInfrastructureElement:
+        superclass: infrastructure_InfrastructureElement
+
+concrete:
+    ConcreteInfrastructure:
+        superclass: commons_DOMLElement
+        associations:
+            providers:
+                class: concrete_RuntimeProvider
+                multiplicity: "0..*"
+    ConcreteElement:
+        superclass: commons_DOMLElement
+        associations:
+            refs:
+                class: concrete_ConcreteElement
+                multiplicity: "0..*"
+        attributes:
+            resourceName:
+                type: String
+                multiplicity: "0..1"
+            configurationScript:
+                type: String
+                multiplicity: "0..1"
+            preexisting:
+                multiplicity: "1"
+                type: Boolean
+                default: false
+    RuntimeProvider:
+        superclass: commons_DOMLElement
+        associations:
+            resources:
+                class: concrete_GenericResource
+                multiplicity: "0..*"
+            vms:
+                class: concrete_VirtualMachine
+                multiplicity: "0..*"
+            executionEnvironments:
+                class: concrete_ExecutionEnvironment
+                multiplicity: "0..*"
+            vmImages:
+                class: concrete_VMImage
+                multiplicity: "0..*"
+            containerImages:
+                class: concrete_ContainerImage
+                multiplicity: "0..*"
+            networks:
+                class: concrete_Network
+                multiplicity: "0..*"
+            storages:
+                class: concrete_Storage
+                multiplicity: "0..*"
+            faas:
+                class: concrete_FunctionAsAService
+                multiplicity: "0..*"
+            autoScalingGroups:
+                class: concrete_AutoScalingGroup
+                multiplicity: "0..*"
+    VirtualMachine:
+        superclass: concrete_ConcreteElement
+        attributes:
+            vm_type:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            maps:
+                class: infrastructure_VirtualMachine
+                multiplicity: "0..1"
+    VMImage:
+        superclass: concrete_ConcreteElement
+        attributes:
+            image_name:
+                type: String
+                multiplicity: "1"
+        associations:
+            maps:
+                class: infrastructure_VMImage
+                multiplicity: "0..1"
+    ContainerImage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_ContainerImage
+                multiplicity: "0..1"
+    ExecutionEnvironment:
+        superclass: concrete_ConcreteElement
+        attributes:
+            instance_type:
+                type: String
+                multiplicity: "0..1"
+            storage_type:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            maps:
+                class: infrastructure_ExecutionEnvironment
+                multiplicity: "0..1"
+    Network:
+        superclass: concrete_ConcreteElement
+        attributes:
+            protocol:
+                type: String
+                multiplicity: "0..1"
+            addressRange:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            subnets:
+                class: concrete_Subnet
+                multiplicity: "0..*"
+            maps:
+                class: infrastructure_Network
+                multiplicity: "0..1"
+    Subnet:
+        superclass: concrete_Network
+    Storage:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_Storage
+                multiplicity: "0..1"
+    FunctionAsAService:
+        superclass: concrete_ConcreteElement
+        associations:
+            maps:
+                class: infrastructure_FunctionAsAService
+                multiplicity: "0..1"
+    AutoScalingGroup:
+        superclass: concrete_ConcreteElement
+        attributes:
+            vm_type:
+                type: String
+                multiplicity: "0..1"
+        associations:
+            maps:
+                class: infrastructure_AutoScalingGroup
+                multiplicity: "0..1"
+    GenericResource:
+        superclass: concrete_ConcreteElement
+        attributes:
+            type:
+                type: "String"
+                multiplicity: "1"
diff --git a/mc_openapi/assets/metamodels/doml_v3.1.ecore b/mc_openapi/assets/metamodels/doml_v3.1.ecore
new file mode 100644
index 0000000000000000000000000000000000000000..ce4f02e1e1cd9b8186b33d6ab0dd5a2452c699e8
--- /dev/null
+++ b/mc_openapi/assets/metamodels/doml_v3.1.ecore
@@ -0,0 +1,489 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="doml" nsURI="http://www.piacere-project.eu/doml" nsPrefix="doml">
+  <eAnnotations source="emf.gen">
+    <details key="basePackage" value="eu.piacere.doml"/>
+    <details key="fileExtensions" value="domlx"/>
+    <details key="complianceLevel" value="JDK80"/>
+  </eAnnotations>
+  <eSubpackages name="commons" nsURI="http://www.piacere-project.eu/doml/commons"
+      nsPrefix="commons">
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLModel" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="version" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="3.1"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="application" eType="#//application/ApplicationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="infrastructure" eType="#//infrastructure/InfrastructureLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="concretizations" upperBound="-1"
+          eType="#//concrete/ConcreteInfrastructure" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="optimization" eType="#//optimization/OptimizationLayer"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1"
+          eType="#//commons/Configuration" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeConfiguration"
+          eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="activeInfrastructure"
+          eType="#//concrete/ConcreteInfrastructure"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="functionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Property" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ListProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="values" upperBound="-1"
+          eType="#//commons/Property" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="IProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="BProperty" eSuperTypes="#//commons/Property">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtensionElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="metaclassName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DOMLElement" abstract="true">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="annotations" upperBound="-1"
+          eType="#//commons/Property" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="contributesTo" upperBound="-1"
+          eType="#//commons/Requirement" eOpposite="#//commons/Requirement/predicatesOn"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Configuration" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="deployments" upperBound="-1"
+          eType="#//commons/Deployment" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeployableElement" abstract="true"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Deployment">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="component" lowerBound="1"
+          eType="#//commons/DeployableElement"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="node" lowerBound="1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="predicatesOn" upperBound="-1"
+          eType="#//commons/DOMLElement" eOpposite="#//commons/DOMLElement/contributesTo"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RangedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="EnumeratedRequirement" eSuperTypes="#//commons/Requirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentRequirement" abstract="true"
+        eSuperTypes="#//commons/Requirement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeTypeRequirement" eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="validTypes" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToNodeWithPropertyRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="values" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DeploymentToSpecificNodeRequirement"
+        eSuperTypes="#//commons/DeploymentRequirement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="validElements" upperBound="-1"
+          eType="#//infrastructure/InfrastructureElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Credentials" abstract="true" eSuperTypes="#//commons/DOMLElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="KeyPair" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="user" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="key" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="algorithm" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="bits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="UserPass" eSuperTypes="#//commons/Credentials">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="username" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="password" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Source" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="entry" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="inventory" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="backend" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+  </eSubpackages>
+  <eSubpackages name="application" nsURI="http://www.piacere-project.eu/doml/application"
+      nsPrefix="app">
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="components" upperBound="-1"
+          eType="#//application/ApplicationComponent" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ApplicationComponent" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareComponent" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="isPersistent" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="consumedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="src" eType="#//commons/Source"
+          containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="DBMS" eSuperTypes="#//application/SoftwareComponent"/>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaS" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="licenseCost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="exposedInterfaces" upperBound="-1"
+          eType="#//application/SoftwareInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SaaSDBMS" eSuperTypes="#//application/SaaS">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="databaseName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="engine" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="engineVersion" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SoftwareInterface" eSuperTypes="#//application/ApplicationComponent">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtApplicationComponent" eSuperTypes="#//application/ApplicationComponent #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="infrastructure" nsURI="http://www.piacere-project.eu/doml/infrastructure"
+      nsPrefix="infra">
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generators" upperBound="-1"
+          eType="#//infrastructure/ComputingNodeGenerator" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//infrastructure/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//infrastructure/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" upperBound="-1"
+          eType="#//commons/Credentials" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="executionEnvironments"
+          upperBound="-1" eType="#//infrastructure/ExecutionEnvironment" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groups" upperBound="-1"
+          eType="#//infrastructure/ComputingGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//infrastructure/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/MonitoringRule" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="MonitoringRule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="condition" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategy" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="strategyConfigurationString"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingGroup" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="groupedNodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" eOpposite="#//infrastructure/ComputingNode/group"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="machineDefinition" lowerBound="1"
+          eType="#//infrastructure/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="min" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="max" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"
+          defaultValueLiteral="1"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="loadBalancer" eType="#//infrastructure/LoadBalancerKind"
+          defaultValueLiteral="DEFAULT"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="LoadBalancerKind">
+      <eLiterals name="DEFAULT"/>
+      <eLiterals name="INTERNAL" value="1"/>
+      <eLiterals name="EXTERNAL" value="2"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Rule" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RuleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="fromPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="toPort" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cidr" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RuleKind">
+      <eLiterals name="EGRESS"/>
+      <eLiterals name="INGRESS" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SecurityGroup" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="rules" upperBound="-1"
+          eType="#//infrastructure/Rule" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/associated"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="InfrastructureElement" abstract="true"
+        eSuperTypes="#//commons/DOMLElement #//commons/DeployableElement"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Node" abstract="true" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="ifaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNode" abstract="true" eSuperTypes="#//infrastructure/Node">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="architecture" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="os" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="memory_mb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cpu_count" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="credentials" eType="#//commons/Credentials"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="group" eType="#//infrastructure/ComputingGroup"
+          eOpposite="#//infrastructure/ComputingGroup/groupedNodes"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodeSpecificMonitoring"
+          upperBound="-1" eType="#//infrastructure/MonitoringRule"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="disabledMonitorings"
+          upperBound="-1" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ComputingNodeGenerator" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="uri" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/GeneratorKind"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="GeneratorKind">
+      <eLiterals name="SCRIPT"/>
+      <eLiterals name="IMAGE" value="1"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedVMs" upperBound="-1"
+          eType="#//infrastructure/VirtualMachine" eOpposite="#//infrastructure/VirtualMachine/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//infrastructure/ComputingNodeGenerator">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedContainers"
+          upperBound="-1" eType="#//infrastructure/Container" eOpposite="#//infrastructure/Container/generatedFrom"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="PhysicalComputingNode" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configInterface" eType="#//infrastructure/NetworkInterface"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="sizeDescription" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/VMImage"
+          eOpposite="#//infrastructure/VMImage/generatedVMs"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configInterface" eType="#//infrastructure/NetworkInterface"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Location" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="region" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="zone" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerConfig" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="container_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_port" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EIntegerObject"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="iface" eType="#//infrastructure/NetworkInterface"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerHostConfig" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="environment_variables"
+          upperBound="-1" eType="#//commons/SProperty" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="host" eType="#//infrastructure/ComputingNode"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="configurations" upperBound="-1"
+          eType="#//infrastructure/ContainerConfig" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Container" eSuperTypes="#//infrastructure/ComputingNode">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="generatedFrom" eType="#//infrastructure/ContainerImage"
+          eOpposite="#//infrastructure/ContainerImage/generatedContainers"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="hostConfigs" upperBound="-1"
+          eType="#//infrastructure/ContainerHostConfig" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//infrastructure/ContainerNetwork"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="volumes" upperBound="-1"
+          eType="#//infrastructure/ContainerVolume"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="dependsOn" upperBound="-1"
+          eType="#//infrastructure/Container"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerGroup" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="services" lowerBound="1"
+          upperBound="-1" eType="#//infrastructure/Container" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//infrastructure/ContainerNetwork" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="volumes" upperBound="-1"
+          eType="#//infrastructure/ContainerVolume" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerNetwork" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="containerNetworkName"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerVolume" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="containerVolumeName"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="path" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExecutionEnvironment" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="size" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="maxSize" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloat"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="location" eType="#//infrastructure/Location"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="network" eType="#//infrastructure/Network"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="securityGroups" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="TCP/IP"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedIfaces" upperBound="-1"
+          eType="#//infrastructure/NetworkInterface" eOpposite="#//infrastructure/NetworkInterface/belongsTo"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="gateways" upperBound="-1"
+          eType="#//infrastructure/InternetGateway" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1"
+          eType="#//infrastructure/Subnet" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//infrastructure/Network">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="connectedTo" upperBound="-1"
+          eType="#//infrastructure/Subnet"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="NetworkInterface" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="speed" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="endPoint" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="belongsTo" eType="#//infrastructure/Network"
+          eOpposite="#//infrastructure/Network/connectedIfaces"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="associated" upperBound="-1"
+          eType="#//infrastructure/SecurityGroup" eOpposite="#//infrastructure/SecurityGroup/ifaces"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="InternetGateway" eSuperTypes="#//infrastructure/Node">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="address" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="label" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="size_gb" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//infrastructure/InfrastructureElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EEnum" name="RoleKind">
+      <eLiterals name="NONE"/>
+      <eLiterals name="MANAGER" value="1"/>
+      <eLiterals name="WORKER" value="2"/>
+      <eLiterals name="MASTER" value="3"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="SwarmRole" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" eType="#//infrastructure/RoleKind"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nodes" upperBound="-1"
+          eType="#//infrastructure/ComputingNode" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Swarm" eSuperTypes="#//infrastructure/ComputingGroup">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="roles" upperBound="-1"
+          eType="#//infrastructure/SwarmRole" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtInfrastructureElement" eSuperTypes="#//infrastructure/InfrastructureElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="concrete" nsURI="http://www.piacere-project.eu/doml/concrete"
+      nsPrefix="concrete">
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteInfrastructure" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="providers" upperBound="-1"
+          eType="#//concrete/RuntimeProvider" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="RuntimeProvider" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="resources" upperBound="-1"
+          eType="#//concrete/GenericResource" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vms" upperBound="-1"
+          eType="#//concrete/VirtualMachine" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="executionEnvironments"
+          upperBound="-1" eType="#//concrete/ExecutionEnvironment" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="vmImages" upperBound="-1"
+          eType="#//concrete/VMImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="containerImages" upperBound="-1"
+          eType="#//concrete/ContainerImage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="networks" upperBound="-1"
+          eType="#//concrete/Network" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="storages" upperBound="-1"
+          eType="#//concrete/Storage" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="faas" upperBound="-1"
+          eType="#//concrete/FunctionAsAService" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="autoScalingGroups" upperBound="-1"
+          eType="#//concrete/AutoScalingGroup" containment="true"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ConcreteElement" abstract="true" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="resourceName" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="configurationScript"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="preexisting" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBooleanObject"
+          defaultValueLiteral="false"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="refs" upperBound="-1"
+          eType="#//concrete/ConcreteElement"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="GenericResource" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VirtualMachine" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VirtualMachine"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="VMImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="image_name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/VMImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ContainerImage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ContainerImage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExecutionEnvironment" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="instance_type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="storage_type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/ExecutionEnvironment"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Network" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="protocol" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="addressRange" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="subnets" upperBound="-1"
+          eType="#//concrete/Subnet" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Network"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="Subnet" eSuperTypes="#//concrete/Network"/>
+    <eClassifiers xsi:type="ecore:EClass" name="Storage" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/Storage"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="FunctionAsAService" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/FunctionAsAService"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="AutoScalingGroup" eSuperTypes="#//concrete/ConcreteElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="vm_type" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="maps" eType="#//infrastructure/AutoScalingGroup"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtConcreteElement" eSuperTypes="#//concrete/ConcreteElement #//commons/ExtensionElement"/>
+  </eSubpackages>
+  <eSubpackages name="optimization" nsURI="http://www.piacere-project.eu/doml/optimization"
+      nsPrefix="opt">
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationLayer" eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="startingHint" eType="#//commons/Configuration"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="solutions" upperBound="-1"
+          eType="#//optimization/OptimizationSolution" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" upperBound="-1"
+          eType="#//optimization/OptimizationObjective" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EReference" name="nonfunctionalRequirements"
+          upperBound="-1" eType="#//commons/Requirement" containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="runtime" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="ObjectiveValue">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="cost" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="availability" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="performance" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EFloatObject"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationSolution" eSuperTypes="#//commons/Configuration">
+      <eStructuralFeatures xsi:type="ecore:EReference" name="objectives" eType="#//optimization/ObjectiveValue"
+          containment="true"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="decisions" upperBound="-1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="OptimizationObjective" abstract="true"
+        eSuperTypes="#//commons/DOMLElement">
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="kind" lowerBound="1"
+          eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"
+          defaultValueLiteral="Max"/>
+      <eStructuralFeatures xsi:type="ecore:EAttribute" name="property" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eClassifiers>
+    <eClassifiers xsi:type="ecore:EClass" name="CountObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="MeasurableObjective" eSuperTypes="#//optimization/OptimizationObjective"/>
+    <eClassifiers xsi:type="ecore:EClass" name="ExtOptimizationObjective" eSuperTypes="#//optimization/OptimizationObjective #//commons/ExtensionElement"/>
+  </eSubpackages>
+</ecore:EPackage>
diff --git a/mc_openapi/assets/templates/mc.html b/mc_openapi/assets/templates/mc.html
index 4c39aee609fe99f66c29627330dc183468c78b12..019b39595d705c827852170d4a4f68012bb7c913 100644
--- a/mc_openapi/assets/templates/mc.html
+++ b/mc_openapi/assets/templates/mc.html
@@ -1,7 +1,12 @@
 {% extends "base.html" %}
 
 {% block content %}
-<h1 class="title">DOML Model Checker Results</h1>
+<h1 class="title">DOML Model Checker Results
+    <span class="tags has-addons">
+        <span class="tag is-dark">DOML Version</span>
+        <span class="tag is-info">{{doml_version}}</span>
+    </span>
+</h1>
 <div class="box">
     <h2 class="title is-4">Result:
         {% if result == "sat" %}
@@ -11,13 +16,8 @@
         {% endif %}
     </h2>
     <div class="control">
-        <div class="tags has-addons">
-            <span class="tag is-dark">DOML Version</span>
-            <span class="tag is-info">{{doml_version}}</span>
-        </div>
+        <p>Model validated in {{elapsed_time}}s.</p>
     </div>
-    {% if result != "sat" %}
-
     {% if all_reqs %}
     <label class="checkbox my-4">
         <input type="checkbox" id="show-sat-reqs">
@@ -48,15 +48,15 @@
         {% else %}
         <li class="message is-success sat-req is-hidden">
             <div class="message-header">
-                <p>
-                    Satisfied ({{req.time}}s)
-                </p>
                 <p>
                     <span class="tag is-family-monospace is-success is-light">
                         {{req.id}}
                     </span>
                     <span class="tag is-success is-light">{{req.type}}</span>
                 </p>
+                <p>
+                    satisfied ({{req.time}}s)
+                </p>
             </div>
             <div class="message-body">
                 <h2 class="title is-6 my-2">Description</h2>
@@ -98,18 +98,22 @@
         </div>
     </article>
     {% endif %}
-    {% endif %}
-    <script>
-        const checkbox = document.querySelector("#show-sat-reqs")
-        const satReqs = document.querySelectorAll(".sat-req")
 
-        checkbox.addEventListener("click", () => {
-            satReqs.forEach(el => el.classList.toggle('is-hidden'))
-        })
-    </script>
+    {% if net_validation %}
+    {% include "net.html" %}
+    {% else %}
+    <h3 class="title is-5">Network Validation</h3>
+    No issue detected within the model network configuration.
+    {% endif %}
 </div>
+<script>
+    const checkbox = document.querySelector("#show-sat-reqs")
+    const satReqs = document.querySelectorAll(".sat-req")
 
-
+    checkbox.addEventListener("click", () => {
+        satReqs.forEach(el => el.classList.toggle('is-hidden'))
+    })
+</script>
 {% if csp %}
 {% include "csp_content.html" %}
 {% endif %}
diff --git a/mc_openapi/assets/templates/net.html b/mc_openapi/assets/templates/net.html
new file mode 100644
index 0000000000000000000000000000000000000000..ec8371c861bbd7baae79b25d5d6b707c50e18ab8
--- /dev/null
+++ b/mc_openapi/assets/templates/net.html
@@ -0,0 +1,10 @@
+<h3 class="title is-5">Network Validation</h3>
+<ul>
+    {% for warn in net_validation %}
+    <li class="message">
+        <div class="message-body">
+            {{warn}}
+        </div>
+    </li>
+    {% endfor %}
+</ul>
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/__init__.py b/mc_openapi/doml_mc/builtin_requirements/__init__.py
index edac2d1505124d44dca3f55bf71460d30d5a4aec..3f67bf2dc0630730dc6f61f2c9b6f0698f7025ef 100644
--- a/mc_openapi/doml_mc/builtin_requirements/__init__.py
+++ b/mc_openapi/doml_mc/builtin_requirements/__init__.py
@@ -7,15 +7,20 @@ CELEMS_V2_0 = [
     ("infrastructure_ComputingGroup", "concrete_RuntimeProvider::group","concrete_ComputingGroup::maps"),
 ]
 
+CELEMS_V3_1 = [
+    *CELEMS_V2_0[0:5],
+    ("infrastructure_ComputingGroup", "concrete_RuntimeProvider::autoScalingGroups","concrete_AutoScalingGroup::maps")
+]
+
 from .vm_has_iface import VM_HAS_IFACE, VM_HAS_IFACE_V2_3
-from .software_package_iface_net import SOFTWARE_PACKAGE_IFACE_NET, SOFTWARE_PACKAGE_IFACE_NET_V2_1, SOFTWARE_PACKAGE_IFACE_NET_V2_3
+from .software_package_iface_net import SOFTWARE_PACKAGE_IFACE_NET, SOFTWARE_PACKAGE_IFACE_NET_V2_1, SOFTWARE_PACKAGE_IFACE_NET_V2_3, SOFTWARE_PACKAGE_IFACE_NET_V3_1
 from .iface_uniq import IFACE_UNIQ
 from .all_software_components_deployed import ALL_SOFTWARE_COMPONENTS_DEPLOYED
-from .all_infrastructure_elements_deployed import ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED
-from .all_concrete_maps_something import ALL_CONCRETE_MAP_SOMETHING
-from .security_group_must_have_iface import SECURITY_GROUP_MUST_HAVE_IFACE
+from .all_infrastructure_elements_deployed import ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED, ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED_V3_1
+from .all_concrete_maps_something import ALL_CONCRETE_MAP_SOMETHING, ALL_CONCRETE_MAP_SOMETHING_V3_1
+from .security_group_must_have_iface import SECURITY_GROUP_MUST_HAVE_IFACE, SECURITY_GROUP_MUST_HAVE_IFACE_V3_1
 from .concrete_asg_no_vm import CONCRETE_ASG_NO_VM
-from .vm_os_required import VM_OS_REQUIRED
+from .vm_os_required import VM_OS_REQUIRED, VM_OS_REQUIRED_V3_1
 
 __ALL__ = [
     VM_HAS_IFACE,
@@ -23,11 +28,16 @@ __ALL__ = [
     SOFTWARE_PACKAGE_IFACE_NET,
     SOFTWARE_PACKAGE_IFACE_NET_V2_1,
     SOFTWARE_PACKAGE_IFACE_NET_V2_3,
+    SOFTWARE_PACKAGE_IFACE_NET_V3_1,
     IFACE_UNIQ,
     ALL_SOFTWARE_COMPONENTS_DEPLOYED,
     ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED,
+    ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED_V3_1,
     ALL_CONCRETE_MAP_SOMETHING,
+    ALL_CONCRETE_MAP_SOMETHING_V3_1,
     SECURITY_GROUP_MUST_HAVE_IFACE,
+    SECURITY_GROUP_MUST_HAVE_IFACE_V3_1,
     CONCRETE_ASG_NO_VM,
-    VM_OS_REQUIRED
+    VM_OS_REQUIRED,
+    VM_OS_REQUIRED_V3_1
 ]
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/all_concrete_maps_something.py b/mc_openapi/doml_mc/builtin_requirements/all_concrete_maps_something.py
index 18a571973dad731f86236deca6c5f2048083be70..01e2f1e7ce243a895b3ef48369ccfc4975c5ce8b 100644
--- a/mc_openapi/doml_mc/builtin_requirements/all_concrete_maps_something.py
+++ b/mc_openapi/doml_mc/builtin_requirements/all_concrete_maps_something.py
@@ -2,7 +2,7 @@ from z3 import And, Const, Consts, Exists, ExprRef, Not, Or, Solver, Implies
 from mc_openapi.doml_mc.imc import Requirement, SMTEncoding, SMTSorts
 from mc_openapi.doml_mc.intermediate_model import DOMLVersion, IntermediateModel
 from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name
-from . import CELEMS_V2_0
+from . import CELEMS_V2_0, CELEMS_V3_1
 
 # All elements in the active concretization are mapped to some abstract infrastructure element.
 
@@ -38,6 +38,38 @@ def all_concrete_map_something(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprR
         )
     )
 
+def all_concrete_map_something_v3_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    def checkOneClass(ielem, provider, celem, providerAssoc, celemAssoc):
+        return And(
+            smtenc.association_rel(
+                provider, smtenc.associations[providerAssoc], celem),
+            Not(
+                Exists(
+                    [ielem],
+                    smtenc.association_rel(
+                        celem, smtenc.associations[celemAssoc], ielem)
+                )
+            )
+        )
+
+    ielem, concr, provider, celem = Consts(
+       "ielem concr provider celem", smtsorts.element_sort)
+    return And(
+        smtenc.element_class_fun(
+            concr) == smtenc.classes["concrete_ConcreteInfrastructure"],
+        smtenc.association_rel(
+            concr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider),
+        Or(
+            *(
+                checkOneClass(
+                    ielem, provider, celem,
+                    providerAssoc, celemAssoc
+                )
+                for _, providerAssoc, celemAssoc in CELEMS_V3_1
+            )
+        )
+    )
+
 
 def ed_all_concrete_map_something(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
     try:
@@ -56,4 +88,11 @@ ALL_CONCRETE_MAP_SOMETHING = (
     "all_concrete_map_something",
     MSG,
     ed_all_concrete_map_something
+)
+
+ALL_CONCRETE_MAP_SOMETHING_V3_1 = (
+    all_concrete_map_something_v3_1,
+    "all_concrete_map_something",
+    MSG,
+    ed_all_concrete_map_something
 )
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/all_infrastructure_elements_deployed.py b/mc_openapi/doml_mc/builtin_requirements/all_infrastructure_elements_deployed.py
index 0d0f366cf1b018a0f0534642a1e65568115254d1..7e4b4e300caa546a06f9f110de3f34af7d0e8a27 100644
--- a/mc_openapi/doml_mc/builtin_requirements/all_infrastructure_elements_deployed.py
+++ b/mc_openapi/doml_mc/builtin_requirements/all_infrastructure_elements_deployed.py
@@ -2,7 +2,7 @@ from z3 import And, Const, Consts, Exists, ExprRef, Not, Or, Solver, Implies
 from mc_openapi.doml_mc.imc import Requirement, SMTEncoding, SMTSorts
 from mc_openapi.doml_mc.intermediate_model import DOMLVersion, IntermediateModel
 from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name
-from . import CELEMS_V2_0
+from . import CELEMS_V2_0, CELEMS_V3_1
 
 # Provider > elements generated by IOP only have "commons_DOMLElement::annotations" as an association
 # and do not have maps. Also networks are not generated by the IOP. But they are the same class
@@ -70,6 +70,75 @@ def all_infrastructure_elements_deployed(smtenc: SMTEncoding, smtsorts: SMTSorts
         )
     )
 
+def all_infrastructure_elements_deployed_v3_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    def checkOneClass(ielem, cinfr, provider, celem, ielemClass, providerAssoc, celemAssoc):
+        return And(
+            smtenc.element_class_fun(ielem) == smtenc.classes[ielemClass],
+            Not(
+                Exists(
+                    [provider, celem],
+                    And(
+                        smtenc.association_rel(
+                            cinfr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider),
+                        smtenc.association_rel(
+                            provider, smtenc.associations[providerAssoc], celem),
+                        smtenc.association_rel(
+                            celem, smtenc.associations[celemAssoc], ielem)
+                    )
+                )
+            )
+        )
+
+    ielem, concr, provider, celem, net, asg = Consts("ielem concr provider celem net asg", smtsorts.element_sort)
+    return And(
+        smtenc.element_class_fun(
+            concr) == smtenc.classes["concrete_ConcreteInfrastructure"],
+        Or(
+            *(
+                checkOneClass(
+                    ielem, concr, provider, celem,
+                    ielemClass, providerAssoc, celemAssoc
+                ) 
+                for ielemClass, providerAssoc, celemAssoc in CELEMS_V3_1
+                if ielemClass != 'infrastructure_VirtualMachine' # handle special case separately in concrete_asg_no_vm and below
+            ),
+            And(
+                smtenc.element_class_fun(ielem) == smtenc.classes["infrastructure_VirtualMachine"],
+                Not(Exists([asg],
+                    Or(
+                        smtenc.association_rel(
+                            asg, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], ielem),
+                        Exists(
+                            [provider, celem],
+                            And(
+                                smtenc.association_rel(
+                                    concr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider),
+                                smtenc.association_rel(
+                                    provider, smtenc.associations["concrete_RuntimeProvider::vms"], celem),
+                                smtenc.association_rel(
+                                    celem, smtenc.associations["concrete_VirtualMachine::maps"], ielem)
+                            )
+                        )
+                    )
+                ))
+            ),
+            And(
+                smtenc.element_class_fun(ielem) == smtenc.classes["infrastructure_Subnet"],
+                Not(Exists([provider, net, celem],
+                    And(
+                        smtenc.association_rel(
+                            concr, smtenc.associations["concrete_ConcreteInfrastructure::providers"], provider),
+                        smtenc.association_rel(
+                            provider, smtenc.associations["concrete_RuntimeProvider::networks"], net),
+                        smtenc.association_rel(
+                            net, smtenc.associations["concrete_Network::subnets"], celem),
+                        smtenc.association_rel(
+                            celem, smtenc.associations["concrete_Network::maps"], ielem)
+                    )
+                ))
+            )
+        )
+    )
 
 def ed_all_infrastructure_elements_deployed(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
     try:
@@ -88,4 +157,11 @@ ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED = (
     "all_infrastructure_elements_deployed",
     MSG,
     ed_all_infrastructure_elements_deployed
+)
+
+ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED_V3_1 = (
+    all_infrastructure_elements_deployed_v3_1,
+    "all_infrastructure_elements_deployed",
+    MSG,
+    ed_all_infrastructure_elements_deployed
 )
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/security_group_must_have_iface.py b/mc_openapi/doml_mc/builtin_requirements/security_group_must_have_iface.py
index e18ec59597bfac1797e261793f3d6f2d26283e07..6e9cbabf07ee335e565146c45d66e5145239f61c 100644
--- a/mc_openapi/doml_mc/builtin_requirements/security_group_must_have_iface.py
+++ b/mc_openapi/doml_mc/builtin_requirements/security_group_must_have_iface.py
@@ -18,21 +18,44 @@ def security_group_must_have_iface(smtenc: SMTEncoding, smtsorts: SMTSorts) -> E
         ))
     )
 
+def security_group_must_have_iface_v3_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    sg, elem = Consts("sg elem", smtsorts.element_sort)
+    return And(
+        smtenc.element_class_fun(
+            sg) == smtenc.classes["infrastructure_SecurityGroup"],
+        Not(Exists([elem],
+            Or(
+                smtenc.association_rel(
+                    elem, smtenc.associations["infrastructure_NetworkInterface::associated"], sg),
+                smtenc.association_rel(
+                    elem, smtenc.associations["infrastructure_ExecutionEnvironment::securityGroups"], sg)
+            )
+        ))
+    )
+
+
 def ed_security_group_must_have_iface(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
     try:
         sg = Const("sg", smtsorts.element_sort)
         sg_name = get_user_friendly_name(
             intermediate_model, solver.model(), sg)
         if sg_name:
-            return f"Security group '{sg_name}' is not associated with any network interface."
+            return f"Security group '{sg_name}' is not associated with any network interface. You should probably remove it."
     except:
-        return "A network interface doesn't belong to any security group, or a security group is not associated with any network interface."
+        return "A security group is not associated with any element. You should probably remove it."
 
-MSG = "All security group should be a associated to a network interface."
+MSG = "All security group should be a associated to an element."
 
 SECURITY_GROUP_MUST_HAVE_IFACE = (
     security_group_must_have_iface,
     "security_group_must_have_iface",
     MSG,
     ed_security_group_must_have_iface
+)
+
+SECURITY_GROUP_MUST_HAVE_IFACE_V3_1 = (
+    security_group_must_have_iface_v3_1,
+    "security_group_must_have_iface",
+    MSG,
+    ed_security_group_must_have_iface
 )
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/software_package_iface_net.py b/mc_openapi/doml_mc/builtin_requirements/software_package_iface_net.py
index e4ab9d07d93656b1da46fe4ad31d03656003a972..e570717bb4833641014f7076d0ae94f2c625ad3b 100644
--- a/mc_openapi/doml_mc/builtin_requirements/software_package_iface_net.py
+++ b/mc_openapi/doml_mc/builtin_requirements/software_package_iface_net.py
@@ -495,6 +495,169 @@ def software_package_iface_net_v2_3(smtenc: SMTEncoding, smtsorts: SMTSorts) ->
         )
     )
 
+def software_package_iface_net_v3_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    asc_consumer, asc_exposer, siface, net, net_iface, cnode, cdeployment, enode, edeployment, vm, cconf, csubnet, esubnet = Consts(
+        "asc_consumer asc_exposer siface net net_iface cnode cdeployment enode edeployment vm cconf csubnet esubnet", smtsorts.element_sort
+    )
+    return And(
+        smtenc.association_rel(
+            asc_consumer, smtenc.associations["application_SoftwareComponent::exposedInterfaces"], siface),
+        smtenc.association_rel(
+            asc_exposer, smtenc.associations["application_SoftwareComponent::consumedInterfaces"], siface),
+        Not(
+            Or(
+                Exists(
+                    [cdeployment, cnode, edeployment, enode, net],
+                    And(
+                        smtenc.association_rel(
+                            cdeployment, smtenc.associations["commons_Deployment::component"], asc_consumer),
+                        smtenc.association_rel(
+                            cdeployment, smtenc.associations["commons_Deployment::node"], cnode),
+                        Exists(
+                            [vm, net_iface, cconf],
+                            Or(
+                                And(  # asc_consumer is deployed on a component with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                                And(  # asc_consumer is deployed on a container hosted in a VM with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_Container::hostConfigs"], cconf),
+                                    smtenc.association_rel(
+                                        cconf, smtenc.associations["infrastructure_ContainerHostConfig::host"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                                And(  # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                            )
+                        ),
+                        smtenc.association_rel(
+                            edeployment, smtenc.associations["commons_Deployment::component"], asc_exposer),
+                        smtenc.association_rel(
+                            edeployment, smtenc.associations["commons_Deployment::node"], enode),
+                        Exists(
+                            [vm, net_iface, cconf],
+                            Or(
+                                And(  # asc_exposer is deployed on a component with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                                And(  # asc_exposer is deployed on a container hosted on a VM with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_Container::hostConfigs"], cconf),
+                                    smtenc.association_rel(
+                                        cconf, smtenc.associations["infrastructure_ContainerHostConfig::host"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                                And(  # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], net),
+                                ),
+                            )
+                        )
+                    )
+                ),  # OR
+                Exists(
+                    [cdeployment, cnode, edeployment, enode, csubnet, esubnet],
+                    And(
+                        smtenc.association_rel(
+                            cdeployment, smtenc.associations["commons_Deployment::component"], asc_consumer),
+                        smtenc.association_rel(
+                            cdeployment, smtenc.associations["commons_Deployment::node"], cnode),
+                        Or(
+                            smtenc.association_rel(
+                                csubnet, smtenc.associations["infrastructure_Subnet::connectedTo"], esubnet),
+                            smtenc.association_rel(
+                                esubnet, smtenc.associations["infrastructure_Subnet::connectedTo"], csubnet),
+                        ),
+                        Exists(
+                            [vm, net_iface, cconf],
+                            Or(
+                                And(  # asc_consumer is deployed on a component with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], csubnet),
+                                ),
+                                And(  # asc_consumer is deployed on a container hosted in a VM with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_Container::hostConfigs"], cconf),
+                                    smtenc.association_rel(
+                                        cconf, smtenc.associations["infrastructure_ContainerHostConfig::host"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], csubnet),
+                                ),
+                                And(  # asc_consumer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                    smtenc.association_rel(
+                                        cnode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], csubnet),
+                                ),
+                            )
+                        ),
+                        smtenc.association_rel(
+                            edeployment, smtenc.associations["commons_Deployment::component"], asc_exposer),
+                        smtenc.association_rel(
+                            edeployment, smtenc.associations["commons_Deployment::node"], enode),
+                        Exists(
+                            [vm, net_iface, cconf],
+                            Or(
+                                And(  # asc_exposer is deployed on a component with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], esubnet),
+                                ),
+                                And(  # asc_exposer is deployed on a container hosted on a VM with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_Container::hostConfigs"], cconf),
+                                    smtenc.association_rel(
+                                        cconf, smtenc.associations["infrastructure_ContainerHostConfig::host"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], esubnet),
+                                ),
+                                And(  # asc_exposer is deployed on a VM in an AutoScalingGroup with an interface in network n
+                                    smtenc.association_rel(
+                                        enode, smtenc.associations["infrastructure_AutoScalingGroup::machineDefinition"], vm),
+                                    smtenc.association_rel(
+                                        vm, smtenc.associations["infrastructure_Node::ifaces"], net_iface),
+                                    smtenc.association_rel(
+                                        net_iface, smtenc.associations["infrastructure_NetworkInterface::belongsTo"], esubnet),
+                                )
+                            )
+                        )
+                    )
+                )
+            )
+        )
+    )
+
 
 def ed_software_package_iface_net(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
     try:
@@ -537,4 +700,11 @@ SOFTWARE_PACKAGE_IFACE_NET_V2_3 = (
     "software_package_iface_net",
     MSG,
     ed_software_package_iface_net
+)
+
+SOFTWARE_PACKAGE_IFACE_NET_V3_1 = (
+    software_package_iface_net_v3_1,
+    "software_package_iface_net",
+    MSG,
+    ed_software_package_iface_net
 )
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py b/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py
index 2209c8892378224ce74cd6605c85e7a13c6f2df4..73a6ce4d5ade7a56c48c4319720989ef4b7a4e20 100644
--- a/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py
+++ b/mc_openapi/doml_mc/builtin_requirements/vm_os_required.py
@@ -5,25 +5,6 @@ from mc_openapi.doml_mc.error_desc_helper import get_user_friendly_name
 
 
 def vm_os_required(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
-    # cont, contcfg, vm = Consts("cont contcfg vm", smtsorts.element_sort)
-    # os = Const("os", smtsorts.attr_data_sort)
-    # return And(
-    #     smtenc.element_class_fun(cont) == smtenc.classes["infrastructure_Container"],
-    #     Not(
-    #         Exists(
-    #             [contcfg, os],
-    #             And(
-    #                 smtenc.association_rel(
-    #                     cont, smtenc.associations["infrastructure_Container::configs"], contcfg),
-    #                 smtenc.association_rel(
-    #                     contcfg, smtenc.associations["infrastructure_ContainerConfig::host"], vm),
-    #                 smtenc.attribute_rel(
-    #                     vm, smtenc.attributes["infrastructure_ComputingNode::os"], os
-    #                 )
-    #             )
-    #         )
-    #     )
-    # )
     vm, cont, ccfg = Consts("vm cont ccfg", smtsorts.element_sort)
     os = Const("os", smtsorts.attr_data_sort)
     return And(
@@ -46,6 +27,28 @@ def vm_os_required(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
         )
     )
 
+def vm_os_required_v3_1(smtenc: SMTEncoding, smtsorts: SMTSorts) -> ExprRef:
+    vm, cont, ccfg = Consts("vm cont ccfg", smtsorts.element_sort)
+    os = Const("os", smtsorts.attr_data_sort)
+    return And(
+        smtenc.element_class_fun(
+            vm) == smtenc.classes["infrastructure_VirtualMachine"],
+        smtenc.element_class_fun(
+            cont) == smtenc.classes["infrastructure_Container"],
+        Not(
+            Exists(
+                [vm, os, ccfg],
+                And(
+                    smtenc.association_rel(
+                        cont, smtenc.associations["infrastructure_Container::hostConfigs"], ccfg),
+                    smtenc.association_rel(
+                        ccfg, smtenc.associations["infrastructure_ContainerHostConfig::host"], vm),
+                    smtenc.attribute_rel(
+                        vm, smtenc.attributes["infrastructure_ComputingNode::os"], os)
+                )
+            )
+        )
+    )
 
 def ed_vm_os_required(solver: Solver, smtsorts: SMTSorts, intermediate_model: IntermediateModel) -> str:
     try:
@@ -70,3 +73,9 @@ VM_OS_REQUIRED = (
     ed_vm_os_required
 )
 
+VM_OS_REQUIRED_V3_1 = (
+    vm_os_required_v3_1, 
+    "vm_os_required",
+    MSG,
+    ed_vm_os_required
+)
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/common_reqs.py b/mc_openapi/doml_mc/common_reqs.py
index 6f989d94ea44781eeb4737ddba0c7aa88ddd7b84..74edd900f6dea5d2695f8be48488e851b3b27d56 100644
--- a/mc_openapi/doml_mc/common_reqs.py
+++ b/mc_openapi/doml_mc/common_reqs.py
@@ -54,6 +54,17 @@ REQUIREMENTS = {
         SECURITY_GROUP_MUST_HAVE_IFACE,
         CONCRETE_ASG_NO_VM,
         VM_OS_REQUIRED
+    ],
+    DOMLVersion.V3_1: [
+        VM_HAS_IFACE_V2_3,
+        SOFTWARE_PACKAGE_IFACE_NET_V3_1,
+        IFACE_UNIQ,
+        ALL_SOFTWARE_COMPONENTS_DEPLOYED,
+        ALL_INFRASTRUCTURE_ELEMENTS_DEPLOYED_V3_1,
+        ALL_CONCRETE_MAP_SOMETHING_V3_1,
+        SECURITY_GROUP_MUST_HAVE_IFACE_V3_1,
+        CONCRETE_ASG_NO_VM,
+        VM_OS_REQUIRED_V3_1
     ]
 }
 
diff --git a/mc_openapi/doml_mc/exceptions.py b/mc_openapi/doml_mc/exceptions.py
index a94ab25111da89185f6c5eecca42906c255af76d..a3284438af998cd6cc9a64f15561918db5694f44 100644
--- a/mc_openapi/doml_mc/exceptions.py
+++ b/mc_openapi/doml_mc/exceptions.py
@@ -1,6 +1,3 @@
-from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion
-
-
 class BadDOMLException(Exception):
     def __init__(self, message: str = None, *args: object) -> None:
         super().__init__(*args)
@@ -21,3 +18,7 @@ class NoActiveConcreteLayerException(Exception):
         super().__init__(*args)
         self.message = message or "No active concrete infrastructure layer has been specified in DOML."
 
+class CommonRequirementException(Exception):
+    def __init__(self, message: str = None, *args: object) -> None:
+        super().__init__(*args)
+        self.message = message or "Couldn't get built-in requirements for this DOML version."
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/intermediate_model/metamodel.py b/mc_openapi/doml_mc/intermediate_model/metamodel.py
index fe0fdf1c8f277928931e25555f71890de686d0ec..f1ab8f48b11e4514f7c7c0dca8ebd3d109c9fc33 100644
--- a/mc_openapi/doml_mc/intermediate_model/metamodel.py
+++ b/mc_openapi/doml_mc/intermediate_model/metamodel.py
@@ -17,6 +17,7 @@ class DOMLVersion(Enum):
     V2_2_1 = "v2.2.1"
     V2_3 = "v2.3"
     V3_0 = "v3.0"
+    V3_1 = "v3.1"
 
     def get(v: str):
         """Retrieve DOML version from string.
diff --git a/mc_openapi/doml_mc/main.py b/mc_openapi/doml_mc/main.py
index 555cf4304eb2b9b14aa527d236ad29a5773dbe63..1d8c8934081bf4e78a17361fb74ac781334051a5 100644
--- a/mc_openapi/doml_mc/main.py
+++ b/mc_openapi/doml_mc/main.py
@@ -11,9 +11,11 @@ from mc_openapi.doml_mc.csp_compatibility import \
     CSPCompatibilityValidator as CSPCompatibility
 from mc_openapi.doml_mc.domlr_parser import (DOMLRTransformer, Parser,
                                              SynthesisDOMLRTransformer)
+from mc_openapi.doml_mc.exceptions import CommonRequirementException
 from mc_openapi.doml_mc.imc import RequirementStore
 from mc_openapi.doml_mc.intermediate_model.metamodel import (DOMLVersion,
                                                              MetaModelDocs)
+from mc_openapi.doml_mc.network_address_validator.validate import validate_network_address
 
 
 def init_model(domlx:bytes, doml_ver: DOMLVersion):
@@ -42,7 +44,7 @@ def verify_model(
 
     # Parse external DOMLR file
     if external_domlr:
-        user_req_store, user_req_str_consts = domlr_parser.parse(external_domlr)
+        user_req_store, user_req_str_consts, flags = domlr_parser.parse(external_domlr)
 
     # Parse internal DOMLR requirements
     if DOMLVersion.has_DOMLR_support(dmc.doml_version):
@@ -58,9 +60,13 @@ def verify_model(
 
     # Built-in requirements
     if not (flags.get('_ignore_builtin', False) or skip_builtin_checks):
-        req_store += CommonRequirements[dmc.doml_version]
-        # Skip selected requirements
-        req_store.skip_requirements_by_id([k for k,v in flags.items() if not k.startswith("_") and v is False])
+        try:
+            req_store += CommonRequirements[dmc.doml_version]
+            # Skip selected requirements
+            req_store.skip_requirements_by_id([k for k,v in flags.items() if not k.startswith("_") and v is False])
+        except:
+            logging.error('Failed to get Common Requirements. DOML Version is wrong?')
+            raise CommonRequirementException()
 
     # Consistency requirements (disabled by default)
     if flags.get('_check_consistency', False) or consistency_checks:
@@ -77,6 +83,7 @@ def verify_model(
 
     # Log all requirements to check
     logging.debug("Checking following requirements: " + ", ".join([k.assert_name for k in req_store.get_all_requirements()]))
+    logging.debug("Flags: { " + ", ".join([f"{k}={v}" for k, v in flags.items()]) + " }")
 
     # Check satisfiability
     results = dmc.check_requirements(
@@ -98,6 +105,9 @@ def verify_model(
     if flags.get('_csp', False):
         res['csp'] = verify_csp_compatibility(dmc)
 
+    # Validate network
+    res['net_validation'] = validate_network_address(dmc)
+
     return res
 
 def synthesize_model(dmc: ModelChecker, external_domlr: str, max_tries: int):
diff --git a/mc_openapi/doml_mc/mc_result.py b/mc_openapi/doml_mc/mc_result.py
index fba8aaa505b8ece2fb0ce3b1bfa2e2feae310282..8693a421cd1377d942896f59265560382e230532 100644
--- a/mc_openapi/doml_mc/mc_result.py
+++ b/mc_openapi/doml_mc/mc_result.py
@@ -42,6 +42,19 @@ class MCResults:
         some_unsat = any(res == MCResult.unsat for res, _, _, _, _, _ in self.results)
         some_dontknow = any(res == MCResult.dontknow for res, _, _, _, _, _ in self.results)
 
+        all_reqs = [
+                        {
+                            "id": id,
+                            "type": type,
+                            "message": msg,
+                            "result": res.name,
+                            "description": desc,
+                            "time": time
+                        }
+                        for res, type, msg, id, desc, time in self.results
+                    ]
+
+
         if some_unsat:
             builtin_err_msgs = [
                 (id, msg, time) for res, type, msg, id, _, time in self.results if res == MCResult.unsat and type == "BUILTIN"]
@@ -60,18 +73,6 @@ class MCResults:
             if some_dontknow:
                 err_msg += '\n' + MCResults.DONTKNOW_MSG
             
-            all_reqs = [
-                {
-                    "id": id,
-                    "type": type,
-                    "message": msg,
-                    "result": res.name,
-                    "description": desc,
-                    "time": time
-                }
-                for res, type, msg, id, desc, time in self.results
-            ]
-
             return {
                 'result': MCResult.unsat,
                 'builtin': builtin_err_msgs,
@@ -83,7 +84,7 @@ class MCResults:
         elif some_dontknow:
             return {'result': MCResult.dontknow, 'description': MCResults.DONTKNOW_MSG }
         else:
-            return {'result': MCResult.sat, 'description': MCResults.SATISFIED_MSG }
+            return {'result': MCResult.sat, 'description': MCResults.SATISFIED_MSG, 'all_reqs': all_reqs }
 
     def add_results(self, results: "MCResults"):
         self.results.extend(results.results)
diff --git a/mc_openapi/doml_mc/network_address_validator/__init__.py b/mc_openapi/doml_mc/network_address_validator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..b64d68b57bb369f04c53eba9a9e436a6fdb7cd1d
--- /dev/null
+++ b/mc_openapi/doml_mc/network_address_validator/__init__.py
@@ -0,0 +1 @@
+from .validate import validate_network_address
\ No newline at end of file
diff --git a/mc_openapi/doml_mc/network_address_validator/validate.py b/mc_openapi/doml_mc/network_address_validator/validate.py
new file mode 100644
index 0000000000000000000000000000000000000000..5cbcdc6dd54a482a895db72e1f57a790b3e58755
--- /dev/null
+++ b/mc_openapi/doml_mc/network_address_validator/validate.py
@@ -0,0 +1,275 @@
+import logging
+from mc_openapi.doml_mc.intermediate_model import DOMLElement
+from mc_openapi.doml_mc.mc import ModelChecker
+from ipaddress import IPv4Address, IPv4Network
+
+
+BASE_ADDR = '0.0.0.0'
+
+
+CONCRETE_NETWORK = 'concrete_Network'
+# associations
+ASSOC_SUBNETS = 'infrastructure_Network::subnets'
+ASSOC_CONCRETE_SUBNETS = 'concrete_Network::subnets'
+ASSOC_CONCRETE_MAPS = 'concrete_Network::maps'
+ASSOC_GATEWAYS = 'infrastructure_Network::gateways'
+ASSOC_NETIFACE = 'infrastructure_Network::connectedIfaces'
+
+# attributes
+ATTR_NET_CIDR = 'infrastructure_Network::cidr'
+ATTR_GATEWAY_ADDRESS = 'infrastructure_InternetGateway::address'
+ATTR_NETIFACE_ADDRESS = 'infrastructure_NetworkInterface::endPoint'
+ATTR_PROTOCOL = 'infrastructure_Network::protocol'
+ATTR_CONCRETE_PROTOCOL = 'concrete_Network::protocol'
+ATTR_CONCRETE_ADDRESS_RANGE = 'concrete_Network::addressRange'
+
+def validate_network_address(imc: ModelChecker):
+    """
+    HOW IT WORKS:
+
+    * Infrastructure Layer
+        - [n] Network.protocol
+        - [e] InternetGateway.address
+        - [e] NetworkInterface.endPoint
+    * Concrete Layer
+        - [n] Network.protocol
+        - [n] Network.addressRange
+        - [n] Subnet.addressRange
+
+    before MC
+    validate network
+    generate report
+    attach report to HTML output
+    """
+    im = imc.intermediate_model
+
+    # warnings: list[str] = []
+    warnings: list[str] = []
+
+    ## Helpers ##
+    def get_attr(elem: DOMLElement, attr_id: str):
+        if elem := elem.attributes.get(attr_id):
+            return elem[0]
+        return None
+        
+    def get_assocs(elem: DOMLElement, assoc_id: str):
+        return elem.associations.get(assoc_id, [])
+
+    def get_elem(elem: DOMLElement, assoc_id: str):
+        assocs = list(get_assocs(elem, assoc_id))
+        if len(assocs) >= 1:
+            return im.get(assocs[0])
+        return None
+
+    def validate_net(cnet: DOMLElement, parent_net: DOMLElement | None = None):
+        
+        if (parent_net):
+            check_proper_subnet(cnet, parent_net)
+            
+        if inet := get_elem(cnet, ASSOC_CONCRETE_MAPS):
+            check_infr_and_conc_protocol_match(inet, cnet)
+            check_cidr_and_address_range(inet, cnet)
+            check_gateway_belongs_to_network(inet, cnet)
+            check_iface_belongs_to_network(inet, cnet)
+
+        debug =  f"{cnet.user_friendly_name} [concrete]\n"
+        debug += f"\tprotocol={get_attr(cnet, ATTR_CONCRETE_PROTOCOL)}\n"
+        debug += f"\taddress_range={get_attr(cnet, ATTR_CONCRETE_ADDRESS_RANGE)}\n"
+        debug += f"\tsubnets=\t{get_assocs(cnet, ASSOC_CONCRETE_SUBNETS)}\n"
+        if inet:
+            debug += f"{inet.user_friendly_name} [infrastructure]\n"
+            debug += f"\tprotocol={get_attr(inet, ATTR_PROTOCOL)}\n"
+            debug += f"\tcidr={get_attr(inet, ATTR_NET_CIDR)}\n"
+            debug += f"\tsubnets=\t{get_assocs(inet, ASSOC_SUBNETS)}\n"
+            debug += f"\tifaces=\t{get_assocs(inet, ASSOC_NETIFACE)}\n"
+            debug += f"\tgateways=\t{get_assocs(inet, ASSOC_GATEWAYS)}\n"
+        debug += "\n"
+        # print(debug)
+
+        csubnet_ids = get_assocs(cnet, ASSOC_CONCRETE_SUBNETS)
+        for csubnet_id in csubnet_ids:
+            if csubnet := im.get(csubnet_id):
+
+                validate_net(csubnet, cnet)
+
+    ## Checks ##
+    def check_infr_and_conc_protocol_match(inet: DOMLElement, cnet: DOMLElement):
+        """Checks if the protocol of an infrastructure network matches the respective protocol of its concrete counterpart."""
+        iprot = get_attr(inet, ATTR_PROTOCOL)
+        cprot = get_attr(cnet, ATTR_CONCRETE_PROTOCOL)
+        if iprot and cprot and iprot != cprot:
+            warnings.append(f"Protocol of infrastructure network '{inet.user_friendly_name}' must match protocol of concrete network '{cnet.user_friendly_name}'.")
+
+    def check_cidr_and_address_range(inet: DOMLElement, cnet: DOMLElement, warnings=warnings):
+        """Checks if the addressRange of a concrete network respects the CIDR specified in the infrastructure layer."""
+        cidr = get_attr(inet, ATTR_NET_CIDR)
+        addr_range = get_attr(cnet, ATTR_CONCRETE_ADDRESS_RANGE)
+        if cidr and addr_range:
+            try:
+                addr_range = IPv4Network(addr_range)
+                if addr_range.prefixlen != cidr:
+                    warnings.append(f"CIDR ({cidr}) of infrastructure network '{inet.user_friendly_name}' does not match the address range of concrete network '{cnet.user_friendly_name}'.")
+            except:
+                warnings.append(f"Failed to parse concrete network '{cnet.user_friendly_name}' address range as an IPv4Network.")
+            
+    def check_proper_subnet(cnet: DOMLElement, parent_net: DOMLElement):
+        """Checks if a subnet address range respects the parent net."""
+        addr_range = get_attr(cnet, ATTR_CONCRETE_ADDRESS_RANGE)
+        parent_addr_range = get_attr(parent_net, ATTR_CONCRETE_ADDRESS_RANGE)
+        if addr_range and parent_addr_range:
+            try: 
+                addr_range = IPv4Network(addr_range)
+                parent_addr_range = IPv4Network(parent_addr_range)
+
+                if not addr_range.subnet_of(parent_addr_range):
+                    warnings.append(f"Subnet '{cnet.user_friendly_name}' is not a proper subnet of '{parent_net.user_friendly_name}'.")
+            except:
+                warnings.append(f"Failed to parse concrete network '{cnet.user_friendly_name}' or '{parent_net.user_friendly_name}' address range as an IPv4Network.")
+
+    def check_gateway_belongs_to_network(inet: DOMLElement, cnet: DOMLElement):
+        """Checks if the address of the gateways of a network belongs to that network address range."""
+        addr_range = get_attr(cnet, ATTR_CONCRETE_ADDRESS_RANGE)
+        gateway_ids = get_assocs(inet, ASSOC_GATEWAYS)
+
+        if addr_range and gateway_ids:
+            for gateway_id in gateway_ids:
+                if gateway := im.get(gateway_id):
+                    addr_gateway = get_attr(gateway, ATTR_GATEWAY_ADDRESS)
+                    if addr_gateway:
+                        try:
+                            addr_range = IPv4Network(addr_range)
+                            addr_gateway = IPv4Address(addr_gateway)
+                            if addr_gateway not in addr_range:
+                                warnings.append(f"Gateway '{gateway.user_friendly_name}' does not belong to network '{cnet.user_friendly_name}'.")
+                        except:
+                            warnings.append(f"Failed to parse concrete network {cnet.user_friendly_name} address range or its gateway address.")
+
+    def check_iface_belongs_to_network(inet: DOMLElement, cnet: DOMLElement):
+        """Checks if the address of the network interfaces of a network belongs to that network address range."""
+        addr_range = get_attr(cnet, ATTR_CONCRETE_ADDRESS_RANGE)
+        iface_ids = get_assocs(inet, ASSOC_NETIFACE)
+
+        if addr_range and iface_ids:
+            for iface_id in iface_ids:
+                if iface := im.get(iface_id):
+                    addr_iface = get_attr(iface, ATTR_NETIFACE_ADDRESS)
+                    if addr_iface:
+                        try:
+                            addr_range = IPv4Network(addr_range)
+                            addr_iface = IPv4Address(addr_iface)
+                            if addr_iface not in addr_range:
+                                warnings.append(f"Network Interface '{addr_iface.user_friendly_name}' does not belong to network '{cnet.user_friendly_name}'.")
+                        except Exception as e:
+                            print(e)
+                            warnings.append(f"Failed to parse concrete network {cnet.user_friendly_name} address range or its associated network interface '{iface.user_friendly_name}' address.")
+
+
+
+
+    concrete_networks = [e for e in im.values() if e.class_ == CONCRETE_NETWORK]
+
+    # print('-'*20)
+    # print('[DEBUG] Network Validation')
+
+    for cnet in concrete_networks:
+        validate_net(cnet)
+               
+    # print('-'*20)
+    # print(warnings)
+    # print('-'*20)
+
+    # networks = [e for e in im.values() if e.class_ == 'concrete_Network']
+    # subnets = [e for e in im.values() if e.class_ == 'infrastructure_Subnet']
+    # ifaces = [e for e in im.values() if e.class_ == 'infrastructure_NetworkInterface']
+
+
+    # def visit_subnet(net: DOMLElement, acc: list):
+    #     """Recursively navigate subnets to populate the `acc` list with all the subnet in a network."""
+    #     for subnet in get_assocs(net, ASSOC_SUBNETS):
+    #         subnet = im[subnet]
+    #         subnet_addr = fix_invalid_address(get_attr(subnet, ATTR_NET_ADDRESS), net, warnings)
+    #         acc.append((subnet, IPv4Network(subnet_addr)))
+    #         visit_subnet(subnet, acc)
+
+    # def fix_invalid_address(address: any, net: DOMLElement, warning: list):
+    #     # TODO: Use a match statement or use regexps once syntax for CIDR/Address is clear
+    #     if isinstance(address, str) and address.startswith('/'):
+    #         warning.append(("Network", f"Net '{net.user_friendly_name}' has an incomplete address: '{address}'. '0.0.0.0' has been temporarily assigned."))
+    #         return f"{BASE_ADDR}{address}"
+
+    #     return address
+
+
+    # for network in networks:
+
+    #     warning = []
+
+    #     # Tuple(elem, cidr)
+    #     subnets: list[tuple[DOMLElement, IPv4Network]] = []
+    #     # Tuple(elem, address)
+    #     addresses: list[tuple[DOMLElement, IPv4Address]] = []
+
+    #     # Add subnets (Networks)
+    #     visit_subnet(network, subnets)
+
+    #     # pprint("SUBNETS:")
+    #     # pprint(subnets)
+
+    #     # Add addresses (gateways, ifaces)
+    #     for gateway in get_assocs(network, ASSOC_GATEWAYS):
+    #         gateway = im[gateway]
+    #         if gateway_address := get_attr(gateway, ATTR_GATEWAY_ADDRESS):
+    #             addresses.append((gateway, IPv4Address(gateway_address)))
+
+    #     for iface in ifaces:
+    #         if owner_id := get_assocs(iface, ASSOC_IFACE_NET):
+    #             owner = im[list(owner_id)[0]]
+    #             if owner.id_ in [s.id_ for (s, _) in subnets] + [network.id_]:
+    #                 if ((iface_address := get_attr(iface, ATTR_NETIFACE_ADDRESS))
+    #                 and (owner_address := get_attr(owner, ATTR_NET_ADDRESS))):
+    #                     owner_address = fix_invalid_address(owner_address, owner, warning)
+    #                     iface_address = IPv4Address(iface_address)
+    #                     owner_address = IPv4Network(owner_address)
+    #                     # TODO: Remove?
+    #                     logging.info(f"{iface.user_friendly_name} ({iface_address}) belongs to {owner.user_friendly_name} ({owner_address})? {iface_address in owner_address.hosts()}")
+
+    #                     addresses.append((iface, iface_address))
+    #             else:
+    #                 logging.info(f"NetworkInterface '{iface.user_friendly_name}' does not belong to net '{owner.user_friendly_name}'.")
+    #                 warning.append((
+    #                     "Address", f"NetworkInterface '{iface.user_friendly_name}' does not belong to net '{owner.user_friendly_name}'."
+    #                 ))
+
+    #     # Validate Network and Subnets
+    #     net_addr = fix_invalid_address(get_attr(network, ATTR_NET_ADDRESS), network, warning)
+    #     # prepend 0.0.0.0 if starts with / i guess, print a warning
+    #     print(f"{net_addr}\t{network.user_friendly_name}")
+
+    #     net = IPv4Network(net_addr)
+
+    #     if len(subnets) > 0:
+    #         for (obj, sn) in subnets:
+    #             logging.info(f"{sn}\t{obj.user_friendly_name} belongs? {sn.subnet_of(net)}")
+    #             if not sn.subnet_of(net):
+    #                 warning.append((
+    #                     "Subnet", f"Subnet {obj.user_friendly_name} ({sn}) does not belong to net '{network.user_friendly_name}' ({net_addr})."
+    #                 ))
+    #     else:
+    #         print("No subnets found!")
+
+    #     # Validate addresses (again)
+    #     for (obj, addr) in addresses:
+    #         if addr not in net.hosts():
+    #             warning.append((
+    #                 "Address", f"'{obj.user_friendly_name}' [{obj.class_}] ({addr}) does not belong to net '{network.user_friendly_name}' ({net_addr})."
+    #             ))
+    #         logging.info(f"NetworkInterface '{obj.user_friendly_name}' ({addr}) belong to net '{network.user_friendly_name}' ({net_addr})? {addr in net.hosts()}")
+
+    #     warnings.append((network.user_friendly_name, list(set(warning))))
+
+    return warnings
+        
+    
+
+  
+
diff --git a/mc_openapi/doml_mc/xmi_parser/special_parsers.py b/mc_openapi/doml_mc/xmi_parser/special_parsers.py
index 66e9b88b96b9870a930d7096845ed5046578cd32..6509d13e4f6c9a4c6410a60e13072029fbd14820 100644
--- a/mc_openapi/doml_mc/xmi_parser/special_parsers.py
+++ b/mc_openapi/doml_mc/xmi_parser/special_parsers.py
@@ -86,6 +86,12 @@ def init_special_parsers():
             ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb,
             ("commons_FProperty", "value"): parse_fproperty,
         },
+        DOMLVersion.V3_1: {
+            ("infrastructure_Network", "addressRange"): parse_cidr,
+            ("infrastructure_NetworkInterface", "endPoint"): parse_iface_address,
+            ("infrastructure_ComputingNode", "memory_mb"): parse_memory_mb,
+            ("commons_FProperty", "value"): parse_fproperty,
+        }
     }
     for ver in DOMLVersion:
         SpecialParsers[ver] = SpecialParser(MetaModels[ver], attribute_parsers[ver])
diff --git a/mc_openapi/notebooks/net_diagram.ipynb b/mc_openapi/notebooks/net_diagram.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..3f4ba4c94b2f72020349941dcaf747a0a703202c
--- /dev/null
+++ b/mc_openapi/notebooks/net_diagram.ipynb
@@ -0,0 +1,239 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/home/andrea/Projects/piacere-model-checker\n"
+     ]
+    }
+   ],
+   "source": [
+    "%cd ../.."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "Collecting diagrams\n",
+      "  Downloading diagrams-0.23.3-py3-none-any.whl (24.4 MB)\n",
+      "\u001b[2K     \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m24.4/24.4 MB\u001b[0m \u001b[31m14.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm eta \u001b[36m0:00:01\u001b[0m[36m0:00:01\u001b[0m\n",
+      "\u001b[?25hCollecting graphviz<0.21.0,>=0.13.2 (from diagrams)\n",
+      "  Downloading graphviz-0.20.1-py3-none-any.whl (47 kB)\n",
+      "\u001b[2K     \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m47.0/47.0 kB\u001b[0m \u001b[31m16.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n",
+      "\u001b[?25hRequirement already satisfied: jinja2<4.0,>=2.10 in ./.venv/lib64/python3.11/site-packages (from diagrams) (3.1.2)\n",
+      "Collecting typed-ast<2.0.0,>=1.5.4 (from diagrams)\n",
+      "  Downloading typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (860 kB)\n",
+      "\u001b[2K     \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m860.3/860.3 kB\u001b[0m \u001b[31m14.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m31m15.1 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\n",
+      "\u001b[?25hRequirement already satisfied: MarkupSafe>=2.0 in ./.venv/lib64/python3.11/site-packages (from jinja2<4.0,>=2.10->diagrams) (2.1.2)\n",
+      "Installing collected packages: typed-ast, graphviz, diagrams\n",
+      "Successfully installed diagrams-0.23.3 graphviz-0.20.1 typed-ast-1.5.5\n",
+      "\n",
+      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.2.1\u001b[0m\n",
+      "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n",
+      "Note: you may need to restart the kernel to use updated packages.\n"
+     ]
+    }
+   ],
+   "source": [
+    "%pip install diagrams"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 98,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# XMI_PATH = \"./tests/doml/CaseStudies/posidonia.domlx\"\n",
+    "XMI_PATH = \"./tests/doml/CaseStudies/nio3_test_exec_env.domlx\"\n",
+    "\n",
+    "with open(XMI_PATH, 'rb') as f:\n",
+    "    doml_xmi = f.read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 99,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 99,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "from mc_openapi.doml_mc.intermediate_model.metamodel import DOMLVersion\n",
+    "from mc_openapi.doml_mc.main import init_model\n",
+    "\n",
+    "dmc = init_model(doml_xmi, doml_ver=None)\n",
+    "\n",
+    "[x for x in dmc.intermediate_model.values() if x.user_friendly_name and x.user_friendly_name.startswith(\"co1\")]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from diagrams import Diagram, Cluster, Node, Edge\n",
+    "from diagrams.aws.compute import EC2, ECS, AutoScaling, AMI, Compute, EC2Instance, AppRunner\n",
+    "from diagrams.aws.network import CloudFront, APIGateway, TransitGateway\n",
+    "from diagrams.aws.storage import S3\n",
+    "from diagrams.aws.security import Shield, IAMPermissions, IdentityAndAccessManagementIamAddOn as KeyPair\n",
+    "from diagrams.aws.general import General\n",
+    "from diagrams.aws.database import DB\n",
+    "from diagrams.aws.mobile import APIGateway\n",
+    "\n",
+    "from mc_openapi.doml_mc.intermediate_model.doml_element import DOMLElement\n",
+    "\n",
+    "elems = [elem for elem in dmc.intermediate_model.values()]\n",
+    "\n",
+    "common_elems = [e for e in elems if e.class_.startswith(\"commons_\") if e.class_ not in [\"commons_Deployment\", \"commons_Configuration\", \"commons_SProperty\", \"commons_FProperty\", \"commons_BProperty\"]] \n",
+    "deployments = [e for e in elems if e.class_ == \"commons_Deployment\"] \n",
+    "app_elems = [e for e in elems if e.class_.startswith(\"application_\") and e.class_ != \"application_ApplicationLayer\"] \n",
+    "infr_elems = [e for e in elems if e.class_.startswith(\"infrastructure_\") and e.class_ != \"infrastructure_InfrastructureLayer\"] \n",
+    "concr_elems = [e for e in elems if e.class_.startswith(\"concrete_\") and e.class_ != \"concrete_ConcreteInfrastructure\"] \n",
+    "\n",
+    "group_elems = {\"Application\": app_elems, \"Infrastructure\": infr_elems, \"Concretization\": concr_elems}\n",
+    "\n",
+    "def prettify_class_name(name: str):\n",
+    "    _, name = name.split('_', 1)\n",
+    "    return name\n",
+    "\n",
+    "def prettify_assoc_name(assoc: str):\n",
+    "    _, assoc = assoc.split('::', 1)\n",
+    "    return assoc\n",
+    "\n",
+    "def get_component(elem: DOMLElement):\n",
+    "    \n",
+    "    class_name = prettify_class_name(elem.class_)\n",
+    "\n",
+    "    name = f\"{elem.user_friendly_name or ''}\\n({class_name})\"\n",
+    "\n",
+    "    match class_name:\n",
+    "        case \"SoftwareComponent\":\n",
+    "            return Compute(name)\n",
+    "        case \"SoftwareInterface\":\n",
+    "            return APIGateway(name)\n",
+    "        case \"DBMS\":\n",
+    "            return DB(name)\n",
+    "        case \"Network\":\n",
+    "            if address := elem.attributes.get('infrastructure_Network::cidr'):\n",
+    "                name += f'\\nCIDR: {address[0]}'\n",
+    "            return CloudFront(name)\n",
+    "        case \"Subnet\":\n",
+    "            if address := elem.attributes.get('infrastructure_Network::cidr'):\n",
+    "                name += f'\\nCIDR: {address[0]}'\n",
+    "            return CloudFront(name)\n",
+    "        case \"InternetGateway\":\n",
+    "            if address := elem.attributes.get('infrastructure_InternetGateway::address'):\n",
+    "                name += f'\\nIP: {address[0]}'\n",
+    "            return TransitGateway(name)\n",
+    "        case \"NetworkInterface\":\n",
+    "            if address := elem.attributes.get('infrastructure_NetworkInterface::endPoint'):\n",
+    "                name += f'\\nIP: {address[0]}'\n",
+    "            return APIGateway(name)\n",
+    "        case \"Storage\":\n",
+    "            return S3(name)\n",
+    "        case \"VirtualMachine\":\n",
+    "            return EC2(name)\n",
+    "        case \"Container\":\n",
+    "            return ECS(name)\n",
+    "        case \"VMImage\":\n",
+    "            return AMI(name)\n",
+    "        case \"AutoScalingGroup\":\n",
+    "            return AutoScaling(name)\n",
+    "        case \"ComputingGroup\":\n",
+    "            return EC2Instance(name)\n",
+    "        case \"RuntimeProvider\":\n",
+    "            return AppRunner(name)\n",
+    "        case \"KeyPair\":\n",
+    "            return KeyPair(name)\n",
+    "        case \"UserPass\":\n",
+    "            return KeyPair(name)\n",
+    "        case \"SecurityGroup\":\n",
+    "            return Shield(name)\n",
+    "        case \"Rule\":\n",
+    "            return IAMPermissions(name)\n",
+    "        case _:\n",
+    "            return General(name)\n",
+    "        \n",
+    "graph_attr = {\n",
+    "    \"pad\": \"1pt\"\n",
+    "}\n",
+    "\n",
+    "HIGHLIGHT_CONNECTIONS = [\n",
+    "    'infrastructure_NetworkInterface::belongsTo'\n",
+    "]\n",
+    "\n",
+    "with Diagram(\"DOML Model\", show=True, outformat=\"svg\", direction=\"TB\", graph_attr=graph_attr) as diagram:\n",
+    "    cached_nodes: dict[str, Node] = {}\n",
+    "    for gk, gv in group_elems.items():\n",
+    "        with Cluster(gk):\n",
+    "            cached_nodes |= {e.id_: get_component(e) for e in gv}\n",
+    "    \n",
+    "    # Dont group common elements\n",
+    "    cached_nodes |= {e.id_: get_component(e) for e in common_elems}\n",
+    "\n",
+    "    for groups in group_elems.values():\n",
+    "        for elem in groups:\n",
+    "            for assoc_k, assocs_v in elem.associations.items():\n",
+    "                for assoc in assocs_v:\n",
+    "                    if (start := cached_nodes.get(elem.id_)) and (end := cached_nodes.get(assoc)):\n",
+    "                        if assoc_k in HIGHLIGHT_CONNECTIONS:\n",
+    "                                start >> Edge(label=prettify_assoc_name(assoc_k), color='green', style=\"bold\") >> end\n",
+    "                        elif 'maps' in assoc_k:\n",
+    "                            start >> Edge(label=prettify_assoc_name(assoc_k), style=\"bold\") >> end\n",
+    "                        else:\n",
+    "                            start >> end\n",
+    "\n",
+    "    for dep in deployments:\n",
+    "        for _component in dep.associations.get('commons_Deployment::component'):\n",
+    "            for _node in dep.associations.get('commons_Deployment::node'):\n",
+    "                 if (start := cached_nodes.get(_component)) and (end := cached_nodes.get(_node)):\n",
+    "                        start >> Edge(style=\"bold\") >> end\n"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": ".venv",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.11.4"
+  },
+  "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mc_openapi/notebooks/net_validation.ipynb b/mc_openapi/notebooks/net_validation.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..7e432991179e0387f072f7ae99e568493c701e39
--- /dev/null
+++ b/mc_openapi/notebooks/net_validation.ipynb
@@ -0,0 +1,201 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "/home/andrea/Projects/piacere-model-checker\n"
+     ]
+    }
+   ],
+   "source": [
+    "%cd ../.."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# XMI_PATH = \"./tests/doml/CaseStudies/posidonia.domlx\"\n",
+    "# XMI_PATH = \"../piacere-workspace/Playground/NetValidation/test1.domlx\" # Subnets, Ifaces, Gateway\n",
+    "# XMI_PATH = \"./tests/doml/CaseStudies/posidonia_IOP.domlx\" # Subnets, no Gateway\n",
+    "# XMI_PATH = \"../piacere-workspace/Playground/CaseStudies/nio3_test_exec_env.domlx\" # No subnets, Gateway\n",
+    "# XMI_PATH = \"../piacere-workspace/Playground/CaseStudies/posidonia.domlx\"\n",
+    "XMI_PATH = \"../piacere-workspace/Playground/3.1/Ericsson_DOML.domlx\"\n",
+    "\n",
+    "with open(XMI_PATH, 'rb') as f:\n",
+    "    doml_xmi = f.read()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from mc_openapi.doml_mc.main import init_model\n",
+    "\n",
+    "dmc = init_model(doml_xmi, doml_ver=None)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "AddressValueError",
+     "evalue": "Expected 4 octets in 'None'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mAddressValueError\u001b[0m                         Traceback (most recent call last)",
+      "\u001b[1;32m/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb Cell 4\u001b[0m line \u001b[0;36m1\n\u001b[1;32m    <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=99'>100</a>\u001b[0m         \u001b[39mfor\u001b[39;00m (obj, addr) \u001b[39min\u001b[39;00m addresses:\n\u001b[1;32m    <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=100'>101</a>\u001b[0m             \u001b[39mprint\u001b[39m(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mNetworkInterface \u001b[39m\u001b[39m'\u001b[39m\u001b[39m{\u001b[39;00mobj\u001b[39m.\u001b[39muser_friendly_name\u001b[39m}\u001b[39;00m\u001b[39m'\u001b[39m\u001b[39m (\u001b[39m\u001b[39m{\u001b[39;00maddr\u001b[39m}\u001b[39;00m\u001b[39m) belong to net \u001b[39m\u001b[39m'\u001b[39m\u001b[39m{\u001b[39;00mnetwork\u001b[39m.\u001b[39muser_friendly_name\u001b[39m}\u001b[39;00m\u001b[39m'\u001b[39m\u001b[39m (\u001b[39m\u001b[39m{\u001b[39;00mnet_addr\u001b[39m}\u001b[39;00m\u001b[39m)? \u001b[39m\u001b[39m{\u001b[39;00maddr\u001b[39m \u001b[39m\u001b[39min\u001b[39;00m\u001b[39m \u001b[39mnet\u001b[39m.\u001b[39mhosts()\u001b[39m}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[0;32m--> <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=104'>105</a>\u001b[0m validate_network_address(dmc)\n",
+      "\u001b[1;32m/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb Cell 4\u001b[0m line \u001b[0;36m6\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=56'>57</a>\u001b[0m addresses: \u001b[39mlist\u001b[39m[\u001b[39mtuple\u001b[39m[DOMLElement, IPv4Address]] \u001b[39m=\u001b[39m []\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=58'>59</a>\u001b[0m \u001b[39m# Add subnets (Networks)\u001b[39;00m\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=59'>60</a>\u001b[0m visit_subnet(network, subnets)\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=61'>62</a>\u001b[0m \u001b[39m# pprint(\"SUBNETS:\")\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=62'>63</a>\u001b[0m \u001b[39m# pprint(subnets)\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=63'>64</a>\u001b[0m \n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=64'>65</a>\u001b[0m \u001b[39m# Add addresses (gateways, ifaces)\u001b[39;00m\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=65'>66</a>\u001b[0m \u001b[39mfor\u001b[39;00m gateway \u001b[39min\u001b[39;00m get_assocs(network, ASSOC_GATEWAYS):\n",
+      "\u001b[1;32m/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb Cell 4\u001b[0m line \u001b[0;36m4\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=40'>41</a>\u001b[0m subnet \u001b[39m=\u001b[39m im[subnet]\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=41'>42</a>\u001b[0m subnet_addr \u001b[39m=\u001b[39m fix_invalid_address( get_attr(subnet, ATTR_NET_ADDRESS) )\n\u001b[0;32m---> <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=42'>43</a>\u001b[0m acc\u001b[39m.\u001b[39mappend((subnet, IPv4Network(subnet_addr)))\n\u001b[1;32m     <a href='vscode-notebook-cell:/home/andrea/Projects/piacere-model-checker/mc_openapi/notebooks/net_validation.ipynb#W3sZmlsZQ%3D%3D?line=43'>44</a>\u001b[0m visit_subnet(subnet, acc)\n",
+      "File \u001b[0;32m/usr/lib64/python3.11/ipaddress.py:1512\u001b[0m, in \u001b[0;36mIPv4Network.__init__\u001b[0;34m(self, address, strict)\u001b[0m\n\u001b[1;32m   1476\u001b[0m \u001b[39m\u001b[39m\u001b[39m\"\"\"Instantiate a new IPv4 network object.\u001b[39;00m\n\u001b[1;32m   1477\u001b[0m \n\u001b[1;32m   1478\u001b[0m \u001b[39mArgs:\u001b[39;00m\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m   1508\u001b[0m \u001b[39m      supplied.\u001b[39;00m\n\u001b[1;32m   1509\u001b[0m \u001b[39m\"\"\"\u001b[39;00m\n\u001b[1;32m   1510\u001b[0m addr, mask \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_split_addr_prefix(address)\n\u001b[0;32m-> 1512\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mnetwork_address \u001b[39m=\u001b[39m IPv4Address(addr)\n\u001b[1;32m   1513\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39mnetmask, \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_prefixlen \u001b[39m=\u001b[39m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_make_netmask(mask)\n\u001b[1;32m   1514\u001b[0m packed \u001b[39m=\u001b[39m \u001b[39mint\u001b[39m(\u001b[39mself\u001b[39m\u001b[39m.\u001b[39mnetwork_address)\n",
+      "File \u001b[0;32m/usr/lib64/python3.11/ipaddress.py:1315\u001b[0m, in \u001b[0;36mIPv4Address.__init__\u001b[0;34m(self, address)\u001b[0m\n\u001b[1;32m   1313\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39m'\u001b[39m\u001b[39m/\u001b[39m\u001b[39m'\u001b[39m \u001b[39min\u001b[39;00m addr_str:\n\u001b[1;32m   1314\u001b[0m     \u001b[39mraise\u001b[39;00m AddressValueError(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mUnexpected \u001b[39m\u001b[39m'\u001b[39m\u001b[39m/\u001b[39m\u001b[39m'\u001b[39m\u001b[39m in \u001b[39m\u001b[39m{\u001b[39;00maddress\u001b[39m!r}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[0;32m-> 1315\u001b[0m \u001b[39mself\u001b[39m\u001b[39m.\u001b[39m_ip \u001b[39m=\u001b[39m \u001b[39mself\u001b[39;49m\u001b[39m.\u001b[39;49m_ip_int_from_string(addr_str)\n",
+      "File \u001b[0;32m/usr/lib64/python3.11/ipaddress.py:1202\u001b[0m, in \u001b[0;36m_BaseV4._ip_int_from_string\u001b[0;34m(cls, ip_str)\u001b[0m\n\u001b[1;32m   1200\u001b[0m octets \u001b[39m=\u001b[39m ip_str\u001b[39m.\u001b[39msplit(\u001b[39m'\u001b[39m\u001b[39m.\u001b[39m\u001b[39m'\u001b[39m)\n\u001b[1;32m   1201\u001b[0m \u001b[39mif\u001b[39;00m \u001b[39mlen\u001b[39m(octets) \u001b[39m!=\u001b[39m \u001b[39m4\u001b[39m:\n\u001b[0;32m-> 1202\u001b[0m     \u001b[39mraise\u001b[39;00m AddressValueError(\u001b[39m\"\u001b[39m\u001b[39mExpected 4 octets in \u001b[39m\u001b[39m%r\u001b[39;00m\u001b[39m\"\u001b[39m \u001b[39m%\u001b[39m ip_str)\n\u001b[1;32m   1204\u001b[0m \u001b[39mtry\u001b[39;00m:\n\u001b[1;32m   1205\u001b[0m     \u001b[39mreturn\u001b[39;00m \u001b[39mint\u001b[39m\u001b[39m.\u001b[39mfrom_bytes(\u001b[39mmap\u001b[39m(\u001b[39mcls\u001b[39m\u001b[39m.\u001b[39m_parse_octet, octets), \u001b[39m'\u001b[39m\u001b[39mbig\u001b[39m\u001b[39m'\u001b[39m)\n",
+      "\u001b[0;31mAddressValueError\u001b[0m: Expected 4 octets in 'None'"
+     ]
+    }
+   ],
+   "source": [
+    "from pprint import pprint\n",
+    "from mc_openapi.doml_mc.intermediate_model import DOMLElement\n",
+    "from mc_openapi.doml_mc.mc import ModelChecker\n",
+    "\n",
+    "from ipaddress import IPv4Address, IPv4Network\n",
+    "\n",
+    "BASE_ADDR = '0.0.0.0'\n",
+    "\n",
+    "ASSOC_SUBNETS = 'infrastructure_Network::subnets'\n",
+    "ASSOC_GATEWAYS = 'infrastructure_Network::gateways'\n",
+    "ASSOC_IFACE_NET = 'infrastructure_NetworkInterface::belongsTo'\n",
+    "\n",
+    "ATTR_NET_ADDRESS = 'infrastructure_Network::cidr' # not here anymore\n",
+    "ATTR_GATEWAY_ADDRESS = 'infrastructure_InternetGateway::address'\n",
+    "ATTR_IFACE_ADDRESS = 'infrastructure_NetworkInterface::endPoint'\n",
+    "\n",
+    "def get_attr(elem: DOMLElement, attr_id: str):\n",
+    "    if elem := elem.attributes.get(attr_id):\n",
+    "        return elem[0]\n",
+    "    return None\n",
+    "    \n",
+    "def get_assocs(elem: DOMLElement, assoc_id: str):\n",
+    "    return elem.associations.get(assoc_id, [])\n",
+    "\n",
+    "def validate_network_address(dmc: ModelChecker):\n",
+    "    im = dmc.intermediate_model\n",
+    "\n",
+    "    networks = [e for e in im.values() if e.class_ == 'infrastructure_Network']\n",
+    "    ifaces = [e for e in im.values() if e.class_ == 'infrastructure_NetworkInterface']\n",
+    "    subnets = [e for e in im.values() if e.class_ == 'infrastructure_Subnet']\n",
+    "\n",
+    "# Network/24\n",
+    "#   Subnet/28\n",
+    "#   Subnet/30\n",
+    "#   Address\n",
+    "#   Address\n",
+    "\n",
+    "    def visit_subnet(net: DOMLElement, acc: list):\n",
+    "        \"\"\"Recursively navigate subnets to populate the `acc` list with all the subnet in a network.\"\"\"\n",
+    "        for subnet in get_assocs(net, ASSOC_SUBNETS):\n",
+    "            subnet = im[subnet]\n",
+    "            subnet_addr = fix_invalid_address( get_attr(subnet, ATTR_NET_ADDRESS) )\n",
+    "            acc.append((subnet, IPv4Network(subnet_addr)))\n",
+    "            visit_subnet(subnet, acc)\n",
+    "\n",
+    "    def fix_invalid_address(address: any):\n",
+    "        if isinstance(address, str) and address.startswith('/'):\n",
+    "            return f\"{BASE_ADDR}{address}\"\n",
+    "\n",
+    "        return address\n",
+    "\n",
+    "\n",
+    "    for network in networks:\n",
+    "        # Tuple(elem, cidr)\n",
+    "        subnets: list[tuple[DOMLElement, IPv4Network]] = []\n",
+    "        # Tuple(elem, address)\n",
+    "        addresses: list[tuple[DOMLElement, IPv4Address]] = []\n",
+    "\n",
+    "        # Add subnets (Networks)\n",
+    "        visit_subnet(network, subnets)\n",
+    "\n",
+    "        # pprint(\"SUBNETS:\")\n",
+    "        # pprint(subnets)\n",
+    "\n",
+    "        # Add addresses (gateways, ifaces)\n",
+    "        for gateway in get_assocs(network, ASSOC_GATEWAYS):\n",
+    "            gateway = im[gateway]\n",
+    "            if gateway_address := get_attr(gateway, ATTR_GATEWAY_ADDRESS):\n",
+    "                addresses.append((gateway, IPv4Address(gateway_address)))\n",
+    "\n",
+    "        for iface in ifaces:\n",
+    "            if owner_id := get_assocs(iface, ASSOC_IFACE_NET):\n",
+    "                owner = im[list(owner_id)[0]]\n",
+    "                if owner.id_ in [s.id_ for (s, _) in subnets] + [network.id_]:\n",
+    "                    if ((iface_address := get_attr(iface, ATTR_IFACE_ADDRESS))\n",
+    "                    and (owner_address := get_attr(owner, ATTR_NET_ADDRESS))):\n",
+    "                        owner_address = fix_invalid_address(owner_address)\n",
+    "                        iface_address = IPv4Address(iface_address)\n",
+    "                        owner_address = IPv4Network(owner_address)\n",
+    "                        print(f\"{iface.user_friendly_name} ({iface_address}) belongs to {owner.user_friendly_name} ({owner_address})? {iface_address in owner_address.hosts()}\")\n",
+    "\n",
+    "                        addresses.append((iface, iface_address))\n",
+    "                else:\n",
+    "                    print(f\"NetworkInterface '{iface.user_friendly_name}' does not belong to net '{owner.user_friendly_name}'.\")\n",
+    "\n",
+    "        # Validate Network and Subnets\n",
+    "        net_addr = fix_invalid_address( get_attr(network, ATTR_NET_ADDRESS) )\n",
+    "        # prepend 0.0.0.0 if starts with / i guess, print a warning\n",
+    "        print(f\"{net_addr}\\t{network.user_friendly_name}\")\n",
+    "\n",
+    "        net = IPv4Network(net_addr)\n",
+    "\n",
+    "        if len(subnets) > 0:\n",
+    "            for (obj, sn) in subnets:\n",
+    "                print(f\"{sn}\\t{obj.user_friendly_name} belongs? {sn.subnet_of(net)}\")\n",
+    "        else:\n",
+    "            print(\"No subnets!\")\n",
+    "\n",
+    "        # Validate addresses (again)\n",
+    "        for (obj, addr) in addresses:\n",
+    "            print(f\"NetworkInterface '{obj.user_friendly_name}' ({addr}) belong to net '{network.user_friendly_name}' ({net_addr})? {addr in net.hosts()}\")\n",
+    "\n",
+    "  \n",
+    "\n",
+    "validate_network_address(dmc)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": ".venv",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.11.5"
+  },
+  "orig_nbformat": 4
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/tests/domlr/example_single_req_v3.0.domlr b/tests/domlr/example_single_req_v3.0.domlr
new file mode 100644
index 0000000000000000000000000000000000000000..8adb15392a464475797d6f33a5b05781b3c7f044
--- /dev/null
+++ b/tests/domlr/example_single_req_v3.0.domlr
@@ -0,0 +1,18 @@
+# vm, iface = get_consts(smtsorts, ["vm", "iface"])
+# return And(
+#     smtenc.element_class_fun(vm) == smtenc.classes["infrastructure_VirtualMachine"],
+#     Not(
+#         Exists(
+#             [iface],
+#             ENCODINGS.association_rel(vm, smtenc.associations["infrastructure_ComputingNode::ifaces"], iface)
+#         )
+#     )
+# )
+
+-   "All VMs have at least one interface 1"
+    vm is class infrastructure.VirtualMachine
+    and
+    not exists iface (
+        vm has abstract.Node.ifaces iface
+    )
+    error: "VM {vm} has no associated interface."