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