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 2019 Joyent, Inc. 14 */ 15 16 /* 17 * varpd client interfaces 18 */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <fcntl.h> 23 #include <errno.h> 24 #include <umem.h> 25 #include <unistd.h> 26 #include <string.h> 27 #include <strings.h> 28 #include <door.h> 29 30 #include <libvarpd_impl.h> 31 32 typedef struct varpd_client { 33 int vcl_doorfd; 34 } varpd_client_t; 35 36 typedef struct varpd_client_prop_info { 37 varpd_client_t *vcprop_client; 38 uint64_t vcprop_instance; 39 uint_t vcprop_propid; 40 uint_t vcprop_type; 41 uint_t vcprop_prot; 42 uint32_t vcprop_defsize; 43 uint32_t vcprop_psize; 44 char vcprop_name[LIBVARPD_PROP_NAMELEN]; 45 uint8_t vcprop_default[LIBVARPD_PROP_SIZEMAX]; 46 uint8_t vcprop_poss[LIBVARPD_PROP_SIZEMAX]; 47 } varpd_client_prop_info_t; 48 49 static int 50 libvarpd_c_door_call(varpd_client_t *client, varpd_client_arg_t *argp, 51 size_t altsize) 52 { 53 int ret; 54 door_arg_t darg; 55 56 darg.data_ptr = (char *)argp; 57 darg.desc_ptr = NULL; 58 darg.desc_num = 0; 59 darg.rbuf = (char *)argp; 60 if (altsize != 0) { 61 darg.data_size = altsize; 62 darg.rsize = altsize; 63 } else { 64 darg.data_size = sizeof (varpd_client_arg_t); 65 darg.rsize = sizeof (varpd_client_arg_t); 66 } 67 68 do { 69 ret = door_call(client->vcl_doorfd, &darg); 70 } while (ret != 0 && errno == EINTR); 71 if (ret != 0) { 72 switch (errno) { 73 case E2BIG: 74 case EFAULT: 75 case EINVAL: 76 case ENOTSUP: 77 case EOVERFLOW: 78 case ENFILE: 79 libvarpd_panic("unhandleable errno from door_call: %d", 80 errno); 81 } 82 ret = errno; 83 } 84 85 return (ret); 86 } 87 88 int 89 libvarpd_c_create(varpd_client_handle_t **chpp, const char *doorname) 90 { 91 varpd_client_t *client; 92 93 client = umem_alloc(sizeof (varpd_client_t), UMEM_DEFAULT); 94 if (client == NULL) 95 return (ENOMEM); 96 97 client->vcl_doorfd = open(doorname, O_RDWR); 98 if (client->vcl_doorfd < 0) { 99 int ret = errno; 100 umem_free(client, sizeof (varpd_client_t)); 101 return (ret); 102 } 103 104 *chpp = (varpd_client_handle_t *)client; 105 return (0); 106 } 107 108 void 109 libvarpd_c_destroy(varpd_client_handle_t *chp) 110 { 111 varpd_client_t *client = (varpd_client_t *)chp; 112 if (close(client->vcl_doorfd) != 0) 113 libvarpd_panic("failed to close door fd %d: %d", 114 client->vcl_doorfd, errno); 115 116 umem_free(chp, sizeof (varpd_client_t)); 117 } 118 119 int 120 libvarpd_c_instance_create(varpd_client_handle_t *chp, datalink_id_t linkid, 121 const char *search, uint64_t *cidp) 122 { 123 int ret; 124 varpd_client_t *client = (varpd_client_t *)chp; 125 varpd_client_arg_t carg; 126 varpd_client_create_arg_t *cap = &carg.vca_un.vca_create; 127 128 if (strlen(search) >= LIBVARPD_PROP_NAMELEN) 129 return (EINVAL); 130 carg.vca_command = VARPD_CLIENT_CREATE; 131 carg.vca_errno = 0; 132 cap->vcca_linkid = linkid; 133 (void) strlcpy(cap->vcca_plugin, search, LIBVARPD_PROP_NAMELEN); 134 135 ret = libvarpd_c_door_call(client, &carg, 0); 136 if (ret != 0) 137 return (ret); 138 139 if (carg.vca_errno != 0) 140 return (carg.vca_errno); 141 142 *cidp = cap->vcca_id; 143 144 return (0); 145 } 146 147 int 148 libvarpd_c_instance_activate(varpd_client_handle_t *chp, uint64_t cid) 149 { 150 int ret; 151 varpd_client_t *client = (varpd_client_t *)chp; 152 varpd_client_arg_t carg; 153 varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance; 154 155 carg.vca_command = VARPD_CLIENT_ACTIVATE; 156 carg.vca_errno = 0; 157 vciap->vcia_id = cid; 158 159 ret = libvarpd_c_door_call(client, &carg, 0); 160 if (ret != 0) 161 return (ret); 162 163 if (carg.vca_errno != 0) 164 return (carg.vca_errno); 165 166 return (0); 167 } 168 169 int 170 libvarpd_c_instance_destroy(varpd_client_handle_t *chp, uint64_t cid) 171 { 172 int ret; 173 varpd_client_t *client = (varpd_client_t *)chp; 174 varpd_client_arg_t carg; 175 varpd_client_instance_arg_t *vciap = &carg.vca_un.vca_instance; 176 177 carg.vca_command = VARPD_CLIENT_DESTROY; 178 carg.vca_errno = 0; 179 vciap->vcia_id = cid; 180 181 ret = libvarpd_c_door_call(client, &carg, 0); 182 if (ret != 0) 183 return (ret); 184 185 if (carg.vca_errno != 0) 186 return (carg.vca_errno); 187 188 return (0); 189 } 190 191 int 192 libvarpd_c_prop_nprops(varpd_client_handle_t *chp, uint64_t cid, uint_t *nprops) 193 { 194 int ret; 195 varpd_client_t *client = (varpd_client_t *)chp; 196 varpd_client_arg_t carg; 197 varpd_client_nprops_arg_t *vcnap = &carg.vca_un.vca_nprops; 198 199 carg.vca_command = VARPD_CLIENT_NPROPS; 200 carg.vca_errno = 0; 201 vcnap->vcna_id = cid; 202 vcnap->vcna_nprops = 0; 203 204 ret = libvarpd_c_door_call(client, &carg, 0); 205 if (ret != 0) 206 return (ret); 207 208 if (carg.vca_errno != 0) 209 return (carg.vca_errno); 210 *nprops = vcnap->vcna_nprops; 211 return (0); 212 } 213 214 int 215 libvarpd_c_prop_handle_alloc(varpd_client_handle_t *chp, uint64_t cid, 216 varpd_client_prop_handle_t **phdlp) 217 { 218 varpd_client_prop_info_t *infop; 219 220 infop = umem_alloc(sizeof (varpd_client_prop_info_t), UMEM_DEFAULT); 221 if (infop == NULL) 222 return (ENOMEM); 223 224 bzero(infop, sizeof (varpd_client_prop_info_t)); 225 infop->vcprop_client = (varpd_client_t *)chp; 226 infop->vcprop_instance = cid; 227 infop->vcprop_propid = UINT_MAX; 228 *phdlp = (varpd_client_prop_handle_t *)infop; 229 return (0); 230 } 231 232 void 233 libvarpd_c_prop_handle_free(varpd_client_prop_handle_t *phdl) 234 { 235 umem_free(phdl, sizeof (varpd_client_prop_info_t)); 236 phdl = NULL; 237 } 238 239 static void 240 libvarpd_c_prop_info_from_door(varpd_client_prop_info_t *infop, 241 const varpd_client_propinfo_arg_t *vcfap) 242 { 243 infop->vcprop_propid = vcfap->vcfa_propid; 244 infop->vcprop_type = vcfap->vcfa_type; 245 infop->vcprop_prot = vcfap->vcfa_prot; 246 infop->vcprop_defsize = vcfap->vcfa_defsize; 247 infop->vcprop_psize = vcfap->vcfa_psize; 248 bcopy(vcfap->vcfa_name, infop->vcprop_name, LIBVARPD_PROP_NAMELEN); 249 bcopy(vcfap->vcfa_default, infop->vcprop_default, 250 LIBVARPD_PROP_SIZEMAX); 251 bcopy(vcfap->vcfa_poss, infop->vcprop_poss, LIBVARPD_PROP_SIZEMAX); 252 } 253 254 int 255 libvarpd_c_prop_info_fill_by_name(varpd_client_prop_handle_t *phdl, 256 const char *name) 257 { 258 int ret; 259 varpd_client_arg_t carg; 260 varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info; 261 varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl; 262 263 if (strlen(name) >= LIBVARPD_PROP_NAMELEN) 264 return (EINVAL); 265 bzero(&carg, sizeof (varpd_client_arg_t)); 266 carg.vca_command = VARPD_CLIENT_PROPINFO; 267 carg.vca_errno = 0; 268 vcfap->vcfa_id = infop->vcprop_instance; 269 vcfap->vcfa_propid = UINT_MAX; 270 (void) strlcpy(vcfap->vcfa_name, name, LIBVARPD_PROP_NAMELEN); 271 272 ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0); 273 if (ret != 0) 274 return (ret); 275 276 if (carg.vca_errno != 0) 277 return (carg.vca_errno); 278 279 libvarpd_c_prop_info_from_door(infop, vcfap); 280 return (0); 281 } 282 283 int 284 libvarpd_c_prop_info_fill(varpd_client_prop_handle_t *phdl, uint_t propid) 285 { 286 int ret; 287 varpd_client_arg_t carg; 288 varpd_client_propinfo_arg_t *vcfap = &carg.vca_un.vca_info; 289 varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl; 290 291 bzero(&carg, sizeof (varpd_client_arg_t)); 292 carg.vca_command = VARPD_CLIENT_PROPINFO; 293 carg.vca_errno = 0; 294 vcfap->vcfa_id = infop->vcprop_instance; 295 vcfap->vcfa_propid = propid; 296 297 ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0); 298 if (ret != 0) 299 return (ret); 300 301 if (carg.vca_errno != 0) 302 return (carg.vca_errno); 303 304 libvarpd_c_prop_info_from_door(infop, vcfap); 305 return (0); 306 } 307 308 int 309 libvarpd_c_prop_info(varpd_client_prop_handle_t *phdl, const char **namep, 310 uint_t *typep, uint_t *protp, const void **defp, uint32_t *defsizep, 311 const mac_propval_range_t **possp) 312 { 313 varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl; 314 if (infop->vcprop_propid == UINT_MAX) 315 return (EINVAL); 316 317 if (namep != NULL) 318 *namep = infop->vcprop_name; 319 if (typep != NULL) 320 *typep = infop->vcprop_type; 321 if (protp != NULL) 322 *protp = infop->vcprop_prot; 323 if (defp != NULL) 324 *defp = infop->vcprop_default; 325 if (defsizep != NULL) 326 *defsizep = infop->vcprop_defsize; 327 if (possp != NULL) 328 *possp = (const mac_propval_range_t *)infop->vcprop_poss; 329 return (0); 330 } 331 332 int 333 libvarpd_c_prop_get(varpd_client_prop_handle_t *phdl, void *buf, uint32_t *len) 334 { 335 int ret; 336 varpd_client_arg_t carg; 337 varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop; 338 varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl; 339 340 if (len == NULL || buf == NULL || infop->vcprop_propid == UINT_MAX) 341 return (EINVAL); 342 if (*len < LIBVARPD_PROP_SIZEMAX) 343 return (EOVERFLOW); 344 345 bzero(&carg, sizeof (varpd_client_arg_t)); 346 carg.vca_command = VARPD_CLIENT_GETPROP; 347 carg.vca_errno = 0; 348 vcpap->vcpa_id = infop->vcprop_instance; 349 vcpap->vcpa_propid = infop->vcprop_propid; 350 351 ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0); 352 if (ret != 0) 353 return (ret); 354 355 if (carg.vca_errno != 0) 356 return (carg.vca_errno); 357 358 /* 359 * If the buffer size is too large then something odd has certainly 360 * happened here, it means that varpd has gone rogue. In such a case we 361 * return a rather odd errror, though we don't believe that this should 362 * generally happen. 363 */ 364 if (vcpap->vcpa_bufsize > LIBVARPD_PROP_SIZEMAX) 365 return (E2BIG); 366 367 bcopy(vcpap->vcpa_buf, buf, vcpap->vcpa_bufsize); 368 *len = vcpap->vcpa_bufsize; 369 return (0); 370 } 371 372 int 373 libvarpd_c_prop_set(varpd_client_prop_handle_t *phdl, const void *buf, 374 uint32_t len) 375 { 376 int ret; 377 varpd_client_arg_t carg; 378 varpd_client_prop_arg_t *vcpap = &carg.vca_un.vca_prop; 379 varpd_client_prop_info_t *infop = (varpd_client_prop_info_t *)phdl; 380 381 if (len == 0 || buf == NULL || infop->vcprop_propid == UINT_MAX) 382 return (EINVAL); 383 if (len > LIBVARPD_PROP_SIZEMAX) 384 return (EOVERFLOW); 385 386 carg.vca_command = VARPD_CLIENT_SETPROP; 387 carg.vca_errno = 0; 388 vcpap->vcpa_id = infop->vcprop_instance; 389 vcpap->vcpa_propid = infop->vcprop_propid; 390 vcpap->vcpa_bufsize = len; 391 bcopy(buf, vcpap->vcpa_buf, len); 392 393 ret = libvarpd_c_door_call(infop->vcprop_client, &carg, 0); 394 if (ret != 0) 395 return (ret); 396 397 if (carg.vca_errno != 0) 398 return (carg.vca_errno); 399 400 return (0); 401 } 402 403 int 404 libvarpd_c_instance_lookup(varpd_client_handle_t *chp, datalink_id_t linkid, 405 uint64_t *instp) 406 { 407 int ret; 408 varpd_client_arg_t carg; 409 varpd_client_lookup_arg_t *vclap = &carg.vca_un.vca_lookup; 410 varpd_client_t *client = (varpd_client_t *)chp; 411 412 carg.vca_command = VARPD_CLIENT_LOOKUP; 413 carg.vca_errno = 0; 414 vclap->vcla_linkid = linkid; 415 ret = libvarpd_c_door_call(client, &carg, 0); 416 if (ret != 0) 417 return (ret); 418 419 if (carg.vca_errno != 0) 420 return (carg.vca_errno); 421 if (instp != NULL) 422 *instp = vclap->vcla_id; 423 424 return (0); 425 } 426 427 int 428 libvarpd_c_instance_target_mode(varpd_client_handle_t *chp, uint64_t cid, 429 uint_t *dtype, uint_t *mtype) 430 { 431 int ret; 432 varpd_client_arg_t carg; 433 varpd_client_target_mode_arg_t *vctmap = &carg.vca_un.vca_mode; 434 varpd_client_t *client = (varpd_client_t *)chp; 435 436 carg.vca_command = VARPD_CLIENT_TARGET_MODE; 437 carg.vca_errno = 0; 438 vctmap->vtma_id = cid; 439 ret = libvarpd_c_door_call(client, &carg, 0); 440 if (ret != 0) 441 return (ret); 442 443 if (carg.vca_errno != 0) 444 return (carg.vca_errno); 445 if (ret == 0) { 446 if (mtype != NULL) 447 *mtype = vctmap->vtma_mode; 448 if (dtype != NULL) 449 *dtype = vctmap->vtma_dest; 450 } 451 452 return (ret); 453 } 454 455 int 456 libvarpd_c_instance_cache_flush(varpd_client_handle_t *chp, uint64_t cid) 457 { 458 int ret; 459 varpd_client_arg_t carg; 460 varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache; 461 varpd_client_t *client = (varpd_client_t *)chp; 462 463 carg.vca_command = VARPD_CLIENT_CACHE_FLUSH; 464 carg.vca_errno = 0; 465 466 vctcap->vtca_id = cid; 467 ret = libvarpd_c_door_call(client, &carg, 0); 468 if (ret != 0) 469 return (ret); 470 471 if (carg.vca_errno != 0) 472 return (carg.vca_errno); 473 474 return (0); 475 } 476 477 int 478 libvarpd_c_instance_cache_delete(varpd_client_handle_t *chp, uint64_t cid, 479 const struct ether_addr *key) 480 { 481 int ret; 482 varpd_client_arg_t carg; 483 varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache; 484 varpd_client_t *client = (varpd_client_t *)chp; 485 486 if (key == NULL) 487 return (EINVAL); 488 489 carg.vca_command = VARPD_CLIENT_CACHE_DELETE; 490 carg.vca_errno = 0; 491 vctcap->vtca_id = cid; 492 bcopy(key, vctcap->vtca_key, ETHERADDRL); 493 494 ret = libvarpd_c_door_call(client, &carg, 0); 495 if (ret != 0) 496 return (ret); 497 498 if (carg.vca_errno != 0) 499 return (carg.vca_errno); 500 501 return (0); 502 } 503 504 int 505 libvarpd_c_instance_cache_get(varpd_client_handle_t *chp, uint64_t cid, 506 const struct ether_addr *key, varpd_client_cache_entry_t *entry) 507 { 508 int ret; 509 varpd_client_arg_t carg; 510 varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache; 511 varpd_client_t *client = (varpd_client_t *)chp; 512 513 if (key == NULL || entry == NULL) 514 return (EINVAL); 515 516 carg.vca_command = VARPD_CLIENT_CACHE_GET; 517 carg.vca_errno = 0; 518 vctcap->vtca_id = cid; 519 bcopy(key, vctcap->vtca_key, ETHERADDRL); 520 bzero(&vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t)); 521 522 ret = libvarpd_c_door_call(client, &carg, 0); 523 if (ret != 0) 524 return (ret); 525 526 if (carg.vca_errno != 0) 527 return (carg.vca_errno); 528 529 bcopy(&vctcap->vtca_entry, entry, sizeof (varpd_client_cache_entry_t)); 530 return (0); 531 } 532 533 int 534 libvarpd_c_instance_cache_set(varpd_client_handle_t *chp, uint64_t cid, 535 const struct ether_addr *key, const varpd_client_cache_entry_t *entry) 536 { 537 int ret; 538 varpd_client_arg_t carg; 539 varpd_client_target_cache_arg_t *vctcap = &carg.vca_un.vca_cache; 540 varpd_client_t *client = (varpd_client_t *)chp; 541 542 if (key == NULL || entry == NULL) 543 return (EINVAL); 544 545 carg.vca_command = VARPD_CLIENT_CACHE_SET; 546 carg.vca_errno = 0; 547 vctcap->vtca_id = cid; 548 bcopy(key, vctcap->vtca_key, ETHERADDRL); 549 bcopy(entry, &vctcap->vtca_entry, sizeof (varpd_client_cache_entry_t)); 550 551 ret = libvarpd_c_door_call(client, &carg, 0); 552 if (ret != 0) 553 return (ret); 554 555 if (carg.vca_errno != 0) 556 return (carg.vca_errno); 557 558 return (0); 559 } 560 561 int 562 libvarpd_c_instance_cache_walk(varpd_client_handle_t *chp, uint64_t cid, 563 varpd_client_cache_f func, void *arg) 564 { 565 int ret = 0; 566 size_t bufsize = sizeof (varpd_client_arg_t) + 567 100 * sizeof (varpd_client_cache_entry_t); 568 varpd_client_t *client = (varpd_client_t *)chp; 569 varpd_client_arg_t *cargp; 570 varpd_client_target_walk_arg_t *vctwap; 571 572 /* 573 * Because the number of entries involved in a walk may be large, we 574 * dynamically allocate a number of queries to make at a single time. 575 * This also means that the average door request doesn't inflate by the 576 * number of entries we want. For now, let's always grab 100 entries in 577 * a request. 578 */ 579 cargp = umem_zalloc(bufsize, UMEM_DEFAULT); 580 if (cargp == NULL) 581 return (errno); 582 vctwap = &cargp->vca_un.vca_walk; 583 for (;;) { 584 int i; 585 586 cargp->vca_command = VARPD_CLIENT_CACHE_WALK; 587 cargp->vca_errno = 0; 588 vctwap->vtcw_id = cid; 589 vctwap->vtcw_count = 100; 590 591 ret = libvarpd_c_door_call(client, cargp, bufsize); 592 if (ret != 0) 593 break; 594 595 if (cargp->vca_errno != 0) { 596 ret = cargp->vca_errno; 597 break; 598 } 599 600 if (vctwap->vtcw_count == 0) { 601 ret = 0; 602 break; 603 } 604 605 for (i = 0; i < vctwap->vtcw_count; i++) { 606 varpd_client_cache_entry_t ent; 607 608 ent.vcp_flags = vctwap->vtcw_ents[i].otce_flags; 609 bcopy(vctwap->vtcw_ents[i].otce_dest.otp_mac, 610 &ent.vcp_mac, ETHERADDRL); 611 ent.vcp_ip = vctwap->vtcw_ents[i].otce_dest.otp_ip; 612 ent.vcp_port = vctwap->vtcw_ents[i].otce_dest.otp_port; 613 ret = func(chp, cid, 614 (struct ether_addr *)vctwap->vtcw_ents[i].otce_mac, 615 &ent, arg); 616 if (ret != 0) { 617 ret = 0; 618 goto done; 619 } 620 } 621 } 622 623 done: 624 umem_free(cargp, bufsize); 625 return (ret); 626 } 627