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

k8snetworkplumbingwg / sriov-network-operator / 8467233545

28 Mar 2024 12:26PM UTC coverage: 38.344% (+0.7%) from 37.675%
8467233545

push

github

web-flow
Merge pull request #643 from ykulazhenkov/pr-turn-on-switchdev

[switchdev 9/9] Enable new switchdev implementation

189 of 289 new or added lines in 9 files covered. (65.4%)

26 existing lines in 8 files now uncovered.

4798 of 12513 relevant lines covered (38.34%)

0.42 hits per line

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

45.77
/api/v1/helper.go
1
package v1
2

3
import (
4
        "context"
5
        "encoding/json"
6
        "fmt"
7
        "os"
8
        "regexp"
9
        "sort"
10
        "strconv"
11
        "strings"
12

13
        corev1 "k8s.io/api/core/v1"
14
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15
        uns "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
16
        intstrutil "k8s.io/apimachinery/pkg/util/intstr"
17
        "k8s.io/client-go/kubernetes"
18
        logf "sigs.k8s.io/controller-runtime/pkg/log"
19

20
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
21
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/render"
22
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
23
)
24

25
const (
26
        LASTNETWORKNAMESPACE    = "operator.sriovnetwork.openshift.io/last-network-namespace"
27
        NETATTDEFFINALIZERNAME  = "netattdef.finalizers.sriovnetwork.openshift.io"
28
        POOLCONFIGFINALIZERNAME = "poolconfig.finalizers.sriovnetwork.openshift.io"
29
        ESwithModeLegacy        = "legacy"
30
        ESwithModeSwitchDev     = "switchdev"
31

32
        SriovCniStateEnable  = "enable"
33
        SriovCniStateDisable = "disable"
34
        SriovCniStateAuto    = "auto"
35
        SriovCniStateOff     = "off"
36
        SriovCniStateOn      = "on"
37
        SriovCniIpam         = "\"ipam\""
38
        SriovCniIpamEmpty    = SriovCniIpam + ":{}"
39
)
40

41
const invalidVfIndex = -1
42

43
var ManifestsPath = "./bindata/manifests/cni-config"
44
var log = logf.Log.WithName("sriovnetwork")
45

46
// NicIDMap contains supported mapping of IDs with each in the format of:
47
// Vendor ID, Physical Function Device ID, Virtual Function Device ID
48
var NicIDMap = []string{}
49

50
var InitialState SriovNetworkNodeState
51

52
// NetFilterType Represents the NetFilter tags to be used
53
type NetFilterType int
54

55
const (
56
        // OpenstackNetworkID network UUID
57
        OpenstackNetworkID NetFilterType = iota
58

59
        SupportedNicIDConfigmap = "supported-nic-ids"
60
)
61

62
type ConfigurationModeType string
63

64
const (
65
        DaemonConfigurationMode  ConfigurationModeType = "daemon"
66
        SystemdConfigurationMode ConfigurationModeType = "systemd"
67
)
68

69
func (e NetFilterType) String() string {
×
70
        switch e {
×
71
        case OpenstackNetworkID:
×
72
                return "openstack/NetworkID"
×
73
        default:
×
74
                return fmt.Sprintf("%d", int(e))
×
75
        }
76
}
77

78
func InitNicIDMapFromConfigMap(client kubernetes.Interface, namespace string) error {
1✔
79
        cm, err := client.CoreV1().ConfigMaps(namespace).Get(
1✔
80
                context.Background(),
1✔
81
                SupportedNicIDConfigmap,
1✔
82
                metav1.GetOptions{},
1✔
83
        )
1✔
84
        // if the configmap does not exist, return false
1✔
85
        if err != nil {
1✔
86
                return err
×
87
        }
×
88
        for _, v := range cm.Data {
2✔
89
                NicIDMap = append(NicIDMap, v)
1✔
90
        }
1✔
91

92
        return nil
1✔
93
}
94

95
func InitNicIDMapFromList(idList []string) {
1✔
96
        NicIDMap = append(NicIDMap, idList...)
1✔
97
}
1✔
98

99
func IsSupportedVendor(vendorID string) bool {
1✔
100
        for _, n := range NicIDMap {
2✔
101
                ids := strings.Split(n, " ")
1✔
102
                if vendorID == ids[0] {
2✔
103
                        return true
1✔
104
                }
1✔
105
        }
106
        return false
1✔
107
}
108

109
func IsSupportedDevice(deviceID string) bool {
1✔
110
        for _, n := range NicIDMap {
2✔
111
                ids := strings.Split(n, " ")
1✔
112
                if deviceID == ids[1] {
1✔
113
                        return true
×
114
                }
×
115
        }
116
        return false
1✔
117
}
118

119
func IsSupportedModel(vendorID, deviceID string) bool {
1✔
120
        for _, n := range NicIDMap {
2✔
121
                ids := strings.Split(n, " ")
1✔
122
                if vendorID == ids[0] && deviceID == ids[1] {
2✔
123
                        return true
1✔
124
                }
1✔
125
        }
126
        log.Info("IsSupportedModel(): found unsupported model", "vendorId:", vendorID, "deviceId:", deviceID)
1✔
127
        return false
1✔
128
}
129

130
func IsVfSupportedModel(vendorID, deviceID string) bool {
1✔
131
        for _, n := range NicIDMap {
2✔
132
                ids := strings.Split(n, " ")
1✔
133
                if vendorID == ids[0] && deviceID == ids[2] {
2✔
134
                        return true
1✔
135
                }
1✔
136
        }
137
        log.Info("IsVfSupportedModel(): found unsupported VF model", "vendorId:", vendorID, "deviceId:", deviceID)
×
138
        return false
×
139
}
140

141
func IsEnabledUnsupportedVendor(vendorID string, unsupportedNicIDMap map[string]string) bool {
×
142
        for _, n := range unsupportedNicIDMap {
×
143
                if IsValidPciString(n) {
×
144
                        ids := strings.Split(n, " ")
×
145
                        if vendorID == ids[0] {
×
146
                                return true
×
147
                        }
×
148
                }
149
        }
150
        return false
×
151
}
152

153
func IsValidPciString(nicIDString string) bool {
×
154
        ids := strings.Split(nicIDString, " ")
×
155

×
156
        if len(ids) != 3 {
×
157
                log.Info("IsValidPciString(): ", nicIDString)
×
158
                return false
×
159
        }
×
160

161
        if len(ids[0]) != 4 {
×
162
                log.Info("IsValidPciString():", "Invalid vendor PciId ", ids[0])
×
163
                return false
×
164
        }
×
165
        if _, err := strconv.ParseInt(ids[0], 16, 32); err != nil {
×
166
                log.Info("IsValidPciString():", "Invalid vendor PciId ", ids[0])
×
167
        }
×
168

169
        if len(ids[1]) != 4 {
×
170
                log.Info("IsValidPciString():", "Invalid PciId of PF ", ids[1])
×
171
                return false
×
172
        }
×
173
        if _, err := strconv.ParseInt(ids[1], 16, 32); err != nil {
×
174
                log.Info("IsValidPciString():", "Invalid PciId of PF ", ids[1])
×
175
        }
×
176

177
        if len(ids[2]) != 4 {
×
178
                log.Info("IsValidPciString():", "Invalid PciId of VF ", ids[2])
×
179
                return false
×
180
        }
×
181
        if _, err := strconv.ParseInt(ids[2], 16, 32); err != nil {
×
182
                log.Info("IsValidPciString():", "Invalid PciId of VF ", ids[2])
×
183
        }
×
184

185
        return true
×
186
}
187

188
func GetSupportedVfIds() []string {
1✔
189
        var vfIds []string
1✔
190
        for _, n := range NicIDMap {
2✔
191
                ids := strings.Split(n, " ")
1✔
192
                vfID := "0x" + ids[2]
1✔
193
                if !StringInArray(vfID, vfIds) {
2✔
194
                        vfIds = append(vfIds, vfID)
1✔
195
                }
1✔
196
        }
197
        // return a sorted slice so that udev rule is stable
198
        sort.Slice(vfIds, func(i, j int) bool {
2✔
199
                ip, _ := strconv.ParseInt(vfIds[i], 0, 32)
1✔
200
                jp, _ := strconv.ParseInt(vfIds[j], 0, 32)
1✔
201
                return ip < jp
1✔
202
        })
1✔
203
        return vfIds
1✔
204
}
205

206
func GetVfDeviceID(deviceID string) string {
×
207
        for _, n := range NicIDMap {
×
208
                ids := strings.Split(n, " ")
×
209
                if deviceID == ids[1] {
×
210
                        return ids[2]
×
211
                }
×
212
        }
213
        return ""
×
214
}
215

216
func IsSwitchdevModeSpec(spec SriovNetworkNodeStateSpec) bool {
1✔
217
        return ContainsSwitchdevInterface(spec.Interfaces)
1✔
218
}
1✔
219

220
// ContainsSwitchdevInterface returns true if provided interface list contains interface
221
// with switchdev configuration
222
func ContainsSwitchdevInterface(interfaces []Interface) bool {
1✔
223
        for _, iface := range interfaces {
2✔
224
                if iface.EswitchMode == ESwithModeSwitchDev {
2✔
225
                        return true
1✔
226
                }
1✔
227
        }
228
        return false
1✔
229
}
230

231
func FindInterface(interfaces Interfaces, name string) (iface Interface, err error) {
×
232
        for _, i := range interfaces {
×
233
                if i.Name == name {
×
234
                        return i, nil
×
235
                }
×
236
        }
237
        return Interface{}, fmt.Errorf("unable to find interface: %v", name)
×
238
}
239

240
// GetEswitchModeFromSpec returns ESwitchMode from the interface spec, returns legacy if not set
241
func GetEswitchModeFromSpec(ifaceSpec *Interface) string {
1✔
242
        if ifaceSpec.EswitchMode == "" {
2✔
243
                return ESwithModeLegacy
1✔
244
        }
1✔
245
        return ifaceSpec.EswitchMode
1✔
246
}
247

248
// GetEswitchModeFromStatus returns ESwitchMode from the interface status, returns legacy if not set
249
func GetEswitchModeFromStatus(ifaceStatus *InterfaceExt) string {
1✔
250
        if ifaceStatus.EswitchMode == "" {
2✔
251
                return ESwithModeLegacy
1✔
252
        }
1✔
253
        return ifaceStatus.EswitchMode
1✔
254
}
255

256
func NeedToUpdateSriov(ifaceSpec *Interface, ifaceStatus *InterfaceExt) bool {
1✔
257
        if ifaceSpec.Mtu > 0 {
2✔
258
                mtu := ifaceSpec.Mtu
1✔
259
                if mtu != ifaceStatus.Mtu {
2✔
260
                        log.V(2).Info("NeedToUpdateSriov(): MTU needs update", "desired", mtu, "current", ifaceStatus.Mtu)
1✔
261
                        return true
1✔
262
                }
1✔
263
        }
264
        currentEswitchMode := GetEswitchModeFromStatus(ifaceStatus)
1✔
265
        desiredEswitchMode := GetEswitchModeFromSpec(ifaceSpec)
1✔
266
        if currentEswitchMode != desiredEswitchMode {
2✔
267
                log.V(2).Info("NeedToUpdateSriov(): EswitchMode needs update", "desired", desiredEswitchMode, "current", currentEswitchMode)
1✔
268
                return true
1✔
269
        }
1✔
270
        if ifaceSpec.NumVfs != ifaceStatus.NumVfs {
2✔
271
                log.V(2).Info("NeedToUpdateSriov(): NumVfs needs update", "desired", ifaceSpec.NumVfs, "current", ifaceStatus.NumVfs)
1✔
272
                return true
1✔
273
        }
1✔
274
        if ifaceSpec.NumVfs > 0 {
2✔
275
                for _, vfStatus := range ifaceStatus.VFs {
2✔
276
                        ingroup := false
1✔
277
                        for _, groupSpec := range ifaceSpec.VfGroups {
2✔
278
                                if IndexInRange(vfStatus.VfID, groupSpec.VfRange) {
2✔
279
                                        ingroup = true
1✔
280
                                        if vfStatus.Driver == "" {
1✔
281
                                                log.V(2).Info("NeedToUpdateSriov(): Driver needs update - has no driver",
×
282
                                                        "desired", groupSpec.DeviceType)
×
283
                                                return true
×
284
                                        }
×
285
                                        if groupSpec.DeviceType != "" && groupSpec.DeviceType != consts.DeviceTypeNetDevice {
1✔
286
                                                if groupSpec.DeviceType != vfStatus.Driver {
×
287
                                                        log.V(2).Info("NeedToUpdateSriov(): Driver needs update",
×
288
                                                                "desired", groupSpec.DeviceType, "current", vfStatus.Driver)
×
289
                                                        return true
×
290
                                                }
×
291
                                        } else {
1✔
292
                                                if StringInArray(vfStatus.Driver, vars.DpdkDrivers) {
1✔
293
                                                        log.V(2).Info("NeedToUpdateSriov(): Driver needs update",
×
294
                                                                "desired", groupSpec.DeviceType, "current", vfStatus.Driver)
×
295
                                                        return true
×
296
                                                }
×
297
                                                if vfStatus.Mtu != 0 && groupSpec.Mtu != 0 && vfStatus.Mtu != groupSpec.Mtu {
2✔
298
                                                        log.V(2).Info("NeedToUpdateSriov(): VF MTU needs update",
1✔
299
                                                                "vf", vfStatus.VfID, "desired", groupSpec.Mtu, "current", vfStatus.Mtu)
1✔
300
                                                        return true
1✔
301
                                                }
1✔
302

303
                                                // this is needed to be sure the admin mac address is configured as expected
304
                                                if ifaceSpec.ExternallyManaged {
1✔
305
                                                        log.V(2).Info("NeedToUpdateSriov(): need to update the device as it's externally manage",
×
306
                                                                "device", ifaceStatus.PciAddress)
×
307
                                                        return true
×
308
                                                }
×
309
                                        }
310
                                        if groupSpec.VdpaType != vfStatus.VdpaType {
1✔
NEW
311
                                                log.V(2).Info("NeedToUpdateSriov(): VF VdpaType mismatch",
×
NEW
312
                                                        "desired", groupSpec.VdpaType, "current", vfStatus.VdpaType)
×
NEW
313
                                                return true
×
NEW
314
                                        }
×
315
                                        break
1✔
316
                                }
317
                        }
318
                        if !ingroup && (StringInArray(vfStatus.Driver, vars.DpdkDrivers) || vfStatus.VdpaType != "") {
1✔
NEW
319
                                // need to reset VF if it is not a part of a group and:
×
NEW
320
                                // a. has DPDK driver loaded
×
NEW
321
                                // b. has VDPA device
×
322
                                return true
×
323
                        }
×
324
                }
325
        }
326
        return false
1✔
327
}
328

329
type ByPriority []SriovNetworkNodePolicy
330

331
func (a ByPriority) Len() int {
×
332
        return len(a)
×
333
}
×
334

335
func (a ByPriority) Less(i, j int) bool {
×
336
        if a[i].Spec.Priority != a[j].Spec.Priority {
×
337
                return a[i].Spec.Priority > a[j].Spec.Priority
×
338
        }
×
339
        return a[i].GetName() < a[j].GetName()
×
340
}
341

342
func (a ByPriority) Swap(i, j int) {
×
343
        a[i], a[j] = a[j], a[i]
×
344
}
×
345

346
// Match check if node is selected by NodeSelector
347
func (p *SriovNetworkNodePolicy) Selected(node *corev1.Node) bool {
1✔
348
        for k, v := range p.Spec.NodeSelector {
1✔
349
                if nv, ok := node.Labels[k]; ok && nv == v {
×
350
                        continue
×
351
                }
352
                return false
×
353
        }
354
        return true
1✔
355
}
356

357
func StringInArray(val string, array []string) bool {
1✔
358
        for i := range array {
2✔
359
                if array[i] == val {
2✔
360
                        return true
1✔
361
                }
1✔
362
        }
363
        return false
1✔
364
}
365

366
func RemoveString(s string, slice []string) (result []string, found bool) {
1✔
367
        if len(slice) != 0 {
2✔
368
                for _, item := range slice {
2✔
369
                        if item == s {
2✔
370
                                found = true
1✔
371
                                continue
1✔
372
                        }
373
                        result = append(result, item)
×
374
                }
375
        }
376
        return
1✔
377
}
378

379
func UniqueAppend(inSlice []string, strings ...string) []string {
×
380
        for _, s := range strings {
×
381
                if !StringInArray(s, inSlice) {
×
382
                        inSlice = append(inSlice, s)
×
383
                }
×
384
        }
385
        return inSlice
×
386
}
387

388
// Apply policy to SriovNetworkNodeState CR
389
func (p *SriovNetworkNodePolicy) Apply(state *SriovNetworkNodeState, equalPriority bool) error {
×
390
        s := p.Spec.NicSelector
×
391
        if s.Vendor == "" && s.DeviceID == "" && len(s.RootDevices) == 0 && len(s.PfNames) == 0 &&
×
392
                len(s.NetFilter) == 0 {
×
393
                // Empty NicSelector match none
×
394
                return nil
×
395
        }
×
396
        for _, iface := range state.Status.Interfaces {
×
397
                if s.Selected(&iface) {
×
398
                        log.Info("Update interface", "name:", iface.Name)
×
399
                        result := Interface{
×
400
                                PciAddress:        iface.PciAddress,
×
401
                                Mtu:               p.Spec.Mtu,
×
402
                                Name:              iface.Name,
×
403
                                LinkType:          p.Spec.LinkType,
×
404
                                EswitchMode:       p.Spec.EswitchMode,
×
405
                                NumVfs:            p.Spec.NumVfs,
×
406
                                ExternallyManaged: p.Spec.ExternallyManaged,
×
407
                        }
×
408
                        if p.Spec.NumVfs > 0 {
×
409
                                group, err := p.generateVfGroup(&iface)
×
410
                                if err != nil {
×
411
                                        return err
×
412
                                }
×
413
                                result.VfGroups = []VfGroup{*group}
×
414
                                found := false
×
415
                                for i := range state.Spec.Interfaces {
×
416
                                        if state.Spec.Interfaces[i].PciAddress == result.PciAddress {
×
417
                                                found = true
×
418
                                                state.Spec.Interfaces[i].mergeConfigs(&result, equalPriority)
×
419
                                                state.Spec.Interfaces[i] = result
×
420
                                                break
×
421
                                        }
422
                                }
423
                                if !found {
×
424
                                        state.Spec.Interfaces = append(state.Spec.Interfaces, result)
×
425
                                }
×
426
                        }
427
                }
428
        }
429
        return nil
×
430
}
431

432
// mergeConfigs merges configs from multiple polices where the last one has the
433
// highest priority. This merge is dependent on: 1. SR-IOV partition is
434
// configured with the #-notation in pfName, 2. The VF groups are
435
// non-overlapping or SR-IOV policies have the same priority.
436
func (iface Interface) mergeConfigs(input *Interface, equalPriority bool) {
×
437
        m := false
×
438
        // merge VF groups (input.VfGroups already contains the highest priority):
×
439
        // - skip group with same ResourceName,
×
440
        // - skip overlapping groups (use only highest priority)
×
441
        for _, gr := range iface.VfGroups {
×
442
                if gr.ResourceName == input.VfGroups[0].ResourceName || gr.isVFRangeOverlapping(input.VfGroups[0]) {
×
443
                        continue
×
444
                }
445
                m = true
×
446
                input.VfGroups = append(input.VfGroups, gr)
×
447
        }
448

449
        if !equalPriority && !m {
×
450
                return
×
451
        }
×
452

453
        // mtu configuration we take the highest value
454
        if input.Mtu < iface.Mtu {
×
455
                input.Mtu = iface.Mtu
×
456
        }
×
457
        if input.NumVfs < iface.NumVfs {
×
458
                input.NumVfs = iface.NumVfs
×
459
        }
×
460
}
461

462
func (gr VfGroup) isVFRangeOverlapping(group VfGroup) bool {
×
463
        rngSt, rngEnd, err := parseRange(gr.VfRange)
×
464
        if err != nil {
×
465
                return false
×
466
        }
×
467
        rngSt2, rngEnd2, err := parseRange(group.VfRange)
×
468
        if err != nil {
×
469
                return false
×
470
        }
×
471
        // compare minimal range has overlap
472
        if rngSt < rngSt2 {
×
473
                return IndexInRange(rngSt2, gr.VfRange) || IndexInRange(rngEnd2, gr.VfRange)
×
474
        }
×
475
        return IndexInRange(rngSt, group.VfRange) || IndexInRange(rngEnd, group.VfRange)
×
476
}
477

478
func (p *SriovNetworkNodePolicy) generateVfGroup(iface *InterfaceExt) (*VfGroup, error) {
×
479
        var err error
×
480
        pfName := ""
×
481
        var rngStart, rngEnd int
×
482
        found := false
×
483
        for _, selector := range p.Spec.NicSelector.PfNames {
×
484
                pfName, rngStart, rngEnd, err = ParsePFName(selector)
×
485
                if err != nil {
×
486
                        log.Error(err, "Unable to parse PF Name.")
×
487
                        return nil, err
×
488
                }
×
489
                if pfName == iface.Name {
×
490
                        found = true
×
491
                        if rngStart == invalidVfIndex && rngEnd == invalidVfIndex {
×
492
                                rngStart, rngEnd = 0, p.Spec.NumVfs-1
×
493
                        }
×
494
                        break
×
495
                }
496
        }
497
        if !found {
×
498
                // assign the default vf index range if the pfName is not specified by the nicSelector
×
499
                rngStart, rngEnd = 0, p.Spec.NumVfs-1
×
500
        }
×
501
        rng := strconv.Itoa(rngStart) + "-" + strconv.Itoa(rngEnd)
×
502
        return &VfGroup{
×
503
                ResourceName: p.Spec.ResourceName,
×
504
                DeviceType:   p.Spec.DeviceType,
×
505
                VfRange:      rng,
×
506
                PolicyName:   p.GetName(),
×
507
                Mtu:          p.Spec.Mtu,
×
508
                IsRdma:       p.Spec.IsRdma,
×
509
                VdpaType:     p.Spec.VdpaType,
×
510
        }, nil
×
511
}
512

513
func IndexInRange(i int, r string) bool {
1✔
514
        rngSt, rngEnd, err := parseRange(r)
1✔
515
        if err != nil {
1✔
516
                return false
×
517
        }
×
518
        if i <= rngEnd && i >= rngSt {
2✔
519
                return true
1✔
520
        }
1✔
521
        return false
1✔
522
}
523

524
func parseRange(r string) (rngSt, rngEnd int, err error) {
1✔
525
        rng := strings.Split(r, "-")
1✔
526
        rngSt, err = strconv.Atoi(rng[0])
1✔
527
        if err != nil {
1✔
528
                return
×
529
        }
×
530
        rngEnd, err = strconv.Atoi(rng[1])
1✔
531
        if err != nil {
1✔
532
                return
×
533
        }
×
534
        return
1✔
535
}
536

537
// Parse PF name with VF range
538
func ParsePFName(name string) (ifName string, rngSt, rngEnd int, err error) {
1✔
539
        rngSt, rngEnd = invalidVfIndex, invalidVfIndex
1✔
540
        if strings.Contains(name, "#") {
2✔
541
                fields := strings.Split(name, "#")
1✔
542
                ifName = fields[0]
1✔
543
                rngSt, rngEnd, err = parseRange(fields[1])
1✔
544
        } else {
1✔
545
                ifName = name
×
546
        }
×
547
        return
1✔
548
}
549

550
func (selector *SriovNetworkNicSelector) Selected(iface *InterfaceExt) bool {
×
551
        if selector.Vendor != "" && selector.Vendor != iface.Vendor {
×
552
                return false
×
553
        }
×
554
        if selector.DeviceID != "" && selector.DeviceID != iface.DeviceID {
×
555
                return false
×
556
        }
×
557
        if len(selector.RootDevices) > 0 && !StringInArray(iface.PciAddress, selector.RootDevices) {
×
558
                return false
×
559
        }
×
560
        if len(selector.PfNames) > 0 {
×
561
                var pfNames []string
×
562
                for _, p := range selector.PfNames {
×
563
                        if strings.Contains(p, "#") {
×
564
                                fields := strings.Split(p, "#")
×
565
                                pfNames = append(pfNames, fields[0])
×
566
                        } else {
×
567
                                pfNames = append(pfNames, p)
×
568
                        }
×
569
                }
570
                if !StringInArray(iface.Name, pfNames) {
×
571
                        return false
×
572
                }
×
573
        }
574
        if selector.NetFilter != "" && !NetFilterMatch(selector.NetFilter, iface.NetFilter) {
×
575
                return false
×
576
        }
×
577

578
        return true
×
579
}
580

581
func (s *SriovNetworkNodeState) GetInterfaceStateByPciAddress(addr string) *InterfaceExt {
1✔
582
        for _, iface := range s.Status.Interfaces {
1✔
583
                if addr == iface.PciAddress {
×
584
                        return &iface
×
585
                }
×
586
        }
587
        return nil
1✔
588
}
589

590
func (s *SriovNetworkNodeState) GetDriverByPciAddress(addr string) string {
×
591
        for _, iface := range s.Status.Interfaces {
×
592
                if addr == iface.PciAddress {
×
593
                        return iface.Driver
×
594
                }
×
595
        }
596
        return ""
×
597
}
598

599
// RenderNetAttDef renders a net-att-def for ib-sriov CNI
600
func (cr *SriovIBNetwork) RenderNetAttDef() (*uns.Unstructured, error) {
1✔
601
        logger := log.WithName("RenderNetAttDef")
1✔
602
        logger.Info("Start to render IB SRIOV CNI NetworkAttachmentDefinition")
1✔
603

1✔
604
        // render RawCNIConfig manifests
1✔
605
        data := render.MakeRenderData()
1✔
606
        data.Data["CniType"] = "ib-sriov"
1✔
607
        data.Data["SriovNetworkName"] = cr.Name
1✔
608
        if cr.Spec.NetworkNamespace == "" {
2✔
609
                data.Data["SriovNetworkNamespace"] = cr.Namespace
1✔
610
        } else {
2✔
611
                data.Data["SriovNetworkNamespace"] = cr.Spec.NetworkNamespace
1✔
612
        }
1✔
613
        data.Data["SriovCniResourceName"] = os.Getenv("RESOURCE_PREFIX") + "/" + cr.Spec.ResourceName
1✔
614

1✔
615
        data.Data["StateConfigured"] = true
1✔
616
        switch cr.Spec.LinkState {
1✔
617
        case SriovCniStateEnable:
1✔
618
                data.Data["SriovCniState"] = SriovCniStateEnable
1✔
619
        case SriovCniStateDisable:
×
620
                data.Data["SriovCniState"] = SriovCniStateDisable
×
621
        case SriovCniStateAuto:
×
622
                data.Data["SriovCniState"] = SriovCniStateAuto
×
623
        default:
1✔
624
                data.Data["StateConfigured"] = false
1✔
625
        }
626

627
        if cr.Spec.Capabilities == "" {
2✔
628
                data.Data["CapabilitiesConfigured"] = false
1✔
629
        } else {
1✔
630
                data.Data["CapabilitiesConfigured"] = true
×
631
                data.Data["SriovCniCapabilities"] = cr.Spec.Capabilities
×
632
        }
×
633

634
        if cr.Spec.IPAM != "" {
2✔
635
                data.Data["SriovCniIpam"] = SriovCniIpam + ":" + strings.Join(strings.Fields(cr.Spec.IPAM), "")
1✔
636
        } else {
2✔
637
                data.Data["SriovCniIpam"] = SriovCniIpamEmpty
1✔
638
        }
1✔
639

640
        // metaplugins for the infiniband cni
641
        data.Data["MetaPluginsConfigured"] = false
1✔
642
        if cr.Spec.MetaPluginsConfig != "" {
1✔
643
                data.Data["MetaPluginsConfigured"] = true
×
644
                data.Data["MetaPlugins"] = cr.Spec.MetaPluginsConfig
×
645
        }
×
646

647
        // logLevel and logFile are currently not supports by the ip-sriov-cni -> hardcode them to false.
648
        data.Data["LogLevelConfigured"] = false
1✔
649
        data.Data["LogFileConfigured"] = false
1✔
650

1✔
651
        objs, err := render.RenderDir(ManifestsPath, &data)
1✔
652
        if err != nil {
1✔
653
                return nil, err
×
654
        }
×
655
        for _, obj := range objs {
2✔
656
                raw, _ := json.Marshal(obj)
1✔
657
                logger.Info("render NetworkAttachmentDefinition output", "raw", string(raw))
1✔
658
        }
1✔
659
        return objs[0], nil
1✔
660
}
661

662
// NetworkNamespace returns target network namespace for the network
663
func (cr *SriovIBNetwork) NetworkNamespace() string {
1✔
664
        return cr.Spec.NetworkNamespace
1✔
665
}
1✔
666

667
// RenderNetAttDef renders a net-att-def for sriov CNI
668
func (cr *SriovNetwork) RenderNetAttDef() (*uns.Unstructured, error) {
1✔
669
        logger := log.WithName("RenderNetAttDef")
1✔
670
        logger.Info("Start to render SRIOV CNI NetworkAttachmentDefinition")
1✔
671

1✔
672
        // render RawCNIConfig manifests
1✔
673
        data := render.MakeRenderData()
1✔
674
        data.Data["CniType"] = "sriov"
1✔
675
        data.Data["SriovNetworkName"] = cr.Name
1✔
676
        if cr.Spec.NetworkNamespace == "" {
2✔
677
                data.Data["SriovNetworkNamespace"] = cr.Namespace
1✔
678
        } else {
2✔
679
                data.Data["SriovNetworkNamespace"] = cr.Spec.NetworkNamespace
1✔
680
        }
1✔
681
        data.Data["SriovCniResourceName"] = os.Getenv("RESOURCE_PREFIX") + "/" + cr.Spec.ResourceName
1✔
682
        data.Data["SriovCniVlan"] = cr.Spec.Vlan
1✔
683

1✔
684
        if cr.Spec.VlanQoS <= 7 && cr.Spec.VlanQoS >= 0 {
2✔
685
                data.Data["VlanQoSConfigured"] = true
1✔
686
                data.Data["SriovCniVlanQoS"] = cr.Spec.VlanQoS
1✔
687
        } else {
1✔
688
                data.Data["VlanQoSConfigured"] = false
×
689
        }
×
690

691
        data.Data["VlanProtoConfigured"] = false
1✔
692
        if cr.Spec.VlanProto != "" {
2✔
693
                data.Data["VlanProtoConfigured"] = true
1✔
694
                data.Data["SriovCniVlanProto"] = cr.Spec.VlanProto
1✔
695
        }
1✔
696

697
        if cr.Spec.Capabilities == "" {
2✔
698
                data.Data["CapabilitiesConfigured"] = false
1✔
699
        } else {
1✔
700
                data.Data["CapabilitiesConfigured"] = true
×
701
                data.Data["SriovCniCapabilities"] = cr.Spec.Capabilities
×
702
        }
×
703

704
        data.Data["SpoofChkConfigured"] = true
1✔
705
        switch cr.Spec.SpoofChk {
1✔
706
        case SriovCniStateOff:
×
707
                data.Data["SriovCniSpoofChk"] = SriovCniStateOff
×
708
        case SriovCniStateOn:
1✔
709
                data.Data["SriovCniSpoofChk"] = SriovCniStateOn
1✔
710
        default:
1✔
711
                data.Data["SpoofChkConfigured"] = false
1✔
712
        }
713

714
        data.Data["TrustConfigured"] = true
1✔
715
        switch cr.Spec.Trust {
1✔
716
        case SriovCniStateOn:
1✔
717
                data.Data["SriovCniTrust"] = SriovCniStateOn
1✔
718
        case SriovCniStateOff:
×
719
                data.Data["SriovCniTrust"] = SriovCniStateOff
×
720
        default:
1✔
721
                data.Data["TrustConfigured"] = false
1✔
722
        }
723

724
        data.Data["StateConfigured"] = true
1✔
725
        switch cr.Spec.LinkState {
1✔
726
        case SriovCniStateEnable:
×
727
                data.Data["SriovCniState"] = SriovCniStateEnable
×
728
        case SriovCniStateDisable:
×
729
                data.Data["SriovCniState"] = SriovCniStateDisable
×
730
        case SriovCniStateAuto:
×
731
                data.Data["SriovCniState"] = SriovCniStateAuto
×
732
        default:
1✔
733
                data.Data["StateConfigured"] = false
1✔
734
        }
735

736
        data.Data["MinTxRateConfigured"] = false
1✔
737
        if cr.Spec.MinTxRate != nil {
1✔
738
                if *cr.Spec.MinTxRate >= 0 {
×
739
                        data.Data["MinTxRateConfigured"] = true
×
740
                        data.Data["SriovCniMinTxRate"] = *cr.Spec.MinTxRate
×
741
                }
×
742
        }
743

744
        data.Data["MaxTxRateConfigured"] = false
1✔
745
        if cr.Spec.MaxTxRate != nil {
1✔
746
                if *cr.Spec.MaxTxRate >= 0 {
×
747
                        data.Data["MaxTxRateConfigured"] = true
×
748
                        data.Data["SriovCniMaxTxRate"] = *cr.Spec.MaxTxRate
×
749
                }
×
750
        }
751

752
        if cr.Spec.IPAM != "" {
2✔
753
                data.Data["SriovCniIpam"] = SriovCniIpam + ":" + strings.Join(strings.Fields(cr.Spec.IPAM), "")
1✔
754
        } else {
1✔
755
                data.Data["SriovCniIpam"] = SriovCniIpamEmpty
×
756
        }
×
757

758
        data.Data["MetaPluginsConfigured"] = false
1✔
759
        if cr.Spec.MetaPluginsConfig != "" {
1✔
760
                data.Data["MetaPluginsConfigured"] = true
×
761
                data.Data["MetaPlugins"] = cr.Spec.MetaPluginsConfig
×
762
        }
×
763

764
        data.Data["LogLevelConfigured"] = (cr.Spec.LogLevel != "")
1✔
765
        data.Data["LogLevel"] = cr.Spec.LogLevel
1✔
766
        data.Data["LogFileConfigured"] = (cr.Spec.LogFile != "")
1✔
767
        data.Data["LogFile"] = cr.Spec.LogFile
1✔
768

1✔
769
        objs, err := render.RenderDir(ManifestsPath, &data)
1✔
770
        if err != nil {
1✔
771
                return nil, err
×
772
        }
×
773
        for _, obj := range objs {
2✔
774
                raw, _ := json.Marshal(obj)
1✔
775
                logger.Info("render NetworkAttachmentDefinition output", "raw", string(raw))
1✔
776
        }
1✔
777
        return objs[0], nil
1✔
778
}
779

780
// NetworkNamespace returns target network namespace for the network
781
func (cr *SriovNetwork) NetworkNamespace() string {
1✔
782
        return cr.Spec.NetworkNamespace
1✔
783
}
1✔
784

785
// NetFilterMatch -- parse netFilter and check for a match
786
func NetFilterMatch(netFilter string, netValue string) (isMatch bool) {
×
787
        logger := log.WithName("NetFilterMatch")
×
788

×
789
        var re = regexp.MustCompile(`(?m)^\s*([^\s]+)\s*:\s*([^\s]+)`)
×
790

×
791
        netFilterResult := re.FindAllStringSubmatch(netFilter, -1)
×
792

×
793
        if netFilterResult == nil {
×
794
                logger.Info("Invalid NetFilter spec...", "netFilter", netFilter)
×
795
                return false
×
796
        }
×
797

798
        netValueResult := re.FindAllStringSubmatch(netValue, -1)
×
799

×
800
        if netValueResult == nil {
×
801
                logger.Info("Invalid netValue...", "netValue", netValue)
×
802
                return false
×
803
        }
×
804

805
        return netFilterResult[0][1] == netValueResult[0][1] && netFilterResult[0][2] == netValueResult[0][2]
×
806
}
807

808
// MaxUnavailable calculate the max number of unavailable nodes to represent the number of nodes
809
// we can drain in parallel
810
func (s *SriovNetworkPoolConfig) MaxUnavailable(numOfNodes int) (int, error) {
1✔
811
        // this means we want to drain all the nodes in parallel
1✔
812
        if s.Spec.MaxUnavailable == nil {
2✔
813
                return -1, nil
1✔
814
        }
1✔
815
        intOrPercent := *s.Spec.MaxUnavailable
1✔
816

1✔
817
        if intOrPercent.Type == intstrutil.String {
1✔
818
                if strings.HasSuffix(intOrPercent.StrVal, "%") {
×
819
                        i := strings.TrimSuffix(intOrPercent.StrVal, "%")
×
820
                        v, err := strconv.Atoi(i)
×
821
                        if err != nil {
×
822
                                return 0, fmt.Errorf("invalid value %q: %v", intOrPercent.StrVal, err)
×
823
                        }
×
824
                        if v > 100 || v < 1 {
×
825
                                return 0, fmt.Errorf("invalid value: percentage needs to be between 1 and 100")
×
826
                        }
×
827
                } else {
×
828
                        return 0, fmt.Errorf("invalid type: strings needs to be a percentage")
×
829
                }
×
830
        }
831

832
        maxunavail, err := intstrutil.GetScaledValueFromIntOrPercent(&intOrPercent, numOfNodes, false)
1✔
833
        if err != nil {
1✔
834
                return 0, err
×
835
        }
×
836

837
        if maxunavail < 0 {
1✔
838
                return 0, fmt.Errorf("negative number is not allowed")
×
839
        }
×
840

841
        return maxunavail, nil
1✔
842
}
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