338 }
339
340 void
341 dlmgmt_table_unlock(void)
342 {
343 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
344 (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
345 (void) pthread_cond_broadcast(&dlmgmt_avl_cv);
346 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
347 }
348
349 void
350 link_destroy(dlmgmt_link_t *linkp)
351 {
352 linkattr_destroy(linkp);
353 free(linkp);
354 }
355
356 /*
357 * Set the DLMGMT_ACTIVE flag on the link to note that it is active.
358 * When a link is active and is owned by an NGZ then it is added to
359 * that zone's datalink list.
360 */
361 int
362 link_activate(dlmgmt_link_t *linkp)
363 {
364 int err = 0;
365 zoneid_t zoneid = ALL_ZONES;
366
367 /*
368 * If zone_check_datalink() returns 0 it means we found the
369 * link in one of the NGZ's datalink lists. Otherwise the link
370 * is under the GZ.
371 */
372 if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
373 /*
374 * This is a bit subtle. If the following expression
375 * is true then the link was found in one of the NGZ's
376 * datalink lists but the link structure has it under
377 * the GZ. This means that the link is supposed to be
378 * loaned out to an NGZ but the dlmgmtd state is out
379 * of sync -- possibly due to the process restarting.
380 * In this case we need to sync the dlmgmtd state by
381 * marking it as on-loan to the NGZ it's currently
382 * under.
383 */
384 if (zoneid != linkp->ll_zoneid) {
385 assert(linkp->ll_zoneid == 0);
386 assert(linkp->ll_onloan == B_FALSE);
387
388 /*
389 * If dlmgmtd already has a link with this
390 * name under the NGZ then we have a problem.
391 */
392 if (link_by_name(linkp->ll_link, zoneid) != NULL) {
393 err = EEXIST;
394 goto done;
395 }
396
397 /*
398 * Remove the current linkp entry from the
399 * list because it's under the wrong zoneid.
400 * We don't have to update the dlmgmt_id_avl
401 * because it compares entries by ll_linkid
402 * only.
403 */
404 if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
405 avl_remove(&dlmgmt_name_avl, linkp);
406
407 /*
408 * Update the link to reflect the fact that
409 * it's on-loan to an NGZ and re-add it to the
410 * list.
411 */
412 linkp->ll_zoneid = zoneid;
413 avl_add(&dlmgmt_name_avl, linkp);
414 linkp->ll_onloan = B_TRUE;
415
416 /*
417 * When a VNIC is not persistent and loaned to
418 * a zone it is considered transient. This is
419 * the same logic found in do_create_vnic()
420 * and is needed here in the event of a
421 * dlmgmtd restart.
422 */
423 if (linkp->ll_class == DATALINK_CLASS_VNIC &&
424 !(linkp->ll_flags & DLMGMT_PERSIST))
425 linkp->ll_trans = B_TRUE;
426 }
427 } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
428 /*
429 * In this case the link was not found under any NGZs
430 * but according to its ll_zoneid member it is owned
431 * by an NGZ. Add the datalink to the appropriate zone
432 * datalink list.
433 */
434 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
435 assert(linkp->ll_onloan == B_FALSE);
436 }
437 done:
438 if (err == 0)
439 linkp->ll_flags |= DLMGMT_ACTIVE;
440 return (err);
441 }
442
443 /*
444 * Is linkp visible from the caller's zoneid? It is if the link is in the
445 * same zone as the caller, or if the caller is in the global zone and the
446 * link is on loan to a non-global zone.
447 */
448 boolean_t
449 link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
473 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
474 link.ll_zoneid = zoneid;
475 linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
476 return (linkp);
477 }
478
479 int
480 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
481 zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
482 {
483 dlmgmt_link_t *linkp = NULL;
484 avl_index_t name_where, id_where;
485 int err = 0;
486
487 if (!dladm_valid_linkname(name))
488 return (EINVAL);
489 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
490 return (ENOSPC);
491 if (flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST | DLMGMT_TRANSIENT) ||
492 ((flags & DLMGMT_PERSIST) && (flags & DLMGMT_TRANSIENT)) ||
493 flags == 0)
494 return (EINVAL);
495
496 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
497 err = ENOMEM;
498 goto done;
499 }
500
501 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
502 linkp->ll_class = class;
503 linkp->ll_media = media;
504 linkp->ll_linkid = dlmgmt_nextlinkid;
505 linkp->ll_zoneid = zoneid;
506 linkp->ll_gen = 0;
507
508 /*
509 * While DLMGMT_TRANSIENT starts off as a flag it is converted
510 * into a link field since it is really a substate of
511 * DLMGMT_ACTIVE -- it should not survive as a flag beyond
512 * this point.
513 */
514 linkp->ll_trans = (flags & DLMGMT_TRANSIENT) ? B_TRUE : B_FALSE;
515 flags &= ~DLMGMT_TRANSIENT;
516
517 if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
518 avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
519 err = EEXIST;
520 goto done;
521 }
522
523 avl_insert(&dlmgmt_name_avl, linkp, name_where);
524 avl_insert(&dlmgmt_id_avl, linkp, id_where);
525
526 if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
527 avl_remove(&dlmgmt_name_avl, linkp);
528 avl_remove(&dlmgmt_id_avl, linkp);
529 goto done;
530 }
531
532 linkp->ll_flags = flags;
533 dlmgmt_advance(linkp);
534 *linkpp = linkp;
|
338 }
339
340 void
341 dlmgmt_table_unlock(void)
342 {
343 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
344 (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
345 (void) pthread_cond_broadcast(&dlmgmt_avl_cv);
346 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
347 }
348
349 void
350 link_destroy(dlmgmt_link_t *linkp)
351 {
352 linkattr_destroy(linkp);
353 free(linkp);
354 }
355
356 /*
357 * Set the DLMGMT_ACTIVE flag on the link to note that it is active.
358 * When a link is active and owned by an NGZ then it is added to
359 * that zone's datalink list.
360 */
361 int
362 link_activate(dlmgmt_link_t *linkp)
363 {
364 int err = 0;
365 zoneid_t zoneid = ALL_ZONES;
366
367 /*
368 * If zone_check_datalink() returns 0 it means we found the
369 * link in one of the NGZ's datalink lists. Otherwise the link
370 * is under the GZ.
371 */
372 if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
373 /*
374 * This is a bit subtle. If the following expression
375 * is true then the link was found in one of the NGZ's
376 * datalink lists but the link structure has it under
377 * the GZ. This means that the link is supposed to be
378 * loaned out to an NGZ but the dlmgmtd state is out
379 * of sync -- possibly due to the process restarting.
380 * In this case we need to sync the dlmgmtd state by
381 * marking it as on-loan to the NGZ it's currently
382 * under.
383 */
384 if (zoneid != linkp->ll_zoneid) {
385 assert(linkp->ll_zoneid == 0);
386 assert(linkp->ll_onloan == B_FALSE);
387 assert(linkp->ll_transient == 0);
388
389 /*
390 * If dlmgmtd already has a link with this
391 * name under the NGZ then we have a problem.
392 */
393 if (link_by_name(linkp->ll_link, zoneid) != NULL) {
394 err = EEXIST;
395 goto done;
396 }
397
398 /*
399 * Remove the current linkp entry from the
400 * list because it's under the wrong zoneid.
401 * We don't have to update the dlmgmt_id_avl
402 * because it compares entries by ll_linkid
403 * only.
404 */
405 if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
406 avl_remove(&dlmgmt_name_avl, linkp);
407
408 /*
409 * Update the link to reflect the fact that
410 * it's on-loan to an NGZ and re-add it to the
411 * list.
412 */
413 linkp->ll_zoneid = zoneid;
414 avl_add(&dlmgmt_name_avl, linkp);
415 linkp->ll_onloan = B_TRUE;
416
417 /*
418 * When a VNIC is not persistent and loaned to
419 * a zone it is considered transient. This is
420 * the same logic found in do_create_vnic()
421 * and is needed here in the event of a
422 * dlmgmtd restart.
423 */
424 if (linkp->ll_class == DATALINK_CLASS_VNIC &&
425 !(linkp->ll_flags & DLMGMT_PERSIST))
426 linkp->ll_transient = B_TRUE;
427 }
428 } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
429 /*
430 * In this case the link was not found under any NGZ
431 * but according to its ll_zoneid member it is owned
432 * by an NGZ. Add the datalink to the appropriate zone
433 * datalink list.
434 */
435 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
436 assert(linkp->ll_onloan == B_FALSE);
437 }
438 done:
439 if (err == 0)
440 linkp->ll_flags |= DLMGMT_ACTIVE;
441 return (err);
442 }
443
444 /*
445 * Is linkp visible from the caller's zoneid? It is if the link is in the
446 * same zone as the caller, or if the caller is in the global zone and the
447 * link is on loan to a non-global zone.
448 */
449 boolean_t
450 link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
474 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
475 link.ll_zoneid = zoneid;
476 linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
477 return (linkp);
478 }
479
480 int
481 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
482 zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
483 {
484 dlmgmt_link_t *linkp = NULL;
485 avl_index_t name_where, id_where;
486 int err = 0;
487
488 if (!dladm_valid_linkname(name))
489 return (EINVAL);
490 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
491 return (ENOSPC);
492 if (flags & ~(DLMGMT_ACTIVE | DLMGMT_PERSIST | DLMGMT_TRANSIENT) ||
493 ((flags & DLMGMT_PERSIST) && (flags & DLMGMT_TRANSIENT)) ||
494 flags == 0) {
495 return (EINVAL);
496 }
497
498 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
499 err = ENOMEM;
500 goto done;
501 }
502
503 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
504 linkp->ll_class = class;
505 linkp->ll_media = media;
506 linkp->ll_linkid = dlmgmt_nextlinkid;
507 linkp->ll_zoneid = zoneid;
508 linkp->ll_gen = 0;
509
510 /*
511 * While DLMGMT_TRANSIENT starts off as a flag it is converted
512 * into a link field since it is really a substate of
513 * DLMGMT_ACTIVE -- it should not survive as a flag beyond
514 * this point.
515 */
516 linkp->ll_transient = (flags & DLMGMT_TRANSIENT) ? B_TRUE : B_FALSE;
517 flags &= ~DLMGMT_TRANSIENT;
518
519 if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
520 avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
521 err = EEXIST;
522 goto done;
523 }
524
525 avl_insert(&dlmgmt_name_avl, linkp, name_where);
526 avl_insert(&dlmgmt_id_avl, linkp, id_where);
527
528 if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
529 avl_remove(&dlmgmt_name_avl, linkp);
530 avl_remove(&dlmgmt_id_avl, linkp);
531 goto done;
532 }
533
534 linkp->ll_flags = flags;
535 dlmgmt_advance(linkp);
536 *linkpp = linkp;
|