github.com/vmware/govmomi@v0.37.2/govc/device/pci/add.go (about)

     1  /*
     2  Copyright (c) 2020-2023 VMware, Inc. All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package pci
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  
    25  	"github.com/vmware/govmomi/govc/cli"
    26  	"github.com/vmware/govmomi/govc/flags"
    27  	"github.com/vmware/govmomi/vim25/types"
    28  )
    29  
    30  type add struct {
    31  	*flags.VirtualMachineFlag
    32  }
    33  
    34  func init() {
    35  	cli.Register("device.pci.add", &add{})
    36  }
    37  
    38  func (cmd *add) Register(ctx context.Context, f *flag.FlagSet) {
    39  	cmd.VirtualMachineFlag, ctx = flags.NewVirtualMachineFlag(ctx)
    40  	cmd.VirtualMachineFlag.Register(ctx, f)
    41  }
    42  
    43  func (cmd *add) Description() string {
    44  	return `Add PCI Passthrough device to VM.
    45  
    46  Examples:
    47    govc device.pci.ls -vm $vm
    48    govc device.pci.add -vm $vm $pci_address
    49    govc device.info -vm $vm
    50  
    51  Assuming vm name is helloworld, list command has below output
    52  
    53  $ govc device.pci.ls -vm helloworld
    54  System ID                             Address       Vendor Name Device Name
    55  5b087ce4-ce46-72c0-c7c2-28ac9e22c3c2  0000:60:00.0  Pensando    Ethernet Controller 1
    56  5b087ce4-ce46-72c0-c7c2-28ac9e22c3c2  0000:61:00.0  Pensando    Ethernet Controller 2
    57  
    58  To add only 'Ethernet Controller 1', command should be as below. No output upon success.
    59  
    60  $ govc device.pci.add -vm helloworld 0000:60:00.0
    61  
    62  To add both 'Ethernet Controller 1' and 'Ethernet Controller 2', command should be as below.
    63  No output upon success.
    64  
    65  $ govc device.pci.add -vm helloworld 0000:60:00.0 0000:61:00.0
    66  
    67  $ govc device.info -vm helloworld
    68  ...
    69  Name:               pcipassthrough-13000
    70    Type:             VirtualPCIPassthrough
    71    Label:            PCI device 0
    72    Summary:
    73    Key:              13000
    74    Controller:       pci-100
    75    Unit number:      18
    76  Name:               pcipassthrough-13001
    77    Type:             VirtualPCIPassthrough
    78    Label:            PCI device 1
    79    Summary:
    80    Key:              13001
    81    Controller:       pci-100
    82    Unit number:      19`
    83  }
    84  
    85  func (cmd *add) Usage() string {
    86  	return "PCI_ADDRESS..."
    87  }
    88  
    89  func (cmd *add) Run(ctx context.Context, f *flag.FlagSet) error {
    90  	if len(f.Args()) == 0 {
    91  		return flag.ErrHelp
    92  	}
    93  
    94  	reqDevices := map[string]*types.VirtualMachinePciPassthroughInfo{}
    95  	for _, n := range f.Args() {
    96  		reqDevices[n] = nil
    97  	}
    98  
    99  	vm, err := cmd.VirtualMachine()
   100  	if err != nil {
   101  		return err
   102  	}
   103  	if vm == nil {
   104  		return flag.ErrHelp
   105  	}
   106  
   107  	vmConfigOptions, err := queryConfigTarget(ctx, vm)
   108  	if err != nil {
   109  		return err
   110  	}
   111  
   112  	for _, d := range vmConfigOptions.PciPassthrough {
   113  		info := d.GetVirtualMachinePciPassthroughInfo()
   114  		if info == nil {
   115  			return errors.New("received invalid pci passthrough info")
   116  		}
   117  
   118  		_, ok := reqDevices[info.PciDevice.Id]
   119  		if !ok {
   120  			continue
   121  		}
   122  		reqDevices[info.PciDevice.Id] = info
   123  	}
   124  
   125  	newDevices := []types.BaseVirtualDevice{}
   126  	for id, d := range reqDevices {
   127  		if d == nil {
   128  			return fmt.Errorf("%s is not found in allowed PCI passthrough device list", id)
   129  		}
   130  		device := &types.VirtualPCIPassthrough{}
   131  		device.Backing = &types.VirtualPCIPassthroughDeviceBackingInfo{
   132  			Id: d.PciDevice.Id, DeviceId: fmt.Sprintf("%x", d.PciDevice.DeviceId),
   133  			SystemId: d.SystemId, VendorId: d.PciDevice.VendorId,
   134  		}
   135  		device.Connectable = &types.VirtualDeviceConnectInfo{StartConnected: true, Connected: true}
   136  		newDevices = append(newDevices, device)
   137  	}
   138  
   139  	return vm.AddDevice(ctx, newDevices...)
   140  }