1a4975cd2SXueming Li /* SPDX-License-Identifier: BSD-3-Clause 2a4975cd2SXueming Li * Copyright (c) 2021 NVIDIA Corporation & Affiliates 3a4975cd2SXueming Li */ 4a4975cd2SXueming Li 5a4975cd2SXueming Li #include <stdlib.h> 6a4975cd2SXueming Li #include <stdio.h> 7a4975cd2SXueming Li #include <string.h> 8a4975cd2SXueming Li 9a4975cd2SXueming Li #include <rte_common.h> 10a4975cd2SXueming Li #include <rte_devargs.h> 11a4975cd2SXueming Li #include <rte_kvargs.h> 12a4975cd2SXueming Li #include <rte_bus.h> 13a4975cd2SXueming Li #include <rte_class.h> 14a4975cd2SXueming Li 15a4975cd2SXueming Li #include "test.h" 16a4975cd2SXueming Li 17a4975cd2SXueming Li /* Check layer arguments. */ 18a4975cd2SXueming Li static int 19a4975cd2SXueming Li test_args(const char *devargs, const char *layer, const char *args, const int n) 20a4975cd2SXueming Li { 21a4975cd2SXueming Li struct rte_kvargs *kvlist; 22a4975cd2SXueming Li 23a4975cd2SXueming Li if (n == 0) { 24a4975cd2SXueming Li if (args != NULL && strlen(args) > 0) { 25a4975cd2SXueming Li printf("rte_devargs_parse(%s) %s args parsed (not expected)\n", 26a4975cd2SXueming Li devargs, layer); 27a4975cd2SXueming Li return -1; 28a4975cd2SXueming Li } else { 29a4975cd2SXueming Li return 0; 30a4975cd2SXueming Li } 31a4975cd2SXueming Li } 32a4975cd2SXueming Li if (args == NULL) { 33a4975cd2SXueming Li printf("rte_devargs_parse(%s) %s args not parsed\n", 34a4975cd2SXueming Li devargs, layer); 35a4975cd2SXueming Li return -1; 36a4975cd2SXueming Li } 37a4975cd2SXueming Li kvlist = rte_kvargs_parse(args, NULL); 38a4975cd2SXueming Li if (kvlist == NULL) { 39a4975cd2SXueming Li printf("rte_devargs_parse(%s) %s_str: %s not parsed\n", 40a4975cd2SXueming Li devargs, layer, args); 41a4975cd2SXueming Li return -1; 42a4975cd2SXueming Li } 43a4975cd2SXueming Li if ((int)kvlist->count != n) { 44a4975cd2SXueming Li printf("rte_devargs_parse(%s) %s_str: %s kv number %u, not %d\n", 45a4975cd2SXueming Li devargs, layer, args, kvlist->count, n); 46d05c2dccSXueming Li rte_kvargs_free(kvlist); 47a4975cd2SXueming Li return -1; 48a4975cd2SXueming Li } 49d05c2dccSXueming Li rte_kvargs_free(kvlist); 50a4975cd2SXueming Li return 0; 51a4975cd2SXueming Li } 52a4975cd2SXueming Li 53a4975cd2SXueming Li struct devargs_case { 54a4975cd2SXueming Li const char *devargs; 55a4975cd2SXueming Li int bus_kv; 56a4975cd2SXueming Li int class_kv; 57a4975cd2SXueming Li int driver_kv; 58a4975cd2SXueming Li const char *bus; 59a4975cd2SXueming Li const char *name; 60a4975cd2SXueming Li const char *class; 61a4975cd2SXueming Li }; 62a4975cd2SXueming Li 63a4975cd2SXueming Li static int 64a4975cd2SXueming Li test_valid_devargs_cases(const struct devargs_case *list, size_t n) 65a4975cd2SXueming Li { 66a4975cd2SXueming Li struct rte_devargs da; 67a4975cd2SXueming Li uint32_t i; 68a4975cd2SXueming Li int ret; 69a4975cd2SXueming Li int fail = TEST_SUCCESS; 70a4975cd2SXueming Li struct rte_bus *pci_bus = rte_bus_find_by_name("pci"); 71a4975cd2SXueming Li struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev"); 72a4975cd2SXueming Li struct rte_class *eth_class = rte_class_find_by_name("eth"); 73a4975cd2SXueming Li 74a4975cd2SXueming Li for (i = 0; i < n; i++) { 75a4975cd2SXueming Li if (pci_bus == NULL && list[i].bus != NULL && 76a4975cd2SXueming Li strcmp(list[i].bus, "pci") == 0) 77a4975cd2SXueming Li continue; 78a4975cd2SXueming Li if (vdev_bus == NULL && list[i].bus != NULL && 79a4975cd2SXueming Li strcmp(list[i].bus, "vdev") == 0) 80a4975cd2SXueming Li continue; 81a4975cd2SXueming Li if (eth_class == NULL && list[i].class != NULL && 82a4975cd2SXueming Li strcmp(list[i].class, "eth") == 0) 83a4975cd2SXueming Li continue; 84a4975cd2SXueming Li memset(&da, 0, sizeof(da)); 85a4975cd2SXueming Li ret = rte_devargs_parse(&da, list[i].devargs); 86a4975cd2SXueming Li if (ret < 0) { 87a4975cd2SXueming Li printf("rte_devargs_parse(%s) returned %d (but should not)\n", 88a4975cd2SXueming Li list[i].devargs, ret); 89a4975cd2SXueming Li goto fail; 90a4975cd2SXueming Li } 91a4975cd2SXueming Li if ((list[i].bus_kv > 0 || list[i].bus != NULL) && 92a4975cd2SXueming Li da.bus == NULL) { 93a4975cd2SXueming Li printf("rte_devargs_parse(%s) bus not parsed\n", 94a4975cd2SXueming Li list[i].devargs); 95a4975cd2SXueming Li goto fail; 96a4975cd2SXueming Li } 97a4975cd2SXueming Li if (test_args(list[i].devargs, "bus", da.bus_str, 98a4975cd2SXueming Li list[i].bus_kv) != 0) 99a4975cd2SXueming Li goto fail; 100a4975cd2SXueming Li if (list[i].bus != NULL && 101*148c51a3SDavid Marchand strcmp(rte_bus_name(da.bus), list[i].bus) != 0) { 102a4975cd2SXueming Li printf("rte_devargs_parse(%s) bus name (%s) not expected (%s)\n", 103*148c51a3SDavid Marchand list[i].devargs, rte_bus_name(da.bus), list[i].bus); 104a4975cd2SXueming Li goto fail; 105a4975cd2SXueming Li } 106a4975cd2SXueming Li if ((list[i].class_kv > 0 || list[i].class != NULL) && 107a4975cd2SXueming Li da.cls == NULL) { 108a4975cd2SXueming Li printf("rte_devargs_parse(%s) class not parsed\n", 109a4975cd2SXueming Li list[i].devargs); 110a4975cd2SXueming Li goto fail; 111a4975cd2SXueming Li } 112a4975cd2SXueming Li if (test_args(list[i].devargs, "class", da.cls_str, 113a4975cd2SXueming Li list[i].class_kv) != 0) 114a4975cd2SXueming Li goto fail; 115a4975cd2SXueming Li if (list[i].class != NULL && 116a4975cd2SXueming Li strcmp(da.cls->name, list[i].class) != 0) { 117a4975cd2SXueming Li printf("rte_devargs_parse(%s) class name (%s) not expected (%s)\n", 118a4975cd2SXueming Li list[i].devargs, da.cls->name, list[i].class); 119a4975cd2SXueming Li goto fail; 120a4975cd2SXueming Li } 121a4975cd2SXueming Li if (test_args(list[i].devargs, "driver", da.drv_str, 122a4975cd2SXueming Li list[i].driver_kv) != 0) 123a4975cd2SXueming Li goto fail; 124a4975cd2SXueming Li if (list[i].name != NULL && 125a4975cd2SXueming Li strcmp(da.name, list[i].name) != 0) { 126a4975cd2SXueming Li printf("rte_devargs_parse(%s) device name (%s) not expected (%s)\n", 127a4975cd2SXueming Li list[i].devargs, da.name, list[i].name); 128a4975cd2SXueming Li goto fail; 129a4975cd2SXueming Li } 130a4975cd2SXueming Li goto cleanup; 131a4975cd2SXueming Li fail: 132a4975cd2SXueming Li fail = TEST_FAILED; 133a4975cd2SXueming Li cleanup: 134a4975cd2SXueming Li rte_devargs_reset(&da); 135a4975cd2SXueming Li } 136a4975cd2SXueming Li return fail; 137a4975cd2SXueming Li } 138a4975cd2SXueming Li 139a4975cd2SXueming Li /* Test several valid cases */ 140a4975cd2SXueming Li static int 141a4975cd2SXueming Li test_valid_devargs(void) 142a4975cd2SXueming Li { 143a4975cd2SXueming Li static const struct devargs_case list[] = { 144a4975cd2SXueming Li /* Global devargs syntax: */ 145a4975cd2SXueming Li { "bus=pci", 146a4975cd2SXueming Li 1, 0, 0, "pci", NULL, NULL}, 147a4975cd2SXueming Li { "class=eth", 148a4975cd2SXueming Li 0, 1, 0, NULL, NULL, "eth" }, 149a4975cd2SXueming Li { "bus=pci,addr=1:2.3/class=eth/driver=abc,k0=v0", 150a4975cd2SXueming Li 2, 1, 2, "pci", "0000:01:02.3", "eth" }, 151a4975cd2SXueming Li { "bus=vdev,name=/dev/file/name/class=eth", 152a4975cd2SXueming Li 2, 1, 0, "vdev", "/dev/file/name", "eth" }, 153a4975cd2SXueming Li { "bus=vdev,name=/class/bus/path/class=eth", 154a4975cd2SXueming Li 2, 1, 0, "vdev", "/class/bus/path", "eth" }, 155a4975cd2SXueming Li { "bus=vdev,name=///dblslsh/class=eth", 156a4975cd2SXueming Li 2, 1, 0, "vdev", "///dblslsh", "eth" }, 157a4975cd2SXueming Li /* Legacy devargs syntax: */ 158a4975cd2SXueming Li { "1:2.3", 0, 0, 0, 159a4975cd2SXueming Li "pci", "1:2.3", NULL }, 160a4975cd2SXueming Li { "pci:1:2.3,k0=v0", 161a4975cd2SXueming Li 0, 0, 1, "pci", "1:2.3", NULL }, 162a4975cd2SXueming Li }; 163a4975cd2SXueming Li static const struct devargs_case legacy_ring_list[] = { 164a4975cd2SXueming Li { "net_ring0", 165a4975cd2SXueming Li 0, 0, 0, "vdev", "net_ring0", NULL }, 166a4975cd2SXueming Li { "net_ring0,iface=test,path=/class/bus/,queues=1", 167a4975cd2SXueming Li 0, 0, 3, "vdev", "net_ring0", NULL }, 168a4975cd2SXueming Li }; 169a4975cd2SXueming Li struct rte_bus *vdev_bus = rte_bus_find_by_name("vdev"); 170a4975cd2SXueming Li int ret; 171a4975cd2SXueming Li 172a4975cd2SXueming Li ret = test_valid_devargs_cases(list, RTE_DIM(list)); 173a4975cd2SXueming Li if (vdev_bus != NULL && vdev_bus->parse("net_ring0", NULL) == 0) 174a4975cd2SXueming Li /* Ring vdev driver enabled. */ 175a4975cd2SXueming Li ret |= test_valid_devargs_cases(legacy_ring_list, 176a4975cd2SXueming Li RTE_DIM(legacy_ring_list)); 177a4975cd2SXueming Li return ret; 178a4975cd2SXueming Li } 179a4975cd2SXueming Li 180a4975cd2SXueming Li /* Test several invalid cases */ 181a4975cd2SXueming Li static int 182a4975cd2SXueming Li test_invalid_devargs(void) 183a4975cd2SXueming Li { 184a4975cd2SXueming Li static const char * const list[] = { 185a4975cd2SXueming Li "bus=wrong-bus", 186a4975cd2SXueming Li "class=wrong-class"}; 187a4975cd2SXueming Li struct rte_devargs da; 188a4975cd2SXueming Li uint32_t i; 189a4975cd2SXueming Li int ret; 190a4975cd2SXueming Li int fail = 0; 191a4975cd2SXueming Li 192a4975cd2SXueming Li for (i = 0; i < RTE_DIM(list); i++) { 193a4975cd2SXueming Li ret = rte_devargs_parse(&da, list[i]); 194a4975cd2SXueming Li if (ret >= 0) { 195a4975cd2SXueming Li printf("rte_devargs_parse(%s) returned %d (but should not)\n", 196a4975cd2SXueming Li list[i], ret); 197a4975cd2SXueming Li fail = ret; 198a4975cd2SXueming Li } 199a4975cd2SXueming Li rte_devargs_reset(&da); 200a4975cd2SXueming Li } 201a4975cd2SXueming Li return fail; 202a4975cd2SXueming Li } 203a4975cd2SXueming Li 204a4975cd2SXueming Li static int 205a4975cd2SXueming Li test_devargs(void) 206a4975cd2SXueming Li { 207a4975cd2SXueming Li printf("== test valid case ==\n"); 208a4975cd2SXueming Li if (test_valid_devargs() < 0) 209a4975cd2SXueming Li return -1; 210a4975cd2SXueming Li printf("== test invalid case ==\n"); 211a4975cd2SXueming Li if (test_invalid_devargs() < 0) 212a4975cd2SXueming Li return -1; 213a4975cd2SXueming Li return 0; 214a4975cd2SXueming Li } 215a4975cd2SXueming Li 216a4975cd2SXueming Li REGISTER_TEST_COMMAND(devargs_autotest, test_devargs); 217