def __update_smart_nic_labels_and_capacities(
            self, *, available_component: ComponentSliver,
            requested_component: ComponentSliver) -> ComponentSliver:
        """
        Update the IFS for the Smart NIC with VLAN, MAC and IP Address information
        This is to enable AM handler to configure network interfaces at VM creation.
        This is only done for Layer 2 services
        :param available_component: Available Component
        :param requested_component: Requested Component
        :return updated requested component with VLAN, MAC and IP information
        """

        # Find the VLAN from the BQM Component
        if available_component.network_service_info is None or \
                len(available_component.network_service_info.network_services) != 1:
            message = "Smart NIC Card must have at one Network Service"
            self.logger.error(message)
            raise BrokerException(error_code=ExceptionErrorCode.FAILURE,
                                  msg=f"{message}")

        ns_name = next(
            iter(available_component.network_service_info.network_services))
        ns = available_component.network_service_info.network_services[ns_name]

        if ns.interface_info is None or len(ns.interface_info.interfaces) < 0:
            message = "Smart NIC Card must have at least one Connection Point"
            self.logger.error(message)
            raise BrokerException(error_code=ExceptionErrorCode.FAILURE,
                                  msg=f"{message}")

        for ifs in ns.interface_info.interfaces.values():
            delegation_id, ifs_delegated_labels = self._get_delegations(
                lab_cap_delegations=ifs.get_label_delegations())

            for requested_ns in requested_component.network_service_info.network_services.values(
            ):
                if requested_ns.interface_info is not None and requested_ns.interface_info.interfaces is not None:
                    for requested_ifs in requested_ns.interface_info.interfaces.values(
                    ):
                        if requested_ifs.labels.local_name == ifs_delegated_labels.local_name:
                            lab = Labels()
                            lab.mac = ifs_delegated_labels.mac
                            lab.local_name = ifs_delegated_labels.local_name

                            # Update the VLAN and IP address to be used for configuration at AM only for L2 services
                            # Information for L3 services is updated later after NetworkService has been ticketed
                            if requested_ns.layer == NSLayer.L2:
                                if requested_ifs.labels is not None and requested_ifs.labels.vlan is not None:
                                    lab.vlan = requested_ifs.labels.vlan

                                if requested_ifs.labels.ipv4 is not None:
                                    lab.ipv4 = requested_ifs.labels.ipv4

                                if requested_ifs.labels.ipv6 is not None:
                                    lab.ipv6 = requested_ifs.labels.ipv6

                            requested_ifs.set_label_allocations(lab=lab)
                        self.logger.info(
                            f"Assigned Interface Sliver: {requested_ifs}")
        return requested_component
    def __update_shared_nic_labels_and_capacities(
            self, *, available_component: ComponentSliver,
            requested_component: ComponentSliver) -> ComponentSliver:
        """
        Update the shared NIC Labels and Capacities. Assign the 1st available PCI address/bdf to the requested component
        Traverse the available component's labels to find the index for bdf assigned
        Using the found labels, assign BDF, MAC and VLAN address to the IFS on the Requested component
        In case of L2 service, also copy the requested IP address so it can be used by the AMHandler to configure the
        interface post VM creation
        :param available_component: Available Component
        :param requested_component: Requested Component
        :return updated requested component with VLAN, MAC and IP information
        """
        # Check labels
        delegation_id, delegated_label = self._get_delegations(
            lab_cap_delegations=available_component.get_label_delegations())

        if delegated_label.bdf is None or len(delegated_label.bdf) < 1:
            message = "No PCI devices available in the delegation"
            self.logger.error(message)
            raise BrokerException(
                error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES,
                msg=f"{message}")

        # Assign the first PCI Id from the list of available PCI slots
        requested_component.label_allocations = Labels(
            bdf=delegated_label.bdf[0])

        # Find the VLAN from the BQM Component
        if available_component.network_service_info is None or \
                len(available_component.network_service_info.network_services) != 1:
            message = "Shared NIC Card must have one Network Service"
            self.logger.error(message)
            raise BrokerException(error_code=ExceptionErrorCode.FAILURE,
                                  msg=f"{message}")

        ns_name = next(
            iter(available_component.network_service_info.network_services))
        ns = available_component.network_service_info.network_services[ns_name]

        if ns.interface_info is None or len(ns.interface_info.interfaces) != 1:
            message = "Shared NIC Card must have one Connection Point"
            self.logger.error(message)
            raise BrokerException(error_code=ExceptionErrorCode.FAILURE,
                                  msg=f"{message}")

        ifs_name = next(iter(ns.interface_info.interfaces))
        ifs = ns.interface_info.interfaces[ifs_name]

        delegation_id, ifs_delegated_labels = self._get_delegations(
            lab_cap_delegations=ifs.get_label_delegations())

        # Determine the index which points to the same PCI id as assigned above
        # This index points to the other relevant information such as MAC Address,
        # VLAN tag for that PCI device
        i = 0
        for pci_id in ifs_delegated_labels.bdf:
            if pci_id == delegated_label.bdf[0]:
                break
            i += 1

        # Updated the Requested component with VLAN, BDF, MAC
        req_ns_name = next(
            iter(requested_component.network_service_info.network_services))
        req_ns = requested_component.network_service_info.network_services[
            req_ns_name]
        req_ifs_name = next(iter(req_ns.interface_info.interfaces))
        req_ifs = req_ns.interface_info.interfaces[req_ifs_name]

        lab = Labels(bdf=ifs_delegated_labels.bdf[i],
                     mac=ifs_delegated_labels.mac[i],
                     vlan=ifs_delegated_labels.vlan[i],
                     local_name=ifs_delegated_labels.local_name[i])

        # For the Layer 2 copying the IP address to the label allocations
        # This is to be used by AM Handler to configure Network Interface
        if req_ns.layer == NSLayer.L2:
            if req_ifs.labels is not None and req_ifs.labels.ipv4 is not None:
                lab.ipv4 = req_ifs.labels.ipv4
            if req_ifs.labels is not None and req_ifs.labels.ipv6 is not None:
                lab.ipv6 = req_ifs.labels.ipv6

        req_ifs.set_label_allocations(lab=lab)

        self.logger.info(f"Assigned Interface Sliver: {req_ifs}")
        return requested_component
    def create_unit(include_pci: bool = True,
                    include_image: bool = True,
                    include_name: bool = True,
                    include_instance_name: bool = False,
                    include_ns: bool = False) -> Unit:
        """
        Create a unit
        :param include_pci:
        :param include_image:
        :param include_name:
        :param include_instance_name:
        :param include_ns:
        :return:
        """
        u = Unit(rid=ID(uid="rid-1"))
        sliver = NodeSliver()
        cap = Capacities()
        cap.set_fields(core=4, ram=64, disk=500)
        catalog = InstanceCatalog()
        instance_type = catalog.map_capacities_to_instance(cap=cap)
        cap_hints = CapacityHints().set_fields(instance_type=instance_type)
        sliver.set_properties(
            type=NodeType.VM,
            site="RENC",
            capacity_hints=cap_hints,
            capacity_allocations=catalog.get_instance_capacities(
                instance_type=instance_type))
        sliver.label_allocations = Labels().set_fields(
            instance_parent="renc-w1.fabric-testbed.net")

        if include_name:
            sliver.set_properties(name="n1")

        if include_image:
            sliver.set_properties(image_type='qcow2',
                                  image_ref='default_centos_8')

        if include_pci:
            component = ComponentSliver()
            labels = Labels()
            labels.set_fields(bdf=["0000:41:00.0", "0000:41:00.1"])
            component.set_properties(type=ComponentType.SmartNIC,
                                     model='ConnectX-6',
                                     name='nic1',
                                     label_allocations=labels)
            sliver.attached_components_info = AttachedComponentsInfo()
            sliver.attached_components_info.add_device(device_info=component)

        if include_instance_name:
            sliver.label_allocations.set_fields(instance="instance-001")

        if include_ns:
            sliver.network_service_info = NetworkServiceInfo()
            ns = NetworkServiceSliver()
            ns.interface_info = InterfaceInfo()
            ifs1 = InterfaceSliver()
            c = Capacities()
            c.bw = 100
            c.unit = 1
            l1 = Labels()
            l1.ipv4 = '192.168.11.3'
            l1.vlan = '200'
            l1.local_name = 'p1'
            la_1 = Labels()
            la_1.mac = '0C:42:A1:EA:C7:51'
            la_1.vlan = '200'
            ifs1.capacities = c
            ifs1.labels = l1
            ifs1.label_allocations = la_1

            ifs2 = InterfaceSliver()
            ifs2.capacities = c
            l2 = Labels()
            l2.ipv4 = '192.168.11.2'
            l2.local_name = 'p2'
            la_2 = Labels()
            la_2.mac = '0C:42:A1:EA:C7:52'

            ifs2.labels = l2
            ifs2.label_allocations = la_1

            ns.interface_info.interfaces = {'ifs1': ifs1, 'ifs2': ifs2}
            sliver.network_service_info.network_services = {'ns1': ns}

        u.set_sliver(sliver=sliver)
        return u
示例#4
0
    def allocate(
        self, *, rid: ID, requested_ns: NetworkServiceSliver,
        owner_switch: NodeSliver,
        existing_reservations: List[ABCReservationMixin]
    ) -> NetworkServiceSliver:
        """
        Allocate Network Service Sliver (Only for L3 Service)
            - grab the /17 or /48 from BQM Site specific NetworkService
            - divide it into /24 or /64 subnets
            - exclude the 1st subnet (reserved for control plane)
            - exclude the subnets already assigned to other V3/V4 NetworkService on the same owner switch
            - allocate the first available subnet to the NetworkService
        :param requested_ns: Requested NetworkService
        :param owner_switch: BQM Owner site switch identified to serve the NetworkService
        :param existing_reservations: Existing Reservations which also are served by the owner switch
        :return NetworkService updated with the allocated subnet for FABNetv4 and FABNetv6 services
        Return the sliver updated with the subnet
        """
        if requested_ns.get_type(
        ) != ServiceType.FABNetv4 and requested_ns.get_type(
        ) != ServiceType.FABNetv6:
            return requested_ns

        for ns in owner_switch.network_service_info.network_services.values():
            if requested_ns.get_type() == ns.get_type():
                # Grab Label Delegations
                delegation_id, delegated_label = self._get_delegations(
                    lab_cap_delegations=ns.get_label_delegations())

                subnet_list = None
                # Get Subnet
                if ns.get_type() == ServiceType.FABNetv6:
                    ip_network = IPv6Network(delegated_label.ipv6_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=64))

                elif ns.get_type() == ServiceType.FABNetv4:
                    ip_network = IPv4Network(delegated_label.ipv4_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=24))

                # Exclude the 1st subnet as it is reserved for control plane
                subnet_list.pop(0)

                # Exclude the already allocated VLANs and subnets
                for reservation in existing_reservations:
                    if rid == reservation.get_reservation_id():
                        continue
                    # For Active or Ticketed or Ticketing reservations; reduce the counts from available
                    allocated_sliver = None
                    if reservation.is_ticketing(
                    ) and reservation.get_approved_resources() is not None:
                        allocated_sliver = reservation.get_approved_resources(
                        ).get_sliver()

                    if (reservation.is_active() or reservation.is_ticketed()) and \
                            reservation.get_resources() is not None:
                        allocated_sliver = reservation.get_resources(
                        ).get_sliver()

                    self.logger.debug(
                        f"Existing res# {reservation.get_reservation_id()} allocated: {allocated_sliver}"
                    )

                    if allocated_sliver is None:
                        continue

                    if allocated_sliver.get_type() != requested_ns.get_type():
                        continue

                    if allocated_sliver.get_type() == ServiceType.FABNetv4:
                        subnet_to_remove = IPv4Network(
                            allocated_sliver.get_gateway().lab.ipv4_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IP4Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv4_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                    elif allocated_sliver.get_gateway(
                    ).lab.ipv6_subnet is not None:
                        subnet_to_remove = IPv6Network(
                            allocated_sliver.get_gateway().lab.ipv6_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IPv6Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv6_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                gateway_labels = Labels()
                if requested_ns.get_type() == ServiceType.FABNetv4:
                    gateway_labels.ipv4_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv4 = str(next(subnet_list[0].hosts()))

                elif requested_ns.get_type() == ServiceType.FABNetv6:
                    gateway_labels.ipv6_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv6 = str(next(subnet_list[0].hosts()))

                requested_ns.gateway = Gateway(lab=gateway_labels)
                break
        return requested_ns