diff --git a/src/Constants.py b/src/Constants.py index fee596b01cf9181bfa58333ac5d216b742a1b07c..b05deea6ed43789881f0a8d2d70e4a42d6e28cee 100644 --- a/src/Constants.py +++ b/src/Constants.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This file is an original contribution from Telefonica Innovación Digital S.L. +# This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os, json @@ -48,12 +48,16 @@ PCE_EXTERNAL = False # Controller Flags # If True, config is not sent to controllers DUMMY_MODE = False + +#####TERAFLOW##### # Teraflow IP TFS_IP = ips.get('TFS_IP') -UPLOAD_TYPE = "NBI" # "WEBUI" or "NBI" +UPLOAD_TYPE = "WEBUI" # "WEBUI" or "NBI" NBI_L2_PATH = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" # Flag to determine if additional L2VPN configuration support is required for deploying L2VPNs with path selection TFS_L2VPN_SUPPORT = False + +#####IXIA##### # IXIA NEII IP IXIA_IP = ips.get('IXIA_IP') diff --git a/src/network_slice_controller.py b/src/network_slice_controller.py index 55a338962c6f8165775ee8585bc823b2c216e264..34697b39e404e43a72c76499f65b82b8a9e9b94e 100644 --- a/src/network_slice_controller.py +++ b/src/network_slice_controller.py @@ -302,10 +302,12 @@ class NSController: if UPLOAD_TYPE == "WEBUI": response = tfs_connector().webui_post(self.tfs_ip, requests) elif UPLOAD_TYPE == "NBI": - response = tfs_connector().nbi_post(self.tfs_ip, requests, self.path) + for intent in requests["services"]: + # Send each separate NBI request + response = tfs_connector().nbi_post(self.tfs_ip, intent, self.path) - if not response.ok: - return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") + if not response.ok: + return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") # For deploying an L2VPN with path selection (not supported by Teraflow) if self.need_l2vpn_support: @@ -855,23 +857,11 @@ class NSController: # Extract QoS Profile from intent QoSProfile = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["id"] - vlan_value = 0 - - # Load L2VPN service template - self.__load_template(2, os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json")) - tfs_request = json.loads(str(self.__teraflow_template))["services"][0] - - # Generate unique service UUID - tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) - - # Configure service endpoints - for endpoint in tfs_request["service_endpoint_ids"]: - endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id - endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if self.answer[self.subnet]["QoS Requirements"] = [] - # Add service constraints + + # Populate response with QoS requirements and VLAN from intent for i, constraint in enumerate(ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"]): bound = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["bound"] metric_type = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-type"] @@ -883,26 +873,65 @@ class NSController: } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) - tfs_request["service_constraints"].append(service_constraint) - - # Add configuration rules - for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): - router_id = origin_router_id if i == 1 else destination_router_id - router_if = origin_router_if if i == 1 else destination_router_if - resource_value = config_rule["custom"]["resource_value"] + + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"] + self.answer[self.subnet]["VLAN"] = vlan_value - sdp_index = i - 1 - vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] - if vlan_value: - resource_value["vlan_id"] = int(vlan_value) - resource_value["circuit_id"] = vlan_value - resource_value["remote_router"] = destination_router_id if i == 1 else origin_router_id - resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) - config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" + if UPLOAD_TYPE == "WEBUI": + # Load L2VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "L2-VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template))["services"][0] + + # Generate unique service UUID + tfs_request["service_id"]["service_uuid"]["uuid"] += "-" + str(int(datetime.now().timestamp() * 1e7)) + + # Configure service endpoints + for endpoint in tfs_request["service_endpoint_ids"]: + endpoint["device_id"]["device_uuid"]["uuid"] = origin_router_id if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_id + endpoint["endpoint_uuid"]["uuid"] = origin_router_if if endpoint is tfs_request["service_endpoint_ids"][0] else destination_router_if + + # Add service constraints + for constraint in self.answer[self.subnet]["QoS Requirements"]: + tfs_request["service_constraints"].append({"custom": constraint}) + + # Add configuration rules + for i, config_rule in enumerate(tfs_request["service_config"]["config_rules"][1:], start=1): + router_id = origin_router_id if i == 1 else destination_router_id + router_if = origin_router_if if i == 1 else destination_router_if + resource_value = config_rule["custom"]["resource_value"] + + sdp_index = i - 1 + vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"] + if vlan_value: + resource_value["vlan_id"] = int(vlan_value) + resource_value["circuit_id"] = vlan_value + resource_value["remote_router"] = destination_router_id if i == 1 else origin_router_id + resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) + config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" + + elif UPLOAD_TYPE == "NBI": + + # Load IETF L2VPN service template + self.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template_empty.json")) + tfs_request = json.loads(str(self.__teraflow_template)) + + # Generate service UUID + full_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["id"] + uuid_only = full_id.split("slice-service-")[-1] + tfs_request["ietf-l2vpn-svc:vpn-service"][0]["vpn-id"] = uuid_only + + # Configure service endpoints + for site in tfs_request["ietf-l2vpn-svc:vpn-service"][0]["site"]: + if site is tfs_request["ietf-l2vpn-svc:vpn-service"][0]["site"][0]: + site["site-id"] = origin_router_id + site["site-location"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["node-id"] + site["site-network-access"]["interface"]["ip-address"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["sdp-ip-address"] + else: + site["site-id"] = destination_router_id + site["site-location"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["node-id"] + site["site-network-access"]["interface"]["ip-address"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["sdp-ip-address"] - # Log and store VLAN information logging.info(f"L2VPN Intent realized\n") - self.answer[self.subnet]["VLAN"] = vlan_value return tfs_request def __tfs_l2vpn_support(self, requests): @@ -994,7 +1023,7 @@ class NSController: dict: A TeraFlow service request for L3VPN configuration. """ # Hardcoded router endpoints - # TODO should be dynamically determined + # TODO (should be dynamically determined) origin_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] origin_router_if = '0/0/0-GigabitEthernet0/0/0/0' destination_router_id = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][1]["attachment-circuits"]["attachment-circuit"][0]["sdp-peering"]["peer-sap-id"] diff --git a/src/templates/ietfL2VPN_template.json b/src/templates/ietfL2VPN_template_empty.json similarity index 58% rename from src/templates/ietfL2VPN_template.json rename to src/templates/ietfL2VPN_template_empty.json index 6430e40b261fc21578038d8a0b18d5eb2fef3088..d7d6be05fc6a78f2ac3e8acaebae9410fd97905a 100644 --- a/src/templates/ietfL2VPN_template.json +++ b/src/templates/ietfL2VPN_template_empty.json @@ -1,29 +1,27 @@ { "ietf-l2vpn-svc:vpn-service": [ { - "vpn-id": "11327140-7361-41b3-aa45-e84a7fb40be9", + "vpn-id": "", "customer-name": "osm", "vpn-svc-type": "vpws", "svc-topo": "any-to-any", "site": [ { - "site-id": "1.1.1.1", - "site-role": "hub", - "site-location": "CU-N2", + "site-id": "", + "site-location": "", "site-network-access": { "interface": { - "ip-address": "10.60.11.3", + "ip-address": "", "encapsulation": "ethernet" } } }, { - "site-id": "3.3.3.3", - "site-role": "spoke", - "site-location": "AMF-N2", + "site-id": "", + "site-location": "", "site-network-access": { "interface": { - "ip-address": "10.60.60.105", + "ip-address": "", "encapsulation": "ethernet" } } diff --git a/src/templates/ietfL3VPN_template.json b/src/templates/ietfL3VPN_template.json deleted file mode 100644 index 07ffbe91b29addee98b3ac390076a581916038d5..0000000000000000000000000000000000000000 --- a/src/templates/ietfL3VPN_template.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "ietf-l3vpn-svc:l3vpn-svc": { - "sites": { - "site": [ - { - "devices": { - "device": [ - { - "device-id": "4.4.4.4", - "location": "router4" - } - ] - }, - "locations": { - "location": [ - { - "location-id": "router4" - } - ] - }, - "management": { - "type": "ietf-l3vpn-svc:provider-managed" - }, - "routing-protocols": { - "routing-protocol": [ - { - "static": { - "cascaded-lan-prefixes": { - "ipv4-lan-prefixes": [ - { - "lan": "4.4.4.4/24", - "lan-tag": "100", - "next-hop": "2.2.2.2" - } - ] - } - }, - "type": "ietf-l3vpn-svc:static" - } - ] - }, - "site-id": "site_router4", - "site-network-accesses": { - "site-network-access": [ - { - "device-reference": "4.4.4.4", - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "customer-address": "2.2.2.2", - "prefix-length": "24", - "provider-address": "4.4.4.4" - } - } - }, - "service": { - "qos": { - "qos-profile": { - "classes": { - "class": [ - { - "bandwidth": { - "guaranteed-bw-percent": 100 - }, - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": { - "latency-boundary": 20 - } - } - ] - } - } - }, - "svc-input-bandwidth": 5000000000, - "svc-mtu": 1500, - "svc-output-bandwidth": 1000000000 - }, - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "vpn-attachment": { - "site-role": "ietf-l3vpn-svc:hub-role", - "vpn-id": "vpn-example" - } - } - ] - } - }, - { - "devices": { - "device": [ - { - "device-id": "5.5.5.5", - "location": "router5" - } - ] - }, - "locations": { - "location": [ - { - "location-id": "router5" - } - ] - }, - "management": { - "type": "ietf-l3vpn-svc:provider-managed" - }, - "routing-protocols": { - "routing-protocol": [ - { - "static": { - "cascaded-lan-prefixes": { - "ipv4-lan-prefixes": [ - { - "lan": "5.5.5.5/24", - "lan-tag": "200", - "next-hop": "2.2.2.2" - } - ] - } - }, - "type": "ietf-l3vpn-svc:static" - } - ] - }, - "site-id": "site_router5", - "site-network-accesses": { - "site-network-access": [ - { - "device-reference": "5.5.5.5", - "ip-connection": { - "ipv4": { - "address-allocation-type": "ietf-l3vpn-svc:static-address", - "addresses": { - "customer-address": "2.2.2.2", - "prefix-length": "24", - "provider-address": "5.5.5.5" - } - } - }, - "service": { - "qos": { - "qos-profile": { - "classes": { - "class": [ - { - "bandwidth": { - "guaranteed-bw-percent": 100 - }, - "class-id": "qos-realtime", - "direction": "ietf-l3vpn-svc:both", - "latency": { - "latency-boundary": 10 - } - } - ] - } - } - }, - "svc-input-bandwidth": 1000000000, - "svc-mtu": 1500, - "svc-output-bandwidth": 5000000000 - }, - "site-network-access-type": "ietf-l3vpn-svc:multipoint", - "vpn-attachment": { - "site-role": "ietf-l3vpn-svc:spoke-role", - "vpn-id": "vpn-example" - } - } - ] - } - } - ] - }, - "vpn-services": { - "vpn-service": [ - { - "vpn-id": "vpn-example" - } - ] - } - } - } - \ No newline at end of file