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