xref: /freebsd/usr.sbin/ctld/nvmf.cc (revision 66b5296f1b29083634e2875ff08c32e7b6b866a8)
1*66b5296fSJohn Baldwin /*-
2*66b5296fSJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3*66b5296fSJohn Baldwin  *
4*66b5296fSJohn Baldwin  * Copyright (c) 2025 Chelsio Communications, Inc.
5*66b5296fSJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6*66b5296fSJohn Baldwin  */
7*66b5296fSJohn Baldwin 
8*66b5296fSJohn Baldwin #include <sys/param.h>
9*66b5296fSJohn Baldwin #include <sys/linker.h>
10*66b5296fSJohn Baldwin #include <sys/module.h>
11*66b5296fSJohn Baldwin #include <sys/time.h>
12*66b5296fSJohn Baldwin #include <assert.h>
13*66b5296fSJohn Baldwin #include <ctype.h>
14*66b5296fSJohn Baldwin #include <errno.h>
15*66b5296fSJohn Baldwin #include <libiscsiutil.h>
16*66b5296fSJohn Baldwin #include <libnvmf.h>
17*66b5296fSJohn Baldwin #include <libutil.h>
18*66b5296fSJohn Baldwin #include <limits.h>
19*66b5296fSJohn Baldwin #include <stdbool.h>
20*66b5296fSJohn Baldwin #include <stdio.h>
21*66b5296fSJohn Baldwin #include <stdlib.h>
22*66b5296fSJohn Baldwin #include <string.h>
23*66b5296fSJohn Baldwin #include <unistd.h>
24*66b5296fSJohn Baldwin #include <cam/ctl/ctl.h>
25*66b5296fSJohn Baldwin #include <cam/ctl/ctl_io.h>
26*66b5296fSJohn Baldwin #include <cam/ctl/ctl_ioctl.h>
27*66b5296fSJohn Baldwin 
28*66b5296fSJohn Baldwin #include <memory>
29*66b5296fSJohn Baldwin 
30*66b5296fSJohn Baldwin #include "ctld.hh"
31*66b5296fSJohn Baldwin #include "nvmf.hh"
32*66b5296fSJohn Baldwin 
33*66b5296fSJohn Baldwin #define	DEFAULT_MAXH2CDATA	(256 * 1024)
34*66b5296fSJohn Baldwin 
35*66b5296fSJohn Baldwin struct nvmf_io_portal final : public nvmf_portal {
nvmf_io_portalnvmf_io_portal36*66b5296fSJohn Baldwin 	nvmf_io_portal(struct portal_group *pg, const char *listen,
37*66b5296fSJohn Baldwin 	    portal_protocol protocol, freebsd::addrinfo_up ai,
38*66b5296fSJohn Baldwin 	    const struct nvmf_association_params &aparams,
39*66b5296fSJohn Baldwin 	    nvmf_association_up na) :
40*66b5296fSJohn Baldwin 		nvmf_portal(pg, listen, protocol, std::move(ai), aparams,
41*66b5296fSJohn Baldwin 		    std::move(na)) {}
42*66b5296fSJohn Baldwin 
43*66b5296fSJohn Baldwin 	void handle_connection(freebsd::fd_up fd, const char *host,
44*66b5296fSJohn Baldwin 	    const struct sockaddr *client_sa) override;
45*66b5296fSJohn Baldwin };
46*66b5296fSJohn Baldwin 
47*66b5296fSJohn Baldwin struct nvmf_transport_group final : public portal_group {
nvmf_transport_groupnvmf_transport_group48*66b5296fSJohn Baldwin 	nvmf_transport_group(struct conf *conf, std::string_view name) :
49*66b5296fSJohn Baldwin 		portal_group(conf, name) {}
50*66b5296fSJohn Baldwin 
keywordnvmf_transport_group51*66b5296fSJohn Baldwin 	const char *keyword() const override
52*66b5296fSJohn Baldwin 	{ return "transport-group"; }
53*66b5296fSJohn Baldwin 
54*66b5296fSJohn Baldwin 	void allocate_tag() override;
55*66b5296fSJohn Baldwin 	bool add_portal(const char *value, portal_protocol protocol)
56*66b5296fSJohn Baldwin 	    override;
57*66b5296fSJohn Baldwin 	void add_default_portals() override;
58*66b5296fSJohn Baldwin 	bool set_filter(const char *str) override;
59*66b5296fSJohn Baldwin 
60*66b5296fSJohn Baldwin 	virtual port_up create_port(struct target *target, auth_group_sp ag)
61*66b5296fSJohn Baldwin 	    override;
62*66b5296fSJohn Baldwin 	virtual port_up create_port(struct target *target, uint32_t ctl_port)
63*66b5296fSJohn Baldwin 	    override;
64*66b5296fSJohn Baldwin 
65*66b5296fSJohn Baldwin private:
66*66b5296fSJohn Baldwin 	struct nvmf_association_params init_aparams(portal_protocol protocol);
67*66b5296fSJohn Baldwin 
68*66b5296fSJohn Baldwin 	static uint16_t last_port_id;
69*66b5296fSJohn Baldwin };
70*66b5296fSJohn Baldwin 
71*66b5296fSJohn Baldwin struct nvmf_port final : public portal_group_port {
nvmf_portnvmf_port72*66b5296fSJohn Baldwin 	nvmf_port(struct target *target, struct portal_group *pg,
73*66b5296fSJohn Baldwin 	    auth_group_sp ag) :
74*66b5296fSJohn Baldwin 		portal_group_port(target, pg, ag) {}
nvmf_portnvmf_port75*66b5296fSJohn Baldwin 	nvmf_port(struct target *target, struct portal_group *pg,
76*66b5296fSJohn Baldwin 	    uint32_t ctl_port) :
77*66b5296fSJohn Baldwin 		portal_group_port(target, pg, ctl_port) {}
78*66b5296fSJohn Baldwin 
79*66b5296fSJohn Baldwin 	bool kernel_create_port() override;
80*66b5296fSJohn Baldwin 	bool kernel_remove_port() override;
81*66b5296fSJohn Baldwin 
82*66b5296fSJohn Baldwin private:
83*66b5296fSJohn Baldwin 	static bool modules_loaded;
84*66b5296fSJohn Baldwin 	static void load_kernel_modules();
85*66b5296fSJohn Baldwin };
86*66b5296fSJohn Baldwin 
87*66b5296fSJohn Baldwin struct nvmf_controller final : public target {
nvmf_controllernvmf_controller88*66b5296fSJohn Baldwin 	nvmf_controller(struct conf *conf, std::string_view name) :
89*66b5296fSJohn Baldwin 		target(conf, "controller", name) {}
90*66b5296fSJohn Baldwin 
91*66b5296fSJohn Baldwin 	bool add_host_nqn(std::string_view name) override;
92*66b5296fSJohn Baldwin 	bool add_host_address(const char *addr) override;
93*66b5296fSJohn Baldwin 	bool add_namespace(u_int id, const char *lun_name) override;
94*66b5296fSJohn Baldwin 	bool add_portal_group(const char *pg_name, const char *ag_name)
95*66b5296fSJohn Baldwin 	    override;
96*66b5296fSJohn Baldwin 	struct lun *start_namespace(u_int id) override;
97*66b5296fSJohn Baldwin 
98*66b5296fSJohn Baldwin protected:
99*66b5296fSJohn Baldwin 	struct portal_group *default_portal_group() override;
100*66b5296fSJohn Baldwin };
101*66b5296fSJohn Baldwin 
102*66b5296fSJohn Baldwin uint16_t nvmf_transport_group::last_port_id = 0;
103*66b5296fSJohn Baldwin bool nvmf_port::modules_loaded = false;
104*66b5296fSJohn Baldwin 
105*66b5296fSJohn Baldwin static bool need_tcp_transport = false;
106*66b5296fSJohn Baldwin 
107*66b5296fSJohn Baldwin static bool
parse_bool(const nvlist_t * nvl,const char * key,bool def)108*66b5296fSJohn Baldwin parse_bool(const nvlist_t *nvl, const char *key, bool def)
109*66b5296fSJohn Baldwin {
110*66b5296fSJohn Baldwin 	const char *value;
111*66b5296fSJohn Baldwin 
112*66b5296fSJohn Baldwin 	if (!nvlist_exists_string(nvl, key))
113*66b5296fSJohn Baldwin 		return def;
114*66b5296fSJohn Baldwin 
115*66b5296fSJohn Baldwin 	value = nvlist_get_string(nvl, key);
116*66b5296fSJohn Baldwin 	if (strcasecmp(value, "true") == 0 ||
117*66b5296fSJohn Baldwin 	    strcasecmp(value, "1") == 0)
118*66b5296fSJohn Baldwin 		return true;
119*66b5296fSJohn Baldwin 	if (strcasecmp(value, "false") == 0 ||
120*66b5296fSJohn Baldwin 	    strcasecmp(value, "0") == 0)
121*66b5296fSJohn Baldwin 		return false;
122*66b5296fSJohn Baldwin 
123*66b5296fSJohn Baldwin 	log_warnx("Invalid value \"%s\" for boolean option %s", value, key);
124*66b5296fSJohn Baldwin 	return def;
125*66b5296fSJohn Baldwin }
126*66b5296fSJohn Baldwin 
127*66b5296fSJohn Baldwin static uint64_t
parse_number(const nvlist_t * nvl,const char * key,uint64_t def,uint64_t minv,uint64_t maxv)128*66b5296fSJohn Baldwin parse_number(const nvlist_t *nvl, const char *key, uint64_t def, uint64_t minv,
129*66b5296fSJohn Baldwin     uint64_t maxv)
130*66b5296fSJohn Baldwin {
131*66b5296fSJohn Baldwin 	const char *value;
132*66b5296fSJohn Baldwin 	int64_t val;
133*66b5296fSJohn Baldwin 
134*66b5296fSJohn Baldwin 	if (!nvlist_exists_string(nvl, key))
135*66b5296fSJohn Baldwin 		return def;
136*66b5296fSJohn Baldwin 
137*66b5296fSJohn Baldwin 	value = nvlist_get_string(nvl, key);
138*66b5296fSJohn Baldwin 	if (expand_number(value, &val) == 0 && val >= 0 &&
139*66b5296fSJohn Baldwin 	    (uint64_t)val >= minv && (uint64_t)val <= maxv)
140*66b5296fSJohn Baldwin 		return (uint64_t)val;
141*66b5296fSJohn Baldwin 
142*66b5296fSJohn Baldwin 	log_warnx("Invalid value \"%s\" for numeric option %s", value, key);
143*66b5296fSJohn Baldwin 	return def;
144*66b5296fSJohn Baldwin }
145*66b5296fSJohn Baldwin 
146*66b5296fSJohn Baldwin struct nvmf_association_params
init_aparams(portal_protocol protocol)147*66b5296fSJohn Baldwin nvmf_transport_group::init_aparams(portal_protocol protocol)
148*66b5296fSJohn Baldwin {
149*66b5296fSJohn Baldwin 	struct nvmf_association_params params;
150*66b5296fSJohn Baldwin 	memset(&params, 0, sizeof(params));
151*66b5296fSJohn Baldwin 
152*66b5296fSJohn Baldwin 	/* Options shared between discovery and I/O associations. */
153*66b5296fSJohn Baldwin 	const nvlist_t *nvl = pg_options.get();
154*66b5296fSJohn Baldwin 	params.tcp.header_digests = parse_bool(nvl, "HDGST", false);
155*66b5296fSJohn Baldwin 	params.tcp.data_digests = parse_bool(nvl, "DDGST", false);
156*66b5296fSJohn Baldwin 	uint64_t value = parse_number(nvl, "MAXH2CDATA", DEFAULT_MAXH2CDATA,
157*66b5296fSJohn Baldwin 	    4096, UINT32_MAX);
158*66b5296fSJohn Baldwin 	if (value % 4 != 0) {
159*66b5296fSJohn Baldwin 		log_warnx("Invalid value \"%ju\" for option MAXH2CDATA",
160*66b5296fSJohn Baldwin 		    (uintmax_t)value);
161*66b5296fSJohn Baldwin 		value = DEFAULT_MAXH2CDATA;
162*66b5296fSJohn Baldwin 	}
163*66b5296fSJohn Baldwin 	params.tcp.maxh2cdata = value;
164*66b5296fSJohn Baldwin 
165*66b5296fSJohn Baldwin 	switch (protocol) {
166*66b5296fSJohn Baldwin 	case portal_protocol::NVME_TCP:
167*66b5296fSJohn Baldwin 		params.sq_flow_control = parse_bool(nvl, "SQFC", false);
168*66b5296fSJohn Baldwin 		params.dynamic_controller_model = true;
169*66b5296fSJohn Baldwin 		params.max_admin_qsize = parse_number(nvl, "max_admin_qsize",
170*66b5296fSJohn Baldwin 		    NVME_MAX_ADMIN_ENTRIES, NVME_MIN_ADMIN_ENTRIES,
171*66b5296fSJohn Baldwin 		    NVME_MAX_ADMIN_ENTRIES);
172*66b5296fSJohn Baldwin 		params.max_io_qsize = parse_number(nvl, "max_io_qsize",
173*66b5296fSJohn Baldwin 		    NVME_MAX_IO_ENTRIES, NVME_MIN_IO_ENTRIES,
174*66b5296fSJohn Baldwin 		    NVME_MAX_IO_ENTRIES);
175*66b5296fSJohn Baldwin 		params.tcp.pda = 0;
176*66b5296fSJohn Baldwin 		break;
177*66b5296fSJohn Baldwin 	case portal_protocol::NVME_DISCOVERY_TCP:
178*66b5296fSJohn Baldwin 		params.sq_flow_control = false;
179*66b5296fSJohn Baldwin 		params.dynamic_controller_model = true;
180*66b5296fSJohn Baldwin 		params.max_admin_qsize = NVME_MAX_ADMIN_ENTRIES;
181*66b5296fSJohn Baldwin 		params.tcp.pda = 0;
182*66b5296fSJohn Baldwin 		break;
183*66b5296fSJohn Baldwin 	default:
184*66b5296fSJohn Baldwin 		__assert_unreachable();
185*66b5296fSJohn Baldwin 	}
186*66b5296fSJohn Baldwin 
187*66b5296fSJohn Baldwin 	return params;
188*66b5296fSJohn Baldwin }
189*66b5296fSJohn Baldwin 
190*66b5296fSJohn Baldwin portal_group_up
nvmf_make_transport_group(struct conf * conf,std::string_view name)191*66b5296fSJohn Baldwin nvmf_make_transport_group(struct conf *conf, std::string_view name)
192*66b5296fSJohn Baldwin {
193*66b5296fSJohn Baldwin 	return std::make_unique<nvmf_transport_group>(conf, name);
194*66b5296fSJohn Baldwin }
195*66b5296fSJohn Baldwin 
196*66b5296fSJohn Baldwin target_up
nvmf_make_controller(struct conf * conf,std::string_view name)197*66b5296fSJohn Baldwin nvmf_make_controller(struct conf *conf, std::string_view name)
198*66b5296fSJohn Baldwin {
199*66b5296fSJohn Baldwin 	return std::make_unique<nvmf_controller>(conf, name);
200*66b5296fSJohn Baldwin }
201*66b5296fSJohn Baldwin 
202*66b5296fSJohn Baldwin void
allocate_tag()203*66b5296fSJohn Baldwin nvmf_transport_group::allocate_tag()
204*66b5296fSJohn Baldwin {
205*66b5296fSJohn Baldwin 	set_tag(++last_port_id);
206*66b5296fSJohn Baldwin }
207*66b5296fSJohn Baldwin 
208*66b5296fSJohn Baldwin bool
add_portal(const char * value,portal_protocol protocol)209*66b5296fSJohn Baldwin nvmf_transport_group::add_portal(const char *value, portal_protocol protocol)
210*66b5296fSJohn Baldwin {
211*66b5296fSJohn Baldwin 	freebsd::addrinfo_up ai;
212*66b5296fSJohn Baldwin 	enum nvmf_trtype trtype;
213*66b5296fSJohn Baldwin 
214*66b5296fSJohn Baldwin 	switch (protocol) {
215*66b5296fSJohn Baldwin 	case portal_protocol::NVME_TCP:
216*66b5296fSJohn Baldwin 		trtype = NVMF_TRTYPE_TCP;
217*66b5296fSJohn Baldwin 		ai = parse_addr_port(value, "4420");
218*66b5296fSJohn Baldwin 		break;
219*66b5296fSJohn Baldwin 	case portal_protocol::NVME_DISCOVERY_TCP:
220*66b5296fSJohn Baldwin 		trtype = NVMF_TRTYPE_TCP;
221*66b5296fSJohn Baldwin 		ai = parse_addr_port(value, "8009");
222*66b5296fSJohn Baldwin 		break;
223*66b5296fSJohn Baldwin 	default:
224*66b5296fSJohn Baldwin 		log_warnx("unsupported transport protocol for %s", value);
225*66b5296fSJohn Baldwin 		return false;
226*66b5296fSJohn Baldwin 	}
227*66b5296fSJohn Baldwin 
228*66b5296fSJohn Baldwin 	if (!ai) {
229*66b5296fSJohn Baldwin 		log_warnx("invalid listen address %s", value);
230*66b5296fSJohn Baldwin 		return false;
231*66b5296fSJohn Baldwin 	}
232*66b5296fSJohn Baldwin 
233*66b5296fSJohn Baldwin 	struct nvmf_association_params aparams = init_aparams(protocol);
234*66b5296fSJohn Baldwin 	nvmf_association_up association(nvmf_allocate_association(trtype, true,
235*66b5296fSJohn Baldwin 	    &aparams));
236*66b5296fSJohn Baldwin 	if (!association) {
237*66b5296fSJohn Baldwin 		log_warn("Failed to create NVMe controller association");
238*66b5296fSJohn Baldwin 		return false;
239*66b5296fSJohn Baldwin 	}
240*66b5296fSJohn Baldwin 
241*66b5296fSJohn Baldwin 	/*
242*66b5296fSJohn Baldwin 	 * XXX: getaddrinfo(3) may return multiple addresses; we should turn
243*66b5296fSJohn Baldwin 	 *	those into multiple portals.
244*66b5296fSJohn Baldwin 	 */
245*66b5296fSJohn Baldwin 
246*66b5296fSJohn Baldwin 	portal_up portal;
247*66b5296fSJohn Baldwin 	if (protocol == portal_protocol::NVME_DISCOVERY_TCP) {
248*66b5296fSJohn Baldwin 		portal = std::make_unique<nvmf_discovery_portal>(this, value,
249*66b5296fSJohn Baldwin 		    protocol, std::move(ai), aparams, std::move(association));
250*66b5296fSJohn Baldwin 	} else {
251*66b5296fSJohn Baldwin 		portal = std::make_unique<nvmf_io_portal>(this, value,
252*66b5296fSJohn Baldwin 		    protocol, std::move(ai), aparams, std::move(association));
253*66b5296fSJohn Baldwin 		need_tcp_transport = true;
254*66b5296fSJohn Baldwin 	}
255*66b5296fSJohn Baldwin 
256*66b5296fSJohn Baldwin 	pg_portals.emplace_back(std::move(portal));
257*66b5296fSJohn Baldwin 	return true;
258*66b5296fSJohn Baldwin }
259*66b5296fSJohn Baldwin 
260*66b5296fSJohn Baldwin void
add_default_portals()261*66b5296fSJohn Baldwin nvmf_transport_group::add_default_portals()
262*66b5296fSJohn Baldwin {
263*66b5296fSJohn Baldwin 	add_portal("0.0.0.0", portal_protocol::NVME_DISCOVERY_TCP);
264*66b5296fSJohn Baldwin 	add_portal("[::]", portal_protocol::NVME_DISCOVERY_TCP);
265*66b5296fSJohn Baldwin 	add_portal("0.0.0.0", portal_protocol::NVME_TCP);
266*66b5296fSJohn Baldwin 	add_portal("[::]", portal_protocol::NVME_TCP);
267*66b5296fSJohn Baldwin }
268*66b5296fSJohn Baldwin 
269*66b5296fSJohn Baldwin bool
set_filter(const char * str)270*66b5296fSJohn Baldwin nvmf_transport_group::set_filter(const char *str)
271*66b5296fSJohn Baldwin {
272*66b5296fSJohn Baldwin 	enum discovery_filter filter;
273*66b5296fSJohn Baldwin 
274*66b5296fSJohn Baldwin 	if (strcmp(str, "none") == 0) {
275*66b5296fSJohn Baldwin 		filter = discovery_filter::NONE;
276*66b5296fSJohn Baldwin 	} else if (strcmp(str, "address") == 0) {
277*66b5296fSJohn Baldwin 		filter = discovery_filter::PORTAL;
278*66b5296fSJohn Baldwin 	} else if (strcmp(str, "address-name") == 0) {
279*66b5296fSJohn Baldwin 		filter = discovery_filter::PORTAL_NAME;
280*66b5296fSJohn Baldwin 	} else {
281*66b5296fSJohn Baldwin 		log_warnx("invalid discovery-filter \"%s\" for transport-group "
282*66b5296fSJohn Baldwin 		    "\"%s\"; valid values are \"none\", \"address\", "
283*66b5296fSJohn Baldwin 		    "and \"address-name\"",
284*66b5296fSJohn Baldwin 		    str, name());
285*66b5296fSJohn Baldwin 		return false;
286*66b5296fSJohn Baldwin 	}
287*66b5296fSJohn Baldwin 
288*66b5296fSJohn Baldwin 	if (pg_discovery_filter != discovery_filter::UNKNOWN &&
289*66b5296fSJohn Baldwin 	    pg_discovery_filter != filter) {
290*66b5296fSJohn Baldwin 		log_warnx("cannot set discovery-filter to \"%s\" for "
291*66b5296fSJohn Baldwin 		    "transport-group \"%s\"; already has a different "
292*66b5296fSJohn Baldwin 		    "value", str, name());
293*66b5296fSJohn Baldwin 		return false;
294*66b5296fSJohn Baldwin 	}
295*66b5296fSJohn Baldwin 
296*66b5296fSJohn Baldwin 	pg_discovery_filter = filter;
297*66b5296fSJohn Baldwin 	return true;
298*66b5296fSJohn Baldwin }
299*66b5296fSJohn Baldwin 
300*66b5296fSJohn Baldwin port_up
create_port(struct target * target,auth_group_sp ag)301*66b5296fSJohn Baldwin nvmf_transport_group::create_port(struct target *target, auth_group_sp ag)
302*66b5296fSJohn Baldwin {
303*66b5296fSJohn Baldwin 	return std::make_unique<nvmf_port>(target, this, ag);
304*66b5296fSJohn Baldwin }
305*66b5296fSJohn Baldwin 
306*66b5296fSJohn Baldwin port_up
create_port(struct target * target,uint32_t ctl_port)307*66b5296fSJohn Baldwin nvmf_transport_group::create_port(struct target *target, uint32_t ctl_port)
308*66b5296fSJohn Baldwin {
309*66b5296fSJohn Baldwin 	return std::make_unique<nvmf_port>(target, this, ctl_port);
310*66b5296fSJohn Baldwin }
311*66b5296fSJohn Baldwin 
312*66b5296fSJohn Baldwin void
load_kernel_modules()313*66b5296fSJohn Baldwin nvmf_port::load_kernel_modules()
314*66b5296fSJohn Baldwin {
315*66b5296fSJohn Baldwin 	int saved_errno;
316*66b5296fSJohn Baldwin 
317*66b5296fSJohn Baldwin 	if (modules_loaded)
318*66b5296fSJohn Baldwin 		return;
319*66b5296fSJohn Baldwin 
320*66b5296fSJohn Baldwin 	saved_errno = errno;
321*66b5296fSJohn Baldwin 	if (modfind("nvmft") == -1 && kldload("nvmft") == -1)
322*66b5296fSJohn Baldwin 		log_warn("couldn't load nvmft");
323*66b5296fSJohn Baldwin 
324*66b5296fSJohn Baldwin 	if (need_tcp_transport) {
325*66b5296fSJohn Baldwin 		if (modfind("nvmf/tcp") == -1 && kldload("nvmf_tcp") == -1)
326*66b5296fSJohn Baldwin 			log_warn("couldn't load nvmf_tcp");
327*66b5296fSJohn Baldwin 	}
328*66b5296fSJohn Baldwin 
329*66b5296fSJohn Baldwin 	errno = saved_errno;
330*66b5296fSJohn Baldwin 	modules_loaded = true;
331*66b5296fSJohn Baldwin }
332*66b5296fSJohn Baldwin 
333*66b5296fSJohn Baldwin bool
kernel_create_port()334*66b5296fSJohn Baldwin nvmf_port::kernel_create_port()
335*66b5296fSJohn Baldwin {
336*66b5296fSJohn Baldwin 	struct portal_group *pg = p_portal_group;
337*66b5296fSJohn Baldwin 	struct target *targ = p_target;
338*66b5296fSJohn Baldwin 
339*66b5296fSJohn Baldwin 	load_kernel_modules();
340*66b5296fSJohn Baldwin 
341*66b5296fSJohn Baldwin 	freebsd::nvlist_up nvl = pg->options();
342*66b5296fSJohn Baldwin 	nvlist_add_string(nvl.get(), "subnqn", targ->name());
343*66b5296fSJohn Baldwin 	nvlist_add_string(nvl.get(), "ctld_transport_group_name",
344*66b5296fSJohn Baldwin 	    pg->name());
345*66b5296fSJohn Baldwin 	nvlist_add_stringf(nvl.get(), "portid", "%u", pg->tag());
346*66b5296fSJohn Baldwin 	if (!nvlist_exists_string(nvl.get(), "max_io_qsize"))
347*66b5296fSJohn Baldwin 		nvlist_add_stringf(nvl.get(), "max_io_qsize", "%u",
348*66b5296fSJohn Baldwin 		    NVME_MAX_IO_ENTRIES);
349*66b5296fSJohn Baldwin 
350*66b5296fSJohn Baldwin 	return ctl_create_port("nvmf", nvl.get(), &p_ctl_port);
351*66b5296fSJohn Baldwin }
352*66b5296fSJohn Baldwin 
353*66b5296fSJohn Baldwin bool
kernel_remove_port()354*66b5296fSJohn Baldwin nvmf_port::kernel_remove_port()
355*66b5296fSJohn Baldwin {
356*66b5296fSJohn Baldwin 	freebsd::nvlist_up nvl(nvlist_create(0));
357*66b5296fSJohn Baldwin 	nvlist_add_string(nvl.get(), "subnqn", p_target->name());
358*66b5296fSJohn Baldwin 
359*66b5296fSJohn Baldwin 	return ctl_remove_port("nvmf", nvl.get());
360*66b5296fSJohn Baldwin }
361*66b5296fSJohn Baldwin 
362*66b5296fSJohn Baldwin bool
add_host_nqn(std::string_view name)363*66b5296fSJohn Baldwin nvmf_controller::add_host_nqn(std::string_view name)
364*66b5296fSJohn Baldwin {
365*66b5296fSJohn Baldwin 	if (!use_private_auth("host-nqn"))
366*66b5296fSJohn Baldwin 		return false;
367*66b5296fSJohn Baldwin 	return t_auth_group->add_host_nqn(name);
368*66b5296fSJohn Baldwin }
369*66b5296fSJohn Baldwin 
370*66b5296fSJohn Baldwin bool
add_host_address(const char * addr)371*66b5296fSJohn Baldwin nvmf_controller::add_host_address(const char *addr)
372*66b5296fSJohn Baldwin {
373*66b5296fSJohn Baldwin 	if (!use_private_auth("host-address"))
374*66b5296fSJohn Baldwin 		return false;
375*66b5296fSJohn Baldwin 	return t_auth_group->add_host_address(addr);
376*66b5296fSJohn Baldwin }
377*66b5296fSJohn Baldwin 
378*66b5296fSJohn Baldwin bool
add_namespace(u_int id,const char * lun_name)379*66b5296fSJohn Baldwin nvmf_controller::add_namespace(u_int id, const char *lun_name)
380*66b5296fSJohn Baldwin {
381*66b5296fSJohn Baldwin 	if (id == 0) {
382*66b5296fSJohn Baldwin 		log_warnx("namespace ID cannot be 0 for %s", label());
383*66b5296fSJohn Baldwin 		return false;
384*66b5296fSJohn Baldwin 	}
385*66b5296fSJohn Baldwin 
386*66b5296fSJohn Baldwin 	std::string lun_label = "namespace ID " + std::to_string(id - 1);
387*66b5296fSJohn Baldwin 	return target::add_lun(id, lun_label.c_str(), lun_name);
388*66b5296fSJohn Baldwin }
389*66b5296fSJohn Baldwin 
390*66b5296fSJohn Baldwin bool
add_portal_group(const char * pg_name,const char * ag_name)391*66b5296fSJohn Baldwin nvmf_controller::add_portal_group(const char *pg_name, const char *ag_name)
392*66b5296fSJohn Baldwin {
393*66b5296fSJohn Baldwin 	struct portal_group *pg;
394*66b5296fSJohn Baldwin 	auth_group_sp ag;
395*66b5296fSJohn Baldwin 
396*66b5296fSJohn Baldwin 	pg = t_conf->find_transport_group(pg_name);
397*66b5296fSJohn Baldwin 	if (pg == NULL) {
398*66b5296fSJohn Baldwin 		log_warnx("unknown transport-group \"%s\" for %s", pg_name,
399*66b5296fSJohn Baldwin 		    label());
400*66b5296fSJohn Baldwin 		return false;
401*66b5296fSJohn Baldwin 	}
402*66b5296fSJohn Baldwin 
403*66b5296fSJohn Baldwin 	if (ag_name != NULL) {
404*66b5296fSJohn Baldwin 		ag = t_conf->find_auth_group(ag_name);
405*66b5296fSJohn Baldwin 		if (ag == NULL) {
406*66b5296fSJohn Baldwin 			log_warnx("unknown auth-group \"%s\" for %s", ag_name,
407*66b5296fSJohn Baldwin 			    label());
408*66b5296fSJohn Baldwin 			return false;
409*66b5296fSJohn Baldwin 		}
410*66b5296fSJohn Baldwin 	}
411*66b5296fSJohn Baldwin 
412*66b5296fSJohn Baldwin 	if (!t_conf->add_port(this, pg, std::move(ag))) {
413*66b5296fSJohn Baldwin 		log_warnx("can't link transport-group \"%s\" to %s", pg_name,
414*66b5296fSJohn Baldwin 		    label());
415*66b5296fSJohn Baldwin 		return false;
416*66b5296fSJohn Baldwin 	}
417*66b5296fSJohn Baldwin 	return true;
418*66b5296fSJohn Baldwin }
419*66b5296fSJohn Baldwin 
420*66b5296fSJohn Baldwin struct lun *
start_namespace(u_int id)421*66b5296fSJohn Baldwin nvmf_controller::start_namespace(u_int id)
422*66b5296fSJohn Baldwin {
423*66b5296fSJohn Baldwin 	if (id == 0) {
424*66b5296fSJohn Baldwin 		log_warnx("namespace ID cannot be 0 for %s", label());
425*66b5296fSJohn Baldwin 		return nullptr;
426*66b5296fSJohn Baldwin 	}
427*66b5296fSJohn Baldwin 
428*66b5296fSJohn Baldwin 	std::string lun_label = "namespace ID " + std::to_string(id - 1);
429*66b5296fSJohn Baldwin 	std::string lun_name = freebsd::stringf("%s,nsid,%u", name(), id);
430*66b5296fSJohn Baldwin 	return target::start_lun(id, lun_label.c_str(), lun_name.c_str());
431*66b5296fSJohn Baldwin }
432*66b5296fSJohn Baldwin 
433*66b5296fSJohn Baldwin struct portal_group *
default_portal_group()434*66b5296fSJohn Baldwin nvmf_controller::default_portal_group()
435*66b5296fSJohn Baldwin {
436*66b5296fSJohn Baldwin 	return t_conf->find_transport_group("default");
437*66b5296fSJohn Baldwin }
438*66b5296fSJohn Baldwin 
439*66b5296fSJohn Baldwin void
handle_connection(freebsd::fd_up fd,const char * host __unused,const struct sockaddr * client_sa __unused)440*66b5296fSJohn Baldwin nvmf_io_portal::handle_connection(freebsd::fd_up fd, const char *host __unused,
441*66b5296fSJohn Baldwin     const struct sockaddr *client_sa __unused)
442*66b5296fSJohn Baldwin {
443*66b5296fSJohn Baldwin 	struct nvmf_qpair_params qparams;
444*66b5296fSJohn Baldwin 	memset(&qparams, 0, sizeof(qparams));
445*66b5296fSJohn Baldwin 	qparams.tcp.fd = fd;
446*66b5296fSJohn Baldwin 
447*66b5296fSJohn Baldwin 	struct nvmf_capsule *nc = NULL;
448*66b5296fSJohn Baldwin 	struct nvmf_fabric_connect_data data;
449*66b5296fSJohn Baldwin 	nvmf_qpair_up qp(nvmf_accept(association(), &qparams, &nc, &data));
450*66b5296fSJohn Baldwin 	if (!qp) {
451*66b5296fSJohn Baldwin 		log_warnx("Failed to create NVMe I/O qpair: %s",
452*66b5296fSJohn Baldwin 		    nvmf_association_error(association()));
453*66b5296fSJohn Baldwin 		return;
454*66b5296fSJohn Baldwin 	}
455*66b5296fSJohn Baldwin 	nvmf_capsule_up nc_guard(nc);
456*66b5296fSJohn Baldwin 	const struct nvmf_fabric_connect_cmd *cmd =
457*66b5296fSJohn Baldwin 	    (const struct nvmf_fabric_connect_cmd *)nvmf_capsule_sqe(nc);
458*66b5296fSJohn Baldwin 
459*66b5296fSJohn Baldwin 	struct ctl_nvmf req;
460*66b5296fSJohn Baldwin 	memset(&req, 0, sizeof(req));
461*66b5296fSJohn Baldwin 	req.type = CTL_NVMF_HANDOFF;
462*66b5296fSJohn Baldwin 	int error = nvmf_handoff_controller_qpair(qp.get(), cmd, &data,
463*66b5296fSJohn Baldwin 	    &req.data.handoff);
464*66b5296fSJohn Baldwin 	if (error != 0) {
465*66b5296fSJohn Baldwin 		log_warnc(error,
466*66b5296fSJohn Baldwin 		    "Failed to prepare NVMe I/O qpair for handoff");
467*66b5296fSJohn Baldwin 		return;
468*66b5296fSJohn Baldwin 	}
469*66b5296fSJohn Baldwin 
470*66b5296fSJohn Baldwin 	if (ioctl(ctl_fd, CTL_NVMF, &req) != 0)
471*66b5296fSJohn Baldwin 		log_warn("ioctl(CTL_NVMF/CTL_NVMF_HANDOFF)");
472*66b5296fSJohn Baldwin 	if (req.status == CTL_NVMF_ERROR)
473*66b5296fSJohn Baldwin 		log_warnx("Failed to handoff NVMF connection: %s",
474*66b5296fSJohn Baldwin 		    req.error_str);
475*66b5296fSJohn Baldwin 	else if (req.status != CTL_NVMF_OK)
476*66b5296fSJohn Baldwin 		log_warnx("Failed to handoff NVMF connection with status %d",
477*66b5296fSJohn Baldwin 		    req.status);
478*66b5296fSJohn Baldwin }
479