...

Source file src/github.com/Microsoft/hcsshim/internal/devices/assigned_devices.go

Documentation: github.com/Microsoft/hcsshim/internal/devices

     1  //go:build windows
     2  // +build windows
     3  
     4  package devices
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  
    10  	"github.com/Microsoft/hcsshim/internal/cmd"
    11  	"github.com/Microsoft/hcsshim/internal/log"
    12  	"github.com/Microsoft/hcsshim/internal/uvm"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // AddDevice is the api exposed to hcsoci to handle assigning a device on a UVM
    17  //
    18  // `idType` refers to the specified device's type, supported types here are `VPCIDeviceIDType`
    19  // and `VPCIDeviceIDTypeLegacy`.
    20  //
    21  // `deviceID` refers to the specified device's identifier. This must refer to a device instance id
    22  // for hyper-v isolated device assignment.
    23  //
    24  // `deviceUtilPath` refers to the path in the UVM of the device-util tool used for finding the given
    25  // device's location path(s).
    26  //
    27  // Returns the allocated vpci device in `vpci` to be tracked for release by the caller. On failure in
    28  // this function, `vpci` is released and nil is returned for that value.
    29  //
    30  // Returns a slice of strings representing the resulting location path(s) for the specified device.
    31  func AddDevice(ctx context.Context, vm *uvm.UtilityVM, idType, deviceID string, index uint16, deviceUtilPath string) (vpci *uvm.VPCIDevice, locationPaths []string, err error) {
    32  	defer func() {
    33  		if err != nil && vpci != nil {
    34  			// best effort clean up allocated resource on failure
    35  			if releaseErr := vpci.Release(ctx); releaseErr != nil {
    36  				log.G(ctx).WithError(releaseErr).Error("failed to release container resource")
    37  			}
    38  			vpci = nil
    39  		}
    40  	}()
    41  	if idType == uvm.VPCIDeviceIDType || idType == uvm.VPCIDeviceIDTypeLegacy {
    42  		vpci, err = vm.AssignDevice(ctx, deviceID, index, "")
    43  		if err != nil {
    44  			return vpci, nil, errors.Wrapf(err, "failed to assign device %s of type %s to pod %s", deviceID, idType, vm.ID())
    45  		}
    46  		vmBusInstanceID := vm.GetAssignedDeviceVMBUSInstanceID(vpci.VMBusGUID)
    47  		log.G(ctx).WithField("vmbus id", vmBusInstanceID).Info("vmbus instance ID")
    48  
    49  		locationPaths, err = getChildrenDeviceLocationPaths(ctx, vm, vmBusInstanceID, deviceUtilPath)
    50  		return vpci, locationPaths, err
    51  	}
    52  
    53  	return vpci, nil, fmt.Errorf("device type %s for device %s is not supported in windows", idType, deviceID)
    54  }
    55  
    56  // getChildrenDeviceLocationPaths queries the UVM with the device-util tool with the formatted
    57  // parent bus device for the children devices' location paths from the uvm's view.
    58  // Returns a slice of strings representing the resulting children location paths
    59  func getChildrenDeviceLocationPaths(ctx context.Context, vm *uvm.UtilityVM, vmBusInstanceID string, deviceUtilPath string) ([]string, error) {
    60  	p, l, err := cmd.CreateNamedPipeListener()
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	defer l.Close()
    65  
    66  	var pipeResults []string
    67  	errChan := make(chan error)
    68  
    69  	go readCsPipeOutput(l, errChan, &pipeResults)
    70  
    71  	args := createDeviceUtilChildrenCommand(deviceUtilPath, vmBusInstanceID)
    72  	cmdReq := &cmd.CmdProcessRequest{
    73  		Args:   args,
    74  		Stdout: p,
    75  	}
    76  	exitCode, err := cmd.ExecInUvm(ctx, vm, cmdReq)
    77  	if err != nil {
    78  		return nil, errors.Wrapf(err, "failed to find devices with exit code %d", exitCode)
    79  	}
    80  
    81  	// wait to finish parsing stdout results
    82  	select {
    83  	case err := <-errChan:
    84  		if err != nil {
    85  			return nil, err
    86  		}
    87  	case <-ctx.Done():
    88  		return nil, ctx.Err()
    89  	}
    90  
    91  	return pipeResults, nil
    92  }
    93  
    94  // createDeviceUtilChildrenCommand constructs a device-util command to query the UVM for
    95  // device information
    96  //
    97  // `deviceUtilPath` is the UVM path to device-util
    98  //
    99  // `vmBusInstanceID` is a string of the vmbus instance ID already assigned to the UVM
   100  //
   101  // Returns a slice of strings that represent the location paths in the UVM of the
   102  // target devices
   103  func createDeviceUtilChildrenCommand(deviceUtilPath string, vmBusInstanceID string) []string {
   104  	parentIDsFlag := fmt.Sprintf("--parentID=%s", vmBusInstanceID)
   105  	args := []string{deviceUtilPath, "children", parentIDsFlag, "--property=location"}
   106  	return args
   107  }
   108  

View as plain text