Loading src/Constants.py +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ DUMMY_MODE = False TFS_IP = ips.get('TFS_IP') UPLOAD_TYPE = "WEBUI" # "WEBUI" or "NBI" NBI_L2_PATH = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" NBI_L3_PATH = "restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" # Flag to determine if additional L2VPN configuration support is required for deploying L2VPNs with path selection TFS_L2VPN_SUPPORT = False Loading src/network_slice_controller.py +159 −69 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, UPLOAD_TYPE, NBI_L2_PATH 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, NBI_L3_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=NBI_L2_PATH): def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT): """ Initialize the Network Slice Controller. Loading @@ -61,7 +61,7 @@ class NSController: """ self.controller_type = controller_type self.tfs_ip = tfs_ip self.path = path self.path = "" self.answer = {} self.cool_answer = {} self.start_time = 0 Loading Loading @@ -442,6 +442,7 @@ class NSController: else: # Select slice service method way = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["service-tags"]["tag-type"]["value"] way = "L3VPN" return self.__select_way(controller=self.controller_type, way=way, ietf_intent=ietf_intent) ### Generic functionalities Loading Loading @@ -639,8 +640,8 @@ class NSController: metrics = { ("uLThptPerSliceSubnet", "MaxThpt"): ("throughput", "kbps"), ("uLLatency",): ("latency", "ms"), ("uLThptPerSliceSubnet", "MaxThpt"): ("one-way-bandwidth", "kbps"), ("uLLatency",): ("one-way-delay-maximum", "milliseconds"), ("EnergyConsumption",): ("energy_consumption", "Joules"), ("EnergyEfficiency",): ("energy_efficiency", "W/bps"), ("CarbonEmissions",): ("carbon_emission", "gCO2eq"), Loading Loading @@ -862,18 +863,32 @@ class NSController: 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"]) slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] # Process metrics for metric in slo_policy.get("metric-bound", []): constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" constraint_value = str(metric["bound"]) self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": constraint_type, "constraint_value": constraint_value }) # Availability if "availability" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "availability[%]", "constraint_value": str(slo_policy["availability"]) }) # MTU if "mtu" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "mtu[bytes]", "constraint_value": str(slo_policy["mtu"]) }) # VLAN 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 Loading Loading @@ -910,7 +925,7 @@ class NSController: config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" elif UPLOAD_TYPE == "NBI": self.path = NBI_L2_PATH # 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)) Loading @@ -921,15 +936,16 @@ class NSController: 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"] sites = tfs_request["ietf-l2vpn-svc:vpn-service"][0]["site"] sdps = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"] for i, site in enumerate(sites): is_origin = (i == 0) router_id = origin_router_id if is_origin else destination_router_id sdp = sdps[0] if is_origin else sdps[1] site["site-id"] = router_id site["site-location"] = sdp["node-id"] site["site-network-access"]["interface"]["ip-address"] = sdp["sdp-ip-address"] logging.info(f"L2VPN Intent realized\n") return tfs_request Loading Loading @@ -1029,6 +1045,43 @@ class NSController: 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.answer[self.subnet]["QoS Requirements"] = [] # Populate response with QoS requirements and VLAN from intent slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] # Process metrics for metric in slo_policy.get("metric-bound", []): constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" constraint_value = str(metric["bound"]) self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": constraint_type, "constraint_value": constraint_value }) # Availability if "availability" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "availability[%]", "constraint_value": str(slo_policy["availability"]) }) # MTU if "mtu" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "mtu[bytes]", "constraint_value": str(slo_policy["mtu"]) }) # VLAN 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 L3VPN service template self.__load_template(2, os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json")) tfs_request = json.loads(str(self.__teraflow_template))["services"][0] Loading @@ -1041,20 +1094,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 @@ -1072,6 +1114,54 @@ 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" elif UPLOAD_TYPE == "NBI": self.path = NBI_L3_PATH # Load IETF L3VPN service template self.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL3VPN_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"] tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["vpn-services"]["vpn-service"][0]["vpn-id"] = full_id # Configure service endpoints for i, site in enumerate(tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["sites"]["site"]): # Determine if origin or destination is_origin = (i == 0) sdp_index = 0 if is_origin else 1 location = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["node-id"] router_id = origin_router_id if is_origin else destination_router_id router_if = origin_router_if if is_origin else destination_router_if # Assign common values site["site-id"] = f"site_{location}" site["locations"]["location"][0]["location-id"] = location site["devices"]["device"][0]["device-id"] = router_id site["devices"]["device"][0]["location"] = location access = site["site-network-accesses"]["site-network-access"][0] access["site-network-access-id"] = router_if access["device-reference"] = router_id access["vpn-attachment"]["vpn-id"] = full_id # Aplicar restricciones QoS for constraint in self.answer[self.subnet]["QoS Requirements"]: ctype = constraint["constraint_type"] cvalue = float(constraint["constraint_value"]) if constraint["constraint_type"].startswith("one-way-bandwidth"): unit = constraint["constraint_type"].split("[")[-1].rstrip("]") multiplier = {"bps": 1, "kbps": 1_000, "Mbps": 1_000_000, "Gbps": 1_000_000_000}.get(unit, 1) value = int(cvalue * multiplier) access["service"]["svc-input-bandwidth"] = value access["service"]["svc-output-bandwidth"] = value elif ctype == "one-way-delay-maximum[milliseconds]": access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["latency"]["latency-boundary"] = int(cvalue) elif ctype == "availability[%]": access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["bandwidth"]["guaranteed-bw-percent"] = int(cvalue) elif ctype == "mtu[bytes]": access["service"]["svc-mtu"] = int(cvalue) logging.info(f"L3VPN Intent realized\n") self.answer[self.subnet]["VLAN"] = vlan_value return tfs_request Loading src/templates/ietfL3VPN_template_empty.json 0 → 100644 +83 −0 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": {"vpn-service": [{"vpn-id": ""}]}, "sites": { "site": [ { "site-id": "", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": ""}]}, "devices": {"device": [{"device-id": "", "location": ""}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "", "vpn-attachment": {"vpn-id": "", "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": 1, "svc-output-bandwidth": 1, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 100}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } }, { "site-id": "", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": ""}]}, "devices": {"device": [{"device-id": "", "location": ""}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "", "vpn-attachment": {"vpn-id": "", "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": 1, "svc-output-bandwidth": 1, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 100}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } } ] } } } Loading
src/Constants.py +1 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ DUMMY_MODE = False TFS_IP = ips.get('TFS_IP') UPLOAD_TYPE = "WEBUI" # "WEBUI" or "NBI" NBI_L2_PATH = "restconf/data/ietf-l2vpn-svc:l2vpn-svc/vpn-services" NBI_L3_PATH = "restconf/data/ietf-l3vpn-svc:l3vpn-svc/vpn-services" # Flag to determine if additional L2VPN configuration support is required for deploying L2VPNs with path selection TFS_L2VPN_SUPPORT = False Loading
src/network_slice_controller.py +159 −69 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, UPLOAD_TYPE, NBI_L2_PATH 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, NBI_L3_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=NBI_L2_PATH): def __init__(self, controller_type = "TFS", tfs_ip=TFS_IP, ixia_ip =IXIA_IP, need_l2vpn_support=TFS_L2VPN_SUPPORT): """ Initialize the Network Slice Controller. Loading @@ -61,7 +61,7 @@ class NSController: """ self.controller_type = controller_type self.tfs_ip = tfs_ip self.path = path self.path = "" self.answer = {} self.cool_answer = {} self.start_time = 0 Loading Loading @@ -442,6 +442,7 @@ class NSController: else: # Select slice service method way = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["service-tags"]["tag-type"]["value"] way = "L3VPN" return self.__select_way(controller=self.controller_type, way=way, ietf_intent=ietf_intent) ### Generic functionalities Loading Loading @@ -639,8 +640,8 @@ class NSController: metrics = { ("uLThptPerSliceSubnet", "MaxThpt"): ("throughput", "kbps"), ("uLLatency",): ("latency", "ms"), ("uLThptPerSliceSubnet", "MaxThpt"): ("one-way-bandwidth", "kbps"), ("uLLatency",): ("one-way-delay-maximum", "milliseconds"), ("EnergyConsumption",): ("energy_consumption", "Joules"), ("EnergyEfficiency",): ("energy_efficiency", "W/bps"), ("CarbonEmissions",): ("carbon_emission", "gCO2eq"), Loading Loading @@ -862,18 +863,32 @@ class NSController: 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"]) slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] # Process metrics for metric in slo_policy.get("metric-bound", []): constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" constraint_value = str(metric["bound"]) self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": constraint_type, "constraint_value": constraint_value }) # Availability if "availability" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "availability[%]", "constraint_value": str(slo_policy["availability"]) }) # MTU if "mtu" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "mtu[bytes]", "constraint_value": str(slo_policy["mtu"]) }) # VLAN 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 Loading Loading @@ -910,7 +925,7 @@ class NSController: config_rule["custom"]["resource_key"] = f"/device[{router_id}]/endpoint[{router_if}]/settings" elif UPLOAD_TYPE == "NBI": self.path = NBI_L2_PATH # 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)) Loading @@ -921,15 +936,16 @@ class NSController: 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"] sites = tfs_request["ietf-l2vpn-svc:vpn-service"][0]["site"] sdps = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"] for i, site in enumerate(sites): is_origin = (i == 0) router_id = origin_router_id if is_origin else destination_router_id sdp = sdps[0] if is_origin else sdps[1] site["site-id"] = router_id site["site-location"] = sdp["node-id"] site["site-network-access"]["interface"]["ip-address"] = sdp["sdp-ip-address"] logging.info(f"L2VPN Intent realized\n") return tfs_request Loading Loading @@ -1029,6 +1045,43 @@ class NSController: 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.answer[self.subnet]["QoS Requirements"] = [] # Populate response with QoS requirements and VLAN from intent slo_policy = ietf_intent["ietf-network-slice-service:network-slice-services"]["slo-sle-templates"]["slo-sle-template"][0]["slo-policy"] # Process metrics for metric in slo_policy.get("metric-bound", []): constraint_type = f"{metric['metric-type']}[{metric['metric-unit']}]" constraint_value = str(metric["bound"]) self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": constraint_type, "constraint_value": constraint_value }) # Availability if "availability" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "availability[%]", "constraint_value": str(slo_policy["availability"]) }) # MTU if "mtu" in slo_policy: self.answer[self.subnet]["QoS Requirements"].append({ "constraint_type": "mtu[bytes]", "constraint_value": str(slo_policy["mtu"]) }) # VLAN 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 L3VPN service template self.__load_template(2, os.path.join(TEMPLATES_PATH, "L3-VPN_template_empty.json")) tfs_request = json.loads(str(self.__teraflow_template))["services"][0] Loading @@ -1041,20 +1094,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 @@ -1072,6 +1114,54 @@ 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" elif UPLOAD_TYPE == "NBI": self.path = NBI_L3_PATH # Load IETF L3VPN service template self.__load_template(2, os.path.join(TEMPLATES_PATH, "ietfL3VPN_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"] tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["vpn-services"]["vpn-service"][0]["vpn-id"] = full_id # Configure service endpoints for i, site in enumerate(tfs_request["ietf-l3vpn-svc:l3vpn-svc"]["sites"]["site"]): # Determine if origin or destination is_origin = (i == 0) sdp_index = 0 if is_origin else 1 location = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["node-id"] router_id = origin_router_id if is_origin else destination_router_id router_if = origin_router_if if is_origin else destination_router_if # Assign common values site["site-id"] = f"site_{location}" site["locations"]["location"][0]["location-id"] = location site["devices"]["device"][0]["device-id"] = router_id site["devices"]["device"][0]["location"] = location access = site["site-network-accesses"]["site-network-access"][0] access["site-network-access-id"] = router_if access["device-reference"] = router_id access["vpn-attachment"]["vpn-id"] = full_id # Aplicar restricciones QoS for constraint in self.answer[self.subnet]["QoS Requirements"]: ctype = constraint["constraint_type"] cvalue = float(constraint["constraint_value"]) if constraint["constraint_type"].startswith("one-way-bandwidth"): unit = constraint["constraint_type"].split("[")[-1].rstrip("]") multiplier = {"bps": 1, "kbps": 1_000, "Mbps": 1_000_000, "Gbps": 1_000_000_000}.get(unit, 1) value = int(cvalue * multiplier) access["service"]["svc-input-bandwidth"] = value access["service"]["svc-output-bandwidth"] = value elif ctype == "one-way-delay-maximum[milliseconds]": access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["latency"]["latency-boundary"] = int(cvalue) elif ctype == "availability[%]": access["service"]["qos"]["qos-profile"]["classes"]["class"][0]["bandwidth"]["guaranteed-bw-percent"] = int(cvalue) elif ctype == "mtu[bytes]": access["service"]["svc-mtu"] = int(cvalue) logging.info(f"L3VPN Intent realized\n") self.answer[self.subnet]["VLAN"] = vlan_value return tfs_request Loading
src/templates/ietfL3VPN_template_empty.json 0 → 100644 +83 −0 Original line number Diff line number Diff line { "ietf-l3vpn-svc:l3vpn-svc": { "vpn-services": {"vpn-service": [{"vpn-id": ""}]}, "sites": { "site": [ { "site-id": "", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": ""}]}, "devices": {"device": [{"device-id": "", "location": ""}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "", "vpn-attachment": {"vpn-id": "", "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": 1, "svc-output-bandwidth": 1, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 100}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } }, { "site-id": "", "management": {"type": "ietf-l3vpn-svc:provider-managed"}, "locations": {"location": [{"location-id": ""}]}, "devices": {"device": [{"device-id": "", "location": ""}]}, "site-network-accesses": { "site-network-access": [ { "site-network-access-id": "", "site-network-access-type": "ietf-l3vpn-svc:multipoint", "device-reference": "", "vpn-attachment": {"vpn-id": "", "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": 1, "svc-output-bandwidth": 1, "qos": {"qos-profile": {"classes": {"class": [{ "class-id": "qos-realtime", "direction": "ietf-l3vpn-svc:both", "latency": {"latency-boundary": 100}, "bandwidth": {"guaranteed-bw-percent": 100} }]}}} } } ] } } ] } } }