diff --git a/doc/metadata.txt b/doc/metadata.txt index 909a1836c5d6..4af88bdcc22a 100644 --- a/doc/metadata.txt +++ b/doc/metadata.txt @@ -1007,7 +1007,7 @@ This option specifies whether to register the VLAN using the GARP VLAN Registrat ``` ```{config:option} hwaddr device-nic-physical-device-conf -:defaultdesc: "randomly assigned" +:defaultdesc: "parent MAC address" :managed: "no" :shortdesc: "MAC address of the new interface" :type: "string" diff --git a/lxc/config_device.go b/lxc/config_device.go index d8f00c7f320e..fd2671fcda52 100644 --- a/lxc/config_device.go +++ b/lxc/config_device.go @@ -107,12 +107,13 @@ lxc profile device add [:]profile1 disk pool=some-pool sou } } - if len(args) == 1 { + // The second positional argument is used for the device name, so we provide device completions for the third positional argument. + if len(args) == 2 { return c.global.cmpInstanceAllDevices(toComplete) } - if len(args) == 2 { - return c.global.cmpInstanceAllDeviceOptions(args[0], args[1]) + if len(args) == 3 { + return c.global.cmpInstanceAllDeviceOptions(args[0], args[2]) } return nil, cobra.ShellCompDirectiveNoFileComp diff --git a/lxd/device/nic.go b/lxd/device/nic.go index b539dc6e5e74..67e794572ba6 100644 --- a/lxd/device/nic.go +++ b/lxd/device/nic.go @@ -161,7 +161,7 @@ func nicValidationRules(requiredFields []string, optionalFields []string, instCo // defaultdesc: `false` // shortdesc: Whether to use GARP VLAN Registration Protocol "gvrp": validate.Optional(validate.IsBool), - // lxdmeta:generate(entities=device-nic-{bridged+macvlan+sriov+physical+ovn}; group=device-conf; key=hwaddr) + // lxdmeta:generate(entities=device-nic-{bridged+macvlan+sriov+ovn}; group=device-conf; key=hwaddr) // // --- // type: string @@ -169,6 +169,14 @@ func nicValidationRules(requiredFields []string, optionalFields []string, instCo // managed: no // shortdesc: MAC address of the new interface + // lxdmeta:generate(entities=device-nic-physical; group=device-conf; key=hwaddr) + // + // --- + // type: string + // defaultdesc: parent MAC address + // managed: no + // shortdesc: MAC address of the new interface + // lxdmeta:generate(entities=device-nic-{ipvlan+p2p+routed}; group=device-conf; key=hwaddr) // // --- diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go index 98804bf4c607..3848c2725f50 100644 --- a/lxd/device/nic_physical.go +++ b/lxd/device/nic_physical.go @@ -137,6 +137,8 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, error) { // pciIOMMUGroup, used for VM physical passthrough. var pciIOMMUGroup uint64 + var hwaddr string + // If VM, then try and load the vfio-pci module first. if d.inst.Type() == instancetype.VM { err = util.LoadModule("vfio-pci") @@ -200,6 +202,12 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, error) { } } } else if d.inst.Type() == instancetype.VM { + // Try to get MAC address of the parent interface. + hwaddr, err = NetworkGetDevMAC(saveData["host_name"]) + if err != nil { + return nil, err + } + // Try to get PCI information about the network interface. ueventPath := fmt.Sprintf("/sys/class/net/%s/device/uevent", saveData["host_name"]) pciDev, err := pcidev.ParseUeventFile(ueventPath) @@ -245,6 +253,7 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, error) { {Key: "devName", Value: d.name}, {Key: "pciSlotName", Value: saveData["last_state.pci.slot.name"]}, {Key: "pciIOMMUGroup", Value: fmt.Sprintf("%d", pciIOMMUGroup)}, + {Key: "hwaddr", Value: hwaddr}, }...) } diff --git a/lxd/metadata/configuration.json b/lxd/metadata/configuration.json index ed74207fe14e..0550c119920b 100644 --- a/lxd/metadata/configuration.json +++ b/lxd/metadata/configuration.json @@ -1147,7 +1147,7 @@ }, { "hwaddr": { - "defaultdesc": "randomly assigned", + "defaultdesc": "parent MAC address", "longdesc": "", "managed": "no", "shortdesc": "MAC address of the new interface",