• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

k8snetworkplumbingwg / sriov-network-operator / 19855289298

02 Dec 2025 10:24AM UTC coverage: 62.126% (-0.02%) from 62.149%
19855289298

Pull #967

github

web-flow
Merge e77928524 into d34e85b1c
Pull Request #967: Add support for network interface alternative names

70 of 91 new or added lines in 7 files covered. (76.92%)

21 existing lines in 6 files now uncovered.

8820 of 14197 relevant lines covered (62.13%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

66.0
/pkg/webhook/validate.go
1
package webhook
2

3
import (
4
        "context"
5
        "fmt"
6
        "os"
7
        "regexp"
8
        "strconv"
9
        "strings"
10

11
        v1 "k8s.io/api/admission/v1"
12
        corev1 "k8s.io/api/core/v1"
13
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
14
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
        "k8s.io/apimachinery/pkg/labels"
16
        runtimeclient "sigs.k8s.io/controller-runtime/pkg/client"
17
        "sigs.k8s.io/controller-runtime/pkg/log"
18

19
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
20
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
21
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
22
)
23

24
const (
25
        IntelID    = "8086"
26
        MellanoxID = "15b3"
27
        MlxMaxVFs  = 128
28
)
29

30
var (
31
        nodesSelected     bool
32
        interfaceSelected bool
33
)
34

35
func validateSriovOperatorConfig(cr *sriovnetworkv1.SriovOperatorConfig, operation v1.Operation) (bool, []string, error) {
1✔
36
        log.Log.V(2).Info("validateSriovOperatorConfig", "object", cr)
1✔
37
        var warnings []string
1✔
38

1✔
39
        if operation == v1.Delete {
2✔
40
                return true, warnings, nil
1✔
41
        }
1✔
42

43
        if cr.GetName() != consts.DefaultConfigName || cr.GetNamespace() != vars.Namespace {
1✔
44
                return false, warnings, fmt.Errorf("only default SriovOperatorConfig in %s namespace is used", vars.Namespace)
×
45
        }
×
46

47
        if cr.Spec.DisableDrain {
2✔
48
                warnings = append(warnings, "Node draining is disabled for applying SriovNetworkNodePolicy, it may result in workload interruption.")
1✔
49
        }
1✔
50

51
        err := validateSriovOperatorConfigDisableDrain(cr)
1✔
52
        if err != nil {
2✔
53
                return false, warnings, err
1✔
54
        }
1✔
55

56
        return true, warnings, nil
1✔
57
}
58

59
// validateSriovOperatorConfigDisableDrain checks if the user is setting `.Spec.DisableDrain` from false to true while
60
// operator is updating one or more nodes. Disabling the drain at this stage would prevent the operator to uncordon a node at
61
// the end of the update operation, keeping nodes un-schedulable until manual intervention.
62
func validateSriovOperatorConfigDisableDrain(cr *sriovnetworkv1.SriovOperatorConfig) error {
1✔
63
        if !cr.Spec.DisableDrain {
1✔
64
                return nil
×
65
        }
×
66
        previousConfig := &sriovnetworkv1.SriovOperatorConfig{}
1✔
67
        err := client.Get(context.Background(), runtimeclient.ObjectKey{Name: cr.Name, Namespace: namespace}, previousConfig)
1✔
68
        if err != nil {
2✔
69
                if k8serrors.IsNotFound(err) {
2✔
70
                        return nil
1✔
71
                }
1✔
72
                return fmt.Errorf("can't validate SriovOperatorConfig[%s] DisableDrain against its previous value: %q", cr.Name, err)
×
73
        }
74

75
        if previousConfig.Spec.DisableDrain == cr.Spec.DisableDrain {
1✔
76
                // DisableDrain didn't change
×
77
                return nil
×
78
        }
×
79

80
        // DisableDrain has been changed `false -> true`, check if any node is updating
81
        nodeStates := &sriovnetworkv1.SriovNetworkNodeStateList{}
1✔
82
        err = client.List(context.Background(), nodeStates, &runtimeclient.ListOptions{Namespace: namespace})
1✔
83
        if err != nil {
1✔
84
                return fmt.Errorf("can't validate SriovOperatorConfig[%s] DisableDrain transition to true: %q", cr.Name, err)
×
85
        }
×
86

87
        for _, nodeState := range nodeStates.Items {
2✔
88
                if nodeState.Status.SyncStatus == "InProgress" {
2✔
89
                        return fmt.Errorf("can't set Spec.DisableDrain = true while node[%s] is updating", nodeState.Name)
1✔
90
                }
1✔
91
        }
92

93
        return nil
1✔
94
}
95

96
// validateSriovNetworkPoolConfig checks if the use tries to remove the default pool config and block it
97
func validateSriovNetworkPoolConfig(cr *sriovnetworkv1.SriovNetworkPoolConfig, operation v1.Operation) (bool, []string, error) {
1✔
98
        log.Log.V(2).Info("validateSriovNetworkPoolConfig", "object", cr)
1✔
99
        var warnings []string
1✔
100

1✔
101
        if (cr.Spec.MaxUnavailable != nil || cr.Spec.NodeSelector != nil) && cr.Spec.OvsHardwareOffloadConfig.Name != "" {
2✔
102
                return false, warnings, fmt.Errorf("SriovOperatorConfig can't have both parallel configuration and OvsHardwareOffloadConfig")
1✔
103
        }
1✔
104

105
        if cr.Spec.MaxUnavailable != nil {
2✔
106
                _, err := cr.MaxUnavailable(0)
1✔
107
                if err != nil {
1✔
108
                        return false, warnings, fmt.Errorf("SriovOperatorConfig invalid maxUnavailable: %v", err)
×
109
                }
×
110
        }
111

112
        return true, warnings, nil
1✔
113
}
114

115
func validateSriovNetworkNodePolicy(cr *sriovnetworkv1.SriovNetworkNodePolicy, operation v1.Operation) (bool, []string, error) {
1✔
116
        log.Log.V(2).Info("validateSriovNetworkNodePolicy", "object", cr)
1✔
117
        var warnings []string
1✔
118

1✔
119
        if cr.GetName() == consts.DefaultPolicyName && cr.GetNamespace() == vars.Namespace {
2✔
120
                // skip validating (deprecated) default policy
1✔
121
                return true, warnings, nil
1✔
122
        }
1✔
123

124
        if cr.GetNamespace() != vars.Namespace {
×
125
                warnings = append(warnings, cr.GetName()+
×
126
                        fmt.Sprintf(" is created or updated but not used. Only policy in %s namespace is respected.", vars.Namespace))
×
127
        }
×
128

129
        if operation == v1.Delete {
×
130
                return true, warnings, nil
×
131
        }
×
132

133
        admit, err := staticValidateSriovNetworkNodePolicy(cr)
×
134
        if err != nil {
×
135
                return admit, warnings, err
×
136
        }
×
137

138
        admit, err = dynamicValidateSriovNetworkNodePolicy(cr)
×
139
        if err != nil {
×
140
                return admit, warnings, err
×
141
        }
×
142

143
        return admit, warnings, nil
×
144
}
145

146
func staticValidateSriovNetworkNodePolicy(cr *sriovnetworkv1.SriovNetworkNodePolicy) (bool, error) {
1✔
147
        var validString = regexp.MustCompile(`^[a-zA-Z0-9_]+$`)
1✔
148
        if !validString.MatchString(cr.Spec.ResourceName) {
1✔
149
                return false, fmt.Errorf("resource name \"%s\" contains invalid characters, the accepted syntax of the regular expressions is: \"^[a-zA-Z0-9_]+$\"", cr.Spec.ResourceName)
×
150
        }
×
151

152
        if cr.Spec.NicSelector.Vendor == "" && cr.Spec.NicSelector.DeviceID == "" && len(cr.Spec.NicSelector.PfNames) == 0 && len(cr.Spec.NicSelector.RootDevices) == 0 && cr.Spec.NicSelector.NetFilter == "" {
2✔
153
                return false, fmt.Errorf("at least one of these parameters (vendor, deviceID, pfNames, rootDevices or netFilter) has to be defined in nicSelector in CR %s", cr.GetName())
1✔
154
        }
1✔
155

156
        devMode := false
1✔
157
        if os.Getenv("DEV_MODE") == "TRUE" {
2✔
158
                devMode = true
1✔
159
                log.Log.V(0).Info("dev mode enabled - Admitting not supported NICs")
1✔
160
        }
1✔
161

162
        if !devMode {
2✔
163
                if cr.Spec.NicSelector.Vendor != "" {
2✔
164
                        if !sriovnetworkv1.IsSupportedVendor(cr.Spec.NicSelector.Vendor) {
2✔
165
                                return false, fmt.Errorf("vendor %s is not supported", cr.Spec.NicSelector.Vendor)
1✔
166
                        }
1✔
167
                        if cr.Spec.NicSelector.DeviceID != "" {
2✔
168
                                if !sriovnetworkv1.IsSupportedModel(cr.Spec.NicSelector.Vendor, cr.Spec.NicSelector.DeviceID) {
2✔
169
                                        return false, fmt.Errorf("vendor/device %s/%s is not supported", cr.Spec.NicSelector.Vendor, cr.Spec.NicSelector.DeviceID)
1✔
170
                                }
1✔
171
                        }
172
                } else if cr.Spec.NicSelector.DeviceID != "" {
2✔
173
                        if !sriovnetworkv1.IsSupportedDevice(cr.Spec.NicSelector.DeviceID) {
2✔
174
                                return false, fmt.Errorf("device %s is not supported", cr.Spec.NicSelector.DeviceID)
1✔
175
                        }
1✔
176
                }
177
        }
178

179
        if len(cr.Spec.NicSelector.PfNames) > 0 {
2✔
180
                for _, pf := range cr.Spec.NicSelector.PfNames {
2✔
181
                        if strings.Contains(pf, "#") {
1✔
182
                                fields := strings.Split(pf, "#")
×
183
                                if len(fields) != 2 {
×
184
                                        return false, fmt.Errorf("failed to parse %s PF name in nicSelector, probably incorrect separator character usage", pf)
×
185
                                }
×
186
                                rng := strings.Split(fields[1], "-")
×
187
                                if len(rng) != 2 {
×
188
                                        return false, fmt.Errorf("failed to parse %s PF name nicSelector, probably incorrect range character usage", pf)
×
189
                                }
×
190
                                rngSt, err := strconv.Atoi(rng[0])
×
191
                                if err != nil {
×
192
                                        return false, fmt.Errorf("failed to parse %s PF name nicSelector, start range is incorrect", pf)
×
193
                                }
×
194
                                rngEnd, err := strconv.Atoi(rng[1])
×
195
                                if err != nil {
×
196
                                        return false, fmt.Errorf("failed to parse %s PF name nicSelector, end range is incorrect", pf)
×
197
                                }
×
198
                                if rngEnd < rngSt {
×
199
                                        return false, fmt.Errorf("failed to parse %s PF name nicSelector, end range shall not be smaller than start range", pf)
×
200
                                }
×
201
                                if !(rngEnd < cr.Spec.NumVfs) {
×
202
                                        return false, fmt.Errorf("failed to parse %s PF name nicSelector, end range exceeds the maximum VF index ", pf)
×
203
                                }
×
204
                        }
205
                }
206
        }
207

208
        // To configure RoCE on baremetal or virtual machine:
209
        // BM: DeviceType = netdevice && isRdma = true
210
        // VM: DeviceType = vfio-pci && isRdma = false
211
        if cr.Spec.DeviceType == consts.DeviceTypeVfioPci && cr.Spec.IsRdma {
2✔
212
                return false, fmt.Errorf("'deviceType: vfio-pci' conflicts with 'isRdma: true'; Set 'deviceType' to (string)'netdevice' Or Set 'isRdma' to (bool)'false'")
1✔
213
        }
1✔
214

215
        // switchdev mode can be used only with ethernet links
216
        if cr.Spec.LinkType != "" && !strings.EqualFold(cr.Spec.LinkType, consts.LinkTypeETH) && cr.Spec.EswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
2✔
217
                return false, fmt.Errorf("'eSwitchMode: switchdev' can be used only with ethernet links")
1✔
218
        }
1✔
219

220
        // vdpa: deviceType must be set to 'netdevice'
221
        if cr.Spec.DeviceType != consts.DeviceTypeNetDevice && (cr.Spec.VdpaType == consts.VdpaTypeVirtio || cr.Spec.VdpaType == consts.VdpaTypeVhost) {
2✔
222
                return false, fmt.Errorf("'deviceType: %s' conflicts with '%s'; Set 'deviceType' to (string)'netdevice' Or Remove 'vdpaType'", cr.Spec.DeviceType, cr.Spec.VdpaType)
1✔
223
        }
1✔
224
        // vdpa: device must be configured in switchdev mode
225
        if (cr.Spec.VdpaType == consts.VdpaTypeVirtio || cr.Spec.VdpaType == consts.VdpaTypeVhost) && cr.Spec.EswitchMode != sriovnetworkv1.ESwithModeSwitchDev {
2✔
226
                return false, fmt.Errorf("vdpa requires the device to be configured in switchdev mode")
1✔
227
        }
1✔
228
        // software bridge management: device must be configured in switchdev mode
229
        if !cr.Spec.Bridge.IsEmpty() && cr.Spec.EswitchMode != sriovnetworkv1.ESwithModeSwitchDev {
2✔
230
                return false, fmt.Errorf("software bridge management requires the device to be configured in switchdev mode")
1✔
231
        }
1✔
232
        // software bridge management: device can't be externally managed
233
        if !cr.Spec.Bridge.IsEmpty() && cr.Spec.ExternallyManaged {
2✔
234
                return false, fmt.Errorf("software bridge management can't be used when the device externally managed")
1✔
235
        }
1✔
236
        return true, nil
1✔
237
}
238

239
func dynamicValidateSriovNetworkNodePolicy(cr *sriovnetworkv1.SriovNetworkNodePolicy) (bool, error) {
×
240
        nodesSelected = false
×
241
        interfaceSelected = false
×
242
        nodeInterfaceErrorList := make(map[string][]string)
×
243

×
244
        nodeList, err := kubeclient.CoreV1().Nodes().List(context.Background(), metav1.ListOptions{
×
245
                LabelSelector: labels.Set(cr.Spec.NodeSelector).String(),
×
246
        })
×
247
        if err != nil {
×
248
                return false, err
×
249
        }
×
250
        nsList := &sriovnetworkv1.SriovNetworkNodeStateList{}
×
251
        err = client.List(context.Background(), nsList, &runtimeclient.ListOptions{Namespace: namespace})
×
252
        if err != nil {
×
253
                return false, err
×
254
        }
×
255
        npList := &sriovnetworkv1.SriovNetworkNodePolicyList{}
×
256
        err = client.List(context.Background(), npList, &runtimeclient.ListOptions{Namespace: namespace})
×
257
        if err != nil {
×
258
                return false, err
×
259
        }
×
260
        for _, node := range nodeList.Items {
×
261
                if cr.Selected(&node) {
×
262
                        nodesSelected = true
×
263
                        err = validatePolicyForNodeStateAndPolicy(nsList, npList, &node, cr, nodeInterfaceErrorList)
×
264
                        if err != nil {
×
265
                                return false, err
×
266
                        }
×
267
                }
268
        }
269

270
        if !nodesSelected {
×
271
                return false, fmt.Errorf("no matched node is selected by the nodeSelector in CR %s", cr.GetName())
×
272
        }
×
273
        if !interfaceSelected {
×
274
                for nodeName, messages := range nodeInterfaceErrorList {
×
275
                        for _, message := range messages {
×
276
                                log.Log.V(2).Info("interface selection errors", "nodeName", nodeName, "message", message)
×
277
                        }
×
278
                }
279
                return false, fmt.Errorf("no supported NIC is selected by the nicSelector in CR %s", cr.GetName())
×
280
        }
281

282
        return true, nil
×
283
}
284

285
func validatePolicyForNodeStateAndPolicy(nsList *sriovnetworkv1.SriovNetworkNodeStateList, npList *sriovnetworkv1.SriovNetworkNodePolicyList, node *corev1.Node, cr *sriovnetworkv1.SriovNetworkNodePolicy, nodeInterfaceErrorList map[string][]string) error {
×
NEW
286
        var currentNodeState *sriovnetworkv1.SriovNetworkNodeState
×
287
        for _, ns := range nsList.Items {
×
288
                if ns.GetName() == node.GetName() {
×
NEW
289
                        currentNodeState = &ns
×
290
                        interfaceAndErrorList, err := validatePolicyForNodeState(cr, &ns, node)
×
291
                        if err != nil {
×
292
                                return err
×
293
                        }
×
294
                        if interfaceAndErrorList != nil {
×
295
                                nodeInterfaceErrorList[ns.GetName()] = interfaceAndErrorList
×
296
                        }
×
297
                        break
×
298
                }
299
        }
UNCOV
300
        for _, np := range npList.Items {
×
UNCOV
301
                if np.GetName() != cr.GetName() && np.Selected(node) {
×
NEW
302
                        if err := validatePolicyForNodePolicy(cr, &np, currentNodeState); err != nil {
×
303
                                return err
×
304
                        }
×
305
                }
306
        }
307
        return nil
×
308
}
309

310
func validatePolicyForNodeState(policy *sriovnetworkv1.SriovNetworkNodePolicy, state *sriovnetworkv1.SriovNetworkNodeState, node *corev1.Node) ([]string, error) {
1✔
311
        log.Log.V(2).Info("validatePolicyForNodeState(): validate policy for node", "policy-name",
1✔
312
                policy.GetName(), "node-name", state.GetName())
1✔
313
        interfaceSelectedForNode := false
1✔
314
        var noInterfacesSelectedLog []string
1✔
315
        for _, iface := range state.Status.Interfaces {
2✔
316
                err := validateNicModel(&policy.Spec.NicSelector, &iface, node)
1✔
317
                if err == nil {
2✔
318
                        interfaceSelected = true
1✔
319
                        interfaceSelectedForNode = true
1✔
320
                        if policy.GetName() != consts.DefaultPolicyName && policy.Spec.NumVfs == 0 {
1✔
321
                                return nil, fmt.Errorf("numVfs(%d) in CR %s is not allowed", policy.Spec.NumVfs, policy.GetName())
×
322
                        }
×
323
                        if policy.Spec.NumVfs > iface.TotalVfs && iface.Vendor == IntelID {
2✔
324
                                return nil, fmt.Errorf("numVfs(%d) in CR %s exceed the maximum allowed value(%d) interface(%s)", policy.Spec.NumVfs, policy.GetName(), iface.TotalVfs, iface.Name)
1✔
325
                        }
1✔
326
                        if policy.Spec.NumVfs > MlxMaxVFs && iface.Vendor == MellanoxID {
1✔
327
                                return nil, fmt.Errorf("numVfs(%d) in CR %s exceed the maximum allowed value(%d) interface(%s)", policy.Spec.NumVfs, policy.GetName(), MlxMaxVFs, iface.Name)
×
328
                        }
×
329

330
                        // Externally create validations
331
                        if policy.Spec.ExternallyManaged {
2✔
332
                                if policy.Spec.NumVfs > iface.NumVfs {
2✔
333
                                        return nil, fmt.Errorf("numVfs(%d) in CR %s is higher than the virtual functions allocated for the PF externally value(%d)", policy.Spec.NumVfs, policy.GetName(), iface.NumVfs)
1✔
334
                                }
1✔
335

336
                                if policy.Spec.Mtu != 0 && policy.Spec.Mtu > iface.Mtu {
2✔
337
                                        return nil, fmt.Errorf("MTU(%d) in CR %s is higher than the MTU for the PF externally value(%d)", policy.Spec.Mtu, policy.GetName(), iface.Mtu)
1✔
338
                                }
1✔
339

340
                                if policy.Spec.LinkType != "" && strings.ToLower(policy.Spec.LinkType) != strings.ToLower(iface.LinkType) {
1✔
341
                                        return nil, fmt.Errorf("LinkType(%s) in CR %s is not equal to the LinkType for the PF externally value(%s)", policy.Spec.LinkType, policy.GetName(), iface.LinkType)
×
342
                                }
×
343
                        }
344
                        // vdpa: only mellanox cards are supported
345
                        if (policy.Spec.VdpaType == consts.VdpaTypeVirtio || policy.Spec.VdpaType == consts.VdpaTypeVhost) && iface.Vendor != MellanoxID {
2✔
346
                                return nil, fmt.Errorf("vendor(%s) in CR %s not supported for vdpa interface(%s)", iface.Vendor, policy.GetName(), iface.Name)
1✔
347
                        }
1✔
348
                } else {
1✔
349
                        errorMessage := fmt.Sprintf("Interface: %s was not selected, since NIC model could not be validated due to the following error: %s \n", iface.Name, err)
1✔
350
                        noInterfacesSelectedLog = append(noInterfacesSelectedLog, errorMessage)
1✔
351
                }
1✔
352
        }
353

354
        if !interfaceSelectedForNode {
2✔
355
                return noInterfacesSelectedLog, nil
1✔
356
        }
1✔
357
        return nil, nil
1✔
358
}
359

360
func validatePolicyForNodePolicy(current *sriovnetworkv1.SriovNetworkNodePolicy, previous *sriovnetworkv1.SriovNetworkNodePolicy, nodeState *sriovnetworkv1.SriovNetworkNodeState) error {
1✔
361
        log.Log.V(2).Info("validateConflictPolicy(): validate policy against policy",
1✔
362
                "source", current.GetName(), "target", previous.GetName())
1✔
363

1✔
364
        if current.GetName() == previous.GetName() {
2✔
365
                return nil
1✔
366
        }
1✔
367

368
        err := validatePfNames(current, previous, nodeState)
1✔
369
        if err != nil {
2✔
370
                return err
1✔
371
        }
1✔
372

373
        err = validateRootDevices(current, previous)
1✔
374
        if err != nil {
2✔
375
                return err
1✔
376
        }
1✔
377

378
        err = validateExludeTopologyField(current, previous)
1✔
379
        if err != nil {
2✔
380
                return err
1✔
381
        }
1✔
382

383
        return nil
1✔
384
}
385

386
func validatePfNames(current *sriovnetworkv1.SriovNetworkNodePolicy, previous *sriovnetworkv1.SriovNetworkNodePolicy, nodeState *sriovnetworkv1.SriovNetworkNodeState) error {
1✔
387
        for _, curPf := range current.Spec.NicSelector.PfNames {
2✔
388
                curName, curRngSt, curRngEnd, err := sriovnetworkv1.ParseVfRange(curPf)
1✔
389
                if err != nil {
1✔
390
                        return fmt.Errorf("invalid PF name: %s", curPf)
×
391
                }
×
392
                // Resolve altName to actual interface name if nodeState is available
393
                if nodeState != nil {
2✔
394
                        curName = sriovnetworkv1.ResolveInterfaceName(curName, nodeState)
1✔
395
                }
1✔
396
                for _, prePf := range previous.Spec.NicSelector.PfNames {
2✔
397
                        // Not validate return err for previous PF
1✔
398
                        // since it should already be evaluated in previous run.
1✔
399
                        preName, preRngSt, preRngEnd, _ := sriovnetworkv1.ParseVfRange(prePf)
1✔
400
                        // Resolve altName to actual interface name if nodeState is available
1✔
401
                        if nodeState != nil {
2✔
402
                                preName = sriovnetworkv1.ResolveInterfaceName(preName, nodeState)
1✔
403
                        }
1✔
404
                        if curName == preName {
2✔
405
                                err = validateExternallyManage(current, previous)
1✔
406
                                if err != nil {
2✔
407
                                        return err
1✔
408
                                }
1✔
409

410
                                // Check for overlapping ranges
411
                                if curRngEnd < preRngSt || curRngSt > preRngEnd {
2✔
412
                                        return nil
1✔
413
                                } else {
2✔
414
                                        return fmt.Errorf("VF index range in %s is overlapped with existing policy %s", curPf, previous.GetName())
1✔
415
                                }
1✔
416
                        }
417
                }
418
        }
419
        return nil
1✔
420
}
421

422
func validateRootDevices(current *sriovnetworkv1.SriovNetworkNodePolicy, previous *sriovnetworkv1.SriovNetworkNodePolicy) error {
1✔
423
        for _, curRootDevice := range current.Spec.NicSelector.RootDevices {
2✔
424
                for _, preRootDevice := range previous.Spec.NicSelector.RootDevices {
2✔
425
                        // TODO: (SchSeba) implement range for root devices
1✔
426
                        if curRootDevice == preRootDevice {
2✔
427
                                return fmt.Errorf("root device %s is overlapped with existing policy %s", curRootDevice, previous.GetName())
1✔
428
                        }
1✔
429
                }
430
        }
431
        return nil
1✔
432
}
433

434
func validateExternallyManage(current, previous *sriovnetworkv1.SriovNetworkNodePolicy) error {
1✔
435
        // reject policy with externallyManage if there is a policy on the same PF without it
1✔
436
        if current.Spec.ExternallyManaged != previous.Spec.ExternallyManaged {
2✔
437
                return fmt.Errorf("externallyManage is inconsistent with existing policy %s", previous.GetName())
1✔
438
        }
1✔
439

440
        return nil
1✔
441
}
442

443
func validateExludeTopologyField(current *sriovnetworkv1.SriovNetworkNodePolicy, previous *sriovnetworkv1.SriovNetworkNodePolicy) error {
1✔
444
        if current.Spec.ResourceName != previous.Spec.ResourceName {
2✔
445
                return nil
1✔
446
        }
1✔
447

448
        if current.Spec.ExcludeTopology == previous.Spec.ExcludeTopology {
2✔
449
                return nil
1✔
450
        }
1✔
451

452
        return fmt.Errorf("excludeTopology[%t] field conflicts with policy [%s].ExcludeTopology[%t] as they target the same resource[%s]",
1✔
453
                current.Spec.ExcludeTopology, previous.GetName(), previous.Spec.ExcludeTopology, current.Spec.ResourceName)
1✔
454
}
455

456
func validateNicModel(selector *sriovnetworkv1.SriovNetworkNicSelector, iface *sriovnetworkv1.InterfaceExt, node *corev1.Node) error {
1✔
457
        if selector.Vendor != "" && selector.Vendor != iface.Vendor {
1✔
458
                return fmt.Errorf("selector vendor: %s is not equal to the interface vendor: %s", selector.Vendor, iface.Vendor)
×
459
        }
×
460
        if selector.DeviceID != "" && selector.DeviceID != iface.DeviceID {
2✔
461
                return fmt.Errorf("selector device ID: %s is not equal to the interface device ID: %s", selector.Vendor, iface.Vendor)
1✔
462
        }
1✔
463
        if len(selector.RootDevices) > 0 && !sriovnetworkv1.StringInArray(iface.PciAddress, selector.RootDevices) {
2✔
464
                return fmt.Errorf("interface PCI address: %s not found in root devices", iface.PciAddress)
1✔
465
        }
1✔
466
        if len(selector.PfNames) > 0 {
2✔
467
                var pfNames []string
1✔
468
                for _, p := range selector.PfNames {
2✔
469
                        if strings.Contains(p, "#") {
2✔
470
                                fields := strings.Split(p, "#")
1✔
471
                                pfNames = append(pfNames, fields[0])
1✔
472
                        } else {
2✔
473
                                pfNames = append(pfNames, p)
1✔
474
                        }
1✔
475
                }
476
                if !sriovnetworkv1.NameOrAltNameMatchesPfNames(iface.Name, iface.AltNames, pfNames) {
2✔
477
                        return fmt.Errorf("interface name: %s (and alternative names) not found in physical function names", iface.Name)
1✔
478
                }
1✔
479
        }
480

481
        // check the vendor/device ID to make sure only devices in supported list are allowed.
482
        if sriovnetworkv1.IsSupportedModel(iface.Vendor, iface.DeviceID) {
2✔
483
                return nil
1✔
484
        }
1✔
485

486
        // Check the vendor and device ID of the VF only if we are on a virtual environment
487
        for key := range vars.PlatformsMap {
2✔
488
                if strings.Contains(strings.ToLower(node.Spec.ProviderID), strings.ToLower(key)) &&
1✔
489
                        selector.NetFilter != "" && selector.NetFilter == iface.NetFilter &&
1✔
490
                        sriovnetworkv1.IsVfSupportedModel(iface.Vendor, iface.DeviceID) {
2✔
491
                        return nil
1✔
492
                }
1✔
493
        }
494

495
        return fmt.Errorf("vendor and device ID is not in supported list")
1✔
496
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc