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

k8snetworkplumbingwg / sriov-network-operator / 3957506820

pending completion
3957506820

Pull #365

github

GitHub
Merge 42b397513 into bf4e12202
Pull Request #365: Implementation for new systemd configuration method

956 of 956 new or added lines in 18 files covered. (100.0%)

1993 of 8328 relevant lines covered (23.93%)

0.27 hits per line

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

6.44
/pkg/utils/utils.go
1
package utils
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io/ioutil"
7
        "math/rand"
8
        "net"
9
        "os"
10
        "os/exec"
11
        "path/filepath"
12
        "regexp"
13
        "strconv"
14
        "strings"
15
        "syscall"
16
        "time"
17

18
        "github.com/cenkalti/backoff"
19
        "github.com/golang/glog"
20
        "github.com/jaypipes/ghw"
21
        "github.com/vishvananda/netlink"
22
        "k8s.io/apimachinery/pkg/util/wait"
23

24
        dputils "github.com/k8snetworkplumbingwg/sriov-network-device-plugin/pkg/utils"
25

26
        sriovnetworkv1 "github.com/k8snetworkplumbingwg/sriov-network-operator/api/v1"
27
        constants "github.com/k8snetworkplumbingwg/sriov-network-operator/pkg/consts"
28
)
29

30
const (
31
        sysBusPciDevices      = "/sys/bus/pci/devices"
32
        sysBusPciDrivers      = "/sys/bus/pci/drivers"
33
        sysBusPciDriversProbe = "/sys/bus/pci/drivers_probe"
34
        sysClassNet           = "/sys/class/net"
35
        netClass              = 0x02
36
        numVfsFile            = "sriov_numvfs"
37

38
        ClusterTypeOpenshift  = "openshift"
39
        ClusterTypeKubernetes = "kubernetes"
40
        VendorMellanox        = "15b3"
41
        DeviceBF2             = "a2d6"
42
)
43

44
var InitialState sriovnetworkv1.SriovNetworkNodeState
45
var ClusterType string
46

47
var pfPhysPortNameRe = regexp.MustCompile(`p\d+`)
48

49
func init() {
1✔
50
        ClusterType = os.Getenv("CLUSTER_TYPE")
1✔
51
}
1✔
52

53
func DiscoverSriovDevices(withUnsupported bool) ([]sriovnetworkv1.InterfaceExt, error) {
×
54
        glog.V(2).Info("DiscoverSriovDevices")
×
55
        pfList := []sriovnetworkv1.InterfaceExt{}
×
56

×
57
        pci, err := ghw.PCI()
×
58
        if err != nil {
×
59
                return nil, fmt.Errorf("DiscoverSriovDevices(): error getting PCI info: %v", err)
×
60
        }
×
61

62
        devices := pci.ListDevices()
×
63
        if len(devices) == 0 {
×
64
                return nil, fmt.Errorf("DiscoverSriovDevices(): could not retrieve PCI devices")
×
65
        }
×
66

67
        for _, device := range devices {
×
68
                devClass, err := strconv.ParseInt(device.Class.ID, 16, 64)
×
69
                if err != nil {
×
70
                        glog.Warningf("DiscoverSriovDevices(): unable to parse device class for device %+v %q", device, err)
×
71
                        continue
×
72
                }
73
                if devClass != netClass {
×
74
                        // Not network device
×
75
                        continue
×
76
                }
77

78
                // TODO: exclude devices used by host system
79

80
                if dputils.IsSriovVF(device.Address) {
×
81
                        continue
×
82
                }
83

84
                driver, err := dputils.GetDriverName(device.Address)
×
85
                if err != nil {
×
86
                        glog.Warningf("DiscoverSriovDevices(): unable to parse device driver for device %+v %q", device, err)
×
87
                        continue
×
88
                }
89

90
                deviceNames, err := dputils.GetNetNames(device.Address)
×
91
                if err != nil {
×
92
                        glog.Warningf("DiscoverSriovDevices(): unable to get device names for device %+v %q", device, err)
×
93
                        continue
×
94
                }
95

96
                if len(deviceNames) == 0 {
×
97
                        // no network devices found, skipping device
×
98
                        continue
×
99
                }
100

101
                if !withUnsupported {
×
102
                        if !sriovnetworkv1.IsSupportedModel(device.Vendor.ID, device.Product.ID) {
×
103
                                glog.Infof("DiscoverSriovDevices(): unsupported device %+v", device)
×
104
                                continue
×
105
                        }
106
                }
107

108
                iface := sriovnetworkv1.InterfaceExt{
×
109
                        PciAddress: device.Address,
×
110
                        Driver:     driver,
×
111
                        Vendor:     device.Vendor.ID,
×
112
                        DeviceID:   device.Product.ID,
×
113
                }
×
114
                if mtu := getNetdevMTU(device.Address); mtu > 0 {
×
115
                        iface.Mtu = mtu
×
116
                }
×
117
                if name := tryGetInterfaceName(device.Address); name != "" {
×
118
                        iface.Name = name
×
119
                        iface.Mac = getNetDevMac(name)
×
120
                        iface.LinkSpeed = getNetDevLinkSpeed(name)
×
121
                }
×
122
                iface.LinkType = getLinkType(iface)
×
123

×
124
                if dputils.IsSriovPF(device.Address) {
×
125
                        iface.TotalVfs = dputils.GetSriovVFcapacity(device.Address)
×
126
                        iface.NumVfs = dputils.GetVFconfigured(device.Address)
×
127
                        if iface.EswitchMode, err = GetNicSriovMode(device.Address); err != nil {
×
128
                                glog.Warningf("DiscoverSriovDevices(): unable to get device mode %+v %q", device.Address, err)
×
129
                        }
×
130
                        if dputils.SriovConfigured(device.Address) {
×
131
                                vfs, err := dputils.GetVFList(device.Address)
×
132
                                if err != nil {
×
133
                                        glog.Warningf("DiscoverSriovDevices(): unable to parse VFs for device %+v %q", device, err)
×
134
                                        continue
×
135
                                }
136
                                for _, vf := range vfs {
×
137
                                        instance := getVfInfo(vf, devices)
×
138
                                        iface.VFs = append(iface.VFs, instance)
×
139
                                }
×
140
                        }
141
                }
142
                pfList = append(pfList, iface)
×
143
        }
144

145
        return pfList, nil
×
146
}
147

148
// SyncNodeState Attempt to update the node state to match the desired state
149
func SyncNodeState(newState *sriovnetworkv1.SriovNetworkNodeState, pfsToConfig map[string]bool) error {
×
150
        return ConfigSriovInterfaces(newState.Spec.Interfaces, newState.Status.Interfaces, pfsToConfig)
×
151
}
×
152

153
func ConfigSriovInterfaces(interfaces []sriovnetworkv1.Interface, ifaceStatuses []sriovnetworkv1.InterfaceExt, pfsToConfig map[string]bool) error {
×
154
        if IsKernelLockdownMode(true) && hasMellanoxInterfacesInSpec(ifaceStatuses, interfaces) {
×
155
                glog.Warningf("cannot use mellanox devices when in kernel lockdown mode")
×
156
                return fmt.Errorf("cannot use mellanox devices when in kernel lockdown mode")
×
157
        }
×
158
        var err error
×
159
        for _, ifaceStatus := range ifaceStatuses {
×
160
                configured := false
×
161
                for _, iface := range interfaces {
×
162
                        if iface.PciAddress == ifaceStatus.PciAddress {
×
163
                                configured = true
×
164

×
165
                                if skip := pfsToConfig[iface.PciAddress]; skip {
×
166
                                        break
×
167
                                }
168

169
                                if !NeedUpdate(&iface, &ifaceStatus) {
×
170
                                        glog.V(2).Infof("syncNodeState(): no need update interface %s", iface.PciAddress)
×
171
                                        break
×
172
                                }
173
                                if err = configSriovDevice(&iface, &ifaceStatus); err != nil {
×
174
                                        glog.Errorf("SyncNodeState(): fail to configure sriov interface %s: %v. resetting interface.", iface.PciAddress, err)
×
175
                                        if resetErr := resetSriovDevice(ifaceStatus); resetErr != nil {
×
176
                                                glog.Errorf("SyncNodeState(): fail to reset on error SR-IOV interface: %s", resetErr)
×
177
                                        }
×
178
                                        return err
×
179
                                }
180
                                break
×
181
                        }
182
                }
183
                if !configured && ifaceStatus.NumVfs > 0 {
×
184
                        if skip := pfsToConfig[ifaceStatus.PciAddress]; skip {
×
185
                                continue
×
186
                        }
187

188
                        if err = resetSriovDevice(ifaceStatus); err != nil {
×
189
                                return err
×
190
                        }
×
191
                }
192
        }
193
        return nil
×
194
}
195

196
// skipConfigVf Use systemd service to configure switchdev mode or BF-2 NICs in OpenShift
197
func skipConfigVf(ifSpec sriovnetworkv1.Interface, ifStatus sriovnetworkv1.InterfaceExt) (bool, error) {
1✔
198
        if ifSpec.EswitchMode == sriovnetworkv1.ESwithModeSwitchDev {
1✔
199
                glog.V(2).Infof("skipConfigVf(): skip config VF for switchdev device")
×
200
                return true, nil
×
201
        }
×
202

203
        // Nvidia_mlx5_MT42822_BlueField-2_integrated_ConnectX-6_Dx in OpenShift
204
        if ClusterType == ClusterTypeOpenshift && ifStatus.Vendor == VendorMellanox && ifStatus.DeviceID == DeviceBF2 {
1✔
205
                // TODO: remove this when switch to the systemd configuration support.
×
206
                mode, err := mellanoxBlueFieldMode(ifStatus.PciAddress)
×
207
                if err != nil {
×
208
                        return false, fmt.Errorf("failed to read Mellanox Bluefield card mode for %s,%v", ifStatus.PciAddress, err)
×
209
                }
×
210

211
                if mode == bluefieldConnectXMode {
×
212
                        return false, nil
×
213
                }
×
214

215
                glog.V(2).Infof("skipConfigVf(): skip config VF for Bluefiled card on DPU mode")
×
216
                return true, nil
×
217
        }
218

219
        return false, nil
1✔
220
}
221

222
// GetPfsToSkip return a map of devices pci addresses to should be configured via systemd instead if the legacy mode
223
// we skip devices in switchdev mode and Bluefield card in ConnectX mode
224
func GetPfsToSkip(ns *sriovnetworkv1.SriovNetworkNodeState) (map[string]bool, error) {
1✔
225
        pfsToSkip := map[string]bool{}
1✔
226
        for _, ifaceStatus := range ns.Status.Interfaces {
2✔
227
                for _, iface := range ns.Spec.Interfaces {
2✔
228
                        if iface.PciAddress == ifaceStatus.PciAddress {
2✔
229
                                skip, err := skipConfigVf(iface, ifaceStatus)
1✔
230
                                if err != nil {
1✔
231
                                        glog.Errorf("GetPfsToSkip(): fail to check for skip VFs %s: %v.", iface.PciAddress, err)
×
232
                                        return pfsToSkip, err
×
233
                                }
×
234
                                pfsToSkip[iface.PciAddress] = skip
1✔
235
                                break
1✔
236
                        }
237
                }
238
        }
239

240
        return pfsToSkip, nil
1✔
241
}
242

243
func NeedUpdate(iface *sriovnetworkv1.Interface, ifaceStatus *sriovnetworkv1.InterfaceExt) bool {
1✔
244
        if iface.Mtu > 0 {
2✔
245
                mtu := iface.Mtu
1✔
246
                if mtu != ifaceStatus.Mtu {
1✔
247
                        glog.V(2).Infof("NeedUpdate(): MTU needs update, desired=%d, current=%d", mtu, ifaceStatus.Mtu)
×
248
                        return true
×
249
                }
×
250
        }
251

252
        if iface.NumVfs != ifaceStatus.NumVfs {
1✔
253
                glog.V(2).Infof("NeedUpdate(): NumVfs needs update desired=%d, current=%d", iface.NumVfs, ifaceStatus.NumVfs)
×
254
                return true
×
255
        }
×
256
        if iface.NumVfs > 0 {
2✔
257
                for _, vf := range ifaceStatus.VFs {
2✔
258
                        ingroup := false
1✔
259
                        for _, group := range iface.VfGroups {
2✔
260
                                if sriovnetworkv1.IndexInRange(vf.VfID, group.VfRange) {
2✔
261
                                        ingroup = true
1✔
262
                                        if group.DeviceType != constants.DeviceTypeNetDevice {
1✔
263
                                                if group.DeviceType != vf.Driver {
×
264
                                                        glog.V(2).Infof("NeedUpdate(): Driver needs update, desired=%s, current=%s", group.DeviceType, vf.Driver)
×
265
                                                        return true
×
266
                                                }
×
267
                                        } else {
1✔
268
                                                if sriovnetworkv1.StringInArray(vf.Driver, DpdkDrivers) {
1✔
269
                                                        glog.V(2).Infof("NeedUpdate(): Driver needs update, desired=%s, current=%s", group.DeviceType, vf.Driver)
×
270
                                                        return true
×
271
                                                }
×
272
                                                if vf.Mtu != 0 && group.Mtu != 0 && vf.Mtu != group.Mtu {
2✔
273
                                                        glog.V(2).Infof("NeedUpdate(): VF %d MTU needs update, desired=%d, current=%d", vf.VfID, group.Mtu, vf.Mtu)
1✔
274
                                                        return true
1✔
275
                                                }
1✔
276
                                        }
277
                                        break
1✔
278
                                }
279
                        }
280
                        if !ingroup && sriovnetworkv1.StringInArray(vf.Driver, DpdkDrivers) {
1✔
281
                                // VF which has DPDK driver loaded but not in any group, needs to be reset to default driver.
×
282
                                return true
×
283
                        }
×
284
                }
285
        }
286
        return false
1✔
287
}
288

289
func configSriovDevice(iface *sriovnetworkv1.Interface, ifaceStatus *sriovnetworkv1.InterfaceExt) error {
×
290
        glog.V(2).Infof("configSriovDevice(): config interface %s with %v", iface.PciAddress, iface)
×
291
        var err error
×
292
        if iface.NumVfs > ifaceStatus.TotalVfs {
×
293
                err := fmt.Errorf("cannot config SRIOV device: NumVfs (%d) is larger than TotalVfs (%d)", iface.NumVfs, ifaceStatus.TotalVfs)
×
294
                glog.Errorf("configSriovDevice(): fail to set NumVfs for device %s: %v", iface.PciAddress, err)
×
295
                return err
×
296
        }
×
297
        // set numVFs
298
        if iface.NumVfs != ifaceStatus.NumVfs {
×
299
                err = setSriovNumVfs(iface.PciAddress, iface.NumVfs)
×
300
                if err != nil {
×
301
                        glog.Errorf("configSriovDevice(): fail to set NumVfs for device %s", iface.PciAddress)
×
302
                        return err
×
303
                }
×
304
        }
305
        // set PF mtu
306
        if iface.Mtu > 0 && iface.Mtu != ifaceStatus.Mtu {
×
307
                err = setNetdevMTU(iface.PciAddress, iface.Mtu)
×
308
                if err != nil {
×
309
                        glog.Warningf("configSriovDevice(): fail to set mtu for PF %s: %v", iface.PciAddress, err)
×
310
                        return err
×
311
                }
×
312
        }
313
        // Config VFs
314
        if iface.NumVfs > 0 {
×
315
                vfAddrs, err := dputils.GetVFList(iface.PciAddress)
×
316
                if err != nil {
×
317
                        glog.Warningf("configSriovDevice(): unable to parse VFs for device %+v %q", iface.PciAddress, err)
×
318
                }
×
319
                pfLink, err := netlink.LinkByName(iface.Name)
×
320
                if err != nil {
×
321
                        glog.Errorf("configSriovDevice(): unable to get PF link for device %+v %q", iface, err)
×
322
                        return err
×
323
                }
×
324

325
                for _, addr := range vfAddrs {
×
326
                        var group sriovnetworkv1.VfGroup
×
327
                        i := 0
×
328
                        var dpdkDriver string
×
329
                        var isRdma bool
×
330
                        vfID, err := dputils.GetVFID(addr)
×
331
                        for i, group = range iface.VfGroups {
×
332
                                if err != nil {
×
333
                                        glog.Warningf("configSriovDevice(): unable to get VF id %+v %q", iface.PciAddress, err)
×
334
                                }
×
335
                                if sriovnetworkv1.IndexInRange(vfID, group.VfRange) {
×
336
                                        isRdma = group.IsRdma
×
337
                                        if sriovnetworkv1.StringInArray(group.DeviceType, DpdkDrivers) {
×
338
                                                dpdkDriver = group.DeviceType
×
339
                                        }
×
340
                                        break
×
341
                                }
342
                        }
343

344
                        // only set GUID and MAC for VF with default driver
345
                        // for userspace drivers like vfio we configure the vf mac using the kernel nic mac address
346
                        // before we switch to the userspace driver
347
                        if yes, d := hasDriver(addr); yes && !sriovnetworkv1.StringInArray(d, DpdkDrivers) {
×
348
                                // LinkType is an optional field. Let's fallback to current link type
×
349
                                // if nothing is specified in the SriovNodePolicy
×
350
                                linkType := iface.LinkType
×
351
                                if linkType == "" {
×
352
                                        linkType = ifaceStatus.LinkType
×
353
                                }
×
354
                                if strings.EqualFold(linkType, constants.LinkTypeIB) {
×
355
                                        if err = setVfGUID(addr, pfLink); err != nil {
×
356
                                                return err
×
357
                                        }
×
358
                                } else {
×
359
                                        vfLink, err := vfIsReady(addr)
×
360
                                        if err != nil {
×
361
                                                glog.Errorf("configSriovDevice(): VF link is not ready for device %s %q", addr, err)
×
362
                                                err = RebindVfToDefaultDriver(addr)
×
363
                                                if err != nil {
×
364
                                                        glog.Errorf("configSriovDevice(): failed to rebind VF %s %q", addr, err)
×
365
                                                        return err
×
366
                                                }
×
367

368
                                                // Try to check the VF status again
369
                                                vfLink, err = vfIsReady(addr)
×
370
                                                if err != nil {
×
371
                                                        glog.Errorf("configSriovDevice(): VF link is not ready for device %s %q", addr, err)
×
372
                                                        return err
×
373
                                                }
×
374
                                        }
375
                                        if err = setVfAdminMac(addr, pfLink, vfLink); err != nil {
×
376
                                                glog.Errorf("configSriovDevice(): fail to configure VF admin mac address for device %s %q", addr, err)
×
377
                                                return err
×
378
                                        }
×
379
                                }
380
                        }
381

382
                        if err = unbindDriverIfNeeded(addr, isRdma); err != nil {
×
383
                                return err
×
384
                        }
×
385

386
                        if dpdkDriver == "" {
×
387
                                if err := BindDefaultDriver(addr); err != nil {
×
388
                                        glog.Warningf("configSriovDevice(): fail to bind default driver for device %s", addr)
×
389
                                        return err
×
390
                                }
×
391
                                // only set MTU for VF with default driver
392
                                if iface.VfGroups[i].Mtu > 0 {
×
393
                                        if err := setNetdevMTU(addr, iface.VfGroups[i].Mtu); err != nil {
×
394
                                                glog.Warningf("configSriovDevice(): fail to set mtu for VF %s: %v", addr, err)
×
395
                                                return err
×
396
                                        }
×
397
                                }
398
                        } else {
×
399
                                if err := BindDpdkDriver(addr, dpdkDriver); err != nil {
×
400
                                        glog.Warningf("configSriovDevice(): fail to bind driver %s for device %s", dpdkDriver, addr)
×
401
                                        return err
×
402
                                }
×
403
                        }
404
                }
405
        }
406
        // Set PF link up
407
        pfLink, err := netlink.LinkByName(ifaceStatus.Name)
×
408
        if err != nil {
×
409
                return err
×
410
        }
×
411
        if pfLink.Attrs().OperState != netlink.OperUp {
×
412
                err = netlink.LinkSetUp(pfLink)
×
413
                if err != nil {
×
414
                        return err
×
415
                }
×
416
        }
417
        return nil
×
418
}
419

420
func setSriovNumVfs(pciAddr string, numVfs int) error {
×
421
        glog.V(2).Infof("setSriovNumVfs(): set NumVfs for device %s to %d", pciAddr, numVfs)
×
422
        numVfsFilePath := filepath.Join(sysBusPciDevices, pciAddr, numVfsFile)
×
423
        bs := []byte(strconv.Itoa(numVfs))
×
424
        err := ioutil.WriteFile(numVfsFilePath, []byte("0"), os.ModeAppend)
×
425
        if err != nil {
×
426
                glog.Warningf("setSriovNumVfs(): fail to reset NumVfs file %s", numVfsFilePath)
×
427
                return err
×
428
        }
×
429
        err = ioutil.WriteFile(numVfsFilePath, bs, os.ModeAppend)
×
430
        if err != nil {
×
431
                glog.Warningf("setSriovNumVfs(): fail to set NumVfs file %s", numVfsFilePath)
×
432
                return err
×
433
        }
×
434
        return nil
×
435
}
436

437
func setNetdevMTU(pciAddr string, mtu int) error {
×
438
        glog.V(2).Infof("setNetdevMTU(): set MTU for device %s to %d", pciAddr, mtu)
×
439
        if mtu <= 0 {
×
440
                glog.V(2).Infof("setNetdevMTU(): not set MTU to %d", mtu)
×
441
                return nil
×
442
        }
×
443
        b := backoff.NewConstantBackOff(1 * time.Second)
×
444
        err := backoff.Retry(func() error {
×
445
                ifaceName, err := dputils.GetNetNames(pciAddr)
×
446
                if err != nil {
×
447
                        glog.Warningf("setNetdevMTU(): fail to get interface name for %s: %s", pciAddr, err)
×
448
                        return err
×
449
                }
×
450
                if len(ifaceName) < 1 {
×
451
                        return fmt.Errorf("setNetdevMTU(): interface name is empty")
×
452
                }
×
453
                mtuFile := "net/" + ifaceName[0] + "/mtu"
×
454
                mtuFilePath := filepath.Join(sysBusPciDevices, pciAddr, mtuFile)
×
455
                return ioutil.WriteFile(mtuFilePath, []byte(strconv.Itoa(mtu)), os.ModeAppend)
×
456
        }, backoff.WithMaxRetries(b, 10))
457
        if err != nil {
×
458
                glog.Warningf("setNetdevMTU(): fail to write mtu file after retrying: %v", err)
×
459
                return err
×
460
        }
×
461
        return nil
×
462
}
463

464
func tryGetInterfaceName(pciAddr string) string {
×
465
        names, err := dputils.GetNetNames(pciAddr)
×
466
        if err != nil || len(names) < 1 {
×
467
                return ""
×
468
        }
×
469
        netDevName := names[0]
×
470

×
471
        // Switchdev PF and their VFs representors are existing under the same PCI address since kernel 5.8
×
472
        // if device is switchdev then return PF name
×
473
        for _, name := range names {
×
474
                if !isSwitchdev(name) {
×
475
                        continue
×
476
                }
477
                // Try to get the phys port name, if not exists then fallback to check without it
478
                // phys_port_name should be in formant p<port-num> e.g p0,p1,p2 ...etc.
479
                if physPortName, err := GetPhysPortName(name); err == nil {
×
480
                        if !pfPhysPortNameRe.MatchString(physPortName) {
×
481
                                continue
×
482
                        }
483
                }
484
                return name
×
485
        }
486

487
        glog.V(2).Infof("tryGetInterfaceName(): name is %s", netDevName)
×
488
        return netDevName
×
489
}
490

491
func getNetdevMTU(pciAddr string) int {
×
492
        glog.V(2).Infof("getNetdevMTU(): get MTU for device %s", pciAddr)
×
493
        ifaceName := tryGetInterfaceName(pciAddr)
×
494
        if ifaceName == "" {
×
495
                return 0
×
496
        }
×
497
        mtuFile := "net/" + ifaceName + "/mtu"
×
498
        mtuFilePath := filepath.Join(sysBusPciDevices, pciAddr, mtuFile)
×
499
        data, err := ioutil.ReadFile(mtuFilePath)
×
500
        if err != nil {
×
501
                glog.Warningf("getNetdevMTU(): fail to read mtu file %s", mtuFilePath)
×
502
                return 0
×
503
        }
×
504
        mtu, err := strconv.Atoi(strings.TrimSpace(string(data)))
×
505
        if err != nil {
×
506
                glog.Warningf("getNetdevMTU(): fail to convert mtu %s to int", strings.TrimSpace(string(data)))
×
507
                return 0
×
508
        }
×
509
        return mtu
×
510
}
511

512
func getNetDevMac(ifaceName string) string {
×
513
        glog.V(2).Infof("getNetDevMac(): get Mac for device %s", ifaceName)
×
514
        macFilePath := filepath.Join(sysClassNet, ifaceName, "address")
×
515
        data, err := ioutil.ReadFile(macFilePath)
×
516
        if err != nil {
×
517
                glog.Warningf("getNetDevMac(): fail to read Mac file %s", macFilePath)
×
518
                return ""
×
519
        }
×
520

521
        return strings.TrimSpace(string(data))
×
522
}
523

524
func getNetDevLinkSpeed(ifaceName string) string {
×
525
        glog.V(2).Infof("getNetDevLinkSpeed(): get LinkSpeed for device %s", ifaceName)
×
526
        speedFilePath := filepath.Join(sysClassNet, ifaceName, "speed")
×
527
        data, err := ioutil.ReadFile(speedFilePath)
×
528
        if err != nil {
×
529
                glog.Warningf("getNetDevLinkSpeed(): fail to read Link Speed file %s", speedFilePath)
×
530
                return ""
×
531
        }
×
532

533
        return fmt.Sprintf("%s Mb/s", strings.TrimSpace(string(data)))
×
534
}
535

536
func resetSriovDevice(ifaceStatus sriovnetworkv1.InterfaceExt) error {
×
537
        glog.V(2).Infof("resetSriovDevice(): reset SRIOV device %s", ifaceStatus.PciAddress)
×
538
        if err := setSriovNumVfs(ifaceStatus.PciAddress, 0); err != nil {
×
539
                return err
×
540
        }
×
541
        if ifaceStatus.LinkType == constants.LinkTypeETH {
×
542
                var mtu int
×
543
                is := InitialState.GetInterfaceStateByPciAddress(ifaceStatus.PciAddress)
×
544
                if is != nil {
×
545
                        mtu = is.Mtu
×
546
                } else {
×
547
                        mtu = 1500
×
548
                }
×
549
                glog.V(2).Infof("resetSriovDevice(): reset mtu to %d", mtu)
×
550
                if err := setNetdevMTU(ifaceStatus.PciAddress, mtu); err != nil {
×
551
                        return err
×
552
                }
×
553
        } else if ifaceStatus.LinkType == constants.LinkTypeIB {
×
554
                if err := setNetdevMTU(ifaceStatus.PciAddress, 2048); err != nil {
×
555
                        return err
×
556
                }
×
557
        }
558
        return nil
×
559
}
560

561
func getVfInfo(pciAddr string, devices []*ghw.PCIDevice) sriovnetworkv1.VirtualFunction {
×
562
        driver, err := dputils.GetDriverName(pciAddr)
×
563
        if err != nil {
×
564
                glog.Warningf("getVfInfo(): unable to parse device driver for device %s %q", pciAddr, err)
×
565
        }
×
566
        id, err := dputils.GetVFID(pciAddr)
×
567
        if err != nil {
×
568
                glog.Warningf("getVfInfo(): unable to get VF index for device %s %q", pciAddr, err)
×
569
        }
×
570
        vf := sriovnetworkv1.VirtualFunction{
×
571
                PciAddress: pciAddr,
×
572
                Driver:     driver,
×
573
                VfID:       id,
×
574
        }
×
575

×
576
        if mtu := getNetdevMTU(pciAddr); mtu > 0 {
×
577
                vf.Mtu = mtu
×
578
        }
×
579
        if name := tryGetInterfaceName(pciAddr); name != "" {
×
580
                vf.Name = name
×
581
                vf.Mac = getNetDevMac(name)
×
582
        }
×
583

584
        for _, device := range devices {
×
585
                if pciAddr == device.Address {
×
586
                        vf.Vendor = device.Vendor.ID
×
587
                        vf.DeviceID = device.Product.ID
×
588
                        break
×
589
                }
590
                continue
×
591
        }
592
        return vf
×
593
}
594

595
func Chroot(path string) (func() error, error) {
×
596
        root, err := os.Open("/")
×
597
        if err != nil {
×
598
                return nil, err
×
599
        }
×
600

601
        if err := syscall.Chroot(path); err != nil {
×
602
                root.Close()
×
603
                return nil, err
×
604
        }
×
605

606
        return func() error {
×
607
                defer root.Close()
×
608
                if err := root.Chdir(); err != nil {
×
609
                        return err
×
610
                }
×
611
                return syscall.Chroot(".")
×
612
        }, nil
613
}
614

615
func vfIsReady(pciAddr string) (netlink.Link, error) {
×
616
        glog.Infof("vfIsReady(): VF device %s", pciAddr)
×
617
        var err error
×
618
        var vfLink netlink.Link
×
619
        err = wait.PollImmediate(time.Second, 10*time.Second, func() (bool, error) {
×
620
                vfName := tryGetInterfaceName(pciAddr)
×
621
                vfLink, err = netlink.LinkByName(vfName)
×
622
                if err != nil {
×
623
                        glog.Errorf("vfIsReady(): unable to get VF link for device %+v, %q", pciAddr, err)
×
624
                }
×
625
                return err == nil, nil
×
626
        })
627
        if err != nil {
×
628
                return vfLink, err
×
629
        }
×
630
        return vfLink, nil
×
631
}
632

633
func setVfAdminMac(vfAddr string, pfLink, vfLink netlink.Link) error {
×
634
        glog.Infof("setVfAdminMac(): VF %s", vfAddr)
×
635

×
636
        vfID, err := dputils.GetVFID(vfAddr)
×
637
        if err != nil {
×
638
                glog.Errorf("setVfAdminMac(): unable to get VF id %+v %q", vfAddr, err)
×
639
                return err
×
640
        }
×
641

642
        if err := netlink.LinkSetVfHardwareAddr(pfLink, vfID, vfLink.Attrs().HardwareAddr); err != nil {
×
643
                return err
×
644
        }
×
645

646
        return nil
×
647
}
648

649
func unbindDriverIfNeeded(vfAddr string, isRdma bool) error {
×
650
        if isRdma {
×
651
                glog.Infof("unbindDriverIfNeeded(): unbind driver for %s", vfAddr)
×
652
                if err := Unbind(vfAddr); err != nil {
×
653
                        return err
×
654
                }
×
655
        }
656
        return nil
×
657
}
658

659
func getLinkType(ifaceStatus sriovnetworkv1.InterfaceExt) string {
×
660
        glog.Infof("getLinkType(): Device %s", ifaceStatus.PciAddress)
×
661
        if ifaceStatus.Name != "" {
×
662
                link, err := netlink.LinkByName(ifaceStatus.Name)
×
663
                if err != nil {
×
664
                        glog.Warningf("getLinkType(): %v", err)
×
665
                        return ""
×
666
                }
×
667
                linkType := link.Attrs().EncapType
×
668
                if linkType == "ether" {
×
669
                        return constants.LinkTypeETH
×
670
                } else if linkType == "infiniband" {
×
671
                        return constants.LinkTypeIB
×
672
                }
×
673
        }
674

675
        return ""
×
676
}
677

678
func setVfGUID(vfAddr string, pfLink netlink.Link) error {
×
679
        glog.Infof("setVfGuid(): VF %s", vfAddr)
×
680
        vfID, err := dputils.GetVFID(vfAddr)
×
681
        if err != nil {
×
682
                glog.Errorf("setVfGuid(): unable to get VF id %+v %q", vfAddr, err)
×
683
                return err
×
684
        }
×
685
        guid := generateRandomGUID()
×
686
        if err := netlink.LinkSetVfNodeGUID(pfLink, vfID, guid); err != nil {
×
687
                return err
×
688
        }
×
689
        if err := netlink.LinkSetVfPortGUID(pfLink, vfID, guid); err != nil {
×
690
                return err
×
691
        }
×
692
        if err = Unbind(vfAddr); err != nil {
×
693
                return err
×
694
        }
×
695

696
        return nil
×
697
}
698

699
func generateRandomGUID() net.HardwareAddr {
×
700
        guid := make(net.HardwareAddr, 8)
×
701

×
702
        // First field is 0x01 - xfe to avoid all zero and all F invalid guids
×
703
        guid[0] = byte(1 + rand.Intn(0xfe))
×
704

×
705
        for i := 1; i < len(guid); i++ {
×
706
                guid[i] = byte(rand.Intn(0x100))
×
707
        }
×
708

709
        return guid
×
710
}
711

712
func GetNicSriovMode(pciAddress string) (string, error) {
×
713
        glog.V(2).Infof("GetNicSriovMode(): device %s", pciAddress)
×
714
        devLink, err := netlink.DevLinkGetDeviceByName("pci", pciAddress)
×
715
        if err != nil {
×
716
                return "", err
×
717
        }
×
718
        return devLink.Attrs.Eswitch.Mode, nil
×
719
}
720

721
func GetPhysSwitchID(name string) (string, error) {
×
722
        swIDFile := filepath.Join(sysClassNet, name, "phys_switch_id")
×
723
        physSwitchID, err := ioutil.ReadFile(swIDFile)
×
724
        if err != nil {
×
725
                return "", err
×
726
        }
×
727
        if physSwitchID != nil {
×
728
                return strings.TrimSpace(string(physSwitchID)), nil
×
729
        }
×
730
        return "", nil
×
731
}
732

733
func GetPhysPortName(name string) (string, error) {
×
734
        devicePortNameFile := filepath.Join(sysClassNet, name, "phys_port_name")
×
735
        physPortName, err := ioutil.ReadFile(devicePortNameFile)
×
736
        if err != nil {
×
737
                return "", err
×
738
        }
×
739
        if physPortName != nil {
×
740
                return strings.TrimSpace(string(physPortName)), nil
×
741
        }
×
742
        return "", nil
×
743
}
744

745
func isSwitchdev(name string) bool {
×
746
        switchID, err := GetPhysSwitchID(name)
×
747
        if err != nil || switchID == "" {
×
748
                return false
×
749
        }
×
750

751
        return true
×
752
}
753

754
// IsKernelLockdownMode returns true when kernel lockdown mode is enabled
755
func IsKernelLockdownMode(chroot bool) bool {
×
756
        path := "/sys/kernel/security/lockdown"
×
757
        if !chroot {
×
758
                path = "/host" + path
×
759
        }
×
760
        out, err := RunCommand("cat", path)
×
761
        glog.V(2).Infof("IsKernelLockdownMode(): %s, %+v", out, err)
×
762
        if err != nil {
×
763
                return false
×
764
        }
×
765
        return strings.Contains(out, "[integrity]") || strings.Contains(out, "[confidentiality]")
×
766
}
767

768
// RunCommand runs a command
769
func RunCommand(command string, args ...string) (string, error) {
×
770
        glog.Infof("RunCommand(): %s %v", command, args)
×
771
        var stdout, stderr bytes.Buffer
×
772

×
773
        cmd := exec.Command(command, args...)
×
774
        cmd.Stdout = &stdout
×
775
        cmd.Stderr = &stderr
×
776

×
777
        err := cmd.Run()
×
778
        glog.V(2).Infof("RunCommand(): out:(%s), err:(%v)", stdout.String(), err)
×
779
        return stdout.String(), err
×
780
}
×
781

782
func hasMellanoxInterfacesInSpec(ifaceStatuses sriovnetworkv1.InterfaceExts, ifaceSpecs sriovnetworkv1.Interfaces) bool {
×
783
        for _, ifaceStatus := range ifaceStatuses {
×
784
                if ifaceStatus.Vendor == VendorMellanox {
×
785
                        for _, iface := range ifaceSpecs {
×
786
                                if iface.PciAddress == ifaceStatus.PciAddress {
×
787
                                        glog.V(2).Infof("hasMellanoxInterfacesInSpec(): Mellanox device %s (pci: %s) specified in SriovNetworkNodeState spec", ifaceStatus.Name, ifaceStatus.PciAddress)
×
788
                                        return true
×
789
                                }
×
790
                        }
791
                }
792
        }
793
        return false
×
794
}
795

796
// Workaround function to handle a case where the vf default driver is stuck and not able to create the vf kernel interface.
797
// This function unbind the VF from the default driver and try to bind it again
798
// bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2045087
799
func RebindVfToDefaultDriver(vfAddr string) error {
×
800
        glog.Infof("RebindVfToDefaultDriver(): VF %s", vfAddr)
×
801
        if err := Unbind(vfAddr); err != nil {
×
802
                return err
×
803
        }
×
804
        if err := BindDefaultDriver(vfAddr); err != nil {
×
805
                glog.Errorf("RebindVfToDefaultDriver(): fail to bind default driver for device %s", vfAddr)
×
806
                return err
×
807
        }
×
808

809
        glog.Warningf("RebindVfToDefaultDriver(): workaround implemented for VF %s", vfAddr)
×
810
        return nil
×
811
}
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

© 2026 Coveralls, Inc