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

k8snetworkplumbingwg / sriov-network-operator / 10058808149

23 Jul 2024 12:22PM UTC coverage: 43.964% (+0.6%) from 43.351%
10058808149

Pull #659

github

web-flow
Merge f199eb95f into 588abb449
Pull Request #659: Configure IB VFs' GUIDs using a statically provided GUID pool

212 of 280 new or added lines in 13 files covered. (75.71%)

2 existing lines in 1 file now uncovered.

6526 of 14844 relevant lines covered (43.96%)

0.48 hits per line

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

55.5
/pkg/host/internal/sriov/sriov.go
1
package sriov
2

3
import (
4
        "errors"
5
        "fmt"
6
        "os"
7
        "path/filepath"
8
        "strconv"
9
        "strings"
10
        "syscall"
11
        "time"
12

13
        "github.com/jaypipes/ghw"
14
        "github.com/vishvananda/netlink"
15
        "k8s.io/apimachinery/pkg/util/wait"
16
        "sigs.k8s.io/controller-runtime/pkg/log"
17

18
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
19
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
20
        dputilsPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/dputils"
21
        ghwPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/ghw"
22
        netlinkPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/netlink"
23
        sriovnetPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/sriovnet"
24
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/store"
25
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
26
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
27
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
28
)
29

30
type interfaceToConfigure struct {
31
        iface       sriovnetworkv1.Interface
32
        ifaceStatus sriovnetworkv1.InterfaceExt
33
}
34

35
type sriov struct {
36
        utilsHelper      utils.CmdInterface
37
        kernelHelper     types.KernelInterface
38
        networkHelper    types.NetworkInterface
39
        udevHelper       types.UdevInterface
40
        vdpaHelper       types.VdpaInterface
41
        infinibandHelper types.InfinibandInterface
42
        netlinkLib       netlinkPkg.NetlinkLib
43
        dputilsLib       dputilsPkg.DPUtilsLib
44
        sriovnetLib      sriovnetPkg.SriovnetLib
45
        ghwLib           ghwPkg.GHWLib
46
}
47

48
func New(utilsHelper utils.CmdInterface,
49
        kernelHelper types.KernelInterface,
50
        networkHelper types.NetworkInterface,
51
        udevHelper types.UdevInterface,
52
        vdpaHelper types.VdpaInterface,
53
        infinibandHelper types.InfinibandInterface,
54
        netlinkLib netlinkPkg.NetlinkLib,
55
        dputilsLib dputilsPkg.DPUtilsLib,
56
        sriovnetLib sriovnetPkg.SriovnetLib,
57
        ghwLib ghwPkg.GHWLib) types.SriovInterface {
1✔
58
        return &sriov{utilsHelper: utilsHelper,
1✔
59
                kernelHelper:     kernelHelper,
1✔
60
                networkHelper:    networkHelper,
1✔
61
                udevHelper:       udevHelper,
1✔
62
                vdpaHelper:       vdpaHelper,
1✔
63
                infinibandHelper: infinibandHelper,
1✔
64
                netlinkLib:       netlinkLib,
1✔
65
                dputilsLib:       dputilsLib,
1✔
66
                sriovnetLib:      sriovnetLib,
1✔
67
                ghwLib:           ghwLib,
1✔
68
        }
1✔
69
}
1✔
70

71
func (s *sriov) SetSriovNumVfs(pciAddr string, numVfs int) error {
1✔
72
        log.Log.V(2).Info("SetSriovNumVfs(): set NumVfs", "device", pciAddr, "numVfs", numVfs)
1✔
73
        numVfsFilePath := filepath.Join(vars.FilesystemRoot, consts.SysBusPciDevices, pciAddr, consts.NumVfsFile)
1✔
74
        bs := []byte(strconv.Itoa(numVfs))
1✔
75
        err := os.WriteFile(numVfsFilePath, []byte("0"), os.ModeAppend)
1✔
76
        if err != nil {
2✔
77
                log.Log.Error(err, "SetSriovNumVfs(): fail to reset NumVfs file", "path", numVfsFilePath)
1✔
78
                return err
1✔
79
        }
1✔
80
        if numVfs == 0 {
2✔
81
                return nil
1✔
82
        }
1✔
83
        err = os.WriteFile(numVfsFilePath, bs, os.ModeAppend)
1✔
84
        if err != nil {
1✔
85
                log.Log.Error(err, "SetSriovNumVfs(): fail to set NumVfs file", "path", numVfsFilePath)
×
86
                return err
×
87
        }
×
88
        return nil
1✔
89
}
90

91
func (s *sriov) ResetSriovDevice(ifaceStatus sriovnetworkv1.InterfaceExt) error {
1✔
92
        log.Log.V(2).Info("ResetSriovDevice(): reset SRIOV device", "address", ifaceStatus.PciAddress)
1✔
93
        if ifaceStatus.LinkType == consts.LinkTypeETH {
2✔
94
                var mtu int
1✔
95
                eswitchMode := sriovnetworkv1.ESwithModeLegacy
1✔
96
                is := sriovnetworkv1.InitialState.GetInterfaceStateByPciAddress(ifaceStatus.PciAddress)
1✔
97
                if is != nil {
1✔
98
                        mtu = is.Mtu
×
99
                        eswitchMode = sriovnetworkv1.GetEswitchModeFromStatus(is)
×
100
                } else {
1✔
101
                        mtu = 1500
1✔
102
                }
1✔
103
                log.Log.V(2).Info("ResetSriovDevice(): reset mtu", "value", mtu)
1✔
104
                if err := s.networkHelper.SetNetdevMTU(ifaceStatus.PciAddress, mtu); err != nil {
1✔
105
                        return err
×
106
                }
×
107
                log.Log.V(2).Info("ResetSriovDevice(): reset eswitch mode and number of VFs", "mode", eswitchMode)
1✔
108
                if err := s.setEswitchModeAndNumVFs(ifaceStatus.PciAddress, eswitchMode, 0); err != nil {
1✔
109
                        return err
×
110
                }
×
111
        } else if ifaceStatus.LinkType == consts.LinkTypeIB {
×
112
                if err := s.SetSriovNumVfs(ifaceStatus.PciAddress, 0); err != nil {
×
113
                        return err
×
114
                }
×
115
                if err := s.networkHelper.SetNetdevMTU(ifaceStatus.PciAddress, 2048); err != nil {
×
116
                        return err
×
117
                }
×
118
        }
119
        return nil
1✔
120
}
121

122
func (s *sriov) getVfInfo(vfAddr string, pfName string, eswitchMode string, devices []*ghw.PCIDevice) sriovnetworkv1.VirtualFunction {
1✔
123
        driver, err := s.dputilsLib.GetDriverName(vfAddr)
1✔
124
        if err != nil {
1✔
125
                log.Log.Error(err, "getVfInfo(): unable to parse device driver", "device", vfAddr)
×
126
        }
×
127
        id, err := s.dputilsLib.GetVFID(vfAddr)
1✔
128
        if err != nil {
1✔
129
                log.Log.Error(err, "getVfInfo(): unable to get VF index", "device", vfAddr)
×
130
        }
×
131
        vf := sriovnetworkv1.VirtualFunction{
1✔
132
                PciAddress: vfAddr,
1✔
133
                Driver:     driver,
1✔
134
                VfID:       id,
1✔
135
                VdpaType:   s.vdpaHelper.DiscoverVDPAType(vfAddr),
1✔
136
        }
1✔
137

1✔
138
        if eswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
2✔
139
                repName, err := s.sriovnetLib.GetVfRepresentor(pfName, id)
1✔
140
                if err != nil {
1✔
141
                        log.Log.Error(err, "getVfInfo(): failed to get VF representor name", "device", vfAddr)
×
142
                } else {
1✔
143
                        vf.RepresentorName = repName
1✔
144
                }
1✔
145
        }
146

147
        if name := s.networkHelper.TryGetInterfaceName(vfAddr); name != "" {
2✔
148
                link, err := s.netlinkLib.LinkByName(name)
1✔
149
                if err != nil {
1✔
150
                        log.Log.Error(err, "getVfInfo(): unable to get VF Link Object", "name", name, "device", vfAddr)
×
151
                } else {
1✔
152
                        vf.Name = name
1✔
153
                        vf.Mtu = link.Attrs().MTU
1✔
154
                        vf.Mac = link.Attrs().HardwareAddr.String()
1✔
155
                }
1✔
156
        }
157
        vf.GUID = s.networkHelper.GetNetDevNodeGUID(vfAddr)
1✔
158

1✔
159
        for _, device := range devices {
2✔
160
                if vfAddr == device.Address {
2✔
161
                        vf.Vendor = device.Vendor.ID
1✔
162
                        vf.DeviceID = device.Product.ID
1✔
163
                        break
1✔
164
                }
165
        }
166
        return vf
1✔
167
}
168

169
func (s *sriov) VFIsReady(pciAddr string) (netlink.Link, error) {
1✔
170
        log.Log.Info("VFIsReady()", "device", pciAddr)
1✔
171
        var err error
1✔
172
        var vfLink netlink.Link
1✔
173
        err = wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
2✔
174
                vfIndex, err := s.networkHelper.GetInterfaceIndex(pciAddr)
1✔
175
                if err != nil {
2✔
176
                        log.Log.Error(err, "VFIsReady(): invalid index number")
1✔
177
                        return false, nil
1✔
178
                }
1✔
179
                vfLink, err = s.netlinkLib.LinkByIndex(vfIndex)
1✔
180
                if err != nil {
1✔
181
                        log.Log.Error(err, "VFIsReady(): unable to get VF link", "device", pciAddr)
×
182
                        return false, nil
×
183
                }
×
184
                return true, nil
1✔
185
        })
186
        if err != nil {
1✔
187
                return vfLink, err
×
188
        }
×
189
        return vfLink, nil
1✔
190
}
191

192
func (s *sriov) SetVfAdminMac(vfAddr string, pfLink, vfLink netlink.Link) error {
1✔
193
        log.Log.Info("SetVfAdminMac()", "vf", vfAddr)
1✔
194

1✔
195
        vfID, err := s.dputilsLib.GetVFID(vfAddr)
1✔
196
        if err != nil {
1✔
197
                log.Log.Error(err, "SetVfAdminMac(): unable to get VF id", "address", vfAddr)
×
198
                return err
×
199
        }
×
200

201
        if err := s.netlinkLib.LinkSetVfHardwareAddr(pfLink, vfID, vfLink.Attrs().HardwareAddr); err != nil {
1✔
202
                return err
×
203
        }
×
204

205
        return nil
1✔
206
}
207

208
func (s *sriov) DiscoverSriovDevices(storeManager store.ManagerInterface) ([]sriovnetworkv1.InterfaceExt, error) {
1✔
209
        log.Log.V(2).Info("DiscoverSriovDevices")
1✔
210
        pfList := []sriovnetworkv1.InterfaceExt{}
1✔
211

1✔
212
        pci, err := s.ghwLib.PCI()
1✔
213
        if err != nil {
1✔
214
                return nil, fmt.Errorf("DiscoverSriovDevices(): error getting PCI info: %v", err)
×
215
        }
×
216

217
        devices := pci.ListDevices()
1✔
218
        if len(devices) == 0 {
1✔
219
                return nil, fmt.Errorf("DiscoverSriovDevices(): could not retrieve PCI devices")
×
220
        }
×
221

222
        for _, device := range devices {
2✔
223
                devClass, err := strconv.ParseInt(device.Class.ID, 16, 64)
1✔
224
                if err != nil {
1✔
225
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse device class, skipping",
×
226
                                "device", device)
×
227
                        continue
×
228
                }
229
                if devClass != consts.NetClass {
2✔
230
                        // Not network device
1✔
231
                        continue
1✔
232
                }
233

234
                // TODO: exclude devices used by host system
235

236
                if s.dputilsLib.IsSriovVF(device.Address) {
2✔
237
                        continue
1✔
238
                }
239

240
                if !vars.DevMode {
2✔
241
                        if !sriovnetworkv1.IsSupportedModel(device.Vendor.ID, device.Product.ID) {
2✔
242
                                log.Log.Info("DiscoverSriovDevices(): unsupported device", "device", device)
1✔
243
                                continue
1✔
244
                        }
245
                }
246

247
                driver, err := s.dputilsLib.GetDriverName(device.Address)
1✔
248
                if err != nil {
1✔
249
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse device driver for device, skipping", "device", device)
×
250
                        continue
×
251
                }
252

253
                pfNetName := s.networkHelper.TryGetInterfaceName(device.Address)
1✔
254

1✔
255
                if pfNetName == "" {
1✔
256
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get device name for device, skipping", "device", device.Address)
×
257
                        continue
×
258
                }
259

260
                link, err := s.netlinkLib.LinkByName(pfNetName)
1✔
261
                if err != nil {
1✔
262
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get Link for device, skipping", "device", device.Address)
×
263
                        continue
×
264
                }
265

266
                iface := sriovnetworkv1.InterfaceExt{
1✔
267
                        Name:           pfNetName,
1✔
268
                        PciAddress:     device.Address,
1✔
269
                        Driver:         driver,
1✔
270
                        Vendor:         device.Vendor.ID,
1✔
271
                        DeviceID:       device.Product.ID,
1✔
272
                        Mtu:            link.Attrs().MTU,
1✔
273
                        Mac:            link.Attrs().HardwareAddr.String(),
1✔
274
                        LinkType:       s.encapTypeToLinkType(link.Attrs().EncapType),
1✔
275
                        LinkSpeed:      s.networkHelper.GetNetDevLinkSpeed(pfNetName),
1✔
276
                        LinkAdminState: s.networkHelper.GetNetDevLinkAdminState(pfNetName),
1✔
277
                }
1✔
278

1✔
279
                pfStatus, exist, err := storeManager.LoadPfsStatus(iface.PciAddress)
1✔
280
                if err != nil {
1✔
281
                        log.Log.Error(err, "DiscoverSriovDevices(): failed to load PF status from disk")
×
282
                } else {
1✔
283
                        if exist {
1✔
284
                                iface.ExternallyManaged = pfStatus.ExternallyManaged
×
285
                        }
×
286
                }
287

288
                if s.dputilsLib.IsSriovPF(device.Address) {
2✔
289
                        iface.TotalVfs = s.dputilsLib.GetSriovVFcapacity(device.Address)
1✔
290
                        iface.NumVfs = s.dputilsLib.GetVFconfigured(device.Address)
1✔
291
                        iface.EswitchMode = s.GetNicSriovMode(device.Address)
1✔
292
                        if s.dputilsLib.SriovConfigured(device.Address) {
2✔
293
                                vfs, err := s.dputilsLib.GetVFList(device.Address)
1✔
294
                                if err != nil {
1✔
295
                                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse VFs for device, skipping",
×
296
                                                "device", device)
×
297
                                        continue
×
298
                                }
299
                                for _, vf := range vfs {
2✔
300
                                        instance := s.getVfInfo(vf, pfNetName, iface.EswitchMode, devices)
1✔
301
                                        iface.VFs = append(iface.VFs, instance)
1✔
302
                                }
1✔
303
                        }
304
                }
305
                pfList = append(pfList, iface)
1✔
306
        }
307

308
        return pfList, nil
1✔
309
}
310

311
func (s *sriov) configSriovPFDevice(iface *sriovnetworkv1.Interface) error {
1✔
312
        log.Log.V(2).Info("configSriovPFDevice(): configure PF sriov device",
1✔
313
                "device", iface.PciAddress)
1✔
314
        totalVfs := s.dputilsLib.GetSriovVFcapacity(iface.PciAddress)
1✔
315
        if iface.NumVfs > totalVfs {
1✔
316
                err := fmt.Errorf("cannot config SRIOV device: NumVfs (%d) is larger than TotalVfs (%d)", iface.NumVfs, totalVfs)
×
317
                log.Log.Error(err, "configSriovPFDevice(): fail to set NumVfs for device", "device", iface.PciAddress)
×
318
                return err
×
319
        }
×
320
        if err := s.configureHWOptionsForSwitchdev(iface); err != nil {
1✔
321
                return err
×
322
        }
×
323
        // remove all UDEV rules for the PF before adding new rules to
324
        // make sure that rules are always in a consistent state, e.g. there is no
325
        // switchdev-related rules for PF in legacy mode
326
        if err := s.removeUdevRules(iface.PciAddress); err != nil {
1✔
327
                log.Log.Error(err, "configSriovPFDevice(): fail to remove udev rules", "device", iface.PciAddress)
×
328
                return err
×
329
        }
×
330
        err := s.addUdevRules(iface)
1✔
331
        if err != nil {
1✔
332
                log.Log.Error(err, "configSriovPFDevice(): fail to add udev rules", "device", iface.PciAddress)
×
333
                return err
×
334
        }
×
335
        err = s.createVFs(iface)
1✔
336
        if err != nil {
1✔
337
                log.Log.Error(err, "configSriovPFDevice(): fail to set NumVfs for device", "device", iface.PciAddress)
×
338
                return err
×
339
        }
×
340
        if err := s.addVfRepresentorUdevRule(iface); err != nil {
1✔
341
                log.Log.Error(err, "configSriovPFDevice(): fail to add VR representor udev rule", "device", iface.PciAddress)
×
342
                return err
×
343
        }
×
344
        // set PF mtu
345
        if iface.Mtu > 0 && iface.Mtu > s.networkHelper.GetNetdevMTU(iface.PciAddress) {
1✔
346
                err = s.networkHelper.SetNetdevMTU(iface.PciAddress, iface.Mtu)
×
347
                if err != nil {
×
348
                        log.Log.Error(err, "configSriovPFDevice(): fail to set mtu for PF", "device", iface.PciAddress)
×
349
                        return err
×
350
                }
×
351
        }
352
        return nil
1✔
353
}
354

355
func (s *sriov) configureHWOptionsForSwitchdev(iface *sriovnetworkv1.Interface) error {
1✔
356
        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): configure HW options for device",
1✔
357
                "device", iface.PciAddress)
1✔
358
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) != sriovnetworkv1.ESwithModeSwitchDev {
2✔
359
                // we need to configure HW options only for PFs for which switchdev is a target mode
1✔
360
                return nil
1✔
361
        }
1✔
362
        if err := s.networkHelper.EnableHwTcOffload(iface.Name); err != nil {
1✔
363
                return err
×
364
        }
×
365
        desiredFlowSteeringMode := "smfs"
1✔
366
        currentFlowSteeringMode, err := s.networkHelper.GetDevlinkDeviceParam(iface.PciAddress, "flow_steering_mode")
1✔
367
        if err != nil {
2✔
368
                if errors.Is(err, syscall.EINVAL) || errors.Is(err, syscall.ENODEV) {
2✔
369
                        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): device has no flow_steering_mode parameter, skip",
1✔
370
                                "device", iface.PciAddress)
1✔
371
                        return nil
1✔
372
                }
1✔
373
                log.Log.Error(err, "configureHWOptionsForSwitchdev(): fail to read current flow steering mode for the device", "device", iface.PciAddress)
×
374
                return err
×
375
        }
376
        if currentFlowSteeringMode == desiredFlowSteeringMode {
×
377
                return nil
×
378
        }
×
379
        // flow steering mode can be changed only when NIC is in legacy mode
380
        if s.GetNicSriovMode(iface.PciAddress) != sriovnetworkv1.ESwithModeLegacy {
×
381
                s.setEswitchModeAndNumVFs(iface.PciAddress, sriovnetworkv1.ESwithModeLegacy, 0)
×
382
        }
×
383
        if err := s.networkHelper.SetDevlinkDeviceParam(iface.PciAddress, "flow_steering_mode", desiredFlowSteeringMode); err != nil {
×
384
                if errors.Is(err, syscall.ENOTSUP) {
×
385
                        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): device doesn't support changing of flow_steering_mode, skip", "device", iface.PciAddress)
×
386
                        return nil
×
387
                }
×
388
                log.Log.Error(err, "configureHWOptionsForSwitchdev(): fail to configure flow steering mode for the device", "device", iface.PciAddress)
×
389
                return err
×
390
        }
391
        return nil
×
392
}
393

394
func (s *sriov) checkExternallyManagedPF(iface *sriovnetworkv1.Interface) error {
1✔
395
        log.Log.V(2).Info("checkExternallyManagedPF(): configure PF sriov device",
1✔
396
                "device", iface.PciAddress)
1✔
397
        currentNumVfs := s.dputilsLib.GetVFconfigured(iface.PciAddress)
1✔
398
        if iface.NumVfs > currentNumVfs {
2✔
399
                errMsg := fmt.Sprintf("checkExternallyManagedPF(): number of request virtual functions %d is not equal to configured virtual "+
1✔
400
                        "functions %d but the policy is configured as ExternallyManaged for device %s",
1✔
401
                        iface.NumVfs, currentNumVfs, iface.PciAddress)
1✔
402
                log.Log.Error(nil, errMsg)
1✔
403
                return fmt.Errorf(errMsg)
1✔
404
        }
1✔
405
        currentEswitchMode := s.GetNicSriovMode(iface.PciAddress)
1✔
406
        expectedEswitchMode := sriovnetworkv1.GetEswitchModeFromSpec(iface)
1✔
407
        if currentEswitchMode != expectedEswitchMode {
1✔
408
                errMsg := fmt.Sprintf("checkExternallyManagedPF(): requested ESwitchMode mode \"%s\" is not equal to configured \"%s\" "+
×
409
                        "but the policy is configured as ExternallyManaged for device %s", expectedEswitchMode, currentEswitchMode, iface.PciAddress)
×
410
                log.Log.Error(nil, errMsg)
×
411
                return fmt.Errorf(errMsg)
×
412
        }
×
413
        currentMtu := s.networkHelper.GetNetdevMTU(iface.PciAddress)
1✔
414
        if iface.Mtu > 0 && iface.Mtu > currentMtu {
2✔
415
                err := fmt.Errorf("checkExternallyManagedPF(): requested MTU(%d) is greater than configured MTU(%d) for device %s. cannot change MTU as policy is configured as ExternallyManaged",
1✔
416
                        iface.Mtu, currentMtu, iface.PciAddress)
1✔
417
                log.Log.Error(nil, err.Error())
1✔
418
                return err
1✔
419
        }
1✔
420
        return nil
×
421
}
422

423
func (s *sriov) configSriovVFDevices(iface *sriovnetworkv1.Interface) error {
1✔
424
        log.Log.V(2).Info("configSriovVFDevices(): configure PF sriov device",
1✔
425
                "device", iface.PciAddress)
1✔
426
        if iface.NumVfs > 0 {
2✔
427
                vfAddrs, err := s.dputilsLib.GetVFList(iface.PciAddress)
1✔
428
                if err != nil {
1✔
429
                        log.Log.Error(err, "configSriovVFDevices(): unable to parse VFs for device", "device", iface.PciAddress)
×
430
                }
×
431
                pfLink, err := s.netlinkLib.LinkByName(iface.Name)
1✔
432
                if err != nil {
1✔
433
                        log.Log.Error(err, "configSriovVFDevices(): unable to get PF link for device", "device", iface)
×
434
                        return err
×
435
                }
×
436

437
                for _, addr := range vfAddrs {
2✔
438
                        hasDriver, _ := s.kernelHelper.HasDriver(addr)
1✔
439
                        if !hasDriver {
2✔
440
                                if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
1✔
441
                                        log.Log.Error(err, "configSriovVFDevices(): fail to bind default driver for device", "device", addr)
×
442
                                        return err
×
443
                                }
×
444
                        }
445
                        var group *sriovnetworkv1.VfGroup
1✔
446

1✔
447
                        vfID, err := s.dputilsLib.GetVFID(addr)
1✔
448
                        if err != nil {
1✔
449
                                log.Log.Error(err, "configSriovVFDevices(): unable to get VF id", "device", iface.PciAddress)
×
450
                                return err
×
451
                        }
×
452

453
                        for i := range iface.VfGroups {
2✔
454
                                if sriovnetworkv1.IndexInRange(vfID, iface.VfGroups[i].VfRange) {
2✔
455
                                        group = &iface.VfGroups[i]
1✔
456
                                        break
1✔
457
                                }
458
                        }
459

460
                        // VF group not found.
461
                        if group == nil {
1✔
462
                                continue
×
463
                        }
464

465
                        // only set GUID and MAC for VF with default driver
466
                        // for userspace drivers like vfio we configure the vf mac using the kernel nic mac address
467
                        // before we switch to the userspace driver
468
                        if yes, d := s.kernelHelper.HasDriver(addr); yes && !sriovnetworkv1.StringInArray(d, vars.DpdkDrivers) {
2✔
469
                                // LinkType is an optional field. Let's fallback to current link type
1✔
470
                                // if nothing is specified in the SriovNodePolicy
1✔
471
                                linkType := iface.LinkType
1✔
472
                                if linkType == "" {
2✔
473
                                        linkType = s.GetLinkType(iface.Name)
1✔
474
                                }
1✔
475
                                if strings.EqualFold(linkType, consts.LinkTypeIB) {
2✔
476
                                        if err := s.infinibandHelper.ConfigureVfGUID(addr, iface.PciAddress, vfID, pfLink); err != nil {
1✔
NEW
477
                                                return err
×
NEW
478
                                        }
×
479
                                        if err := s.kernelHelper.Unbind(iface.PciAddress); err != nil {
1✔
480
                                                return err
×
481
                                        }
×
482
                                } else {
1✔
483
                                        vfLink, err := s.VFIsReady(addr)
1✔
484
                                        if err != nil {
1✔
485
                                                log.Log.Error(err, "configSriovVFDevices(): VF link is not ready", "address", addr)
×
486
                                                err = s.kernelHelper.RebindVfToDefaultDriver(addr)
×
487
                                                if err != nil {
×
488
                                                        log.Log.Error(err, "configSriovVFDevices(): failed to rebind VF", "address", addr)
×
489
                                                        return err
×
490
                                                }
×
491

492
                                                // Try to check the VF status again
493
                                                vfLink, err = s.VFIsReady(addr)
×
494
                                                if err != nil {
×
495
                                                        log.Log.Error(err, "configSriovVFDevices(): VF link is not ready", "address", addr)
×
496
                                                        return err
×
497
                                                }
×
498
                                        }
499
                                        if err = s.SetVfAdminMac(addr, pfLink, vfLink); err != nil {
1✔
500
                                                log.Log.Error(err, "configSriovVFDevices(): fail to configure VF admin mac", "device", addr)
×
501
                                                return err
×
502
                                        }
×
503
                                }
504
                        }
505

506
                        if err = s.kernelHelper.UnbindDriverIfNeeded(addr, group.IsRdma); err != nil {
1✔
507
                                return err
×
508
                        }
×
509
                        // we set eswitch mode before this point and if the desired mode (and current at this point)
510
                        // is legacy, then VDPA device is already automatically disappeared,
511
                        // so we don't need to check it
512
                        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev && group.VdpaType == "" {
1✔
513
                                if err := s.vdpaHelper.DeleteVDPADevice(addr); err != nil {
×
514
                                        log.Log.Error(err, "configSriovVFDevices(): fail to delete VDPA device",
×
515
                                                "device", addr)
×
516
                                        return err
×
517
                                }
×
518
                        }
519
                        if !sriovnetworkv1.StringInArray(group.DeviceType, vars.DpdkDrivers) {
2✔
520
                                if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
1✔
521
                                        log.Log.Error(err, "configSriovVFDevices(): fail to bind default driver for device", "device", addr)
×
522
                                        return err
×
523
                                }
×
524
                                // only set MTU for VF with default driver
525
                                if group.Mtu > 0 {
2✔
526
                                        if err := s.networkHelper.SetNetdevMTU(addr, group.Mtu); err != nil {
1✔
527
                                                log.Log.Error(err, "configSriovVFDevices(): fail to set mtu for VF", "address", addr)
×
528
                                                return err
×
529
                                        }
×
530
                                }
531
                                if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev && group.VdpaType != "" {
2✔
532
                                        if err := s.vdpaHelper.CreateVDPADevice(addr, group.VdpaType); err != nil {
1✔
533
                                                log.Log.Error(err, "configSriovVFDevices(): fail to create VDPA device",
×
534
                                                        "vdpaType", group.VdpaType, "device", addr)
×
535
                                                return err
×
536
                                        }
×
537
                                }
538
                        } else {
1✔
539
                                if err := s.kernelHelper.BindDpdkDriver(addr, group.DeviceType); err != nil {
1✔
540
                                        log.Log.Error(err, "configSriovVFDevices(): fail to bind driver for device",
×
541
                                                "driver", group.DeviceType, "device", addr)
×
542
                                        return err
×
543
                                }
×
544
                        }
545
                }
546
        }
547
        return nil
1✔
548
}
549

550
func (s *sriov) configSriovDevice(iface *sriovnetworkv1.Interface, skipVFConfiguration bool) error {
1✔
551
        log.Log.V(2).Info("configSriovDevice(): configure sriov device",
1✔
552
                "device", iface.PciAddress, "config", iface, "skipVFConfiguration", skipVFConfiguration)
1✔
553
        if !iface.ExternallyManaged {
2✔
554
                if err := s.configSriovPFDevice(iface); err != nil {
1✔
555
                        return err
×
556
                }
×
557
        }
558
        if skipVFConfiguration {
2✔
559
                if iface.ExternallyManaged {
1✔
560
                        return nil
×
561
                }
×
562
                log.Log.V(2).Info("configSriovDevice(): skipVFConfiguration is true, unbind all VFs from drivers",
1✔
563
                        "device", iface.PciAddress)
1✔
564
                return s.unbindAllVFsOnPF(iface.PciAddress)
1✔
565
        }
566
        // we don't need to validate externally managed PFs when skipVFConfiguration is true.
567
        // The function usually called with skipVFConfiguration true when running in the systemd mode and configuration is
568
        // in pre phase. Externally managed PFs may not be configured at this stage yet (preConfig stage is executed before NetworkManager, netplan)
569

570
        if iface.ExternallyManaged {
2✔
571
                if err := s.checkExternallyManagedPF(iface); err != nil {
2✔
572
                        return err
1✔
573
                }
1✔
574
        }
575
        if err := s.configSriovVFDevices(iface); err != nil {
1✔
576
                return err
×
577
        }
×
578
        // Set PF link up
579
        pfLink, err := s.netlinkLib.LinkByName(iface.Name)
1✔
580
        if err != nil {
1✔
581
                return err
×
582
        }
×
583
        if !s.netlinkLib.IsLinkAdminStateUp(pfLink) {
2✔
584
                err = s.netlinkLib.LinkSetUp(pfLink)
1✔
585
                if err != nil {
1✔
586
                        return err
×
587
                }
×
588
        }
589
        return nil
1✔
590
}
591

592
func (s *sriov) ConfigSriovInterfaces(storeManager store.ManagerInterface,
593
        interfaces []sriovnetworkv1.Interface, ifaceStatuses []sriovnetworkv1.InterfaceExt, skipVFConfiguration bool) error {
1✔
594
        toBeConfigured, toBeResetted, err := s.getConfigureAndReset(storeManager, interfaces, ifaceStatuses)
1✔
595
        if err != nil {
1✔
596
                log.Log.Error(err, "cannot get a list of interfaces to configure")
×
597
                return fmt.Errorf("cannot get a list of interfaces to configure")
×
598
        }
×
599

600
        if vars.ParallelNicConfig {
1✔
601
                err = s.configSriovInterfacesInParallel(storeManager, toBeConfigured, skipVFConfiguration)
×
602
        } else {
1✔
603
                err = s.configSriovInterfaces(storeManager, toBeConfigured, skipVFConfiguration)
1✔
604
        }
1✔
605
        if err != nil {
2✔
606
                log.Log.Error(err, "cannot configure sriov interfaces")
1✔
607
                return fmt.Errorf("cannot configure sriov interfaces")
1✔
608
        }
1✔
609
        if sriovnetworkv1.ContainsSwitchdevInterface(interfaces) && len(toBeConfigured) > 0 {
2✔
610
                // for switchdev devices we create udev rule that renames VF representors
1✔
611
                // after VFs are created. Reload rules to update interfaces
1✔
612
                if err := s.udevHelper.LoadUdevRules(); err != nil {
1✔
613
                        log.Log.Error(err, "cannot reload udev rules")
×
614
                        return fmt.Errorf("failed to reload udev rules: %v", err)
×
615
                }
×
616
        }
617

618
        if vars.ParallelNicConfig {
1✔
619
                err = s.resetSriovInterfacesInParallel(storeManager, toBeResetted)
×
620
        } else {
1✔
621
                err = s.resetSriovInterfaces(storeManager, toBeResetted)
1✔
622
        }
1✔
623
        if err != nil {
1✔
624
                log.Log.Error(err, "cannot reset sriov interfaces")
×
625
                return fmt.Errorf("cannot reset sriov interfaces")
×
626
        }
×
627
        return nil
1✔
628
}
629

630
func (s *sriov) getConfigureAndReset(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.Interface,
631
        ifaceStatuses []sriovnetworkv1.InterfaceExt) ([]interfaceToConfigure, []sriovnetworkv1.InterfaceExt, error) {
1✔
632
        toBeConfigured := []interfaceToConfigure{}
1✔
633
        toBeResetted := []sriovnetworkv1.InterfaceExt{}
1✔
634
        for _, ifaceStatus := range ifaceStatuses {
2✔
635
                configured := false
1✔
636
                for _, iface := range interfaces {
2✔
637
                        if iface.PciAddress == ifaceStatus.PciAddress {
2✔
638
                                configured = true
1✔
639
                                skip, err := skipSriovConfig(&iface, &ifaceStatus, storeManager)
1✔
640
                                if err != nil {
1✔
641
                                        log.Log.Error(err, "getConfigureAndReset(): failed to check interface")
×
642
                                        return nil, nil, err
×
643
                                }
×
644
                                if skip {
1✔
645
                                        break
×
646
                                }
647
                                iface := iface
1✔
648
                                ifaceStatus := ifaceStatus
1✔
649
                                toBeConfigured = append(toBeConfigured, interfaceToConfigure{iface: iface, ifaceStatus: ifaceStatus})
1✔
650
                        }
651
                }
652

653
                if !configured && ifaceStatus.NumVfs > 0 {
2✔
654
                        toBeResetted = append(toBeResetted, ifaceStatus)
1✔
655
                }
1✔
656
        }
657
        return toBeConfigured, toBeResetted, nil
1✔
658
}
659

660
func (s *sriov) configSriovInterfacesInParallel(storeManager store.ManagerInterface, interfaces []interfaceToConfigure, skipVFConfiguration bool) error {
×
661
        log.Log.V(2).Info("configSriovInterfacesInParallel(): start sriov configuration")
×
662

×
663
        var result error
×
664
        errChannel := make(chan error)
×
665
        interfacesToConfigure := 0
×
666
        for ifaceIndex, iface := range interfaces {
×
667
                interfacesToConfigure += 1
×
668
                go func(iface *interfaceToConfigure) {
×
669
                        var err error
×
670
                        if err = s.configSriovDevice(&iface.iface, skipVFConfiguration); err != nil {
×
671
                                log.Log.Error(err, "configSriovInterfacesInParallel(): fail to configure sriov interface. resetting interface.", "address", iface.iface.PciAddress)
×
672
                                if iface.iface.ExternallyManaged {
×
673
                                        log.Log.V(2).Info("configSriovInterfacesInParallel(): skipping device reset as the nic is marked as externally created")
×
674
                                } else {
×
675
                                        if resetErr := s.ResetSriovDevice(iface.ifaceStatus); resetErr != nil {
×
676
                                                log.Log.Error(resetErr, "configSriovInterfacesInParallel(): failed to reset on error SR-IOV interface")
×
677
                                                err = resetErr
×
678
                                        }
×
679
                                }
680
                        }
681
                        errChannel <- err
×
682
                }(&interfaces[ifaceIndex])
683
                // Save the PF status to the host
684
                err := storeManager.SaveLastPfAppliedStatus(&iface.iface)
×
685
                if err != nil {
×
686
                        log.Log.Error(err, "configSriovInterfacesInParallel(): failed to save PF applied config to host")
×
687
                        return err
×
688
                }
×
689
        }
690

691
        for i := 0; i < interfacesToConfigure; i++ {
×
692
                errMsg := <-errChannel
×
693
                result = errors.Join(result, errMsg)
×
694
        }
×
695
        if result != nil {
×
696
                log.Log.Error(result, "configSriovInterfacesInParallel(): fail to configure sriov interfaces")
×
697
                return result
×
698
        }
×
699
        log.Log.V(2).Info("configSriovInterfacesInParallel(): sriov configuration finished")
×
700
        return nil
×
701
}
702

703
func (s *sriov) resetSriovInterfacesInParallel(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.InterfaceExt) error {
×
704
        var result error
×
705
        errChannel := make(chan error, len(interfaces))
×
706
        interfacesToReset := 0
×
707
        for ifaceIndex := range interfaces {
×
708
                interfacesToReset += 1
×
709
                go func(iface *sriovnetworkv1.InterfaceExt) {
×
710
                        var err error
×
711
                        if err = s.checkForConfigAndReset(*iface, storeManager); err != nil {
×
712
                                log.Log.Error(err, "resetSriovInterfacesInParallel(): fail to reset sriov interface. resetting interface.", "address", iface.PciAddress)
×
713
                        }
×
714
                        errChannel <- err
×
715
                }(&interfaces[ifaceIndex])
716
        }
717

718
        for i := 0; i < interfacesToReset; i++ {
×
719
                errMsg := <-errChannel
×
720
                result = errors.Join(result, errMsg)
×
721
        }
×
722
        if result != nil {
×
723
                log.Log.Error(result, "resetSriovInterfacesInParallel(): fail to reset sriov interface")
×
724
                return result
×
725
        }
×
726
        log.Log.V(2).Info("resetSriovInterfacesInParallel(): sriov reset finished")
×
727

×
728
        return nil
×
729
}
730

731
func (s *sriov) configSriovInterfaces(storeManager store.ManagerInterface, interfaces []interfaceToConfigure, skipVFConfiguration bool) error {
1✔
732
        log.Log.V(2).Info("configSriovInterfaces(): start sriov configuration")
1✔
733
        for _, iface := range interfaces {
2✔
734
                if err := s.configSriovDevice(&iface.iface, skipVFConfiguration); err != nil {
2✔
735
                        log.Log.Error(err, "configSriovInterfaces(): fail to configure sriov interface. resetting interface.", "address", iface.iface.PciAddress)
1✔
736
                        if iface.iface.ExternallyManaged {
2✔
737
                                log.Log.V(2).Info("configSriovInterfaces(): skipping device reset as the nic is marked as externally created")
1✔
738
                        } else {
1✔
739
                                if resetErr := s.ResetSriovDevice(iface.ifaceStatus); resetErr != nil {
×
740
                                        log.Log.Error(resetErr, "configSriovInterfaces(): failed to reset on error SR-IOV interface")
×
741
                                }
×
742
                        }
743
                        return err
1✔
744
                }
745

746
                // Save the PF status to the host
747
                err := storeManager.SaveLastPfAppliedStatus(&iface.iface)
1✔
748
                if err != nil {
1✔
749
                        log.Log.Error(err, "configSriovInterfaces(): failed to save PF applied config to host")
×
750
                        return err
×
751
                }
×
752
        }
753
        log.Log.V(2).Info("configSriovInterfaces(): sriov configuration finished")
1✔
754
        return nil
1✔
755
}
756

757
func (s *sriov) resetSriovInterfaces(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.InterfaceExt) error {
1✔
758
        for _, iface := range interfaces {
2✔
759
                if err := s.checkForConfigAndReset(iface, storeManager); err != nil {
1✔
760
                        log.Log.Error(err, "resetSriovInterfaces(): failed to reset sriov interface. resetting interface.", "address", iface.PciAddress)
×
761
                        return err
×
762
                }
×
763
        }
764
        log.Log.V(2).Info("resetSriovInterfaces(): sriov reset finished")
1✔
765
        return nil
1✔
766
}
767

768
// / skipSriovConfig checks if we need to apply SR-IOV configuration specified specific interface
769
func skipSriovConfig(iface *sriovnetworkv1.Interface, ifaceStatus *sriovnetworkv1.InterfaceExt, storeManager store.ManagerInterface) (bool, error) {
1✔
770
        if !sriovnetworkv1.NeedToUpdateSriov(iface, ifaceStatus) {
1✔
771
                log.Log.V(2).Info("ConfigSriovInterfaces(): no need update interface", "address", iface.PciAddress)
×
772

×
773
                // Save the PF status to the host
×
774
                err := storeManager.SaveLastPfAppliedStatus(iface)
×
775
                if err != nil {
×
776
                        log.Log.Error(err, "ConfigSriovInterfaces(): failed to save PF applied status config to host")
×
777
                        return false, err
×
778
                }
×
779

780
                return true, nil
×
781
        }
782
        return false, nil
1✔
783
}
784

785
func (s *sriov) checkForConfigAndReset(ifaceStatus sriovnetworkv1.InterfaceExt, storeManager store.ManagerInterface) error {
1✔
786
        // load the PF info
1✔
787
        pfStatus, exist, err := storeManager.LoadPfsStatus(ifaceStatus.PciAddress)
1✔
788
        if err != nil {
1✔
789
                log.Log.Error(err, "checkForConfigAndReset(): failed to load info about PF status for device",
×
790
                        "address", ifaceStatus.PciAddress)
×
791
                return err
×
792
        }
×
793

794
        if !exist {
1✔
795
                log.Log.V(2).Info("checkForConfigAndReset(): PF name with pci address has VFs configured but they weren't created by the sriov operator. Skipping the device reset",
×
796
                        "pf-name", ifaceStatus.Name,
×
797
                        "address", ifaceStatus.PciAddress)
×
798
                return nil
×
799
        }
×
800

801
        if pfStatus.ExternallyManaged {
2✔
802
                log.Log.V(2).Info("checkForConfigAndReset(): PF name with pci address was externally created skipping the device reset",
1✔
803
                        "pf-name", ifaceStatus.Name,
1✔
804
                        "address", ifaceStatus.PciAddress)
1✔
805

1✔
806
                // remove pf status from host
1✔
807
                err = storeManager.RemovePfAppliedStatus(ifaceStatus.PciAddress)
1✔
808
                if err != nil {
1✔
809
                        return err
×
810
                }
×
811

812
                return nil
1✔
813
        }
814
        err = s.removeUdevRules(ifaceStatus.PciAddress)
1✔
815
        if err != nil {
1✔
816
                return err
×
817
        }
×
818

819
        if err = s.ResetSriovDevice(ifaceStatus); err != nil {
1✔
820
                return err
×
821
        }
×
822

823
        // remove pf status from host
824
        err = storeManager.RemovePfAppliedStatus(ifaceStatus.PciAddress)
1✔
825
        if err != nil {
1✔
826
                return err
×
827
        }
×
828

829
        return nil
1✔
830
}
831

832
func (s *sriov) ConfigSriovDeviceVirtual(iface *sriovnetworkv1.Interface) error {
×
833
        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): config interface", "address", iface.PciAddress, "config", iface)
×
834
        // Config VFs
×
835
        if iface.NumVfs > 0 {
×
836
                if iface.NumVfs > 1 {
×
837
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): in a virtual environment, only one VF per interface",
×
838
                                "numVfs", iface.NumVfs)
×
839
                        return errors.New("NumVfs > 1")
×
840
                }
×
841
                if len(iface.VfGroups) != 1 {
×
842
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): missing VFGroup")
×
843
                        return errors.New("NumVfs != 1")
×
844
                }
×
845
                addr := iface.PciAddress
×
846
                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "address", addr)
×
847
                driver := ""
×
848
                vfID := 0
×
849
                for _, group := range iface.VfGroups {
×
850
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "group", group)
×
851
                        if sriovnetworkv1.IndexInRange(vfID, group.VfRange) {
×
852
                                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "indexInRange", vfID)
×
853
                                if sriovnetworkv1.StringInArray(group.DeviceType, vars.DpdkDrivers) {
×
854
                                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "driver", group.DeviceType)
×
855
                                        driver = group.DeviceType
×
856
                                }
×
857
                                break
×
858
                        }
859
                }
860
                if driver == "" {
×
861
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind default")
×
862
                        if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
×
863
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind default driver", "device", addr)
×
864
                                return err
×
865
                        }
×
866
                } else {
×
867
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind driver", "driver", driver)
×
868
                        if err := s.kernelHelper.BindDpdkDriver(addr, driver); err != nil {
×
869
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind driver for device",
×
870
                                        "driver", driver, "device", addr)
×
871
                                return err
×
872
                        }
×
873
                }
874
        }
875
        return nil
×
876
}
877

878
func (s *sriov) GetNicSriovMode(pciAddress string) string {
1✔
879
        log.Log.V(2).Info("GetNicSriovMode()", "device", pciAddress)
1✔
880
        devLink, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
881
        if err != nil {
2✔
882
                if !errors.Is(err, syscall.ENODEV) {
2✔
883
                        log.Log.Error(err, "GetNicSriovMode(): failed to get eswitch mode, assume legacy", "device", pciAddress)
1✔
884
                }
1✔
885
        }
886
        if devLink != nil && devLink.Attrs.Eswitch.Mode != "" {
2✔
887
                return devLink.Attrs.Eswitch.Mode
1✔
888
        }
1✔
889

890
        return sriovnetworkv1.ESwithModeLegacy
1✔
891
}
892

893
func (s *sriov) SetNicSriovMode(pciAddress string, mode string) error {
1✔
894
        log.Log.V(2).Info("SetNicSriovMode()", "device", pciAddress, "mode", mode)
1✔
895

1✔
896
        dev, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
897
        if err != nil {
2✔
898
                return err
1✔
899
        }
1✔
900
        return s.netlinkLib.DevLinkSetEswitchMode(dev, mode)
1✔
901
}
902

903
func (s *sriov) GetLinkType(name string) string {
1✔
904
        log.Log.V(2).Info("GetLinkType()", "name", name)
1✔
905
        link, err := s.netlinkLib.LinkByName(name)
1✔
906
        if err != nil {
1✔
907
                log.Log.Error(err, "GetLinkType(): failed to get link", "device", name)
×
908
                return ""
×
909
        }
×
910
        return s.encapTypeToLinkType(link.Attrs().EncapType)
1✔
911
}
912

913
func (s *sriov) encapTypeToLinkType(encapType string) string {
1✔
914
        if encapType == "ether" {
2✔
915
                return consts.LinkTypeETH
1✔
916
        } else if encapType == "infiniband" {
1✔
917
                return consts.LinkTypeIB
×
918
        }
×
919
        return ""
×
920
}
921

922
// create required udev rules for PF:
923
// * rule to disable NetworkManager for VFs - for all modes
924
// * rule to keep PF name after switching to switchdev mode - only for switchdev mode
925
func (s *sriov) addUdevRules(iface *sriovnetworkv1.Interface) error {
1✔
926
        log.Log.V(2).Info("addUdevRules(): add udev rules for device",
1✔
927
                "device", iface.PciAddress)
1✔
928
        if err := s.udevHelper.AddDisableNMUdevRule(iface.PciAddress); err != nil {
1✔
929
                return err
×
930
        }
×
931
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
932
                if err := s.udevHelper.AddPersistPFNameUdevRule(iface.PciAddress, iface.Name); err != nil {
1✔
933
                        return err
×
934
                }
×
935
        }
936
        return nil
1✔
937
}
938

939
// add switchdev-specific udev rule that renames representors.
940
// this rule relies on phys_port_name and phys_switch_id parameter which
941
// on old kernels can be read only after switching PF to switchdev mode.
942
// if PF doesn't expose phys_port_name and phys_switch_id, then rule creation will be skipped
943
func (s *sriov) addVfRepresentorUdevRule(iface *sriovnetworkv1.Interface) error {
1✔
944
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
945
                portName, err := s.networkHelper.GetPhysPortName(iface.Name)
1✔
946
                if err != nil {
1✔
947
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_port_name for device, skip creation of UDEV rule")
×
948
                        return nil
×
949
                }
×
950
                switchID, err := s.networkHelper.GetPhysSwitchID(iface.Name)
1✔
951
                if err != nil {
1✔
952
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_switch_id for device, skip creation of UDEV rule")
×
953
                        return nil
×
954
                }
×
955
                return s.udevHelper.AddVfRepresentorUdevRule(iface.PciAddress, iface.Name, switchID, portName)
1✔
956
        }
957
        return nil
1✔
958
}
959

960
// remove all udev rules for PF created by the operator
961
func (s *sriov) removeUdevRules(pciAddress string) error {
1✔
962
        log.Log.V(2).Info("removeUdevRules(): remove udev rules for device",
1✔
963
                "device", pciAddress)
1✔
964
        if err := s.udevHelper.RemoveDisableNMUdevRule(pciAddress); err != nil {
1✔
965
                return err
×
966
        }
×
967
        if err := s.udevHelper.RemoveVfRepresentorUdevRule(pciAddress); err != nil {
1✔
968
                return err
×
969
        }
×
970
        return s.udevHelper.RemovePersistPFNameUdevRule(pciAddress)
1✔
971
}
972

973
// create VFs on the PF
974
func (s *sriov) createVFs(iface *sriovnetworkv1.Interface) error {
1✔
975
        expectedEswitchMode := sriovnetworkv1.GetEswitchModeFromSpec(iface)
1✔
976
        log.Log.V(2).Info("createVFs(): configure VFs for device",
1✔
977
                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
1✔
978

1✔
979
        if s.dputilsLib.GetVFconfigured(iface.PciAddress) == iface.NumVfs {
1✔
980
                if s.GetNicSriovMode(iface.PciAddress) == expectedEswitchMode {
×
981
                        log.Log.V(2).Info("createVFs(): device is already configured",
×
982
                                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
×
983
                        return nil
×
984
                }
×
985
        }
986
        return s.setEswitchModeAndNumVFs(iface.PciAddress, expectedEswitchMode, iface.NumVfs)
1✔
987
}
988

989
func (s *sriov) setEswitchMode(pciAddr, eswitchMode string) error {
1✔
990
        log.Log.V(2).Info("setEswitchMode(): set eswitch mode", "device", pciAddr, "mode", eswitchMode)
1✔
991
        if err := s.unbindAllVFsOnPF(pciAddr); err != nil {
1✔
992
                log.Log.Error(err, "setEswitchMode(): failed to unbind VFs", "device", pciAddr, "mode", eswitchMode)
×
993
                return err
×
994
        }
×
995
        if err := s.SetNicSriovMode(pciAddr, eswitchMode); err != nil {
1✔
996
                err = fmt.Errorf("failed to switch NIC to SRIOV %s mode: %v", eswitchMode, err)
×
997
                log.Log.Error(err, "setEswitchMode(): failed to set mode", "device", pciAddr, "mode", eswitchMode)
×
998
                return err
×
999
        }
×
1000
        return nil
1✔
1001
}
1002

1003
func (s *sriov) setEswitchModeAndNumVFs(pciAddr string, desiredEswitchMode string, numVFs int) error {
1✔
1004
        log.Log.V(2).Info("setEswitchModeAndNumVFs(): configure VFs for device",
1✔
1005
                "device", pciAddr, "count", numVFs, "mode", desiredEswitchMode)
1✔
1006

1✔
1007
        // always switch NIC to the legacy mode before creating VFs. This is required because some drivers
1✔
1008
        // may not support VF creation in the switchdev mode
1✔
1009
        if s.GetNicSriovMode(pciAddr) != sriovnetworkv1.ESwithModeLegacy {
1✔
1010
                if err := s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeLegacy); err != nil {
×
1011
                        return err
×
1012
                }
×
1013
        }
1014
        if err := s.SetSriovNumVfs(pciAddr, numVFs); err != nil {
1✔
1015
                return err
×
1016
        }
×
1017

1018
        if desiredEswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
2✔
1019
                return s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeSwitchDev)
1✔
1020
        }
1✔
1021
        return nil
1✔
1022
}
1023

1024
// retrieve all VFs for the PF and unbind them from a driver
1025
func (s *sriov) unbindAllVFsOnPF(addr string) error {
1✔
1026
        log.Log.V(2).Info("unbindAllVFsOnPF(): unbind all VFs on PF", "device", addr)
1✔
1027
        vfAddrs, err := s.dputilsLib.GetVFList(addr)
1✔
1028
        if err != nil {
1✔
1029
                return fmt.Errorf("failed to read VF list: %v", err)
×
1030
        }
×
1031
        for _, vfAddr := range vfAddrs {
2✔
1032
                if err := s.kernelHelper.Unbind(vfAddr); err != nil {
1✔
1033
                        return fmt.Errorf("failed to unbind VF from the driver: %v", err)
×
1034
                }
×
1035
        }
1036
        return nil
1✔
1037
}
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