xref: /spdk/test/nvme/connect_stress/connect_stress.c (revision dbcc38f096e5336dcc4ab5e60b10202db51c0a38)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2021 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/env.h"
9 #include "spdk/nvme.h"
10 #include "spdk/string.h"
11 #include "spdk/util.h"
12 #include "spdk/log.h"
13 #include "spdk/likely.h"
14 #include "spdk/sock.h"
15 
16 static int g_time_in_sec;
17 
18 static struct spdk_nvme_transport_id g_trid;
19 
20 static void
21 usage(char *program_name)
22 {
23 	printf("%s options", program_name);
24 	printf("\n");
25 	printf("\t[-t, --time <sec> time in seconds]\n");
26 	printf("\t[-c, --core-mask <mask>]\n");
27 	printf("\t\t(default: 1)\n");
28 	printf("\t[-r, --transport <fmt> Transport ID for local PCIe NVMe or NVMeoF]\n");
29 	printf("\t Format: 'key:value [key:value] ...'\n");
30 	printf("\t Keys:\n");
31 	printf("\t  trtype      Transport type (e.g. PCIe, RDMA)\n");
32 	printf("\t  adrfam      Address family (e.g. IPv4, IPv6)\n");
33 	printf("\t  traddr      Transport address (e.g. 0000:04:00.0 for PCIe or 192.168.100.8 for RDMA)\n");
34 	printf("\t  trsvcid     Transport service identifier (e.g. 4420)\n");
35 	printf("\t  subnqn      Subsystem NQN\n");
36 	printf("\t Example: -r 'trtype:PCIe traddr:0000:04:00.0' for PCIe or\n");
37 	printf("\t          -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420' for NVMeoF\n");
38 	printf("\t[-s, --hugemem-size <MB> DPDK huge memory size in MB.]\n");
39 	printf("\t\t(default: 0 - unlimited)\n");
40 	printf("\t[-i, --shmem-grp-id <id> shared memory group ID]\n");
41 	printf("\t");
42 	spdk_log_usage(stdout, "-T");
43 	printf("\t[-S, --default-sock-impl <impl> set the default sock impl, e.g. \"posix\"]\n");
44 #ifdef DEBUG
45 	printf("\t[-G, --enable-debug enable debug logging]\n");
46 #else
47 	printf("\t[-G, --enable-debug enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
48 	printf("\t[--iova-mode <mode> specify DPDK IOVA mode: va|pa]\n");
49 	printf("\t[--no-huge, SPDK is run without hugepages\n");
50 #endif
51 }
52 
53 static int
54 add_trid(const char *trid_str)
55 {
56 	g_trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
57 	snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
58 
59 	if (spdk_nvme_transport_id_parse(&g_trid, trid_str) != 0) {
60 		fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str);
61 		return 1;
62 	}
63 
64 	spdk_nvme_transport_id_populate_trstring(&g_trid,
65 			spdk_nvme_transport_id_trtype_str(g_trid.trtype));
66 
67 	return 0;
68 }
69 
70 #define PERF_GETOPT_SHORT "c:i:r:s:t:GS:T:"
71 
72 static const struct option g_cmdline_opts[] = {
73 #define PERF_CORE_MASK	'c'
74 	{"core-mask",			required_argument,	NULL, PERF_CORE_MASK},
75 #define PERF_SHMEM_GROUP_ID	'i'
76 	{"shmem-grp-id",		required_argument,	NULL, PERF_SHMEM_GROUP_ID},
77 #define PERF_TRANSPORT	'r'
78 	{"transport",			required_argument,	NULL, PERF_TRANSPORT},
79 #define PERF_HUGEMEM_SIZE	's'
80 	{"hugemem-size",		required_argument,	NULL, PERF_HUGEMEM_SIZE},
81 #define PERF_TIME	't'
82 	{"time",			required_argument,	NULL, PERF_TIME},
83 #define PERF_ENABLE_DEBUG	'G'
84 	{"enable-debug",		no_argument,		NULL, PERF_ENABLE_DEBUG},
85 #define PERF_DEFAULT_SOCK_IMPL	'S'
86 	{"default-sock-impl",		required_argument,	NULL, PERF_DEFAULT_SOCK_IMPL},
87 #define PERF_LOG_FLAG	'T'
88 	{"logflag",			required_argument,	NULL, PERF_LOG_FLAG},
89 #define PERF_IOVA_MODE		258
90 	{"iova-mode",			required_argument,	NULL, PERF_IOVA_MODE},
91 #define PERF_NO_HUGE		259
92 	{"no-huge",		no_argument,		NULL, PERF_NO_HUGE},
93 	/* Should be the last element */
94 	{0, 0, 0, 0}
95 };
96 
97 static int
98 parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
99 {
100 	bool trid_set = false;
101 	int op, long_idx;
102 	long int val;
103 	int rc;
104 
105 	while ((op = getopt_long(argc, argv, PERF_GETOPT_SHORT, g_cmdline_opts, &long_idx)) != -1) {
106 		switch (op) {
107 		case PERF_SHMEM_GROUP_ID:
108 		case PERF_HUGEMEM_SIZE:
109 		case PERF_TIME:
110 			val = spdk_strtol(optarg, 10);
111 			if (val < 0) {
112 				fprintf(stderr, "Converting a string to integer failed\n");
113 				return val;
114 			}
115 			switch (op) {
116 			case PERF_SHMEM_GROUP_ID:
117 				env_opts->shm_id = val;
118 				break;
119 			case PERF_HUGEMEM_SIZE:
120 				env_opts->mem_size = val;
121 				break;
122 			case PERF_TIME:
123 				g_time_in_sec = val;
124 				break;
125 			}
126 			break;
127 		case PERF_CORE_MASK:
128 			env_opts->core_mask = optarg;
129 			break;
130 		case PERF_TRANSPORT:
131 			if (trid_set) {
132 				fprintf(stderr, "Only one trid can be specified\n");
133 				usage(argv[0]);
134 				return 1;
135 			}
136 			trid_set = true;
137 			if (add_trid(optarg)) {
138 				usage(argv[0]);
139 				return 1;
140 			}
141 			break;
142 		case PERF_ENABLE_DEBUG:
143 #ifndef DEBUG
144 			fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n",
145 				argv[0]);
146 			usage(argv[0]);
147 			return 1;
148 #else
149 			spdk_log_set_flag("nvme");
150 			spdk_log_set_print_level(SPDK_LOG_DEBUG);
151 			break;
152 #endif
153 		case PERF_LOG_FLAG:
154 			rc = spdk_log_set_flag(optarg);
155 			if (rc < 0) {
156 				fprintf(stderr, "unknown flag\n");
157 				usage(argv[0]);
158 				exit(EXIT_FAILURE);
159 			}
160 #ifdef DEBUG
161 			spdk_log_set_print_level(SPDK_LOG_DEBUG);
162 #endif
163 			break;
164 		case PERF_DEFAULT_SOCK_IMPL:
165 			rc = spdk_sock_set_default_impl(optarg);
166 			if (rc) {
167 				fprintf(stderr, "Failed to set sock impl %s, err %d (%s)\n", optarg, errno, strerror(errno));
168 				return 1;
169 			}
170 			break;
171 		case PERF_IOVA_MODE:
172 			env_opts->iova_mode = optarg;
173 			break;
174 		case PERF_NO_HUGE:
175 			env_opts->no_huge = true;
176 			break;
177 		default:
178 			usage(argv[0]);
179 			return 1;
180 		}
181 	}
182 
183 	if (!g_time_in_sec) {
184 		fprintf(stderr, "missing -t (--time) operand\n");
185 		usage(argv[0]);
186 		return 1;
187 	}
188 
189 	if (!trid_set) {
190 		fprintf(stderr, "missing -r operand\n");
191 		usage(argv[0]);
192 		return 1;
193 	}
194 
195 	env_opts->no_pci = true;
196 	if (g_trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
197 		env_opts->no_pci = false;
198 	}
199 
200 	return 0;
201 }
202 
203 static int
204 test_controller(void)
205 {
206 	const int LOOP_COUNT = 5;
207 	struct spdk_nvme_qpair *qpair[LOOP_COUNT];
208 	union spdk_nvme_csts_register csts;
209 	struct spdk_nvme_ctrlr *ctrlr;
210 
211 	ctrlr = spdk_nvme_connect(&g_trid, NULL, 0);
212 	if (ctrlr == NULL) {
213 		fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n",
214 			g_trid.traddr);
215 		return -1;
216 	}
217 	if (spdk_nvme_ctrlr_is_discovery(ctrlr)) {
218 		fprintf(stderr, "discovery controller not allowed for this test\n");
219 		spdk_nvme_detach(ctrlr);
220 		return -1;
221 	}
222 
223 	for (int i = 0; i < LOOP_COUNT; i++) {
224 		csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr);
225 		if (csts.raw == 0xFFFFFFFF) {
226 			fprintf(stderr, "could not read csts\n");
227 			spdk_nvme_detach(ctrlr);
228 			return -1;
229 		}
230 		qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
231 		if (qpair[i] == NULL) {
232 			fprintf(stderr, "could not allocate io qpair\n");
233 			spdk_nvme_detach(ctrlr);
234 			return -1;
235 		}
236 	}
237 	for (int i = 0; i < LOOP_COUNT; i++) {
238 		spdk_nvme_ctrlr_free_io_qpair(qpair[i]);
239 	}
240 
241 	spdk_nvme_detach(ctrlr);
242 
243 	return 0;
244 }
245 
246 int
247 main(int argc, char **argv)
248 {
249 	struct spdk_env_opts opts;
250 	uint64_t tsc_end;
251 	int rc;
252 
253 	spdk_env_opts_init(&opts);
254 	opts.name = "connect_stress";
255 	rc = parse_args(argc, argv, &opts);
256 	if (rc != 0) {
257 		return rc;
258 	}
259 	if (spdk_env_init(&opts) < 0) {
260 		fprintf(stderr, "Unable to initialize SPDK env\n");
261 		return -1;
262 	}
263 
264 	if (g_trid.trtype != SPDK_NVME_TRANSPORT_PCIE) {
265 		printf("Testing NVMe over Fabrics controller at %s:%s: %s\n",
266 		       g_trid.traddr, g_trid.trsvcid,
267 		       g_trid.subnqn);
268 	} else {
269 		printf("Testing NVMe PCI controller at %s\n", g_trid.traddr);
270 	}
271 
272 	tsc_end = spdk_get_ticks() + g_time_in_sec * spdk_get_ticks_hz();
273 	while (spdk_get_ticks() < tsc_end && rc == 0) {
274 		rc = test_controller();
275 	}
276 
277 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
278 }
279