github.com/vishvananda/netlink@v1.3.0/devlink_test.go (about) 1 //go:build linux 2 // +build linux 3 4 package netlink 5 6 import ( 7 "flag" 8 "math/rand" 9 "net" 10 "os" 11 "strconv" 12 "testing" 13 14 "github.com/vishvananda/netlink/nl" 15 ) 16 17 func TestDevLinkGetDeviceList(t *testing.T) { 18 minKernelRequired(t, 4, 12) 19 setUpNetlinkTestWithKModule(t, "devlink") 20 _, err := DevLinkGetDeviceList() 21 if err != nil { 22 t.Fatal(err) 23 } 24 } 25 26 func TestDevLinkGetDeviceByName(t *testing.T) { 27 minKernelRequired(t, 4, 12) 28 setUpNetlinkTestWithKModule(t, "devlink") 29 _, err := DevLinkGetDeviceByName("foo", "bar") 30 if err != nil { 31 t.Fatal(err) 32 } 33 } 34 35 func TestDevLinkSetEswitchMode(t *testing.T) { 36 minKernelRequired(t, 4, 12) 37 setUpNetlinkTestWithKModule(t, "devlink") 38 dev, err := DevLinkGetDeviceByName("foo", "bar") 39 if err != nil { 40 t.Fatal(err) 41 } 42 err = DevLinkSetEswitchMode(dev, "switchdev") 43 if err != nil { 44 t.Fatal(err) 45 } 46 err = DevLinkSetEswitchMode(dev, "legacy") 47 if err != nil { 48 t.Fatal(err) 49 } 50 } 51 52 func TestDevLinkGetAllPortList(t *testing.T) { 53 minKernelRequired(t, 5, 4) 54 ports, err := DevLinkGetAllPortList() 55 if err != nil { 56 t.Fatal(err) 57 } 58 t.Log("devlink port count = ", len(ports)) 59 for _, port := range ports { 60 t.Log(*port) 61 } 62 } 63 64 func TestDevLinkAddDelSfPort(t *testing.T) { 65 var addAttrs DevLinkPortAddAttrs 66 minKernelRequired(t, 5, 13) 67 if bus == "" || device == "" { 68 t.Log("devlink bus and device are empty, skipping test") 69 return 70 } 71 72 dev, err := DevLinkGetDeviceByName(bus, device) 73 if err != nil { 74 t.Fatal(err) 75 return 76 } 77 addAttrs.SfNumberValid = true 78 addAttrs.SfNumber = uint32(sfnum) 79 addAttrs.PfNumber = 0 80 port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs) 81 if err2 != nil { 82 t.Fatal(err2) 83 return 84 } 85 t.Log(*port) 86 if port.Fn != nil { 87 t.Log("function attributes = ", *port.Fn) 88 } 89 err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex) 90 if err2 != nil { 91 t.Fatal(err2) 92 } 93 } 94 95 func TestDevLinkSfPortFnSet(t *testing.T) { 96 var addAttrs DevLinkPortAddAttrs 97 var stateAttr DevlinkPortFnSetAttrs 98 99 minKernelRequired(t, 5, 12) 100 if bus == "" || device == "" { 101 t.Log("devlink bus and device are empty, skipping test") 102 return 103 } 104 105 dev, err := DevLinkGetDeviceByName(bus, device) 106 if err != nil { 107 t.Fatal(err) 108 return 109 } 110 addAttrs.SfNumberValid = true 111 addAttrs.SfNumber = uint32(sfnum) 112 addAttrs.PfNumber = 0 113 port, err2 := DevLinkPortAdd(dev.BusName, dev.DeviceName, 7, addAttrs) 114 if err2 != nil { 115 t.Fatal(err2) 116 return 117 } 118 t.Log(*port) 119 if port.Fn != nil { 120 t.Log("function attributes = ", *port.Fn) 121 } 122 macAttr := DevlinkPortFnSetAttrs{ 123 FnAttrs: DevlinkPortFn{ 124 HwAddr: net.HardwareAddr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}, 125 }, 126 HwAddrValid: true, 127 } 128 err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, macAttr) 129 if err2 != nil { 130 t.Log("function mac set err = ", err2) 131 } 132 stateAttr.FnAttrs.State = 1 133 stateAttr.StateValid = true 134 err2 = DevlinkPortFnSet(dev.BusName, dev.DeviceName, port.PortIndex, stateAttr) 135 if err2 != nil { 136 t.Log("function state set err = ", err2) 137 } 138 139 port, err3 := DevLinkGetPortByIndex(dev.BusName, dev.DeviceName, port.PortIndex) 140 if err3 == nil { 141 t.Log(*port) 142 t.Log(*port.Fn) 143 } 144 err2 = DevLinkPortDel(dev.BusName, dev.DeviceName, port.PortIndex) 145 if err2 != nil { 146 t.Fatal(err2) 147 } 148 } 149 150 var bus string 151 var device string 152 var sfnum uint 153 154 func init() { 155 flag.StringVar(&bus, "bus", "", "devlink device bus name") 156 flag.StringVar(&device, "device", "", "devlink device devicename") 157 flag.UintVar(&sfnum, "sfnum", 0, "devlink port sfnumber") 158 } 159 160 func TestDevlinkGetDeviceInfoByNameAsMap(t *testing.T) { 161 info, err := pkgHandle.DevlinkGetDeviceInfoByNameAsMap("pci", "0000:00:00.0", mockDevlinkInfoGetter) 162 if err != nil { 163 t.Fatal(err) 164 } 165 testInfo := devlinkTestInfoParesd() 166 for k, v := range info { 167 if testInfo[k] != v { 168 t.Fatal("Value", v, "retrieved for key", k, "is not equal to", testInfo[k]) 169 } 170 } 171 } 172 173 func TestDevlinkGetDeviceInfoByName(t *testing.T) { 174 info, err := pkgHandle.DevlinkGetDeviceInfoByName("pci", "0000:00:00.0", mockDevlinkInfoGetter) 175 if err != nil { 176 t.Fatal(err) 177 } 178 testInfo := parseInfoData(devlinkTestInfoParesd()) 179 if !areInfoStructsEqual(info, testInfo) { 180 t.Fatal("Info structures are not equal") 181 } 182 } 183 184 func TestDevlinkGetDeviceInfoByNameAsMapFail(t *testing.T) { 185 _, err := pkgHandle.DevlinkGetDeviceInfoByNameAsMap("pci", "0000:00:00.0", mockDevlinkInfoGetterEmpty) 186 if err == nil { 187 t.Fatal() 188 } 189 } 190 191 func TestDevlinkGetDeviceInfoByNameFail(t *testing.T) { 192 _, err := pkgHandle.DevlinkGetDeviceInfoByName("pci", "0000:00:00.0", mockDevlinkInfoGetterEmpty) 193 if err == nil { 194 t.Fatal() 195 } 196 } 197 198 func mockDevlinkInfoGetter(bus, device string) ([]byte, error) { 199 return devlinkInfo(), nil 200 } 201 202 func mockDevlinkInfoGetterEmpty(bus, device string) ([]byte, error) { 203 return []byte{}, nil 204 } 205 206 func devlinkInfo() []byte { 207 return []byte{51, 1, 0, 0, 8, 0, 1, 0, 112, 99, 105, 0, 17, 0, 2, 0, 48, 208 48, 48, 48, 58, 56, 52, 58, 48, 48, 46, 48, 0, 0, 0, 0, 8, 0, 98, 0, 209 105, 99, 101, 0, 28, 0, 99, 0, 51, 48, 45, 56, 57, 45, 97, 51, 45, 210 102, 102, 45, 102, 102, 45, 99, 97, 45, 48, 53, 45, 54, 56, 0, 36, 211 0, 100, 0, 13, 0, 103, 0, 98, 111, 97, 114, 100, 46, 105, 100, 0, 0, 212 0, 0, 15, 0, 104, 0, 75, 56, 53, 53, 56, 53, 45, 48, 48, 48, 0, 0, 213 28, 0, 101, 0, 12, 0, 103, 0, 102, 119, 46, 109, 103, 109, 116, 0, 214 10, 0, 104, 0, 53, 46, 52, 46, 53, 0, 0, 0, 28, 0, 101, 0, 16, 0, 215 103, 0, 102, 119, 46, 109, 103, 109, 116, 46, 97, 112, 105, 0, 8, 0, 216 104, 0, 49, 46, 55, 0, 40, 0, 101, 0, 18, 0, 103, 0, 102, 119, 46, 217 109, 103, 109, 116, 46, 98, 117, 105, 108, 100, 0, 0, 0, 15, 0, 104, 218 0, 48, 120, 51, 57, 49, 102, 55, 54, 52, 48, 0, 0, 32, 0, 101, 0, 219 12, 0, 103, 0, 102, 119, 46, 117, 110, 100, 105, 0, 13, 0, 104, 0, 220 49, 46, 50, 56, 57, 56, 46, 48, 0, 0, 0, 0, 32, 0, 101, 0, 16, 0, 221 103, 0, 102, 119, 46, 112, 115, 105, 100, 46, 97, 112, 105, 0, 9, 0, 222 104, 0, 50, 46, 52, 50, 0, 0, 0, 0, 40, 0, 101, 0, 17, 0, 103, 0, 223 102, 119, 46, 98, 117, 110, 100, 108, 101, 95, 105, 100, 0, 0, 0, 0, 224 15, 0, 104, 0, 48, 120, 56, 48, 48, 48, 55, 48, 54, 98, 0, 0, 48, 0, 225 101, 0, 16, 0, 103, 0, 102, 119, 46, 97, 112, 112, 46, 110, 97, 109, 226 101, 0, 27, 0, 104, 0, 73, 67, 69, 32, 79, 83, 32, 68, 101, 102, 97, 227 117, 108, 116, 32, 80, 97, 99, 107, 97, 103, 101, 0, 0, 32, 0, 101, 228 0, 11, 0, 103, 0, 102, 119, 46, 97, 112, 112, 0, 0, 13, 0, 104, 0, 229 49, 46, 51, 46, 50, 52, 46, 48, 0, 0, 0, 0, 44, 0, 101, 0, 21, 0, 230 103, 0, 102, 119, 46, 97, 112, 112, 46, 98, 117, 110, 100, 108, 231 101, 95, 105, 100, 0, 0, 0, 0, 15, 0, 104, 0, 48, 120, 99, 48, 48, 232 48, 48, 48, 48, 49, 0, 0, 44, 0, 101, 0, 15, 0, 103, 0, 102, 119, 233 46, 110, 101, 116, 108, 105, 115, 116, 0, 0, 21, 0, 104, 0, 50, 46, 234 52, 48, 46, 50, 48, 48, 48, 45, 51, 46, 49, 54, 46, 48, 0, 0, 0, 0, 235 44, 0, 101, 0, 21, 0, 103, 0, 102, 119, 46, 110, 101, 116, 108, 105, 236 115, 116, 46, 98, 117, 105, 108, 100, 0, 0, 0, 0, 15, 0, 104, 0, 48, 237 120, 54, 55, 54, 97, 52, 56, 57, 100, 0, 0} 238 } 239 240 func devlinkTestInfoParesd() map[string]string { 241 return map[string]string{ 242 "board.id": "K85585-000", 243 "fw.app": "1.3.24.0", 244 "fw.app.bundle_id": "0xc0000001", 245 "fw.app.name": "ICE OS Default Package", 246 "fw.bundle_id": "0x8000706b", 247 "fw.mgmt": "5.4.5", 248 "fw.mgmt.api": "1.7", 249 "fw.mgmt.build": "0x391f7640", 250 "fw.netlist": "2.40.2000-3.16.0", 251 "fw.netlist.build": "0x676a489d", 252 "fw.psid.api": "2.42", 253 "fw.undi": "1.2898.0", 254 "driver": "ice", 255 "serialNumber": "30-89-a3-ff-ff-ca-05-68", 256 } 257 } 258 259 func areInfoStructsEqual(first *DevlinkDeviceInfo, second *DevlinkDeviceInfo) bool { 260 if first.FwApp != second.FwApp || first.FwAppBoundleID != second.FwAppBoundleID || 261 first.FwAppName != second.FwAppName || first.FwBoundleID != second.FwBoundleID || 262 first.FwMgmt != second.FwMgmt || first.FwMgmtAPI != second.FwMgmtAPI || 263 first.FwMgmtBuild != second.FwMgmtBuild || first.FwNetlist != second.FwNetlist || 264 first.FwNetlistBuild != second.FwNetlistBuild || first.FwPsidAPI != second.FwPsidAPI || 265 first.BoardID != second.BoardID || first.FwUndi != second.FwUndi || 266 first.Driver != second.Driver || first.SerialNumber != second.SerialNumber { 267 return false 268 } 269 return true 270 } 271 272 func TestDevlinkGetDeviceResources(t *testing.T) { 273 minKernelRequired(t, 5, 11) 274 tearDown := setUpNetlinkTestWithKModule(t, "devlink") 275 defer tearDown() 276 277 if bus == "" || device == "" { 278 //TODO: setup netdevsim device instead of getting device from flags 279 t.Log("devlink bus and device are empty, skipping test") 280 t.SkipNow() 281 } 282 283 res, err := DevlinkGetDeviceResources(bus, device) 284 if err != nil { 285 t.Fatalf("failed to get device(%s/%s) resources. %s", bus, device, err) 286 } 287 288 if res.Bus != bus || res.Device != device { 289 t.Fatalf("missmatching bus/device") 290 } 291 292 t.Logf("Resources: %+v", res) 293 } 294 295 // devlink device parameters can be tested with netdevsim 296 // function will create netdevsim/netdevsim<random_id> virtual device that can be used for testing 297 // netdevsim module should be loaded to run devlink param tests 298 func setupDevlinkDeviceParamTest(t *testing.T) (string, string, func()) { 299 t.Helper() 300 skipUnlessRoot(t) 301 skipUnlessKModuleLoaded(t, "netdevsim") 302 testDevID := strconv.Itoa(1000 + rand.Intn(1000)) 303 err := os.WriteFile("/sys/bus/netdevsim/new_device", []byte(testDevID), 0755) 304 if err != nil { 305 t.Fatalf("can't create netdevsim test device %s: %v", testDevID, err) 306 } 307 308 return "netdevsim", "netdevsim" + testDevID, func() { 309 _ = os.WriteFile("/sys/bus/netdevsim/del_device", []byte(testDevID), 0755) 310 } 311 } 312 313 func TestDevlinkGetDeviceParams(t *testing.T) { 314 busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t) 315 defer cleanupFunc() 316 params, err := DevlinkGetDeviceParams(busName, deviceName) 317 if err != nil { 318 t.Fatalf("failed to get device(%s/%s) parameters. %s", busName, deviceName, err) 319 } 320 if len(params) == 0 { 321 t.Fatal("parameters list is empty") 322 } 323 for _, p := range params { 324 validateDeviceParams(t, p) 325 } 326 } 327 328 func TestDevlinkGetDeviceParamByName(t *testing.T) { 329 busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t) 330 defer cleanupFunc() 331 param, err := DevlinkGetDeviceParamByName(busName, deviceName, "max_macs") 332 if err != nil { 333 t.Fatalf("failed to get device(%s/%s) parameter max_macs. %s", busName, deviceName, err) 334 } 335 validateDeviceParams(t, param) 336 } 337 338 func TestDevlinkSetDeviceParam(t *testing.T) { 339 busName, deviceName, cleanupFunc := setupDevlinkDeviceParamTest(t) 340 defer cleanupFunc() 341 err := DevlinkSetDeviceParam(busName, deviceName, "max_macs", nl.DEVLINK_PARAM_CMODE_DRIVERINIT, uint32(8)) 342 if err != nil { 343 t.Fatalf("failed to set max_macs for device(%s/%s): %s", busName, deviceName, err) 344 } 345 param, err := DevlinkGetDeviceParamByName(busName, deviceName, "max_macs") 346 if err != nil { 347 t.Fatalf("failed to get device(%s/%s) parameter max_macs. %s", busName, deviceName, err) 348 } 349 validateDeviceParams(t, param) 350 v, ok := param.Values[0].Data.(uint32) 351 if !ok { 352 t.Fatalf("unexpected value") 353 } 354 if v != uint32(8) { 355 t.Fatalf("value not set") 356 } 357 } 358 359 func validateDeviceParams(t *testing.T, p *DevlinkParam) { 360 if p.Name == "" { 361 t.Fatal("Name field not set") 362 } 363 if p.Name == "max_macs" && !p.IsGeneric { 364 t.Fatal("IsGeneric should be true for generic parameter") 365 } 366 // test1 is a driver-specific parameter in netdevsim device, check should 367 // also path on HW devices 368 if p.Name == "test1" && p.IsGeneric { 369 t.Fatal("IsGeneric should be false for driver-specific parameter") 370 } 371 switch p.Type { 372 case nl.DEVLINK_PARAM_TYPE_U8, 373 nl.DEVLINK_PARAM_TYPE_U16, 374 nl.DEVLINK_PARAM_TYPE_U32, 375 nl.DEVLINK_PARAM_TYPE_STRING, 376 nl.DEVLINK_PARAM_TYPE_BOOL: 377 default: 378 t.Fatal("Type has unexpected value") 379 } 380 if len(p.Values) == 0 { 381 t.Fatal("Values are not set") 382 } 383 for _, v := range p.Values { 384 switch v.CMODE { 385 case nl.DEVLINK_PARAM_CMODE_RUNTIME, 386 nl.DEVLINK_PARAM_CMODE_DRIVERINIT, 387 nl.DEVLINK_PARAM_CMODE_PERMANENT: 388 default: 389 t.Fatal("CMODE has unexpected value") 390 } 391 if p.Name == "max_macs" { 392 _, ok := v.Data.(uint32) 393 if !ok { 394 t.Fatalf("value max_macs has wrong type: %T, expected: uint32", v.Data) 395 } 396 } 397 if p.Name == "test1" { 398 _, ok := v.Data.(bool) 399 if !ok { 400 t.Fatalf("value test1 has wrong type: %T, expected: bool", v.Data) 401 } 402 } 403 } 404 }