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 */ 15 16 #include <libdladm_impl.h> 17 #include <libdllink.h> 18 #include <libdloverlay.h> 19 #include <sys/dld.h> 20 #include <sys/overlay.h> 21 #include <strings.h> 22 #include <unistd.h> 23 #include <stdlib.h> 24 #include <errno.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 #include <limits.h> 28 #include <libvarpd_client.h> 29 30 #define VARPD_PROPERTY_NAME "varpd/id" 31 32 static const char *dladm_overlay_doorpath = "/var/run/varpd/varpd.door"; 33 34 typedef struct dladm_overlay_propinfo { 35 boolean_t dop_isvarpd; 36 union { 37 overlay_ioc_propinfo_t *dop_overlay; 38 varpd_client_prop_handle_t *dop_varpd; 39 } dop_un; 40 } dladm_overlay_propinfo_t; 41 42 dladm_status_t 43 dladm_overlay_prop_info(dladm_overlay_propinfo_handle_t phdl, 44 const char **namep, uint_t *typep, uint_t *protp, const void **defp, 45 uint32_t *sizep, const mac_propval_range_t **possp) 46 { 47 dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)phdl; 48 overlay_ioc_propinfo_t *oinfop = infop->dop_un.dop_overlay; 49 50 if (infop->dop_isvarpd == B_FALSE) { 51 if (namep != NULL) 52 *namep = oinfop->oipi_name; 53 if (typep != NULL) 54 *typep = oinfop->oipi_type; 55 if (protp != NULL) 56 *protp = oinfop->oipi_prot; 57 if (defp != NULL) 58 *defp = oinfop->oipi_default; 59 if (sizep != NULL) 60 *sizep = oinfop->oipi_defsize; 61 if (possp != NULL) { 62 *possp = (const mac_propval_range_t *)oinfop->oipi_poss; 63 } 64 65 } else { 66 int ret; 67 ret = libvarpd_c_prop_info(infop->dop_un.dop_varpd, namep, 68 typep, protp, defp, sizep, possp); 69 if (ret != 0) 70 return (dladm_errno2status(ret)); 71 72 } 73 74 return (DLADM_STATUS_OK); 75 } 76 77 static dladm_status_t 78 dladm_overlay_parse_prop(overlay_prop_type_t type, void *buf, uint32_t *sizep, 79 const char *val) 80 { 81 int ret; 82 int64_t ival; 83 uint64_t uval; 84 char *eptr; 85 struct in6_addr ipv6; 86 struct in_addr ip; 87 88 switch (type) { 89 case OVERLAY_PROP_T_INT: 90 errno = 0; 91 ival = strtol(val, &eptr, 10); 92 if ((ival == 0 && errno == EINVAL) || 93 ((ival == LONG_MAX || ival == LONG_MIN) && 94 errno == ERANGE)) 95 return (DLADM_STATUS_BADARG); 96 bcopy(&ival, buf, sizeof (int64_t)); 97 *sizep = sizeof (int64_t); 98 break; 99 case OVERLAY_PROP_T_UINT: 100 errno = 0; 101 uval = strtol(val, &eptr, 10); 102 if ((uval == 0 && errno == EINVAL) || 103 (uval == ULONG_MAX && errno == ERANGE)) 104 return (DLADM_STATUS_BADARG); 105 bcopy(&uval, buf, sizeof (uint64_t)); 106 *sizep = sizeof (uint64_t); 107 break; 108 case OVERLAY_PROP_T_STRING: 109 ret = strlcpy((char *)buf, val, OVERLAY_PROP_SIZEMAX); 110 if (ret >= OVERLAY_PROP_SIZEMAX) 111 return (DLADM_STATUS_BADARG); 112 *sizep = ret + 1; 113 break; 114 case OVERLAY_PROP_T_IP: 115 /* 116 * Always try to parse the IP as an IPv6 address. If that fails, 117 * try to interpret it as an IPv4 address and transform it into 118 * an IPv6 mapped IPv4 address. 119 */ 120 if (inet_pton(AF_INET6, val, &ipv6) != 1) { 121 if (inet_pton(AF_INET, val, &ip) != 1) 122 return (DLADM_STATUS_BADARG); 123 124 IN6_INADDR_TO_V4MAPPED(&ip, &ipv6); 125 } 126 bcopy(&ipv6, buf, sizeof (struct in6_addr)); 127 *sizep = sizeof (struct in6_addr); 128 break; 129 default: 130 abort(); 131 } 132 133 return (DLADM_STATUS_OK); 134 } 135 136 /* ARGSUSED */ 137 static dladm_status_t 138 dladm_overlay_varpd_setprop(dladm_handle_t handle, varpd_client_handle_t *chdl, 139 uint64_t inst, const char *name, char *const *valp, uint_t cnt) 140 { 141 int ret; 142 uint32_t size; 143 uint8_t buf[LIBVARPD_PROP_SIZEMAX]; 144 varpd_client_prop_handle_t *phdl; 145 uint_t type; 146 dladm_status_t status; 147 148 if ((ret = libvarpd_c_prop_handle_alloc(chdl, inst, &phdl)) != 0) 149 return (dladm_errno2status(ret)); 150 151 if ((ret = libvarpd_c_prop_info_fill_by_name(phdl, name)) != 0) { 152 libvarpd_c_prop_handle_free(phdl); 153 return (dladm_errno2status(ret)); 154 } 155 156 if ((ret = libvarpd_c_prop_info(phdl, NULL, &type, NULL, NULL, NULL, 157 NULL)) != 0) { 158 libvarpd_c_prop_handle_free(phdl); 159 return (dladm_errno2status(ret)); 160 } 161 162 if ((status = dladm_overlay_parse_prop(type, buf, &size, valp[0])) != 163 DLADM_STATUS_OK) { 164 libvarpd_c_prop_handle_free(phdl); 165 return (status); 166 } 167 168 ret = libvarpd_c_prop_set(phdl, buf, size); 169 libvarpd_c_prop_handle_free(phdl); 170 171 return (dladm_errno2status(ret)); 172 } 173 174 dladm_status_t 175 dladm_overlay_setprop(dladm_handle_t handle, datalink_id_t linkid, 176 const char *name, char *const *valp, uint_t cnt) 177 { 178 int ret; 179 dladm_status_t status; 180 overlay_ioc_propinfo_t info; 181 overlay_ioc_prop_t prop; 182 183 if (linkid == DATALINK_INVALID_LINKID || 184 name == NULL || valp == NULL || cnt != 1) 185 return (DLADM_STATUS_BADARG); 186 187 bzero(&info, sizeof (overlay_ioc_propinfo_t)); 188 info.oipi_linkid = linkid; 189 info.oipi_id = -1; 190 if (strlcpy(info.oipi_name, name, OVERLAY_PROP_NAMELEN) >= 191 OVERLAY_PROP_NAMELEN) 192 return (DLADM_STATUS_BADARG); 193 194 status = DLADM_STATUS_OK; 195 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &info); 196 if (ret != 0) 197 status = dladm_errno2status(errno); 198 199 if (status != DLADM_STATUS_OK) 200 return (status); 201 202 prop.oip_linkid = linkid; 203 prop.oip_id = info.oipi_id; 204 prop.oip_name[0] = '\0'; 205 if ((ret = dladm_overlay_parse_prop(info.oipi_type, prop.oip_value, 206 &prop.oip_size, valp[0])) != DLADM_STATUS_OK) 207 return (ret); 208 209 status = DLADM_STATUS_OK; 210 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_SETPROP, &prop); 211 if (ret != 0) 212 status = dladm_errno2status(errno); 213 214 return (ret); 215 } 216 217 /* 218 * Tell the user about any unset required properties. 219 */ 220 static int 221 dladm_overlay_activate_cb(dladm_handle_t handle, datalink_id_t linkid, 222 dladm_overlay_propinfo_handle_t phdl, void *arg) 223 { 224 dladm_status_t status; 225 uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; 226 uint_t prot; 227 size_t size = sizeof (buf); 228 const char *name; 229 dladm_errlist_t *errs = arg; 230 231 if ((status = dladm_overlay_prop_info(phdl, &name, NULL, &prot, NULL, 232 NULL, NULL)) != DLADM_STATUS_OK) 233 return (status); 234 235 if ((prot & OVERLAY_PROP_PERM_REQ) == 0) 236 return (DLADM_WALK_CONTINUE); 237 238 if (dladm_overlay_get_prop(handle, linkid, phdl, buf, &size) != 239 DLADM_STATUS_OK) 240 return (DLADM_WALK_CONTINUE); 241 242 if (size == 0) 243 (void) dladm_errlist_append(errs, "unset required property: %s", 244 name); 245 246 return (DLADM_WALK_CONTINUE); 247 } 248 249 /* 250 * We need to clean up the world here. The problem is that we may or may not 251 * actually have everything created. While in the normal case, we'd always have 252 * an overlay device, assigned datalink id, and a varpd instance, we might not 253 * have any of those, except for the datalink instance. Therefore, as long as 254 * the id refers to a valid overlay, we should try to clean up as much of the 255 * state as possible and most importantly, we need to make sure we delete the 256 * datalink id. If we fail to do that, then that name will become lost to time. 257 */ 258 dladm_status_t 259 dladm_overlay_delete(dladm_handle_t handle, datalink_id_t linkid) 260 { 261 datalink_class_t class; 262 overlay_ioc_delete_t oid; 263 varpd_client_handle_t *chdl; 264 int ret; 265 uint32_t flags; 266 uint64_t varpdid; 267 268 if (dladm_datalink_id2info(handle, linkid, &flags, &class, NULL, 269 NULL, 0) != DLADM_STATUS_OK) 270 return (DLADM_STATUS_BADARG); 271 272 if (class != DATALINK_CLASS_OVERLAY) 273 return (DLADM_STATUS_BADARG); 274 275 oid.oid_linkid = linkid; 276 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_DELETE, &oid); 277 if (ret != 0 && errno != ENOENT) { 278 return (dladm_errno2status(errno)); 279 } 280 281 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) { 282 return (dladm_errno2status(ret)); 283 } 284 285 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 286 if (ret == ENOENT) { 287 goto finish; 288 } 289 (void) libvarpd_c_destroy(chdl); 290 return (dladm_errno2status(ret)); 291 } 292 293 ret = libvarpd_c_instance_destroy(chdl, varpdid); 294 finish: 295 (void) libvarpd_c_destroy(chdl); 296 (void) dladm_destroy_datalink_id(handle, linkid, flags); 297 298 return (dladm_errno2status(ret)); 299 } 300 301 dladm_status_t 302 dladm_overlay_get_prop(dladm_handle_t handle, datalink_id_t linkid, 303 dladm_overlay_propinfo_handle_t infohdl, void *buf, size_t *sizep) 304 { 305 int ret; 306 overlay_ioc_prop_t oip; 307 dladm_overlay_propinfo_t *infop = (dladm_overlay_propinfo_t *)infohdl; 308 309 /* 310 * It'd be nice if we had a better or more specific error for this. If 311 * this kind of error becomes common place, let's get a better dladm 312 * error. 313 */ 314 if (*sizep < DLADM_OVERLAY_PROP_SIZEMAX) 315 return (dladm_errno2status(ERANGE)); 316 317 if (infop->dop_isvarpd == B_FALSE) { 318 bzero(&oip, sizeof (overlay_ioc_prop_t)); 319 oip.oip_linkid = linkid; 320 oip.oip_id = infop->dop_un.dop_overlay->oipi_id; 321 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_GETPROP, &oip); 322 if (ret != 0) 323 return (dladm_errno2status(errno)); 324 bcopy(oip.oip_value, buf, DLADM_OVERLAY_PROP_SIZEMAX); 325 *sizep = oip.oip_size; 326 } else { 327 uint32_t size = *sizep; 328 329 ret = libvarpd_c_prop_get(infop->dop_un.dop_varpd, buf, &size); 330 if (ret != 0) 331 return (dladm_errno2status(errno)); 332 *sizep = size; 333 } 334 335 return (DLADM_STATUS_OK); 336 } 337 338 static dladm_status_t 339 dladm_overlay_walk_varpd_prop(dladm_handle_t handle, datalink_id_t linkid, 340 uint64_t varpdid, dladm_overlay_prop_f func, void *arg) 341 { 342 int ret, i; 343 varpd_client_handle_t *chdl; 344 varpd_client_prop_handle_t *phdl; 345 uint_t nprops; 346 dladm_status_t status; 347 348 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 349 return (dladm_errno2status(ret)); 350 351 if ((ret = libvarpd_c_prop_handle_alloc(chdl, varpdid, &phdl)) != 0) { 352 (void) libvarpd_c_destroy(chdl); 353 return (dladm_errno2status(ret)); 354 } 355 356 if ((ret = libvarpd_c_prop_nprops(chdl, varpdid, &nprops)) != 0) { 357 libvarpd_c_prop_handle_free(phdl); 358 (void) libvarpd_c_destroy(chdl); 359 return (dladm_errno2status(ret)); 360 } 361 362 status = DLADM_STATUS_OK; 363 for (i = 0; i < nprops; i++) { 364 dladm_overlay_propinfo_t dop; 365 366 bzero(&dop, sizeof (dop)); 367 dop.dop_isvarpd = B_TRUE; 368 dop.dop_un.dop_varpd = phdl; 369 370 if ((ret = libvarpd_c_prop_info_fill(phdl, i)) != 0) { 371 status = dladm_errno2status(ret); 372 break; 373 } 374 375 ret = func(handle, linkid, 376 (dladm_overlay_propinfo_handle_t)&dop, arg); 377 if (ret == DLADM_WALK_TERMINATE) 378 break; 379 } 380 381 libvarpd_c_prop_handle_free(phdl); 382 libvarpd_c_destroy(chdl); 383 384 return (status); 385 } 386 387 dladm_status_t 388 dladm_overlay_walk_prop(dladm_handle_t handle, datalink_id_t linkid, 389 dladm_overlay_prop_f func, void *arg, dladm_errlist_t *errs) 390 { 391 int i, ret; 392 char buf[MAXLINKNAMELEN]; 393 char errmsg[DLADM_STRSIZE]; 394 datalink_class_t class; 395 dladm_status_t info_status; 396 overlay_ioc_nprops_t oin; 397 overlay_ioc_propinfo_t oipi; 398 dladm_overlay_propinfo_t dop; 399 uint64_t varpdid = UINT64_MAX; 400 401 if ((info_status = dladm_datalink_id2info(handle, linkid, NULL, &class, 402 NULL, buf, MAXLINKNAMELEN)) != DLADM_STATUS_OK) { 403 (void) dladm_errlist_append(errs, "failed to get info for " 404 "datalink id %u: %s", 405 linkid, dladm_status2str(info_status, errmsg)); 406 return (DLADM_STATUS_BADARG); 407 } 408 409 if (class != DATALINK_CLASS_OVERLAY) { 410 (void) dladm_errlist_append(errs, "%s is not an overlay", buf); 411 return (DLADM_STATUS_BADARG); 412 } 413 414 bzero(&oin, sizeof (overlay_ioc_nprops_t)); 415 oin.oipn_linkid = linkid; 416 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_NPROPS, &oin); 417 if (ret != 0) { 418 (void) dladm_errlist_append(errs, "failed to get " 419 "overlay properties for overlay %s: %s", 420 buf, strerror(errno)); 421 return (dladm_errno2status(errno)); 422 } 423 424 for (i = 0; i < oin.oipn_nprops; i++) { 425 bzero(&dop, sizeof (dladm_overlay_propinfo_t)); 426 bzero(&oipi, sizeof (overlay_ioc_propinfo_t)); 427 oipi.oipi_linkid = linkid; 428 oipi.oipi_id = i; 429 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_PROPINFO, &oipi); 430 if (ret != 0) { 431 (void) dladm_errlist_append(errs, "failed to get " 432 "propinfo for overlay %s, property %d: %s", 433 buf, i, strerror(errno)); 434 return (dladm_errno2status(errno)); 435 } 436 437 dop.dop_isvarpd = B_FALSE; 438 dop.dop_un.dop_overlay = &oipi; 439 ret = func(handle, linkid, 440 (dladm_overlay_propinfo_handle_t)&dop, arg); 441 if (ret == DLADM_WALK_TERMINATE) 442 break; 443 444 if (strcmp(oipi.oipi_name, VARPD_PROPERTY_NAME) == 0) { 445 uint8_t buf[DLADM_OVERLAY_PROP_SIZEMAX]; 446 size_t bufsize = sizeof (buf); 447 uint64_t *vp; 448 449 if (dladm_overlay_get_prop(handle, linkid, 450 (dladm_overlay_propinfo_handle_t)&dop, buf, 451 &bufsize) != DLADM_STATUS_OK) 452 continue; 453 454 vp = (uint64_t *)buf; 455 varpdid = *vp; 456 } 457 } 458 459 /* Should this really be possible? */ 460 if (varpdid == UINT64_MAX) 461 return (DLADM_STATUS_OK); 462 463 ret = dladm_overlay_walk_varpd_prop(handle, linkid, varpdid, func, 464 arg); 465 if (ret != DLADM_STATUS_OK) { 466 (void) dladm_errlist_append(errs, 467 "failed to get varpd props for " 468 "overlay %s, varpd id %llu: %s", 469 buf, varpdid, dladm_status2str(info_status, errmsg)); 470 } 471 return (ret); 472 } 473 474 dladm_status_t 475 dladm_overlay_create(dladm_handle_t handle, const char *name, 476 const char *encap, const char *search, uint64_t vid, 477 dladm_arg_list_t *props, dladm_errlist_t *errs, uint32_t flags) 478 { 479 int ret, i; 480 dladm_status_t status; 481 datalink_id_t linkid; 482 overlay_ioc_create_t oic; 483 overlay_ioc_activate_t oia; 484 size_t slen; 485 varpd_client_handle_t *vch; 486 uint64_t id; 487 488 status = dladm_create_datalink_id(handle, name, DATALINK_CLASS_OVERLAY, 489 DL_ETHER, flags, &linkid); 490 if (status != DLADM_STATUS_OK) 491 return (status); 492 493 bzero(&oic, sizeof (oic)); 494 oic.oic_linkid = linkid; 495 oic.oic_vnetid = vid; 496 (void) strlcpy(oic.oic_encap, encap, MAXLINKNAMELEN); 497 498 status = DLADM_STATUS_OK; 499 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_CREATE, &oic); 500 if (ret != 0) { 501 /* 502 * It'd be nice if we had private errors so we could better 503 * distinguish between different classes of errors. 504 */ 505 status = dladm_errno2status(errno); 506 } 507 508 if (status != DLADM_STATUS_OK) { 509 (void) dladm_destroy_datalink_id(handle, linkid, flags); 510 return (status); 511 } 512 513 slen = strlen(search); 514 for (i = 0; props != NULL && i < props->al_count; i++) { 515 dladm_arg_info_t *aip = &props->al_info[i]; 516 517 /* 518 * If it's a property for the search plugin, eg. it has the 519 * prefix '<search>/', then we don't set the property on the 520 * overlay device and instead set it on the varpd instance. 521 */ 522 if (strncmp(aip->ai_name, search, slen) == 0 && 523 aip->ai_name[slen] == '/') 524 continue; 525 status = dladm_overlay_setprop(handle, linkid, aip->ai_name, 526 aip->ai_val, aip->ai_count); 527 if (status != DLADM_STATUS_OK) { 528 (void) dladm_errlist_append(errs, 529 "failed to set property %s", 530 aip->ai_name); 531 (void) dladm_overlay_delete(handle, linkid); 532 return (status); 533 } 534 } 535 536 if ((ret = libvarpd_c_create(&vch, dladm_overlay_doorpath)) != 0) { 537 (void) dladm_errlist_append(errs, 538 "failed to create libvarpd handle: %s", strerror(ret)); 539 (void) dladm_overlay_delete(handle, linkid); 540 return (dladm_errno2status(ret)); 541 } 542 543 if ((ret = libvarpd_c_instance_create(vch, linkid, search, 544 &id)) != 0) { 545 (void) dladm_errlist_append(errs, 546 "failed to create varpd instance: %s", strerror(ret)); 547 libvarpd_c_destroy(vch); 548 (void) dladm_overlay_delete(handle, linkid); 549 return (dladm_errno2status(ret)); 550 } 551 552 for (i = 0; props != NULL && i < props->al_count; i++) { 553 dladm_arg_info_t *aip = &props->al_info[i]; 554 555 /* 556 * Skip arguments we've processed already. 557 */ 558 if (strncmp(aip->ai_name, search, slen) != 0) 559 continue; 560 561 if (aip->ai_name[slen] != '/') 562 continue; 563 564 ret = dladm_overlay_varpd_setprop(handle, vch, id, aip->ai_name, 565 aip->ai_val, aip->ai_count); 566 if (ret != 0) { 567 (void) dladm_errlist_append(errs, 568 "failed to set varpd prop: %s\n", 569 aip->ai_name); 570 (void) libvarpd_c_instance_destroy(vch, id); 571 libvarpd_c_destroy(vch); 572 (void) dladm_overlay_delete(handle, linkid); 573 return (dladm_errno2status(ret)); 574 } 575 } 576 577 if ((ret = libvarpd_c_instance_activate(vch, id)) != 0) { 578 (void) dladm_errlist_append(errs, 579 "failed to activate varpd instance: %s", strerror(ret)); 580 (void) dladm_overlay_walk_varpd_prop(handle, linkid, id, 581 dladm_overlay_activate_cb, errs); 582 (void) libvarpd_c_instance_destroy(vch, id); 583 libvarpd_c_destroy(vch); 584 (void) dladm_overlay_delete(handle, linkid); 585 return (dladm_errno2status(ret)); 586 587 } 588 589 bzero(&oia, sizeof (oia)); 590 oia.oia_linkid = linkid; 591 status = DLADM_STATUS_OK; 592 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_ACTIVATE, &oia); 593 if (ret != 0) { 594 ret = errno; 595 (void) dladm_errlist_append(errs, "failed to activate " 596 "device: %s", strerror(ret)); 597 (void) libvarpd_c_instance_destroy(vch, id); 598 (void) dladm_overlay_walk_prop(handle, linkid, 599 dladm_overlay_activate_cb, errs, errs); 600 status = dladm_errno2status(ret); 601 (void) libvarpd_c_instance_destroy(vch, id); 602 } 603 604 libvarpd_c_destroy(vch); 605 if (status != DLADM_STATUS_OK) 606 (void) dladm_overlay_delete(handle, linkid); 607 608 return (status); 609 } 610 611 612 613 typedef struct overlay_walk_cb { 614 dladm_handle_t owc_handle; 615 datalink_id_t owc_linkid; 616 void *owc_arg; 617 dladm_overlay_cache_f owc_func; 618 uint_t owc_mode; 619 uint_t owc_dest; 620 } overlay_walk_cb_t; 621 622 /* ARGSUSED */ 623 static int 624 dladm_overlay_walk_cache_cb(varpd_client_handle_t *chdl, uint64_t varpdid, 625 const struct ether_addr *key, const varpd_client_cache_entry_t *entry, 626 void *arg) 627 { 628 overlay_walk_cb_t *owc = arg; 629 dladm_overlay_point_t point; 630 631 bzero(&point, sizeof (dladm_overlay_point_t)); 632 point.dop_dest = owc->owc_dest; 633 point.dop_mac = entry->vcp_mac; 634 point.dop_flags = entry->vcp_flags; 635 point.dop_ip = entry->vcp_ip; 636 point.dop_port = entry->vcp_port; 637 638 if (owc->owc_mode == OVERLAY_TARGET_POINT) 639 point.dop_flags |= DLADM_OVERLAY_F_DEFAULT; 640 641 if (owc->owc_func(owc->owc_handle, owc->owc_linkid, key, &point, 642 owc->owc_arg) == DLADM_WALK_TERMINATE) 643 return (1); 644 return (0); 645 } 646 647 dladm_status_t 648 dladm_overlay_walk_cache(dladm_handle_t handle, datalink_id_t linkid, 649 dladm_overlay_cache_f func, void *arg) 650 { 651 int ret; 652 uint_t mode, dest; 653 uint64_t varpdid; 654 varpd_client_handle_t *chdl; 655 overlay_walk_cb_t cbarg; 656 657 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 658 return (dladm_errno2status(ret)); 659 660 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 661 libvarpd_c_destroy(chdl); 662 return (dladm_errno2status(ret)); 663 } 664 665 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 666 &dest, &mode)) != 0) { 667 libvarpd_c_destroy(chdl); 668 return (dladm_errno2status(ret)); 669 } 670 671 cbarg.owc_handle = handle; 672 cbarg.owc_linkid = linkid; 673 cbarg.owc_arg = arg; 674 cbarg.owc_func = func; 675 cbarg.owc_dest = dest; 676 cbarg.owc_mode = mode; 677 ret = libvarpd_c_instance_cache_walk(chdl, varpdid, 678 dladm_overlay_walk_cache_cb, &cbarg); 679 libvarpd_c_destroy(chdl); 680 681 return (dladm_errno2status(ret)); 682 } 683 684 /* ARGSUSED */ 685 dladm_status_t 686 dladm_overlay_cache_flush(dladm_handle_t handle, datalink_id_t linkid) 687 { 688 int ret; 689 uint64_t varpdid; 690 varpd_client_handle_t *chdl; 691 692 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 693 return (dladm_errno2status(ret)); 694 695 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 696 libvarpd_c_destroy(chdl); 697 return (dladm_errno2status(ret)); 698 } 699 700 ret = libvarpd_c_instance_cache_flush(chdl, varpdid); 701 libvarpd_c_destroy(chdl); 702 703 return (dladm_errno2status(ret)); 704 } 705 706 /* ARGSUSED */ 707 dladm_status_t 708 dladm_overlay_cache_delete(dladm_handle_t handle, datalink_id_t linkid, 709 const struct ether_addr *key) 710 { 711 int ret; 712 uint64_t varpdid; 713 varpd_client_handle_t *chdl; 714 715 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 716 return (dladm_errno2status(ret)); 717 718 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 719 libvarpd_c_destroy(chdl); 720 return (dladm_errno2status(ret)); 721 } 722 723 ret = libvarpd_c_instance_cache_delete(chdl, varpdid, key); 724 libvarpd_c_destroy(chdl); 725 726 return (dladm_errno2status(ret)); 727 } 728 729 /* ARGSUSED */ 730 dladm_status_t 731 dladm_overlay_cache_set(dladm_handle_t handle, datalink_id_t linkid, 732 const struct ether_addr *key, char *val) 733 { 734 int ret; 735 uint_t dest; 736 uint64_t varpdid; 737 char *ip, *port = NULL; 738 varpd_client_handle_t *chdl; 739 varpd_client_cache_entry_t vcp; 740 741 742 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 743 return (dladm_errno2status(ret)); 744 745 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 746 libvarpd_c_destroy(chdl); 747 return (dladm_errno2status(ret)); 748 } 749 750 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 751 &dest, NULL)) != 0) { 752 libvarpd_c_destroy(chdl); 753 return (dladm_errno2status(ret)); 754 } 755 756 /* 757 * Mode tells us what we should expect in val. It we have more than one 758 * thing listed, the canonical format of it right now is mac,ip:port. 759 */ 760 bzero(&vcp, sizeof (varpd_client_cache_entry_t)); 761 762 if (strcasecmp(val, "drop") == 0) { 763 vcp.vcp_flags = OVERLAY_TARGET_CACHE_DROP; 764 goto send; 765 } 766 767 if (dest & OVERLAY_PLUGIN_D_ETHERNET) { 768 if (ether_aton_r(val, &vcp.vcp_mac) == NULL) { 769 libvarpd_c_destroy(chdl); 770 return (dladm_errno2status(EINVAL)); 771 } 772 } 773 774 if (dest & OVERLAY_PLUGIN_D_IP) { 775 if (dest & OVERLAY_PLUGIN_D_ETHERNET) { 776 if ((ip = strchr(val, ',')) == NULL) { 777 libvarpd_c_destroy(chdl); 778 return (dladm_errno2status(ret)); 779 } 780 ip++; 781 } else { 782 ip = val; 783 } 784 785 if (dest & OVERLAY_PLUGIN_D_PORT) { 786 if ((port = strchr(val, ':')) == NULL) { 787 libvarpd_c_destroy(chdl); 788 return (dladm_errno2status(ret)); 789 } 790 *port = '\0'; 791 port++; 792 } 793 794 /* Try v6, then fall back to v4 */ 795 ret = inet_pton(AF_INET6, ip, &vcp.vcp_ip); 796 if (ret == -1) 797 abort(); 798 if (ret == 0) { 799 struct in_addr v4; 800 801 ret = inet_pton(AF_INET, ip, &v4); 802 if (ret == -1) 803 abort(); 804 if (ret == 0) { 805 libvarpd_c_destroy(chdl); 806 return (dladm_errno2status(ret)); 807 } 808 IN6_INADDR_TO_V4MAPPED(&v4, &vcp.vcp_ip); 809 } 810 } 811 812 if (dest & OVERLAY_PLUGIN_D_PORT) { 813 char *eptr; 814 unsigned long l; 815 if (port == NULL && (dest & OVERLAY_PLUGIN_D_ETHERNET)) { 816 if ((port = strchr(val, ',')) == NULL) { 817 libvarpd_c_destroy(chdl); 818 return (dladm_errno2status(EINVAL)); 819 } 820 } else if (port == NULL) 821 port = val; 822 823 errno = 0; 824 l = strtoul(port, &eptr, 10); 825 if (errno != 0 || *eptr != '\0') { 826 libvarpd_c_destroy(chdl); 827 return (dladm_errno2status(EINVAL)); 828 } 829 if (l == 0 || l > UINT16_MAX) { 830 libvarpd_c_destroy(chdl); 831 return (dladm_errno2status(EINVAL)); 832 } 833 vcp.vcp_port = l; 834 } 835 836 send: 837 ret = libvarpd_c_instance_cache_set(chdl, varpdid, key, &vcp); 838 839 libvarpd_c_destroy(chdl); 840 return (dladm_errno2status(ret)); 841 } 842 843 /* ARGSUSED */ 844 dladm_status_t 845 dladm_overlay_cache_get(dladm_handle_t handle, datalink_id_t linkid, 846 const struct ether_addr *key, dladm_overlay_point_t *point) 847 { 848 int ret; 849 uint_t dest, mode; 850 uint64_t varpdid; 851 varpd_client_handle_t *chdl; 852 varpd_client_cache_entry_t entry; 853 854 if ((ret = libvarpd_c_create(&chdl, dladm_overlay_doorpath)) != 0) 855 return (dladm_errno2status(ret)); 856 857 if ((ret = libvarpd_c_instance_lookup(chdl, linkid, &varpdid)) != 0) { 858 libvarpd_c_destroy(chdl); 859 return (dladm_errno2status(ret)); 860 } 861 862 if ((ret = libvarpd_c_instance_target_mode(chdl, varpdid, 863 &dest, &mode)) != 0) { 864 libvarpd_c_destroy(chdl); 865 return (dladm_errno2status(ret)); 866 } 867 868 ret = libvarpd_c_instance_cache_get(chdl, varpdid, key, &entry); 869 if (ret == 0) { 870 point->dop_dest = dest; 871 point->dop_mac = entry.vcp_mac; 872 point->dop_flags = entry.vcp_flags; 873 point->dop_ip = entry.vcp_ip; 874 point->dop_port = entry.vcp_port; 875 if (mode == OVERLAY_TARGET_POINT) 876 point->dop_flags |= DLADM_OVERLAY_F_DEFAULT; 877 } 878 879 libvarpd_c_destroy(chdl); 880 return (dladm_errno2status(ret)); 881 } 882 883 dladm_status_t 884 dladm_overlay_status(dladm_handle_t handle, datalink_id_t linkid, 885 dladm_overlay_status_f func, void *arg) 886 { 887 int ret; 888 dladm_status_t status; 889 overlay_ioc_status_t ois; 890 dladm_overlay_status_t dos; 891 892 ois.ois_linkid = linkid; 893 status = DLADM_STATUS_OK; 894 ret = ioctl(dladm_dld_fd(handle), OVERLAY_IOC_STATUS, &ois); 895 if (ret != 0) 896 status = dladm_errno2status(errno); 897 if (status != DLADM_STATUS_OK) 898 return (status); 899 900 dos.dos_degraded = ois.ois_status == OVERLAY_I_DEGRADED ? B_TRUE : 901 B_FALSE; 902 (void) strlcpy(dos.dos_fmamsg, ois.ois_message, 903 sizeof (dos.dos_fmamsg)); 904 func(handle, linkid, &dos, arg); 905 return (DLADM_STATUS_OK); 906 } 907