Loading src/Constants.py +4 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ import logging, os, json # Default logging level DEFAULT_LOGGING_LEVEL = logging.DEBUG DEFAULT_LOGGING_LEVEL = logging.INFO # Default port for NSC deployment NSC_PORT = 8081 Loading Loading @@ -47,10 +47,11 @@ PCE_EXTERNAL = False # Controller Flags # If True, config is not sent to controllers DUMMY_MODE = True DUMMY_MODE = False # Teraflow IP TFS_IP = ips.get('TFS_IP') path = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" UPLOAD_TYPE = "NBI" # "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 NEII IP Loading src/helpers.py +28 −6 Original line number Diff line number Diff line Loading @@ -26,18 +26,40 @@ logging.basicConfig( #Teraflow class tfs_connector(): def simple_post(self, tfs_ip, service, path): def webui_post(self, tfs_ip, service): user="admin" password="admin" token="" 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 = 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): token="" user="admin" password="admin" token="" session = requests.Session() session.auth = (user, password) url = f'http://{tfs_ip}/{path}' logging.info(service) headers = {'Content-Type': 'application/json'} json_data = json.dumps(service) json_decoded = json_data data = json.dumps(service) logging.debug("Posting to TFS NBI: %s",data) token={'csrf_token':token} response = requests.post(url,headers=headers,data=json_decoded,timeout=60) logging.info(response.text) response = session.post(url,headers=headers,data=data,timeout=60) logging.debug("Http response: %s",response.text) return response #CISCO Loading src/network_slice_controller.py +38 −37 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ import json, time, os, logging, uuid, traceback, sys from datetime import datetime from src.helpers import tfs_connector, cisco_connector from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_IP, TFS_L2VPN_SUPPORT, IXIA_IP, SRC_PATH, TEMPLATES_PATH, DUMMY_MODE, DUMP_TEMPLATES, PLANNER_ENABLED, NRP_ENABLED, path, path_l3 from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_IP, TFS_L2VPN_SUPPORT, IXIA_IP, SRC_PATH, TEMPLATES_PATH, DUMMY_MODE, DUMP_TEMPLATES, PLANNER_ENABLED, NRP_ENABLED, UPLOAD_TYPE, NBI_L2_PATH from src.realizers.ixia.NEII_V4 import NEII_controller from src.planner.planner import Planner Loading @@ -42,7 +42,7 @@ class NSController: - Slice Realization: Convert intents to specific network configurations (L2VPN, L3VPN) """ def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT, path=path): def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT, path=NBI_L2_PATH): """ Initialize the Network Slice Controller. Loading @@ -62,7 +62,6 @@ class NSController: self.controller_type = controller_type self.tfs_ip = tfs_ip self.path = path self.path_l3 = path_l3 self.answer = {} self.cool_answer = {} self.start_time = 0 Loading Loading @@ -300,7 +299,10 @@ class NSController: # Optional: Upload template to Teraflow if not DUMMY_MODE: if self.controller_type == "TFS": response = tfs_connector().simple_post(self.tfs_ip, requests, self.path) 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) if not response.ok: return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") Loading Loading @@ -494,7 +496,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 @@ -825,6 +826,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 @@ -847,27 +849,26 @@ 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 = '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"] # 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 Loading Loading @@ -993,7 +994,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 +31 −35 Original line number Diff line number Diff line { "l2vpn": { "vpn-services": { "vpn-service": [ "ietf-l2vpn-svc:vpn-service": [ { "vpn-id": 100, "name": "VPN_L2_Example", "vpn-type": "point-to-point", "vpn-id": "11327140-7361-41b3-aa45-e84a7fb40be9", "customer-name": "osm", "vpn-svc-type": "vpws", "svc-topo": "any-to-any", "site": [ { "site-id": 1, "site-id": "1.1.1.1", "site-role": "hub", "site-location": "R4", "site-location": "CU-N2", "site-network-access": { "interface": { "ip-address": "4.4.4.4", "ip-address": "10.60.11.3", "encapsulation": "ethernet" } } }, { "site-id": 2, "site-id": "3.3.3.3", "site-role": "spoke", "site-location": "R5", "site-location": "AMF-N2", "site-network-access": { "interface": { "ip-address": "5.5.5.5", "ip-address": "10.60.60.105", "encapsulation": "ethernet" } } Loading @@ -33,6 +32,3 @@ } ] } } } No newline at end of file Loading
src/Constants.py +4 −3 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ import logging, os, json # Default logging level DEFAULT_LOGGING_LEVEL = logging.DEBUG DEFAULT_LOGGING_LEVEL = logging.INFO # Default port for NSC deployment NSC_PORT = 8081 Loading Loading @@ -47,10 +47,11 @@ PCE_EXTERNAL = False # Controller Flags # If True, config is not sent to controllers DUMMY_MODE = True DUMMY_MODE = False # Teraflow IP TFS_IP = ips.get('TFS_IP') path = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" UPLOAD_TYPE = "NBI" # "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 NEII IP Loading
src/helpers.py +28 −6 Original line number Diff line number Diff line Loading @@ -26,18 +26,40 @@ logging.basicConfig( #Teraflow class tfs_connector(): def simple_post(self, tfs_ip, service, path): def webui_post(self, tfs_ip, service): user="admin" password="admin" token="" 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 = 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): token="" user="admin" password="admin" token="" session = requests.Session() session.auth = (user, password) url = f'http://{tfs_ip}/{path}' logging.info(service) headers = {'Content-Type': 'application/json'} json_data = json.dumps(service) json_decoded = json_data data = json.dumps(service) logging.debug("Posting to TFS NBI: %s",data) token={'csrf_token':token} response = requests.post(url,headers=headers,data=json_decoded,timeout=60) logging.info(response.text) response = session.post(url,headers=headers,data=data,timeout=60) logging.debug("Http response: %s",response.text) return response #CISCO Loading
src/network_slice_controller.py +38 −37 Original line number Diff line number Diff line Loading @@ -17,7 +17,7 @@ import json, time, os, logging, uuid, traceback, sys from datetime import datetime from src.helpers import tfs_connector, cisco_connector from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_IP, TFS_L2VPN_SUPPORT, IXIA_IP, SRC_PATH, TEMPLATES_PATH, DUMMY_MODE, DUMP_TEMPLATES, PLANNER_ENABLED, NRP_ENABLED, path, path_l3 from src.Constants import DEFAULT_LOGGING_LEVEL, TFS_IP, TFS_L2VPN_SUPPORT, IXIA_IP, SRC_PATH, TEMPLATES_PATH, DUMMY_MODE, DUMP_TEMPLATES, PLANNER_ENABLED, NRP_ENABLED, UPLOAD_TYPE, NBI_L2_PATH from src.realizers.ixia.NEII_V4 import NEII_controller from src.planner.planner import Planner Loading @@ -42,7 +42,7 @@ class NSController: - Slice Realization: Convert intents to specific network configurations (L2VPN, L3VPN) """ def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT, path=path): def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT, path=NBI_L2_PATH): """ Initialize the Network Slice Controller. Loading @@ -62,7 +62,6 @@ class NSController: self.controller_type = controller_type self.tfs_ip = tfs_ip self.path = path self.path_l3 = path_l3 self.answer = {} self.cool_answer = {} self.start_time = 0 Loading Loading @@ -300,7 +299,10 @@ class NSController: # Optional: Upload template to Teraflow if not DUMMY_MODE: if self.controller_type == "TFS": response = tfs_connector().simple_post(self.tfs_ip, requests, self.path) 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) if not response.ok: return self.__send_response(False, code=response.status_code, message=f"Teraflow upload failed. Response: {response.text}") Loading Loading @@ -494,7 +496,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 @@ -825,6 +826,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 @@ -847,27 +849,26 @@ 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 = '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"] # 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 Loading Loading @@ -993,7 +994,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 +31 −35 Original line number Diff line number Diff line { "l2vpn": { "vpn-services": { "vpn-service": [ "ietf-l2vpn-svc:vpn-service": [ { "vpn-id": 100, "name": "VPN_L2_Example", "vpn-type": "point-to-point", "vpn-id": "11327140-7361-41b3-aa45-e84a7fb40be9", "customer-name": "osm", "vpn-svc-type": "vpws", "svc-topo": "any-to-any", "site": [ { "site-id": 1, "site-id": "1.1.1.1", "site-role": "hub", "site-location": "R4", "site-location": "CU-N2", "site-network-access": { "interface": { "ip-address": "4.4.4.4", "ip-address": "10.60.11.3", "encapsulation": "ethernet" } } }, { "site-id": 2, "site-id": "3.3.3.3", "site-role": "spoke", "site-location": "R5", "site-location": "AMF-N2", "site-network-access": { "interface": { "ip-address": "5.5.5.5", "ip-address": "10.60.60.105", "encapsulation": "ethernet" } } Loading @@ -33,6 +32,3 @@ } ] } } } No newline at end of file