Loading our-temp/ietf-l3vpn-service.jsondeleted 100644 → 0 +0 −83 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]}, "sites": { "site": [ { "site-id": "site_DC1", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": "DC1"}]}, "devices": {"device": [{"device-id": "dc1", "location": "DC1"}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "eth1", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "dc1", "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "192.168.1.1", "customer-address": "192.168.1.10", "prefix-length": 24 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 10}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } }, { "site-id": "site_DC2", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": "DC2"}]}, "devices": {"device": [{"device-id": "dc2", "location": "DC2"}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "eth1", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "dc2", "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"}, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "192.168.2.1", "customer-address": "192.168.2.10", "prefix-length": 24 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 10}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } } ] } } } src/Constants.py +10 −2 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os, json # Default logging level DEFAULT_LOGGING_LEVEL = logging.INFO Loading Loading @@ -44,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/helpers.py +14 −28 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading @@ -17,7 +17,6 @@ import logging, requests, json from netmiko import ConnectHandler from src.Constants import DEFAULT_LOGGING_LEVEL from requests.auth import HTTPBasicAuth # Configure logging to provide clear and informative log messages logging.basicConfig( Loading @@ -31,33 +30,20 @@ class tfs_connector(): user="admin" password="admin" token="" #session = requests.Session() #session.auth = (user, password) #url = f'http://{tfs_ip}/{path}' url_l2 = f'http://{user}:{password}@{tfs_ip}/{path}' #url_l3 = f'http://{user}:{password}@{tfs_ip}/{path_l3}' logging.info(service) #response=session.get(url=url) #for item in response.iter_lines(): # if("csrf_token" in str(item)): # string=str(item).split('<input id="csrf_token" name="csrf_token" type="hidden" value=')[1] # token=string.split(">")[0].strip('"') #logging.debug("csrf token %s",token) #files = {'descriptors': ("data.json", json.dumps(service).encode("utf-8"), "application/json")} headers = {'Content-Type': 'application/json'} json_data = json.dumps(service) #json_url="/home/tfs/nsc-hackfest7/our-temp/ietf-l3vpn-service.json" #with open(json_url, 'r', encoding="UTF-8") as file: # json_data = json.load(file) # logging.debug("this is the JSON data that we have") # logging.debug(json_data) # json_decoded = json.dumps(json_data) json_decoded = json_data session = requests.Session() session.auth = (user, password) url=f'http://{tfs_ip}/webui' response=session.get(url=url) for item in response.iter_lines(): if("csrf_token" in str(item)): string=str(item).split('<input id="csrf_token" name="csrf_token" type="hidden" value=')[1] token=string.split(">")[0].strip('"') logging.debug("csrf token %s",token) files = {'descriptors': ("data.json", json.dumps(service).encode("utf-8"), "application/json")} token={'csrf_token':token} response = requests.post(url_l2, headers=headers, data=json_decoded, timeout=60) logging.info(response.text) #logging.debug("Http response: %s",response.text) response = session.post(url,files=files,data=token,timeout=60) logging.debug("Http response: %s",response.text) return response def nbi_post(self, tfs_ip, service, path): Loading src/network_slice_controller.py +69 −59 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading 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 @@ -496,7 +498,6 @@ class NSController: "setup_time": self.setup_time } # Add slice details to the response logging.info(self.answer) for subnet in self.answer: slice_info = { "id": subnet, Loading Loading @@ -827,6 +828,7 @@ class NSController: logging.warning(f"Unsupported controller: {controller}. Defaulting to TFS L2VPN realization.") realizing_request = self.__tfs_l2vpn(ietf_intent) return realizing_request def __tfs_l2vpn(self, ietf_intent): """ Translate slice intent into a TeraFlow service request. Loading @@ -849,48 +851,17 @@ class NSController: # Hardcoded router endpoints # 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 = 'eth2' origin_router_if = 'eth2' 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"] destination_router_if = '0/0/0-GigabitEthernet0/0/0/0' # 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.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template.json")) tfs_request = json.loads(str(self.__teraflow_template)) 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 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"] # 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.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template.json")) tfs_request = json.loads(str(self.__teraflow_template)) 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 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"] 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"] Loading @@ -902,7 +873,26 @@ class NSController: } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) tfs_request["service_constraints"].append(service_constraint) 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] # 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): Loading @@ -919,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 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 Loading
our-temp/ietf-l3vpn-service.jsondeleted 100644 → 0 +0 −83 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": {"vpn-service": [{"vpn-id": "ietf-l3vpn-svc"}]}, "sites": { "site": [ { "site-id": "site_DC1", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": "DC1"}]}, "devices": {"device": [{"device-id": "dc1", "location": "DC1"}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "eth1", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "dc1", "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:spoke-role"}, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "192.168.1.1", "customer-address": "192.168.1.10", "prefix-length": 24 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 10}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } }, { "site-id": "site_DC2", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": "DC2"}]}, "devices": {"device": [{"device-id": "dc2", "location": "DC2"}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "eth1", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "dc2", "vpn-attachment": {"vpn-id": "ietf-l3vpn-svc", "site-role": "ietf-l3vpn-svc:hub-role"}, "ip-connection": { "ipv4": { "address-allocation-type": "ietf-l3vpn-svc:static-address", "addresses": { "provider-address": "192.168.2.1", "customer-address": "192.168.2.10", "prefix-length": 24 } } }, "service": { "svc-mtu": 1500, "svc-input-bandwidth": 1000000000, "svc-output-bandwidth": 1000000000, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 10}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } } ] } } }
src/Constants.py +10 −2 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading @@ -12,6 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. # This file includes original contributions from Telefonica Innovación Digital S.L. import logging, os, json # Default logging level DEFAULT_LOGGING_LEVEL = logging.INFO Loading Loading @@ -44,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/helpers.py +14 −28 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading @@ -17,7 +17,6 @@ import logging, requests, json from netmiko import ConnectHandler from src.Constants import DEFAULT_LOGGING_LEVEL from requests.auth import HTTPBasicAuth # Configure logging to provide clear and informative log messages logging.basicConfig( Loading @@ -31,33 +30,20 @@ class tfs_connector(): user="admin" password="admin" token="" #session = requests.Session() #session.auth = (user, password) #url = f'http://{tfs_ip}/{path}' url_l2 = f'http://{user}:{password}@{tfs_ip}/{path}' #url_l3 = f'http://{user}:{password}@{tfs_ip}/{path_l3}' logging.info(service) #response=session.get(url=url) #for item in response.iter_lines(): # if("csrf_token" in str(item)): # string=str(item).split('<input id="csrf_token" name="csrf_token" type="hidden" value=')[1] # token=string.split(">")[0].strip('"') #logging.debug("csrf token %s",token) #files = {'descriptors': ("data.json", json.dumps(service).encode("utf-8"), "application/json")} headers = {'Content-Type': 'application/json'} json_data = json.dumps(service) #json_url="/home/tfs/nsc-hackfest7/our-temp/ietf-l3vpn-service.json" #with open(json_url, 'r', encoding="UTF-8") as file: # json_data = json.load(file) # logging.debug("this is the JSON data that we have") # logging.debug(json_data) # json_decoded = json.dumps(json_data) json_decoded = json_data session = requests.Session() session.auth = (user, password) url=f'http://{tfs_ip}/webui' response=session.get(url=url) for item in response.iter_lines(): if("csrf_token" in str(item)): string=str(item).split('<input id="csrf_token" name="csrf_token" type="hidden" value=')[1] token=string.split(">")[0].strip('"') logging.debug("csrf token %s",token) files = {'descriptors': ("data.json", json.dumps(service).encode("utf-8"), "application/json")} token={'csrf_token':token} response = requests.post(url_l2, headers=headers, data=json_decoded, timeout=60) logging.info(response.text) #logging.debug("Http response: %s",response.text) response = session.post(url,files=files,data=token,timeout=60) logging.debug("Http response: %s",response.text) return response def nbi_post(self, tfs_ip, service, path): Loading
src/network_slice_controller.py +69 −59 Original line number Diff line number Diff line # Copyright 2025 Telefonica Innovación Digital S.L. # Copyright 2022-2025 ETSI SDG TeraFlowSDN (TFS) (https://tfs.etsi.org/) # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. Loading 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 @@ -496,7 +498,6 @@ class NSController: "setup_time": self.setup_time } # Add slice details to the response logging.info(self.answer) for subnet in self.answer: slice_info = { "id": subnet, Loading Loading @@ -827,6 +828,7 @@ class NSController: logging.warning(f"Unsupported controller: {controller}. Defaulting to TFS L2VPN realization.") realizing_request = self.__tfs_l2vpn(ietf_intent) return realizing_request def __tfs_l2vpn(self, ietf_intent): """ Translate slice intent into a TeraFlow service request. Loading @@ -849,48 +851,17 @@ class NSController: # Hardcoded router endpoints # 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 = 'eth2' origin_router_if = 'eth2' 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"] destination_router_if = '0/0/0-GigabitEthernet0/0/0/0' # 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.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template.json")) tfs_request = json.loads(str(self.__teraflow_template)) 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 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"] # 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.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL2VPN_template.json")) tfs_request = json.loads(str(self.__teraflow_template)) 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 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"] 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"] Loading @@ -902,7 +873,26 @@ class NSController: } } self.answer[self.subnet]["QoS Requirements"].append(service_constraint["custom"]) tfs_request["service_constraints"].append(service_constraint) 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] # 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): Loading @@ -919,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
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