xref: /spdk/test/nvme/connect_stress/connect_stress.c (revision cdb0726b95631d46eaf4f2e39ddb6533f150fd27)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (c) 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 #endif
50 }
51 
52 static int
53 add_trid(const char *trid_str)
54 {
55 	g_trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
56 	snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
57 
58 	if (spdk_nvme_transport_id_parse(&g_trid, trid_str) != 0) {
59 		fprintf(stderr, "Invalid transport ID format '%s'\n", trid_str);
60 		return 1;
61 	}
62 
63 	spdk_nvme_transport_id_populate_trstring(&g_trid,
64 			spdk_nvme_transport_id_trtype_str(g_trid.trtype));
65 
66 	return 0;
67 }
68 
69 #define PERF_GETOPT_SHORT "c:i:r:s:t:GS:T:"
70 
71 static const struct option g_cmdline_opts[] = {
72 #define PERF_CORE_MASK	'c'
73 	{"core-mask",			required_argument,	NULL, PERF_CORE_MASK},
74 #define PERF_SHMEM_GROUP_ID	'i'
75 	{"shmem-grp-id",		required_argument,	NULL, PERF_SHMEM_GROUP_ID},
76 #define PERF_TRANSPORT	'r'
77 	{"transport",			required_argument,	NULL, PERF_TRANSPORT},
78 #define PERF_HUGEMEM_SIZE	's'
79 	{"hugemem-size",		required_argument,	NULL, PERF_HUGEMEM_SIZE},
80 #define PERF_TIME	't'
81 	{"time",			required_argument,	NULL, PERF_TIME},
82 #define PERF_ENABLE_DEBUG	'G'
83 	{"enable-debug",		no_argument,		NULL, PERF_ENABLE_DEBUG},
84 #define PERF_DEFAULT_SOCK_IMPL	'S'
85 	{"default-sock-impl",		required_argument,	NULL, PERF_DEFAULT_SOCK_IMPL},
86 #define PERF_LOG_FLAG	'T'
87 	{"logflag",			required_argument,	NULL, PERF_LOG_FLAG},
88 #define PERF_IOVA_MODE		258
89 	{"iova-mode",			required_argument,	NULL, PERF_IOVA_MODE},
90 	/* Should be the last element */
91 	{0, 0, 0, 0}
92 };
93 
94 static int
95 parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
96 {
97 	bool trid_set = false;
98 	int op, long_idx;
99 	long int val;
100 	int rc;
101 
102 	while ((op = getopt_long(argc, argv, PERF_GETOPT_SHORT, g_cmdline_opts, &long_idx)) != -1) {
103 		switch (op) {
104 		case PERF_SHMEM_GROUP_ID:
105 		case PERF_HUGEMEM_SIZE:
106 		case PERF_TIME:
107 			val = spdk_strtol(optarg, 10);
108 			if (val < 0) {
109 				fprintf(stderr, "Converting a string to integer failed\n");
110 				return val;
111 			}
112 			switch (op) {
113 			case PERF_SHMEM_GROUP_ID:
114 				env_opts->shm_id = val;
115 				break;
116 			case PERF_HUGEMEM_SIZE:
117 				env_opts->mem_size = val;
118 				break;
119 			case PERF_TIME:
120 				g_time_in_sec = val;
121 				break;
122 			}
123 			break;
124 		case PERF_CORE_MASK:
125 			env_opts->core_mask = optarg;
126 			break;
127 		case PERF_TRANSPORT:
128 			if (trid_set) {
129 				fprintf(stderr, "Only one trid can be specified\n");
130 				usage(argv[0]);
131 				return 1;
132 			}
133 			trid_set = true;
134 			if (add_trid(optarg)) {
135 				usage(argv[0]);
136 				return 1;
137 			}
138 			break;
139 		case PERF_ENABLE_DEBUG:
140 #ifndef DEBUG
141 			fprintf(stderr, "%s must be configured with --enable-debug for -G flag\n",
142 				argv[0]);
143 			usage(argv[0]);
144 			return 1;
145 #else
146 			spdk_log_set_flag("nvme");
147 			spdk_log_set_print_level(SPDK_LOG_DEBUG);
148 			break;
149 #endif
150 		case PERF_LOG_FLAG:
151 			rc = spdk_log_set_flag(optarg);
152 			if (rc < 0) {
153 				fprintf(stderr, "unknown flag\n");
154 				usage(argv[0]);
155 				exit(EXIT_FAILURE);
156 			}
157 #ifdef DEBUG
158 			spdk_log_set_print_level(SPDK_LOG_DEBUG);
159 #endif
160 			break;
161 		case PERF_DEFAULT_SOCK_IMPL:
162 			rc = spdk_sock_set_default_impl(optarg);
163 			if (rc) {
164 				fprintf(stderr, "Failed to set sock impl %s, err %d (%s)\n", optarg, errno, strerror(errno));
165 				return 1;
166 			}
167 			break;
168 		case PERF_IOVA_MODE:
169 			env_opts->iova_mode = optarg;
170 			break;
171 		default:
172 			usage(argv[0]);
173 			return 1;
174 		}
175 	}
176 
177 	if (!g_time_in_sec) {
178 		fprintf(stderr, "missing -t (--time) operand\n");
179 		usage(argv[0]);
180 		return 1;
181 	}
182 
183 	if (!trid_set) {
184 		fprintf(stderr, "missing -r operand\n");
185 		usage(argv[0]);
186 		return 1;
187 	}
188 
189 	env_opts->no_pci = true;
190 	if (g_trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
191 		env_opts->no_pci = false;
192 	}
193 
194 	return 0;
195 }
196 
197 static int
198 test_controller(void)
199 {
200 	const int LOOP_COUNT = 5;
201 	struct spdk_nvme_qpair *qpair[LOOP_COUNT];
202 	union spdk_nvme_csts_register csts;
203 	struct spdk_nvme_ctrlr *ctrlr;
204 
205 	ctrlr = spdk_nvme_connect(&g_trid, NULL, 0);
206 	if (ctrlr == NULL) {
207 		fprintf(stderr, "spdk_nvme_connect() failed for transport address '%s'\n",
208 			g_trid.traddr);
209 		return -1;
210 	}
211 	if (spdk_nvme_ctrlr_is_discovery(ctrlr)) {
212 		fprintf(stderr, "discovery controller not allowed for this test\n");
213 		spdk_nvme_detach(ctrlr);
214 		return -1;
215 	}
216 
217 	for (int i = 0; i < LOOP_COUNT; i++) {
218 		csts = spdk_nvme_ctrlr_get_regs_csts(ctrlr);
219 		if (csts.raw == 0xFFFFFFFF) {
220 			fprintf(stderr, "could not read csts\n");
221 			spdk_nvme_detach(ctrlr);
222 			return -1;
223 		}
224 		qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
225 		if (qpair[i] == NULL) {
226 			fprintf(stderr, "could not allocate io qpair\n");
227 			spdk_nvme_detach(ctrlr);
228 			return -1;
229 		}
230 	}
231 	for (int i = 0; i < LOOP_COUNT; i++) {
232 		spdk_nvme_ctrlr_free_io_qpair(qpair[i]);
233 	}
234 
235 	spdk_nvme_detach(ctrlr);
236 
237 	return 0;
238 }
239 
240 int
241 main(int argc, char **argv)
242 {
243 	struct spdk_env_opts opts;
244 	uint64_t tsc_end;
245 	int rc;
246 
247 	spdk_env_opts_init(&opts);
248 	opts.name = "connect_stress";
249 	rc = parse_args(argc, argv, &opts);
250 	if (rc != 0) {
251 		return rc;
252 	}
253 	if (spdk_env_init(&opts) < 0) {
254 		fprintf(stderr, "Unable to initialize SPDK env\n");
255 		return -1;
256 	}
257 
258 	if (g_trid.trtype != SPDK_NVME_TRANSPORT_PCIE) {
259 		printf("Testing NVMe over Fabrics controller at %s:%s: %s\n",
260 		       g_trid.traddr, g_trid.trsvcid,
261 		       g_trid.subnqn);
262 	} else {
263 		printf("Testing NVMe PCI controller at %s\n", g_trid.traddr);
264 	}
265 
266 	tsc_end = spdk_get_ticks() + g_time_in_sec * spdk_get_ticks_hz();
267 	while (spdk_get_ticks() < tsc_end && rc == 0) {
268 		rc = test_controller();
269 	}
270 
271 	return 0;
272 }
273