Skip to content
network_slice_controller.py 59.3 KiB
Newer Older
Javier Velázquez's avatar
Javier Velázquez committed
        cisco_destiny.execute_commands(commands)

    def __tfs_l2vpn_delete(self):
        """
        Delete L2VPN configurations from Cisco devices.

        This method removes L2VPN configurations from Cisco routers

        Notes:
            - Uses cisco_connector to generate and execute deletion commands
            - Clears Network Interface (NI) settings
        """
        # Delete Source Endpoint Configuration
        source_address = "10.60.125.44"
        cisco_source = cisco_connector(source_address)
        cisco_source.execute_commands(cisco_source.create_command_template_delete())

        # Delete Destination Endpoint Configuration
        destination_address = "10.60.125.45"
        cisco_destiny = cisco_connector(destination_address)
        cisco_destiny.execute_commands(cisco_destiny.create_command_template_delete())
    
    def __tfs_l3vpn(self, ietf_intent):
        """
        Translate L3VPN (Layer 3 Virtual Private Network) intent into a TeraFlow service request.

        Similar to __tfs_l2vpn, but configured for Layer 3 VPN:
        1. Defines endpoint routers
        2. Loads service template
        3. Generates unique service UUID
        4. Configures service endpoints
        5. Adds QoS constraints
        6. Prepares configuration rules for network interfaces

        Args:
            ietf_intent (dict): IETF-formatted network slice intent.

        Returns:
            dict: A TeraFlow service request for L3VPN configuration.
        """
        # 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"]
Javier Velázquez's avatar
Javier Velázquez committed
        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"]
Javier Velázquez's avatar
Javier Velázquez committed
        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
Javier Velázquez's avatar
Javier Velázquez committed
        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]
            
            # 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):
                router_id = origin_router_id if i == 1 else destination_router_id
                router_if = origin_router_if if i == 1 else destination_router_if
                resource_value = config_rule["custom"]["resource_value"]

                sdp_index = i - 1
                vlan_value = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][sdp_index]["service-match-criteria"]["match-criterion"][0]["value"]
                resource_value["router_id"] = destination_router_id if i == 1 else origin_router_id
                resource_value["vlan_id"] = int(vlan_value)
                resource_value["address_ip"] = destination_router_id if i == 1 else origin_router_id
                resource_value["policy_AZ"] = "policyA"
                resource_value["policy_ZA"] = "policyB"
                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)

Javier Velázquez's avatar
Javier Velázquez committed
        logging.info(f"L3VPN Intent realized\n")
        self.answer[self.subnet]["VLAN"] = vlan_value
Javier Velázquez's avatar
Javier Velázquez committed
        return tfs_request

Javier Velázquez's avatar
Javier Velázquez committed
    def __ixia(self, ietf_intent):
        """
        Prepare an Ixia service request based on the IETF intent.
Javier Velázquez's avatar
Javier Velázquez committed
        This method configures an Ixia service request by:
        1. Defining endpoint routers
        2. Loading a service template
        3. Generating a unique service UUID
        4. Configuring service endpoints
        5. Adding QoS constraints
Javier Velázquez's avatar
Javier Velázquez committed
        Args:
            ietf_intent (dict): IETF-formatted network slice intent.
Javier Velázquez's avatar
Javier Velázquez committed
        Returns:
            dict: An Ixia service request for configuration.
        """
        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"])
        self.answer[self.subnet]["VLAN"] = ietf_intent["ietf-network-slice-service:network-slice-services"]["slice-service"][0]["sdps"]["sdp"][0]["service-match-criteria"]["match-criterion"][0]["value"]
        # Extraer la lista de métricas de forma segura
        metric_bounds = ietf_intent.get("ietf-network-slice-service:network-slice-services", {}) \
            .get("slo-sle-templates", {}) \
            .get("slo-sle-template", [{}])[0] \
            .get("slo-policy", {}) \
            .get("metric-bound", [])

        # Inicializar valores
        bandwidth = None
        latency = None
        tolerance = None

        # Asignar valores según el tipo de métrica
        for metric in metric_bounds:
            metric_type = metric.get("metric-type")
            bound = metric.get("bound")

            if metric_type == "one-way-bandwidth":
                bandwidth = bound
            elif metric_type == "one-way-delay-maximum":
                latency = bound
            elif metric_type == "one-way-delay-variation-maximum": 
                tolerance = bound

        # Construcción del diccionario intent
        intent = {
            "src_node_ip": ietf_intent.get("ietf-network-slice-service:network-slice-services", {})
                .get("slice-service", [{}])[0]
                .get("sdps", {}).get("sdp", [{}])[0]
                .get("attachment-circuits", {}).get("attachment-circuit", [{}])[0]
                .get("sdp-peering", {}).get("peer-sap-id"),

            "dst_node_ip": ietf_intent.get("ietf-network-slice-service:network-slice-services", {})
                .get("slice-service", [{}])[0]
                .get("sdps", {}).get("sdp", [{}, {}])[1]
                .get("attachment-circuits", {}).get("attachment-circuit", [{}])[0]
                .get("sdp-peering", {}).get("peer-sap-id"),

            "vlan_id": ietf_intent.get("ietf-network-slice-service:network-slice-services", {})
                .get("slice-service", [{}])[0]
                .get("sdps", {}).get("sdp", [{}])[0]
                .get("service-match-criteria", {}).get("match-criterion", [{}])[0]
                .get("value"),

            "bandwidth": bandwidth,
            "latency": latency,
            "tolerance": tolerance,

            "latency_version": ietf_intent.get("ietf-network-slice-service:network-slice-services", {})
                .get("slo-sle-templates", {}).get("slo-sle-template", [{}])[0]
                .get("description"),

            "reliability": ietf_intent.get("ietf-network-slice-service:network-slice-services", {})
                .get("slo-sle-templates", {}).get("slo-sle-template", [{}])[0]
                .get("sle-policy", {}).get("reliability"),
        }
Javier Velázquez's avatar
Javier Velázquez committed
        logging.info(f"IXIA Intent realized\n")
        return intent