• 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

43.93
/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
        netlinkPkg "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/internal/lib/netlink"
22
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/store"
23
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/host/types"
24
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/utils"
25
        "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vars"
26
        mlx "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/vendors/mellanox"
27
)
28

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

34
type sriov struct {
35
        utilsHelper   utils.CmdInterface
36
        kernelHelper  types.KernelInterface
37
        networkHelper types.NetworkInterface
38
        udevHelper    types.UdevInterface
39
        vdpaHelper    types.VdpaInterface
40
        netlinkLib    netlinkPkg.NetlinkLib
41
        dputilsLib    dputilsPkg.DPUtilsLib
42
}
43

44
func New(utilsHelper utils.CmdInterface,
45
        kernelHelper types.KernelInterface,
46
        networkHelper types.NetworkInterface,
47
        udevHelper types.UdevInterface,
48
        vdpaHelper types.VdpaInterface,
49
        netlinkLib netlinkPkg.NetlinkLib,
50
        dputilsLib dputilsPkg.DPUtilsLib) types.SriovInterface {
1✔
51
        return &sriov{utilsHelper: utilsHelper,
1✔
52
                kernelHelper:  kernelHelper,
1✔
53
                networkHelper: networkHelper,
1✔
54
                udevHelper:    udevHelper,
1✔
55
                vdpaHelper:    vdpaHelper,
1✔
56
                netlinkLib:    netlinkLib,
1✔
57
                dputilsLib:    dputilsLib,
1✔
58
        }
1✔
59
}
1✔
60

61
func (s *sriov) SetSriovNumVfs(pciAddr string, numVfs int) error {
1✔
62
        log.Log.V(2).Info("SetSriovNumVfs(): set NumVfs", "device", pciAddr, "numVfs", numVfs)
1✔
63
        numVfsFilePath := filepath.Join(vars.FilesystemRoot, consts.SysBusPciDevices, pciAddr, consts.NumVfsFile)
1✔
64
        bs := []byte(strconv.Itoa(numVfs))
1✔
65
        err := os.WriteFile(numVfsFilePath, []byte("0"), os.ModeAppend)
1✔
66
        if err != nil {
2✔
67
                log.Log.Error(err, "SetSriovNumVfs(): fail to reset NumVfs file", "path", numVfsFilePath)
1✔
68
                return err
1✔
69
        }
1✔
70
        if numVfs == 0 {
2✔
71
                return nil
1✔
72
        }
1✔
73
        err = os.WriteFile(numVfsFilePath, bs, os.ModeAppend)
1✔
74
        if err != nil {
1✔
75
                log.Log.Error(err, "SetSriovNumVfs(): fail to set NumVfs file", "path", numVfsFilePath)
×
76
                return err
×
77
        }
×
78
        return nil
1✔
79
}
80

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

112
func (s *sriov) GetVfInfo(pciAddr string, devices []*ghw.PCIDevice) sriovnetworkv1.VirtualFunction {
×
113
        driver, err := s.dputilsLib.GetDriverName(pciAddr)
×
114
        if err != nil {
×
115
                log.Log.Error(err, "getVfInfo(): unable to parse device driver", "device", pciAddr)
×
116
        }
×
117
        id, err := s.dputilsLib.GetVFID(pciAddr)
×
118
        if err != nil {
×
119
                log.Log.Error(err, "getVfInfo(): unable to get VF index", "device", pciAddr)
×
120
        }
×
121
        vf := sriovnetworkv1.VirtualFunction{
×
122
                PciAddress: pciAddr,
×
123
                Driver:     driver,
×
124
                VfID:       id,
×
NEW
125
                VdpaType:   s.vdpaHelper.DiscoverVDPAType(pciAddr),
×
126
        }
×
127

×
128
        if name := s.networkHelper.TryGetInterfaceName(pciAddr); name != "" {
×
129
                link, err := s.netlinkLib.LinkByName(name)
×
130
                if err != nil {
×
131
                        log.Log.Error(err, "getVfInfo(): unable to get VF Link Object", "name", name, "device", pciAddr)
×
132
                } else {
×
133
                        vf.Name = name
×
134
                        vf.Mtu = link.Attrs().MTU
×
135
                        vf.Mac = link.Attrs().HardwareAddr.String()
×
136
                }
×
137
        }
138

139
        for _, device := range devices {
×
140
                if pciAddr == device.Address {
×
141
                        vf.Vendor = device.Vendor.ID
×
142
                        vf.DeviceID = device.Product.ID
×
143
                        break
×
144
                }
145
        }
146
        return vf
×
147
}
148

149
func (s *sriov) SetVfGUID(vfAddr string, pfLink netlink.Link) error {
1✔
150
        log.Log.Info("SetVfGUID()", "vf", vfAddr)
1✔
151
        vfID, err := s.dputilsLib.GetVFID(vfAddr)
1✔
152
        if err != nil {
1✔
153
                log.Log.Error(err, "SetVfGUID(): unable to get VF id", "address", vfAddr)
×
154
                return err
×
155
        }
×
156
        guid := utils.GenerateRandomGUID()
1✔
157
        if err := s.netlinkLib.LinkSetVfNodeGUID(pfLink, vfID, guid); err != nil {
1✔
158
                return err
×
159
        }
×
160
        if err := s.netlinkLib.LinkSetVfPortGUID(pfLink, vfID, guid); err != nil {
1✔
161
                return err
×
162
        }
×
163
        if err = s.kernelHelper.Unbind(vfAddr); err != nil {
1✔
164
                return err
×
165
        }
×
166

167
        return nil
1✔
168
}
169

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

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

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

197
        if err := s.netlinkLib.LinkSetVfHardwareAddr(pfLink, vfID, vfLink.Attrs().HardwareAddr); err != nil {
1✔
198
                return err
×
199
        }
×
200

201
        return nil
1✔
202
}
203

204
func (s *sriov) DiscoverSriovDevices(storeManager store.ManagerInterface) ([]sriovnetworkv1.InterfaceExt, error) {
×
205
        log.Log.V(2).Info("DiscoverSriovDevices")
×
206
        pfList := []sriovnetworkv1.InterfaceExt{}
×
207

×
208
        pci, err := ghw.PCI()
×
209
        if err != nil {
×
210
                return nil, fmt.Errorf("DiscoverSriovDevices(): error getting PCI info: %v", err)
×
211
        }
×
212

213
        devices := pci.ListDevices()
×
214
        if len(devices) == 0 {
×
215
                return nil, fmt.Errorf("DiscoverSriovDevices(): could not retrieve PCI devices")
×
216
        }
×
217

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

230
                // TODO: exclude devices used by host system
231

232
                if s.dputilsLib.IsSriovVF(device.Address) {
×
233
                        continue
×
234
                }
235

236
                if !vars.DevMode {
×
237
                        if !sriovnetworkv1.IsSupportedModel(device.Vendor.ID, device.Product.ID) {
×
238
                                log.Log.Info("DiscoverSriovDevices(): unsupported device", "device", device)
×
239
                                continue
×
240
                        }
241
                }
242

243
                driver, err := s.dputilsLib.GetDriverName(device.Address)
×
244
                if err != nil {
×
245
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse device driver for device, skipping", "device", device)
×
246
                        continue
×
247
                }
248

249
                pfNetName := s.networkHelper.TryGetInterfaceName(device.Address)
×
250

×
251
                if pfNetName == "" {
×
252
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get device name for device, skipping", "device", device.Address)
×
253
                        continue
×
254
                }
255

256
                link, err := s.netlinkLib.LinkByName(pfNetName)
×
257
                if err != nil {
×
258
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get Link for device, skipping", "device", device.Address)
×
259
                        continue
×
260
                }
261

262
                iface := sriovnetworkv1.InterfaceExt{
×
263
                        Name:       pfNetName,
×
264
                        PciAddress: device.Address,
×
265
                        Driver:     driver,
×
266
                        Vendor:     device.Vendor.ID,
×
267
                        DeviceID:   device.Product.ID,
×
268
                        Mtu:        link.Attrs().MTU,
×
269
                        Mac:        link.Attrs().HardwareAddr.String(),
×
270
                        LinkType:   s.encapTypeToLinkType(link.Attrs().EncapType),
×
271
                        LinkSpeed:  s.networkHelper.GetNetDevLinkSpeed(pfNetName),
×
272
                }
×
273

×
274
                pfStatus, exist, err := storeManager.LoadPfsStatus(iface.PciAddress)
×
275
                if err != nil {
×
276
                        log.Log.Error(err, "DiscoverSriovDevices(): failed to load PF status from disk")
×
277
                } else {
×
278
                        if exist {
×
279
                                iface.ExternallyManaged = pfStatus.ExternallyManaged
×
280
                        }
×
281
                }
282

283
                if s.dputilsLib.IsSriovPF(device.Address) {
×
284
                        iface.TotalVfs = s.dputilsLib.GetSriovVFcapacity(device.Address)
×
285
                        iface.NumVfs = s.dputilsLib.GetVFconfigured(device.Address)
×
286
                        iface.EswitchMode = s.GetNicSriovMode(device.Address)
×
287
                        if s.dputilsLib.SriovConfigured(device.Address) {
×
288
                                vfs, err := s.dputilsLib.GetVFList(device.Address)
×
289
                                if err != nil {
×
290
                                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse VFs for device, skipping",
×
291
                                                "device", device)
×
292
                                        continue
×
293
                                }
294
                                for _, vf := range vfs {
×
295
                                        instance := s.GetVfInfo(vf, devices)
×
296
                                        iface.VFs = append(iface.VFs, instance)
×
297
                                }
×
298
                        }
299
                }
300
                pfList = append(pfList, iface)
×
301
        }
302

303
        return pfList, nil
×
304
}
305

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

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

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

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

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

1✔
442
                        vfID, err := s.dputilsLib.GetVFID(addr)
1✔
443
                        if err != nil {
1✔
444
                                log.Log.Error(err, "configSriovVFDevices(): unable to get VF id", "device", iface.PciAddress)
×
445
                                return err
×
446
                        }
×
447

448
                        for i := range iface.VfGroups {
2✔
449
                                if sriovnetworkv1.IndexInRange(vfID, iface.VfGroups[i].VfRange) {
2✔
450
                                        group = &iface.VfGroups[i]
1✔
451
                                        break
1✔
452
                                }
453
                        }
454

455
                        // VF group not found.
456
                        if group == nil {
1✔
457
                                continue
×
458
                        }
459

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

484
                                                // Try to check the VF status again
485
                                                vfLink, err = s.VFIsReady(addr)
×
486
                                                if err != nil {
×
487
                                                        log.Log.Error(err, "configSriovVFDevices(): VF link is not ready", "address", addr)
×
488
                                                        return err
×
489
                                                }
×
490
                                        }
491
                                        if err = s.SetVfAdminMac(addr, pfLink, vfLink); err != nil {
1✔
492
                                                log.Log.Error(err, "configSriovVFDevices(): fail to configure VF admin mac", "device", addr)
×
493
                                                return err
×
494
                                        }
×
495
                                }
496
                        }
497

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

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

562
        if iface.ExternallyManaged {
2✔
563
                if err := s.checkExternallyManagedPF(iface); err != nil {
2✔
564
                        return err
1✔
565
                }
1✔
566
        }
567
        if err := s.configSriovVFDevices(iface); err != nil {
1✔
568
                return err
×
569
        }
×
570
        // Set PF link up
571
        pfLink, err := s.netlinkLib.LinkByName(iface.Name)
1✔
572
        if err != nil {
1✔
573
                return err
×
574
        }
×
575
        if pfLink.Attrs().OperState != netlink.OperUp {
2✔
576
                err = s.netlinkLib.LinkSetUp(pfLink)
1✔
577
                if err != nil {
1✔
578
                        return err
×
579
                }
×
580
        }
581
        return nil
1✔
582
}
583

584
func (s *sriov) ConfigSriovInterfaces(storeManager store.ManagerInterface,
585
        interfaces []sriovnetworkv1.Interface, ifaceStatuses []sriovnetworkv1.InterfaceExt, skipVFConfiguration bool) error {
1✔
586
        if s.kernelHelper.IsKernelLockdownMode() && mlx.HasMellanoxInterfacesInSpec(ifaceStatuses, interfaces) {
1✔
587
                log.Log.Error(nil, "cannot use mellanox devices when in kernel lockdown mode")
×
588
                return fmt.Errorf("cannot use mellanox devices when in kernel lockdown mode")
×
589
        }
×
590

591
        toBeConfigured, toBeResetted, err := s.getConfigureAndReset(storeManager, interfaces, ifaceStatuses)
1✔
592
        if err != nil {
1✔
593
                log.Log.Error(err, "cannot get a list of interfaces to configure")
×
594
                return fmt.Errorf("cannot get a list of interfaces to configure")
×
595
        }
×
596

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

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

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

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

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

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

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

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

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

×
725
        return nil
×
726
}
727

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

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

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

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

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

777
                return true, nil
×
778
        }
779
        return false, nil
1✔
780
}
781

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

791
        if !exist {
1✔
792
                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",
×
793
                        "pf-name", ifaceStatus.Name,
×
794
                        "address", ifaceStatus.PciAddress)
×
795
                return nil
×
796
        }
×
797

798
        if pfStatus.ExternallyManaged {
2✔
799
                log.Log.V(2).Info("checkForConfigAndReset(): PF name with pci address was externally created skipping the device reset",
1✔
800
                        "pf-name", ifaceStatus.Name,
1✔
801
                        "address", ifaceStatus.PciAddress)
1✔
802
                return nil
1✔
803
        }
1✔
804
        err = s.removeUdevRules(ifaceStatus.PciAddress)
1✔
805
        if err != nil {
1✔
806
                return err
×
807
        }
×
808

809
        if err = s.ResetSriovDevice(ifaceStatus); err != nil {
1✔
810
                return err
×
811
        }
×
812

813
        return nil
1✔
814
}
815

816
func (s *sriov) ConfigSriovDeviceVirtual(iface *sriovnetworkv1.Interface) error {
×
817
        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): config interface", "address", iface.PciAddress, "config", iface)
×
818
        // Config VFs
×
819
        if iface.NumVfs > 0 {
×
820
                if iface.NumVfs > 1 {
×
821
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): in a virtual environment, only one VF per interface",
×
822
                                "numVfs", iface.NumVfs)
×
823
                        return errors.New("NumVfs > 1")
×
824
                }
×
825
                if len(iface.VfGroups) != 1 {
×
826
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): missing VFGroup")
×
827
                        return errors.New("NumVfs != 1")
×
828
                }
×
829
                addr := iface.PciAddress
×
830
                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "address", addr)
×
831
                driver := ""
×
832
                vfID := 0
×
833
                for _, group := range iface.VfGroups {
×
834
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "group", group)
×
835
                        if sriovnetworkv1.IndexInRange(vfID, group.VfRange) {
×
836
                                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "indexInRange", vfID)
×
837
                                if sriovnetworkv1.StringInArray(group.DeviceType, vars.DpdkDrivers) {
×
838
                                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "driver", group.DeviceType)
×
839
                                        driver = group.DeviceType
×
840
                                }
×
841
                                break
×
842
                        }
843
                }
844
                if driver == "" {
×
845
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind default")
×
846
                        if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
×
847
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind default driver", "device", addr)
×
848
                                return err
×
849
                        }
×
850
                } else {
×
851
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind driver", "driver", driver)
×
852
                        if err := s.kernelHelper.BindDpdkDriver(addr, driver); err != nil {
×
853
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind driver for device",
×
854
                                        "driver", driver, "device", addr)
×
855
                                return err
×
856
                        }
×
857
                }
858
        }
859
        return nil
×
860
}
861

862
func (s *sriov) GetNicSriovMode(pciAddress string) string {
1✔
863
        log.Log.V(2).Info("GetNicSriovMode()", "device", pciAddress)
1✔
864
        devLink, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
865
        if err != nil {
2✔
866
                if !errors.Is(err, syscall.ENODEV) {
2✔
867
                        log.Log.Error(err, "GetNicSriovMode(): failed to get eswitch mode, assume legacy", "device", pciAddress)
1✔
868
                }
1✔
869
        }
870
        if devLink != nil && devLink.Attrs.Eswitch.Mode != "" {
2✔
871
                return devLink.Attrs.Eswitch.Mode
1✔
872
        }
1✔
873

874
        return sriovnetworkv1.ESwithModeLegacy
1✔
875
}
876

877
func (s *sriov) SetNicSriovMode(pciAddress string, mode string) error {
1✔
878
        log.Log.V(2).Info("SetNicSriovMode()", "device", pciAddress, "mode", mode)
1✔
879

1✔
880
        dev, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
881
        if err != nil {
2✔
882
                return err
1✔
883
        }
1✔
884
        return s.netlinkLib.DevLinkSetEswitchMode(dev, mode)
1✔
885
}
886

887
func (s *sriov) GetLinkType(name string) string {
1✔
888
        log.Log.V(2).Info("GetLinkType()", "name", name)
1✔
889
        link, err := s.netlinkLib.LinkByName(name)
1✔
890
        if err != nil {
1✔
891
                log.Log.Error(err, "GetLinkType(): failed to get link", "device", name)
×
892
                return ""
×
893
        }
×
894
        return s.encapTypeToLinkType(link.Attrs().EncapType)
1✔
895
}
896

897
func (s *sriov) encapTypeToLinkType(encapType string) string {
1✔
898
        if encapType == "ether" {
2✔
899
                return consts.LinkTypeETH
1✔
900
        } else if encapType == "infiniband" {
1✔
901
                return consts.LinkTypeIB
×
902
        }
×
903
        return ""
×
904
}
905

906
// create required udev rules for PF:
907
// * rule to disable NetworkManager for VFs - for all modes
908
// * rule to keep PF name after switching to switchdev mode - only for switchdev mode
909
func (s *sriov) addUdevRules(iface *sriovnetworkv1.Interface) error {
1✔
910
        log.Log.V(2).Info("addUdevRules(): add udev rules for device",
1✔
911
                "device", iface.PciAddress)
1✔
912
        if err := s.udevHelper.AddDisableNMUdevRule(iface.PciAddress); err != nil {
1✔
913
                return err
×
914
        }
×
915
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
916
                if err := s.udevHelper.AddPersistPFNameUdevRule(iface.PciAddress, iface.Name); err != nil {
1✔
NEW
917
                        return err
×
NEW
918
                }
×
919
        }
920
        return nil
1✔
921
}
922

923
// add switchdev-specific udev rule that renames representors.
924
// this rule relies on phys_port_name and phys_switch_id parameter which
925
// on old kernels can be read only after switching PF to switchdev mode.
926
// if PF doesn't expose phys_port_name and phys_switch_id, then rule creation will be skipped
927
func (s *sriov) addVfRepresentorUdevRule(iface *sriovnetworkv1.Interface) error {
1✔
928
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
929
                portName, err := s.networkHelper.GetPhysPortName(iface.Name)
1✔
930
                if err != nil {
1✔
NEW
931
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_port_name for device, skip creation of UDEV rule")
×
NEW
932
                        return nil
×
UNCOV
933
                }
×
934
                switchID, err := s.networkHelper.GetPhysSwitchID(iface.Name)
1✔
935
                if err != nil {
1✔
NEW
936
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_switch_id for device, skip creation of UDEV rule")
×
NEW
937
                        return nil
×
UNCOV
938
                }
×
939
                return s.udevHelper.AddVfRepresentorUdevRule(iface.PciAddress, iface.Name, switchID, portName)
1✔
940
        }
941
        return nil
1✔
942
}
943

944
// remove all udev rules for PF created by the operator
945
func (s *sriov) removeUdevRules(pciAddress string) error {
1✔
946
        log.Log.V(2).Info("removeUdevRules(): remove udev rules for device",
1✔
947
                "device", pciAddress)
1✔
948
        if err := s.udevHelper.RemoveDisableNMUdevRule(pciAddress); err != nil {
1✔
NEW
949
                return err
×
NEW
950
        }
×
951
        if err := s.udevHelper.RemoveVfRepresentorUdevRule(pciAddress); err != nil {
1✔
952
                return err
×
953
        }
×
954
        return s.udevHelper.RemovePersistPFNameUdevRule(pciAddress)
1✔
955
}
956

957
// create VFs on the PF
958
func (s *sriov) createVFs(iface *sriovnetworkv1.Interface) error {
1✔
959
        expectedEswitchMode := sriovnetworkv1.GetEswitchModeFromSpec(iface)
1✔
960
        log.Log.V(2).Info("createVFs(): configure VFs for device",
1✔
961
                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
1✔
962

1✔
963
        if s.dputilsLib.GetVFconfigured(iface.PciAddress) == iface.NumVfs {
1✔
964
                if s.GetNicSriovMode(iface.PciAddress) == expectedEswitchMode {
×
965
                        log.Log.V(2).Info("createVFs(): device is already configured",
×
966
                                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
×
967
                        return nil
×
968
                }
×
969
        }
970
        return s.setEswitchModeAndNumVFs(iface.PciAddress, expectedEswitchMode, iface.NumVfs)
1✔
971
}
972

973
func (s *sriov) setEswitchMode(pciAddr, eswitchMode string) error {
1✔
974
        log.Log.V(2).Info("setEswitchMode(): set eswitch mode", "device", pciAddr, "mode", eswitchMode)
1✔
975
        if err := s.unbindAllVFsOnPF(pciAddr); err != nil {
1✔
976
                log.Log.Error(err, "setEswitchMode(): failed to unbind VFs", "device", pciAddr, "mode", eswitchMode)
×
977
                return err
×
978
        }
×
979
        if err := s.SetNicSriovMode(pciAddr, eswitchMode); err != nil {
1✔
980
                err = fmt.Errorf("failed to switch NIC to SRIOV %s mode: %v", eswitchMode, err)
×
981
                log.Log.Error(err, "setEswitchMode(): failed to set mode", "device", pciAddr, "mode", eswitchMode)
×
982
                return err
×
983
        }
×
984
        return nil
1✔
985
}
986

987
func (s *sriov) setEswitchModeAndNumVFs(pciAddr string, desiredEswitchMode string, numVFs int) error {
1✔
988
        log.Log.V(2).Info("setEswitchModeAndNumVFs(): configure VFs for device",
1✔
989
                "device", pciAddr, "count", numVFs, "mode", desiredEswitchMode)
1✔
990

1✔
991
        // always switch NIC to the legacy mode before creating VFs. This is required because some drivers
1✔
992
        // may not support VF creation in the switchdev mode
1✔
993
        if s.GetNicSriovMode(pciAddr) != sriovnetworkv1.ESwithModeLegacy {
1✔
994
                if err := s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeLegacy); err != nil {
×
995
                        return err
×
996
                }
×
997
        }
998
        if err := s.SetSriovNumVfs(pciAddr, numVFs); err != nil {
1✔
999
                return err
×
1000
        }
×
1001

1002
        if desiredEswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
2✔
1003
                return s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeSwitchDev)
1✔
1004
        }
1✔
1005
        return nil
1✔
1006
}
1007

1008
// retrieve all VFs for the PF and unbind them from a driver
1009
func (s *sriov) unbindAllVFsOnPF(addr string) error {
1✔
1010
        log.Log.V(2).Info("unbindAllVFsOnPF(): unbind all VFs on PF", "device", addr)
1✔
1011
        vfAddrs, err := s.dputilsLib.GetVFList(addr)
1✔
1012
        if err != nil {
1✔
1013
                return fmt.Errorf("failed to read VF list: %v", err)
×
1014
        }
×
1015
        for _, vfAddr := range vfAddrs {
2✔
1016
                if err := s.kernelHelper.Unbind(vfAddr); err != nil {
1✔
1017
                        return fmt.Errorf("failed to unbind VF from the driver: %v", err)
×
1018
                }
×
1019
        }
1020
        return nil
1✔
1021
}
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