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 2015 Joyent, Inc. 14 */ 15 16 /* 17 * Interactions with /dev/overlay 18 */ 19 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <fcntl.h> 23 #include <errno.h> 24 #include <assert.h> 25 #include <unistd.h> 26 #include <stdlib.h> 27 #include <stropts.h> 28 #include <strings.h> 29 #include <umem.h> 30 31 #include <libvarpd_impl.h> 32 #include <sys/overlay_target.h> 33 34 #define OVERLAY_PATH "/dev/overlay" 35 36 int 37 libvarpd_overlay_init(varpd_impl_t *vip) 38 { 39 vip->vdi_overlayfd = open(OVERLAY_PATH, O_RDWR | O_EXCL); 40 if (vip->vdi_overlayfd == -1) 41 return (errno); 42 return (0); 43 } 44 45 void 46 libvarpd_overlay_fini(varpd_impl_t *vip) 47 { 48 assert(vip->vdi_overlayfd > 0); 49 if (close(vip->vdi_overlayfd) != 0) 50 libvarpd_panic("failed to close /dev/overlay fd %d: %d", 51 vip->vdi_overlayfd, errno); 52 } 53 54 int 55 libvarpd_overlay_info(varpd_impl_t *vip, datalink_id_t linkid, 56 overlay_plugin_dest_t *destp, uint64_t *flags, uint64_t *vnetid) 57 { 58 overlay_targ_info_t oti; 59 60 oti.oti_linkid = linkid; 61 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_INFO, &oti) != 0) 62 return (errno); 63 64 if (destp != NULL) 65 *destp = oti.oti_needs; 66 if (flags != NULL) 67 *flags = oti.oti_flags; 68 if (vnetid != NULL) 69 *vnetid = oti.oti_vnetid; 70 return (0); 71 } 72 73 int 74 libvarpd_overlay_associate(varpd_instance_t *inst) 75 { 76 overlay_targ_associate_t ota; 77 varpd_impl_t *vip = inst->vri_impl; 78 79 bzero(&ota, sizeof (overlay_targ_associate_t)); 80 ota.ota_linkid = inst->vri_linkid; 81 ota.ota_mode = inst->vri_mode; 82 ota.ota_id = inst->vri_id; 83 ota.ota_provides = inst->vri_dest; 84 85 if (ota.ota_mode == OVERLAY_TARGET_POINT) { 86 int ret; 87 ret = inst->vri_plugin->vpp_ops->vpo_default(inst->vri_private, 88 &ota.ota_point); 89 if (ret != VARPD_LOOKUP_OK) 90 return (ret); 91 } 92 93 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_ASSOCIATE, &ota) != 0) 94 return (errno); 95 96 return (0); 97 } 98 99 int 100 libvarpd_overlay_disassociate(varpd_instance_t *inst) 101 { 102 overlay_targ_id_t otid; 103 varpd_impl_t *vip = inst->vri_impl; 104 105 otid.otid_linkid = inst->vri_linkid; 106 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DISASSOCIATE, &otid) != 0) 107 return (errno); 108 return (0); 109 } 110 111 int 112 libvarpd_overlay_degrade_datalink(varpd_impl_t *vip, datalink_id_t linkid, 113 const char *msg) 114 { 115 overlay_targ_degrade_t otd; 116 117 otd.otd_linkid = linkid; 118 (void) strlcpy(otd.otd_buf, msg, OVERLAY_STATUS_BUFLEN); 119 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_DEGRADE, &otd) != 0) 120 return (errno); 121 return (0); 122 123 } 124 125 int 126 libvarpd_overlay_degrade(varpd_instance_t *inst, const char *msg) 127 { 128 return (libvarpd_overlay_degrade_datalink(inst->vri_impl, 129 inst->vri_linkid, msg)); 130 } 131 132 int 133 libvarpd_overlay_restore(varpd_instance_t *inst) 134 { 135 overlay_targ_id_t otid; 136 varpd_impl_t *vip = inst->vri_impl; 137 138 otid.otid_linkid = inst->vri_linkid; 139 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_RESTORE, &otid) != 0) 140 return (errno); 141 return (0); 142 } 143 144 int 145 libvarpd_overlay_packet(varpd_impl_t *vip, const overlay_targ_lookup_t *otl, 146 void *buf, size_t *buflen) 147 { 148 int ret; 149 overlay_targ_pkt_t otp; 150 151 otp.otp_linkid = UINT64_MAX; 152 otp.otp_reqid = otl->otl_reqid; 153 otp.otp_size = *buflen; 154 otp.otp_buf = buf; 155 156 do { 157 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_PKT, &otp); 158 } while (ret != 0 && errno == EINTR); 159 if (ret != 0 && errno == EFAULT) 160 libvarpd_panic("OVERLAY_TARG_PKT ioctl efault"); 161 else if (ret != 0) 162 ret = errno; 163 164 if (ret == 0) 165 *buflen = otp.otp_size; 166 167 return (ret); 168 } 169 170 static int 171 libvarpd_overlay_inject_common(varpd_impl_t *vip, varpd_instance_t *inst, 172 const overlay_targ_lookup_t *otl, void *buf, size_t buflen, int cmd) 173 { 174 int ret; 175 overlay_targ_pkt_t otp; 176 177 if (otl == NULL) { 178 otp.otp_linkid = inst->vri_linkid; 179 otp.otp_reqid = 0; 180 } else { 181 otp.otp_linkid = UINT64_MAX; 182 otp.otp_reqid = otl->otl_reqid; 183 } 184 otp.otp_size = buflen; 185 otp.otp_buf = buf; 186 187 do { 188 ret = ioctl(vip->vdi_overlayfd, cmd, &otp); 189 } while (ret != 0 && errno == EINTR); 190 if (ret != 0 && errno == EFAULT) 191 libvarpd_panic("overlay_inject_common ioctl EFAULT"); 192 else if (ret != 0) 193 ret = errno; 194 195 return (ret); 196 } 197 198 int 199 libvarpd_overlay_inject(varpd_impl_t *vip, const overlay_targ_lookup_t *otl, 200 void *buf, size_t buflen) 201 { 202 return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen, 203 OVERLAY_TARG_INJECT)); 204 } 205 206 int 207 libvarpd_overlay_instance_inject(varpd_instance_t *inst, void *buf, 208 size_t buflen) 209 { 210 return (libvarpd_overlay_inject_common(inst->vri_impl, inst, NULL, buf, 211 buflen, OVERLAY_TARG_INJECT)); 212 } 213 214 int 215 libvarpd_overlay_resend(varpd_impl_t *vip, const overlay_targ_lookup_t *otl, 216 void *buf, size_t buflen) 217 { 218 return (libvarpd_overlay_inject_common(vip, NULL, otl, buf, buflen, 219 OVERLAY_TARG_RESEND)); 220 } 221 222 static void 223 libvarpd_overlay_lookup_reply(varpd_impl_t *vip, 224 const overlay_targ_lookup_t *otl, overlay_targ_resp_t *otr, int cmd) 225 { 226 int ret; 227 228 otr->otr_reqid = otl->otl_reqid; 229 do { 230 ret = ioctl(vip->vdi_overlayfd, cmd, otr); 231 } while (ret != 0 && errno == EINTR); 232 233 /* 234 * The only errors that should cause us to end up here are due to 235 * programmer errors. Arguably the EINVAL case indicates that something 236 * is a bit off; however, at this time we don't opt to kill varpd. 237 */ 238 if (ret != 0 && errno != EINVAL) 239 libvarpd_panic("received bad errno from lookup_reply " 240 "(cmd %d): %d\n", cmd, errno); 241 } 242 243 static void 244 libvarpd_overlay_lookup_handle(varpd_impl_t *vip) 245 { 246 int ret; 247 varpd_query_t *vqp; 248 overlay_targ_lookup_t *otl; 249 overlay_targ_resp_t *otr; 250 varpd_instance_t *inst; 251 252 vqp = umem_cache_alloc(vip->vdi_qcache, UMEM_DEFAULT); 253 otl = &vqp->vq_lookup; 254 otr = &vqp->vq_response; 255 /* 256 * abort doesn't really help here that much, maybe we can instead try 257 * and for a reap or something? 258 */ 259 if (vqp == NULL) 260 libvarpd_panic("failed to allocate memory for lookup " 261 "handle..., we should not panic()"); 262 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LOOKUP, otl); 263 if (ret != 0 && errno != ETIME && errno != EINTR) 264 libvarpd_panic("received bad errno from OVERLAY_TARG_LOOKUP: " 265 "%d", errno); 266 267 if (ret != 0) { 268 umem_cache_free(vip->vdi_qcache, vqp); 269 return; 270 } 271 272 inst = (varpd_instance_t *)libvarpd_instance_lookup( 273 (varpd_handle_t *)vip, otl->otl_varpdid); 274 if (inst == NULL) { 275 libvarpd_overlay_lookup_reply(vip, otl, otr, 276 OVERLAY_TARG_DROP); 277 umem_cache_free(vip->vdi_qcache, vqp); 278 return; 279 } 280 vqp->vq_instance = inst; 281 282 inst->vri_plugin->vpp_ops->vpo_lookup(inst->vri_private, 283 (varpd_query_handle_t *)vqp, otl, &otr->otr_answer); 284 } 285 286 /* Use "void *" for vhp here to play nicely with thr_create(). */ 287 void * 288 libvarpd_overlay_lookup_run(void *vhp) 289 { 290 varpd_impl_t *vip = (varpd_impl_t *)vhp; 291 292 mutex_enter(&vip->vdi_lock); 293 if (vip->vdi_lthr_quiesce == B_TRUE) { 294 mutex_exit(&vip->vdi_lock); 295 return (NULL); 296 } 297 vip->vdi_lthr_count++; 298 299 for (;;) { 300 mutex_exit(&vip->vdi_lock); 301 libvarpd_overlay_lookup_handle(vip); 302 mutex_enter(&vip->vdi_lock); 303 if (vip->vdi_lthr_quiesce == B_TRUE) 304 break; 305 } 306 assert(vip->vdi_lthr_count > 0); 307 vip->vdi_lthr_count--; 308 (void) cond_signal(&vip->vdi_lthr_cv); 309 mutex_exit(&vip->vdi_lock); 310 return (NULL); 311 } 312 313 void 314 libvarpd_overlay_lookup_quiesce(varpd_handle_t *vhp) 315 { 316 varpd_impl_t *vip = (varpd_impl_t *)vhp; 317 318 mutex_enter(&vip->vdi_lock); 319 if (vip->vdi_lthr_count == 0) { 320 mutex_exit(&vip->vdi_lock); 321 return; 322 } 323 vip->vdi_lthr_quiesce = B_TRUE; 324 while (vip->vdi_lthr_count > 0) 325 (void) cond_wait(&vip->vdi_lthr_cv, &vip->vdi_lock); 326 vip->vdi_lthr_quiesce = B_FALSE; 327 mutex_exit(&vip->vdi_lock); 328 } 329 330 int 331 libvarpd_overlay_iter(varpd_impl_t *vip, libvarpd_overlay_iter_f func, 332 void *arg) 333 { 334 uint32_t curents = 0, i; 335 size_t size; 336 overlay_targ_list_t *otl; 337 338 for (;;) { 339 size = sizeof (overlay_targ_list_t) + 340 sizeof (uint32_t) * curents; 341 otl = umem_alloc(size, UMEM_DEFAULT); 342 if (otl == NULL) 343 return (ENOMEM); 344 345 otl->otl_nents = curents; 346 if (ioctl(vip->vdi_overlayfd, OVERLAY_TARG_LIST, otl) != 0) { 347 if (errno == EFAULT) 348 libvarpd_panic("OVERLAY_TARG_LIST ioctl " 349 "efault"); 350 umem_free(otl, size); 351 if (errno == EINTR) 352 continue; 353 else 354 return (errno); 355 } 356 357 if (otl->otl_nents == curents) 358 break; 359 360 curents = otl->otl_nents; 361 umem_free(otl, size); 362 } 363 364 for (i = 0; i < otl->otl_nents; i++) { 365 if (func(vip, otl->otl_ents[i], arg) != 0) 366 break; 367 } 368 umem_free(otl, size); 369 return (0); 370 } 371 372 int 373 libvarpd_overlay_cache_flush(varpd_instance_t *inst) 374 { 375 int ret; 376 overlay_targ_cache_t cache; 377 varpd_impl_t *vip = inst->vri_impl; 378 379 bzero(&cache, sizeof (overlay_targ_cache_t)); 380 cache.otc_linkid = inst->vri_linkid; 381 382 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_FLUSH, &cache); 383 if (ret != 0 && errno == EFAULT) 384 libvarpd_panic("OVERLAY_TARG_CACHE_FLUSH ioctl efault"); 385 else if (ret != 0) 386 ret = errno; 387 388 return (ret); 389 } 390 391 int 392 libvarpd_overlay_cache_delete(varpd_instance_t *inst, const uint8_t *key) 393 { 394 int ret; 395 overlay_targ_cache_t cache; 396 varpd_impl_t *vip = inst->vri_impl; 397 398 bzero(&cache, sizeof (overlay_targ_cache_t)); 399 cache.otc_linkid = inst->vri_linkid; 400 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL); 401 402 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_REMOVE, &cache); 403 if (ret != 0 && errno == EFAULT) 404 libvarpd_panic("OVERLAY_TARG_CACHE_REMOVE ioctl efault"); 405 else if (ret != 0) 406 ret = errno; 407 408 return (ret); 409 410 } 411 412 int 413 libvarpd_overlay_cache_get(varpd_instance_t *inst, const uint8_t *key, 414 varpd_client_cache_entry_t *entry) 415 { 416 int ret; 417 overlay_targ_cache_t cache; 418 varpd_impl_t *vip = inst->vri_impl; 419 420 bzero(&cache, sizeof (overlay_targ_cache_t)); 421 cache.otc_linkid = inst->vri_linkid; 422 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL); 423 424 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_GET, &cache); 425 if (ret != 0 && errno == EFAULT) 426 libvarpd_panic("OVERLAY_TARG_CACHE_GET ioctl efault"); 427 else if (ret != 0) 428 return (errno); 429 430 bcopy(cache.otc_entry.otce_dest.otp_mac, &entry->vcp_mac, ETHERADDRL); 431 entry->vcp_flags = cache.otc_entry.otce_flags; 432 entry->vcp_ip = cache.otc_entry.otce_dest.otp_ip; 433 entry->vcp_port = cache.otc_entry.otce_dest.otp_port; 434 435 return (0); 436 } 437 438 int 439 libvarpd_overlay_cache_set(varpd_instance_t *inst, const uint8_t *key, 440 const varpd_client_cache_entry_t *entry) 441 { 442 int ret; 443 overlay_targ_cache_t cache; 444 varpd_impl_t *vip = inst->vri_impl; 445 446 bzero(&cache, sizeof (overlay_targ_cache_t)); 447 cache.otc_linkid = inst->vri_linkid; 448 bcopy(key, cache.otc_entry.otce_mac, ETHERADDRL); 449 bcopy(&entry->vcp_mac, cache.otc_entry.otce_dest.otp_mac, ETHERADDRL); 450 cache.otc_entry.otce_flags = entry->vcp_flags; 451 cache.otc_entry.otce_dest.otp_ip = entry->vcp_ip; 452 cache.otc_entry.otce_dest.otp_port = entry->vcp_port; 453 454 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &cache); 455 if (ret != 0 && errno == EFAULT) 456 libvarpd_panic("OVERLAY_TARG_CACHE_SET ioctl efault"); 457 else if (ret != 0) 458 return (errno); 459 460 return (0); 461 } 462 463 int 464 libvarpd_overlay_cache_walk_fill(varpd_instance_t *inst, uint64_t *markerp, 465 uint64_t *countp, overlay_targ_cache_entry_t *ents) 466 { 467 int ret; 468 size_t asize; 469 overlay_targ_cache_iter_t *iter; 470 varpd_impl_t *vip = inst->vri_impl; 471 472 if (*countp > 200) 473 return (E2BIG); 474 475 asize = sizeof (overlay_targ_cache_iter_t) + 476 *countp * sizeof (overlay_targ_cache_entry_t); 477 iter = umem_alloc(asize, UMEM_DEFAULT); 478 if (iter == NULL) 479 return (ENOMEM); 480 481 iter->otci_linkid = inst->vri_linkid; 482 iter->otci_marker = *markerp; 483 iter->otci_count = *countp; 484 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_ITER, iter); 485 if (ret != 0 && errno == EFAULT) 486 libvarpd_panic("OVERLAY_TARG_CACHE_ITER ioctl efault"); 487 else if (ret != 0) { 488 ret = errno; 489 goto out; 490 } 491 492 *markerp = iter->otci_marker; 493 *countp = iter->otci_count; 494 bcopy(iter->otci_ents, ents, 495 *countp * sizeof (overlay_targ_cache_entry_t)); 496 out: 497 umem_free(iter, asize); 498 return (ret); 499 } 500 501 void 502 libvarpd_plugin_query_reply(varpd_query_handle_t *vqh, int action) 503 { 504 varpd_query_t *vqp = (varpd_query_t *)vqh; 505 506 if (vqp == NULL) 507 libvarpd_panic("unknown plugin passed invalid " 508 "varpd_query_handle_t"); 509 510 if (action == VARPD_LOOKUP_DROP) 511 libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl, 512 &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_DROP); 513 else if (action == VARPD_LOOKUP_OK) 514 libvarpd_overlay_lookup_reply(vqp->vq_instance->vri_impl, 515 &vqp->vq_lookup, &vqp->vq_response, OVERLAY_TARG_RESPOND); 516 else 517 libvarpd_panic("plugin %s passed in an invalid action: %d", 518 vqp->vq_instance->vri_plugin->vpp_name, action); 519 520 umem_cache_free(vqp->vq_instance->vri_impl->vdi_qcache, vqp); 521 } 522 523 void 524 libvarpd_inject_varp(varpd_provider_handle_t *vph, const uint8_t *mac, 525 const overlay_target_point_t *otp) 526 { 527 int ret; 528 overlay_targ_cache_t otc; 529 varpd_instance_t *inst = (varpd_instance_t *)vph; 530 varpd_impl_t *vip = inst->vri_impl; 531 532 if (otp == NULL) { 533 (void) libvarpd_overlay_cache_delete(inst, mac); 534 return; 535 } 536 537 otc.otc_linkid = inst->vri_linkid; 538 otc.otc_entry.otce_flags = 0; 539 bcopy(mac, otc.otc_entry.otce_mac, ETHERADDRL); 540 bcopy(otp, &otc.otc_entry.otce_dest, sizeof (overlay_target_point_t)); 541 542 ret = ioctl(vip->vdi_overlayfd, OVERLAY_TARG_CACHE_SET, &otc); 543 if (ret != 0) { 544 switch (errno) { 545 case EBADF: 546 case EFAULT: 547 case ENOTSUP: 548 libvarpd_panic("received bad errno from " 549 "OVERLAY_TARG_CACHE_SET: %d", errno); 550 default: 551 break; 552 } 553 } 554 } 555 556 void 557 libvarpd_fma_degrade(varpd_provider_handle_t *vph, const char *msg) 558 { 559 int ret; 560 varpd_instance_t *inst = (varpd_instance_t *)vph; 561 562 ret = libvarpd_overlay_degrade(inst, msg); 563 switch (ret) { 564 case ENOENT: 565 case EFAULT: 566 libvarpd_panic("received bad errno from degrade ioctl: %d", 567 errno); 568 default: 569 break; 570 } 571 } 572 573 void 574 libvarpd_fma_restore(varpd_provider_handle_t *vph) 575 { 576 int ret; 577 varpd_instance_t *inst = (varpd_instance_t *)vph; 578 579 ret = libvarpd_overlay_restore(inst); 580 switch (ret) { 581 case ENOENT: 582 case EFAULT: 583 libvarpd_panic("received bad errno from restore ioctl: %d", 584 errno); 585 default: 586 break; 587 } 588 } 589