Commit d246c96b authored by Javier Velázquez's avatar Javier Velázquez
Browse files

Merge branch 'feat/4-challenge-4-l3vpn-support' into 'develop'

Merge feat/4-challenge-4-l3vpn-support

See merge request !9
parents 952b856b 8cef7eeb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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

+159 −69
Original line number Diff line number Diff line
@@ -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

@@ -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.

@@ -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
@@ -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
@@ -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"),
@@ -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

@@ -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))
@@ -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
@@ -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]
@@ -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):
@@ -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
+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}
                                    }]}}}
                                }
                            }
                        ]
                    }
                }
            ]
        }
    }
}