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

k8snetworkplumbingwg / sriov-network-operator / 3751025296

pending completion
3751025296

Pull #365

github

GitHub
Merge 421284b55 into 788d76f7e
Pull Request #365: Implementation for new systemd configuration method

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

1971 of 8330 relevant lines covered (23.66%)

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
//
150
func SyncNodeState(newState *sriovnetworkv1.SriovNetworkNodeState, pfsToConfig map[string]bool) error {
×
151
        return ConfigSriovInterfaces(newState.Spec.Interfaces, newState.Status.Interfaces, pfsToConfig)
×
152
}
×
153

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

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

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

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

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

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

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

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

220
        return false, nil
1✔
221
}
222

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

241
        return pfsToSkip, nil
1✔
242
}
243

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

647
        return nil
×
648
}
649

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

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

676
        return ""
×
677
}
678

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

697
        return nil
×
698
}
699

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

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

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

710
        return guid
×
711
}
712

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

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

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

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

752
        return true
×
753
}
754

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

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

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

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

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

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

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