Print this page
OS-1885 deadlock between vnic destroy and kstat read
OS-676 debug kernel blew assertion in dls_devnet_stat_create()
OS-428 add link zonename kstat
OS-406
OS-327
OS-276 global zone duplicate kstat when two zones have same vnic name
OS-249
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/dls/dls_mgmt.c
+++ new/usr/src/uts/common/io/dls/dls_mgmt.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
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + * Copyright (c) 2013 Joyent, Inc. All rights reserved.
24 25 */
25 26
26 27 /*
27 28 * Datalink management routines.
28 29 */
29 30
30 31 #include <sys/types.h>
31 32 #include <sys/door.h>
32 33 #include <sys/zone.h>
33 34 #include <sys/modctl.h>
34 35 #include <sys/file.h>
35 36 #include <sys/modhash.h>
36 37 #include <sys/kstat.h>
37 38 #include <sys/vnode.h>
38 39 #include <sys/cmn_err.h>
39 40 #include <sys/softmac.h>
40 41 #include <sys/dls.h>
41 42 #include <sys/dls_impl.h>
42 43 #include <sys/stropts.h>
43 44 #include <sys/netstack.h>
44 45 #include <inet/iptun/iptun_impl.h>
45 46
46 47 /*
47 48 * This vanity name management module is treated as part of the GLD framework
48 49 * and we don't hold any GLD framework lock across a call to any mac
49 50 * function that needs to acquire the mac perimeter. The hierarchy is
50 51 * mac perimeter -> framework locks
51 52 */
52 53
53 54 typedef struct dls_stack {
54 55 zoneid_t dlss_zoneid;
55 56 } dls_stack_t;
56 57
57 58 static kmem_cache_t *i_dls_devnet_cachep;
58 59 static kmutex_t i_dls_mgmt_lock;
59 60 static krwlock_t i_dls_devnet_lock;
60 61 static mod_hash_t *i_dls_devnet_id_hash;
61 62 static mod_hash_t *i_dls_devnet_hash;
62 63
63 64 boolean_t devnet_need_rebuild;
64 65
65 66 #define VLAN_HASHSZ 67 /* prime */
66 67
67 68 /*
68 69 * The following macros take a link name without the trailing PPA as input.
69 70 * Opening a /dev/net node with one of these names causes a tunnel link to be
70 71 * implicitly created in dls_devnet_hold_by_name() for backward compatibility
71 72 * with Solaris 10 and prior.
72 73 */
73 74 #define IS_IPV4_TUN(name) (strcmp((name), "ip.tun") == 0)
74 75 #define IS_IPV6_TUN(name) (strcmp((name), "ip6.tun") == 0)
75 76 #define IS_6TO4_TUN(name) (strcmp((name), "ip.6to4tun") == 0)
76 77 #define IS_IPTUN_LINK(name) ( \
77 78 IS_IPV4_TUN(name) || IS_IPV6_TUN(name) || IS_6TO4_TUN(name))
78 79
79 80 /* Upcall door handle */
80 81 static door_handle_t dls_mgmt_dh = NULL;
81 82
82 83 #define DD_CONDEMNED 0x1
83 84 #define DD_KSTAT_CHANGING 0x2
84 85 #define DD_IMPLICIT_IPTUN 0x4 /* Implicitly-created ip*.*tun* tunnel */
85 86
86 87 /*
87 88 * This structure is used to keep the <linkid, macname> mapping.
88 89 * This structure itself is not protected by the mac perimeter, but is
89 90 * protected by the dd_mutex and i_dls_devnet_lock. Thus most of the
90 91 * functions manipulating this structure such as dls_devnet_set/unset etc.
91 92 * may be called while not holding the mac perimeter.
92 93 */
93 94 typedef struct dls_devnet_s {
94 95 datalink_id_t dd_linkid;
95 96 char dd_linkname[MAXLINKNAMELEN];
96 97 char dd_mac[MAXNAMELEN];
97 98 kstat_t *dd_ksp; /* kstat in owner_zid */
|
↓ open down ↓ |
64 lines elided |
↑ open up ↑ |
98 99 kstat_t *dd_zone_ksp; /* in dd_zid if != owner_zid */
99 100 uint32_t dd_ref;
100 101 kmutex_t dd_mutex;
101 102 kcondvar_t dd_cv;
102 103 uint32_t dd_tref;
103 104 uint_t dd_flags;
104 105 zoneid_t dd_owner_zid; /* zone where node was created */
105 106 zoneid_t dd_zid; /* current zone */
106 107 boolean_t dd_prop_loaded;
107 108 taskqid_t dd_prop_taskid;
109 + boolean_t dd_transient; /* link goes away when zone does */
108 110 } dls_devnet_t;
109 111
110 112 static int i_dls_devnet_create_iptun(const char *, const char *,
111 113 datalink_id_t *);
112 114 static int i_dls_devnet_destroy_iptun(datalink_id_t);
113 -static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t);
115 +static int i_dls_devnet_setzid(dls_devnet_t *, zoneid_t, boolean_t, boolean_t);
114 116 static int dls_devnet_unset(const char *, datalink_id_t *, boolean_t);
115 117
116 118 /*ARGSUSED*/
117 119 static int
118 120 i_dls_devnet_constructor(void *buf, void *arg, int kmflag)
119 121 {
120 122 dls_devnet_t *ddp = buf;
121 123
122 124 bzero(buf, sizeof (dls_devnet_t));
123 125 mutex_init(&ddp->dd_mutex, NULL, MUTEX_DEFAULT, NULL);
124 126 cv_init(&ddp->dd_cv, NULL, CV_DEFAULT, NULL);
125 127 return (0);
126 128 }
127 129
128 130 /*ARGSUSED*/
129 131 static void
130 132 i_dls_devnet_destructor(void *buf, void *arg)
131 133 {
132 134 dls_devnet_t *ddp = buf;
133 135
134 136 ASSERT(ddp->dd_ksp == NULL);
135 137 ASSERT(ddp->dd_ref == 0);
136 138 ASSERT(ddp->dd_tref == 0);
137 139 mutex_destroy(&ddp->dd_mutex);
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
138 140 cv_destroy(&ddp->dd_cv);
139 141 }
140 142
141 143 /* ARGSUSED */
142 144 static int
143 145 dls_zone_remove(datalink_id_t linkid, void *arg)
144 146 {
145 147 dls_devnet_t *ddp;
146 148
147 149 if (dls_devnet_hold_tmp(linkid, &ddp) == 0) {
148 - (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID);
150 + /*
151 + * Don't bother moving transient links back to the global zone
152 + * since we will simply delete them in dls_devnet_unset.
153 + */
154 + if (!ddp->dd_transient)
155 + (void) dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
149 156 dls_devnet_rele_tmp(ddp);
150 157 }
151 158 return (0);
152 159 }
153 160
154 161 /* ARGSUSED */
155 162 static void *
156 163 dls_stack_init(netstackid_t stackid, netstack_t *ns)
157 164 {
158 165 dls_stack_t *dlss;
159 166
160 167 dlss = kmem_zalloc(sizeof (*dlss), KM_SLEEP);
161 168 dlss->dlss_zoneid = netstackid_to_zoneid(stackid);
162 169 return (dlss);
163 170 }
164 171
165 172 /* ARGSUSED */
166 173 static void
167 174 dls_stack_shutdown(netstackid_t stackid, void *arg)
168 175 {
169 176 dls_stack_t *dlss = (dls_stack_t *)arg;
170 177
171 178 /* Move remaining datalinks in this zone back to the global zone. */
172 179 (void) zone_datalink_walk(dlss->dlss_zoneid, dls_zone_remove, NULL);
173 180 }
174 181
175 182 /* ARGSUSED */
176 183 static void
177 184 dls_stack_fini(netstackid_t stackid, void *arg)
178 185 {
179 186 dls_stack_t *dlss = (dls_stack_t *)arg;
180 187
181 188 kmem_free(dlss, sizeof (*dlss));
182 189 }
183 190
184 191 /*
185 192 * Module initialization and finalization functions.
186 193 */
187 194 void
188 195 dls_mgmt_init(void)
189 196 {
190 197 mutex_init(&i_dls_mgmt_lock, NULL, MUTEX_DEFAULT, NULL);
191 198 rw_init(&i_dls_devnet_lock, NULL, RW_DEFAULT, NULL);
192 199
193 200 /*
194 201 * Create a kmem_cache of dls_devnet_t structures.
195 202 */
196 203 i_dls_devnet_cachep = kmem_cache_create("dls_devnet_cache",
197 204 sizeof (dls_devnet_t), 0, i_dls_devnet_constructor,
198 205 i_dls_devnet_destructor, NULL, NULL, NULL, 0);
199 206 ASSERT(i_dls_devnet_cachep != NULL);
200 207
201 208 /*
202 209 * Create a hash table, keyed by dd_linkid, of dls_devnet_t.
203 210 */
204 211 i_dls_devnet_id_hash = mod_hash_create_idhash("dls_devnet_id_hash",
205 212 VLAN_HASHSZ, mod_hash_null_valdtor);
206 213
207 214 /*
208 215 * Create a hash table, keyed by dd_mac
209 216 */
210 217 i_dls_devnet_hash = mod_hash_create_extended("dls_devnet_hash",
211 218 VLAN_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
212 219 mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
213 220
214 221 devnet_need_rebuild = B_FALSE;
215 222
216 223 netstack_register(NS_DLS, dls_stack_init, dls_stack_shutdown,
217 224 dls_stack_fini);
218 225 }
219 226
220 227 void
221 228 dls_mgmt_fini(void)
222 229 {
223 230 netstack_unregister(NS_DLS);
224 231 mod_hash_destroy_hash(i_dls_devnet_hash);
225 232 mod_hash_destroy_hash(i_dls_devnet_id_hash);
226 233 kmem_cache_destroy(i_dls_devnet_cachep);
227 234 rw_destroy(&i_dls_devnet_lock);
228 235 mutex_destroy(&i_dls_mgmt_lock);
229 236 }
230 237
231 238 int
232 239 dls_mgmt_door_set(boolean_t start)
233 240 {
234 241 int err;
235 242
236 243 /* handle daemon restart */
237 244 mutex_enter(&i_dls_mgmt_lock);
238 245 if (dls_mgmt_dh != NULL) {
239 246 door_ki_rele(dls_mgmt_dh);
240 247 dls_mgmt_dh = NULL;
241 248 }
242 249
243 250 if (start && ((err = door_ki_open(DLMGMT_DOOR, &dls_mgmt_dh)) != 0)) {
244 251 mutex_exit(&i_dls_mgmt_lock);
245 252 return (err);
246 253 }
247 254
248 255 mutex_exit(&i_dls_mgmt_lock);
249 256
250 257 /*
251 258 * Create and associate <link name, linkid> mapping for network devices
252 259 * which are already attached before the daemon is started.
253 260 */
254 261 if (start)
255 262 softmac_recreate();
256 263 return (0);
257 264 }
258 265
259 266 static boolean_t
260 267 i_dls_mgmt_door_revoked(door_handle_t dh)
261 268 {
262 269 struct door_info info;
263 270 extern int sys_shutdown;
264 271
265 272 ASSERT(dh != NULL);
266 273
267 274 if (sys_shutdown) {
268 275 cmn_err(CE_NOTE, "dls_mgmt_door: shutdown observed\n");
269 276 return (B_TRUE);
270 277 }
271 278
272 279 if (door_ki_info(dh, &info) != 0)
273 280 return (B_TRUE);
274 281
275 282 return ((info.di_attributes & DOOR_REVOKED) != 0);
276 283 }
277 284
278 285 /*
279 286 * Upcall to the datalink management daemon (dlmgmtd).
280 287 */
281 288 static int
282 289 i_dls_mgmt_upcall(void *arg, size_t asize, void *rbuf, size_t rsize)
283 290 {
284 291 door_arg_t darg, save_arg;
285 292 door_handle_t dh;
286 293 int err;
287 294 int retry = 0;
288 295
289 296 #define MAXRETRYNUM 3
290 297
291 298 ASSERT(arg);
292 299 darg.data_ptr = arg;
293 300 darg.data_size = asize;
294 301 darg.desc_ptr = NULL;
295 302 darg.desc_num = 0;
296 303 darg.rbuf = rbuf;
297 304 darg.rsize = rsize;
298 305 save_arg = darg;
299 306
300 307 retry:
301 308 mutex_enter(&i_dls_mgmt_lock);
302 309 dh = dls_mgmt_dh;
303 310 if ((dh == NULL) || i_dls_mgmt_door_revoked(dh)) {
304 311 mutex_exit(&i_dls_mgmt_lock);
305 312 return (EBADF);
306 313 }
307 314 door_ki_hold(dh);
308 315 mutex_exit(&i_dls_mgmt_lock);
309 316
310 317 for (;;) {
311 318 retry++;
312 319 if ((err = door_ki_upcall_limited(dh, &darg, zone_kcred(),
313 320 SIZE_MAX, 0)) == 0)
314 321 break;
315 322
316 323 /*
317 324 * handle door call errors
318 325 */
319 326 darg = save_arg;
320 327 switch (err) {
321 328 case EINTR:
322 329 /*
323 330 * If the operation which caused this door upcall gets
324 331 * interrupted, return directly.
325 332 */
326 333 goto done;
327 334 case EAGAIN:
328 335 /*
329 336 * Repeat upcall if the maximum attempt limit has not
330 337 * been reached.
331 338 */
332 339 if (retry < MAXRETRYNUM) {
333 340 delay(2 * hz);
334 341 break;
335 342 }
336 343 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
337 344 goto done;
338 345 default:
339 346 /* A fatal door error */
340 347 if (i_dls_mgmt_door_revoked(dh)) {
341 348 cmn_err(CE_NOTE,
342 349 "dls: dlmgmtd door service revoked\n");
343 350
344 351 if (retry < MAXRETRYNUM) {
345 352 door_ki_rele(dh);
346 353 goto retry;
347 354 }
348 355 }
349 356 cmn_err(CE_WARN, "dls: dlmgmtd fatal error %d\n", err);
350 357 goto done;
351 358 }
352 359 }
353 360
354 361 if (darg.rbuf != rbuf) {
355 362 /*
356 363 * The size of the input rbuf was not big enough, so the
357 364 * upcall allocated the rbuf itself. If this happens, assume
358 365 * that this was an invalid door call request.
359 366 */
360 367 kmem_free(darg.rbuf, darg.rsize);
361 368 err = ENOSPC;
362 369 goto done;
363 370 }
364 371
365 372 if (darg.rsize != rsize) {
366 373 err = EINVAL;
367 374 goto done;
368 375 }
369 376
370 377 err = ((dlmgmt_retval_t *)rbuf)->lr_err;
371 378
372 379 done:
373 380 door_ki_rele(dh);
374 381 return (err);
375 382 }
376 383
377 384 /*
378 385 * Request the datalink management daemon to create a link with the attributes
379 386 * below. Upon success, zero is returned and linkidp contains the linkid for
380 387 * the new link; otherwise, an errno is returned.
381 388 *
382 389 * - dev physical dev_t. required for all physical links,
383 390 * including GLDv3 links. It will be used to force the
384 391 * attachment of a physical device, hence the
385 392 * registration of its mac
386 393 * - class datalink class
387 394 * - media type media type; DL_OTHER means unknown
388 395 * - persist whether to persist the datalink
389 396 */
390 397 int
391 398 dls_mgmt_create(const char *devname, dev_t dev, datalink_class_t class,
392 399 uint32_t media, boolean_t persist, datalink_id_t *linkidp)
393 400 {
394 401 dlmgmt_upcall_arg_create_t create;
395 402 dlmgmt_create_retval_t retval;
396 403 int err;
397 404
398 405 create.ld_cmd = DLMGMT_CMD_DLS_CREATE;
399 406 create.ld_class = class;
400 407 create.ld_media = media;
401 408 create.ld_phymaj = getmajor(dev);
402 409 create.ld_phyinst = getminor(dev);
403 410 create.ld_persist = persist;
404 411 if (strlcpy(create.ld_devname, devname, sizeof (create.ld_devname)) >=
405 412 sizeof (create.ld_devname))
406 413 return (EINVAL);
407 414
408 415 if ((err = i_dls_mgmt_upcall(&create, sizeof (create), &retval,
409 416 sizeof (retval))) == 0) {
410 417 *linkidp = retval.lr_linkid;
411 418 }
412 419 return (err);
413 420 }
414 421
415 422 /*
416 423 * Request the datalink management daemon to destroy the specified link.
417 424 * Returns zero upon success, or an errno upon failure.
418 425 */
419 426 int
420 427 dls_mgmt_destroy(datalink_id_t linkid, boolean_t persist)
421 428 {
422 429 dlmgmt_upcall_arg_destroy_t destroy;
423 430 dlmgmt_destroy_retval_t retval;
424 431
425 432 destroy.ld_cmd = DLMGMT_CMD_DLS_DESTROY;
426 433 destroy.ld_linkid = linkid;
427 434 destroy.ld_persist = persist;
428 435
429 436 return (i_dls_mgmt_upcall(&destroy, sizeof (destroy),
430 437 &retval, sizeof (retval)));
431 438 }
432 439
433 440 /*
434 441 * Request the datalink management daemon to verify/update the information
435 442 * for a physical link. Upon success, get its linkid.
436 443 *
437 444 * - media type media type
438 445 * - novanity whether this physical datalink supports vanity naming.
439 446 * physical links that do not use the GLDv3 MAC plugin
440 447 * cannot suport vanity naming
441 448 *
442 449 * This function could fail with ENOENT or EEXIST. Two cases return EEXIST:
443 450 *
444 451 * 1. A link with devname already exists, but the media type does not match.
445 452 * In this case, mediap will bee set to the media type of the existing link.
446 453 * 2. A link with devname already exists, but its link name does not match
447 454 * the device name, although this link does not support vanity naming.
448 455 */
449 456 int
450 457 dls_mgmt_update(const char *devname, uint32_t media, boolean_t novanity,
451 458 uint32_t *mediap, datalink_id_t *linkidp)
452 459 {
453 460 dlmgmt_upcall_arg_update_t update;
454 461 dlmgmt_update_retval_t retval;
455 462 int err;
456 463
457 464 update.ld_cmd = DLMGMT_CMD_DLS_UPDATE;
458 465
459 466 if (strlcpy(update.ld_devname, devname, sizeof (update.ld_devname)) >=
460 467 sizeof (update.ld_devname))
461 468 return (EINVAL);
462 469
463 470 update.ld_media = media;
464 471 update.ld_novanity = novanity;
465 472
466 473 if ((err = i_dls_mgmt_upcall(&update, sizeof (update), &retval,
467 474 sizeof (retval))) == EEXIST) {
468 475 *linkidp = retval.lr_linkid;
469 476 *mediap = retval.lr_media;
470 477 } else if (err == 0) {
471 478 *linkidp = retval.lr_linkid;
472 479 }
473 480
474 481 return (err);
475 482 }
476 483
477 484 /*
478 485 * Request the datalink management daemon to get the information for a link.
479 486 * Returns zero upon success, or an errno upon failure.
480 487 *
481 488 * Only fills in information for argument pointers that are non-NULL.
482 489 * Note that the link argument is expected to be MAXLINKNAMELEN bytes.
483 490 */
484 491 int
485 492 dls_mgmt_get_linkinfo(datalink_id_t linkid, char *link,
486 493 datalink_class_t *classp, uint32_t *mediap, uint32_t *flagsp)
487 494 {
488 495 dlmgmt_door_getname_t getname;
489 496 dlmgmt_getname_retval_t retval;
490 497 int err, len;
491 498
492 499 getname.ld_cmd = DLMGMT_CMD_GETNAME;
493 500 getname.ld_linkid = linkid;
494 501
495 502 if ((err = i_dls_mgmt_upcall(&getname, sizeof (getname), &retval,
496 503 sizeof (retval))) != 0) {
497 504 return (err);
498 505 }
499 506
500 507 len = strlen(retval.lr_link);
501 508 if (len <= 1 || len >= MAXLINKNAMELEN)
502 509 return (EINVAL);
503 510
504 511 if (link != NULL)
505 512 (void) strlcpy(link, retval.lr_link, MAXLINKNAMELEN);
506 513 if (classp != NULL)
507 514 *classp = retval.lr_class;
508 515 if (mediap != NULL)
509 516 *mediap = retval.lr_media;
510 517 if (flagsp != NULL)
511 518 *flagsp = retval.lr_flags;
512 519 return (0);
513 520 }
514 521
515 522 /*
516 523 * Request the datalink management daemon to get the linkid for a link.
517 524 * Returns a non-zero error code on failure. The linkid argument is only
518 525 * set on success (when zero is returned.)
|
↓ open down ↓ |
360 lines elided |
↑ open up ↑ |
519 526 */
520 527 int
521 528 dls_mgmt_get_linkid(const char *link, datalink_id_t *linkid)
522 529 {
523 530 dlmgmt_door_getlinkid_t getlinkid;
524 531 dlmgmt_getlinkid_retval_t retval;
525 532 int err;
526 533
527 534 getlinkid.ld_cmd = DLMGMT_CMD_GETLINKID;
528 535 (void) strlcpy(getlinkid.ld_link, link, MAXLINKNAMELEN);
536 + getlinkid.ld_zoneid = getzoneid();
529 537
530 538 if ((err = i_dls_mgmt_upcall(&getlinkid, sizeof (getlinkid), &retval,
531 539 sizeof (retval))) == 0) {
532 540 *linkid = retval.lr_linkid;
533 541 }
534 542 return (err);
535 543 }
536 544
537 545 datalink_id_t
538 546 dls_mgmt_get_next(datalink_id_t linkid, datalink_class_t class,
539 547 datalink_media_t dmedia, uint32_t flags)
540 548 {
541 549 dlmgmt_door_getnext_t getnext;
542 550 dlmgmt_getnext_retval_t retval;
543 551
544 552 getnext.ld_cmd = DLMGMT_CMD_GETNEXT;
545 553 getnext.ld_class = class;
546 554 getnext.ld_dmedia = dmedia;
547 555 getnext.ld_flags = flags;
548 556 getnext.ld_linkid = linkid;
549 557
550 558 if (i_dls_mgmt_upcall(&getnext, sizeof (getnext), &retval,
551 559 sizeof (retval)) != 0) {
552 560 return (DATALINK_INVALID_LINKID);
553 561 }
554 562
555 563 return (retval.lr_linkid);
556 564 }
557 565
558 566 static int
559 567 i_dls_mgmt_get_linkattr(const datalink_id_t linkid, const char *attr,
560 568 void *attrval, size_t *attrszp)
561 569 {
562 570 dlmgmt_upcall_arg_getattr_t getattr;
563 571 dlmgmt_getattr_retval_t retval;
564 572 int err;
565 573
566 574 getattr.ld_cmd = DLMGMT_CMD_DLS_GETATTR;
567 575 getattr.ld_linkid = linkid;
568 576 (void) strlcpy(getattr.ld_attr, attr, MAXLINKATTRLEN);
569 577
570 578 if ((err = i_dls_mgmt_upcall(&getattr, sizeof (getattr), &retval,
571 579 sizeof (retval))) == 0) {
572 580 if (*attrszp < retval.lr_attrsz)
573 581 return (EINVAL);
574 582 *attrszp = retval.lr_attrsz;
575 583 bcopy(retval.lr_attrval, attrval, retval.lr_attrsz);
576 584 }
577 585
578 586 return (err);
579 587 }
580 588
581 589 /*
582 590 * Note that this function can only get devp successfully for non-VLAN link.
583 591 */
584 592 int
585 593 dls_mgmt_get_phydev(datalink_id_t linkid, dev_t *devp)
586 594 {
587 595 uint64_t maj, inst;
588 596 size_t attrsz = sizeof (uint64_t);
589 597
590 598 if (i_dls_mgmt_get_linkattr(linkid, FPHYMAJ, &maj, &attrsz) != 0 ||
591 599 attrsz != sizeof (uint64_t) ||
592 600 i_dls_mgmt_get_linkattr(linkid, FPHYINST, &inst, &attrsz) != 0 ||
593 601 attrsz != sizeof (uint64_t)) {
594 602 return (EINVAL);
595 603 }
596 604
597 605 *devp = makedevice((major_t)maj, (minor_t)inst);
598 606 return (0);
599 607 }
600 608
601 609 /*
602 610 * Request the datalink management daemon to push in
603 611 * all properties associated with the link.
604 612 * Returns a non-zero error code on failure.
605 613 */
606 614 int
607 615 dls_mgmt_linkprop_init(datalink_id_t linkid)
608 616 {
609 617 dlmgmt_door_linkprop_init_t li;
610 618 dlmgmt_linkprop_init_retval_t retval;
611 619 int err;
612 620
613 621 li.ld_cmd = DLMGMT_CMD_LINKPROP_INIT;
614 622 li.ld_linkid = linkid;
615 623
616 624 err = i_dls_mgmt_upcall(&li, sizeof (li), &retval, sizeof (retval));
617 625 return (err);
618 626 }
619 627
620 628 static void
621 629 dls_devnet_prop_task(void *arg)
622 630 {
623 631 dls_devnet_t *ddp = arg;
624 632
625 633 (void) dls_mgmt_linkprop_init(ddp->dd_linkid);
626 634
627 635 mutex_enter(&ddp->dd_mutex);
628 636 ddp->dd_prop_loaded = B_TRUE;
629 637 ddp->dd_prop_taskid = NULL;
630 638 cv_broadcast(&ddp->dd_cv);
631 639 mutex_exit(&ddp->dd_mutex);
632 640 }
633 641
634 642 /*
635 643 * Ensure property loading task is completed.
636 644 */
637 645 void
638 646 dls_devnet_prop_task_wait(dls_dl_handle_t ddp)
639 647 {
640 648 mutex_enter(&ddp->dd_mutex);
641 649 while (ddp->dd_prop_taskid != NULL)
642 650 cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
643 651 mutex_exit(&ddp->dd_mutex);
644 652 }
645 653
646 654 void
647 655 dls_devnet_rele_tmp(dls_dl_handle_t dlh)
648 656 {
649 657 dls_devnet_t *ddp = dlh;
650 658
651 659 mutex_enter(&ddp->dd_mutex);
652 660 ASSERT(ddp->dd_tref != 0);
653 661 if (--ddp->dd_tref == 0)
654 662 cv_signal(&ddp->dd_cv);
655 663 mutex_exit(&ddp->dd_mutex);
656 664 }
657 665
658 666 int
659 667 dls_devnet_hold_link(datalink_id_t linkid, dls_dl_handle_t *ddhp,
660 668 dls_link_t **dlpp)
661 669 {
662 670 dls_dl_handle_t dlh;
663 671 dls_link_t *dlp;
664 672 int err;
665 673
666 674 if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
667 675 return (err);
668 676
669 677 if ((err = dls_link_hold(dls_devnet_mac(dlh), &dlp)) != 0) {
670 678 dls_devnet_rele_tmp(dlh);
671 679 return (err);
672 680 }
673 681
674 682 ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
675 683
676 684 *ddhp = dlh;
677 685 *dlpp = dlp;
678 686 return (0);
679 687 }
680 688
681 689 void
682 690 dls_devnet_rele_link(dls_dl_handle_t dlh, dls_link_t *dlp)
683 691 {
684 692 ASSERT(MAC_PERIM_HELD(dlp->dl_mh));
685 693
686 694 dls_link_rele(dlp);
687 695 dls_devnet_rele_tmp(dlh);
688 696 }
689 697
690 698 /*
691 699 * "link" kstats related functions.
692 700 */
693 701
694 702 /*
695 703 * Query the "link" kstats.
696 704 *
697 705 * We may be called from the kstat subsystem in an arbitrary context.
698 706 * If the caller is the stack, the context could be an upcall data
699 707 * thread. Hence we can't acquire the mac perimeter in this function
700 708 * for fear of deadlock.
701 709 */
702 710 static int
703 711 dls_devnet_stat_update(kstat_t *ksp, int rw)
704 712 {
705 713 dls_devnet_t *ddp = ksp->ks_private;
706 714 dls_link_t *dlp;
707 715 int err;
708 716
709 717 /*
710 718 * Check the link is being renamed or if the link is going away
711 719 * before incrementing dd_tref which in turn prevents the link
712 720 * from being renamed or deleted until we finish.
713 721 */
714 722 mutex_enter(&ddp->dd_mutex);
715 723 if (ddp->dd_flags & (DD_CONDEMNED | DD_KSTAT_CHANGING)) {
716 724 mutex_exit(&ddp->dd_mutex);
717 725 return (ENOENT);
718 726 }
719 727 ddp->dd_tref++;
720 728 mutex_exit(&ddp->dd_mutex);
721 729
722 730 /*
723 731 * If a device detach happens at this time, it will block in
724 732 * dls_devnet_unset since the dd_tref has been bumped up above. So the
725 733 * access to 'dlp' is safe even though we don't hold the mac perimeter.
726 734 */
727 735 if (mod_hash_find(i_dls_link_hash, (mod_hash_key_t)ddp->dd_mac,
728 736 (mod_hash_val_t *)&dlp) != 0) {
729 737 dls_devnet_rele_tmp(ddp);
730 738 return (ENOENT);
731 739 }
732 740
|
↓ open down ↓ |
194 lines elided |
↑ open up ↑ |
733 741 err = dls_stat_update(ksp, dlp, rw);
734 742
735 743 dls_devnet_rele_tmp(ddp);
736 744 return (err);
737 745 }
738 746
739 747 /*
740 748 * Create the "link" kstats.
741 749 */
742 750 static void
743 -dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid)
751 +dls_devnet_stat_create(dls_devnet_t *ddp, zoneid_t zoneid, zoneid_t newzoneid)
744 752 {
745 753 kstat_t *ksp;
754 + char *nm;
755 + char kname[MAXLINKNAMELEN];
746 756
747 - if (dls_stat_create("link", 0, ddp->dd_linkname, zoneid,
748 - dls_devnet_stat_update, ddp, &ksp) == 0) {
757 + if (zoneid != newzoneid) {
758 + ASSERT(zoneid == GLOBAL_ZONEID);
759 + (void) snprintf(kname, sizeof (kname), "z%d_%s", newzoneid,
760 + ddp->dd_linkname);
761 + nm = kname;
762 + } else {
763 + nm = ddp->dd_linkname;
764 + }
765 +
766 + if (dls_stat_create("link", 0, nm, zoneid,
767 + dls_devnet_stat_update, ddp, &ksp, newzoneid) == 0) {
749 768 ASSERT(ksp != NULL);
750 769 if (zoneid == ddp->dd_owner_zid) {
751 770 ASSERT(ddp->dd_ksp == NULL);
752 771 ddp->dd_ksp = ksp;
753 772 } else {
754 773 ASSERT(ddp->dd_zone_ksp == NULL);
755 774 ddp->dd_zone_ksp = ksp;
756 775 }
757 776 }
758 777 }
759 778
760 779 /*
761 780 * Destroy the "link" kstats.
762 781 */
763 782 static void
764 783 dls_devnet_stat_destroy(dls_devnet_t *ddp, zoneid_t zoneid)
765 784 {
766 785 if (zoneid == ddp->dd_owner_zid) {
767 786 if (ddp->dd_ksp != NULL) {
768 - kstat_delete(ddp->dd_ksp);
787 + dls_stat_delete(ddp->dd_ksp);
769 788 ddp->dd_ksp = NULL;
770 789 }
771 790 } else {
772 791 if (ddp->dd_zone_ksp != NULL) {
773 - kstat_delete(ddp->dd_zone_ksp);
792 + dls_stat_delete(ddp->dd_zone_ksp);
774 793 ddp->dd_zone_ksp = NULL;
775 794 }
776 795 }
777 796 }
778 797
779 798 /*
780 799 * The link has been renamed. Destroy the old non-legacy kstats ("link kstats")
781 800 * and create the new set using the new name.
782 801 */
783 802 static void
784 -dls_devnet_stat_rename(dls_devnet_t *ddp)
803 +dls_devnet_stat_rename(dls_devnet_t *ddp, boolean_t zoneinit)
785 804 {
786 805 if (ddp->dd_ksp != NULL) {
787 - kstat_delete(ddp->dd_ksp);
806 + dls_stat_delete(ddp->dd_ksp);
788 807 ddp->dd_ksp = NULL;
789 808 }
790 - /* We can't rename a link while it's assigned to a non-global zone. */
809 + if (zoneinit && ddp->dd_zone_ksp != NULL) {
810 + dls_stat_delete(ddp->dd_zone_ksp);
811 + ddp->dd_zone_ksp = NULL;
812 + }
813 + /*
814 + * We can't rename a link while it's assigned to a non-global zone
815 + * unless we're first initializing the zone while readying it.
816 + */
791 817 ASSERT(ddp->dd_zone_ksp == NULL);
792 - dls_devnet_stat_create(ddp, ddp->dd_owner_zid);
818 + dls_devnet_stat_create(ddp, ddp->dd_owner_zid,
819 + (zoneinit ? ddp->dd_zid : ddp->dd_owner_zid));
820 + if (zoneinit)
821 + dls_devnet_stat_create(ddp, ddp->dd_zid, ddp->dd_zid);
793 822 }
794 823
795 824 /*
796 825 * Associate a linkid with a given link (identified by macname)
797 826 */
798 827 static int
799 828 dls_devnet_set(const char *macname, datalink_id_t linkid, zoneid_t zoneid,
800 829 dls_devnet_t **ddpp)
801 830 {
802 831 dls_devnet_t *ddp = NULL;
803 832 datalink_class_t class;
804 833 int err;
805 834 boolean_t stat_create = B_FALSE;
806 835 char linkname[MAXLINKNAMELEN];
807 836
808 837 rw_enter(&i_dls_devnet_lock, RW_WRITER);
809 838
810 839 /*
811 840 * Don't allow callers to set a link name with a linkid that already
812 841 * has a name association (that's what rename is for).
813 842 */
814 843 if (linkid != DATALINK_INVALID_LINKID) {
815 844 if (mod_hash_find(i_dls_devnet_id_hash,
816 845 (mod_hash_key_t)(uintptr_t)linkid,
817 846 (mod_hash_val_t *)&ddp) == 0) {
818 847 err = EEXIST;
819 848 goto done;
820 849 }
821 850 if ((err = dls_mgmt_get_linkinfo(linkid, linkname, &class,
822 851 NULL, NULL)) != 0)
823 852 goto done;
824 853 }
825 854
826 855 if ((err = mod_hash_find(i_dls_devnet_hash,
827 856 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) == 0) {
828 857 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
829 858 err = EEXIST;
830 859 goto done;
831 860 }
832 861
833 862 /*
834 863 * This might be a physical link that has already
835 864 * been created, but which does not have a linkid
836 865 * because dlmgmtd was not running when it was created.
837 866 */
838 867 if (linkid == DATALINK_INVALID_LINKID ||
839 868 class != DATALINK_CLASS_PHYS) {
840 869 err = EINVAL;
841 870 goto done;
842 871 }
843 872 } else {
844 873 ddp = kmem_cache_alloc(i_dls_devnet_cachep, KM_SLEEP);
845 874 ddp->dd_tref = 0;
846 875 ddp->dd_ref++;
847 876 ddp->dd_owner_zid = zoneid;
848 877 (void) strlcpy(ddp->dd_mac, macname, sizeof (ddp->dd_mac));
849 878 VERIFY(mod_hash_insert(i_dls_devnet_hash,
850 879 (mod_hash_key_t)ddp->dd_mac, (mod_hash_val_t)ddp) == 0);
851 880 }
852 881
853 882 if (linkid != DATALINK_INVALID_LINKID) {
854 883 ddp->dd_linkid = linkid;
855 884 (void) strlcpy(ddp->dd_linkname, linkname,
856 885 sizeof (ddp->dd_linkname));
857 886 VERIFY(mod_hash_insert(i_dls_devnet_id_hash,
858 887 (mod_hash_key_t)(uintptr_t)linkid,
859 888 (mod_hash_val_t)ddp) == 0);
860 889 devnet_need_rebuild = B_TRUE;
861 890 stat_create = B_TRUE;
862 891 mutex_enter(&ddp->dd_mutex);
863 892 if (!ddp->dd_prop_loaded && (ddp->dd_prop_taskid == NULL)) {
864 893 ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
865 894 dls_devnet_prop_task, ddp, TQ_SLEEP);
866 895 }
867 896 mutex_exit(&ddp->dd_mutex);
868 897 }
869 898 err = 0;
870 899 done:
|
↓ open down ↓ |
68 lines elided |
↑ open up ↑ |
871 900 /*
872 901 * It is safe to drop the i_dls_devnet_lock at this point. In the case
873 902 * of physical devices, the softmac framework will fail the device
874 903 * detach based on the smac_state or smac_hold_cnt. Other cases like
875 904 * vnic and aggr use their own scheme to serialize creates and deletes
876 905 * and ensure that *ddp is valid.
877 906 */
878 907 rw_exit(&i_dls_devnet_lock);
879 908 if (err == 0) {
880 909 if (zoneid != GLOBAL_ZONEID &&
881 - (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE)) != 0)
910 + (err = i_dls_devnet_setzid(ddp, zoneid, B_FALSE,
911 + B_FALSE)) != 0)
882 912 (void) dls_devnet_unset(macname, &linkid, B_TRUE);
883 913 /*
884 914 * The kstat subsystem holds its own locks (rather perimeter)
885 915 * before calling the ks_update (dls_devnet_stat_update) entry
886 916 * point which in turn grabs the i_dls_devnet_lock. So the
887 917 * lock hierarchy is kstat locks -> i_dls_devnet_lock.
888 918 */
889 919 if (stat_create)
890 - dls_devnet_stat_create(ddp, zoneid);
920 + dls_devnet_stat_create(ddp, zoneid, zoneid);
891 921 if (ddpp != NULL)
892 922 *ddpp = ddp;
893 923 }
894 924 return (err);
895 925 }
896 926
897 927 /*
898 928 * Disassociate a linkid with a given link (identified by macname)
899 929 * This waits until temporary references to the dls_devnet_t are gone.
900 930 */
901 931 static int
902 932 dls_devnet_unset(const char *macname, datalink_id_t *id, boolean_t wait)
903 933 {
904 934 dls_devnet_t *ddp;
905 935 int err;
906 936 mod_hash_val_t val;
907 937
908 938 rw_enter(&i_dls_devnet_lock, RW_WRITER);
909 939 if ((err = mod_hash_find(i_dls_devnet_hash,
910 940 (mod_hash_key_t)macname, (mod_hash_val_t *)&ddp)) != 0) {
911 941 ASSERT(err == MH_ERR_NOTFOUND);
912 942 rw_exit(&i_dls_devnet_lock);
913 943 return (ENOENT);
914 944 }
915 945
916 946 mutex_enter(&ddp->dd_mutex);
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
917 947
918 948 /*
919 949 * Make sure downcalls into softmac_create or softmac_destroy from
920 950 * devfs don't cv_wait on any devfs related condition for fear of
921 951 * deadlock. Return EBUSY if the asynchronous thread started for
922 952 * property loading as part of the post attach hasn't yet completed.
923 953 */
924 954 ASSERT(ddp->dd_ref != 0);
925 955 if ((ddp->dd_ref != 1) || (!wait &&
926 956 (ddp->dd_tref != 0 || ddp->dd_prop_taskid != NULL))) {
927 - mutex_exit(&ddp->dd_mutex);
928 - rw_exit(&i_dls_devnet_lock);
929 - return (EBUSY);
957 + int zstatus = 0;
958 +
959 + /*
960 + * There are a couple of alternatives that might be going on
961 + * here; a) the zone is shutting down and it has a transient
962 + * link assigned, in which case we want to clean it up instead
963 + * of moving it back to the global zone, or b) its possible
964 + * that we're trying to clean up an orphaned vnic that was
965 + * delegated to a zone and which wasn't cleaned up properly
966 + * when the zone went away. Check for either of these cases
967 + * before we simply return EBUSY.
968 + *
969 + * zstatus indicates which situation we are dealing with:
970 + * 0 - means return EBUSY
971 + * 1 - means case (a), cleanup transient link
972 + * -1 - means case (b), orphained VNIC
973 + */
974 + if (ddp->dd_ref > 1 && ddp->dd_zid != GLOBAL_ZONEID) {
975 + zone_t *zp;
976 +
977 + if ((zp = zone_find_by_id(ddp->dd_zid)) == NULL) {
978 + zstatus = -1;
979 + } else {
980 + if (ddp->dd_transient) {
981 + zone_status_t s = zone_status_get(zp);
982 +
983 + if (s >= ZONE_IS_SHUTTING_DOWN)
984 + zstatus = 1;
985 + }
986 + zone_rele(zp);
987 + }
988 + }
989 +
990 + if (zstatus == 0) {
991 + mutex_exit(&ddp->dd_mutex);
992 + rw_exit(&i_dls_devnet_lock);
993 + return (EBUSY);
994 + }
995 +
996 + /*
997 + * We want to delete the link, reset ref to 1;
998 + */
999 + if (zstatus == -1)
1000 + /* Log a warning, but continue in this case */
1001 + cmn_err(CE_WARN, "clear orphaned datalink: %s\n",
1002 + ddp->dd_linkname);
1003 + ddp->dd_ref = 1;
930 1004 }
931 1005
932 1006 ddp->dd_flags |= DD_CONDEMNED;
933 1007 ddp->dd_ref--;
934 1008 *id = ddp->dd_linkid;
935 1009
936 - if (ddp->dd_zid != GLOBAL_ZONEID)
937 - (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE);
1010 + if (ddp->dd_zid != GLOBAL_ZONEID) {
1011 + /*
1012 + * We need to release the dd_mutex before we try and destroy the
1013 + * stat. When we destroy it, we'll need to grab the lock for the
1014 + * kstat but if there's a concurrent reader of the kstat, we'll
1015 + * be blocked on it. This will lead to deadlock because these
1016 + * kstats employ a ks_update function (dls_devnet_stat_update)
1017 + * which needs the dd_mutex that we currently hold.
1018 + *
1019 + * Because we've already flagged the dls_devnet_t as
1020 + * DD_CONDEMNED and we still have a write lock on
1021 + * i_dls_devnet_lock, we should be able to release the dd_mutex.
1022 + */
1023 + mutex_exit(&ddp->dd_mutex);
1024 + dls_devnet_stat_destroy(ddp, ddp->dd_zid);
1025 + mutex_enter(&ddp->dd_mutex);
1026 + (void) i_dls_devnet_setzid(ddp, GLOBAL_ZONEID, B_FALSE,
1027 + B_FALSE);
1028 + }
938 1029
939 1030 /*
940 1031 * Remove this dls_devnet_t from the hash table.
941 1032 */
942 1033 VERIFY(mod_hash_remove(i_dls_devnet_hash,
943 1034 (mod_hash_key_t)ddp->dd_mac, &val) == 0);
944 1035
945 1036 if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
946 1037 VERIFY(mod_hash_remove(i_dls_devnet_id_hash,
947 1038 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, &val) == 0);
948 1039
949 1040 devnet_need_rebuild = B_TRUE;
950 1041 }
951 1042 rw_exit(&i_dls_devnet_lock);
952 1043
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
953 1044 if (wait) {
954 1045 /*
955 1046 * Wait until all temporary references are released.
956 1047 */
957 1048 while ((ddp->dd_tref != 0) || (ddp->dd_prop_taskid != NULL))
958 1049 cv_wait(&ddp->dd_cv, &ddp->dd_mutex);
959 1050 } else {
960 1051 ASSERT(ddp->dd_tref == 0 && ddp->dd_prop_taskid == NULL);
961 1052 }
962 1053
963 - if (ddp->dd_linkid != DATALINK_INVALID_LINKID)
1054 + if (ddp->dd_linkid != DATALINK_INVALID_LINKID) {
1055 + /*
1056 + * See the earlier call in this function for an explanation.
1057 + */
1058 + mutex_exit(&ddp->dd_mutex);
964 1059 dls_devnet_stat_destroy(ddp, ddp->dd_owner_zid);
1060 + mutex_enter(&ddp->dd_mutex);
1061 + }
965 1062
1063 +
966 1064 ddp->dd_prop_loaded = B_FALSE;
967 1065 ddp->dd_linkid = DATALINK_INVALID_LINKID;
968 1066 ddp->dd_flags = 0;
969 1067 mutex_exit(&ddp->dd_mutex);
970 1068 kmem_cache_free(i_dls_devnet_cachep, ddp);
971 1069
972 1070 return (0);
973 1071 }
974 1072
975 1073 static int
976 1074 dls_devnet_hold_common(datalink_id_t linkid, dls_devnet_t **ddpp,
977 1075 boolean_t tmp_hold)
978 1076 {
979 1077 dls_devnet_t *ddp;
980 1078 dev_t phydev = 0;
981 1079 dls_dev_handle_t ddh = NULL;
982 1080 int err;
983 1081
984 1082 /*
985 1083 * Hold this link to prevent it being detached in case of a
986 1084 * physical link.
987 1085 */
988 1086 if (dls_mgmt_get_phydev(linkid, &phydev) == 0)
989 1087 (void) softmac_hold_device(phydev, &ddh);
990 1088
991 1089 rw_enter(&i_dls_devnet_lock, RW_WRITER);
992 1090 if ((err = mod_hash_find(i_dls_devnet_id_hash,
993 1091 (mod_hash_key_t)(uintptr_t)linkid, (mod_hash_val_t *)&ddp)) != 0) {
994 1092 ASSERT(err == MH_ERR_NOTFOUND);
995 1093 rw_exit(&i_dls_devnet_lock);
996 1094 softmac_rele_device(ddh);
997 1095 return (ENOENT);
998 1096 }
999 1097
1000 1098 mutex_enter(&ddp->dd_mutex);
1001 1099 ASSERT(ddp->dd_ref > 0);
1002 1100 if (ddp->dd_flags & DD_CONDEMNED) {
1003 1101 mutex_exit(&ddp->dd_mutex);
1004 1102 rw_exit(&i_dls_devnet_lock);
1005 1103 softmac_rele_device(ddh);
1006 1104 return (ENOENT);
1007 1105 }
1008 1106 if (tmp_hold)
1009 1107 ddp->dd_tref++;
1010 1108 else
1011 1109 ddp->dd_ref++;
1012 1110 mutex_exit(&ddp->dd_mutex);
1013 1111 rw_exit(&i_dls_devnet_lock);
1014 1112
1015 1113 softmac_rele_device(ddh);
1016 1114
1017 1115 *ddpp = ddp;
1018 1116 return (0);
1019 1117 }
1020 1118
1021 1119 int
1022 1120 dls_devnet_hold(datalink_id_t linkid, dls_devnet_t **ddpp)
1023 1121 {
1024 1122 return (dls_devnet_hold_common(linkid, ddpp, B_FALSE));
1025 1123 }
1026 1124
1027 1125 /*
1028 1126 * Hold the vanity naming structure (dls_devnet_t) temporarily. The request to
1029 1127 * delete the dls_devnet_t will wait until the temporary reference is released.
1030 1128 */
1031 1129 int
1032 1130 dls_devnet_hold_tmp(datalink_id_t linkid, dls_devnet_t **ddpp)
1033 1131 {
1034 1132 return (dls_devnet_hold_common(linkid, ddpp, B_TRUE));
1035 1133 }
1036 1134
1037 1135 /*
1038 1136 * This funtion is called when a DLS client tries to open a device node.
1039 1137 * This dev_t could a result of a /dev/net node access (returned by
1040 1138 * devnet_create_rvp->dls_devnet_open()) or a direct /dev node access.
1041 1139 * In both cases, this function bumps up the reference count of the
1042 1140 * dls_devnet_t structure. The reference is held as long as the device node
1043 1141 * is open. In the case of /dev/net while it is true that the initial reference
1044 1142 * is held when the devnet_create_rvp->dls_devnet_open call happens, this
1045 1143 * initial reference is released immediately in devnet_inactive_callback ->
1046 1144 * dls_devnet_close(). (Note that devnet_inactive_callback() is called right
1047 1145 * after dld_open completes, not when the /dev/net node is being closed).
1048 1146 * To undo this function, call dls_devnet_rele()
1049 1147 */
1050 1148 int
1051 1149 dls_devnet_hold_by_dev(dev_t dev, dls_dl_handle_t *ddhp)
1052 1150 {
1053 1151 char name[MAXNAMELEN];
1054 1152 char *drv;
1055 1153 dls_dev_handle_t ddh = NULL;
1056 1154 dls_devnet_t *ddp;
1057 1155 int err;
1058 1156
1059 1157 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1060 1158 return (EINVAL);
1061 1159
1062 1160 (void) snprintf(name, sizeof (name), "%s%d", drv,
1063 1161 DLS_MINOR2INST(getminor(dev)));
1064 1162
1065 1163 /*
1066 1164 * Hold this link to prevent it being detached in case of a
1067 1165 * GLDv3 physical link.
1068 1166 */
1069 1167 if (DLS_MINOR2INST(getminor(dev)) <= DLS_MAX_PPA)
1070 1168 (void) softmac_hold_device(dev, &ddh);
1071 1169
1072 1170 rw_enter(&i_dls_devnet_lock, RW_WRITER);
1073 1171 if ((err = mod_hash_find(i_dls_devnet_hash,
1074 1172 (mod_hash_key_t)name, (mod_hash_val_t *)&ddp)) != 0) {
1075 1173 ASSERT(err == MH_ERR_NOTFOUND);
1076 1174 rw_exit(&i_dls_devnet_lock);
1077 1175 softmac_rele_device(ddh);
1078 1176 return (ENOENT);
1079 1177 }
1080 1178 mutex_enter(&ddp->dd_mutex);
1081 1179 ASSERT(ddp->dd_ref > 0);
1082 1180 if (ddp->dd_flags & DD_CONDEMNED) {
1083 1181 mutex_exit(&ddp->dd_mutex);
1084 1182 rw_exit(&i_dls_devnet_lock);
1085 1183 softmac_rele_device(ddh);
1086 1184 return (ENOENT);
1087 1185 }
1088 1186 ddp->dd_ref++;
1089 1187 mutex_exit(&ddp->dd_mutex);
1090 1188 rw_exit(&i_dls_devnet_lock);
1091 1189
1092 1190 softmac_rele_device(ddh);
1093 1191
1094 1192 *ddhp = ddp;
1095 1193 return (0);
1096 1194 }
1097 1195
1098 1196 void
1099 1197 dls_devnet_rele(dls_devnet_t *ddp)
1100 1198 {
1101 1199 mutex_enter(&ddp->dd_mutex);
1102 1200 ASSERT(ddp->dd_ref > 1);
1103 1201 ddp->dd_ref--;
1104 1202 if ((ddp->dd_flags & DD_IMPLICIT_IPTUN) && ddp->dd_ref == 1) {
1105 1203 mutex_exit(&ddp->dd_mutex);
1106 1204 if (i_dls_devnet_destroy_iptun(ddp->dd_linkid) != 0)
1107 1205 ddp->dd_flags |= DD_IMPLICIT_IPTUN;
1108 1206 return;
1109 1207 }
1110 1208 mutex_exit(&ddp->dd_mutex);
1111 1209 }
1112 1210
1113 1211 static int
1114 1212 dls_devnet_hold_by_name(const char *link, dls_devnet_t **ddpp)
1115 1213 {
1116 1214 char drv[MAXLINKNAMELEN];
1117 1215 uint_t ppa;
1118 1216 major_t major;
1119 1217 dev_t phy_dev, tmp_dev;
1120 1218 datalink_id_t linkid;
1121 1219 dls_dev_handle_t ddh;
1122 1220 int err;
1123 1221
1124 1222 if ((err = dls_mgmt_get_linkid(link, &linkid)) == 0)
1125 1223 return (dls_devnet_hold(linkid, ddpp));
1126 1224
1127 1225 /*
1128 1226 * If we failed to get the link's linkid because the dlmgmtd daemon
1129 1227 * has not been started, return ENOENT so that the application can
1130 1228 * fallback to open the /dev node.
1131 1229 */
1132 1230 if (err == EBADF)
1133 1231 return (ENOENT);
1134 1232
1135 1233 if (err != ENOENT)
1136 1234 return (err);
1137 1235
1138 1236 if (ddi_parse(link, drv, &ppa) != DDI_SUCCESS)
1139 1237 return (ENOENT);
1140 1238
1141 1239 if (IS_IPTUN_LINK(drv)) {
1142 1240 if ((err = i_dls_devnet_create_iptun(link, drv, &linkid)) != 0)
1143 1241 return (err);
1144 1242 /*
1145 1243 * At this point, an IP tunnel MAC has registered, which
1146 1244 * resulted in a link being created.
1147 1245 */
1148 1246 err = dls_devnet_hold(linkid, ddpp);
1149 1247 ASSERT(err == 0);
1150 1248 if (err != 0) {
1151 1249 VERIFY(i_dls_devnet_destroy_iptun(linkid) == 0);
1152 1250 return (err);
1153 1251 }
1154 1252 /*
1155 1253 * dls_devnet_rele() will know to destroy the implicit IP
1156 1254 * tunnel on last reference release if DD_IMPLICIT_IPTUN is
1157 1255 * set.
1158 1256 */
1159 1257 (*ddpp)->dd_flags |= DD_IMPLICIT_IPTUN;
1160 1258 return (0);
1161 1259 }
1162 1260
1163 1261 /*
1164 1262 * If this link:
1165 1263 * (a) is a physical device, (b) this is the first boot, (c) the MAC
1166 1264 * is not registered yet, and (d) we cannot find its linkid, then the
1167 1265 * linkname is the same as the devname.
1168 1266 *
1169 1267 * First filter out invalid names.
1170 1268 */
1171 1269 if ((major = ddi_name_to_major(drv)) == (major_t)-1)
1172 1270 return (ENOENT);
1173 1271
1174 1272 phy_dev = makedevice(major, DLS_PPA2MINOR(ppa));
1175 1273 if (softmac_hold_device(phy_dev, &ddh) != 0)
1176 1274 return (ENOENT);
1177 1275
1178 1276 /*
1179 1277 * At this time, the MAC should be registered, check its phy_dev using
1180 1278 * the given name.
1181 1279 */
1182 1280 if ((err = dls_mgmt_get_linkid(link, &linkid)) != 0 ||
1183 1281 (err = dls_mgmt_get_phydev(linkid, &tmp_dev)) != 0) {
1184 1282 softmac_rele_device(ddh);
1185 1283 return (err);
1186 1284 }
1187 1285 if (tmp_dev != phy_dev) {
1188 1286 softmac_rele_device(ddh);
1189 1287 return (ENOENT);
1190 1288 }
1191 1289
1192 1290 err = dls_devnet_hold(linkid, ddpp);
1193 1291 softmac_rele_device(ddh);
1194 1292 return (err);
1195 1293 }
1196 1294
1197 1295 int
1198 1296 dls_devnet_macname2linkid(const char *macname, datalink_id_t *linkidp)
1199 1297 {
1200 1298 dls_devnet_t *ddp;
1201 1299
1202 1300 rw_enter(&i_dls_devnet_lock, RW_READER);
1203 1301 if (mod_hash_find(i_dls_devnet_hash, (mod_hash_key_t)macname,
1204 1302 (mod_hash_val_t *)&ddp) != 0) {
1205 1303 rw_exit(&i_dls_devnet_lock);
1206 1304 return (ENOENT);
1207 1305 }
1208 1306
1209 1307 *linkidp = ddp->dd_linkid;
1210 1308 rw_exit(&i_dls_devnet_lock);
1211 1309 return (0);
1212 1310 }
1213 1311
1214 1312 /*
1215 1313 * Get linkid for the given dev.
1216 1314 */
1217 1315 int
1218 1316 dls_devnet_dev2linkid(dev_t dev, datalink_id_t *linkidp)
1219 1317 {
1220 1318 char macname[MAXNAMELEN];
1221 1319 char *drv;
1222 1320
1223 1321 if ((drv = ddi_major_to_name(getmajor(dev))) == NULL)
1224 1322 return (EINVAL);
1225 1323
1226 1324 (void) snprintf(macname, sizeof (macname), "%s%d", drv,
1227 1325 DLS_MINOR2INST(getminor(dev)));
1228 1326 return (dls_devnet_macname2linkid(macname, linkidp));
1229 1327 }
1230 1328
1231 1329 /*
1232 1330 * Get the link's physical dev_t. It this is a VLAN, get the dev_t of the
1233 1331 * link this VLAN is created on.
1234 1332 */
1235 1333 int
1236 1334 dls_devnet_phydev(datalink_id_t vlanid, dev_t *devp)
1237 1335 {
1238 1336 dls_devnet_t *ddp;
1239 1337 int err;
1240 1338
1241 1339 if ((err = dls_devnet_hold_tmp(vlanid, &ddp)) != 0)
1242 1340 return (err);
1243 1341
1244 1342 err = dls_mgmt_get_phydev(ddp->dd_linkid, devp);
1245 1343 dls_devnet_rele_tmp(ddp);
1246 1344 return (err);
1247 1345 }
1248 1346
1249 1347 /*
1250 1348 * Handle the renaming requests. There are two rename cases:
1251 1349 *
1252 1350 * 1. Request to rename a valid link (id1) to an non-existent link name
1253 1351 * (id2). In this case id2 is DATALINK_INVALID_LINKID. Just check whether
|
↓ open down ↓ |
278 lines elided |
↑ open up ↑ |
1254 1352 * id1 is held by any applications.
1255 1353 *
1256 1354 * In this case, the link's kstats need to be updated using the given name.
1257 1355 *
1258 1356 * 2. Request to rename a valid link (id1) to the name of a REMOVED
1259 1357 * physical link (id2). In this case, check that id1 and its associated
1260 1358 * mac is not held by any application, and update the link's linkid to id2.
1261 1359 *
1262 1360 * This case does not change the <link name, linkid> mapping, so the link's
1263 1361 * kstats need to be updated with using name associated the given id2.
1362 + *
1363 + * The zonename parameter is used to allow us to create a VNIC in the global
1364 + * zone which is assigned to a non-global zone. Since there is a race condition
1365 + * in the create process if two VNICs have the same name, we need to rename it
1366 + * after it has been assigned to the zone.
1264 1367 */
1265 1368 int
1266 -dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link)
1369 +dls_devnet_rename(datalink_id_t id1, datalink_id_t id2, const char *link,
1370 + boolean_t zoneinit)
1267 1371 {
1268 1372 dls_dev_handle_t ddh = NULL;
1269 1373 int err = 0;
1270 1374 dev_t phydev = 0;
1271 1375 dls_devnet_t *ddp;
1272 1376 mac_perim_handle_t mph = NULL;
1273 1377 mac_handle_t mh;
1274 1378 mod_hash_val_t val;
1275 1379 boolean_t clear_dd_flag = B_FALSE;
1276 1380
1277 1381 /*
1278 1382 * In the second case, id2 must be a REMOVED physical link.
1279 1383 */
1280 1384 if ((id2 != DATALINK_INVALID_LINKID) &&
1281 1385 (dls_mgmt_get_phydev(id2, &phydev) == 0) &&
1282 1386 softmac_hold_device(phydev, &ddh) == 0) {
1283 1387 softmac_rele_device(ddh);
1284 1388 return (EEXIST);
1285 1389 }
1286 1390
1287 1391 /*
1288 1392 * Hold id1 to prevent it from being detached (if a physical link).
1289 1393 */
1290 1394 if (dls_mgmt_get_phydev(id1, &phydev) == 0)
1291 1395 (void) softmac_hold_device(phydev, &ddh);
1292 1396
1293 1397 /*
1294 1398 * The framework does not hold hold locks across calls to the
1295 1399 * mac perimeter, hence enter the perimeter first. This also waits
1296 1400 * for the property loading to finish.
1297 1401 */
1298 1402 if ((err = mac_perim_enter_by_linkid(id1, &mph)) != 0) {
1299 1403 softmac_rele_device(ddh);
1300 1404 return (err);
1301 1405 }
1302 1406
1303 1407 rw_enter(&i_dls_devnet_lock, RW_WRITER);
1304 1408 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1305 1409 (mod_hash_key_t)(uintptr_t)id1, (mod_hash_val_t *)&ddp)) != 0) {
|
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
1306 1410 ASSERT(err == MH_ERR_NOTFOUND);
1307 1411 err = ENOENT;
1308 1412 goto done;
1309 1413 }
1310 1414
1311 1415 /*
1312 1416 * Return EBUSY if any applications have this link open, if any thread
1313 1417 * is currently accessing the link kstats, or if the link is on-loan
1314 1418 * to a non-global zone. Then set the DD_KSTAT_CHANGING flag to
1315 1419 * prevent any access to the kstats while we delete and recreate
1316 - * kstats below.
1420 + * kstats below. However, we skip this check if we're renaming the
1421 + * vnic as part of bringing it up for a zone.
1317 1422 */
1318 1423 mutex_enter(&ddp->dd_mutex);
1319 - if (ddp->dd_ref > 1) {
1320 - mutex_exit(&ddp->dd_mutex);
1321 - err = EBUSY;
1322 - goto done;
1424 + if (!zoneinit) {
1425 + if (ddp->dd_ref > 1) {
1426 + mutex_exit(&ddp->dd_mutex);
1427 + err = EBUSY;
1428 + goto done;
1429 + }
1323 1430 }
1324 1431
1325 1432 ddp->dd_flags |= DD_KSTAT_CHANGING;
1326 1433 clear_dd_flag = B_TRUE;
1327 1434 mutex_exit(&ddp->dd_mutex);
1328 1435
1329 1436 if (id2 == DATALINK_INVALID_LINKID) {
1330 1437 (void) strlcpy(ddp->dd_linkname, link,
1331 1438 sizeof (ddp->dd_linkname));
1332 1439
1333 1440 /* rename mac client name and its flow if exists */
1334 1441 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1335 1442 goto done;
1336 - (void) mac_rename_primary(mh, link);
1443 + if (zoneinit) {
1444 + char tname[MAXLINKNAMELEN];
1445 +
1446 + (void) snprintf(tname, sizeof (tname), "z%d_%s",
1447 + ddp->dd_zid, link);
1448 + (void) mac_rename_primary(mh, tname);
1449 + } else {
1450 + (void) mac_rename_primary(mh, link);
1451 + }
1337 1452 mac_close(mh);
1338 1453 goto done;
1339 1454 }
1340 1455
1341 1456 /*
1342 1457 * The second case, check whether the MAC is used by any MAC
1343 1458 * user. This must be a physical link so ddh must not be NULL.
1344 1459 */
1345 1460 if (ddh == NULL) {
1346 1461 err = EINVAL;
1347 1462 goto done;
1348 1463 }
1349 1464
1350 1465 if ((err = mac_open(ddp->dd_mac, &mh)) != 0)
1351 1466 goto done;
1352 1467
1353 1468 /*
1354 1469 * We release the reference of the MAC which mac_open() is
1355 1470 * holding. Note that this mac will not be unregistered
1356 1471 * because the physical device is held.
1357 1472 */
1358 1473 mac_close(mh);
1359 1474
1360 1475 /*
1361 1476 * Check if there is any other MAC clients, if not, hold this mac
1362 1477 * exclusively until we are done.
1363 1478 */
1364 1479 if ((err = mac_mark_exclusive(mh)) != 0)
1365 1480 goto done;
1366 1481
1367 1482 /*
1368 1483 * Update the link's linkid.
1369 1484 */
1370 1485 if ((err = mod_hash_find(i_dls_devnet_id_hash,
1371 1486 (mod_hash_key_t)(uintptr_t)id2, &val)) != MH_ERR_NOTFOUND) {
1372 1487 mac_unmark_exclusive(mh);
1373 1488 err = EEXIST;
1374 1489 goto done;
1375 1490 }
1376 1491
1377 1492 err = dls_mgmt_get_linkinfo(id2, ddp->dd_linkname, NULL, NULL, NULL);
1378 1493 if (err != 0) {
1379 1494 mac_unmark_exclusive(mh);
1380 1495 goto done;
1381 1496 }
1382 1497
1383 1498 (void) mod_hash_remove(i_dls_devnet_id_hash,
1384 1499 (mod_hash_key_t)(uintptr_t)id1, &val);
1385 1500
1386 1501 ddp->dd_linkid = id2;
1387 1502 (void) mod_hash_insert(i_dls_devnet_id_hash,
1388 1503 (mod_hash_key_t)(uintptr_t)ddp->dd_linkid, (mod_hash_val_t)ddp);
1389 1504
1390 1505 mac_unmark_exclusive(mh);
1391 1506
1392 1507 /* load properties for new id */
1393 1508 mutex_enter(&ddp->dd_mutex);
1394 1509 ddp->dd_prop_loaded = B_FALSE;
1395 1510 ddp->dd_prop_taskid = taskq_dispatch(system_taskq,
1396 1511 dls_devnet_prop_task, ddp, TQ_SLEEP);
1397 1512 mutex_exit(&ddp->dd_mutex);
1398 1513
|
↓ open down ↓ |
52 lines elided |
↑ open up ↑ |
1399 1514 done:
1400 1515 /*
1401 1516 * Change the name of the kstat based on the new link name.
1402 1517 * We can't hold the i_dls_devnet_lock across calls to the kstat
1403 1518 * subsystem. Instead the DD_KSTAT_CHANGING flag set above in this
1404 1519 * function prevents any access to the dd_ksp while we delete and
1405 1520 * recreate it below.
1406 1521 */
1407 1522 rw_exit(&i_dls_devnet_lock);
1408 1523 if (err == 0)
1409 - dls_devnet_stat_rename(ddp);
1524 + dls_devnet_stat_rename(ddp, zoneinit);
1410 1525
1411 1526 if (clear_dd_flag) {
1412 1527 mutex_enter(&ddp->dd_mutex);
1413 1528 ddp->dd_flags &= ~DD_KSTAT_CHANGING;
1414 1529 mutex_exit(&ddp->dd_mutex);
1415 1530 }
1416 1531
1417 1532 if (mph != NULL)
1418 1533 mac_perim_exit(mph);
1419 1534 softmac_rele_device(ddh);
1420 1535 return (err);
1421 1536 }
1422 1537
1423 1538 static int
1424 -i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop)
1539 +i_dls_devnet_setzid(dls_devnet_t *ddp, zoneid_t new_zoneid, boolean_t setprop,
1540 + boolean_t transient)
1425 1541 {
1426 1542 int err;
1427 1543 mac_perim_handle_t mph;
1428 1544 boolean_t upcall_done = B_FALSE;
1429 1545 datalink_id_t linkid = ddp->dd_linkid;
1430 1546 zoneid_t old_zoneid = ddp->dd_zid;
1431 1547 dlmgmt_door_setzoneid_t setzid;
1432 1548 dlmgmt_setzoneid_retval_t retval;
1433 1549
1434 1550 if (old_zoneid == new_zoneid)
1435 1551 return (0);
1436 1552
1437 1553 if ((err = mac_perim_enter_by_macname(ddp->dd_mac, &mph)) != 0)
1438 1554 return (err);
1439 1555
1440 1556 /*
1441 1557 * When changing the zoneid of an existing link, we need to tell
1442 1558 * dlmgmtd about it. dlmgmtd already knows the zoneid associated with
1443 1559 * newly created links.
1444 1560 */
1445 1561 if (setprop) {
1446 1562 setzid.ld_cmd = DLMGMT_CMD_SETZONEID;
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
1447 1563 setzid.ld_linkid = linkid;
1448 1564 setzid.ld_zoneid = new_zoneid;
1449 1565 err = i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1450 1566 sizeof (retval));
1451 1567 if (err != 0)
1452 1568 goto done;
1453 1569 upcall_done = B_TRUE;
1454 1570 }
1455 1571 if ((err = dls_link_setzid(ddp->dd_mac, new_zoneid)) == 0) {
1456 1572 ddp->dd_zid = new_zoneid;
1573 + ddp->dd_transient = transient;
1457 1574 devnet_need_rebuild = B_TRUE;
1458 1575 }
1459 1576
1460 1577 done:
1461 1578 if (err != 0 && upcall_done) {
1462 1579 setzid.ld_zoneid = old_zoneid;
1463 1580 (void) i_dls_mgmt_upcall(&setzid, sizeof (setzid), &retval,
1464 1581 sizeof (retval));
1465 1582 }
1466 1583 mac_perim_exit(mph);
1467 1584 return (err);
1468 1585 }
1469 1586
1470 1587 int
1471 -dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid)
1588 +dls_devnet_setzid(dls_dl_handle_t ddh, zoneid_t new_zid, boolean_t transient)
1472 1589 {
1473 1590 dls_devnet_t *ddp;
1474 1591 int err;
1475 1592 zoneid_t old_zid;
1476 1593 boolean_t refheld = B_FALSE;
1477 1594
1478 1595 old_zid = ddh->dd_zid;
1479 1596
1480 1597 if (old_zid == new_zid)
1481 1598 return (0);
1482 1599
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
1483 1600 /*
1484 1601 * Acquire an additional reference to the link if it is being assigned
1485 1602 * to a non-global zone from the global zone.
1486 1603 */
1487 1604 if (old_zid == GLOBAL_ZONEID && new_zid != GLOBAL_ZONEID) {
1488 1605 if ((err = dls_devnet_hold(ddh->dd_linkid, &ddp)) != 0)
1489 1606 return (err);
1490 1607 refheld = B_TRUE;
1491 1608 }
1492 1609
1493 - if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE)) != 0) {
1610 + if ((err = i_dls_devnet_setzid(ddh, new_zid, B_TRUE, transient)) != 0) {
1494 1611 if (refheld)
1495 1612 dls_devnet_rele(ddp);
1496 1613 return (err);
1497 1614 }
1498 1615
1499 1616 /*
1500 1617 * Release the additional reference if the link is returning to the
1501 1618 * global zone from a non-global zone.
1502 1619 */
1503 1620 if (old_zid != GLOBAL_ZONEID && new_zid == GLOBAL_ZONEID)
1504 1621 dls_devnet_rele(ddh);
1505 1622
1506 1623 /* Re-create kstats in the appropriate zones. */
1507 1624 if (old_zid != GLOBAL_ZONEID)
1508 1625 dls_devnet_stat_destroy(ddh, old_zid);
1509 1626 if (new_zid != GLOBAL_ZONEID)
1510 - dls_devnet_stat_create(ddh, new_zid);
1627 + dls_devnet_stat_create(ddh, new_zid, new_zid);
1511 1628
1512 1629 return (0);
1513 1630 }
1514 1631
1515 1632 zoneid_t
1516 1633 dls_devnet_getzid(dls_dl_handle_t ddh)
1517 1634 {
1518 1635 return (((dls_devnet_t *)ddh)->dd_zid);
1519 1636 }
1520 1637
1521 1638 zoneid_t
1522 1639 dls_devnet_getownerzid(dls_dl_handle_t ddh)
1523 1640 {
1524 1641 return (((dls_devnet_t *)ddh)->dd_owner_zid);
1525 1642 }
1526 1643
1527 1644 /*
1528 1645 * Is linkid visible from zoneid? A link is visible if it was created in the
1529 1646 * zone, or if it is currently assigned to the zone.
1530 1647 */
1531 1648 boolean_t
1532 1649 dls_devnet_islinkvisible(datalink_id_t linkid, zoneid_t zoneid)
1533 1650 {
1534 1651 dls_devnet_t *ddp;
1535 1652 boolean_t result;
1536 1653
1537 1654 if (dls_devnet_hold_tmp(linkid, &ddp) != 0)
1538 1655 return (B_FALSE);
1539 1656 result = (ddp->dd_owner_zid == zoneid || ddp->dd_zid == zoneid);
1540 1657 dls_devnet_rele_tmp(ddp);
1541 1658 return (result);
1542 1659 }
1543 1660
1544 1661 /*
1545 1662 * Access a vanity naming node.
1546 1663 */
1547 1664 int
1548 1665 dls_devnet_open(const char *link, dls_dl_handle_t *dhp, dev_t *devp)
1549 1666 {
1550 1667 dls_devnet_t *ddp;
1551 1668 dls_link_t *dlp;
1552 1669 zoneid_t zid = getzoneid();
1553 1670 int err;
1554 1671 mac_perim_handle_t mph;
1555 1672
1556 1673 if ((err = dls_devnet_hold_by_name(link, &ddp)) != 0)
1557 1674 return (err);
1558 1675
1559 1676 dls_devnet_prop_task_wait(ddp);
1560 1677
1561 1678 /*
1562 1679 * Opening a link that does not belong to the current non-global zone
1563 1680 * is not allowed.
1564 1681 */
1565 1682 if (zid != GLOBAL_ZONEID && ddp->dd_zid != zid) {
1566 1683 dls_devnet_rele(ddp);
1567 1684 return (ENOENT);
1568 1685 }
1569 1686
1570 1687 err = mac_perim_enter_by_macname(ddp->dd_mac, &mph);
1571 1688 if (err != 0) {
1572 1689 dls_devnet_rele(ddp);
1573 1690 return (err);
1574 1691 }
1575 1692
1576 1693 err = dls_link_hold_create(ddp->dd_mac, &dlp);
1577 1694 mac_perim_exit(mph);
1578 1695
1579 1696 if (err != 0) {
1580 1697 dls_devnet_rele(ddp);
1581 1698 return (err);
1582 1699 }
1583 1700
1584 1701 *dhp = ddp;
1585 1702 *devp = dls_link_dev(dlp);
1586 1703 return (0);
1587 1704 }
1588 1705
1589 1706 /*
1590 1707 * Close access to a vanity naming node.
1591 1708 */
1592 1709 void
1593 1710 dls_devnet_close(dls_dl_handle_t dlh)
1594 1711 {
1595 1712 dls_devnet_t *ddp = dlh;
1596 1713 dls_link_t *dlp;
1597 1714 mac_perim_handle_t mph;
1598 1715
1599 1716 VERIFY(mac_perim_enter_by_macname(ddp->dd_mac, &mph) == 0);
1600 1717 VERIFY(dls_link_hold(ddp->dd_mac, &dlp) == 0);
1601 1718
1602 1719 /*
1603 1720 * One rele for the hold placed in dls_devnet_open, another for
1604 1721 * the hold done just above
1605 1722 */
1606 1723 dls_link_rele(dlp);
1607 1724 dls_link_rele(dlp);
1608 1725 mac_perim_exit(mph);
1609 1726
1610 1727 dls_devnet_rele(ddp);
1611 1728 }
1612 1729
1613 1730 /*
1614 1731 * This is used by /dev/net to rebuild the nodes for readdir(). It is not
1615 1732 * critical and no protection is needed.
1616 1733 */
1617 1734 boolean_t
1618 1735 dls_devnet_rebuild()
1619 1736 {
1620 1737 boolean_t updated = devnet_need_rebuild;
1621 1738
1622 1739 devnet_need_rebuild = B_FALSE;
1623 1740 return (updated);
1624 1741 }
1625 1742
1626 1743 int
1627 1744 dls_devnet_create(mac_handle_t mh, datalink_id_t linkid, zoneid_t zoneid)
1628 1745 {
1629 1746 dls_link_t *dlp;
1630 1747 dls_devnet_t *ddp;
1631 1748 int err;
1632 1749 mac_perim_handle_t mph;
1633 1750
1634 1751 /*
1635 1752 * Holding the mac perimeter ensures that the downcall from the
1636 1753 * dlmgmt daemon which does the property loading does not proceed
1637 1754 * until we relinquish the perimeter.
1638 1755 */
1639 1756 mac_perim_enter_by_mh(mh, &mph);
1640 1757 /*
1641 1758 * Make this association before we call dls_link_hold_create as
1642 1759 * we need to use the linkid to get the user name for the link
1643 1760 * when we create the MAC client.
1644 1761 */
1645 1762 if ((err = dls_devnet_set(mac_name(mh), linkid, zoneid, &ddp)) == 0) {
1646 1763 if ((err = dls_link_hold_create(mac_name(mh), &dlp)) != 0) {
1647 1764 mac_perim_exit(mph);
1648 1765 (void) dls_devnet_unset(mac_name(mh), &linkid, B_TRUE);
1649 1766 return (err);
1650 1767 }
1651 1768 }
1652 1769 mac_perim_exit(mph);
1653 1770 return (err);
1654 1771 }
1655 1772
1656 1773 /*
1657 1774 * Set the linkid of the dls_devnet_t and add it into the i_dls_devnet_id_hash.
1658 1775 * This is called in the case that the dlmgmtd daemon is started later than
1659 1776 * the physical devices get attached, and the linkid is only known after the
1660 1777 * daemon starts.
1661 1778 */
1662 1779 int
1663 1780 dls_devnet_recreate(mac_handle_t mh, datalink_id_t linkid)
1664 1781 {
1665 1782 ASSERT(linkid != DATALINK_INVALID_LINKID);
1666 1783 return (dls_devnet_set(mac_name(mh), linkid, GLOBAL_ZONEID, NULL));
1667 1784 }
1668 1785
1669 1786 int
1670 1787 dls_devnet_destroy(mac_handle_t mh, datalink_id_t *idp, boolean_t wait)
1671 1788 {
1672 1789 int err;
1673 1790 mac_perim_handle_t mph;
1674 1791
1675 1792 *idp = DATALINK_INVALID_LINKID;
1676 1793 err = dls_devnet_unset(mac_name(mh), idp, wait);
1677 1794 if (err != 0 && err != ENOENT)
1678 1795 return (err);
1679 1796
1680 1797 mac_perim_enter_by_mh(mh, &mph);
1681 1798 err = dls_link_rele_by_name(mac_name(mh));
1682 1799 mac_perim_exit(mph);
1683 1800
1684 1801 if (err != 0) {
1685 1802 /*
1686 1803 * XXX It is a general GLDv3 bug that dls_devnet_set() has to
1687 1804 * be called to re-set the link when destroy fails. The
1688 1805 * zoneid below will be incorrect if this function is ever
1689 1806 * called from kernel context or from a zone other than that
1690 1807 * which initially created the link.
1691 1808 */
1692 1809 (void) dls_devnet_set(mac_name(mh), *idp, crgetzoneid(CRED()),
1693 1810 NULL);
1694 1811 }
1695 1812 return (err);
1696 1813 }
1697 1814
1698 1815 /*
1699 1816 * Implicitly create an IP tunnel link.
1700 1817 */
1701 1818 static int
1702 1819 i_dls_devnet_create_iptun(const char *linkname, const char *drvname,
1703 1820 datalink_id_t *linkid)
1704 1821 {
1705 1822 int err;
1706 1823 iptun_kparams_t ik;
1707 1824 uint32_t media;
1708 1825 netstack_t *ns;
1709 1826 major_t iptun_major;
1710 1827 dev_info_t *iptun_dip;
1711 1828
1712 1829 /* First ensure that the iptun device is attached. */
1713 1830 if ((iptun_major = ddi_name_to_major(IPTUN_DRIVER_NAME)) == (major_t)-1)
1714 1831 return (EINVAL);
1715 1832 if ((iptun_dip = ddi_hold_devi_by_instance(iptun_major, 0, 0)) == NULL)
1716 1833 return (EINVAL);
1717 1834
1718 1835 if (IS_IPV4_TUN(drvname)) {
1719 1836 ik.iptun_kparam_type = IPTUN_TYPE_IPV4;
1720 1837 media = DL_IPV4;
1721 1838 } else if (IS_6TO4_TUN(drvname)) {
1722 1839 ik.iptun_kparam_type = IPTUN_TYPE_6TO4;
1723 1840 media = DL_6TO4;
1724 1841 } else if (IS_IPV6_TUN(drvname)) {
1725 1842 ik.iptun_kparam_type = IPTUN_TYPE_IPV6;
1726 1843 media = DL_IPV6;
1727 1844 }
1728 1845 ik.iptun_kparam_flags = (IPTUN_KPARAM_TYPE | IPTUN_KPARAM_IMPLICIT);
1729 1846
1730 1847 /* Obtain a datalink id for this tunnel. */
1731 1848 err = dls_mgmt_create((char *)linkname, 0, DATALINK_CLASS_IPTUN, media,
1732 1849 B_FALSE, &ik.iptun_kparam_linkid);
1733 1850 if (err != 0) {
1734 1851 ddi_release_devi(iptun_dip);
1735 1852 return (err);
1736 1853 }
1737 1854
1738 1855 ns = netstack_get_current();
1739 1856 err = iptun_create(&ik, CRED());
1740 1857 netstack_rele(ns);
1741 1858
1742 1859 if (err != 0)
1743 1860 VERIFY(dls_mgmt_destroy(ik.iptun_kparam_linkid, B_FALSE) == 0);
1744 1861 else
1745 1862 *linkid = ik.iptun_kparam_linkid;
1746 1863
1747 1864 ddi_release_devi(iptun_dip);
1748 1865 return (err);
1749 1866 }
1750 1867
1751 1868 static int
1752 1869 i_dls_devnet_destroy_iptun(datalink_id_t linkid)
1753 1870 {
1754 1871 int err;
1755 1872
1756 1873 /*
1757 1874 * Note the use of zone_kcred() here as opposed to CRED(). This is
1758 1875 * because the process that does the last close of this /dev/net node
1759 1876 * may not have necessary privileges to delete this IP tunnel, but the
1760 1877 * tunnel must always be implicitly deleted on last close.
1761 1878 */
1762 1879 if ((err = iptun_delete(linkid, zone_kcred())) == 0)
1763 1880 (void) dls_mgmt_destroy(linkid, B_FALSE);
1764 1881 return (err);
1765 1882 }
1766 1883
1767 1884 const char *
1768 1885 dls_devnet_mac(dls_dl_handle_t ddh)
1769 1886 {
1770 1887 return (ddh->dd_mac);
1771 1888 }
1772 1889
1773 1890 datalink_id_t
1774 1891 dls_devnet_linkid(dls_dl_handle_t ddh)
1775 1892 {
1776 1893 return (ddh->dd_linkid);
1777 1894 }
|
↓ open down ↓ |
257 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX