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