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(¶ms, 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