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