1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2015 Joyent, Inc. 14 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 15 */ 16 17 #include <libdladm_impl.h> 18 #include <libdllink.h> 19 #include <libdloverlay.h> 20 #include <sys/dld.h> 21 #include <sys/overlay.h> 22 #include <strings.h> 23 #include <unistd.h> 24 #include <stdlib.h> 25 #include <errno.h> 26 #include <netinet/in.h> 27 #include <arpa/inet.h> 28 #include <limits.h> 29 #include <libscf.h> 30 #include <libvarpd_client.h> 31 32 #define VARPD_PROPERTY_NAME "varpd/id" 33 #define VARPD_SERVICE "network/varpd:default" 34 35 static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door"; 36 37 static boolean_t 38 varpd_svc_isonline(void) 39 { 40 boolean_t isonline = B_FALSE; 41 char *s; 42 43 if ((s = smf_get_state(VARPD_SERVICE)) != NULL) { 44 if (strcmp(s, SCF_STATE_STRING_ONLINE) == 0) 45 isonline = B_TRUE; 46 free(s); 47 } 48 49 return (isonline); 50 } 51 52 #define MAX_WAIT_TIME 15 53 54 static dladm_status_t 55 varpd_enable_service(void) 56 { 57 uint_t i; 58 59 if (varpd_svc_isonline()) 60 return (DLADM_STATUS_OK); 61 62 if (smf_enable_instance(VARPD_SERVICE, 0) == -1) { 63 if (scf_error() == SCF_ERROR_PERMISSION_DENIED) 64 return (DLADM_STATUS_DENIED); 65 return (DLADM_STATUS_NOTFOUND); 66 } 67 68 /* 69 * Wait up to MAX_WAIT_TIME seconds for the service 70 */ 71 for (i = 0; i < MAX_WAIT_TIME; i++) { 72 if (varpd_svc_isonline()) 73 return (DLADM_STATUS_OK); 74 (void) sleep(1); 75 } 76 return (DLADM_STATUS_FAILED); 77 } 78 79 static int 80 dladm_overlay_count_cb(dladm_handle_t handle __unused, 81 datalink_id_t linkid __unused, void *arg) 82 { 83 (*(uint32_t *)arg)++; 84 return (DLADM_WALK_CONTINUE); 85 } 86 87 /* 88 * Disable the varpd service if there are no overlays left. 89 */ 90 static void 91 varpd_disable_service_when_no_overlays(dladm_handle_t handle) 92 { 93 uint32_t cnt = 0; 94 95 /* 96 * Get the number of the existing overlays. If there are no overlays 97 * left, disable the service. 98 */ 99 100 (void) dladm_walk_datalink_id(dladm_overlay_count_cb, handle, 101 &cnt, DATALINK_CLASS_OVERLAY, DATALINK_ANY_MEDIATYPE, 102 DLADM_OPT_ACTIVE); 103 104 if (cnt == 0) 105 (void) smf_disable_instance(VARPD_SERVICE, 0); 106 } 107 108 typedef struct dladm_overlay_propinfo { 109 boolean_t dop_isvarpd; 110 union { 111 overlay_ioc_propinfo_t *dop_overlay; 112 varpd_client_prop_handle_t *dop_varpd; 113 } dop_un; 114 } dladm_overlay_propinfo_t; 115 116 dladm_status_t 117 dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl, 118 const char **namep, uint_t *typep, uint_t *protp, const void **defp, 119 uint32_t *sizep, const mac_propval_range_t **possp) 120 { 121 dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl; 122 overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay; 123 124 if (infop->dop_isvarpd == B_FALSE) { 125 if (namep != NULL) 126 *namep = oinfop->oipi_name; 127 if (typep != NULL) 128 *typep = oinfop->oipi_type; 129 if (protp != NULL) 130 *protp = oinfop->oipi_prot; 131 if (defp != NULL) 132 *defp = oinfop->oipi_default; 133 if (sizep != NULL) 134 *sizep = oinfop->oipi_defsize; 135 if (possp != NULL) { 136 *possp = (const mac_propval_range_t *)oinfop->oipi_poss; 137 } 138 139 } else { 140 int ret; 141 ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep, 142 typep, protp, defp, sizep, possp); 143 if (ret != 0) 144 return (dladm_errno2status(ret)); 145 146 } 147 148 return (DLADM_STATUS_OK); 149 } 150 151 static dladm_status_t 152 dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep, 153 const char *val) 154 { 155 int ret; 156 int64_t ival; 157 uint64_t uval; 158 char *eptr; 159 struct in6_addr ipv6; 160 struct in_addr ip; 161 162 switch (type) { 163 case OVERLAY_PROP_T_INT: 164 errno = 0; 165 ival = strtol(val, &eptr, 10); 166 if ((ival == 0 && errno == EINVAL) || 167 ((ival == LONG_MAX || ival == LONG_MIN) && 168 errno == ERANGE)) 169 return (DLADM_STATUS_BADARG); 170 bcopy(&ival, buf, sizeof (int64_t)); 171 *sizep = sizeof (int64_t); 172 break; 173 case OVERLAY_PROP_T_UINT: 174 errno = 0; 175 uval = strtol(val, &eptr, 10); 176 if ((uval == 0 && errno == EINVAL) || 177 (uval == ULONG_MAX && errno == ERANGE)) 178 return (DLADM_STATUS_BADARG); 179 bcopy(&uval, buf, sizeof (uint64_t)); 180 *sizep = sizeof (uint64_t); 181 break; 182 case OVERLAY_PROP_T_STRING: 183 ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX); 184 if (ret >= OVERLAY_PROP_SIZEMAX) 185 return (DLADM_STATUS_BADARG); 186 *sizep = ret + 1; 187 break; 188 case OVERLAY_PROP_T_IP: 189 /* 190 * Always try to parse the IP as an IPv6 address. If that fails, 191 * try to interpret it as an IPv4 address and transform it into 192 * an IPv6 mapped IPv4 address. 193 */ 194 if (inet_pton(AF_INET6, val, &ipv6) != 1) { 195 if (inet_pton(AF_INET, val, &ip) != 1) 196 return (DLADM_STATUS_BADARG); 197 198 IN6_INADDR_TO_V4MAPPED(&ip, &ipv6); 199 } 200 bcopy(&ipv6, buf, sizeof (struct in6_addr)); 201 *sizep = sizeof (struct in6_addr); 202 break; 203 default: 204 abort(); 205 } 206 207 return (DLADM_STATUS_OK); 208 } 209 210 static dladm_status_t 211 i_dladm_overlay_setprop_db(dladm_handle_t handle, datalink_id_t linkid, 212 const char *name, char *const *valp, uint_t cnt) 213 { 214 dladm_conf_t conf; 215 dladm_status_t status; 216 217 if (linkid == DATALINK_INVALID_LINKID || 218 name == NULL || valp == NULL || cnt != 1) { 219 return (DLADM_STATUS_BADARG); 220 } 221 222 status = dladm_open_conf(handle, linkid, &conf); 223 if (status != DLADM_STATUS_OK) 224 return (status); 225 226 status = dladm_set_conf_field(handle, conf, name, DLADM_TYPE_STR, 227 valp[0]); 228 if (status == DLADM_STATUS_OK) 229 status = dladm_write_conf(handle, conf); 230 231 dladm_destroy_conf(handle, conf); 232 return (status); 233 } 234 235 static dladm_status_t 236 dladm_overlay_varpd_setprop(dladm_handle_t handle __unused, 237 varpd_client_handle_t *chdl, uint64_t inst, datalink_id_t linkid __unused, 238 const char *name, char *const *valp, uint_t cnt __unused) 239 { 240 int ret; 241 uint32_t size; 242 uint8_t buf[LIBVARPD_PROP_SIZEMAX]; 243 varpd_client_prop_handle_t *phdl; 244 uint_t type; 245 dladm_status_t status; 246 247 if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0) 248 return (dladm_errno2status(ret)); 249 250 if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) { 251 libvarpd_c_prop_handle_free(phdl); 252 return (dladm_errno2status(ret)); 253 } 254 255 if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL, 256 NULL)) != 0) { 257 libvarpd_c_prop_handle_free(phdl); 258 return (dladm_errno2status(ret)); 259 } 260 261 if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) != 262 DLADM_STATUS_OK) { 263 libvarpd_c_prop_handle_free(phdl); 264 return (status); 265 } 266 267 status = DLADM_STATUS_OK; 268 ret = libvarpd_c_prop_set(phdl, buf, size); 269 libvarpd_c_prop_handle_free(phdl); 270 if (ret != 0) 271 status = dladm_errno2status(ret); 272 273 if (status != DLADM_STATUS_OK) 274 return (status); 275 276 return (status); 277 } 278 279 static dladm_status_t 280 dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid, 281 const char *name, char *const *valp, uint_t cnt) 282 { 283 int ret; 284 dladm_status_t status; 285 overlay_ioc_propinfo_t info; 286 overlay_ioc_prop_t prop; 287 288 if (linkid == DATALINK_INVALID_LINKID || 289 name == NULL || valp == NULL || cnt != 1) 290 return (DLADM_STATUS_BADARG); 291 292 bzero(&info, sizeof (overlay_ioc_propinfo_t)); 293 info.oipi_linkid = linkid; 294 info.oipi_id = -1; 295 if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >= 296 OVERLAY_PROP_NAMELEN) 297 return (DLADM_STATUS_BADARG); 298 299 status = DLADM_STATUS_OK; 300 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info); 301 if (ret != 0) 302 status = dladm_errno2status(errno); 303 304 if (status != DLADM_STATUS_OK) 305 return (status); 306 307 prop.oip_linkid = linkid; 308 prop.oip_id = info.oipi_id; 309 prop.oip_name[0] = '\0'; 310 if ((status = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value, 311 &prop.oip_size, valp[0])) != DLADM_STATUS_OK) 312 return (status); 313 314 status = DLADM_STATUS_OK; 315 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop); 316 if (ret != 0) 317 status = dladm_errno2status(errno); 318 319 if (status != DLADM_STATUS_OK) 320 return (status); 321 322 return (status); 323 } 324 325 /* 326 * Tell the user about any unset required properties. 327 */ 328 static int 329 dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid, 330 dladm_overlay_propinfo_handle_t phdl, void *arg) 331 { 332 dladm_status_t status; 333 uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; 334 uint_t prot; 335 size_t size = sizeof (buf); 336 const char *name; 337 dladm_errlist_t *errs = arg; 338 339 if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL, 340 NULL, NULL)) != DLADM_STATUS_OK) 341 return (status); 342 343 if ((prot & OVERLAY_PROP_PERM_REQ) == 0) 344 return (DLADM_WALK_CONTINUE); 345 346 if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) != 347 DLADM_STATUS_OK) 348 return (DLADM_WALK_CONTINUE); 349 350 if (size == 0) 351 (void) dladm_errlist_append(errs, "unset required property: %s", 352 name); 353 354 return (DLADM_WALK_CONTINUE); 355 } 356 357 /* 358 * We need to clean up the world here. The problem is that we may or may not 359 * actually have everything created. While in the normal case, we'd always have 360 * an overlay device, assigned datalink id, and a varpd instance, we might not 361 * have any of those, except for the datalink instance. Therefore, as long as 362 * the id refers to a valid overlay, we should try to clean up as much of the 363 * state as possible and most importantly, we need to make sure we delete the 364 * datalink id. If we fail to do that, then that name will become lost to time. 365 */ 366 dladm_status_t 367 dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid, 368 uint32_t flags) 369 { 370 datalink_class_t class; 371 overlay_ioc_delete_t oid; 372 varpd_client_handle_t *chdl; 373 int ret; 374 uint64_t varpdid; 375 376 if (dladm_datalink_id2info(handle, linkid, NULL, &class, NULL, 377 NULL, 0) != DLADM_STATUS_OK) { 378 return (DLADM_STATUS_BADARG); 379 } 380 381 if (class != DATALINK_CLASS_OVERLAY) 382 return (DLADM_STATUS_BADARG); 383 384 oid.oid_linkid = linkid; 385 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid); 386 if (ret != 0 && errno != ENOENT) { 387 return (dladm_errno2status(errno)); 388 } 389 390 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) { 391 return (dladm_errno2status(ret)); 392 } 393 394 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 395 if (ret == ENOENT) { 396 goto finish; 397 } 398 (void) libvarpd_c_destroy(chdl); 399 return (dladm_errno2status(ret)); 400 } 401 402 ret = libvarpd_c_instance_destroy(chdl, varpdid); 403 finish: 404 (void) libvarpd_c_destroy(chdl); 405 if ((flags & DLADM_OPT_PERSIST) != 0) { 406 (void) dladm_remove_conf(handle, linkid); 407 (void) dladm_destroy_datalink_id(handle, linkid, flags); 408 } 409 410 (void) varpd_disable_service_when_no_overlays(handle); 411 412 return (dladm_errno2status(ret)); 413 } 414 415 dladm_status_t 416 dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid, 417 dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep) 418 { 419 int ret; 420 overlay_ioc_prop_t oip; 421 dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl; 422 423 /* 424 * It'd be nice if we had a better or more specific error for this. If 425 * this kind of error becomes common place, let's get a better dladm 426 * error. 427 */ 428 if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX) 429 return (dladm_errno2status(ERANGE)); 430 431 if (infop->dop_isvarpd == B_FALSE) { 432 bzero(&oip, sizeof (overlay_ioc_prop_t)); 433 oip.oip_linkid = linkid; 434 oip.oip_id = infop->dop_un.dop_overlay->oipi_id; 435 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip); 436 if (ret != 0) 437 return (dladm_errno2status(errno)); 438 bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX); 439 *sizep = oip.oip_size; 440 } else { 441 uint32_t size = *sizep; 442 443 ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size); 444 if (ret != 0) 445 return (dladm_errno2status(errno)); 446 *sizep = size; 447 } 448 449 return (DLADM_STATUS_OK); 450 } 451 452 static dladm_status_t 453 dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid, 454 uint64_t varpdid, dladm_overlay_prop_f func, void *arg) 455 { 456 int ret, i; 457 varpd_client_handle_t *chdl; 458 varpd_client_prop_handle_t *phdl; 459 uint_t nprops; 460 dladm_status_t status; 461 462 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 463 return (dladm_errno2status(ret)); 464 465 if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) { 466 (void) libvarpd_c_destroy(chdl); 467 return (dladm_errno2status(ret)); 468 } 469 470 if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) { 471 libvarpd_c_prop_handle_free(phdl); 472 (void) libvarpd_c_destroy(chdl); 473 return (dladm_errno2status(ret)); 474 } 475 476 status = DLADM_STATUS_OK; 477 for (i = 0; i < nprops; i++) { 478 dladm_overlay_propinfo_t dop; 479 480 bzero(&dop, sizeof (dop)); 481 dop.dop_isvarpd = B_TRUE; 482 dop.dop_un.dop_varpd = phdl; 483 484 if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) { 485 status = dladm_errno2status(ret); 486 break; 487 } 488 489 ret = func(handle, linkid, 490 (dladm_overlay_propinfo_handle_t)&dop, arg); 491 if (ret == DLADM_WALK_TERMINATE) 492 break; 493 } 494 495 libvarpd_c_prop_handle_free(phdl); 496 libvarpd_c_destroy(chdl); 497 498 return (status); 499 } 500 501 dladm_status_t 502 dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid, 503 dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs) 504 { 505 int i, ret; 506 char buf[MAXLINKNAMELEN]; 507 char errmsg[DLADM_STRSIZE]; 508 datalink_class_t class; 509 dladm_status_t info_status; 510 overlay_ioc_nprops_t oin; 511 overlay_ioc_propinfo_t oipi; 512 dladm_overlay_propinfo_t dop; 513 uint64_t varpdid = UINT64_MAX; 514 515 if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class, 516 NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 517 (void) dladm_errlist_append(errs, "failed to get info for " 518 "datalink id %u: %s", 519 linkid, dladm_status2str(info_status, errmsg)); 520 return (DLADM_STATUS_BADARG); 521 } 522 523 if (class != DATALINK_CLASS_OVERLAY) { 524 (void) dladm_errlist_append(errs, "%s is not an overlay", buf); 525 return (DLADM_STATUS_BADARG); 526 } 527 528 bzero(&oin, sizeof (overlay_ioc_nprops_t)); 529 oin.oipn_linkid = linkid; 530 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin); 531 if (ret != 0) { 532 (void) dladm_errlist_append(errs, "failed to get " 533 "overlay properties for overlay %s: %s", 534 buf, strerror(errno)); 535 return (dladm_errno2status(errno)); 536 } 537 538 for (i = 0; i < oin.oipn_nprops; i++) { 539 bzero(&dop, sizeof (dladm_overlay_propinfo_t)); 540 bzero(&oipi, sizeof (overlay_ioc_propinfo_t)); 541 oipi.oipi_linkid = linkid; 542 oipi.oipi_id = i; 543 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi); 544 if (ret != 0) { 545 (void) dladm_errlist_append(errs, "failed to get " 546 "propinfo for overlay %s, property %d: %s", 547 buf, i, strerror(errno)); 548 return (dladm_errno2status(errno)); 549 } 550 551 dop.dop_isvarpd = B_FALSE; 552 dop.dop_un.dop_overlay = &oipi; 553 ret = func(handle, linkid, 554 (dladm_overlay_propinfo_handle_t)&dop, arg); 555 if (ret == DLADM_WALK_TERMINATE) 556 break; 557 558 if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) { 559 uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; 560 size_t bufsize = sizeof (buf); 561 uint64_t *vp; 562 563 if (dladm_overlay_get_prop(handle, linkid, 564 (dladm_overlay_propinfo_handle_t)&dop, buf, 565 &bufsize) != DLADM_STATUS_OK) 566 continue; 567 568 vp = (uint64_t *)buf; 569 varpdid = *vp; 570 } 571 } 572 573 /* Should this really be possible? */ 574 if (varpdid == UINT64_MAX) 575 return (DLADM_STATUS_OK); 576 577 ret = dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func, 578 arg); 579 if (ret != DLADM_STATUS_OK) { 580 (void) dladm_errlist_append(errs, 581 "failed to get varpd props for " 582 "overlay %s, varpd id %llu: %s", 583 buf, varpdid, dladm_status2str(info_status, errmsg)); 584 } 585 return (ret); 586 } 587 588 static dladm_status_t 589 dladm_overlay_persist_config(dladm_handle_t handle, dladm_overlay_attr_t *attr) 590 { 591 dladm_conf_t conf; 592 dladm_status_t status; 593 594 if ((status = dladm_create_conf(handle, attr->oa_name, attr->oa_linkid, 595 DATALINK_CLASS_OVERLAY, DL_ETHER, &conf)) != DLADM_STATUS_OK) { 596 return (status); 597 } 598 599 status = dladm_set_conf_field(handle, conf, FVNETID, 600 DLADM_TYPE_UINT64, &attr->oa_vid); 601 if (status != DLADM_STATUS_OK) 602 goto done; 603 604 status = dladm_set_conf_field(handle, conf, FENCAP, 605 DLADM_TYPE_STR, attr->oa_encap); 606 if (status != DLADM_STATUS_OK) 607 goto done; 608 609 status = dladm_set_conf_field(handle, conf, FSEARCH, 610 DLADM_TYPE_STR, attr->oa_search); 611 if (status != DLADM_STATUS_OK) 612 goto done; 613 614 status = dladm_write_conf(handle, conf); 615 616 done: 617 dladm_destroy_conf(handle, conf); 618 return (status); 619 } 620 621 static dladm_status_t 622 i_dladm_overlay_create_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr) 623 { 624 overlay_ioc_create_t oic; 625 dladm_status_t status; 626 int ret; 627 628 bzero(&oic, sizeof (oic)); 629 oic.oic_linkid = attr->oa_linkid; 630 oic.oic_vnetid = attr->oa_vid; 631 (void) strlcpy(oic.oic_encap, attr->oa_encap, MAXLINKNAMELEN); 632 633 status = DLADM_STATUS_OK; 634 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic); 635 if (ret != 0) { 636 /* 637 * It'd be nice if we had private errors so we could better 638 * distinguish between different classes of errors. 639 */ 640 status = dladm_errno2status(errno); 641 } 642 643 return (status); 644 } 645 646 static dladm_status_t 647 i_dladm_overlay_commit_sys(dladm_handle_t handle, dladm_overlay_attr_t *attr, 648 dladm_arg_list_t *props, dladm_errlist_t *errs) 649 { 650 overlay_ioc_activate_t oia; 651 varpd_client_handle_t *vch; 652 dladm_status_t status; 653 size_t slen; 654 uint64_t id; 655 int ret; 656 uint_t i; 657 658 slen = strlen(attr->oa_search); 659 for (i = 0; props != NULL && i < props->al_count; i++) { 660 dladm_arg_info_t *aip = &props->al_info[i]; 661 662 /* 663 * If it's a property for the search plugin, eg. it has the 664 * prefix '<search>/', then we don't set the property on the 665 * overlay device and instead set it on the varpd instance. 666 */ 667 if (strncmp(aip->ai_name, attr->oa_search, slen) == 0 && 668 aip->ai_name[slen] == '/') 669 continue; 670 status = dladm_overlay_setprop(handle, attr->oa_linkid, 671 aip->ai_name, aip->ai_val, aip->ai_count); 672 if (status != DLADM_STATUS_OK) { 673 (void) dladm_errlist_append(errs, 674 "failed to set property %s", aip->ai_name); 675 return (status); 676 } 677 678 if (attr->oa_flags & DLADM_OPT_PERSIST) { 679 status = i_dladm_overlay_setprop_db(handle, 680 attr->oa_linkid, aip->ai_name, aip->ai_val, 681 aip->ai_count); 682 if (status != DLADM_STATUS_OK) { 683 (void) dladm_errlist_append(errs, 684 "failed to persistently set property %s", 685 aip->ai_name); 686 return (status); 687 } 688 } 689 } 690 691 if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) { 692 (void) dladm_errlist_append(errs, 693 "failed to create libvarpd handle: %s", strerror(ret)); 694 return (dladm_errno2status(ret)); 695 } 696 697 if ((ret = libvarpd_c_instance_create(vch, attr->oa_linkid, 698 attr->oa_search, &id)) != 0) { 699 (void) dladm_errlist_append(errs, 700 "failed to create varpd instance: %s", strerror(ret)); 701 libvarpd_c_destroy(vch); 702 return (dladm_errno2status(ret)); 703 } 704 705 for (i = 0; props != NULL && i < props->al_count; i++) { 706 dladm_arg_info_t *aip = &props->al_info[i]; 707 708 /* 709 * Skip arguments we've processed already. 710 */ 711 if (strncmp(aip->ai_name, attr->oa_search, slen) != 0 || 712 aip->ai_name[slen] != '/') 713 continue; 714 715 ret = dladm_overlay_varpd_setprop(handle, vch, id, 716 attr->oa_linkid, aip->ai_name, aip->ai_val, aip->ai_count); 717 if (ret != 0) { 718 (void) dladm_errlist_append(errs, 719 "failed to set varpd prop: %s\n", aip->ai_name); 720 (void) libvarpd_c_instance_destroy(vch, id); 721 libvarpd_c_destroy(vch); 722 return (dladm_errno2status(ret)); 723 } 724 725 if (attr->oa_flags & DLADM_OPT_PERSIST) { 726 status = i_dladm_overlay_setprop_db(handle, 727 attr->oa_linkid, aip->ai_name, aip->ai_val, 728 aip->ai_count); 729 if (status != DLADM_STATUS_OK) { 730 (void) dladm_errlist_append(errs, "failed to " 731 "persistently set varpd prop: %s\n", 732 aip->ai_name); 733 (void) libvarpd_c_instance_destroy(vch, id); 734 libvarpd_c_destroy(vch); 735 return (status); 736 } 737 } 738 } 739 740 if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) { 741 (void) dladm_errlist_append(errs, 742 "failed to activate varpd instance: %s", strerror(ret)); 743 (void) dladm_overlay_walk_varpd_prop(handle, attr->oa_linkid, 744 id, dladm_overlay_activate_cb, errs); 745 (void) libvarpd_c_instance_destroy(vch, id); 746 libvarpd_c_destroy(vch); 747 return (dladm_errno2status(ret)); 748 749 } 750 751 bzero(&oia, sizeof (oia)); 752 oia.oia_linkid = attr->oa_linkid; 753 status = DLADM_STATUS_OK; 754 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia); 755 if (ret != 0) { 756 ret = errno; 757 (void) dladm_errlist_append(errs, "failed to activate " 758 "device: %s", strerror(ret)); 759 (void) libvarpd_c_instance_destroy(vch, id); 760 (void) dladm_overlay_walk_prop(handle, attr->oa_linkid, 761 dladm_overlay_activate_cb, errs, errs); 762 status = dladm_errno2status(ret); 763 } 764 765 libvarpd_c_destroy(vch); 766 767 return (status); 768 } 769 770 dladm_status_t 771 dladm_overlay_create(dladm_handle_t handle, const char *name, 772 const char *encap, const char *search, uint64_t vid, 773 dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags) 774 { 775 dladm_status_t status; 776 datalink_id_t linkid; 777 dladm_overlay_attr_t attr; 778 char errmsg[DLADM_STRSIZE]; 779 780 if (strlcpy(attr.oa_name, name, sizeof (attr.oa_name)) >= 781 sizeof (attr.oa_name)) { 782 return (DLADM_STATUS_BADARG); 783 } 784 if (strlcpy(attr.oa_encap, encap, sizeof (attr.oa_encap)) >= 785 sizeof (attr.oa_encap)) { 786 return (DLADM_STATUS_BADARG); 787 } 788 if (strlcpy(attr.oa_search, search, sizeof (attr.oa_search)) >= 789 sizeof (attr.oa_search)) { 790 return (DLADM_STATUS_BADARG); 791 } 792 793 status = varpd_enable_service(); 794 if (status != DLADM_STATUS_OK) 795 return (status); 796 797 status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY, 798 DL_ETHER, flags, &linkid); 799 if (status != DLADM_STATUS_OK) 800 return (status); 801 802 attr.oa_linkid = linkid; 803 attr.oa_vid = vid; 804 attr.oa_flags = flags; 805 806 status = i_dladm_overlay_create_sys(handle, &attr); 807 808 if (status != DLADM_STATUS_OK) { 809 (void) dladm_destroy_datalink_id(handle, linkid, flags); 810 return (status); 811 } 812 813 if ((flags & DLADM_OPT_PERSIST) != 0) { 814 status = dladm_overlay_persist_config(handle, &attr); 815 if (status != DLADM_STATUS_OK) { 816 (void) dladm_errlist_append(errs, "failed to create " 817 "persistent configuration for %s: %s", 818 attr.oa_name, dladm_status2str(status, errmsg)); 819 } 820 } 821 822 if (status == DLADM_STATUS_OK) 823 status = i_dladm_overlay_commit_sys(handle, &attr, props, errs); 824 825 if (status != DLADM_STATUS_OK) { 826 (void) dladm_overlay_delete(handle, linkid, flags); 827 (void) dladm_destroy_datalink_id(handle, linkid, flags); 828 } 829 830 return (status); 831 } 832 833 typedef struct overlay_walk_cb { 834 dladm_handle_t owc_handle; 835 datalink_id_t owc_linkid; 836 void *owc_arg; 837 dladm_overlay_cache_f owc_func; 838 uint_t owc_mode; 839 uint_t owc_dest; 840 } overlay_walk_cb_t; 841 842 static int 843 dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl __unused, 844 uint64_t varpdid __unused, const struct ether_addr *key, 845 const varpd_client_cache_entry_t *entry, void *arg) 846 { 847 overlay_walk_cb_t *owc = arg; 848 dladm_overlay_point_t point; 849 850 bzero(&point, sizeof (dladm_overlay_point_t)); 851 point.dop_dest = owc->owc_dest; 852 point.dop_mac = entry->vcp_mac; 853 point.dop_flags = entry->vcp_flags; 854 point.dop_ip = entry->vcp_ip; 855 point.dop_port = entry->vcp_port; 856 857 if (owc->owc_mode == OVERLAY_TARGET_POINT) 858 point.dop_flags |= DLADM_OVERLAY_F_DEFAULT; 859 860 if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point, 861 owc->owc_arg) == DLADM_WALK_TERMINATE) 862 return (1); 863 return (0); 864 } 865 866 dladm_status_t 867 dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid, 868 dladm_overlay_cache_f func, void *arg) 869 { 870 int ret; 871 uint_t mode, dest; 872 uint64_t varpdid; 873 varpd_client_handle_t *chdl; 874 overlay_walk_cb_t cbarg; 875 876 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 877 return (dladm_errno2status(ret)); 878 879 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 880 libvarpd_c_destroy(chdl); 881 return (dladm_errno2status(ret)); 882 } 883 884 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 885 &dest, &mode)) != 0) { 886 libvarpd_c_destroy(chdl); 887 return (dladm_errno2status(ret)); 888 } 889 890 cbarg.owc_handle = handle; 891 cbarg.owc_linkid = linkid; 892 cbarg.owc_arg = arg; 893 cbarg.owc_func = func; 894 cbarg.owc_dest = dest; 895 cbarg.owc_mode = mode; 896 ret = libvarpd_c_instance_cache_walk(chdl, varpdid, 897 dladm_overlay_walk_cache_cb, &cbarg); 898 libvarpd_c_destroy(chdl); 899 900 return (dladm_errno2status(ret)); 901 } 902 903 dladm_status_t 904 dladm_overlay_cache_flush(dladm_handle_t handle __unused, datalink_id_t linkid) 905 { 906 int ret; 907 uint64_t varpdid; 908 varpd_client_handle_t *chdl; 909 910 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 911 return (dladm_errno2status(ret)); 912 913 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 914 libvarpd_c_destroy(chdl); 915 return (dladm_errno2status(ret)); 916 } 917 918 ret = libvarpd_c_instance_cache_flush(chdl, varpdid); 919 libvarpd_c_destroy(chdl); 920 921 return (dladm_errno2status(ret)); 922 } 923 924 dladm_status_t 925 dladm_overlay_cache_delete(dladm_handle_t handle __unused, datalink_id_t linkid, 926 const struct ether_addr *key) 927 { 928 int ret; 929 uint64_t varpdid; 930 varpd_client_handle_t *chdl; 931 932 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 933 return (dladm_errno2status(ret)); 934 935 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 936 libvarpd_c_destroy(chdl); 937 return (dladm_errno2status(ret)); 938 } 939 940 ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key); 941 libvarpd_c_destroy(chdl); 942 943 return (dladm_errno2status(ret)); 944 } 945 946 dladm_status_t 947 dladm_overlay_cache_set(dladm_handle_t handle __unused, datalink_id_t linkid, 948 const struct ether_addr *key, char *val) 949 { 950 int ret; 951 uint_t dest; 952 uint64_t varpdid; 953 char *ip, *port = NULL; 954 varpd_client_handle_t *chdl; 955 varpd_client_cache_entry_t vcp; 956 957 958 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 959 return (dladm_errno2status(ret)); 960 961 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 962 libvarpd_c_destroy(chdl); 963 return (dladm_errno2status(ret)); 964 } 965 966 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 967 &dest, NULL)) != 0) { 968 libvarpd_c_destroy(chdl); 969 return (dladm_errno2status(ret)); 970 } 971 972 /* 973 * Mode tells us what we should expect in val. It we have more than one 974 * thing listed, the canonical format of it right now is mac,ip:port. 975 */ 976 bzero(&vcp, sizeof (varpd_client_cache_entry_t)); 977 978 if (strcasecmp(val, "drop") == 0) { 979 vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP; 980 goto send; 981 } 982 983 if (dest & OVERLAY_PLUGIN_D_ETHERNET) { 984 if (ether_aton_r(val, &vcp.vcp_mac) == NULL) { 985 libvarpd_c_destroy(chdl); 986 return (dladm_errno2status(EINVAL)); 987 } 988 } 989 990 if (dest & OVERLAY_PLUGIN_D_IP) { 991 if (dest & OVERLAY_PLUGIN_D_ETHERNET) { 992 if ((ip = strchr(val, ',')) == NULL) { 993 libvarpd_c_destroy(chdl); 994 return (dladm_errno2status(ret)); 995 } 996 ip++; 997 } else { 998 ip = val; 999 } 1000 1001 if (dest & OVERLAY_PLUGIN_D_PORT) { 1002 if ((port = strchr(val, ':')) == NULL) { 1003 libvarpd_c_destroy(chdl); 1004 return (dladm_errno2status(ret)); 1005 } 1006 *port = '\0'; 1007 port++; 1008 } 1009 1010 /* Try v6, then fall back to v4 */ 1011 ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip); 1012 if (ret == -1) 1013 abort(); 1014 if (ret == 0) { 1015 struct in_addr v4; 1016 1017 ret = inet_pton(AF_INET, ip, &v4); 1018 if (ret == -1) 1019 abort(); 1020 if (ret == 0) { 1021 libvarpd_c_destroy(chdl); 1022 return (dladm_errno2status(ret)); 1023 } 1024 IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip); 1025 } 1026 } 1027 1028 if (dest & OVERLAY_PLUGIN_D_PORT) { 1029 char *eptr; 1030 unsigned long l; 1031 if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) { 1032 if ((port = strchr(val, ',')) == NULL) { 1033 libvarpd_c_destroy(chdl); 1034 return (dladm_errno2status(EINVAL)); 1035 } 1036 } else if (port == NULL) 1037 port = val; 1038 1039 errno = 0; 1040 l = strtoul(port, &eptr, 10); 1041 if (errno != 0 || *eptr != '\0') { 1042 libvarpd_c_destroy(chdl); 1043 return (dladm_errno2status(EINVAL)); 1044 } 1045 if (l == 0 || l > UINT16_MAX) { 1046 libvarpd_c_destroy(chdl); 1047 return (dladm_errno2status(EINVAL)); 1048 } 1049 vcp.vcp_port = l; 1050 } 1051 1052 send: 1053 ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp); 1054 1055 libvarpd_c_destroy(chdl); 1056 return (dladm_errno2status(ret)); 1057 } 1058 1059 dladm_status_t 1060 dladm_overlay_cache_get(dladm_handle_t handle __unused, datalink_id_t linkid, 1061 const struct ether_addr *key, dladm_overlay_point_t *point) 1062 { 1063 int ret; 1064 uint_t dest, mode; 1065 uint64_t varpdid; 1066 varpd_client_handle_t *chdl; 1067 varpd_client_cache_entry_t entry; 1068 1069 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 1070 return (dladm_errno2status(ret)); 1071 1072 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 1073 libvarpd_c_destroy(chdl); 1074 return (dladm_errno2status(ret)); 1075 } 1076 1077 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 1078 &dest, &mode)) != 0) { 1079 libvarpd_c_destroy(chdl); 1080 return (dladm_errno2status(ret)); 1081 } 1082 1083 ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry); 1084 if (ret == 0) { 1085 point->dop_dest = dest; 1086 point->dop_mac = entry.vcp_mac; 1087 point->dop_flags = entry.vcp_flags; 1088 point->dop_ip = entry.vcp_ip; 1089 point->dop_port = entry.vcp_port; 1090 if (mode == OVERLAY_TARGET_POINT) 1091 point->dop_flags |= DLADM_OVERLAY_F_DEFAULT; 1092 } 1093 1094 libvarpd_c_destroy(chdl); 1095 return (dladm_errno2status(ret)); 1096 } 1097 1098 dladm_status_t 1099 dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid, 1100 dladm_overlay_status_f func, void *arg) 1101 { 1102 int ret; 1103 dladm_status_t status; 1104 overlay_ioc_status_t ois; 1105 dladm_overlay_status_t dos; 1106 1107 ois.ois_linkid = linkid; 1108 status = DLADM_STATUS_OK; 1109 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois); 1110 if (ret != 0) 1111 status = dladm_errno2status(errno); 1112 if (status != DLADM_STATUS_OK) 1113 return (status); 1114 1115 dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE : 1116 B_FALSE; 1117 (void) strlcpy(dos.dos_fmamsg, ois.ois_message, 1118 sizeof (dos.dos_fmamsg)); 1119 func(handle, linkid, &dos, arg); 1120 return (DLADM_STATUS_OK); 1121 } 1122 1123 /* 1124 * dladm_parse_args() usually creates a dladm_arg_list_t by tokenising a 1125 * delimited string and storing pointers to pieces of that string in the 1126 * dladm_arg_info_t structure. Those pointers do not need to be individually 1127 * freed. 1128 * 1129 * This function deals with property lists which have instead been built from 1130 * the persistent datalink configuration database, in order to bring up an 1131 * overlay at boot time. In this case, the properties have been retrieved 1132 * one-by-one, duplicated with strdup(), and added to the list. When the list 1133 * is finished with, this function takes care of freeing the memory. 1134 */ 1135 static void 1136 i_dladm_overlay_props_free(dladm_handle_t handle __unused, 1137 dladm_arg_list_t *props) 1138 { 1139 uint_t i, j; 1140 1141 for (i = 0; props != NULL && i < props->al_count; i++) { 1142 dladm_arg_info_t *aip = &props->al_info[i]; 1143 1144 /* For ai_name, we need to cast away the 'const' qualifier. */ 1145 free((char *)aip->ai_name); 1146 for (j = 0; j < aip->ai_count; j++) 1147 free(aip->ai_val[j]); 1148 } 1149 free(props); 1150 } 1151 1152 static dladm_status_t 1153 i_dladm_overlay_fetch_persistent_config(dladm_handle_t handle, 1154 datalink_id_t linkid, dladm_overlay_attr_t *attrp, 1155 dladm_arg_list_t **props) 1156 { 1157 dladm_conf_t conf; 1158 dladm_status_t status; 1159 char attr[MAXLINKATTRLEN], last_attr[MAXLINKATTRLEN]; 1160 char attrval[OVERLAY_PROP_SIZEMAX]; 1161 size_t attrsz; 1162 dladm_arg_list_t *list = NULL; 1163 1164 *props = NULL; 1165 1166 if ((status = dladm_getsnap_conf(handle, linkid, &conf)) != 1167 DLADM_STATUS_OK) { 1168 return (status); 1169 } 1170 1171 attrp->oa_linkid = linkid; 1172 1173 status = dladm_get_conf_field(handle, conf, FVNETID, &attrp->oa_vid, 1174 sizeof (attrp->oa_vid)); 1175 if (status != DLADM_STATUS_OK) 1176 goto done; 1177 1178 status = dladm_get_conf_field(handle, conf, FENCAP, 1179 attrp->oa_encap, sizeof (attrp->oa_encap)); 1180 if (status != DLADM_STATUS_OK) 1181 goto done; 1182 1183 status = dladm_get_conf_field(handle, conf, FSEARCH, 1184 attrp->oa_search, sizeof (attrp->oa_search)); 1185 if (status != DLADM_STATUS_OK) 1186 goto done; 1187 1188 list = calloc(1, sizeof (dladm_arg_list_t)); 1189 1190 *last_attr = '\0'; 1191 while (dladm_getnext_conf_linkprop(handle, conf, last_attr, 1192 attr, attrval, sizeof (attrval), &attrsz) == DLADM_STATUS_OK) { 1193 dladm_arg_info_t *aip; 1194 1195 (void) strlcpy(last_attr, attr, sizeof (last_attr)); 1196 if (strchr(attr, '/') == NULL) 1197 continue; 1198 1199 aip = &list->al_info[list->al_count]; 1200 bzero(aip, sizeof (dladm_arg_info_t)); 1201 if ((aip->ai_name = strdup(attr)) == NULL) { 1202 status = dladm_errno2status(errno); 1203 break; 1204 } 1205 if ((aip->ai_val[0] = strdup(attrval)) == NULL) { 1206 status = dladm_errno2status(errno); 1207 break; 1208 } 1209 aip->ai_count = 1; 1210 list->al_count++; 1211 if (list->al_count >= DLADM_MAX_ARG_CNT) { 1212 status = DLADM_STATUS_TOOMANYELEMENTS; 1213 break; 1214 } 1215 } 1216 1217 done: 1218 1219 dladm_destroy_conf(handle, conf); 1220 1221 if (status != DLADM_STATUS_OK) { 1222 if (list != NULL) 1223 i_dladm_overlay_props_free(handle, list); 1224 return (status); 1225 } 1226 1227 *props = list; 1228 return (DLADM_STATUS_OK); 1229 } 1230 1231 typedef struct dladm_overlay_up_arg_s { 1232 dladm_errlist_t *errlist; 1233 } dladm_overlay_up_arg_t; 1234 1235 static int 1236 i_dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid, void *arg) 1237 { 1238 dladm_overlay_up_arg_t *argp = arg; 1239 dladm_errlist_t *errs = argp->errlist; 1240 datalink_class_t class; 1241 dladm_status_t status; 1242 dladm_overlay_attr_t attr; 1243 dladm_arg_list_t *props; 1244 char errmsg[DLADM_STRSIZE]; 1245 1246 bzero(&attr, sizeof (attr)); 1247 1248 status = dladm_datalink_id2info(handle, linkid, NULL, &class, 1249 NULL, attr.oa_name, sizeof (attr.oa_name)); 1250 if (status != DLADM_STATUS_OK) { 1251 (void) dladm_errlist_append(errs, "failed to get info for " 1252 "datalink id %u: %s", 1253 linkid, dladm_status2str(status, errmsg)); 1254 return (DLADM_STATUS_BADARG); 1255 } 1256 1257 if (class != DATALINK_CLASS_OVERLAY) { 1258 (void) dladm_errlist_append(errs, "%s is not an overlay", 1259 attr.oa_name); 1260 return (DLADM_STATUS_BADARG); 1261 } 1262 1263 status = varpd_enable_service(); 1264 if (status != DLADM_STATUS_OK) { 1265 (void) dladm_errlist_append(errs, "failed to enable svc:/%s", 1266 VARPD_SERVICE); 1267 return (DLADM_WALK_TERMINATE); 1268 } 1269 1270 status = i_dladm_overlay_fetch_persistent_config(handle, linkid, 1271 &attr, &props); 1272 if (status != DLADM_STATUS_OK) { 1273 (void) dladm_errlist_append(errs, "failed to retrieve " 1274 "persistent configuration for %s: %s", 1275 attr.oa_name, dladm_status2str(status, errmsg)); 1276 return (DLADM_WALK_CONTINUE); 1277 } 1278 1279 status = i_dladm_overlay_create_sys(handle, &attr); 1280 if (status != DLADM_STATUS_OK) { 1281 (void) dladm_errlist_append(errs, 1282 "failed to create overlay device %s: %s", 1283 attr.oa_name, dladm_status2str(status, errmsg)); 1284 goto out; 1285 } 1286 1287 status = i_dladm_overlay_commit_sys(handle, &attr, props, errs); 1288 if (status != DLADM_STATUS_OK) { 1289 (void) dladm_errlist_append(errs, 1290 "failed to set properties for overlay device %s: %s", 1291 attr.oa_name, dladm_status2str(status, errmsg)); 1292 dladm_overlay_delete(handle, linkid, 0); 1293 goto out; 1294 } 1295 1296 status = dladm_up_datalink_id(handle, linkid); 1297 if (status != DLADM_STATUS_OK) { 1298 (void) dladm_errlist_append(errs, 1299 "failed to bring datalink up for overlay device %s: %s", 1300 attr.oa_name, dladm_status2str(status, errmsg)); 1301 dladm_overlay_delete(handle, linkid, 0); 1302 goto out; 1303 } 1304 1305 out: 1306 i_dladm_overlay_props_free(handle, props); 1307 1308 return (DLADM_WALK_CONTINUE); 1309 } 1310 1311 dladm_status_t 1312 dladm_overlay_up(dladm_handle_t handle, datalink_id_t linkid, 1313 dladm_errlist_t *errs) 1314 { 1315 dladm_overlay_up_arg_t overlay_arg = { 1316 .errlist = errs 1317 }; 1318 1319 if (linkid == DATALINK_ALL_LINKID) { 1320 (void) dladm_walk_datalink_id(i_dladm_overlay_up, handle, 1321 &overlay_arg, DATALINK_CLASS_OVERLAY, 1322 DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1323 } else { 1324 (void) i_dladm_overlay_up(handle, linkid, &overlay_arg); 1325 } 1326 1327 if (dladm_errlist_count(errs) == 0) 1328 return (DLADM_STATUS_OK); 1329 1330 return (DLADM_STATUS_FAILED); 1331 } 1332