Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/v1alpha1/proxmoxmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func restoreProxmoxMachineSpec(src *ProxmoxMachineSpec, dst *v1alpha2.ProxmoxMac
if i < len(restored.Network.NetworkDevices) {
dst.Network.NetworkDevices[i].DefaultIPv4 = restored.Network.NetworkDevices[i].DefaultIPv4
dst.Network.NetworkDevices[i].DefaultIPv6 = restored.Network.NetworkDevices[i].DefaultIPv6
dst.Network.NetworkDevices[i].Queues = restored.Network.NetworkDevices[i].Queues
}
}
}
Expand Down
1 change: 1 addition & 0 deletions api/v1alpha1/zz_generated.conversion.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions api/v1alpha2/proxmoxmachine_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,13 @@ type NetworkDevice struct {
// +kubebuilder:validation:Maximum=4094
VLAN *int32 `json:"vlan,omitempty"`

// queues is the number of queues assigned to the device.
// This value is passed to the Multiqueue field in PROXMOX.
// +optional
// +kubebuilder:validation:Minimum=1
// +kubebuilder:validation:Maximum=65535
Queues *int32 `json:"queues,omitempty"`

// name is the network device name.
// +default="net0"
// +optional
Expand Down
49 changes: 49 additions & 0 deletions api/v1alpha2/proxmoxmachine_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,55 @@ var _ = Describe("ProxmoxMachine Test", func() {
})
})

Context("Queues", func() {
It("Should not allow machine with network device queue equal to 0", func() {
dm := defaultMachine()
dm.Spec.Network = &NetworkSpec{
NetworkDevices: []NetworkDevice{{
Bridge: ptr.To("vmbr0"),
Queues: ptr.To(int32(0)),
}},
}

Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("should be greater than or equal to 1")))
})

It("Should not allow machine with network device queue greater than 65535", func() {
dm := defaultMachine()
dm.Spec.Network = &NetworkSpec{
NetworkDevices: []NetworkDevice{{
Bridge: ptr.To("vmbr0"),
Queues: ptr.To(int32(65536)),
}},
}

Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("should be less than or equal to 65535")))
})

It("Should allow machine with network device queue between 1 and 65535", func() {
dm := defaultMachine()
dm.Spec.Network = &NetworkSpec{
NetworkDevices: []NetworkDevice{{
Bridge: ptr.To("vmbr0"),
Queues: ptr.To(int32(4)),
}},
}

Expect(k8sClient.Create(context.Background(), dm)).Should(Succeed())
})

It("Should allow machine with network device queue unset", func() {
dm := defaultMachine()
dm.Spec.Network = &NetworkSpec{
NetworkDevices: []NetworkDevice{{
Bridge: ptr.To("vmbr0"),
}},
}

Expect(k8sClient.Create(context.Background(), dm)).Should(Succeed())
})
})

Context("VMIDRange", func() {
It("Should only allow spec.vmIDRange.start >= 100", func() {
dm := defaultMachine()
Expand Down
5 changes: 5 additions & 0 deletions api/v1alpha2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1114,6 +1114,14 @@ spec:
minLength: 4
pattern: ^net[0-9]+$
type: string
queues:
description: |-
queues is the number of queues assigned to the device.
This value is passed to the Multiqueue field in PROXMOX.
format: int32
maximum: 65535
minimum: 1
type: integer
routes:
description: routes are the routes associated with this
interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,14 @@ spec:
minLength: 4
pattern: ^net[0-9]+$
type: string
queues:
description: |-
queues is the number of queues assigned to the device.
This value is passed to the Multiqueue field in PROXMOX.
format: int32
maximum: 65535
minimum: 1
type: integer
routes:
description: routes are the routes associated with
this interface.
Expand Down
31 changes: 29 additions & 2 deletions internal/service/vmservice/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,21 @@ func extractNetworkVLAN(input string) int32 {
return 0
}

// extractNetworkQueue returns the queue out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1,mtu=1500,tag=100,queues=4.
func extractNetworkQueue(input string) int32 {
re := regexp.MustCompile(`queues=(\d+)`)
match := re.FindStringSubmatch(input)
if len(match) > 1 {
queue, err := strconv.ParseUint(match[1], 10, 16)
if err != nil {
return 0
}
return int32(queue)
}

return 0
}

func shouldUpdateNetworkDevices(machineScope *scope.MachineScope) bool {
if machineScope.ProxmoxMachine.Spec.Network == nil {
// no network config needed
Expand Down Expand Up @@ -180,14 +195,22 @@ func shouldUpdateNetworkDevices(machineScope *scope.MachineScope) bool {
return true
}
}

if v.Queues != nil {
queues := extractNetworkQueue(net)

if queues != *v.Queues {
return true
}
}
}

return false
}

// formatNetworkDevice formats a network device config
// example 'virtio,bridge=vmbr0,tag=100'.
func formatNetworkDevice(model, bridge string, mtu *int32, vlan *int32) string {
// example 'virtio,bridge=vmbr0,tag=100,queues=4'.
func formatNetworkDevice(model, bridge string, mtu *int32, vlan *int32, queues *int32) string {
var components = []string{model, fmt.Sprintf("bridge=%s", bridge)}

if mtu != nil {
Expand All @@ -198,6 +221,10 @@ func formatNetworkDevice(model, bridge string, mtu *int32, vlan *int32) string {
components = append(components, fmt.Sprintf("tag=%d", *vlan))
}

if queues != nil {
components = append(components, fmt.Sprintf("queues=%d", *queues))
}

return strings.Join(components, ",")
}

Expand Down
2 changes: 1 addition & 1 deletion internal/service/vmservice/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ func reconcileVirtualMachineConfig(ctx context.Context, machineScope *scope.Mach
for _, v := range devices {
vmOptions = append(vmOptions, proxmox.VirtualMachineOption{
Name: string(v.Name),
Value: formatNetworkDevice(ptr.Deref(v.Model, "virtio"), ptr.Deref(v.Bridge, ""), v.MTU, v.VLAN),
Value: formatNetworkDevice(ptr.Deref(v.Model, "virtio"), ptr.Deref(v.Bridge, ""), v.MTU, v.VLAN, v.Queues),
})
}
}
Expand Down
39 changes: 35 additions & 4 deletions internal/service/vmservice/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,8 +449,8 @@ func TestReconcileVirtualMachineConfig_ApplyConfig(t *testing.T) {
proxmox.VirtualMachineOption{Name: optionCores, Value: *machineScope.ProxmoxMachine.Spec.NumCores},
proxmox.VirtualMachineOption{Name: optionMemory, Value: *machineScope.ProxmoxMachine.Spec.MemoryMiB},
proxmox.VirtualMachineOption{Name: optionDescription, Value: machineScope.ProxmoxMachine.Spec.Description},
proxmox.VirtualMachineOption{Name: "net0", Value: formatNetworkDevice("virtio", "vmbr0", ptr.To[int32](1500), nil)},
proxmox.VirtualMachineOption{Name: "net1", Value: formatNetworkDevice("virtio", "vmbr1", ptr.To[int32](1500), nil)},
proxmox.VirtualMachineOption{Name: "net0", Value: formatNetworkDevice("virtio", "vmbr0", ptr.To[int32](1500), nil, nil)},
proxmox.VirtualMachineOption{Name: "net1", Value: formatNetworkDevice("virtio", "vmbr1", ptr.To[int32](1500), nil, nil)},
}

proxmoxClient.EXPECT().ConfigureVM(context.Background(), vm, expectedOptions...).Return(task, nil).Once()
Expand Down Expand Up @@ -624,8 +624,39 @@ func TestReconcileVirtualMachineConfigVLAN(t *testing.T) {
proxmox.VirtualMachineOption{Name: optionSockets, Value: *machineScope.ProxmoxMachine.Spec.NumSockets},
proxmox.VirtualMachineOption{Name: optionCores, Value: *machineScope.ProxmoxMachine.Spec.NumCores},
proxmox.VirtualMachineOption{Name: optionMemory, Value: *machineScope.ProxmoxMachine.Spec.MemoryMiB},
proxmox.VirtualMachineOption{Name: "net0", Value: formatNetworkDevice("virtio", "vmbr0", nil, ptr.To(int32(100)))},
proxmox.VirtualMachineOption{Name: "net1", Value: formatNetworkDevice("virtio", "vmbr1", nil, ptr.To(int32(100)))},
proxmox.VirtualMachineOption{Name: "net0", Value: formatNetworkDevice("virtio", "vmbr0", nil, ptr.To(int32(100)), nil)},
proxmox.VirtualMachineOption{Name: "net1", Value: formatNetworkDevice("virtio", "vmbr1", nil, ptr.To(int32(100)), nil)},
}

proxmoxClient.EXPECT().ConfigureVM(context.TODO(), vm, expectedOptions...).Return(task, nil).Once()

requeue, err := reconcileVirtualMachineConfig(context.TODO(), machineScope)
require.NoError(t, err)
require.True(t, requeue)
require.EqualValues(t, task.UPID, *machineScope.ProxmoxMachine.Status.TaskRef)
}

func TestReconcileVirtualMachineConfigQueue(t *testing.T) {
machineScope, proxmoxClient, _ := setupReconcilerTestWithCondition(t, infrav1.ProxmoxMachineVirtualMachineProvisionedCloningReason)
machineScope.ProxmoxMachine.Spec.NumSockets = ptr.To(int32(4))
machineScope.ProxmoxMachine.Spec.NumCores = ptr.To(int32(4))
machineScope.ProxmoxMachine.Spec.MemoryMiB = ptr.To(int32(16 * 1024))
machineScope.ProxmoxMachine.Spec.Network = &infrav1.NetworkSpec{
NetworkDevices: []infrav1.NetworkDevice{
{Name: infrav1.NetName("net0"), Bridge: ptr.To("vmbr0"), Model: ptr.To("virtio"), VLAN: ptr.To(int32(100)), Queues: ptr.To(int32(4))},
{Name: infrav1.NetName("net1"), Bridge: ptr.To("vmbr1"), Model: ptr.To("virtio"), VLAN: ptr.To(int32(100)), Queues: ptr.To(int32(4))},
},
}

vm := newStoppedVM()
task := newTask()
machineScope.SetVirtualMachine(vm)
expectedOptions := []interface{}{
proxmox.VirtualMachineOption{Name: optionSockets, Value: *machineScope.ProxmoxMachine.Spec.NumSockets},
proxmox.VirtualMachineOption{Name: optionCores, Value: *machineScope.ProxmoxMachine.Spec.NumCores},
proxmox.VirtualMachineOption{Name: optionMemory, Value: *machineScope.ProxmoxMachine.Spec.MemoryMiB},
proxmox.VirtualMachineOption{Name: "net0", Value: formatNetworkDevice("virtio", "vmbr0", nil, ptr.To(int32(100)), ptr.To(int32(4)))},
proxmox.VirtualMachineOption{Name: "net1", Value: formatNetworkDevice("virtio", "vmbr1", nil, ptr.To(int32(100)), ptr.To(int32(4)))},
}

proxmoxClient.EXPECT().ConfigureVM(context.TODO(), vm, expectedOptions...).Return(task, nil).Once()
Expand Down
Loading