Print this page
OS-3342 dlmgmtd needs to be mindful of lock ordering
OS-2608 dlmgmtd needs to record zone identifiers
OS-3492 zone_free asserts to its destruction when dlmgmtd has fallen
OS-3494 zoneadmd tears down networking too soon when boot fails
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/cmd/dlmgmtd/dlmgmt_util.c
+++ new/usr/src/cmd/dlmgmtd/dlmgmt_util.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 /*
27 27 * Utility functions used by the dlmgmtd daemon.
28 28 */
29 29
30 30 #include <assert.h>
31 31 #include <pthread.h>
32 32 #include <stddef.h>
33 33 #include <stdlib.h>
34 34 #include <stdio.h>
35 35 #include <errno.h>
36 36 #include <strings.h>
37 37 #include <string.h>
38 38 #include <syslog.h>
39 39 #include <stdarg.h>
40 40 #include <zone.h>
41 41 #include <errno.h>
42 42 #include <libdlpi.h>
43 43 #include "dlmgmt_impl.h"
44 44
45 45 /*
46 46 * There are three datalink AVL tables. The dlmgmt_name_avl tree contains all
47 47 * datalinks and is keyed by zoneid and link name. The dlmgmt_id_avl also
48 48 * contains all datalinks, and it is keyed by link ID. The dlmgmt_loan_avl is
49 49 * keyed by link name, and contains the set of global-zone links that are
50 50 * currently on loan to non-global zones.
51 51 */
52 52 avl_tree_t dlmgmt_name_avl;
53 53 avl_tree_t dlmgmt_id_avl;
54 54 avl_tree_t dlmgmt_loan_avl;
55 55
56 56 avl_tree_t dlmgmt_dlconf_avl;
57 57
58 58 static pthread_rwlock_t dlmgmt_avl_lock = PTHREAD_RWLOCK_INITIALIZER;
59 59 static pthread_mutex_t dlmgmt_avl_mutex = PTHREAD_MUTEX_INITIALIZER;
60 60 static pthread_cond_t dlmgmt_avl_cv = PTHREAD_COND_INITIALIZER;
61 61 static pthread_rwlock_t dlmgmt_dlconf_lock = PTHREAD_RWLOCK_INITIALIZER;
62 62
63 63 typedef struct dlmgmt_prefix {
64 64 struct dlmgmt_prefix *lp_next;
65 65 char lp_prefix[MAXLINKNAMELEN];
66 66 zoneid_t lp_zoneid;
67 67 uint_t lp_nextppa;
68 68 } dlmgmt_prefix_t;
69 69 static dlmgmt_prefix_t dlmgmt_prefixlist;
70 70
71 71 datalink_id_t dlmgmt_nextlinkid;
72 72 static datalink_id_t dlmgmt_nextconfid = 1;
73 73
74 74 static void dlmgmt_advance_linkid(dlmgmt_link_t *);
75 75 static void dlmgmt_advance_ppa(dlmgmt_link_t *);
76 76
77 77 void
78 78 dlmgmt_log(int pri, const char *fmt, ...)
79 79 {
80 80 va_list alist;
81 81
82 82 va_start(alist, fmt);
83 83 if (debug) {
84 84 (void) vfprintf(stderr, fmt, alist);
85 85 (void) fputc('\n', stderr);
86 86 } else {
87 87 vsyslog(pri, fmt, alist);
88 88 }
89 89 va_end(alist);
90 90 }
91 91
92 92 static int
93 93 cmp_link_by_name(const void *v1, const void *v2)
94 94 {
95 95 const dlmgmt_link_t *link1 = v1;
96 96 const dlmgmt_link_t *link2 = v2;
97 97 int cmp;
98 98
99 99 cmp = strcmp(link1->ll_link, link2->ll_link);
100 100 return ((cmp == 0) ? 0 : ((cmp < 0) ? -1 : 1));
101 101 }
102 102
103 103 /*
104 104 * Note that the zoneid associated with a link is effectively part of its
105 105 * name. This is essentially what results in having each zone have disjoint
106 106 * datalink namespaces.
107 107 */
108 108 static int
109 109 cmp_link_by_zname(const void *v1, const void *v2)
110 110 {
111 111 const dlmgmt_link_t *link1 = v1;
112 112 const dlmgmt_link_t *link2 = v2;
113 113
114 114 if (link1->ll_zoneid < link2->ll_zoneid)
115 115 return (-1);
116 116 if (link1->ll_zoneid > link2->ll_zoneid)
117 117 return (1);
118 118 return (cmp_link_by_name(link1, link2));
119 119 }
120 120
121 121 static int
122 122 cmp_link_by_id(const void *v1, const void *v2)
123 123 {
124 124 const dlmgmt_link_t *link1 = v1;
125 125 const dlmgmt_link_t *link2 = v2;
126 126
127 127 if ((uint64_t)(link1->ll_linkid) == (uint64_t)(link2->ll_linkid))
128 128 return (0);
129 129 else if ((uint64_t)(link1->ll_linkid) < (uint64_t)(link2->ll_linkid))
130 130 return (-1);
131 131 else
132 132 return (1);
133 133 }
134 134
135 135 static int
136 136 cmp_dlconf_by_id(const void *v1, const void *v2)
137 137 {
138 138 const dlmgmt_dlconf_t *dlconfp1 = v1;
139 139 const dlmgmt_dlconf_t *dlconfp2 = v2;
140 140
141 141 if (dlconfp1->ld_id == dlconfp2->ld_id)
142 142 return (0);
143 143 else if (dlconfp1->ld_id < dlconfp2->ld_id)
144 144 return (-1);
145 145 else
146 146 return (1);
147 147 }
148 148
149 149 void
150 150 dlmgmt_linktable_init(void)
151 151 {
152 152 /*
153 153 * Initialize the prefix list. First add the "net" prefix for the
154 154 * global zone to the list.
155 155 */
156 156 dlmgmt_prefixlist.lp_next = NULL;
157 157 dlmgmt_prefixlist.lp_zoneid = GLOBAL_ZONEID;
158 158 dlmgmt_prefixlist.lp_nextppa = 0;
159 159 (void) strlcpy(dlmgmt_prefixlist.lp_prefix, "net", MAXLINKNAMELEN);
160 160
161 161 avl_create(&dlmgmt_name_avl, cmp_link_by_zname, sizeof (dlmgmt_link_t),
162 162 offsetof(dlmgmt_link_t, ll_name_node));
163 163 avl_create(&dlmgmt_id_avl, cmp_link_by_id, sizeof (dlmgmt_link_t),
164 164 offsetof(dlmgmt_link_t, ll_id_node));
165 165 avl_create(&dlmgmt_loan_avl, cmp_link_by_name, sizeof (dlmgmt_link_t),
166 166 offsetof(dlmgmt_link_t, ll_loan_node));
167 167 avl_create(&dlmgmt_dlconf_avl, cmp_dlconf_by_id,
168 168 sizeof (dlmgmt_dlconf_t), offsetof(dlmgmt_dlconf_t, ld_node));
169 169 dlmgmt_nextlinkid = 1;
170 170 }
171 171
172 172 void
173 173 dlmgmt_linktable_fini(void)
174 174 {
175 175 dlmgmt_prefix_t *lpp, *next;
176 176
177 177 for (lpp = dlmgmt_prefixlist.lp_next; lpp != NULL; lpp = next) {
178 178 next = lpp->lp_next;
179 179 free(lpp);
180 180 }
181 181
182 182 avl_destroy(&dlmgmt_dlconf_avl);
183 183 avl_destroy(&dlmgmt_name_avl);
184 184 avl_destroy(&dlmgmt_loan_avl);
185 185 avl_destroy(&dlmgmt_id_avl);
186 186 }
187 187
188 188 static void
189 189 linkattr_add(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
190 190 {
191 191 if (*headp == NULL) {
192 192 *headp = attrp;
193 193 } else {
194 194 (*headp)->lp_prev = attrp;
195 195 attrp->lp_next = *headp;
196 196 *headp = attrp;
197 197 }
198 198 }
199 199
200 200 static void
201 201 linkattr_rm(dlmgmt_linkattr_t **headp, dlmgmt_linkattr_t *attrp)
202 202 {
203 203 dlmgmt_linkattr_t *next, *prev;
204 204
205 205 next = attrp->lp_next;
206 206 prev = attrp->lp_prev;
207 207 if (next != NULL)
208 208 next->lp_prev = prev;
209 209 if (prev != NULL)
210 210 prev->lp_next = next;
211 211 else
212 212 *headp = next;
213 213 }
214 214
215 215 dlmgmt_linkattr_t *
216 216 linkattr_find(dlmgmt_linkattr_t *headp, const char *attr)
217 217 {
218 218 dlmgmt_linkattr_t *attrp;
219 219
220 220 for (attrp = headp; attrp != NULL; attrp = attrp->lp_next) {
221 221 if (strcmp(attrp->lp_name, attr) == 0)
222 222 break;
223 223 }
224 224 return (attrp);
225 225 }
226 226
227 227 int
228 228 linkattr_set(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
229 229 size_t attrsz, dladm_datatype_t type)
230 230 {
231 231 dlmgmt_linkattr_t *attrp;
232 232 void *newval;
233 233 boolean_t new;
234 234
235 235 attrp = linkattr_find(*headp, attr);
236 236 if (attrp != NULL) {
237 237 /*
238 238 * It is already set. If the value changed, update it.
239 239 */
240 240 if (linkattr_equal(headp, attr, attrval, attrsz))
241 241 return (0);
242 242 new = B_FALSE;
243 243 } else {
244 244 /*
245 245 * It is not set yet, allocate the linkattr and prepend to the
246 246 * list.
247 247 */
248 248 if ((attrp = calloc(1, sizeof (dlmgmt_linkattr_t))) == NULL)
249 249 return (ENOMEM);
250 250
251 251 (void) strlcpy(attrp->lp_name, attr, MAXLINKATTRLEN);
252 252 new = B_TRUE;
253 253 }
254 254 if ((newval = calloc(1, attrsz)) == NULL) {
255 255 if (new)
256 256 free(attrp);
257 257 return (ENOMEM);
258 258 }
259 259
260 260 if (!new)
261 261 free(attrp->lp_val);
262 262 attrp->lp_val = newval;
263 263 bcopy(attrval, attrp->lp_val, attrsz);
264 264 attrp->lp_sz = attrsz;
265 265 attrp->lp_type = type;
266 266 attrp->lp_linkprop = dladm_attr_is_linkprop(attr);
267 267 if (new)
268 268 linkattr_add(headp, attrp);
269 269 return (0);
270 270 }
271 271
272 272 void
273 273 linkattr_unset(dlmgmt_linkattr_t **headp, const char *attr)
274 274 {
275 275 dlmgmt_linkattr_t *attrp;
276 276
277 277 if ((attrp = linkattr_find(*headp, attr)) != NULL) {
278 278 linkattr_rm(headp, attrp);
279 279 free(attrp->lp_val);
280 280 free(attrp);
281 281 }
282 282 }
283 283
284 284 int
285 285 linkattr_get(dlmgmt_linkattr_t **headp, const char *attr, void **attrvalp,
286 286 size_t *attrszp, dladm_datatype_t *typep)
287 287 {
288 288 dlmgmt_linkattr_t *attrp;
289 289
290 290 if ((attrp = linkattr_find(*headp, attr)) == NULL)
291 291 return (ENOENT);
292 292
293 293 *attrvalp = attrp->lp_val;
294 294 *attrszp = attrp->lp_sz;
295 295 if (typep != NULL)
296 296 *typep = attrp->lp_type;
297 297 return (0);
298 298 }
299 299
300 300 boolean_t
301 301 linkattr_equal(dlmgmt_linkattr_t **headp, const char *attr, void *attrval,
302 302 size_t attrsz)
303 303 {
304 304 void *saved_attrval;
305 305 size_t saved_attrsz;
306 306
307 307 if (linkattr_get(headp, attr, &saved_attrval, &saved_attrsz, NULL) != 0)
308 308 return (B_FALSE);
309 309
310 310 return ((saved_attrsz == attrsz) &&
311 311 (memcmp(saved_attrval, attrval, attrsz) == 0));
312 312 }
313 313
314 314 void
315 315 linkattr_destroy(dlmgmt_link_t *linkp)
316 316 {
317 317 dlmgmt_linkattr_t *next, *attrp;
318 318
319 319 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
320 320 next = attrp->lp_next;
321 321 free(attrp->lp_val);
322 322 free(attrp);
323 323 }
324 324 }
325 325
326 326 static int
327 327 dlmgmt_table_readwritelock(boolean_t write)
328 328 {
329 329 if (write)
330 330 return (pthread_rwlock_trywrlock(&dlmgmt_avl_lock));
331 331 else
332 332 return (pthread_rwlock_tryrdlock(&dlmgmt_avl_lock));
333 333 }
334 334
335 335 void
336 336 dlmgmt_table_lock(boolean_t write)
337 337 {
338 338 (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
339 339 while (dlmgmt_table_readwritelock(write) == EBUSY)
340 340 (void) pthread_cond_wait(&dlmgmt_avl_cv, &dlmgmt_avl_mutex);
341 341
342 342 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
343 343 }
344 344
345 345 void
346 346 dlmgmt_table_unlock(void)
347 347 {
348 348 (void) pthread_rwlock_unlock(&dlmgmt_avl_lock);
349 349 (void) pthread_mutex_lock(&dlmgmt_avl_mutex);
350 350 (void) pthread_cond_broadcast(&dlmgmt_avl_cv);
351 351 (void) pthread_mutex_unlock(&dlmgmt_avl_mutex);
352 352 }
353 353
354 354 void
355 355 link_destroy(dlmgmt_link_t *linkp)
356 356 {
357 357 linkattr_destroy(linkp);
358 358 free(linkp);
359 359 }
360 360
361 361 /*
362 362 * Set the DLMGMT_ACTIVE flag on the link to note that it is active. When a
363 363 * link becomes active and it belongs to a non-global zone, it is also added
364 364 * to that zone.
365 365 */
366 366 int
367 367 link_activate(dlmgmt_link_t *linkp)
368 368 {
369 369 int err = 0;
370 370 zoneid_t zoneid = ALL_ZONES;
371 371
372 372 if (zone_check_datalink(&zoneid, linkp->ll_linkid) == 0) {
373 373 /*
374 374 * This link was already added to a non-global zone. This can
375 375 * happen if dlmgmtd is restarted.
376 376 */
377 377 if (zoneid != linkp->ll_zoneid) {
378 378 if (link_by_name(linkp->ll_link, zoneid) != NULL) {
379 379 err = EEXIST;
380 380 goto done;
381 381 }
382 382
383 383 if (avl_find(&dlmgmt_name_avl, linkp, NULL) != NULL)
384 384 avl_remove(&dlmgmt_name_avl, linkp);
385 385
386 386 linkp->ll_zoneid = zoneid;
387 387 avl_add(&dlmgmt_name_avl, linkp);
388 388 avl_add(&dlmgmt_loan_avl, linkp);
389 389 linkp->ll_onloan = B_TRUE;
390 390 }
391 391 } else if (linkp->ll_zoneid != GLOBAL_ZONEID) {
392 392 err = zone_add_datalink(linkp->ll_zoneid, linkp->ll_linkid);
393 393 }
394 394 done:
395 395 if (err == 0)
396 396 linkp->ll_flags |= DLMGMT_ACTIVE;
397 397 return (err);
398 398 }
399 399
400 400 /*
401 401 * Is linkp visible from the caller's zoneid? It is if the link is in the
402 402 * same zone as the caller, or if the caller is in the global zone and the
403 403 * link is on loan to a non-global zone.
404 404 */
405 405 boolean_t
406 406 link_is_visible(dlmgmt_link_t *linkp, zoneid_t zoneid)
407 407 {
408 408 return (linkp->ll_zoneid == zoneid ||
409 409 (zoneid == GLOBAL_ZONEID && linkp->ll_onloan));
410 410 }
411 411
412 412 dlmgmt_link_t *
413 413 link_by_id(datalink_id_t linkid, zoneid_t zoneid)
414 414 {
415 415 dlmgmt_link_t link, *linkp;
416 416
417 417 link.ll_linkid = linkid;
418 418 if ((linkp = avl_find(&dlmgmt_id_avl, &link, NULL)) == NULL)
419 419 return (NULL);
420 420 if (zoneid != GLOBAL_ZONEID && linkp->ll_zoneid != zoneid)
421 421 return (NULL);
422 422 return (linkp);
423 423 }
424 424
425 425 dlmgmt_link_t *
426 426 link_by_name(const char *name, zoneid_t zoneid)
427 427 {
428 428 dlmgmt_link_t link, *linkp;
429 429
430 430 (void) strlcpy(link.ll_link, name, MAXLINKNAMELEN);
431 431 link.ll_zoneid = zoneid;
432 432 linkp = avl_find(&dlmgmt_name_avl, &link, NULL);
433 433 if (linkp == NULL && zoneid == GLOBAL_ZONEID) {
434 434 /* The link could be on loan to a non-global zone? */
435 435 linkp = avl_find(&dlmgmt_loan_avl, &link, NULL);
436 436 }
437 437 return (linkp);
438 438 }
439 439
440 440 int
441 441 dlmgmt_create_common(const char *name, datalink_class_t class, uint32_t media,
442 442 zoneid_t zoneid, uint32_t flags, dlmgmt_link_t **linkpp)
443 443 {
444 444 dlmgmt_link_t *linkp = NULL;
445 445 avl_index_t name_where, id_where;
446 446 int err = 0;
447 447
448 448 if (!dladm_valid_linkname(name))
449 449 return (EINVAL);
450 450 if (dlmgmt_nextlinkid == DATALINK_INVALID_LINKID)
451 451 return (ENOSPC);
452 452
453 453 if ((linkp = calloc(1, sizeof (dlmgmt_link_t))) == NULL) {
|
↓ open down ↓ |
453 lines elided |
↑ open up ↑ |
454 454 err = ENOMEM;
455 455 goto done;
456 456 }
457 457
458 458 (void) strlcpy(linkp->ll_link, name, MAXLINKNAMELEN);
459 459 linkp->ll_class = class;
460 460 linkp->ll_media = media;
461 461 linkp->ll_linkid = dlmgmt_nextlinkid;
462 462 linkp->ll_zoneid = zoneid;
463 463 linkp->ll_gen = 0;
464 + linkp->ll_tomb = B_FALSE;
464 465
465 466 if (avl_find(&dlmgmt_name_avl, linkp, &name_where) != NULL ||
466 467 avl_find(&dlmgmt_id_avl, linkp, &id_where) != NULL) {
467 468 err = EEXIST;
468 469 goto done;
469 470 }
470 471
471 472 avl_insert(&dlmgmt_name_avl, linkp, name_where);
472 473 avl_insert(&dlmgmt_id_avl, linkp, id_where);
473 474
474 475 if ((flags & DLMGMT_ACTIVE) && (err = link_activate(linkp)) != 0) {
475 476 avl_remove(&dlmgmt_name_avl, linkp);
476 477 avl_remove(&dlmgmt_id_avl, linkp);
477 478 goto done;
478 479 }
479 480
480 481 linkp->ll_flags = flags;
481 482 dlmgmt_advance(linkp);
482 483 *linkpp = linkp;
483 484
484 485 done:
485 486 if (err != 0)
486 487 free(linkp);
487 488 return (err);
488 489 }
489 490
490 491 int
491 492 dlmgmt_destroy_common(dlmgmt_link_t *linkp, uint32_t flags)
492 493 {
493 494 if ((linkp->ll_flags & flags) == 0) {
494 495 /*
495 496 * The link does not exist in the specified space.
496 497 */
497 498 return (ENOENT);
498 499 }
499 500
500 501 linkp->ll_flags &= ~flags;
501 502 if (flags & DLMGMT_PERSIST) {
502 503 dlmgmt_linkattr_t *next, *attrp;
503 504
504 505 for (attrp = linkp->ll_head; attrp != NULL; attrp = next) {
505 506 next = attrp->lp_next;
506 507 free(attrp->lp_val);
507 508 free(attrp);
508 509 }
509 510 linkp->ll_head = NULL;
510 511 }
511 512
512 513 if ((flags & DLMGMT_ACTIVE) && linkp->ll_zoneid != GLOBAL_ZONEID) {
513 514 (void) zone_remove_datalink(linkp->ll_zoneid, linkp->ll_linkid);
514 515 if (linkp->ll_onloan)
515 516 avl_remove(&dlmgmt_loan_avl, linkp);
516 517 }
517 518
518 519 if (linkp->ll_flags == 0) {
519 520 avl_remove(&dlmgmt_id_avl, linkp);
520 521 avl_remove(&dlmgmt_name_avl, linkp);
521 522 link_destroy(linkp);
522 523 }
523 524
524 525 return (0);
525 526 }
526 527
527 528 int
528 529 dlmgmt_getattr_common(dlmgmt_linkattr_t **headp, const char *attr,
529 530 dlmgmt_getattr_retval_t *retvalp)
530 531 {
531 532 int err;
532 533 void *attrval;
533 534 size_t attrsz;
534 535 dladm_datatype_t attrtype;
535 536
536 537 err = linkattr_get(headp, attr, &attrval, &attrsz, &attrtype);
537 538 if (err != 0)
538 539 return (err);
539 540
540 541 assert(attrsz > 0);
541 542 if (attrsz > MAXLINKATTRVALLEN)
542 543 return (EINVAL);
543 544
544 545 retvalp->lr_type = attrtype;
545 546 retvalp->lr_attrsz = attrsz;
546 547 bcopy(attrval, retvalp->lr_attrval, attrsz);
547 548 return (0);
548 549 }
549 550
550 551 void
551 552 dlmgmt_dlconf_table_lock(boolean_t write)
552 553 {
553 554 if (write)
554 555 (void) pthread_rwlock_wrlock(&dlmgmt_dlconf_lock);
555 556 else
556 557 (void) pthread_rwlock_rdlock(&dlmgmt_dlconf_lock);
557 558 }
558 559
559 560 void
560 561 dlmgmt_dlconf_table_unlock(void)
561 562 {
562 563 (void) pthread_rwlock_unlock(&dlmgmt_dlconf_lock);
563 564 }
564 565
565 566 int
566 567 dlconf_create(const char *name, datalink_id_t linkid, datalink_class_t class,
567 568 uint32_t media, zoneid_t zoneid, dlmgmt_dlconf_t **dlconfpp)
568 569 {
569 570 dlmgmt_dlconf_t *dlconfp = NULL;
570 571 int err = 0;
571 572
572 573 if (dlmgmt_nextconfid == 0) {
573 574 err = ENOSPC;
574 575 goto done;
575 576 }
576 577
577 578 if ((dlconfp = calloc(1, sizeof (dlmgmt_dlconf_t))) == NULL) {
578 579 err = ENOMEM;
579 580 goto done;
580 581 }
581 582
582 583 (void) strlcpy(dlconfp->ld_link, name, MAXLINKNAMELEN);
583 584 dlconfp->ld_linkid = linkid;
584 585 dlconfp->ld_class = class;
585 586 dlconfp->ld_media = media;
586 587 dlconfp->ld_id = dlmgmt_nextconfid;
587 588 dlconfp->ld_zoneid = zoneid;
588 589
589 590 done:
590 591 *dlconfpp = dlconfp;
591 592 return (err);
592 593 }
593 594
594 595 void
595 596 dlconf_destroy(dlmgmt_dlconf_t *dlconfp)
596 597 {
597 598 dlmgmt_linkattr_t *next, *attrp;
598 599
599 600 for (attrp = dlconfp->ld_head; attrp != NULL; attrp = next) {
600 601 next = attrp->lp_next;
601 602 free(attrp->lp_val);
602 603 free(attrp);
603 604 }
604 605 free(dlconfp);
605 606 }
606 607
607 608 int
608 609 dlmgmt_generate_name(const char *prefix, char *name, size_t size,
609 610 zoneid_t zoneid)
610 611 {
611 612 dlmgmt_prefix_t *lpp, *prev = NULL;
612 613 dlmgmt_link_t link, *linkp;
613 614
614 615 /*
615 616 * See whether the requested prefix is already in the list.
616 617 */
617 618 for (lpp = &dlmgmt_prefixlist; lpp != NULL;
618 619 prev = lpp, lpp = lpp->lp_next) {
619 620 if (lpp->lp_zoneid == zoneid &&
620 621 strcmp(prefix, lpp->lp_prefix) == 0)
621 622 break;
622 623 }
623 624
624 625 /*
625 626 * Not found.
626 627 */
627 628 if (lpp == NULL) {
628 629 assert(prev != NULL);
629 630
630 631 /*
631 632 * First add this new prefix into the prefix list.
632 633 */
633 634 if ((lpp = malloc(sizeof (dlmgmt_prefix_t))) == NULL)
634 635 return (ENOMEM);
635 636
636 637 prev->lp_next = lpp;
637 638 lpp->lp_next = NULL;
638 639 lpp->lp_zoneid = zoneid;
639 640 lpp->lp_nextppa = 0;
640 641 (void) strlcpy(lpp->lp_prefix, prefix, MAXLINKNAMELEN);
641 642
642 643 /*
643 644 * Now determine this prefix's nextppa.
644 645 */
645 646 (void) snprintf(link.ll_link, MAXLINKNAMELEN, "%s%d",
646 647 prefix, 0);
647 648 link.ll_zoneid = zoneid;
648 649 if ((linkp = avl_find(&dlmgmt_name_avl, &link, NULL)) != NULL)
649 650 dlmgmt_advance_ppa(linkp);
650 651 }
651 652
652 653 if (lpp->lp_nextppa == (uint_t)-1)
653 654 return (ENOSPC);
654 655
655 656 (void) snprintf(name, size, "%s%d", prefix, lpp->lp_nextppa);
656 657 return (0);
657 658 }
658 659
659 660 /*
660 661 * Advance the next available ppa value if the name prefix of the current
661 662 * link is in the prefix list.
662 663 */
663 664 static void
664 665 dlmgmt_advance_ppa(dlmgmt_link_t *linkp)
665 666 {
666 667 dlmgmt_prefix_t *lpp;
667 668 char prefix[MAXLINKNAMELEN];
668 669 char linkname[MAXLINKNAMELEN];
669 670 uint_t start, ppa;
670 671
671 672 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
672 673
673 674 /*
674 675 * See whether the requested prefix is already in the list.
675 676 */
676 677 for (lpp = &dlmgmt_prefixlist; lpp != NULL; lpp = lpp->lp_next) {
677 678 if (lpp->lp_zoneid == linkp->ll_zoneid &&
678 679 strcmp(prefix, lpp->lp_prefix) == 0)
679 680 break;
680 681 }
681 682
682 683 /*
683 684 * If the link name prefix is in the list, advance the
684 685 * next available ppa for the <prefix>N name.
685 686 */
686 687 if (lpp == NULL || lpp->lp_nextppa != ppa)
687 688 return;
688 689
689 690 start = lpp->lp_nextppa++;
690 691 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
691 692 while (lpp->lp_nextppa != start) {
692 693 if (lpp->lp_nextppa == (uint_t)-1) {
693 694 /*
694 695 * wrapped around. search from <prefix>1.
695 696 */
696 697 lpp->lp_nextppa = 0;
697 698 (void) snprintf(linkname, MAXLINKNAMELEN,
698 699 "%s%d", lpp->lp_prefix, lpp->lp_nextppa);
699 700 linkp = link_by_name(linkname, lpp->lp_zoneid);
700 701 if (linkp == NULL)
701 702 return;
702 703 } else {
703 704 if (linkp == NULL)
704 705 return;
705 706 (void) dlpi_parselink(linkp->ll_link, prefix, &ppa);
706 707 if ((strcmp(prefix, lpp->lp_prefix) != 0) ||
707 708 (ppa != lpp->lp_nextppa)) {
708 709 return;
709 710 }
710 711 }
711 712 linkp = AVL_NEXT(&dlmgmt_name_avl, linkp);
712 713 lpp->lp_nextppa++;
713 714 }
714 715 lpp->lp_nextppa = (uint_t)-1;
715 716 }
716 717
717 718 /*
718 719 * Advance to the next available linkid value.
719 720 */
720 721 static void
721 722 dlmgmt_advance_linkid(dlmgmt_link_t *linkp)
722 723 {
723 724 datalink_id_t start;
724 725
725 726 if (linkp->ll_linkid != dlmgmt_nextlinkid)
726 727 return;
727 728
728 729 start = dlmgmt_nextlinkid;
729 730 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
730 731
731 732 do {
732 733 if (dlmgmt_nextlinkid == DATALINK_MAX_LINKID) {
733 734 /*
734 735 * wrapped around. search from 1.
735 736 */
736 737 dlmgmt_nextlinkid = 1;
737 738 if ((linkp = link_by_id(1, GLOBAL_ZONEID)) == NULL)
738 739 return;
739 740 } else {
740 741 dlmgmt_nextlinkid++;
741 742 if (linkp == NULL)
742 743 return;
743 744 if (linkp->ll_linkid != dlmgmt_nextlinkid)
744 745 return;
745 746 }
746 747
747 748 linkp = AVL_NEXT(&dlmgmt_id_avl, linkp);
748 749 } while (dlmgmt_nextlinkid != start);
749 750
750 751 dlmgmt_nextlinkid = DATALINK_INVALID_LINKID;
751 752 }
752 753
753 754 /*
754 755 * Advance various global values, for example, next linkid value, next ppa for
755 756 * various prefix etc.
756 757 */
757 758 void
758 759 dlmgmt_advance(dlmgmt_link_t *linkp)
759 760 {
760 761 dlmgmt_advance_linkid(linkp);
761 762 dlmgmt_advance_ppa(linkp);
762 763 }
763 764
764 765 /*
765 766 * Advance to the next available dlconf id.
766 767 */
767 768 void
768 769 dlmgmt_advance_dlconfid(dlmgmt_dlconf_t *dlconfp)
769 770 {
770 771 uint_t start;
771 772
772 773 start = dlmgmt_nextconfid++;
773 774 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
774 775 while (dlmgmt_nextconfid != start) {
775 776 if (dlmgmt_nextconfid == 0) {
776 777 dlmgmt_dlconf_t dlconf;
777 778
778 779 /*
779 780 * wrapped around. search from 1.
780 781 */
781 782 dlconf.ld_id = dlmgmt_nextconfid = 1;
782 783 dlconfp = avl_find(&dlmgmt_dlconf_avl, &dlconf, NULL);
783 784 if (dlconfp == NULL)
784 785 return;
785 786 } else {
786 787 if ((dlconfp == NULL) ||
787 788 (dlconfp->ld_id != dlmgmt_nextconfid)) {
788 789 return;
789 790 }
790 791 }
791 792 dlconfp = AVL_NEXT(&dlmgmt_dlconf_avl, dlconfp);
792 793 dlmgmt_nextconfid++;
793 794 }
794 795 dlmgmt_nextconfid = 0;
795 796 }
|
↓ open down ↓ |
322 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX