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 <jceel@FreeBSD.org> 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/ioctl.h> 44 #include <sys/linker.h> 45 #include <sys/module.h> 46 #include <sys/queue.h> 47 #include <sys/sbuf.h> 48 #include <sys/nv.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.h" 71 72 #ifdef ICL_KERNEL_PROXY 73 #include <netdb.h> 74 #endif 75 76 #define NVLIST_BUFSIZE 1024 77 78 extern bool proxy_mode; 79 80 int ctl_fd = 0; 81 82 void 83 kernel_init(void) 84 { 85 int retval, saved_errno; 86 87 ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 88 if (ctl_fd < 0 && errno == ENOENT) { 89 saved_errno = errno; 90 retval = kldload("ctl"); 91 if (retval != -1) 92 ctl_fd = open(CTL_DEFAULT_DEV, O_RDWR); 93 else 94 errno = saved_errno; 95 } 96 if (ctl_fd < 0) 97 log_err(1, "failed to open %s", CTL_DEFAULT_DEV); 98 #ifdef WANT_ISCSI 99 else { 100 saved_errno = errno; 101 if (modfind("cfiscsi") == -1 && kldload("cfiscsi") == -1) 102 log_warn("couldn't load cfiscsi"); 103 errno = saved_errno; 104 } 105 #endif 106 } 107 108 /* 109 * Backend LUN information. 110 */ 111 struct cctl_lun { 112 uint64_t lun_id; 113 char *backend_type; 114 uint8_t device_type; 115 uint64_t size_blocks; 116 uint32_t blocksize; 117 char *serial_number; 118 char *device_id; 119 char *ctld_name; 120 nvlist_t *attr_list; 121 STAILQ_ENTRY(cctl_lun) links; 122 }; 123 124 struct cctl_port { 125 uint32_t port_id; 126 char *port_frontend; 127 char *port_name; 128 int pp; 129 int vp; 130 int cfiscsi_state; 131 char *cfiscsi_target; 132 uint16_t cfiscsi_portal_group_tag; 133 char *ctld_portal_group_name; 134 nvlist_t *attr_list; 135 STAILQ_ENTRY(cctl_port) links; 136 }; 137 138 struct cctl_devlist_data { 139 int num_luns; 140 STAILQ_HEAD(,cctl_lun) lun_list; 141 struct cctl_lun *cur_lun; 142 int num_ports; 143 STAILQ_HEAD(,cctl_port) port_list; 144 struct cctl_port *cur_port; 145 int level; 146 struct sbuf *cur_sb[32]; 147 }; 148 149 static void 150 cctl_start_element(void *user_data, const char *name, const char **attr) 151 { 152 int i; 153 struct cctl_devlist_data *devlist; 154 struct cctl_lun *cur_lun; 155 156 devlist = (struct cctl_devlist_data *)user_data; 157 cur_lun = devlist->cur_lun; 158 devlist->level++; 159 if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) / 160 sizeof(devlist->cur_sb[0]))) 161 log_errx(1, "%s: too many nesting levels, %zd max", __func__, 162 nitems(devlist->cur_sb)); 163 164 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 165 if (devlist->cur_sb[devlist->level] == NULL) 166 log_err(1, "%s: unable to allocate sbuf", __func__); 167 168 if (strcmp(name, "lun") == 0) { 169 if (cur_lun != NULL) 170 log_errx(1, "%s: improper lun element nesting", 171 __func__); 172 173 cur_lun = reinterpret_cast<struct cctl_lun *>(calloc(1, sizeof(*cur_lun))); 174 if (cur_lun == NULL) 175 log_err(1, "%s: cannot allocate %zd bytes", __func__, 176 sizeof(*cur_lun)); 177 178 devlist->num_luns++; 179 devlist->cur_lun = cur_lun; 180 181 cur_lun->attr_list = nvlist_create(0); 182 STAILQ_INSERT_TAIL(&devlist->lun_list, cur_lun, links); 183 184 for (i = 0; attr[i] != NULL; i += 2) { 185 if (strcmp(attr[i], "id") == 0) { 186 cur_lun->lun_id = strtoull(attr[i+1], NULL, 0); 187 } else { 188 log_errx(1, "%s: invalid LUN attribute %s = %s", 189 __func__, attr[i], attr[i+1]); 190 } 191 } 192 } 193 } 194 195 static void 196 cctl_end_element(void *user_data, const char *name) 197 { 198 struct cctl_devlist_data *devlist; 199 struct cctl_lun *cur_lun; 200 char *str; 201 int error; 202 203 devlist = (struct cctl_devlist_data *)user_data; 204 cur_lun = devlist->cur_lun; 205 206 if ((cur_lun == NULL) 207 && (strcmp(name, "ctllunlist") != 0)) 208 log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name); 209 210 if (devlist->cur_sb[devlist->level] == NULL) 211 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 212 devlist->level, name); 213 214 sbuf_finish(devlist->cur_sb[devlist->level]); 215 str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level])); 216 217 if (strlen(str) == 0) { 218 free(str); 219 str = NULL; 220 } 221 222 sbuf_delete(devlist->cur_sb[devlist->level]); 223 devlist->cur_sb[devlist->level] = NULL; 224 devlist->level--; 225 226 if (strcmp(name, "backend_type") == 0) { 227 cur_lun->backend_type = str; 228 str = NULL; 229 } else if (strcmp(name, "lun_type") == 0) { 230 if (str == NULL) 231 log_errx(1, "%s: %s missing its argument", __func__, name); 232 cur_lun->device_type = strtoull(str, NULL, 0); 233 } else if (strcmp(name, "size") == 0) { 234 if (str == NULL) 235 log_errx(1, "%s: %s missing its argument", __func__, name); 236 cur_lun->size_blocks = strtoull(str, NULL, 0); 237 } else if (strcmp(name, "blocksize") == 0) { 238 if (str == NULL) 239 log_errx(1, "%s: %s missing its argument", __func__, name); 240 cur_lun->blocksize = strtoul(str, NULL, 0); 241 } else if (strcmp(name, "serial_number") == 0) { 242 cur_lun->serial_number = str; 243 str = NULL; 244 } else if (strcmp(name, "device_id") == 0) { 245 cur_lun->device_id = str; 246 str = NULL; 247 } else if (strcmp(name, "ctld_name") == 0) { 248 cur_lun->ctld_name = str; 249 str = NULL; 250 } else if (strcmp(name, "lun") == 0) { 251 devlist->cur_lun = NULL; 252 } else if (strcmp(name, "ctllunlist") == 0) { 253 /* Nothing. */ 254 } else { 255 nvlist_move_string(cur_lun->attr_list, name, str); 256 error = nvlist_error(cur_lun->attr_list); 257 if (error != 0) 258 log_errc(1, error, "%s: failed to add nv pair for %s", 259 __func__, name); 260 str = NULL; 261 } 262 263 free(str); 264 } 265 266 static void 267 cctl_start_pelement(void *user_data, const char *name, const char **attr) 268 { 269 int i; 270 struct cctl_devlist_data *devlist; 271 struct cctl_port *cur_port; 272 273 devlist = (struct cctl_devlist_data *)user_data; 274 cur_port = devlist->cur_port; 275 devlist->level++; 276 if ((u_int)devlist->level >= (sizeof(devlist->cur_sb) / 277 sizeof(devlist->cur_sb[0]))) 278 log_errx(1, "%s: too many nesting levels, %zd max", __func__, 279 nitems(devlist->cur_sb)); 280 281 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 282 if (devlist->cur_sb[devlist->level] == NULL) 283 log_err(1, "%s: unable to allocate sbuf", __func__); 284 285 if (strcmp(name, "targ_port") == 0) { 286 if (cur_port != NULL) 287 log_errx(1, "%s: improper port element nesting (%s)", 288 __func__, name); 289 290 cur_port = reinterpret_cast<struct cctl_port *>(calloc(1, sizeof(*cur_port))); 291 if (cur_port == NULL) 292 log_err(1, "%s: cannot allocate %zd bytes", __func__, 293 sizeof(*cur_port)); 294 295 devlist->num_ports++; 296 devlist->cur_port = cur_port; 297 298 cur_port->attr_list = nvlist_create(0); 299 STAILQ_INSERT_TAIL(&devlist->port_list, cur_port, links); 300 301 for (i = 0; attr[i] != NULL; i += 2) { 302 if (strcmp(attr[i], "id") == 0) { 303 cur_port->port_id = strtoul(attr[i+1], NULL, 0); 304 } else { 305 log_errx(1, "%s: invalid LUN attribute %s = %s", 306 __func__, attr[i], attr[i+1]); 307 } 308 } 309 } 310 } 311 312 static void 313 cctl_end_pelement(void *user_data, const char *name) 314 { 315 struct cctl_devlist_data *devlist; 316 struct cctl_port *cur_port; 317 char *str; 318 int error; 319 320 devlist = (struct cctl_devlist_data *)user_data; 321 cur_port = devlist->cur_port; 322 323 if ((cur_port == NULL) 324 && (strcmp(name, "ctlportlist") != 0)) 325 log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name); 326 327 if (devlist->cur_sb[devlist->level] == NULL) 328 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 329 devlist->level, name); 330 331 sbuf_finish(devlist->cur_sb[devlist->level]); 332 str = checked_strdup(sbuf_data(devlist->cur_sb[devlist->level])); 333 334 if (strlen(str) == 0) { 335 free(str); 336 str = NULL; 337 } 338 339 sbuf_delete(devlist->cur_sb[devlist->level]); 340 devlist->cur_sb[devlist->level] = NULL; 341 devlist->level--; 342 343 if (strcmp(name, "frontend_type") == 0) { 344 cur_port->port_frontend = str; 345 str = NULL; 346 } else if (strcmp(name, "port_name") == 0) { 347 cur_port->port_name = str; 348 str = NULL; 349 } else if (strcmp(name, "physical_port") == 0) { 350 if (str == NULL) 351 log_errx(1, "%s: %s missing its argument", __func__, name); 352 cur_port->pp = strtoul(str, NULL, 0); 353 } else if (strcmp(name, "virtual_port") == 0) { 354 if (str == NULL) 355 log_errx(1, "%s: %s missing its argument", __func__, name); 356 cur_port->vp = strtoul(str, NULL, 0); 357 } else if (strcmp(name, "cfiscsi_target") == 0) { 358 cur_port->cfiscsi_target = str; 359 str = NULL; 360 } else if (strcmp(name, "cfiscsi_state") == 0) { 361 if (str == NULL) 362 log_errx(1, "%s: %s missing its argument", __func__, name); 363 cur_port->cfiscsi_state = strtoul(str, NULL, 0); 364 } else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) { 365 if (str == NULL) 366 log_errx(1, "%s: %s missing its argument", __func__, name); 367 cur_port->cfiscsi_portal_group_tag = strtoul(str, NULL, 0); 368 } else if (strcmp(name, "ctld_portal_group_name") == 0) { 369 cur_port->ctld_portal_group_name = str; 370 str = NULL; 371 } else if (strcmp(name, "targ_port") == 0) { 372 devlist->cur_port = NULL; 373 } else if (strcmp(name, "ctlportlist") == 0) { 374 /* Nothing. */ 375 } else { 376 nvlist_move_string(cur_port->attr_list, name, str); 377 error = nvlist_error(cur_port->attr_list); 378 if (error != 0) 379 log_errc(1, error, "%s: failed to add nv pair for %s", 380 __func__, name); 381 str = NULL; 382 } 383 384 free(str); 385 } 386 387 static void 388 cctl_char_handler(void *user_data, const XML_Char *str, int len) 389 { 390 struct cctl_devlist_data *devlist; 391 392 devlist = (struct cctl_devlist_data *)user_data; 393 394 sbuf_bcat(devlist->cur_sb[devlist->level], str, len); 395 } 396 397 struct conf * 398 conf_new_from_kernel(struct kports *kports) 399 { 400 struct conf *conf = NULL; 401 struct target *targ; 402 struct portal_group *pg; 403 struct pport *pp; 404 struct port *cp; 405 struct lun *cl; 406 struct ctl_lun_list list; 407 struct cctl_devlist_data devlist; 408 struct cctl_lun *lun; 409 struct cctl_port *port; 410 XML_Parser parser; 411 const char *key; 412 char *str, *name; 413 void *cookie; 414 int error, len, retval; 415 416 bzero(&devlist, sizeof(devlist)); 417 STAILQ_INIT(&devlist.lun_list); 418 STAILQ_INIT(&devlist.port_list); 419 420 log_debugx("obtaining previously configured CTL luns from the kernel"); 421 422 str = NULL; 423 len = 4096; 424 retry: 425 str = reinterpret_cast<char *>(realloc(str, len)); 426 if (str == NULL) 427 log_err(1, "realloc"); 428 429 bzero(&list, sizeof(list)); 430 list.alloc_len = len; 431 list.status = CTL_LUN_LIST_NONE; 432 list.lun_xml = str; 433 434 if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) { 435 log_warn("error issuing CTL_LUN_LIST ioctl"); 436 free(str); 437 return (NULL); 438 } 439 440 if (list.status == CTL_LUN_LIST_ERROR) { 441 log_warnx("error returned from CTL_LUN_LIST ioctl: %s", 442 list.error_str); 443 free(str); 444 return (NULL); 445 } 446 447 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 448 len = len << 1; 449 goto retry; 450 } 451 452 parser = XML_ParserCreate(NULL); 453 if (parser == NULL) { 454 log_warnx("unable to create XML parser"); 455 free(str); 456 return (NULL); 457 } 458 459 XML_SetUserData(parser, &devlist); 460 XML_SetElementHandler(parser, cctl_start_element, cctl_end_element); 461 XML_SetCharacterDataHandler(parser, cctl_char_handler); 462 463 retval = XML_Parse(parser, str, strlen(str), 1); 464 XML_ParserFree(parser); 465 free(str); 466 if (retval != 1) { 467 log_warnx("XML_Parse failed"); 468 return (NULL); 469 } 470 471 str = NULL; 472 len = 4096; 473 retry_port: 474 str = reinterpret_cast<char *>(realloc(str, len)); 475 if (str == NULL) 476 log_err(1, "realloc"); 477 478 bzero(&list, sizeof(list)); 479 list.alloc_len = len; 480 list.status = CTL_LUN_LIST_NONE; 481 list.lun_xml = str; 482 483 if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) { 484 log_warn("error issuing CTL_PORT_LIST ioctl"); 485 free(str); 486 return (NULL); 487 } 488 489 if (list.status == CTL_LUN_LIST_ERROR) { 490 log_warnx("error returned from CTL_PORT_LIST ioctl: %s", 491 list.error_str); 492 free(str); 493 return (NULL); 494 } 495 496 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 497 len = len << 1; 498 goto retry_port; 499 } 500 501 parser = XML_ParserCreate(NULL); 502 if (parser == NULL) { 503 log_warnx("unable to create XML parser"); 504 free(str); 505 return (NULL); 506 } 507 508 XML_SetUserData(parser, &devlist); 509 XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement); 510 XML_SetCharacterDataHandler(parser, cctl_char_handler); 511 512 retval = XML_Parse(parser, str, strlen(str), 1); 513 XML_ParserFree(parser); 514 free(str); 515 if (retval != 1) { 516 log_warnx("XML_Parse failed"); 517 return (NULL); 518 } 519 520 conf = conf_new(); 521 522 name = NULL; 523 STAILQ_FOREACH(port, &devlist.port_list, links) { 524 if (strcmp(port->port_frontend, "ha") == 0) 525 continue; 526 free(name); 527 if (port->pp == 0 && port->vp == 0) { 528 name = checked_strdup(port->port_name); 529 } else if (port->vp == 0) { 530 retval = asprintf(&name, "%s/%d", 531 port->port_name, port->pp); 532 if (retval <= 0) 533 log_err(1, "asprintf"); 534 } else { 535 retval = asprintf(&name, "%s/%d/%d", 536 port->port_name, port->pp, port->vp); 537 if (retval <= 0) 538 log_err(1, "asprintf"); 539 } 540 541 if (port->cfiscsi_target == NULL) { 542 log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", 543 port->port_id, name); 544 pp = pport_find(kports, name); 545 if (pp == NULL) { 546 pp = pport_new(kports, name, port->port_id); 547 if (pp == NULL) { 548 log_warnx("pport_new failed"); 549 continue; 550 } 551 } 552 continue; 553 } 554 if (port->cfiscsi_state != 1) { 555 log_debugx("CTL port %ju is not active (%d); ignoring", 556 (uintmax_t)port->port_id, port->cfiscsi_state); 557 continue; 558 } 559 560 targ = target_find(conf, port->cfiscsi_target); 561 if (targ == NULL) { 562 targ = target_new(conf, port->cfiscsi_target); 563 if (targ == NULL) { 564 log_warnx("target_new failed"); 565 continue; 566 } 567 } 568 569 if (port->ctld_portal_group_name == NULL) 570 continue; 571 pg = portal_group_find(conf, port->ctld_portal_group_name); 572 if (pg == NULL) { 573 pg = portal_group_new(conf, port->ctld_portal_group_name); 574 if (pg == NULL) { 575 log_warnx("portal_group_new failed"); 576 continue; 577 } 578 } 579 pg->pg_tag = port->cfiscsi_portal_group_tag; 580 cp = port_new(conf, targ, pg); 581 if (cp == NULL) { 582 log_warnx("port_new failed"); 583 continue; 584 } 585 cp->p_ctl_port = port->port_id; 586 } 587 while ((port = STAILQ_FIRST(&devlist.port_list))) { 588 STAILQ_REMOVE_HEAD(&devlist.port_list, links); 589 free(port->port_frontend); 590 free(port->port_name); 591 free(port->cfiscsi_target); 592 free(port->ctld_portal_group_name); 593 nvlist_destroy(port->attr_list); 594 free(port); 595 } 596 free(name); 597 598 STAILQ_FOREACH(lun, &devlist.lun_list, links) { 599 if (lun->ctld_name == NULL) { 600 log_debugx("CTL lun %ju wasn't managed by ctld; " 601 "ignoring", (uintmax_t)lun->lun_id); 602 continue; 603 } 604 605 cl = lun_find(conf, lun->ctld_name); 606 if (cl != NULL) { 607 log_warnx("found CTL lun %ju \"%s\", " 608 "also backed by CTL lun %d; ignoring", 609 (uintmax_t)lun->lun_id, lun->ctld_name, 610 cl->l_ctl_lun); 611 continue; 612 } 613 614 log_debugx("found CTL lun %ju \"%s\"", 615 (uintmax_t)lun->lun_id, lun->ctld_name); 616 617 cl = lun_new(conf, lun->ctld_name); 618 if (cl == NULL) { 619 log_warnx("lun_new failed"); 620 continue; 621 } 622 cl->l_backend = lun->backend_type; 623 lun->backend_type = NULL; 624 cl->l_device_type = lun->device_type; 625 cl->l_blocksize = lun->blocksize; 626 cl->l_device_id = lun->device_id; 627 lun->device_id = NULL; 628 cl->l_serial = lun->serial_number; 629 lun->serial_number = NULL; 630 cl->l_size = lun->size_blocks * cl->l_blocksize; 631 cl->l_ctl_lun = lun->lun_id; 632 633 cookie = NULL; 634 while ((key = nvlist_next(lun->attr_list, NULL, &cookie)) != 635 NULL) { 636 if (strcmp(key, "file") == 0 || 637 strcmp(key, "dev") == 0) { 638 cl->l_path = nvlist_take_string(lun->attr_list, 639 key); 640 continue; 641 } 642 nvlist_add_string(cl->l_options, key, 643 nvlist_get_string(lun->attr_list, key)); 644 error = nvlist_error(cl->l_options); 645 if (error != 0) 646 log_warnc(error, "unable to add CTL lun option " 647 "%s for CTL lun %ju \"%s\"", 648 key, (uintmax_t)lun->lun_id, 649 cl->l_name); 650 } 651 } 652 while ((lun = STAILQ_FIRST(&devlist.lun_list))) { 653 STAILQ_REMOVE_HEAD(&devlist.lun_list, links); 654 nvlist_destroy(lun->attr_list); 655 free(lun); 656 } 657 658 return (conf); 659 } 660 661 static void 662 nvlist_replace_string(nvlist_t *nvl, const char *name, const char *value) 663 { 664 if (nvlist_exists_string(nvl, name)) 665 nvlist_free_string(nvl, name); 666 nvlist_add_string(nvl, name, value); 667 } 668 669 int 670 kernel_lun_add(struct lun *lun) 671 { 672 struct ctl_lun_req req; 673 int error; 674 675 bzero(&req, sizeof(req)); 676 677 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 678 req.reqtype = CTL_LUNREQ_CREATE; 679 680 req.reqdata.create.blocksize_bytes = lun->l_blocksize; 681 682 if (lun->l_size != 0) 683 req.reqdata.create.lun_size_bytes = lun->l_size; 684 685 if (lun->l_ctl_lun >= 0) { 686 req.reqdata.create.req_lun_id = lun->l_ctl_lun; 687 req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ; 688 } 689 690 req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE; 691 req.reqdata.create.device_type = lun->l_device_type; 692 693 if (lun->l_serial != NULL) { 694 strncpy((char *)req.reqdata.create.serial_num, lun->l_serial, 695 sizeof(req.reqdata.create.serial_num)); 696 req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM; 697 } 698 699 if (lun->l_device_id != NULL) { 700 strncpy((char *)req.reqdata.create.device_id, lun->l_device_id, 701 sizeof(req.reqdata.create.device_id)); 702 req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; 703 } 704 705 if (lun->l_path != NULL) 706 nvlist_replace_string(lun->l_options, "file", lun->l_path); 707 708 nvlist_replace_string(lun->l_options, "ctld_name", lun->l_name); 709 710 if (!nvlist_exists_string(lun->l_options, "scsiname") && 711 lun->l_scsiname != NULL) 712 nvlist_add_string(lun->l_options, "scsiname", lun->l_scsiname); 713 714 if (!nvlist_empty(lun->l_options)) { 715 req.args = nvlist_pack(lun->l_options, &req.args_len); 716 if (req.args == NULL) { 717 log_warn("error packing nvlist"); 718 return (1); 719 } 720 } 721 722 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 723 free(req.args); 724 725 if (error != 0) { 726 log_warn("error issuing CTL_LUN_REQ ioctl"); 727 return (1); 728 } 729 730 switch (req.status) { 731 case CTL_LUN_ERROR: 732 log_warnx("LUN creation error: %s", req.error_str); 733 return (1); 734 case CTL_LUN_WARNING: 735 log_warnx("LUN creation warning: %s", req.error_str); 736 break; 737 case CTL_LUN_OK: 738 break; 739 default: 740 log_warnx("unknown LUN creation status: %d", 741 req.status); 742 return (1); 743 } 744 745 lun->l_ctl_lun = req.reqdata.create.req_lun_id; 746 return (0); 747 } 748 749 int 750 kernel_lun_modify(struct lun *lun) 751 { 752 struct ctl_lun_req req; 753 int error; 754 755 bzero(&req, sizeof(req)); 756 757 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 758 req.reqtype = CTL_LUNREQ_MODIFY; 759 760 req.reqdata.modify.lun_id = lun->l_ctl_lun; 761 req.reqdata.modify.lun_size_bytes = lun->l_size; 762 763 if (lun->l_path != NULL) 764 nvlist_replace_string(lun->l_options, "file", lun->l_path); 765 766 nvlist_replace_string(lun->l_options, "ctld_name", lun->l_name); 767 768 if (!nvlist_exists_string(lun->l_options, "scsiname") && 769 lun->l_scsiname != NULL) 770 nvlist_add_string(lun->l_options, "scsiname", lun->l_scsiname); 771 772 if (!nvlist_empty(lun->l_options)) { 773 req.args = nvlist_pack(lun->l_options, &req.args_len); 774 if (req.args == NULL) { 775 log_warn("error packing nvlist"); 776 return (1); 777 } 778 } 779 780 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 781 free(req.args); 782 783 if (error != 0) { 784 log_warn("error issuing CTL_LUN_REQ ioctl"); 785 return (1); 786 } 787 788 switch (req.status) { 789 case CTL_LUN_ERROR: 790 log_warnx("LUN modification error: %s", req.error_str); 791 return (1); 792 case CTL_LUN_WARNING: 793 log_warnx("LUN modification warning: %s", req.error_str); 794 break; 795 case CTL_LUN_OK: 796 break; 797 default: 798 log_warnx("unknown LUN modification status: %d", 799 req.status); 800 return (1); 801 } 802 803 return (0); 804 } 805 806 int 807 kernel_lun_remove(struct lun *lun) 808 { 809 struct ctl_lun_req req; 810 811 bzero(&req, sizeof(req)); 812 813 strlcpy(req.backend, lun->l_backend, sizeof(req.backend)); 814 req.reqtype = CTL_LUNREQ_RM; 815 816 req.reqdata.rm.lun_id = lun->l_ctl_lun; 817 818 if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { 819 log_warn("error issuing CTL_LUN_REQ ioctl"); 820 return (1); 821 } 822 823 switch (req.status) { 824 case CTL_LUN_ERROR: 825 log_warnx("LUN removal error: %s", req.error_str); 826 return (1); 827 case CTL_LUN_WARNING: 828 log_warnx("LUN removal warning: %s", req.error_str); 829 break; 830 case CTL_LUN_OK: 831 break; 832 default: 833 log_warnx("unknown LUN removal status: %d", req.status); 834 return (1); 835 } 836 837 return (0); 838 } 839 840 void 841 kernel_handoff(struct ctld_connection *conn) 842 { 843 struct ctl_iscsi req; 844 845 bzero(&req, sizeof(req)); 846 847 req.type = CTL_ISCSI_HANDOFF; 848 strlcpy(req.data.handoff.initiator_name, 849 conn->conn_initiator_name, sizeof(req.data.handoff.initiator_name)); 850 strlcpy(req.data.handoff.initiator_addr, 851 conn->conn_initiator_addr, sizeof(req.data.handoff.initiator_addr)); 852 if (conn->conn_initiator_alias != NULL) { 853 strlcpy(req.data.handoff.initiator_alias, 854 conn->conn_initiator_alias, sizeof(req.data.handoff.initiator_alias)); 855 } 856 memcpy(req.data.handoff.initiator_isid, conn->conn_initiator_isid, 857 sizeof(req.data.handoff.initiator_isid)); 858 strlcpy(req.data.handoff.target_name, 859 conn->conn_target->t_name, sizeof(req.data.handoff.target_name)); 860 if (conn->conn_portal->p_portal_group->pg_offload != NULL) { 861 strlcpy(req.data.handoff.offload, 862 conn->conn_portal->p_portal_group->pg_offload, 863 sizeof(req.data.handoff.offload)); 864 } 865 #ifdef ICL_KERNEL_PROXY 866 if (proxy_mode) 867 req.data.handoff.connection_id = conn->conn.conn_socket; 868 else 869 req.data.handoff.socket = conn->conn.conn_socket; 870 #else 871 req.data.handoff.socket = conn->conn.conn_socket; 872 #endif 873 req.data.handoff.portal_group_tag = 874 conn->conn_portal->p_portal_group->pg_tag; 875 if (conn->conn.conn_header_digest == CONN_DIGEST_CRC32C) 876 req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; 877 if (conn->conn.conn_data_digest == CONN_DIGEST_CRC32C) 878 req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; 879 req.data.handoff.cmdsn = conn->conn.conn_cmdsn; 880 req.data.handoff.statsn = conn->conn.conn_statsn; 881 req.data.handoff.max_recv_data_segment_length = 882 conn->conn.conn_max_recv_data_segment_length; 883 req.data.handoff.max_send_data_segment_length = 884 conn->conn.conn_max_send_data_segment_length; 885 req.data.handoff.max_burst_length = conn->conn.conn_max_burst_length; 886 req.data.handoff.first_burst_length = 887 conn->conn.conn_first_burst_length; 888 req.data.handoff.immediate_data = conn->conn.conn_immediate_data; 889 890 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 891 log_err(1, "error issuing CTL_ISCSI ioctl; " 892 "dropping connection"); 893 } 894 895 if (req.status != CTL_ISCSI_OK) { 896 log_errx(1, "error returned from CTL iSCSI handoff request: " 897 "%s; dropping connection", req.error_str); 898 } 899 } 900 901 int 902 kernel_port_add(struct port *port) 903 { 904 struct ctl_port_entry entry; 905 struct ctl_req req; 906 struct ctl_lun_map lm; 907 struct target *targ = port->p_target; 908 struct portal_group *pg = port->p_portal_group; 909 char result_buf[NVLIST_BUFSIZE]; 910 int error, i; 911 912 /* Create iSCSI port. */ 913 if (port->p_portal_group || port->p_ioctl_port) { 914 bzero(&req, sizeof(req)); 915 req.reqtype = CTL_REQ_CREATE; 916 917 if (port->p_portal_group) { 918 strlcpy(req.driver, "iscsi", sizeof(req.driver)); 919 req.args_nvl = nvlist_clone(pg->pg_options); 920 nvlist_add_string(req.args_nvl, "cfiscsi_target", 921 targ->t_name); 922 nvlist_add_string(req.args_nvl, 923 "ctld_portal_group_name", pg->pg_name); 924 nvlist_add_stringf(req.args_nvl, 925 "cfiscsi_portal_group_tag", "%u", pg->pg_tag); 926 927 if (targ->t_alias) { 928 nvlist_add_string(req.args_nvl, 929 "cfiscsi_target_alias", targ->t_alias); 930 } 931 } 932 933 if (port->p_ioctl_port) { 934 strlcpy(req.driver, "ioctl", sizeof(req.driver)); 935 req.args_nvl = nvlist_create(0); 936 nvlist_add_stringf(req.args_nvl, "pp", "%d", 937 port->p_ioctl_pp); 938 nvlist_add_stringf(req.args_nvl, "vp", "%d", 939 port->p_ioctl_vp); 940 } 941 942 req.args = nvlist_pack(req.args_nvl, &req.args_len); 943 if (req.args == NULL) { 944 nvlist_destroy(req.args_nvl); 945 log_warn("error packing nvlist"); 946 return (1); 947 } 948 949 req.result = result_buf; 950 req.result_len = sizeof(result_buf); 951 error = ioctl(ctl_fd, CTL_PORT_REQ, &req); 952 free(req.args); 953 nvlist_destroy(req.args_nvl); 954 955 if (error != 0) { 956 log_warn("error issuing CTL_PORT_REQ ioctl"); 957 return (1); 958 } 959 if (req.status == CTL_LUN_ERROR) { 960 log_warnx("error returned from port creation request: %s", 961 req.error_str); 962 return (1); 963 } 964 if (req.status != CTL_LUN_OK) { 965 log_warnx("unknown port creation request status %d", 966 req.status); 967 return (1); 968 } 969 970 req.result_nvl = nvlist_unpack(result_buf, req.result_len, 0); 971 if (req.result_nvl == NULL) { 972 log_warnx("error unpacking result nvlist"); 973 return (1); 974 } 975 976 port->p_ctl_port = nvlist_get_number(req.result_nvl, "port_id"); 977 nvlist_destroy(req.result_nvl); 978 } else if (port->p_pport) { 979 port->p_ctl_port = port->p_pport->pp_ctl_port; 980 981 if (strncmp(targ->t_name, "naa.", 4) == 0 && 982 strlen(targ->t_name) == 20) { 983 bzero(&entry, sizeof(entry)); 984 entry.port_type = CTL_PORT_NONE; 985 entry.targ_port = port->p_ctl_port; 986 entry.flags |= CTL_PORT_WWNN_VALID; 987 entry.wwnn = strtoull(targ->t_name + 4, NULL, 16); 988 if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1) 989 log_warn("CTL_SET_PORT_WWNS ioctl failed"); 990 } 991 } 992 993 /* Explicitly enable mapping to block any access except allowed. */ 994 lm.port = port->p_ctl_port; 995 lm.plun = UINT32_MAX; 996 lm.lun = 0; 997 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 998 if (error != 0) 999 log_warn("CTL_LUN_MAP ioctl failed"); 1000 1001 /* Map configured LUNs */ 1002 for (i = 0; i < MAX_LUNS; i++) { 1003 if (targ->t_luns[i] == NULL) 1004 continue; 1005 lm.port = port->p_ctl_port; 1006 lm.plun = i; 1007 lm.lun = targ->t_luns[i]->l_ctl_lun; 1008 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1009 if (error != 0) 1010 log_warn("CTL_LUN_MAP ioctl failed"); 1011 } 1012 1013 /* Enable port */ 1014 bzero(&entry, sizeof(entry)); 1015 entry.targ_port = port->p_ctl_port; 1016 error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry); 1017 if (error != 0) { 1018 log_warn("CTL_ENABLE_PORT ioctl failed"); 1019 return (-1); 1020 } 1021 1022 return (0); 1023 } 1024 1025 int 1026 kernel_port_update(struct port *port, struct port *oport) 1027 { 1028 struct ctl_lun_map lm; 1029 struct target *targ = port->p_target; 1030 struct target *otarg = oport->p_target; 1031 int error, i; 1032 uint32_t olun; 1033 1034 /* Map configured LUNs and unmap others */ 1035 for (i = 0; i < MAX_LUNS; i++) { 1036 lm.port = port->p_ctl_port; 1037 lm.plun = i; 1038 if (targ->t_luns[i] == NULL) 1039 lm.lun = UINT32_MAX; 1040 else 1041 lm.lun = targ->t_luns[i]->l_ctl_lun; 1042 if (otarg->t_luns[i] == NULL) 1043 olun = UINT32_MAX; 1044 else 1045 olun = otarg->t_luns[i]->l_ctl_lun; 1046 if (lm.lun == olun) 1047 continue; 1048 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1049 if (error != 0) 1050 log_warn("CTL_LUN_MAP ioctl failed"); 1051 } 1052 return (0); 1053 } 1054 1055 int 1056 kernel_port_remove(struct port *port) 1057 { 1058 struct ctl_port_entry entry; 1059 struct ctl_lun_map lm; 1060 struct ctl_req req; 1061 struct target *targ = port->p_target; 1062 struct portal_group *pg = port->p_portal_group; 1063 int error; 1064 1065 /* Disable port */ 1066 bzero(&entry, sizeof(entry)); 1067 entry.targ_port = port->p_ctl_port; 1068 error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); 1069 if (error != 0) { 1070 log_warn("CTL_DISABLE_PORT ioctl failed"); 1071 return (-1); 1072 } 1073 1074 /* Remove iSCSI or ioctl port. */ 1075 if (port->p_portal_group || port->p_ioctl_port) { 1076 bzero(&req, sizeof(req)); 1077 strlcpy(req.driver, port->p_ioctl_port ? "ioctl" : "iscsi", 1078 sizeof(req.driver)); 1079 req.reqtype = CTL_REQ_REMOVE; 1080 req.args_nvl = nvlist_create(0); 1081 if (req.args_nvl == NULL) 1082 log_err(1, "nvlist_create"); 1083 1084 if (port->p_ioctl_port) 1085 nvlist_add_stringf(req.args_nvl, "port_id", "%d", 1086 port->p_ctl_port); 1087 else { 1088 nvlist_add_string(req.args_nvl, "cfiscsi_target", 1089 targ->t_name); 1090 nvlist_add_stringf(req.args_nvl, 1091 "cfiscsi_portal_group_tag", "%u", pg->pg_tag); 1092 } 1093 1094 req.args = nvlist_pack(req.args_nvl, &req.args_len); 1095 if (req.args == NULL) { 1096 nvlist_destroy(req.args_nvl); 1097 log_warn("error packing nvlist"); 1098 return (1); 1099 } 1100 1101 error = ioctl(ctl_fd, CTL_PORT_REQ, &req); 1102 free(req.args); 1103 nvlist_destroy(req.args_nvl); 1104 1105 if (error != 0) { 1106 log_warn("error issuing CTL_PORT_REQ ioctl"); 1107 return (1); 1108 } 1109 if (req.status == CTL_LUN_ERROR) { 1110 log_warnx("error returned from port removal request: %s", 1111 req.error_str); 1112 return (1); 1113 } 1114 if (req.status != CTL_LUN_OK) { 1115 log_warnx("unknown port removal request status %d", 1116 req.status); 1117 return (1); 1118 } 1119 } else { 1120 /* Disable LUN mapping. */ 1121 lm.port = port->p_ctl_port; 1122 lm.plun = UINT32_MAX; 1123 lm.lun = UINT32_MAX; 1124 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1125 if (error != 0) 1126 log_warn("CTL_LUN_MAP ioctl failed"); 1127 } 1128 return (0); 1129 } 1130 1131 #ifdef ICL_KERNEL_PROXY 1132 void 1133 kernel_listen(struct addrinfo *ai, bool iser, int portal_id) 1134 { 1135 struct ctl_iscsi req; 1136 1137 bzero(&req, sizeof(req)); 1138 1139 req.type = CTL_ISCSI_LISTEN; 1140 req.data.listen.iser = iser; 1141 req.data.listen.domain = ai->ai_family; 1142 req.data.listen.socktype = ai->ai_socktype; 1143 req.data.listen.protocol = ai->ai_protocol; 1144 req.data.listen.addr = ai->ai_addr; 1145 req.data.listen.addrlen = ai->ai_addrlen; 1146 req.data.listen.portal_id = portal_id; 1147 1148 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1149 log_err(1, "error issuing CTL_ISCSI ioctl"); 1150 1151 if (req.status != CTL_ISCSI_OK) { 1152 log_errx(1, "error returned from CTL iSCSI listen: %s", 1153 req.error_str); 1154 } 1155 } 1156 1157 void 1158 kernel_accept(int *connection_id, int *portal_id, 1159 struct sockaddr *client_sa, socklen_t *client_salen) 1160 { 1161 struct ctl_iscsi req; 1162 struct sockaddr_storage ss; 1163 1164 bzero(&req, sizeof(req)); 1165 1166 req.type = CTL_ISCSI_ACCEPT; 1167 req.data.accept.initiator_addr = (struct sockaddr *)&ss; 1168 1169 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1170 log_err(1, "error issuing CTL_ISCSI ioctl"); 1171 1172 if (req.status != CTL_ISCSI_OK) { 1173 log_errx(1, "error returned from CTL iSCSI accept: %s", 1174 req.error_str); 1175 } 1176 1177 *connection_id = req.data.accept.connection_id; 1178 *portal_id = req.data.accept.portal_id; 1179 *client_salen = req.data.accept.initiator_addrlen; 1180 memcpy(client_sa, &ss, *client_salen); 1181 } 1182 1183 void 1184 kernel_send(struct pdu *pdu) 1185 { 1186 struct ctl_iscsi req; 1187 1188 bzero(&req, sizeof(req)); 1189 1190 req.type = CTL_ISCSI_SEND; 1191 req.data.send.connection_id = pdu->pdu_connection->conn_socket; 1192 req.data.send.bhs = pdu->pdu_bhs; 1193 req.data.send.data_segment_len = pdu->pdu_data_len; 1194 req.data.send.data_segment = pdu->pdu_data; 1195 1196 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1197 log_err(1, "error issuing CTL_ISCSI ioctl; " 1198 "dropping connection"); 1199 } 1200 1201 if (req.status != CTL_ISCSI_OK) { 1202 log_errx(1, "error returned from CTL iSCSI send: " 1203 "%s; dropping connection", req.error_str); 1204 } 1205 } 1206 1207 void 1208 kernel_receive(struct pdu *pdu) 1209 { 1210 struct connection *conn; 1211 struct ctl_iscsi req; 1212 1213 conn = pdu->pdu_connection; 1214 pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length); 1215 if (pdu->pdu_data == NULL) 1216 log_err(1, "malloc"); 1217 1218 bzero(&req, sizeof(req)); 1219 1220 req.type = CTL_ISCSI_RECEIVE; 1221 req.data.receive.connection_id = conn->conn_socket; 1222 req.data.receive.bhs = pdu->pdu_bhs; 1223 req.data.receive.data_segment_len = 1224 conn->conn_max_recv_data_segment_length; 1225 req.data.receive.data_segment = pdu->pdu_data; 1226 1227 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1228 log_err(1, "error issuing CTL_ISCSI ioctl; " 1229 "dropping connection"); 1230 } 1231 1232 if (req.status != CTL_ISCSI_OK) { 1233 log_errx(1, "error returned from CTL iSCSI receive: " 1234 "%s; dropping connection", req.error_str); 1235 } 1236 1237 } 1238 1239 #endif /* ICL_KERNEL_PROXY */ 1240 1241 /* 1242 * XXX: I CANT INTO LATIN 1243 */ 1244 void 1245 kernel_capsicate(void) 1246 { 1247 cap_rights_t rights; 1248 const unsigned long cmds[] = { CTL_ISCSI }; 1249 1250 cap_rights_init(&rights, CAP_IOCTL); 1251 if (caph_rights_limit(ctl_fd, &rights) < 0) 1252 log_err(1, "cap_rights_limit"); 1253 1254 if (caph_ioctls_limit(ctl_fd, cmds, nitems(cmds)) < 0) 1255 log_err(1, "cap_ioctls_limit"); 1256 1257 if (caph_enter() < 0) 1258 log_err(1, "cap_enter"); 1259 1260 if (cap_sandboxed()) 1261 log_debugx("Capsicum capability mode enabled"); 1262 else 1263 log_warnx("Capsicum capability mode not supported"); 1264 } 1265 1266