Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/ctld/kernel.cc
103829 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2003, 2004 Silicon Graphics International Corp.
5
* Copyright (c) 1997-2007 Kenneth D. Merry
6
* Copyright (c) 2012 The FreeBSD Foundation
7
* Copyright (c) 2017 Jakub Wojciech Klama <[email protected]>
8
* All rights reserved.
9
*
10
* Portions of this software were developed by Edward Tomasz Napierala
11
* under sponsorship from the FreeBSD Foundation.
12
*
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following conditions
15
* are met:
16
* 1. Redistributions of source code must retain the above copyright
17
* notice, this list of conditions, and the following disclaimer,
18
* without modification.
19
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
20
* substantially similar to the "NO WARRANTY" disclaimer below
21
* ("Disclaimer") and any redistribution must be conditioned upon
22
* including a substantially similar Disclaimer requirement for further
23
* binary redistribution.
24
*
25
* NO WARRANTY
26
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
29
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
35
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
* POSSIBILITY OF SUCH DAMAGES.
37
*
38
*/
39
40
#include <sys/param.h>
41
#include <sys/capsicum.h>
42
#include <sys/callout.h>
43
#include <sys/cnv.h>
44
#include <sys/ioctl.h>
45
#include <sys/linker.h>
46
#include <sys/module.h>
47
#include <sys/queue.h>
48
#include <sys/sbuf.h>
49
#include <sys/stat.h>
50
#include <assert.h>
51
#include <bsdxml.h>
52
#include <capsicum_helpers.h>
53
#include <ctype.h>
54
#include <errno.h>
55
#include <fcntl.h>
56
#include <stdint.h>
57
#include <stdio.h>
58
#include <stdlib.h>
59
#include <string.h>
60
#include <strings.h>
61
#include <cam/scsi/scsi_all.h>
62
#include <cam/scsi/scsi_message.h>
63
#include <cam/ctl/ctl.h>
64
#include <cam/ctl/ctl_io.h>
65
#include <cam/ctl/ctl_backend.h>
66
#include <cam/ctl/ctl_ioctl.h>
67
#include <cam/ctl/ctl_util.h>
68
#include <cam/ctl/ctl_scsi_all.h>
69
70
#include "ctld.hh"
71
72
#ifdef ICL_KERNEL_PROXY
73
#include <netdb.h>
74
#endif
75
76
#define NVLIST_BUFSIZE 1024
77
78
int ctl_fd = 0;
79
80
void
81
kernel_init(void)
82
{
83
int retval, saved_errno;
84
85
ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
86
if (ctl_fd < 0 && errno == ENOENT) {
87
saved_errno = errno;
88
retval = kldload("ctl");
89
if (retval != -1)
90
ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR);
91
else
92
errno = saved_errno;
93
}
94
if (ctl_fd < 0)
95
log_err(1, "failed to open %s", CTL_DEFAULT_DEV);
96
#ifdef WANT_ISCSI
97
else {
98
saved_errno = errno;
99
if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1)
100
log_warn("couldn't load cfiscsi");
101
errno = saved_errno;
102
}
103
#endif
104
}
105
106
/*
107
* Backend LUN information.
108
*/
109
using attr_list_t = std::list<std::pair<std::string, std::string>>;
110
111
struct cctl_lun {
112
uint64_t lun_id;
113
std::string backend_type;
114
uint8_t device_type;
115
uint64_t size_blocks;
116
uint32_t blocksize;
117
std::string serial_number;
118
std::string device_id;
119
std::string ctld_name;
120
attr_list_t attr_list;
121
};
122
123
struct cctl_port {
124
uint32_t port_id;
125
std::string port_frontend;
126
std::string port_name;
127
int pp;
128
int vp;
129
uint16_t portid;
130
int cfiscsi_state;
131
std::string cfiscsi_target;
132
std::string nqn;
133
uint16_t cfiscsi_portal_group_tag;
134
std::string ctld_portal_group_name;
135
std::string ctld_transport_group_name;
136
attr_list_t attr_list;
137
};
138
139
struct cctl_devlist_data {
140
std::list<cctl_lun> lun_list;
141
struct cctl_lun *cur_lun = nullptr;
142
std::list<cctl_port> port_list;
143
struct cctl_port *cur_port = nullptr;
144
u_int level = 0;
145
struct sbuf *cur_sb[32] = {};
146
};
147
148
static void
149
cctl_start_element(void *user_data, const char *name, const char **attr)
150
{
151
int i;
152
struct cctl_devlist_data *devlist;
153
struct cctl_lun *cur_lun;
154
155
devlist = (struct cctl_devlist_data *)user_data;
156
cur_lun = devlist->cur_lun;
157
devlist->level++;
158
if (devlist->level >= nitems(devlist->cur_sb))
159
log_errx(1, "%s: too many nesting levels, %zu max", __func__,
160
nitems(devlist->cur_sb));
161
162
devlist->cur_sb[devlist->level] = sbuf_new_auto();
163
if (devlist->cur_sb[devlist->level] == NULL)
164
log_err(1, "%s: unable to allocate sbuf", __func__);
165
166
if (strcmp(name, "lun") == 0) {
167
if (cur_lun != NULL)
168
log_errx(1, "%s: improper lun element nesting",
169
__func__);
170
171
devlist->lun_list.emplace_back();
172
cur_lun = &devlist->lun_list.back();
173
174
devlist->cur_lun = cur_lun;
175
176
for (i = 0; attr[i] != NULL; i += 2) {
177
if (strcmp(attr[i], "id") == 0) {
178
cur_lun->lun_id = strtoull(attr[i+1], NULL, 0);
179
} else {
180
log_errx(1, "%s: invalid LUN attribute %s = %s",
181
__func__, attr[i], attr[i+1]);
182
}
183
}
184
}
185
}
186
187
static void
188
cctl_end_element(void *user_data, const char *name)
189
{
190
struct cctl_devlist_data *devlist;
191
struct cctl_lun *cur_lun;
192
std::string str;
193
194
devlist = (struct cctl_devlist_data *)user_data;
195
cur_lun = devlist->cur_lun;
196
197
if ((cur_lun == NULL)
198
&& (strcmp(name, "ctllunlist") != 0))
199
log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name);
200
201
if (devlist->cur_sb[devlist->level] == NULL)
202
log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
203
devlist->level, name);
204
205
sbuf_finish(devlist->cur_sb[devlist->level]);
206
str = sbuf_data(devlist->cur_sb[devlist->level]);
207
208
sbuf_delete(devlist->cur_sb[devlist->level]);
209
devlist->cur_sb[devlist->level] = NULL;
210
devlist->level--;
211
212
if (strcmp(name, "backend_type") == 0) {
213
cur_lun->backend_type = std::move(str);
214
} else if (strcmp(name, "lun_type") == 0) {
215
if (str.empty())
216
log_errx(1, "%s: %s missing its argument", __func__, name);
217
cur_lun->device_type = strtoull(str.c_str(), NULL, 0);
218
} else if (strcmp(name, "size") == 0) {
219
if (str.empty())
220
log_errx(1, "%s: %s missing its argument", __func__, name);
221
cur_lun->size_blocks = strtoull(str.c_str(), NULL, 0);
222
} else if (strcmp(name, "blocksize") == 0) {
223
if (str.empty())
224
log_errx(1, "%s: %s missing its argument", __func__, name);
225
cur_lun->blocksize = strtoul(str.c_str(), NULL, 0);
226
} else if (strcmp(name, "serial_number") == 0) {
227
cur_lun->serial_number = std::move(str);
228
} else if (strcmp(name, "device_id") == 0) {
229
cur_lun->device_id = std::move(str);
230
} else if (strcmp(name, "ctld_name") == 0) {
231
cur_lun->ctld_name = std::move(str);
232
} else if (strcmp(name, "lun") == 0) {
233
devlist->cur_lun = NULL;
234
} else if (strcmp(name, "ctllunlist") == 0) {
235
/* Nothing. */
236
} else {
237
cur_lun->attr_list.emplace_back(name, std::move(str));
238
}
239
}
240
241
static void
242
cctl_start_pelement(void *user_data, const char *name, const char **attr)
243
{
244
int i;
245
struct cctl_devlist_data *devlist;
246
struct cctl_port *cur_port;
247
248
devlist = (struct cctl_devlist_data *)user_data;
249
cur_port = devlist->cur_port;
250
devlist->level++;
251
if (devlist->level >= nitems(devlist->cur_sb))
252
log_errx(1, "%s: too many nesting levels, %zu max", __func__,
253
nitems(devlist->cur_sb));
254
255
devlist->cur_sb[devlist->level] = sbuf_new_auto();
256
if (devlist->cur_sb[devlist->level] == NULL)
257
log_err(1, "%s: unable to allocate sbuf", __func__);
258
259
if (strcmp(name, "targ_port") == 0) {
260
if (cur_port != NULL)
261
log_errx(1, "%s: improper port element nesting (%s)",
262
__func__, name);
263
264
devlist->port_list.emplace_back();
265
cur_port = &devlist->port_list.back();
266
devlist->cur_port = cur_port;
267
268
for (i = 0; attr[i] != NULL; i += 2) {
269
if (strcmp(attr[i], "id") == 0) {
270
cur_port->port_id = strtoul(attr[i+1], NULL, 0);
271
} else {
272
log_errx(1, "%s: invalid LUN attribute %s = %s",
273
__func__, attr[i], attr[i+1]);
274
}
275
}
276
}
277
}
278
279
static void
280
cctl_end_pelement(void *user_data, const char *name)
281
{
282
struct cctl_devlist_data *devlist;
283
struct cctl_port *cur_port;
284
std::string str;
285
286
devlist = (struct cctl_devlist_data *)user_data;
287
cur_port = devlist->cur_port;
288
289
if ((cur_port == NULL)
290
&& (strcmp(name, "ctlportlist") != 0))
291
log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name);
292
293
if (devlist->cur_sb[devlist->level] == NULL)
294
log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__,
295
devlist->level, name);
296
297
sbuf_finish(devlist->cur_sb[devlist->level]);
298
str = sbuf_data(devlist->cur_sb[devlist->level]);
299
300
sbuf_delete(devlist->cur_sb[devlist->level]);
301
devlist->cur_sb[devlist->level] = NULL;
302
devlist->level--;
303
304
if (strcmp(name, "frontend_type") == 0) {
305
cur_port->port_frontend = std::move(str);
306
} else if (strcmp(name, "port_name") == 0) {
307
cur_port->port_name = std::move(str);
308
} else if (strcmp(name, "physical_port") == 0) {
309
if (str.empty())
310
log_errx(1, "%s: %s missing its argument", __func__, name);
311
cur_port->pp = strtoul(str.c_str(), NULL, 0);
312
} else if (strcmp(name, "virtual_port") == 0) {
313
if (str.empty())
314
log_errx(1, "%s: %s missing its argument", __func__, name);
315
cur_port->vp = strtoul(str.c_str(), NULL, 0);
316
} else if (strcmp(name, "cfiscsi_target") == 0) {
317
cur_port->cfiscsi_target = std::move(str);
318
} else if (strcmp(name, "cfiscsi_state") == 0) {
319
if (str.empty())
320
log_errx(1, "%s: %s missing its argument", __func__, name);
321
cur_port->cfiscsi_state = strtoul(str.c_str(), NULL, 0);
322
} else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) {
323
if (str.empty())
324
log_errx(1, "%s: %s missing its argument", __func__, name);
325
cur_port->cfiscsi_portal_group_tag = strtoul(str.c_str(), NULL, 0);
326
} else if (strcmp(name, "ctld_portal_group_name") == 0) {
327
cur_port->ctld_portal_group_name = std::move(str);
328
} else if (strcmp(name, "ctld_transport_group_name") == 0) {
329
cur_port->ctld_transport_group_name = std::move(str);
330
} else if (strcmp(name, "nqn") == 0) {
331
cur_port->nqn = std::move(str);
332
} else if (strcmp(name, "portid") == 0) {
333
if (str.empty())
334
log_errx(1, "%s: %s missing its argument", __func__, name);
335
cur_port->portid = strtoul(str.c_str(), NULL, 0);
336
} else if (strcmp(name, "targ_port") == 0) {
337
devlist->cur_port = NULL;
338
} else if (strcmp(name, "ctlportlist") == 0) {
339
/* Nothing. */
340
} else {
341
cur_port->attr_list.emplace_back(name, std::move(str));
342
}
343
}
344
345
static void
346
cctl_char_handler(void *user_data, const XML_Char *str, int len)
347
{
348
struct cctl_devlist_data *devlist;
349
350
devlist = (struct cctl_devlist_data *)user_data;
351
352
sbuf_bcat(devlist->cur_sb[devlist->level], str, len);
353
}
354
355
static bool
356
parse_kernel_config(struct cctl_devlist_data &devlist)
357
{
358
struct ctl_lun_list list;
359
XML_Parser parser;
360
int retval;
361
362
std::vector<char> buf(4096);
363
retry:
364
bzero(&list, sizeof(list));
365
list.alloc_len = buf.size();
366
list.status = CTL_LUN_LIST_NONE;
367
list.lun_xml = buf.data();
368
369
if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) {
370
log_warn("error issuing CTL_LUN_LIST ioctl");
371
return (false);
372
}
373
374
if (list.status == CTL_LUN_LIST_ERROR) {
375
log_warnx("error returned from CTL_LUN_LIST ioctl: %s",
376
list.error_str);
377
return (false);
378
}
379
380
if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
381
buf.resize(buf.size() << 1);
382
goto retry;
383
}
384
385
parser = XML_ParserCreate(NULL);
386
if (parser == NULL) {
387
log_warnx("unable to create XML parser");
388
return (false);
389
}
390
391
XML_SetUserData(parser, &devlist);
392
XML_SetElementHandler(parser, cctl_start_element, cctl_end_element);
393
XML_SetCharacterDataHandler(parser, cctl_char_handler);
394
395
retval = XML_Parse(parser, buf.data(), strlen(buf.data()), 1);
396
XML_ParserFree(parser);
397
if (retval != 1) {
398
log_warnx("XML_Parse failed");
399
return (false);
400
}
401
402
retry_port:
403
bzero(&list, sizeof(list));
404
list.alloc_len = buf.size();
405
list.status = CTL_LUN_LIST_NONE;
406
list.lun_xml = buf.data();
407
408
if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) {
409
log_warn("error issuing CTL_PORT_LIST ioctl");
410
return (false);
411
}
412
413
if (list.status == CTL_LUN_LIST_ERROR) {
414
log_warnx("error returned from CTL_PORT_LIST ioctl: %s",
415
list.error_str);
416
return (false);
417
}
418
419
if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) {
420
buf.resize(buf.size() << 1);
421
goto retry_port;
422
}
423
424
parser = XML_ParserCreate(NULL);
425
if (parser == NULL) {
426
log_warnx("unable to create XML parser");
427
return (false);
428
}
429
430
XML_SetUserData(parser, &devlist);
431
XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement);
432
XML_SetCharacterDataHandler(parser, cctl_char_handler);
433
434
retval = XML_Parse(parser, buf.data(), strlen(buf.data()), 1);
435
XML_ParserFree(parser);
436
if (retval != 1) {
437
log_warnx("XML_Parse failed");
438
return (false);
439
}
440
441
return (true);
442
}
443
444
void
445
add_iscsi_port(struct kports &kports, struct conf *conf,
446
const struct cctl_port &port, std::string &name)
447
{
448
if (port.cfiscsi_target.empty()) {
449
log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
450
port.port_id, name.c_str());
451
if (!kports.has_port(name)) {
452
if (!kports.add_port(name, port.port_id)) {
453
log_warnx("kports::add_port failed");
454
return;
455
}
456
}
457
return;
458
}
459
if (port.cfiscsi_state != 1) {
460
log_debugx("CTL port %ju is not active (%d); ignoring",
461
(uintmax_t)port.port_id, port.cfiscsi_state);
462
return;
463
}
464
465
const char *t_name = port.cfiscsi_target.c_str();
466
struct target *targ = conf->find_target(t_name);
467
if (targ == nullptr) {
468
targ = conf->add_target(t_name);
469
if (targ == nullptr) {
470
log_warnx("Failed to add target \"%s\"", t_name);
471
return;
472
}
473
}
474
475
if (port.ctld_portal_group_name.empty())
476
return;
477
478
const char *pg_name = port.ctld_portal_group_name.c_str();
479
struct portal_group *pg = conf->find_portal_group(pg_name);
480
if (pg == nullptr) {
481
pg = conf->add_portal_group(pg_name);
482
if (pg == nullptr) {
483
log_warnx("Failed to add portal-group \"%s\"", pg_name);
484
return;
485
}
486
}
487
pg->set_tag(port.cfiscsi_portal_group_tag);
488
if (!conf->add_port(targ, pg, port.port_id)) {
489
log_warnx("Failed to add port for target \"%s\" and portal-group \"%s\"",
490
t_name, pg_name);
491
}
492
}
493
494
void
495
add_nvmf_port(struct conf *conf, const struct cctl_port &port,
496
std::string &name)
497
{
498
if (port.nqn.empty() || port.ctld_transport_group_name.empty()) {
499
log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
500
port.port_id, name.c_str());
501
return;
502
}
503
504
const char *nqn = port.nqn.c_str();
505
struct target *targ = conf->find_controller(nqn);
506
if (targ == nullptr) {
507
targ = conf->add_controller(nqn);
508
if (targ == nullptr) {
509
log_warnx("Failed to add controller \"%s\"", nqn);
510
return;
511
}
512
}
513
514
const char *tg_name = port.ctld_transport_group_name.c_str();
515
struct portal_group *pg = conf->find_transport_group(tg_name);
516
if (pg == nullptr) {
517
pg = conf->add_transport_group(tg_name);
518
if (pg == nullptr) {
519
log_warnx("Failed to add transport-group \"%s\"",
520
tg_name);
521
return;
522
}
523
}
524
pg->set_tag(port.portid);
525
if (!conf->add_port(targ, pg, port.port_id)) {
526
log_warnx("Failed to add port for controller \"%s\" and transport-group \"%s\"",
527
nqn, tg_name);
528
}
529
}
530
531
conf_up
532
conf_new_from_kernel(struct kports &kports)
533
{
534
struct cctl_devlist_data devlist;
535
536
log_debugx("obtaining previously configured CTL luns from the kernel");
537
538
if (!parse_kernel_config(devlist))
539
return {};
540
541
conf_up conf = std::make_unique<struct conf>();
542
543
for (const auto &port : devlist.port_list) {
544
if (port.port_frontend == "ha")
545
continue;
546
547
std::string name = port.port_name;
548
if (port.pp != 0) {
549
name += "/" + std::to_string(port.pp);
550
if (port.vp != 0)
551
name += "/" + std::to_string(port.vp);
552
}
553
554
if (port.port_frontend == "iscsi") {
555
add_iscsi_port(kports, conf.get(), port, name);
556
} else if (port.port_frontend == "nvmf") {
557
add_nvmf_port(conf.get(), port, name);
558
} else {
559
/* XXX: Treat all unknown ports as iSCSI? */
560
add_iscsi_port(kports, conf.get(), port, name);
561
}
562
}
563
564
for (const auto &lun : devlist.lun_list) {
565
if (lun.ctld_name.empty()) {
566
log_debugx("CTL lun %ju wasn't managed by ctld; "
567
"ignoring", (uintmax_t)lun.lun_id);
568
continue;
569
}
570
571
const char *l_name = lun.ctld_name.c_str();
572
struct lun *cl = conf->find_lun(l_name);
573
if (cl != NULL) {
574
log_warnx("found CTL lun %ju \"%s\", "
575
"also backed by CTL lun %d; ignoring",
576
(uintmax_t)lun.lun_id, l_name,
577
cl->ctl_lun());
578
continue;
579
}
580
581
log_debugx("found CTL lun %ju \"%s\"",
582
(uintmax_t)lun.lun_id, l_name);
583
584
cl = conf->add_lun(l_name);
585
if (cl == NULL) {
586
log_warnx("lun_new failed");
587
continue;
588
}
589
cl->set_backend(lun.backend_type.c_str());
590
cl->set_device_type(lun.device_type);
591
cl->set_blocksize(lun.blocksize);
592
cl->set_device_id(lun.device_id.c_str());
593
cl->set_serial(lun.serial_number.c_str());
594
cl->set_size(lun.size_blocks * lun.blocksize);
595
cl->set_ctl_lun(lun.lun_id);
596
597
for (const auto &pair : lun.attr_list) {
598
const char *key = pair.first.c_str();
599
const char *value = pair.second.c_str();
600
if (pair.first == "file" || pair.first == "dev") {
601
cl->set_path(value);
602
continue;
603
}
604
if (!cl->add_option(key, value))
605
log_warnx("unable to add CTL lun option "
606
"%s for CTL lun %ju \"%s\"",
607
key, (uintmax_t)lun.lun_id,
608
cl->name());
609
}
610
}
611
612
return (conf);
613
}
614
615
bool
616
lun::kernel_add()
617
{
618
struct ctl_lun_req req;
619
int error;
620
621
bzero(&req, sizeof(req));
622
623
strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend));
624
req.reqtype = CTL_LUNREQ_CREATE;
625
626
req.reqdata.create.blocksize_bytes = l_blocksize;
627
628
if (l_size != 0)
629
req.reqdata.create.lun_size_bytes = l_size;
630
631
if (l_ctl_lun >= 0) {
632
req.reqdata.create.req_lun_id = l_ctl_lun;
633
req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ;
634
}
635
636
req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE;
637
req.reqdata.create.device_type = l_device_type;
638
639
if (!l_serial.empty()) {
640
strncpy((char *)req.reqdata.create.serial_num, l_serial.c_str(),
641
sizeof(req.reqdata.create.serial_num));
642
req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM;
643
}
644
645
if (!l_device_id.empty()) {
646
strncpy((char *)req.reqdata.create.device_id,
647
l_device_id.c_str(), sizeof(req.reqdata.create.device_id));
648
req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID;
649
}
650
651
freebsd::nvlist_up nvl = options();
652
req.args = nvlist_pack(nvl.get(), &req.args_len);
653
if (req.args == NULL) {
654
log_warn("error packing nvlist");
655
return (false);
656
}
657
658
error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
659
free(req.args);
660
661
if (error != 0) {
662
log_warn("error issuing CTL_LUN_REQ ioctl");
663
return (false);
664
}
665
666
switch (req.status) {
667
case CTL_LUN_ERROR:
668
log_warnx("LUN creation error: %s", req.error_str);
669
return (false);
670
case CTL_LUN_WARNING:
671
log_warnx("LUN creation warning: %s", req.error_str);
672
break;
673
case CTL_LUN_OK:
674
break;
675
default:
676
log_warnx("unknown LUN creation status: %d",
677
req.status);
678
return (false);
679
}
680
681
l_ctl_lun = req.reqdata.create.req_lun_id;
682
return (true);
683
}
684
685
bool
686
lun::kernel_modify() const
687
{
688
struct ctl_lun_req req;
689
int error;
690
691
bzero(&req, sizeof(req));
692
693
strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend));
694
req.reqtype = CTL_LUNREQ_MODIFY;
695
696
req.reqdata.modify.lun_id = l_ctl_lun;
697
req.reqdata.modify.lun_size_bytes = l_size;
698
699
freebsd::nvlist_up nvl = options();
700
req.args = nvlist_pack(nvl.get(), &req.args_len);
701
if (req.args == NULL) {
702
log_warn("error packing nvlist");
703
return (false);
704
}
705
706
error = ioctl(ctl_fd, CTL_LUN_REQ, &req);
707
free(req.args);
708
709
if (error != 0) {
710
log_warn("error issuing CTL_LUN_REQ ioctl");
711
return (false);
712
}
713
714
switch (req.status) {
715
case CTL_LUN_ERROR:
716
log_warnx("LUN modification error: %s", req.error_str);
717
return (false);
718
case CTL_LUN_WARNING:
719
log_warnx("LUN modification warning: %s", req.error_str);
720
break;
721
case CTL_LUN_OK:
722
break;
723
default:
724
log_warnx("unknown LUN modification status: %d",
725
req.status);
726
return (false);
727
}
728
729
return (true);
730
}
731
732
bool
733
lun::kernel_remove() const
734
{
735
struct ctl_lun_req req;
736
737
bzero(&req, sizeof(req));
738
739
strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend));
740
req.reqtype = CTL_LUNREQ_RM;
741
742
req.reqdata.rm.lun_id = l_ctl_lun;
743
744
if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) {
745
log_warn("error issuing CTL_LUN_REQ ioctl");
746
return (false);
747
}
748
749
switch (req.status) {
750
case CTL_LUN_ERROR:
751
log_warnx("LUN removal error: %s", req.error_str);
752
return (false);
753
case CTL_LUN_WARNING:
754
log_warnx("LUN removal warning: %s", req.error_str);
755
break;
756
case CTL_LUN_OK:
757
break;
758
default:
759
log_warnx("unknown LUN removal status: %d", req.status);
760
return (false);
761
}
762
763
return (true);
764
}
765
766
bool
767
ctl_create_port(const char *driver, const nvlist_t *nvl, uint32_t *ctl_port)
768
{
769
struct ctl_req req;
770
char result_buf[NVLIST_BUFSIZE];
771
int error;
772
773
bzero(&req, sizeof(req));
774
req.reqtype = CTL_REQ_CREATE;
775
776
strlcpy(req.driver, driver, sizeof(req.driver));
777
req.args = nvlist_pack(nvl, &req.args_len);
778
if (req.args == NULL) {
779
log_warn("error packing nvlist");
780
return (false);
781
}
782
783
req.result = result_buf;
784
req.result_len = sizeof(result_buf);
785
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
786
free(req.args);
787
788
if (error != 0) {
789
log_warn("error issuing CTL_PORT_REQ ioctl");
790
return (false);
791
}
792
if (req.status == CTL_LUN_ERROR) {
793
log_warnx("error returned from port creation request: %s",
794
req.error_str);
795
return (false);
796
}
797
if (req.status != CTL_LUN_OK) {
798
log_warnx("unknown port creation request status %d",
799
req.status);
800
return (false);
801
}
802
803
freebsd::nvlist_up result_nvl(nvlist_unpack(result_buf, req.result_len,
804
0));
805
if (result_nvl == NULL) {
806
log_warnx("error unpacking result nvlist");
807
return (false);
808
}
809
810
*ctl_port = nvlist_get_number(result_nvl.get(), "port_id");
811
return (true);
812
}
813
814
bool
815
ioctl_port::kernel_create_port()
816
{
817
freebsd::nvlist_up nvl(nvlist_create(0));
818
nvlist_add_stringf(nvl.get(), "pp", "%d", p_ioctl_pp);
819
nvlist_add_stringf(nvl.get(), "vp", "%d", p_ioctl_vp);
820
821
return (ctl_create_port("ioctl", nvl.get(), &p_ctl_port));
822
}
823
824
bool
825
kernel_port::kernel_create_port()
826
{
827
struct ctl_port_entry entry;
828
struct target *targ = p_target;
829
830
p_ctl_port = p_pport->ctl_port();
831
832
if (strncmp(targ->name(), "naa.", 4) == 0 &&
833
strlen(targ->name()) == 20) {
834
bzero(&entry, sizeof(entry));
835
entry.port_type = CTL_PORT_NONE;
836
entry.targ_port = p_ctl_port;
837
entry.flags |= CTL_PORT_WWNN_VALID;
838
entry.wwnn = strtoull(targ->name() + 4, NULL, 16);
839
if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1)
840
log_warn("CTL_SET_PORT_WWNS ioctl failed");
841
}
842
return (true);
843
}
844
845
bool
846
port::kernel_add()
847
{
848
struct ctl_port_entry entry;
849
struct ctl_lun_map lm;
850
struct target *targ = p_target;
851
int error, i;
852
853
if (!kernel_create_port())
854
return (false);
855
856
/* Explicitly enable mapping to block any access except allowed. */
857
lm.port = p_ctl_port;
858
lm.plun = UINT32_MAX;
859
lm.lun = 0;
860
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
861
if (error != 0)
862
log_warn("CTL_LUN_MAP ioctl failed");
863
864
/* Map configured LUNs */
865
for (i = 0; i < MAX_LUNS; i++) {
866
if (targ->lun(i) == nullptr)
867
continue;
868
lm.port = p_ctl_port;
869
lm.plun = i;
870
lm.lun = targ->lun(i)->ctl_lun();
871
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
872
if (error != 0)
873
log_warn("CTL_LUN_MAP ioctl failed");
874
}
875
876
/* Enable port */
877
bzero(&entry, sizeof(entry));
878
entry.targ_port = p_ctl_port;
879
error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry);
880
if (error != 0) {
881
log_warn("CTL_ENABLE_PORT ioctl failed");
882
return (false);
883
}
884
885
return (true);
886
}
887
888
bool
889
port::kernel_update(const struct port *oport)
890
{
891
struct ctl_lun_map lm;
892
struct target *targ = p_target;
893
struct target *otarg = oport->p_target;
894
int error, i;
895
uint32_t olun;
896
897
p_ctl_port = oport->p_ctl_port;
898
899
/* Map configured LUNs and unmap others */
900
for (i = 0; i < MAX_LUNS; i++) {
901
lm.port = p_ctl_port;
902
lm.plun = i;
903
if (targ->lun(i) == nullptr)
904
lm.lun = UINT32_MAX;
905
else
906
lm.lun = targ->lun(i)->ctl_lun();
907
if (otarg->lun(i) == nullptr)
908
olun = UINT32_MAX;
909
else
910
olun = otarg->lun(i)->ctl_lun();
911
if (lm.lun == olun)
912
continue;
913
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
914
if (error != 0)
915
log_warn("CTL_LUN_MAP ioctl failed");
916
}
917
return (true);
918
}
919
920
bool
921
ctl_remove_port(const char *driver, nvlist_t *nvl)
922
{
923
struct ctl_req req;
924
int error;
925
926
strlcpy(req.driver, driver, sizeof(req.driver));
927
req.reqtype = CTL_REQ_REMOVE;
928
req.args = nvlist_pack(nvl, &req.args_len);
929
if (req.args == NULL) {
930
log_warn("error packing nvlist");
931
return (false);
932
}
933
934
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
935
free(req.args);
936
937
if (error != 0) {
938
log_warn("error issuing CTL_PORT_REQ ioctl");
939
return (false);
940
}
941
if (req.status == CTL_LUN_ERROR) {
942
log_warnx("error returned from port removal request: %s",
943
req.error_str);
944
return (false);
945
}
946
if (req.status != CTL_LUN_OK) {
947
log_warnx("unknown port removal request status %d", req.status);
948
return (false);
949
}
950
return (true);
951
}
952
953
bool
954
ioctl_port::kernel_remove_port()
955
{
956
freebsd::nvlist_up nvl(nvlist_create(0));
957
nvlist_add_stringf(nvl.get(), "port_id", "%d", p_ctl_port);
958
959
return (ctl_remove_port("ioctl", nvl.get()));
960
}
961
962
bool
963
kernel_port::kernel_remove_port()
964
{
965
struct ctl_lun_map lm;
966
int error;
967
968
/* Disable LUN mapping. */
969
lm.port = p_ctl_port;
970
lm.plun = UINT32_MAX;
971
lm.lun = UINT32_MAX;
972
error = ioctl(ctl_fd, CTL_LUN_MAP, &lm);
973
if (error != 0)
974
log_warn("CTL_LUN_MAP ioctl failed");
975
return (true);
976
}
977
978
bool
979
port::kernel_remove()
980
{
981
struct ctl_port_entry entry;
982
int error;
983
984
/* Disable port */
985
bzero(&entry, sizeof(entry));
986
entry.targ_port = p_ctl_port;
987
error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry);
988
if (error != 0) {
989
log_warn("CTL_DISABLE_PORT ioctl failed");
990
return (false);
991
}
992
993
return (kernel_remove_port());
994
}
995
996
#ifdef ICL_KERNEL_PROXY
997
void
998
kernel_listen(struct addrinfo *ai, bool iser, int portal_id)
999
{
1000
struct ctl_iscsi req;
1001
1002
bzero(&req, sizeof(req));
1003
1004
req.type = CTL_ISCSI_LISTEN;
1005
req.data.listen.iser = iser;
1006
req.data.listen.domain = ai->ai_family;
1007
req.data.listen.socktype = ai->ai_socktype;
1008
req.data.listen.protocol = ai->ai_protocol;
1009
req.data.listen.addr = ai->ai_addr;
1010
req.data.listen.addrlen = ai->ai_addrlen;
1011
req.data.listen.portal_id = portal_id;
1012
1013
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1014
log_err(1, "error issuing CTL_ISCSI ioctl");
1015
1016
if (req.status != CTL_ISCSI_OK) {
1017
log_errx(1, "error returned from CTL iSCSI listen: %s",
1018
req.error_str);
1019
}
1020
}
1021
1022
void
1023
kernel_accept(int *connection_id, int *portal_id,
1024
struct sockaddr *client_sa, socklen_t *client_salen)
1025
{
1026
struct ctl_iscsi req;
1027
struct sockaddr_storage ss;
1028
1029
bzero(&req, sizeof(req));
1030
1031
req.type = CTL_ISCSI_ACCEPT;
1032
req.data.accept.initiator_addr = (struct sockaddr *)&ss;
1033
1034
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1)
1035
log_err(1, "error issuing CTL_ISCSI ioctl");
1036
1037
if (req.status != CTL_ISCSI_OK) {
1038
log_errx(1, "error returned from CTL iSCSI accept: %s",
1039
req.error_str);
1040
}
1041
1042
*connection_id = req.data.accept.connection_id;
1043
*portal_id = req.data.accept.portal_id;
1044
*client_salen = req.data.accept.initiator_addrlen;
1045
memcpy(client_sa, &ss, *client_salen);
1046
}
1047
1048
void
1049
kernel_send(struct pdu *pdu)
1050
{
1051
struct ctl_iscsi req;
1052
1053
bzero(&req, sizeof(req));
1054
1055
req.type = CTL_ISCSI_SEND;
1056
req.data.send.connection_id = pdu->pdu_connection->conn_socket;
1057
req.data.send.bhs = pdu->pdu_bhs;
1058
req.data.send.data_segment_len = pdu->pdu_data_len;
1059
req.data.send.data_segment = pdu->pdu_data;
1060
1061
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1062
log_err(1, "error issuing CTL_ISCSI ioctl; "
1063
"dropping connection");
1064
}
1065
1066
if (req.status != CTL_ISCSI_OK) {
1067
log_errx(1, "error returned from CTL iSCSI send: "
1068
"%s; dropping connection", req.error_str);
1069
}
1070
}
1071
1072
void
1073
kernel_receive(struct pdu *pdu)
1074
{
1075
struct connection *conn;
1076
struct ctl_iscsi req;
1077
1078
conn = pdu->pdu_connection;
1079
pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length);
1080
if (pdu->pdu_data == NULL)
1081
log_err(1, "malloc");
1082
1083
bzero(&req, sizeof(req));
1084
1085
req.type = CTL_ISCSI_RECEIVE;
1086
req.data.receive.connection_id = conn->conn_socket;
1087
req.data.receive.bhs = pdu->pdu_bhs;
1088
req.data.receive.data_segment_len =
1089
conn->conn_max_recv_data_segment_length;
1090
req.data.receive.data_segment = pdu->pdu_data;
1091
1092
if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) {
1093
log_err(1, "error issuing CTL_ISCSI ioctl; "
1094
"dropping connection");
1095
}
1096
1097
if (req.status != CTL_ISCSI_OK) {
1098
log_errx(1, "error returned from CTL iSCSI receive: "
1099
"%s; dropping connection", req.error_str);
1100
}
1101
1102
}
1103
1104
#endif /* ICL_KERNEL_PROXY */
1105
1106
/*
1107
* XXX: I CANT INTO LATIN
1108
*/
1109
void
1110
kernel_capsicate(void)
1111
{
1112
cap_rights_t rights;
1113
const unsigned long cmds[] = { CTL_ISCSI, CTL_NVMF };
1114
1115
cap_rights_init(&rights, CAP_IOCTL);
1116
if (caph_rights_limit(ctl_fd, &rights) < 0)
1117
log_err(1, "cap_rights_limit");
1118
1119
if (caph_ioctls_limit(ctl_fd, cmds, nitems(cmds)) < 0)
1120
log_err(1, "cap_ioctls_limit");
1121
1122
if (caph_enter() < 0)
1123
log_err(1, "cap_enter");
1124
1125
if (cap_sandboxed())
1126
log_debugx("Capsicum capability mode enabled");
1127
else
1128
log_warnx("Capsicum capability mode not supported");
1129
}
1130
1131
1132