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