Loading src/Constants.py +6 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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') Loading src/network_slice_controller.py +64 −35 Original line number Diff line number Diff line Loading @@ -302,7 +302,9 @@ 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}") Loading Loading @@ -855,9 +857,27 @@ 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 self.answer[self.subnet]["QoS Requirements"] = [] # 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"] metric_unit = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-unit"] service_constraint ={ "custom": { "constraint_type": f"{metric_type}[{metric_unit}]", "constraint_value": f"{bound}" } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) 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 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] Loading @@ -870,20 +890,9 @@ class NSController: 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 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"] metric_unit = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-unit"] service_constraint ={ "custom": { "constraint_type": f"{metric_type}[{metric_unit}]", "constraint_value": f"{bound}" } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) tfs_request["service_constraints"].append(service_constraint) 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): Loading @@ -900,9 +909,29 @@ class NSController: resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" # Log and store VLAN information 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"] logging.info(f"L2VPN Intent realized\n") self.answer[self.subnet]["VLAN"] = vlan_value return tfs_request def __tfs_l2vpn_support(self, requests): Loading Loading @@ -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"] Loading src/templates/ietfL2VPN_template.json→src/templates/ietfL2VPN_template_empty.json +7 −9 Original line number Diff line number Diff line { "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" } } Loading src/templates/ietfL3VPN_template.jsondeleted 100644 → 0 +0 −184 Original line number Diff line number Diff line { "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 Loading
src/Constants.py +6 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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') Loading
src/network_slice_controller.py +64 −35 Original line number Diff line number Diff line Loading @@ -302,7 +302,9 @@ 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}") Loading Loading @@ -855,9 +857,27 @@ 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 self.answer[self.subnet]["QoS Requirements"] = [] # 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"] metric_unit = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-unit"] service_constraint ={ "custom": { "constraint_type": f"{metric_type}[{metric_unit}]", "constraint_value": f"{bound}" } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) 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 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] Loading @@ -870,20 +890,9 @@ class NSController: 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 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"] metric_unit = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"]["metric-bound"][i]["metric-unit"] service_constraint ={ "custom": { "constraint_type": f"{metric_type}[{metric_unit}]", "constraint_value": f"{bound}" } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) tfs_request["service_constraints"].append(service_constraint) 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): Loading @@ -900,9 +909,29 @@ class NSController: resource_value["ni_name"] = 'ELAN{:s}'.format(str(vlan_value)) config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" # Log and store VLAN information 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"] logging.info(f"L2VPN Intent realized\n") self.answer[self.subnet]["VLAN"] = vlan_value return tfs_request def __tfs_l2vpn_support(self, requests): Loading Loading @@ -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"] Loading
src/templates/ietfL2VPN_template.json→src/templates/ietfL2VPN_template_empty.json +7 −9 Original line number Diff line number Diff line { "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" } } Loading
src/templates/ietfL3VPN_template.jsondeleted 100644 → 0 +0 −184 Original line number Diff line number Diff line { "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