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

k8snetworkplumbingwg / sriov-network-operator / 9939865280

15 Jul 2024 01:00PM UTC coverage: 40.901% (-0.08%) from 40.981%
9939865280

push

github

web-flow
Merge pull request #734 from SchSeba/fix_mlx_plugin

Skip firmware reset on devices the operator doesn't control

16 of 53 new or added lines in 5 files covered. (30.19%)

5 existing lines in 1 file now uncovered.

5599 of 13689 relevant lines covered (40.9%)

0.45 hits per line

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

55.4
/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
        netlinkLib    netlinkPkg.NetlinkLib
42
        dputilsLib    dputilsPkg.DPUtilsLib
43
        sriovnetLib   sriovnetPkg.SriovnetLib
44
        ghwLib        ghwPkg.GHWLib
45
}
46

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

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

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

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

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

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

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

166
func (s *sriov) SetVfGUID(vfAddr string, pfLink netlink.Link) error {
1✔
167
        log.Log.Info("SetVfGUID()", "vf", vfAddr)
1✔
168
        vfID, err := s.dputilsLib.GetVFID(vfAddr)
1✔
169
        if err != nil {
1✔
170
                log.Log.Error(err, "SetVfGUID(): unable to get VF id", "address", vfAddr)
×
171
                return err
×
172
        }
×
173
        guid := utils.GenerateRandomGUID()
1✔
174
        if err := s.netlinkLib.LinkSetVfNodeGUID(pfLink, vfID, guid); err != nil {
1✔
175
                return err
×
176
        }
×
177
        if err := s.netlinkLib.LinkSetVfPortGUID(pfLink, vfID, guid); err != nil {
1✔
178
                return err
×
179
        }
×
180
        if err = s.kernelHelper.Unbind(vfAddr); err != nil {
1✔
181
                return err
×
182
        }
×
183

184
        return nil
1✔
185
}
186

187
func (s *sriov) VFIsReady(pciAddr string) (netlink.Link, error) {
1✔
188
        log.Log.Info("VFIsReady()", "device", pciAddr)
1✔
189
        var err error
1✔
190
        var vfLink netlink.Link
1✔
191
        err = wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
2✔
192
                vfIndex, err := s.networkHelper.GetInterfaceIndex(pciAddr)
1✔
193
                if err != nil {
2✔
194
                        log.Log.Error(err, "VFIsReady(): invalid index number")
1✔
195
                        return false, nil
1✔
196
                }
1✔
197
                vfLink, err = s.netlinkLib.LinkByIndex(vfIndex)
1✔
198
                if err != nil {
1✔
199
                        log.Log.Error(err, "VFIsReady(): unable to get VF link", "device", pciAddr)
×
200
                        return false, nil
×
201
                }
×
202
                return true, nil
1✔
203
        })
204
        if err != nil {
1✔
205
                return vfLink, err
×
206
        }
×
207
        return vfLink, nil
1✔
208
}
209

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

1✔
213
        vfID, err := s.dputilsLib.GetVFID(vfAddr)
1✔
214
        if err != nil {
1✔
215
                log.Log.Error(err, "SetVfAdminMac(): unable to get VF id", "address", vfAddr)
×
216
                return err
×
217
        }
×
218

219
        if err := s.netlinkLib.LinkSetVfHardwareAddr(pfLink, vfID, vfLink.Attrs().HardwareAddr); err != nil {
1✔
220
                return err
×
221
        }
×
222

223
        return nil
1✔
224
}
225

226
func (s *sriov) DiscoverSriovDevices(storeManager store.ManagerInterface) ([]sriovnetworkv1.InterfaceExt, error) {
1✔
227
        log.Log.V(2).Info("DiscoverSriovDevices")
1✔
228
        pfList := []sriovnetworkv1.InterfaceExt{}
1✔
229

1✔
230
        pci, err := s.ghwLib.PCI()
1✔
231
        if err != nil {
1✔
232
                return nil, fmt.Errorf("DiscoverSriovDevices(): error getting PCI info: %v", err)
×
233
        }
×
234

235
        devices := pci.ListDevices()
1✔
236
        if len(devices) == 0 {
1✔
237
                return nil, fmt.Errorf("DiscoverSriovDevices(): could not retrieve PCI devices")
×
238
        }
×
239

240
        for _, device := range devices {
2✔
241
                devClass, err := strconv.ParseInt(device.Class.ID, 16, 64)
1✔
242
                if err != nil {
1✔
243
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse device class, skipping",
×
244
                                "device", device)
×
245
                        continue
×
246
                }
247
                if devClass != consts.NetClass {
2✔
248
                        // Not network device
1✔
249
                        continue
1✔
250
                }
251

252
                // TODO: exclude devices used by host system
253

254
                if s.dputilsLib.IsSriovVF(device.Address) {
2✔
255
                        continue
1✔
256
                }
257

258
                if !vars.DevMode {
2✔
259
                        if !sriovnetworkv1.IsSupportedModel(device.Vendor.ID, device.Product.ID) {
2✔
260
                                log.Log.Info("DiscoverSriovDevices(): unsupported device", "device", device)
1✔
261
                                continue
1✔
262
                        }
263
                }
264

265
                driver, err := s.dputilsLib.GetDriverName(device.Address)
1✔
266
                if err != nil {
1✔
267
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse device driver for device, skipping", "device", device)
×
268
                        continue
×
269
                }
270

271
                pfNetName := s.networkHelper.TryGetInterfaceName(device.Address)
1✔
272

1✔
273
                if pfNetName == "" {
1✔
274
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get device name for device, skipping", "device", device.Address)
×
275
                        continue
×
276
                }
277

278
                link, err := s.netlinkLib.LinkByName(pfNetName)
1✔
279
                if err != nil {
1✔
280
                        log.Log.Error(err, "DiscoverSriovDevices(): unable to get Link for device, skipping", "device", device.Address)
×
281
                        continue
×
282
                }
283

284
                iface := sriovnetworkv1.InterfaceExt{
1✔
285
                        Name:           pfNetName,
1✔
286
                        PciAddress:     device.Address,
1✔
287
                        Driver:         driver,
1✔
288
                        Vendor:         device.Vendor.ID,
1✔
289
                        DeviceID:       device.Product.ID,
1✔
290
                        Mtu:            link.Attrs().MTU,
1✔
291
                        Mac:            link.Attrs().HardwareAddr.String(),
1✔
292
                        LinkType:       s.encapTypeToLinkType(link.Attrs().EncapType),
1✔
293
                        LinkSpeed:      s.networkHelper.GetNetDevLinkSpeed(pfNetName),
1✔
294
                        LinkAdminState: s.networkHelper.GetNetDevLinkAdminState(pfNetName),
1✔
295
                }
1✔
296

1✔
297
                pfStatus, exist, err := storeManager.LoadPfsStatus(iface.PciAddress)
1✔
298
                if err != nil {
1✔
299
                        log.Log.Error(err, "DiscoverSriovDevices(): failed to load PF status from disk")
×
300
                } else {
1✔
301
                        if exist {
1✔
302
                                iface.ExternallyManaged = pfStatus.ExternallyManaged
×
303
                        }
×
304
                }
305

306
                if s.dputilsLib.IsSriovPF(device.Address) {
2✔
307
                        iface.TotalVfs = s.dputilsLib.GetSriovVFcapacity(device.Address)
1✔
308
                        iface.NumVfs = s.dputilsLib.GetVFconfigured(device.Address)
1✔
309
                        iface.EswitchMode = s.GetNicSriovMode(device.Address)
1✔
310
                        if s.dputilsLib.SriovConfigured(device.Address) {
2✔
311
                                vfs, err := s.dputilsLib.GetVFList(device.Address)
1✔
312
                                if err != nil {
1✔
313
                                        log.Log.Error(err, "DiscoverSriovDevices(): unable to parse VFs for device, skipping",
×
314
                                                "device", device)
×
315
                                        continue
×
316
                                }
317
                                for _, vf := range vfs {
2✔
318
                                        instance := s.getVfInfo(vf, pfNetName, iface.EswitchMode, devices)
1✔
319
                                        iface.VFs = append(iface.VFs, instance)
1✔
320
                                }
1✔
321
                        }
322
                }
323
                pfList = append(pfList, iface)
1✔
324
        }
325

326
        return pfList, nil
1✔
327
}
328

329
func (s *sriov) configSriovPFDevice(iface *sriovnetworkv1.Interface) error {
1✔
330
        log.Log.V(2).Info("configSriovPFDevice(): configure PF sriov device",
1✔
331
                "device", iface.PciAddress)
1✔
332
        totalVfs := s.dputilsLib.GetSriovVFcapacity(iface.PciAddress)
1✔
333
        if iface.NumVfs > totalVfs {
1✔
334
                err := fmt.Errorf("cannot config SRIOV device: NumVfs (%d) is larger than TotalVfs (%d)", iface.NumVfs, totalVfs)
×
335
                log.Log.Error(err, "configSriovPFDevice(): fail to set NumVfs for device", "device", iface.PciAddress)
×
336
                return err
×
337
        }
×
338
        if err := s.configureHWOptionsForSwitchdev(iface); err != nil {
1✔
339
                return err
×
340
        }
×
341
        // remove all UDEV rules for the PF before adding new rules to
342
        // make sure that rules are always in a consistent state, e.g. there is no
343
        // switchdev-related rules for PF in legacy mode
344
        if err := s.removeUdevRules(iface.PciAddress); err != nil {
1✔
345
                log.Log.Error(err, "configSriovPFDevice(): fail to remove udev rules", "device", iface.PciAddress)
×
346
                return err
×
347
        }
×
348
        err := s.addUdevRules(iface)
1✔
349
        if err != nil {
1✔
350
                log.Log.Error(err, "configSriovPFDevice(): fail to add udev rules", "device", iface.PciAddress)
×
351
                return err
×
352
        }
×
353
        err = s.createVFs(iface)
1✔
354
        if err != nil {
1✔
355
                log.Log.Error(err, "configSriovPFDevice(): fail to set NumVfs for device", "device", iface.PciAddress)
×
356
                return err
×
357
        }
×
358
        if err := s.addVfRepresentorUdevRule(iface); err != nil {
1✔
359
                log.Log.Error(err, "configSriovPFDevice(): fail to add VR representor udev rule", "device", iface.PciAddress)
×
360
                return err
×
361
        }
×
362
        // set PF mtu
363
        if iface.Mtu > 0 && iface.Mtu > s.networkHelper.GetNetdevMTU(iface.PciAddress) {
1✔
364
                err = s.networkHelper.SetNetdevMTU(iface.PciAddress, iface.Mtu)
×
365
                if err != nil {
×
366
                        log.Log.Error(err, "configSriovPFDevice(): fail to set mtu for PF", "device", iface.PciAddress)
×
367
                        return err
×
368
                }
×
369
        }
370
        return nil
1✔
371
}
372

373
func (s *sriov) configureHWOptionsForSwitchdev(iface *sriovnetworkv1.Interface) error {
1✔
374
        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): configure HW options for device",
1✔
375
                "device", iface.PciAddress)
1✔
376
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) != sriovnetworkv1.ESwithModeSwitchDev {
2✔
377
                // we need to configure HW options only for PFs for which switchdev is a target mode
1✔
378
                return nil
1✔
379
        }
1✔
380
        if err := s.networkHelper.EnableHwTcOffload(iface.Name); err != nil {
1✔
381
                return err
×
382
        }
×
383
        desiredFlowSteeringMode := "smfs"
1✔
384
        currentFlowSteeringMode, err := s.networkHelper.GetDevlinkDeviceParam(iface.PciAddress, "flow_steering_mode")
1✔
385
        if err != nil {
2✔
386
                if errors.Is(err, syscall.EINVAL) || errors.Is(err, syscall.ENODEV) {
2✔
387
                        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): device has no flow_steering_mode parameter, skip",
1✔
388
                                "device", iface.PciAddress)
1✔
389
                        return nil
1✔
390
                }
1✔
391
                log.Log.Error(err, "configureHWOptionsForSwitchdev(): fail to read current flow steering mode for the device", "device", iface.PciAddress)
×
392
                return err
×
393
        }
394
        if currentFlowSteeringMode == desiredFlowSteeringMode {
×
395
                return nil
×
396
        }
×
397
        // flow steering mode can be changed only when NIC is in legacy mode
398
        if s.GetNicSriovMode(iface.PciAddress) != sriovnetworkv1.ESwithModeLegacy {
×
399
                s.setEswitchModeAndNumVFs(iface.PciAddress, sriovnetworkv1.ESwithModeLegacy, 0)
×
400
        }
×
401
        if err := s.networkHelper.SetDevlinkDeviceParam(iface.PciAddress, "flow_steering_mode", desiredFlowSteeringMode); err != nil {
×
402
                if errors.Is(err, syscall.ENOTSUP) {
×
403
                        log.Log.V(2).Info("configureHWOptionsForSwitchdev(): device doesn't support changing of flow_steering_mode, skip", "device", iface.PciAddress)
×
404
                        return nil
×
405
                }
×
406
                log.Log.Error(err, "configureHWOptionsForSwitchdev(): fail to configure flow steering mode for the device", "device", iface.PciAddress)
×
407
                return err
×
408
        }
409
        return nil
×
410
}
411

412
func (s *sriov) checkExternallyManagedPF(iface *sriovnetworkv1.Interface) error {
1✔
413
        log.Log.V(2).Info("checkExternallyManagedPF(): configure PF sriov device",
1✔
414
                "device", iface.PciAddress)
1✔
415
        currentNumVfs := s.dputilsLib.GetVFconfigured(iface.PciAddress)
1✔
416
        if iface.NumVfs > currentNumVfs {
2✔
417
                errMsg := fmt.Sprintf("checkExternallyManagedPF(): number of request virtual functions %d is not equal to configured virtual "+
1✔
418
                        "functions %d but the policy is configured as ExternallyManaged for device %s",
1✔
419
                        iface.NumVfs, currentNumVfs, iface.PciAddress)
1✔
420
                log.Log.Error(nil, errMsg)
1✔
421
                return fmt.Errorf(errMsg)
1✔
422
        }
1✔
423
        currentEswitchMode := s.GetNicSriovMode(iface.PciAddress)
1✔
424
        expectedEswitchMode := sriovnetworkv1.GetEswitchModeFromSpec(iface)
1✔
425
        if currentEswitchMode != expectedEswitchMode {
1✔
426
                errMsg := fmt.Sprintf("checkExternallyManagedPF(): requested ESwitchMode mode \"%s\" is not equal to configured \"%s\" "+
×
427
                        "but the policy is configured as ExternallyManaged for device %s", expectedEswitchMode, currentEswitchMode, iface.PciAddress)
×
428
                log.Log.Error(nil, errMsg)
×
429
                return fmt.Errorf(errMsg)
×
430
        }
×
431
        currentMtu := s.networkHelper.GetNetdevMTU(iface.PciAddress)
1✔
432
        if iface.Mtu > 0 && iface.Mtu > currentMtu {
2✔
433
                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✔
434
                        iface.Mtu, currentMtu, iface.PciAddress)
1✔
435
                log.Log.Error(nil, err.Error())
1✔
436
                return err
1✔
437
        }
1✔
438
        return nil
×
439
}
440

441
func (s *sriov) configSriovVFDevices(iface *sriovnetworkv1.Interface) error {
1✔
442
        log.Log.V(2).Info("configSriovVFDevices(): configure PF sriov device",
1✔
443
                "device", iface.PciAddress)
1✔
444
        if iface.NumVfs > 0 {
2✔
445
                vfAddrs, err := s.dputilsLib.GetVFList(iface.PciAddress)
1✔
446
                if err != nil {
1✔
447
                        log.Log.Error(err, "configSriovVFDevices(): unable to parse VFs for device", "device", iface.PciAddress)
×
448
                }
×
449
                pfLink, err := s.netlinkLib.LinkByName(iface.Name)
1✔
450
                if err != nil {
1✔
451
                        log.Log.Error(err, "configSriovVFDevices(): unable to get PF link for device", "device", iface)
×
452
                        return err
×
453
                }
×
454

455
                for _, addr := range vfAddrs {
2✔
456
                        hasDriver, _ := s.kernelHelper.HasDriver(addr)
1✔
457
                        if !hasDriver {
2✔
458
                                if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
1✔
459
                                        log.Log.Error(err, "configSriovVFDevices(): fail to bind default driver for device", "device", addr)
×
460
                                        return err
×
461
                                }
×
462
                        }
463
                        var group *sriovnetworkv1.VfGroup
1✔
464

1✔
465
                        vfID, err := s.dputilsLib.GetVFID(addr)
1✔
466
                        if err != nil {
1✔
467
                                log.Log.Error(err, "configSriovVFDevices(): unable to get VF id", "device", iface.PciAddress)
×
468
                                return err
×
469
                        }
×
470

471
                        for i := range iface.VfGroups {
2✔
472
                                if sriovnetworkv1.IndexInRange(vfID, iface.VfGroups[i].VfRange) {
2✔
473
                                        group = &iface.VfGroups[i]
1✔
474
                                        break
1✔
475
                                }
476
                        }
477

478
                        // VF group not found.
479
                        if group == nil {
1✔
480
                                continue
×
481
                        }
482

483
                        // only set GUID and MAC for VF with default driver
484
                        // for userspace drivers like vfio we configure the vf mac using the kernel nic mac address
485
                        // before we switch to the userspace driver
486
                        if yes, d := s.kernelHelper.HasDriver(addr); yes && !sriovnetworkv1.StringInArray(d, vars.DpdkDrivers) {
2✔
487
                                // LinkType is an optional field. Let's fallback to current link type
1✔
488
                                // if nothing is specified in the SriovNodePolicy
1✔
489
                                linkType := iface.LinkType
1✔
490
                                if linkType == "" {
2✔
491
                                        linkType = s.GetLinkType(iface.Name)
1✔
492
                                }
1✔
493
                                if strings.EqualFold(linkType, consts.LinkTypeIB) {
2✔
494
                                        if err = s.SetVfGUID(addr, pfLink); err != nil {
1✔
495
                                                return err
×
496
                                        }
×
497
                                } else {
1✔
498
                                        vfLink, err := s.VFIsReady(addr)
1✔
499
                                        if err != nil {
1✔
500
                                                log.Log.Error(err, "configSriovVFDevices(): VF link is not ready", "address", addr)
×
501
                                                err = s.kernelHelper.RebindVfToDefaultDriver(addr)
×
502
                                                if err != nil {
×
503
                                                        log.Log.Error(err, "configSriovVFDevices(): failed to rebind VF", "address", addr)
×
504
                                                        return err
×
505
                                                }
×
506

507
                                                // Try to check the VF status again
508
                                                vfLink, err = s.VFIsReady(addr)
×
509
                                                if err != nil {
×
510
                                                        log.Log.Error(err, "configSriovVFDevices(): VF link is not ready", "address", addr)
×
511
                                                        return err
×
512
                                                }
×
513
                                        }
514
                                        if err = s.SetVfAdminMac(addr, pfLink, vfLink); err != nil {
1✔
515
                                                log.Log.Error(err, "configSriovVFDevices(): fail to configure VF admin mac", "device", addr)
×
516
                                                return err
×
517
                                        }
×
518
                                }
519
                        }
520

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

565
func (s *sriov) configSriovDevice(iface *sriovnetworkv1.Interface, skipVFConfiguration bool) error {
1✔
566
        log.Log.V(2).Info("configSriovDevice(): configure sriov device",
1✔
567
                "device", iface.PciAddress, "config", iface, "skipVFConfiguration", skipVFConfiguration)
1✔
568
        if !iface.ExternallyManaged {
2✔
569
                if err := s.configSriovPFDevice(iface); err != nil {
1✔
570
                        return err
×
571
                }
×
572
        }
573
        if skipVFConfiguration {
2✔
574
                if iface.ExternallyManaged {
1✔
575
                        return nil
×
576
                }
×
577
                log.Log.V(2).Info("configSriovDevice(): skipVFConfiguration is true, unbind all VFs from drivers",
1✔
578
                        "device", iface.PciAddress)
1✔
579
                return s.unbindAllVFsOnPF(iface.PciAddress)
1✔
580
        }
581
        // we don't need to validate externally managed PFs when skipVFConfiguration is true.
582
        // The function usually called with skipVFConfiguration true when running in the systemd mode and configuration is
583
        // in pre phase. Externally managed PFs may not be configured at this stage yet (preConfig stage is executed before NetworkManager, netplan)
584

585
        if iface.ExternallyManaged {
2✔
586
                if err := s.checkExternallyManagedPF(iface); err != nil {
2✔
587
                        return err
1✔
588
                }
1✔
589
        }
590
        if err := s.configSriovVFDevices(iface); err != nil {
1✔
591
                return err
×
592
        }
×
593
        // Set PF link up
594
        pfLink, err := s.netlinkLib.LinkByName(iface.Name)
1✔
595
        if err != nil {
1✔
596
                return err
×
597
        }
×
598
        if !s.netlinkLib.IsLinkAdminStateUp(pfLink) {
2✔
599
                err = s.netlinkLib.LinkSetUp(pfLink)
1✔
600
                if err != nil {
1✔
601
                        return err
×
602
                }
×
603
        }
604
        return nil
1✔
605
}
606

607
func (s *sriov) ConfigSriovInterfaces(storeManager store.ManagerInterface,
608
        interfaces []sriovnetworkv1.Interface, ifaceStatuses []sriovnetworkv1.InterfaceExt, skipVFConfiguration bool) error {
1✔
609
        toBeConfigured, toBeResetted, err := s.getConfigureAndReset(storeManager, interfaces, ifaceStatuses)
1✔
610
        if err != nil {
1✔
611
                log.Log.Error(err, "cannot get a list of interfaces to configure")
×
612
                return fmt.Errorf("cannot get a list of interfaces to configure")
×
613
        }
×
614

615
        if vars.ParallelNicConfig {
1✔
616
                err = s.configSriovInterfacesInParallel(storeManager, toBeConfigured, skipVFConfiguration)
×
617
        } else {
1✔
618
                err = s.configSriovInterfaces(storeManager, toBeConfigured, skipVFConfiguration)
1✔
619
        }
1✔
620
        if err != nil {
2✔
621
                log.Log.Error(err, "cannot configure sriov interfaces")
1✔
622
                return fmt.Errorf("cannot configure sriov interfaces")
1✔
623
        }
1✔
624
        if sriovnetworkv1.ContainsSwitchdevInterface(interfaces) && len(toBeConfigured) > 0 {
2✔
625
                // for switchdev devices we create udev rule that renames VF representors
1✔
626
                // after VFs are created. Reload rules to update interfaces
1✔
627
                if err := s.udevHelper.LoadUdevRules(); err != nil {
1✔
628
                        log.Log.Error(err, "cannot reload udev rules")
×
629
                        return fmt.Errorf("failed to reload udev rules: %v", err)
×
630
                }
×
631
        }
632

633
        if vars.ParallelNicConfig {
1✔
634
                err = s.resetSriovInterfacesInParallel(storeManager, toBeResetted)
×
635
        } else {
1✔
636
                err = s.resetSriovInterfaces(storeManager, toBeResetted)
1✔
637
        }
1✔
638
        if err != nil {
1✔
639
                log.Log.Error(err, "cannot reset sriov interfaces")
×
640
                return fmt.Errorf("cannot reset sriov interfaces")
×
641
        }
×
642
        return nil
1✔
643
}
644

645
func (s *sriov) getConfigureAndReset(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.Interface,
646
        ifaceStatuses []sriovnetworkv1.InterfaceExt) ([]interfaceToConfigure, []sriovnetworkv1.InterfaceExt, error) {
1✔
647
        toBeConfigured := []interfaceToConfigure{}
1✔
648
        toBeResetted := []sriovnetworkv1.InterfaceExt{}
1✔
649
        for _, ifaceStatus := range ifaceStatuses {
2✔
650
                configured := false
1✔
651
                for _, iface := range interfaces {
2✔
652
                        if iface.PciAddress == ifaceStatus.PciAddress {
2✔
653
                                configured = true
1✔
654
                                skip, err := skipSriovConfig(&iface, &ifaceStatus, storeManager)
1✔
655
                                if err != nil {
1✔
656
                                        log.Log.Error(err, "getConfigureAndReset(): failed to check interface")
×
657
                                        return nil, nil, err
×
658
                                }
×
659
                                if skip {
1✔
660
                                        break
×
661
                                }
662
                                iface := iface
1✔
663
                                ifaceStatus := ifaceStatus
1✔
664
                                toBeConfigured = append(toBeConfigured, interfaceToConfigure{iface: iface, ifaceStatus: ifaceStatus})
1✔
665
                        }
666
                }
667

668
                if !configured && ifaceStatus.NumVfs > 0 {
2✔
669
                        toBeResetted = append(toBeResetted, ifaceStatus)
1✔
670
                }
1✔
671
        }
672
        return toBeConfigured, toBeResetted, nil
1✔
673
}
674

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

×
678
        var result error
×
679
        errChannel := make(chan error)
×
680
        interfacesToConfigure := 0
×
681
        for ifaceIndex, iface := range interfaces {
×
682
                interfacesToConfigure += 1
×
683
                go func(iface *interfaceToConfigure) {
×
684
                        var err error
×
685
                        if err = s.configSriovDevice(&iface.iface, skipVFConfiguration); err != nil {
×
686
                                log.Log.Error(err, "configSriovInterfacesInParallel(): fail to configure sriov interface. resetting interface.", "address", iface.iface.PciAddress)
×
687
                                if iface.iface.ExternallyManaged {
×
688
                                        log.Log.V(2).Info("configSriovInterfacesInParallel(): skipping device reset as the nic is marked as externally created")
×
689
                                } else {
×
690
                                        if resetErr := s.ResetSriovDevice(iface.ifaceStatus); resetErr != nil {
×
691
                                                log.Log.Error(resetErr, "configSriovInterfacesInParallel(): failed to reset on error SR-IOV interface")
×
692
                                                err = resetErr
×
693
                                        }
×
694
                                }
695
                        }
696
                        errChannel <- err
×
697
                }(&interfaces[ifaceIndex])
698
                // Save the PF status to the host
699
                err := storeManager.SaveLastPfAppliedStatus(&iface.iface)
×
700
                if err != nil {
×
701
                        log.Log.Error(err, "configSriovInterfacesInParallel(): failed to save PF applied config to host")
×
702
                        return err
×
703
                }
×
704
        }
705

706
        for i := 0; i < interfacesToConfigure; i++ {
×
707
                errMsg := <-errChannel
×
708
                result = errors.Join(result, errMsg)
×
709
        }
×
710
        if result != nil {
×
711
                log.Log.Error(result, "configSriovInterfacesInParallel(): fail to configure sriov interfaces")
×
712
                return result
×
713
        }
×
714
        log.Log.V(2).Info("configSriovInterfacesInParallel(): sriov configuration finished")
×
715
        return nil
×
716
}
717

718
func (s *sriov) resetSriovInterfacesInParallel(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.InterfaceExt) error {
×
719
        var result error
×
720
        errChannel := make(chan error, len(interfaces))
×
721
        interfacesToReset := 0
×
722
        for ifaceIndex := range interfaces {
×
723
                interfacesToReset += 1
×
724
                go func(iface *sriovnetworkv1.InterfaceExt) {
×
725
                        var err error
×
726
                        if err = s.checkForConfigAndReset(*iface, storeManager); err != nil {
×
727
                                log.Log.Error(err, "resetSriovInterfacesInParallel(): fail to reset sriov interface. resetting interface.", "address", iface.PciAddress)
×
728
                        }
×
729
                        errChannel <- err
×
730
                }(&interfaces[ifaceIndex])
731
        }
732

733
        for i := 0; i < interfacesToReset; i++ {
×
734
                errMsg := <-errChannel
×
735
                result = errors.Join(result, errMsg)
×
736
        }
×
737
        if result != nil {
×
738
                log.Log.Error(result, "resetSriovInterfacesInParallel(): fail to reset sriov interface")
×
739
                return result
×
740
        }
×
741
        log.Log.V(2).Info("resetSriovInterfacesInParallel(): sriov reset finished")
×
742

×
743
        return nil
×
744
}
745

746
func (s *sriov) configSriovInterfaces(storeManager store.ManagerInterface, interfaces []interfaceToConfigure, skipVFConfiguration bool) error {
1✔
747
        log.Log.V(2).Info("configSriovInterfaces(): start sriov configuration")
1✔
748
        for _, iface := range interfaces {
2✔
749
                if err := s.configSriovDevice(&iface.iface, skipVFConfiguration); err != nil {
2✔
750
                        log.Log.Error(err, "configSriovInterfaces(): fail to configure sriov interface. resetting interface.", "address", iface.iface.PciAddress)
1✔
751
                        if iface.iface.ExternallyManaged {
2✔
752
                                log.Log.V(2).Info("configSriovInterfaces(): skipping device reset as the nic is marked as externally created")
1✔
753
                        } else {
1✔
754
                                if resetErr := s.ResetSriovDevice(iface.ifaceStatus); resetErr != nil {
×
755
                                        log.Log.Error(resetErr, "configSriovInterfaces(): failed to reset on error SR-IOV interface")
×
756
                                }
×
757
                        }
758
                        return err
1✔
759
                }
760

761
                // Save the PF status to the host
762
                err := storeManager.SaveLastPfAppliedStatus(&iface.iface)
1✔
763
                if err != nil {
1✔
764
                        log.Log.Error(err, "configSriovInterfaces(): failed to save PF applied config to host")
×
765
                        return err
×
766
                }
×
767
        }
768
        log.Log.V(2).Info("configSriovInterfaces(): sriov configuration finished")
1✔
769
        return nil
1✔
770
}
771

772
func (s *sriov) resetSriovInterfaces(storeManager store.ManagerInterface, interfaces []sriovnetworkv1.InterfaceExt) error {
1✔
773
        for _, iface := range interfaces {
2✔
774
                if err := s.checkForConfigAndReset(iface, storeManager); err != nil {
1✔
775
                        log.Log.Error(err, "resetSriovInterfaces(): failed to reset sriov interface. resetting interface.", "address", iface.PciAddress)
×
776
                        return err
×
777
                }
×
778
        }
779
        log.Log.V(2).Info("resetSriovInterfaces(): sriov reset finished")
1✔
780
        return nil
1✔
781
}
782

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

×
788
                // Save the PF status to the host
×
789
                err := storeManager.SaveLastPfAppliedStatus(iface)
×
790
                if err != nil {
×
791
                        log.Log.Error(err, "ConfigSriovInterfaces(): failed to save PF applied status config to host")
×
792
                        return false, err
×
793
                }
×
794

795
                return true, nil
×
796
        }
797
        return false, nil
1✔
798
}
799

800
func (s *sriov) checkForConfigAndReset(ifaceStatus sriovnetworkv1.InterfaceExt, storeManager store.ManagerInterface) error {
1✔
801
        // load the PF info
1✔
802
        pfStatus, exist, err := storeManager.LoadPfsStatus(ifaceStatus.PciAddress)
1✔
803
        if err != nil {
1✔
804
                log.Log.Error(err, "checkForConfigAndReset(): failed to load info about PF status for device",
×
805
                        "address", ifaceStatus.PciAddress)
×
806
                return err
×
807
        }
×
808

809
        if !exist {
1✔
810
                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",
×
811
                        "pf-name", ifaceStatus.Name,
×
812
                        "address", ifaceStatus.PciAddress)
×
813
                return nil
×
814
        }
×
815

816
        if pfStatus.ExternallyManaged {
2✔
817
                log.Log.V(2).Info("checkForConfigAndReset(): PF name with pci address was externally created skipping the device reset",
1✔
818
                        "pf-name", ifaceStatus.Name,
1✔
819
                        "address", ifaceStatus.PciAddress)
1✔
820

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

827
                return nil
1✔
828
        }
829
        err = s.removeUdevRules(ifaceStatus.PciAddress)
1✔
830
        if err != nil {
1✔
831
                return err
×
832
        }
×
833

834
        if err = s.ResetSriovDevice(ifaceStatus); err != nil {
1✔
835
                return err
×
836
        }
×
837

838
        // remove pf status from host
839
        err = storeManager.RemovePfAppliedStatus(ifaceStatus.PciAddress)
1✔
840
        if err != nil {
1✔
NEW
841
                return err
×
NEW
842
        }
×
843

844
        return nil
1✔
845
}
846

847
func (s *sriov) ConfigSriovDeviceVirtual(iface *sriovnetworkv1.Interface) error {
×
848
        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): config interface", "address", iface.PciAddress, "config", iface)
×
849
        // Config VFs
×
850
        if iface.NumVfs > 0 {
×
851
                if iface.NumVfs > 1 {
×
852
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): in a virtual environment, only one VF per interface",
×
853
                                "numVfs", iface.NumVfs)
×
854
                        return errors.New("NumVfs > 1")
×
855
                }
×
856
                if len(iface.VfGroups) != 1 {
×
857
                        log.Log.Error(nil, "ConfigSriovDeviceVirtual(): missing VFGroup")
×
858
                        return errors.New("NumVfs != 1")
×
859
                }
×
860
                addr := iface.PciAddress
×
861
                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "address", addr)
×
862
                driver := ""
×
863
                vfID := 0
×
864
                for _, group := range iface.VfGroups {
×
865
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "group", group)
×
866
                        if sriovnetworkv1.IndexInRange(vfID, group.VfRange) {
×
867
                                log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "indexInRange", vfID)
×
868
                                if sriovnetworkv1.StringInArray(group.DeviceType, vars.DpdkDrivers) {
×
869
                                        log.Log.V(2).Info("ConfigSriovDeviceVirtual()", "driver", group.DeviceType)
×
870
                                        driver = group.DeviceType
×
871
                                }
×
872
                                break
×
873
                        }
874
                }
875
                if driver == "" {
×
876
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind default")
×
877
                        if err := s.kernelHelper.BindDefaultDriver(addr); err != nil {
×
878
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind default driver", "device", addr)
×
879
                                return err
×
880
                        }
×
881
                } else {
×
882
                        log.Log.V(2).Info("ConfigSriovDeviceVirtual(): bind driver", "driver", driver)
×
883
                        if err := s.kernelHelper.BindDpdkDriver(addr, driver); err != nil {
×
884
                                log.Log.Error(err, "ConfigSriovDeviceVirtual(): fail to bind driver for device",
×
885
                                        "driver", driver, "device", addr)
×
886
                                return err
×
887
                        }
×
888
                }
889
        }
890
        return nil
×
891
}
892

893
func (s *sriov) GetNicSriovMode(pciAddress string) string {
1✔
894
        log.Log.V(2).Info("GetNicSriovMode()", "device", pciAddress)
1✔
895
        devLink, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
896
        if err != nil {
2✔
897
                if !errors.Is(err, syscall.ENODEV) {
2✔
898
                        log.Log.Error(err, "GetNicSriovMode(): failed to get eswitch mode, assume legacy", "device", pciAddress)
1✔
899
                }
1✔
900
        }
901
        if devLink != nil && devLink.Attrs.Eswitch.Mode != "" {
2✔
902
                return devLink.Attrs.Eswitch.Mode
1✔
903
        }
1✔
904

905
        return sriovnetworkv1.ESwithModeLegacy
1✔
906
}
907

908
func (s *sriov) SetNicSriovMode(pciAddress string, mode string) error {
1✔
909
        log.Log.V(2).Info("SetNicSriovMode()", "device", pciAddress, "mode", mode)
1✔
910

1✔
911
        dev, err := s.netlinkLib.DevLinkGetDeviceByName("pci", pciAddress)
1✔
912
        if err != nil {
2✔
913
                return err
1✔
914
        }
1✔
915
        return s.netlinkLib.DevLinkSetEswitchMode(dev, mode)
1✔
916
}
917

918
func (s *sriov) GetLinkType(name string) string {
1✔
919
        log.Log.V(2).Info("GetLinkType()", "name", name)
1✔
920
        link, err := s.netlinkLib.LinkByName(name)
1✔
921
        if err != nil {
1✔
922
                log.Log.Error(err, "GetLinkType(): failed to get link", "device", name)
×
923
                return ""
×
924
        }
×
925
        return s.encapTypeToLinkType(link.Attrs().EncapType)
1✔
926
}
927

928
func (s *sriov) encapTypeToLinkType(encapType string) string {
1✔
929
        if encapType == "ether" {
2✔
930
                return consts.LinkTypeETH
1✔
931
        } else if encapType == "infiniband" {
1✔
932
                return consts.LinkTypeIB
×
933
        }
×
934
        return ""
×
935
}
936

937
// create required udev rules for PF:
938
// * rule to disable NetworkManager for VFs - for all modes
939
// * rule to keep PF name after switching to switchdev mode - only for switchdev mode
940
func (s *sriov) addUdevRules(iface *sriovnetworkv1.Interface) error {
1✔
941
        log.Log.V(2).Info("addUdevRules(): add udev rules for device",
1✔
942
                "device", iface.PciAddress)
1✔
943
        if err := s.udevHelper.AddDisableNMUdevRule(iface.PciAddress); err != nil {
1✔
944
                return err
×
945
        }
×
946
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
947
                if err := s.udevHelper.AddPersistPFNameUdevRule(iface.PciAddress, iface.Name); err != nil {
1✔
948
                        return err
×
949
                }
×
950
        }
951
        return nil
1✔
952
}
953

954
// add switchdev-specific udev rule that renames representors.
955
// this rule relies on phys_port_name and phys_switch_id parameter which
956
// on old kernels can be read only after switching PF to switchdev mode.
957
// if PF doesn't expose phys_port_name and phys_switch_id, then rule creation will be skipped
958
func (s *sriov) addVfRepresentorUdevRule(iface *sriovnetworkv1.Interface) error {
1✔
959
        if sriovnetworkv1.GetEswitchModeFromSpec(iface) == sriovnetworkv1.ESwithModeSwitchDev {
2✔
960
                portName, err := s.networkHelper.GetPhysPortName(iface.Name)
1✔
961
                if err != nil {
1✔
962
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_port_name for device, skip creation of UDEV rule")
×
963
                        return nil
×
964
                }
×
965
                switchID, err := s.networkHelper.GetPhysSwitchID(iface.Name)
1✔
966
                if err != nil {
1✔
967
                        log.Log.Error(err, "addVfRepresentorUdevRule(): WARNING: can't read phys_switch_id for device, skip creation of UDEV rule")
×
968
                        return nil
×
969
                }
×
970
                return s.udevHelper.AddVfRepresentorUdevRule(iface.PciAddress, iface.Name, switchID, portName)
1✔
971
        }
972
        return nil
1✔
973
}
974

975
// remove all udev rules for PF created by the operator
976
func (s *sriov) removeUdevRules(pciAddress string) error {
1✔
977
        log.Log.V(2).Info("removeUdevRules(): remove udev rules for device",
1✔
978
                "device", pciAddress)
1✔
979
        if err := s.udevHelper.RemoveDisableNMUdevRule(pciAddress); err != nil {
1✔
980
                return err
×
981
        }
×
982
        if err := s.udevHelper.RemoveVfRepresentorUdevRule(pciAddress); err != nil {
1✔
983
                return err
×
984
        }
×
985
        return s.udevHelper.RemovePersistPFNameUdevRule(pciAddress)
1✔
986
}
987

988
// create VFs on the PF
989
func (s *sriov) createVFs(iface *sriovnetworkv1.Interface) error {
1✔
990
        expectedEswitchMode := sriovnetworkv1.GetEswitchModeFromSpec(iface)
1✔
991
        log.Log.V(2).Info("createVFs(): configure VFs for device",
1✔
992
                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
1✔
993

1✔
994
        if s.dputilsLib.GetVFconfigured(iface.PciAddress) == iface.NumVfs {
1✔
995
                if s.GetNicSriovMode(iface.PciAddress) == expectedEswitchMode {
×
996
                        log.Log.V(2).Info("createVFs(): device is already configured",
×
997
                                "device", iface.PciAddress, "count", iface.NumVfs, "mode", expectedEswitchMode)
×
998
                        return nil
×
999
                }
×
1000
        }
1001
        return s.setEswitchModeAndNumVFs(iface.PciAddress, expectedEswitchMode, iface.NumVfs)
1✔
1002
}
1003

1004
func (s *sriov) setEswitchMode(pciAddr, eswitchMode string) error {
1✔
1005
        log.Log.V(2).Info("setEswitchMode(): set eswitch mode", "device", pciAddr, "mode", eswitchMode)
1✔
1006
        if err := s.unbindAllVFsOnPF(pciAddr); err != nil {
1✔
1007
                log.Log.Error(err, "setEswitchMode(): failed to unbind VFs", "device", pciAddr, "mode", eswitchMode)
×
1008
                return err
×
1009
        }
×
1010
        if err := s.SetNicSriovMode(pciAddr, eswitchMode); err != nil {
1✔
1011
                err = fmt.Errorf("failed to switch NIC to SRIOV %s mode: %v", eswitchMode, err)
×
1012
                log.Log.Error(err, "setEswitchMode(): failed to set mode", "device", pciAddr, "mode", eswitchMode)
×
1013
                return err
×
1014
        }
×
1015
        return nil
1✔
1016
}
1017

1018
func (s *sriov) setEswitchModeAndNumVFs(pciAddr string, desiredEswitchMode string, numVFs int) error {
1✔
1019
        log.Log.V(2).Info("setEswitchModeAndNumVFs(): configure VFs for device",
1✔
1020
                "device", pciAddr, "count", numVFs, "mode", desiredEswitchMode)
1✔
1021

1✔
1022
        // always switch NIC to the legacy mode before creating VFs. This is required because some drivers
1✔
1023
        // may not support VF creation in the switchdev mode
1✔
1024
        if s.GetNicSriovMode(pciAddr) != sriovnetworkv1.ESwithModeLegacy {
1✔
1025
                if err := s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeLegacy); err != nil {
×
1026
                        return err
×
1027
                }
×
1028
        }
1029
        if err := s.SetSriovNumVfs(pciAddr, numVFs); err != nil {
1✔
1030
                return err
×
1031
        }
×
1032

1033
        if desiredEswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
2✔
1034
                return s.setEswitchMode(pciAddr, sriovnetworkv1.ESwithModeSwitchDev)
1✔
1035
        }
1✔
1036
        return nil
1✔
1037
}
1038

1039
// retrieve all VFs for the PF and unbind them from a driver
1040
func (s *sriov) unbindAllVFsOnPF(addr string) error {
1✔
1041
        log.Log.V(2).Info("unbindAllVFsOnPF(): unbind all VFs on PF", "device", addr)
1✔
1042
        vfAddrs, err := s.dputilsLib.GetVFList(addr)
1✔
1043
        if err != nil {
1✔
1044
                return fmt.Errorf("failed to read VF list: %v", err)
×
1045
        }
×
1046
        for _, vfAddr := range vfAddrs {
2✔
1047
                if err := s.kernelHelper.Unbind(vfAddr); err != nil {
1✔
1048
                        return fmt.Errorf("failed to unbind VF from the driver: %v", err)
×
1049
                }
×
1050
        }
1051
        return nil
1✔
1052
}
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