Skip to content

Commit e4a915b

Browse files
authored
feat: implement setting mtu for virtio network device (#42)
* feat: implement setting mtu for virtio network device See https://git.proxmox.com/?p=qemu-server.git;a=commit;h=61a14cde8d568e552d3deaab2da76b479b8aca7b * fix: split extractNetworkModelAndBridge into multiple functions * fix: set maximum mtu to 65520 * test: should not allow mtu less than 1 or more than 65520 * feat: add validating webhook for proxmoxmachine * fix: remove default mtu
1 parent 71d2f82 commit e4a915b

14 files changed

+485
-37
lines changed

PROJECT

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ resources:
3030
kind: ProxmoxMachine
3131
path: github.com/ionos-cloud/cluster-api-provider-proxmox/api/v1alpha1
3232
version: v1alpha1
33+
webhooks:
34+
defaulting: true
35+
validation: true
36+
webhookVersion: v1
3337
- api:
3438
crdVersion: v1
3539
namespaced: true

api/v1alpha1/proxmoxmachine_types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ type NetworkDevice struct {
216216
// +kubebuilder:validation:Enum=e1000;virtio;rtl8139;vmxnet3
217217
// +kubebuilder:default=virtio
218218
Model *string `json:"model,omitempty"`
219+
220+
// MTU is the network device Maximum Transmission Unit.
221+
// Only works with virtio Model.
222+
// +optional
223+
// +kubebuilder:validation:Minimum=1
224+
// +kubebuilder:validation:Maximum=65520
225+
MTU *uint16 `json:"mtu,omitempty"`
219226
}
220227

221228
// AdditionalNetworkDevice the definition of a Proxmox network device.

api/v1alpha1/proxmoxmachine_types_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,5 +200,29 @@ var _ = Describe("ProxmoxMachine Test", func() {
200200
}
201201
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("at least one pool reference must be set, either ipv4PoolRef or ipv6PoolRef")))
202202
})
203+
204+
It("Should not allow machine with network device mtu less than 1", func() {
205+
dm := defaultMachine()
206+
dm.Spec.Network = &NetworkSpec{
207+
Default: &NetworkDevice{
208+
Bridge: "vmbr0",
209+
MTU: ptr.To(uint16(0)),
210+
},
211+
}
212+
213+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("should be greater than or equal to 1")))
214+
})
215+
216+
It("Should not allow machine with network device mtu greater than 65520", func() {
217+
dm := defaultMachine()
218+
dm.Spec.Network = &NetworkSpec{
219+
Default: &NetworkDevice{
220+
Bridge: "vmbr0",
221+
MTU: ptr.To(uint16(65521)),
222+
},
223+
}
224+
225+
Expect(k8sClient.Create(context.Background(), dm)).Should(MatchError(ContainSubstring("should be less than or equal to 65520")))
226+
})
203227
})
204228
})

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachines.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,12 @@ spec:
205205
- rtl8139
206206
- vmxnet3
207207
type: string
208+
mtu:
209+
description: MTU is the network device Maximum Transmission
210+
Unit. Only works with virtio Model.
211+
maximum: 65520
212+
minimum: 1
213+
type: integer
208214
name:
209215
description: Name is the network device name. must be unique
210216
within the virtual machine and different from the primary
@@ -245,6 +251,12 @@ spec:
245251
- rtl8139
246252
- vmxnet3
247253
type: string
254+
mtu:
255+
description: MTU is the network device Maximum Transmission
256+
Unit. Only works with virtio Model.
257+
maximum: 65520
258+
minimum: 1
259+
type: integer
248260
required:
249261
- bridge
250262
type: object

config/crd/bases/infrastructure.cluster.x-k8s.io_proxmoxmachinetemplates.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,12 @@ spec:
223223
- rtl8139
224224
- vmxnet3
225225
type: string
226+
mtu:
227+
description: MTU is the network device Maximum Transmission
228+
Unit. Only works with virtio Model.
229+
maximum: 65520
230+
minimum: 1
231+
type: integer
226232
name:
227233
description: Name is the network device name. must
228234
be unique within the virtual machine and different
@@ -265,6 +271,12 @@ spec:
265271
- rtl8139
266272
- vmxnet3
267273
type: string
274+
mtu:
275+
description: MTU is the network device Maximum Transmission
276+
Unit. Only works with virtio Model.
277+
maximum: 65520
278+
minimum: 1
279+
type: integer
268280
required:
269281
- bridge
270282
type: object

config/webhook/manifests.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,24 @@ webhooks:
2626
resources:
2727
- proxmoxclusters
2828
sideEffects: None
29+
- admissionReviewVersions:
30+
- v1
31+
clientConfig:
32+
service:
33+
name: webhook-service
34+
namespace: system
35+
path: /validate-infrastructure-cluster-x-k8s-io-v1alpha1-proxmoxmachine
36+
failurePolicy: Fail
37+
matchPolicy: Equivalent
38+
name: validation.proxmoxmachine.infrastructure.cluster.x-k8s.io
39+
rules:
40+
- apiGroups:
41+
- infrastructure.cluster.x-k8s.io
42+
apiVersions:
43+
- v1alpha1
44+
operations:
45+
- CREATE
46+
- UPDATE
47+
resources:
48+
- proxmoxmachines
49+
sideEffects: None

internal/service/vmservice/utils.go

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ package vmservice
1919
import (
2020
"fmt"
2121
"regexp"
22+
"strconv"
2223

2324
"github.com/google/uuid"
25+
2426
infrav1alpha1 "github.com/ionos-cloud/cluster-api-provider-proxmox/api/v1alpha1"
2527
"github.com/ionos-cloud/cluster-api-provider-proxmox/pkg/scope"
2628
)
@@ -55,14 +57,39 @@ func IPAddressWithPrefix(ip string, prefix int) string {
5557
return fmt.Sprintf("%s/%d", ip, prefix)
5658
}
5759

58-
// extractNetworkModelAndBridge returns the model & bridge out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1.
59-
func extractNetworkModelAndBridge(input string) (string, string) {
60-
re := regexp.MustCompile(`([^=,]+)=([^,]+),bridge=([^,]+)`)
60+
// extractNetworkModel returns the model out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1,mtu=1500.
61+
func extractNetworkModel(input string) string {
62+
re := regexp.MustCompile(`([^,=]+)(?:=[^,]*)?,bridge=([^,]+)`)
6163
matches := re.FindStringSubmatch(input)
62-
if len(matches) == 4 {
63-
return matches[1], matches[3]
64+
if len(matches) >= 2 {
65+
return matches[1]
66+
}
67+
return ""
68+
}
69+
70+
// extractNetworkBridge returns the bridge out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1,mtu=1500.
71+
func extractNetworkBridge(input string) string {
72+
re := regexp.MustCompile(`bridge=(\w+)`)
73+
match := re.FindStringSubmatch(input)
74+
if len(match) > 1 {
75+
return match[1]
76+
}
77+
return "unknown"
78+
}
79+
80+
// extractNetworkMTU returns the mtu out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1,mtu=1500.
81+
func extractNetworkMTU(input string) uint16 {
82+
re := regexp.MustCompile(`mtu=(\d+)`)
83+
match := re.FindStringSubmatch(input)
84+
if len(match) > 1 {
85+
mtu, err := strconv.ParseUint(match[1], 10, 16)
86+
if err != nil {
87+
return 0
88+
}
89+
return uint16(mtu)
6490
}
65-
return "", ""
91+
92+
return 0
6693
}
6794

6895
func shouldUpdateNetworkDevices(machineScope *scope.MachineScope) bool {
@@ -78,10 +105,23 @@ func shouldUpdateNetworkDevices(machineScope *scope.MachineScope) bool {
78105
if net0 == "" {
79106
return true
80107
}
81-
model, bridge := extractNetworkModelAndBridge(net0)
82-
if model != *machineScope.ProxmoxMachine.Spec.Network.Default.Model || bridge != machineScope.ProxmoxMachine.Spec.Network.Default.Bridge {
108+
109+
desiredDefault := *machineScope.ProxmoxMachine.Spec.Network.Default
110+
111+
model := extractNetworkModel(net0)
112+
bridge := extractNetworkBridge(net0)
113+
114+
if model != *desiredDefault.Model || bridge != desiredDefault.Bridge {
83115
return true
84116
}
117+
118+
if desiredDefault.MTU != nil {
119+
mtu := extractNetworkMTU(net0)
120+
121+
if mtu != *desiredDefault.MTU {
122+
return true
123+
}
124+
}
85125
}
86126

87127
devices := machineScope.ProxmoxMachine.Spec.Network.AdditionalDevices
@@ -91,20 +131,35 @@ func shouldUpdateNetworkDevices(machineScope *scope.MachineScope) bool {
91131
if len(net) == 0 {
92132
return true
93133
}
94-
model, bridge := extractNetworkModelAndBridge(net)
134+
135+
model := extractNetworkModel(net)
136+
bridge := extractNetworkBridge(net)
137+
95138
// current is different from the desired spec.
96139
if model != *v.Model || bridge != v.Bridge {
97140
return true
98141
}
142+
143+
if v.MTU != nil {
144+
mtu := extractNetworkMTU(net)
145+
146+
if mtu != *v.MTU {
147+
return true
148+
}
149+
}
99150
}
100151

101152
return false
102153
}
103154

104155
// formatNetworkDevice formats a network device config
105156
// example 'virtio,bridge=vmbr0'.
106-
func formatNetworkDevice(model, bridge string) string {
107-
return fmt.Sprintf("%s,bridge=%s", model, bridge)
157+
func formatNetworkDevice(model, bridge string, mtu *uint16) string {
158+
if mtu == nil {
159+
return fmt.Sprintf("%s,bridge=%s", model, bridge)
160+
}
161+
162+
return fmt.Sprintf("%s,bridge=%s,mtu=%d", model, bridge, *mtu)
108163
}
109164

110165
// extractMACAddress returns the macaddress out of net device input e.g. virtio=A6:23:64:4D:84:CB,bridge=vmbr1.

0 commit comments

Comments
 (0)