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/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 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 using attr_list = std::list<std::pair<std::string, std::string>>; 112 113 struct cctl_lun { 114 uint64_t lun_id; 115 std::string backend_type; 116 uint8_t device_type; 117 uint64_t size_blocks; 118 uint32_t blocksize; 119 std::string serial_number; 120 std::string device_id; 121 std::string ctld_name; 122 attr_list attr_list; 123 }; 124 125 struct cctl_port { 126 uint32_t port_id; 127 std::string port_frontend; 128 std::string port_name; 129 int pp; 130 int vp; 131 int cfiscsi_state; 132 std::string cfiscsi_target; 133 uint16_t cfiscsi_portal_group_tag; 134 std::string ctld_portal_group_name; 135 attr_list attr_list; 136 }; 137 138 struct cctl_devlist_data { 139 std::list<cctl_lun> lun_list; 140 struct cctl_lun *cur_lun = nullptr; 141 std::list<cctl_port> port_list; 142 struct cctl_port *cur_port = nullptr; 143 u_int level = 0; 144 struct sbuf *cur_sb[32] = {}; 145 }; 146 147 static void 148 cctl_start_element(void *user_data, const char *name, const char **attr) 149 { 150 int i; 151 struct cctl_devlist_data *devlist; 152 struct cctl_lun *cur_lun; 153 154 devlist = (struct cctl_devlist_data *)user_data; 155 cur_lun = devlist->cur_lun; 156 devlist->level++; 157 if (devlist->level >= nitems(devlist->cur_sb)) 158 log_errx(1, "%s: too many nesting levels, %zu max", __func__, 159 nitems(devlist->cur_sb)); 160 161 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 162 if (devlist->cur_sb[devlist->level] == NULL) 163 log_err(1, "%s: unable to allocate sbuf", __func__); 164 165 if (strcmp(name, "lun") == 0) { 166 if (cur_lun != NULL) 167 log_errx(1, "%s: improper lun element nesting", 168 __func__); 169 170 devlist->lun_list.emplace_back(); 171 cur_lun = &devlist->lun_list.back(); 172 173 devlist->cur_lun = cur_lun; 174 175 for (i = 0; attr[i] != NULL; i += 2) { 176 if (strcmp(attr[i], "id") == 0) { 177 cur_lun->lun_id = strtoull(attr[i+1], NULL, 0); 178 } else { 179 log_errx(1, "%s: invalid LUN attribute %s = %s", 180 __func__, attr[i], attr[i+1]); 181 } 182 } 183 } 184 } 185 186 static void 187 cctl_end_element(void *user_data, const char *name) 188 { 189 struct cctl_devlist_data *devlist; 190 struct cctl_lun *cur_lun; 191 std::string str; 192 193 devlist = (struct cctl_devlist_data *)user_data; 194 cur_lun = devlist->cur_lun; 195 196 if ((cur_lun == NULL) 197 && (strcmp(name, "ctllunlist") != 0)) 198 log_errx(1, "%s: cur_lun == NULL! (name = %s)", __func__, name); 199 200 if (devlist->cur_sb[devlist->level] == NULL) 201 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 202 devlist->level, name); 203 204 sbuf_finish(devlist->cur_sb[devlist->level]); 205 str = sbuf_data(devlist->cur_sb[devlist->level]); 206 207 sbuf_delete(devlist->cur_sb[devlist->level]); 208 devlist->cur_sb[devlist->level] = NULL; 209 devlist->level--; 210 211 if (strcmp(name, "backend_type") == 0) { 212 cur_lun->backend_type = std::move(str); 213 } else if (strcmp(name, "lun_type") == 0) { 214 if (str.empty()) 215 log_errx(1, "%s: %s missing its argument", __func__, name); 216 cur_lun->device_type = strtoull(str.c_str(), NULL, 0); 217 } else if (strcmp(name, "size") == 0) { 218 if (str.empty()) 219 log_errx(1, "%s: %s missing its argument", __func__, name); 220 cur_lun->size_blocks = strtoull(str.c_str(), NULL, 0); 221 } else if (strcmp(name, "blocksize") == 0) { 222 if (str.empty()) 223 log_errx(1, "%s: %s missing its argument", __func__, name); 224 cur_lun->blocksize = strtoul(str.c_str(), NULL, 0); 225 } else if (strcmp(name, "serial_number") == 0) { 226 cur_lun->serial_number = std::move(str); 227 } else if (strcmp(name, "device_id") == 0) { 228 cur_lun->device_id = std::move(str); 229 } else if (strcmp(name, "ctld_name") == 0) { 230 cur_lun->ctld_name = std::move(str); 231 } else if (strcmp(name, "lun") == 0) { 232 devlist->cur_lun = NULL; 233 } else if (strcmp(name, "ctllunlist") == 0) { 234 /* Nothing. */ 235 } else { 236 cur_lun->attr_list.emplace_back(name, std::move(str)); 237 } 238 } 239 240 static void 241 cctl_start_pelement(void *user_data, const char *name, const char **attr) 242 { 243 int i; 244 struct cctl_devlist_data *devlist; 245 struct cctl_port *cur_port; 246 247 devlist = (struct cctl_devlist_data *)user_data; 248 cur_port = devlist->cur_port; 249 devlist->level++; 250 if (devlist->level >= nitems(devlist->cur_sb)) 251 log_errx(1, "%s: too many nesting levels, %zu max", __func__, 252 nitems(devlist->cur_sb)); 253 254 devlist->cur_sb[devlist->level] = sbuf_new_auto(); 255 if (devlist->cur_sb[devlist->level] == NULL) 256 log_err(1, "%s: unable to allocate sbuf", __func__); 257 258 if (strcmp(name, "targ_port") == 0) { 259 if (cur_port != NULL) 260 log_errx(1, "%s: improper port element nesting (%s)", 261 __func__, name); 262 263 devlist->port_list.emplace_back(); 264 cur_port = &devlist->port_list.back(); 265 devlist->cur_port = cur_port; 266 267 for (i = 0; attr[i] != NULL; i += 2) { 268 if (strcmp(attr[i], "id") == 0) { 269 cur_port->port_id = strtoul(attr[i+1], NULL, 0); 270 } else { 271 log_errx(1, "%s: invalid LUN attribute %s = %s", 272 __func__, attr[i], attr[i+1]); 273 } 274 } 275 } 276 } 277 278 static void 279 cctl_end_pelement(void *user_data, const char *name) 280 { 281 struct cctl_devlist_data *devlist; 282 struct cctl_port *cur_port; 283 std::string str; 284 285 devlist = (struct cctl_devlist_data *)user_data; 286 cur_port = devlist->cur_port; 287 288 if ((cur_port == NULL) 289 && (strcmp(name, "ctlportlist") != 0)) 290 log_errx(1, "%s: cur_port == NULL! (name = %s)", __func__, name); 291 292 if (devlist->cur_sb[devlist->level] == NULL) 293 log_errx(1, "%s: no valid sbuf at level %d (name %s)", __func__, 294 devlist->level, name); 295 296 sbuf_finish(devlist->cur_sb[devlist->level]); 297 str = sbuf_data(devlist->cur_sb[devlist->level]); 298 299 sbuf_delete(devlist->cur_sb[devlist->level]); 300 devlist->cur_sb[devlist->level] = NULL; 301 devlist->level--; 302 303 if (strcmp(name, "frontend_type") == 0) { 304 cur_port->port_frontend = std::move(str); 305 } else if (strcmp(name, "port_name") == 0) { 306 cur_port->port_name = std::move(str); 307 } else if (strcmp(name, "physical_port") == 0) { 308 if (str.empty()) 309 log_errx(1, "%s: %s missing its argument", __func__, name); 310 cur_port->pp = strtoul(str.c_str(), NULL, 0); 311 } else if (strcmp(name, "virtual_port") == 0) { 312 if (str.empty()) 313 log_errx(1, "%s: %s missing its argument", __func__, name); 314 cur_port->vp = strtoul(str.c_str(), NULL, 0); 315 } else if (strcmp(name, "cfiscsi_target") == 0) { 316 cur_port->cfiscsi_target = std::move(str); 317 } else if (strcmp(name, "cfiscsi_state") == 0) { 318 if (str.empty()) 319 log_errx(1, "%s: %s missing its argument", __func__, name); 320 cur_port->cfiscsi_state = strtoul(str.c_str(), NULL, 0); 321 } else if (strcmp(name, "cfiscsi_portal_group_tag") == 0) { 322 if (str.empty()) 323 log_errx(1, "%s: %s missing its argument", __func__, name); 324 cur_port->cfiscsi_portal_group_tag = strtoul(str.c_str(), NULL, 0); 325 } else if (strcmp(name, "ctld_portal_group_name") == 0) { 326 cur_port->ctld_portal_group_name = std::move(str); 327 } else if (strcmp(name, "targ_port") == 0) { 328 devlist->cur_port = NULL; 329 } else if (strcmp(name, "ctlportlist") == 0) { 330 /* Nothing. */ 331 } else { 332 cur_port->attr_list.emplace_back(name, std::move(str)); 333 } 334 } 335 336 static void 337 cctl_char_handler(void *user_data, const XML_Char *str, int len) 338 { 339 struct cctl_devlist_data *devlist; 340 341 devlist = (struct cctl_devlist_data *)user_data; 342 343 sbuf_bcat(devlist->cur_sb[devlist->level], str, len); 344 } 345 346 static bool 347 parse_kernel_config(struct cctl_devlist_data &devlist) 348 { 349 struct ctl_lun_list list; 350 XML_Parser parser; 351 int retval; 352 353 std::vector<char> buf(4096); 354 retry: 355 bzero(&list, sizeof(list)); 356 list.alloc_len = buf.size(); 357 list.status = CTL_LUN_LIST_NONE; 358 list.lun_xml = buf.data(); 359 360 if (ioctl(ctl_fd, CTL_LUN_LIST, &list) == -1) { 361 log_warn("error issuing CTL_LUN_LIST ioctl"); 362 return (false); 363 } 364 365 if (list.status == CTL_LUN_LIST_ERROR) { 366 log_warnx("error returned from CTL_LUN_LIST ioctl: %s", 367 list.error_str); 368 return (false); 369 } 370 371 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 372 buf.resize(buf.size() << 1); 373 goto retry; 374 } 375 376 parser = XML_ParserCreate(NULL); 377 if (parser == NULL) { 378 log_warnx("unable to create XML parser"); 379 return (false); 380 } 381 382 XML_SetUserData(parser, &devlist); 383 XML_SetElementHandler(parser, cctl_start_element, cctl_end_element); 384 XML_SetCharacterDataHandler(parser, cctl_char_handler); 385 386 retval = XML_Parse(parser, buf.data(), strlen(buf.data()), 1); 387 XML_ParserFree(parser); 388 if (retval != 1) { 389 log_warnx("XML_Parse failed"); 390 return (false); 391 } 392 393 retry_port: 394 bzero(&list, sizeof(list)); 395 list.alloc_len = buf.size(); 396 list.status = CTL_LUN_LIST_NONE; 397 list.lun_xml = buf.data(); 398 399 if (ioctl(ctl_fd, CTL_PORT_LIST, &list) == -1) { 400 log_warn("error issuing CTL_PORT_LIST ioctl"); 401 return (false); 402 } 403 404 if (list.status == CTL_LUN_LIST_ERROR) { 405 log_warnx("error returned from CTL_PORT_LIST ioctl: %s", 406 list.error_str); 407 return (false); 408 } 409 410 if (list.status == CTL_LUN_LIST_NEED_MORE_SPACE) { 411 buf.resize(buf.size() << 1); 412 goto retry_port; 413 } 414 415 parser = XML_ParserCreate(NULL); 416 if (parser == NULL) { 417 log_warnx("unable to create XML parser"); 418 return (false); 419 } 420 421 XML_SetUserData(parser, &devlist); 422 XML_SetElementHandler(parser, cctl_start_pelement, cctl_end_pelement); 423 XML_SetCharacterDataHandler(parser, cctl_char_handler); 424 425 retval = XML_Parse(parser, buf.data(), strlen(buf.data()), 1); 426 XML_ParserFree(parser); 427 if (retval != 1) { 428 log_warnx("XML_Parse failed"); 429 return (false); 430 } 431 432 return (true); 433 } 434 435 conf_up 436 conf_new_from_kernel(struct kports &kports) 437 { 438 struct cctl_devlist_data devlist; 439 440 log_debugx("obtaining previously configured CTL luns from the kernel"); 441 442 if (!parse_kernel_config(devlist)) 443 return {}; 444 445 conf_up conf = std::make_unique<struct conf>(); 446 447 for (const auto &port : devlist.port_list) { 448 if (port.port_frontend == "ha") 449 continue; 450 451 std::string name = port.port_name; 452 if (port.pp != 0) { 453 name += "/" + std::to_string(port.pp); 454 if (port.vp != 0) 455 name += "/" + std::to_string(port.vp); 456 } 457 458 if (port.cfiscsi_target.empty()) { 459 log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ", 460 port.port_id, name.c_str()); 461 if (!kports.has_port(name)) { 462 if (!kports.add_port(name, port.port_id)) { 463 log_warnx("kports::add_port failed"); 464 continue; 465 } 466 } 467 continue; 468 } 469 if (port.cfiscsi_state != 1) { 470 log_debugx("CTL port %ju is not active (%d); ignoring", 471 (uintmax_t)port.port_id, port.cfiscsi_state); 472 continue; 473 } 474 475 const char *t_name = port.cfiscsi_target.c_str(); 476 struct target *targ = conf->find_target(t_name); 477 if (targ == NULL) { 478 targ = conf->add_target(t_name); 479 if (targ == NULL) { 480 log_warnx("Failed to add target \"%s\"", 481 t_name); 482 continue; 483 } 484 } 485 486 if (port.ctld_portal_group_name.empty()) 487 continue; 488 const char *pg_name = port.ctld_portal_group_name.c_str(); 489 struct portal_group *pg = conf->find_portal_group(pg_name); 490 if (pg == NULL) { 491 pg = conf->add_portal_group(pg_name); 492 if (pg == NULL) { 493 log_warnx("Failed to add portal_group \"%s\"", 494 pg_name); 495 continue; 496 } 497 } 498 pg->set_tag(port.cfiscsi_portal_group_tag); 499 if (!conf->add_port(targ, pg, port.port_id)) { 500 log_warnx("Failed to add port for target \"%s\" and portal-group \"%s\"", 501 t_name, pg_name); 502 continue; 503 } 504 } 505 506 for (const auto &lun : devlist.lun_list) { 507 if (lun.ctld_name.empty()) { 508 log_debugx("CTL lun %ju wasn't managed by ctld; " 509 "ignoring", (uintmax_t)lun.lun_id); 510 continue; 511 } 512 513 const char *l_name = lun.ctld_name.c_str(); 514 struct lun *cl = conf->find_lun(l_name); 515 if (cl != NULL) { 516 log_warnx("found CTL lun %ju \"%s\", " 517 "also backed by CTL lun %d; ignoring", 518 (uintmax_t)lun.lun_id, l_name, 519 cl->ctl_lun()); 520 continue; 521 } 522 523 log_debugx("found CTL lun %ju \"%s\"", 524 (uintmax_t)lun.lun_id, l_name); 525 526 cl = conf->add_lun(l_name); 527 if (cl == NULL) { 528 log_warnx("lun_new failed"); 529 continue; 530 } 531 cl->set_backend(lun.backend_type.c_str()); 532 cl->set_device_type(lun.device_type); 533 cl->set_blocksize(lun.blocksize); 534 cl->set_device_id(lun.device_id.c_str()); 535 cl->set_serial(lun.serial_number.c_str()); 536 cl->set_size(lun.size_blocks * lun.blocksize); 537 cl->set_ctl_lun(lun.lun_id); 538 539 for (const auto &pair : lun.attr_list) { 540 const char *key = pair.first.c_str(); 541 const char *value = pair.second.c_str(); 542 if (pair.first == "file" || pair.first == "dev") { 543 cl->set_path(value); 544 continue; 545 } 546 if (!cl->add_option(key, value)) 547 log_warnx("unable to add CTL lun option " 548 "%s for CTL lun %ju \"%s\"", 549 key, (uintmax_t)lun.lun_id, 550 cl->name()); 551 } 552 } 553 554 return (conf); 555 } 556 557 bool 558 lun::kernel_add() 559 { 560 struct ctl_lun_req req; 561 int error; 562 563 bzero(&req, sizeof(req)); 564 565 strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend)); 566 req.reqtype = CTL_LUNREQ_CREATE; 567 568 req.reqdata.create.blocksize_bytes = l_blocksize; 569 570 if (l_size != 0) 571 req.reqdata.create.lun_size_bytes = l_size; 572 573 if (l_ctl_lun >= 0) { 574 req.reqdata.create.req_lun_id = l_ctl_lun; 575 req.reqdata.create.flags |= CTL_LUN_FLAG_ID_REQ; 576 } 577 578 req.reqdata.create.flags |= CTL_LUN_FLAG_DEV_TYPE; 579 req.reqdata.create.device_type = l_device_type; 580 581 if (!l_serial.empty()) { 582 strncpy((char *)req.reqdata.create.serial_num, l_serial.c_str(), 583 sizeof(req.reqdata.create.serial_num)); 584 req.reqdata.create.flags |= CTL_LUN_FLAG_SERIAL_NUM; 585 } 586 587 if (!l_device_id.empty()) { 588 strncpy((char *)req.reqdata.create.device_id, 589 l_device_id.c_str(), sizeof(req.reqdata.create.device_id)); 590 req.reqdata.create.flags |= CTL_LUN_FLAG_DEVID; 591 } 592 593 freebsd::nvlist_up nvl = options(); 594 req.args = nvlist_pack(nvl.get(), &req.args_len); 595 if (req.args == NULL) { 596 log_warn("error packing nvlist"); 597 return (false); 598 } 599 600 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 601 free(req.args); 602 603 if (error != 0) { 604 log_warn("error issuing CTL_LUN_REQ ioctl"); 605 return (false); 606 } 607 608 switch (req.status) { 609 case CTL_LUN_ERROR: 610 log_warnx("LUN creation error: %s", req.error_str); 611 return (false); 612 case CTL_LUN_WARNING: 613 log_warnx("LUN creation warning: %s", req.error_str); 614 break; 615 case CTL_LUN_OK: 616 break; 617 default: 618 log_warnx("unknown LUN creation status: %d", 619 req.status); 620 return (false); 621 } 622 623 l_ctl_lun = req.reqdata.create.req_lun_id; 624 return (true); 625 } 626 627 bool 628 lun::kernel_modify() const 629 { 630 struct ctl_lun_req req; 631 int error; 632 633 bzero(&req, sizeof(req)); 634 635 strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend)); 636 req.reqtype = CTL_LUNREQ_MODIFY; 637 638 req.reqdata.modify.lun_id = l_ctl_lun; 639 req.reqdata.modify.lun_size_bytes = l_size; 640 641 freebsd::nvlist_up nvl = options(); 642 req.args = nvlist_pack(nvl.get(), &req.args_len); 643 if (req.args == NULL) { 644 log_warn("error packing nvlist"); 645 return (false); 646 } 647 648 error = ioctl(ctl_fd, CTL_LUN_REQ, &req); 649 free(req.args); 650 651 if (error != 0) { 652 log_warn("error issuing CTL_LUN_REQ ioctl"); 653 return (false); 654 } 655 656 switch (req.status) { 657 case CTL_LUN_ERROR: 658 log_warnx("LUN modification error: %s", req.error_str); 659 return (false); 660 case CTL_LUN_WARNING: 661 log_warnx("LUN modification warning: %s", req.error_str); 662 break; 663 case CTL_LUN_OK: 664 break; 665 default: 666 log_warnx("unknown LUN modification status: %d", 667 req.status); 668 return (false); 669 } 670 671 return (true); 672 } 673 674 bool 675 lun::kernel_remove() const 676 { 677 struct ctl_lun_req req; 678 679 bzero(&req, sizeof(req)); 680 681 strlcpy(req.backend, l_backend.c_str(), sizeof(req.backend)); 682 req.reqtype = CTL_LUNREQ_RM; 683 684 req.reqdata.rm.lun_id = l_ctl_lun; 685 686 if (ioctl(ctl_fd, CTL_LUN_REQ, &req) == -1) { 687 log_warn("error issuing CTL_LUN_REQ ioctl"); 688 return (false); 689 } 690 691 switch (req.status) { 692 case CTL_LUN_ERROR: 693 log_warnx("LUN removal error: %s", req.error_str); 694 return (false); 695 case CTL_LUN_WARNING: 696 log_warnx("LUN removal warning: %s", req.error_str); 697 break; 698 case CTL_LUN_OK: 699 break; 700 default: 701 log_warnx("unknown LUN removal status: %d", req.status); 702 return (false); 703 } 704 705 return (true); 706 } 707 708 void 709 ctld_connection::kernel_handoff() 710 { 711 struct portal_group *pg = conn_portal->portal_group(); 712 struct ctl_iscsi req; 713 714 bzero(&req, sizeof(req)); 715 716 req.type = CTL_ISCSI_HANDOFF; 717 strlcpy(req.data.handoff.initiator_name, conn_initiator_name.c_str(), 718 sizeof(req.data.handoff.initiator_name)); 719 strlcpy(req.data.handoff.initiator_addr, conn_initiator_addr.c_str(), 720 sizeof(req.data.handoff.initiator_addr)); 721 if (!conn_initiator_alias.empty()) { 722 strlcpy(req.data.handoff.initiator_alias, 723 conn_initiator_alias.c_str(), 724 sizeof(req.data.handoff.initiator_alias)); 725 } 726 memcpy(req.data.handoff.initiator_isid, conn_initiator_isid, 727 sizeof(req.data.handoff.initiator_isid)); 728 strlcpy(req.data.handoff.target_name, conn_target->name(), 729 sizeof(req.data.handoff.target_name)); 730 strlcpy(req.data.handoff.offload, pg->offload(), 731 sizeof(req.data.handoff.offload)); 732 #ifdef ICL_KERNEL_PROXY 733 if (proxy_mode) 734 req.data.handoff.connection_id = conn.conn_socket; 735 else 736 req.data.handoff.socket = conn.conn_socket; 737 #else 738 req.data.handoff.socket = conn.conn_socket; 739 #endif 740 req.data.handoff.portal_group_tag = pg->tag(); 741 if (conn.conn_header_digest == CONN_DIGEST_CRC32C) 742 req.data.handoff.header_digest = CTL_ISCSI_DIGEST_CRC32C; 743 if (conn.conn_data_digest == CONN_DIGEST_CRC32C) 744 req.data.handoff.data_digest = CTL_ISCSI_DIGEST_CRC32C; 745 req.data.handoff.cmdsn = conn.conn_cmdsn; 746 req.data.handoff.statsn = conn.conn_statsn; 747 req.data.handoff.max_recv_data_segment_length = 748 conn.conn_max_recv_data_segment_length; 749 req.data.handoff.max_send_data_segment_length = 750 conn.conn_max_send_data_segment_length; 751 req.data.handoff.max_burst_length = conn.conn_max_burst_length; 752 req.data.handoff.first_burst_length = conn.conn_first_burst_length; 753 req.data.handoff.immediate_data = conn.conn_immediate_data; 754 755 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 756 log_err(1, "error issuing CTL_ISCSI ioctl; " 757 "dropping connection"); 758 } 759 760 if (req.status != CTL_ISCSI_OK) { 761 log_errx(1, "error returned from CTL iSCSI handoff request: " 762 "%s; dropping connection", req.error_str); 763 } 764 } 765 766 static 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 portal_group_port::kernel_create_port() 816 { 817 struct portal_group *pg = p_portal_group; 818 struct target *targ = p_target; 819 820 freebsd::nvlist_up nvl = pg->options(); 821 nvlist_add_string(nvl.get(), "cfiscsi_target", targ->name()); 822 nvlist_add_string(nvl.get(), "ctld_portal_group_name", pg->name()); 823 nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", 824 pg->tag()); 825 826 if (targ->has_alias()) { 827 nvlist_add_string(nvl.get(), "cfiscsi_target_alias", 828 targ->alias()); 829 } 830 831 return (ctl_create_port("iscsi", nvl.get(), &p_ctl_port)); 832 } 833 834 bool 835 ioctl_port::kernel_create_port() 836 { 837 freebsd::nvlist_up nvl(nvlist_create(0)); 838 nvlist_add_stringf(nvl.get(), "pp", "%d", p_ioctl_pp); 839 nvlist_add_stringf(nvl.get(), "vp", "%d", p_ioctl_vp); 840 841 return (ctl_create_port("ioctl", nvl.get(), &p_ctl_port)); 842 } 843 844 bool 845 kernel_port::kernel_create_port() 846 { 847 struct ctl_port_entry entry; 848 struct target *targ = p_target; 849 850 p_ctl_port = p_pport->ctl_port(); 851 852 if (strncmp(targ->name(), "naa.", 4) == 0 && 853 strlen(targ->name()) == 20) { 854 bzero(&entry, sizeof(entry)); 855 entry.port_type = CTL_PORT_NONE; 856 entry.targ_port = p_ctl_port; 857 entry.flags |= CTL_PORT_WWNN_VALID; 858 entry.wwnn = strtoull(targ->name() + 4, NULL, 16); 859 if (ioctl(ctl_fd, CTL_SET_PORT_WWNS, &entry) == -1) 860 log_warn("CTL_SET_PORT_WWNS ioctl failed"); 861 } 862 return (true); 863 } 864 865 bool 866 port::kernel_add() 867 { 868 struct ctl_port_entry entry; 869 struct ctl_lun_map lm; 870 struct target *targ = p_target; 871 int error, i; 872 873 if (!kernel_create_port()) 874 return (false); 875 876 /* Explicitly enable mapping to block any access except allowed. */ 877 lm.port = p_ctl_port; 878 lm.plun = UINT32_MAX; 879 lm.lun = 0; 880 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 881 if (error != 0) 882 log_warn("CTL_LUN_MAP ioctl failed"); 883 884 /* Map configured LUNs */ 885 for (i = 0; i < MAX_LUNS; i++) { 886 if (targ->lun(i) == nullptr) 887 continue; 888 lm.port = p_ctl_port; 889 lm.plun = i; 890 lm.lun = targ->lun(i)->ctl_lun(); 891 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 892 if (error != 0) 893 log_warn("CTL_LUN_MAP ioctl failed"); 894 } 895 896 /* Enable port */ 897 bzero(&entry, sizeof(entry)); 898 entry.targ_port = p_ctl_port; 899 error = ioctl(ctl_fd, CTL_ENABLE_PORT, &entry); 900 if (error != 0) { 901 log_warn("CTL_ENABLE_PORT ioctl failed"); 902 return (false); 903 } 904 905 return (true); 906 } 907 908 bool 909 port::kernel_update(const struct port *oport) 910 { 911 struct ctl_lun_map lm; 912 struct target *targ = p_target; 913 struct target *otarg = oport->p_target; 914 int error, i; 915 uint32_t olun; 916 917 p_ctl_port = oport->p_ctl_port; 918 919 /* Map configured LUNs and unmap others */ 920 for (i = 0; i < MAX_LUNS; i++) { 921 lm.port = p_ctl_port; 922 lm.plun = i; 923 if (targ->lun(i) == nullptr) 924 lm.lun = UINT32_MAX; 925 else 926 lm.lun = targ->lun(i)->ctl_lun(); 927 if (otarg->lun(i) == nullptr) 928 olun = UINT32_MAX; 929 else 930 olun = otarg->lun(i)->ctl_lun(); 931 if (lm.lun == olun) 932 continue; 933 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 934 if (error != 0) 935 log_warn("CTL_LUN_MAP ioctl failed"); 936 } 937 return (true); 938 } 939 940 bool 941 ctl_remove_port(const char *driver, nvlist_t *nvl) 942 { 943 struct ctl_req req; 944 int error; 945 946 strlcpy(req.driver, driver, sizeof(req.driver)); 947 req.reqtype = CTL_REQ_REMOVE; 948 req.args = nvlist_pack(nvl, &req.args_len); 949 if (req.args == NULL) { 950 log_warn("error packing nvlist"); 951 return (false); 952 } 953 954 error = ioctl(ctl_fd, CTL_PORT_REQ, &req); 955 free(req.args); 956 957 if (error != 0) { 958 log_warn("error issuing CTL_PORT_REQ ioctl"); 959 return (false); 960 } 961 if (req.status == CTL_LUN_ERROR) { 962 log_warnx("error returned from port removal request: %s", 963 req.error_str); 964 return (false); 965 } 966 if (req.status != CTL_LUN_OK) { 967 log_warnx("unknown port removal request status %d", req.status); 968 return (false); 969 } 970 return (true); 971 } 972 973 bool 974 portal_group_port::kernel_remove_port() 975 { 976 freebsd::nvlist_up nvl(nvlist_create(0)); 977 nvlist_add_string(nvl.get(), "cfiscsi_target", p_target->name()); 978 nvlist_add_stringf(nvl.get(), "cfiscsi_portal_group_tag", "%u", 979 p_portal_group->tag()); 980 981 return (ctl_remove_port("iscsi", nvl.get())); 982 } 983 984 bool 985 ioctl_port::kernel_remove_port() 986 { 987 freebsd::nvlist_up nvl(nvlist_create(0)); 988 nvlist_add_stringf(nvl.get(), "port_id", "%d", p_ctl_port); 989 990 return (ctl_remove_port("ioctl", nvl.get())); 991 } 992 993 bool 994 kernel_port::kernel_remove_port() 995 { 996 struct ctl_lun_map lm; 997 int error; 998 999 /* Disable LUN mapping. */ 1000 lm.port = p_ctl_port; 1001 lm.plun = UINT32_MAX; 1002 lm.lun = UINT32_MAX; 1003 error = ioctl(ctl_fd, CTL_LUN_MAP, &lm); 1004 if (error != 0) 1005 log_warn("CTL_LUN_MAP ioctl failed"); 1006 return (true); 1007 } 1008 1009 bool 1010 port::kernel_remove() 1011 { 1012 struct ctl_port_entry entry; 1013 int error; 1014 1015 /* Disable port */ 1016 bzero(&entry, sizeof(entry)); 1017 entry.targ_port = p_ctl_port; 1018 error = ioctl(ctl_fd, CTL_DISABLE_PORT, &entry); 1019 if (error != 0) { 1020 log_warn("CTL_DISABLE_PORT ioctl failed"); 1021 return (false); 1022 } 1023 1024 return (kernel_remove_port()); 1025 } 1026 1027 #ifdef ICL_KERNEL_PROXY 1028 void 1029 kernel_listen(struct addrinfo *ai, bool iser, int portal_id) 1030 { 1031 struct ctl_iscsi req; 1032 1033 bzero(&req, sizeof(req)); 1034 1035 req.type = CTL_ISCSI_LISTEN; 1036 req.data.listen.iser = iser; 1037 req.data.listen.domain = ai->ai_family; 1038 req.data.listen.socktype = ai->ai_socktype; 1039 req.data.listen.protocol = ai->ai_protocol; 1040 req.data.listen.addr = ai->ai_addr; 1041 req.data.listen.addrlen = ai->ai_addrlen; 1042 req.data.listen.portal_id = portal_id; 1043 1044 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1045 log_err(1, "error issuing CTL_ISCSI ioctl"); 1046 1047 if (req.status != CTL_ISCSI_OK) { 1048 log_errx(1, "error returned from CTL iSCSI listen: %s", 1049 req.error_str); 1050 } 1051 } 1052 1053 void 1054 kernel_accept(int *connection_id, int *portal_id, 1055 struct sockaddr *client_sa, socklen_t *client_salen) 1056 { 1057 struct ctl_iscsi req; 1058 struct sockaddr_storage ss; 1059 1060 bzero(&req, sizeof(req)); 1061 1062 req.type = CTL_ISCSI_ACCEPT; 1063 req.data.accept.initiator_addr = (struct sockaddr *)&ss; 1064 1065 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) 1066 log_err(1, "error issuing CTL_ISCSI ioctl"); 1067 1068 if (req.status != CTL_ISCSI_OK) { 1069 log_errx(1, "error returned from CTL iSCSI accept: %s", 1070 req.error_str); 1071 } 1072 1073 *connection_id = req.data.accept.connection_id; 1074 *portal_id = req.data.accept.portal_id; 1075 *client_salen = req.data.accept.initiator_addrlen; 1076 memcpy(client_sa, &ss, *client_salen); 1077 } 1078 1079 void 1080 kernel_send(struct pdu *pdu) 1081 { 1082 struct ctl_iscsi req; 1083 1084 bzero(&req, sizeof(req)); 1085 1086 req.type = CTL_ISCSI_SEND; 1087 req.data.send.connection_id = pdu->pdu_connection->conn_socket; 1088 req.data.send.bhs = pdu->pdu_bhs; 1089 req.data.send.data_segment_len = pdu->pdu_data_len; 1090 req.data.send.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 send: " 1099 "%s; dropping connection", req.error_str); 1100 } 1101 } 1102 1103 void 1104 kernel_receive(struct pdu *pdu) 1105 { 1106 struct connection *conn; 1107 struct ctl_iscsi req; 1108 1109 conn = pdu->pdu_connection; 1110 pdu->pdu_data = malloc(conn->conn_max_recv_data_segment_length); 1111 if (pdu->pdu_data == NULL) 1112 log_err(1, "malloc"); 1113 1114 bzero(&req, sizeof(req)); 1115 1116 req.type = CTL_ISCSI_RECEIVE; 1117 req.data.receive.connection_id = conn->conn_socket; 1118 req.data.receive.bhs = pdu->pdu_bhs; 1119 req.data.receive.data_segment_len = 1120 conn->conn_max_recv_data_segment_length; 1121 req.data.receive.data_segment = pdu->pdu_data; 1122 1123 if (ioctl(ctl_fd, CTL_ISCSI, &req) == -1) { 1124 log_err(1, "error issuing CTL_ISCSI ioctl; " 1125 "dropping connection"); 1126 } 1127 1128 if (req.status != CTL_ISCSI_OK) { 1129 log_errx(1, "error returned from CTL iSCSI receive: " 1130 "%s; dropping connection", req.error_str); 1131 } 1132 1133 } 1134 1135 #endif /* ICL_KERNEL_PROXY */ 1136 1137 /* 1138 * XXX: I CANT INTO LATIN 1139 */ 1140 void 1141 kernel_capsicate(void) 1142 { 1143 cap_rights_t rights; 1144 const unsigned long cmds[] = { CTL_ISCSI }; 1145 1146 cap_rights_init(&rights, CAP_IOCTL); 1147 if (caph_rights_limit(ctl_fd, &rights) < 0) 1148 log_err(1, "cap_rights_limit"); 1149 1150 if (caph_ioctls_limit(ctl_fd, cmds, nitems(cmds)) < 0) 1151 log_err(1, "cap_ioctls_limit"); 1152 1153 if (caph_enter() < 0) 1154 log_err(1, "cap_enter"); 1155 1156 if (cap_sandboxed()) 1157 log_debugx("Capsicum capability mode enabled"); 1158 else 1159 log_warnx("Capsicum capability mode not supported"); 1160 } 1161 1162