Print this page
patch tsoome-feedback
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/rcm_daemon/common/vnic_rcm.c
+++ new/usr/src/cmd/rcm_daemon/common/vnic_rcm.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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 /*
26 26 * This RCM module adds support to the RCM framework for VNIC links
27 27 */
28 28
29 29 #include <stdio.h>
30 30 #include <stdlib.h>
31 31 #include <string.h>
32 32 #include <errno.h>
33 33 #include <sys/types.h>
34 34 #include <synch.h>
35 35 #include <assert.h>
36 36 #include <strings.h>
37 37 #include "rcm_module.h"
38 38 #include <libintl.h>
39 39 #include <libdllink.h>
40 40 #include <libdlvnic.h>
41 41 #include <libdlpi.h>
42 42
43 43 /*
44 44 * Definitions
45 45 */
46 46 #ifndef lint
47 47 #define _(x) gettext(x)
48 48 #else
49 49 #define _(x) x
50 50 #endif
51 51
52 52 /* Some generic well-knowns and defaults used in this module */
53 53 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
54 54 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
55 55
56 56 /* VNIC link flags */
57 57 typedef enum {
58 58 VNIC_OFFLINED = 0x1,
59 59 VNIC_CONSUMER_OFFLINED = 0x2,
60 60 VNIC_STALE = 0x4
61 61 } vnic_flag_t;
62 62
63 63 /* link representation */
64 64 typedef struct dl_vnic {
65 65 struct dl_vnic *dlv_next; /* next VNIC on the same link */
66 66 struct dl_vnic *dlv_prev; /* prev VNIC on the same link */
67 67 datalink_id_t dlv_vnic_id;
68 68 vnic_flag_t dlv_flags; /* VNIC link flags */
69 69 } dl_vnic_t;
70 70
71 71 /* VNIC Cache state flags */
72 72 typedef enum {
73 73 CACHE_NODE_STALE = 0x1, /* stale cached data */
74 74 CACHE_NODE_NEW = 0x2, /* new cached nodes */
75 75 CACHE_NODE_OFFLINED = 0x4 /* nodes offlined */
76 76 } cache_node_state_t;
77 77
78 78 /* Network Cache lookup options */
79 79 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
80 80 #define CACHE_REFRESH 0x2 /* refresh cache */
81 81
82 82 /* Cache element */
83 83 typedef struct link_cache {
84 84 struct link_cache *vc_next; /* next cached resource */
85 85 struct link_cache *vc_prev; /* prev cached resource */
86 86 char *vc_resource; /* resource name */
87 87 datalink_id_t vc_linkid; /* linkid */
88 88 dl_vnic_t *vc_vnic; /* VNIC list on this link */
89 89 cache_node_state_t vc_state; /* cache state flags */
90 90 } link_cache_t;
91 91
92 92 /*
93 93 * Global cache for network VNICs
94 94 */
95 95 static link_cache_t cache_head;
96 96 static link_cache_t cache_tail;
97 97 static mutex_t cache_lock;
98 98 static int events_registered = 0;
99 99
100 100 static dladm_handle_t dld_handle = NULL;
101 101
102 102 /*
103 103 * RCM module interface prototypes
104 104 */
105 105 static int vnic_register(rcm_handle_t *);
106 106 static int vnic_unregister(rcm_handle_t *);
107 107 static int vnic_get_info(rcm_handle_t *, char *, id_t, uint_t,
108 108 char **, char **, nvlist_t *, rcm_info_t **);
109 109 static int vnic_suspend(rcm_handle_t *, char *, id_t,
110 110 timespec_t *, uint_t, char **, rcm_info_t **);
111 111 static int vnic_resume(rcm_handle_t *, char *, id_t, uint_t,
112 112 char **, rcm_info_t **);
113 113 static int vnic_offline(rcm_handle_t *, char *, id_t, uint_t,
114 114 char **, rcm_info_t **);
115 115 static int vnic_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
116 116 char **, rcm_info_t **);
117 117 static int vnic_remove(rcm_handle_t *, char *, id_t, uint_t,
118 118 char **, rcm_info_t **);
119 119 static int vnic_notify_event(rcm_handle_t *, char *, id_t, uint_t,
120 120 char **, nvlist_t *, rcm_info_t **);
121 121 static int vnic_configure(rcm_handle_t *, datalink_id_t);
122 122
123 123 /* Module private routines */
124 124 static void cache_free();
125 125 static int cache_update(rcm_handle_t *);
126 126 static void cache_remove(link_cache_t *);
127 127 static void node_free(link_cache_t *);
128 128 static void cache_insert(link_cache_t *);
129 129 static link_cache_t *cache_lookup(rcm_handle_t *, char *, char);
130 130 static int vnic_consumer_offline(rcm_handle_t *, link_cache_t *,
131 131 char **, uint_t, rcm_info_t **);
132 132 static void vnic_consumer_online(rcm_handle_t *, link_cache_t *,
133 133 char **, uint_t, rcm_info_t **);
134 134 static int vnic_offline_vnic(link_cache_t *, uint32_t,
135 135 cache_node_state_t);
136 136 static void vnic_online_vnic(link_cache_t *);
137 137 static char *vnic_usage(link_cache_t *);
138 138 static void vnic_log_err(datalink_id_t, char **, char *);
139 139 static int vnic_consumer_notify(rcm_handle_t *, datalink_id_t,
140 140 char **, uint_t, rcm_info_t **);
141 141
142 142 /* Module-Private data */
143 143 static struct rcm_mod_ops vnic_ops =
144 144 {
145 145 RCM_MOD_OPS_VERSION,
146 146 vnic_register,
147 147 vnic_unregister,
148 148 vnic_get_info,
149 149 vnic_suspend,
150 150 vnic_resume,
151 151 vnic_offline,
152 152 vnic_undo_offline,
153 153 vnic_remove,
154 154 NULL,
155 155 NULL,
156 156 vnic_notify_event
157 157 };
158 158
159 159 /*
160 160 * rcm_mod_init() - Update registrations, and return the ops structure.
161 161 */
162 162 struct rcm_mod_ops *
163 163 rcm_mod_init(void)
164 164 {
165 165 char errmsg[DLADM_STRSIZE];
166 166 dladm_status_t status;
167 167
168 168 rcm_log_message(RCM_TRACE1, "VNIC: mod_init\n");
169 169
170 170 cache_head.vc_next = &cache_tail;
171 171 cache_head.vc_prev = NULL;
172 172 cache_tail.vc_prev = &cache_head;
173 173 cache_tail.vc_next = NULL;
174 174 (void) mutex_init(&cache_lock, 0, NULL);
175 175
176 176 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
177 177 rcm_log_message(RCM_WARNING,
178 178 "VNIC: mod_init failed: cannot open datalink handle: %s\n",
179 179 dladm_status2str(status, errmsg));
180 180 return (NULL);
181 181 }
182 182
183 183 /* Return the ops vectors */
184 184 return (&vnic_ops);
185 185 }
186 186
187 187 /*
188 188 * rcm_mod_info() - Return a string describing this module.
189 189 */
190 190 const char *
191 191 rcm_mod_info(void)
192 192 {
193 193 rcm_log_message(RCM_TRACE1, "VNIC: mod_info\n");
194 194
195 195 return ("VNIC module");
196 196 }
197 197
198 198 /*
199 199 * rcm_mod_fini() - Destroy the network VNIC cache.
200 200 */
201 201 int
202 202 rcm_mod_fini(void)
203 203 {
204 204 rcm_log_message(RCM_TRACE1, "VNIC: mod_fini\n");
205 205
206 206 /*
207 207 * Note that vnic_unregister() does not seem to be called anywhere,
208 208 * therefore we free the cache nodes here. In theory we should call
209 209 * rcm_register_interest() for each node before we free it, the
210 210 * framework does not provide the rcm_handle to allow us to do so.
211 211 */
212 212 cache_free();
213 213 (void) mutex_destroy(&cache_lock);
214 214
215 215 dladm_close(dld_handle);
216 216 return (RCM_SUCCESS);
217 217 }
218 218
219 219 /*
220 220 * vnic_register() - Make sure the cache is properly sync'ed, and its
221 221 * registrations are in order.
222 222 */
223 223 static int
224 224 vnic_register(rcm_handle_t *hd)
225 225 {
226 226 rcm_log_message(RCM_TRACE1, "VNIC: register\n");
227 227
228 228 if (cache_update(hd) < 0)
229 229 return (RCM_FAILURE);
230 230
231 231 /*
232 232 * Need to register interest in all new resources
233 233 * getting attached, so we get attach event notifications
234 234 */
235 235 if (!events_registered) {
236 236 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
237 237 != RCM_SUCCESS) {
238 238 rcm_log_message(RCM_ERROR,
239 239 _("VNIC: failed to register %s\n"),
240 240 RCM_RESOURCE_LINK_NEW);
241 241 return (RCM_FAILURE);
242 242 } else {
243 243 rcm_log_message(RCM_DEBUG, "VNIC: registered %s\n",
244 244 RCM_RESOURCE_LINK_NEW);
245 245 events_registered++;
246 246 }
247 247 }
248 248
249 249 return (RCM_SUCCESS);
250 250 }
251 251
252 252 /*
253 253 * vnic_unregister() - Walk the cache, unregistering all the networks.
254 254 */
255 255 static int
256 256 vnic_unregister(rcm_handle_t *hd)
257 257 {
258 258 link_cache_t *node;
259 259
260 260 rcm_log_message(RCM_TRACE1, "VNIC: unregister\n");
261 261
262 262 /* Walk the cache, unregistering everything */
263 263 (void) mutex_lock(&cache_lock);
264 264 node = cache_head.vc_next;
265 265 while (node != &cache_tail) {
266 266 if (rcm_unregister_interest(hd, node->vc_resource, 0)
267 267 != RCM_SUCCESS) {
268 268 rcm_log_message(RCM_ERROR,
269 269 _("VNIC: failed to unregister %s\n"),
270 270 node->vc_resource);
271 271 (void) mutex_unlock(&cache_lock);
272 272 return (RCM_FAILURE);
273 273 }
274 274 cache_remove(node);
275 275 node_free(node);
276 276 node = cache_head.vc_next;
277 277 }
278 278 (void) mutex_unlock(&cache_lock);
279 279
280 280 /*
281 281 * Unregister interest in all new resources
282 282 */
283 283 if (events_registered) {
284 284 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
285 285 != RCM_SUCCESS) {
286 286 rcm_log_message(RCM_ERROR,
287 287 _("VNIC: failed to unregister %s\n"),
288 288 RCM_RESOURCE_LINK_NEW);
289 289 return (RCM_FAILURE);
290 290 } else {
291 291 rcm_log_message(RCM_DEBUG, "VNIC: unregistered %s\n",
292 292 RCM_RESOURCE_LINK_NEW);
293 293 events_registered--;
294 294 }
295 295 }
296 296
297 297 return (RCM_SUCCESS);
298 298 }
299 299
300 300 /*
301 301 * vnic_offline() - Offline VNICs on a specific node.
302 302 */
303 303 static int
304 304 vnic_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
305 305 char **errorp, rcm_info_t **info)
306 306 {
307 307 link_cache_t *node;
308 308
309 309 rcm_log_message(RCM_TRACE1, "VNIC: offline(%s)\n", rsrc);
310 310
311 311 /* Lock the cache and lookup the resource */
312 312 (void) mutex_lock(&cache_lock);
313 313 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
314 314 if (node == NULL) {
315 315 /* should not happen because the resource is registered. */
316 316 vnic_log_err(DATALINK_INVALID_LINKID, errorp,
317 317 "unrecognized resource");
318 318 (void) mutex_unlock(&cache_lock);
319 319 return (RCM_SUCCESS);
320 320 }
321 321
322 322 /*
323 323 * Inform consumers (IP interfaces) of associated VNICs to be offlined
324 324 */
325 325 if (vnic_consumer_offline(hd, node, errorp, flags, info) ==
326 326 RCM_SUCCESS) {
327 327 rcm_log_message(RCM_DEBUG,
328 328 "VNIC: consumers agreed on offline\n");
329 329 } else {
330 330 vnic_log_err(node->vc_linkid, errorp,
331 331 "consumers failed to offline");
332 332 (void) mutex_unlock(&cache_lock);
333 333 return (RCM_FAILURE);
334 334 }
335 335
336 336 /* Check if it's a query */
337 337 if (flags & RCM_QUERY) {
338 338 rcm_log_message(RCM_TRACE1,
339 339 "VNIC: offline query succeeded(%s)\n", rsrc);
340 340 (void) mutex_unlock(&cache_lock);
341 341 return (RCM_SUCCESS);
342 342 }
343 343
344 344 if (vnic_offline_vnic(node, VNIC_OFFLINED, CACHE_NODE_OFFLINED) !=
345 345 RCM_SUCCESS) {
346 346 vnic_online_vnic(node);
347 347 vnic_log_err(node->vc_linkid, errorp, "offline failed");
348 348 (void) mutex_unlock(&cache_lock);
349 349 return (RCM_FAILURE);
350 350 }
351 351
352 352 rcm_log_message(RCM_TRACE1, "VNIC: Offline succeeded(%s)\n", rsrc);
353 353 (void) mutex_unlock(&cache_lock);
354 354 return (RCM_SUCCESS);
355 355 }
356 356
357 357 /*
358 358 * vnic_undo_offline() - Undo offline of a previously offlined node.
359 359 */
360 360 /*ARGSUSED*/
361 361 static int
362 362 vnic_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
363 363 char **errorp, rcm_info_t **info)
364 364 {
365 365 link_cache_t *node;
366 366
367 367 rcm_log_message(RCM_TRACE1, "VNIC: online(%s)\n", rsrc);
368 368
369 369 (void) mutex_lock(&cache_lock);
370 370 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
371 371 if (node == NULL) {
372 372 vnic_log_err(DATALINK_INVALID_LINKID, errorp, "no such link");
373 373 (void) mutex_unlock(&cache_lock);
374 374 errno = ENOENT;
375 375 return (RCM_FAILURE);
376 376 }
377 377
378 378 /* Check if no attempt should be made to online the link here */
379 379 if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
380 380 vnic_log_err(node->vc_linkid, errorp, "link not offlined");
381 381 (void) mutex_unlock(&cache_lock);
382 382 errno = ENOTSUP;
383 383 return (RCM_SUCCESS);
384 384 }
385 385
386 386 vnic_online_vnic(node);
387 387
388 388 /*
389 389 * Inform IP interfaces on associated VNICs to be onlined
390 390 */
391 391 vnic_consumer_online(hd, node, errorp, flags, info);
392 392
393 393 node->vc_state &= ~CACHE_NODE_OFFLINED;
394 394 rcm_log_message(RCM_TRACE1, "VNIC: online succeeded(%s)\n", rsrc);
395 395 (void) mutex_unlock(&cache_lock);
396 396 return (RCM_SUCCESS);
397 397 }
398 398
399 399 static void
400 400 vnic_online_vnic(link_cache_t *node)
401 401 {
402 402 dl_vnic_t *vnic;
403 403 dladm_status_t status;
404 404 char errmsg[DLADM_STRSIZE];
405 405
406 406 /*
407 407 * Try to bring on all offlined VNICs
408 408 */
409 409 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
410 410 if (!(vnic->dlv_flags & VNIC_OFFLINED))
411 411 continue;
412 412
413 413 if ((status = dladm_vnic_up(dld_handle, vnic->dlv_vnic_id, 0))
414 414 != DLADM_STATUS_OK) {
415 415 /*
416 416 * Print a warning message and continue to online
417 417 * other VNICs.
418 418 */
419 419 rcm_log_message(RCM_WARNING,
420 420 _("VNIC: VNIC online failed (%u): %s\n"),
421 421 vnic->dlv_vnic_id,
422 422 dladm_status2str(status, errmsg));
423 423 } else {
424 424 vnic->dlv_flags &= ~VNIC_OFFLINED;
425 425 }
426 426 }
427 427 }
428 428
429 429 static int
430 430 vnic_offline_vnic(link_cache_t *node, uint32_t flags, cache_node_state_t state)
431 431 {
432 432 dl_vnic_t *vnic;
433 433 dladm_status_t status;
434 434 char errmsg[DLADM_STRSIZE];
435 435
436 436 rcm_log_message(RCM_TRACE2, "VNIC: vnic_offline_vnic (%s %u %u)\n",
437 437 node->vc_resource, flags, state);
438 438
439 439 /*
440 440 * Try to delete all explicit created VNIC
441 441 */
442 442 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
443 443
444 444 if ((status = dladm_vnic_delete(dld_handle, vnic->dlv_vnic_id,
445 445 DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK) {
446 446 rcm_log_message(RCM_WARNING,
447 447 _("VNIC: VNIC offline failed (%u): %s\n"),
448 448 vnic->dlv_vnic_id,
449 449 dladm_status2str(status, errmsg));
450 450 return (RCM_FAILURE);
451 451 } else {
452 452 rcm_log_message(RCM_TRACE1,
453 453 "VNIC: VNIC offline succeeded(%u)\n",
454 454 vnic->dlv_vnic_id);
455 455 vnic->dlv_flags |= flags;
456 456 }
457 457 }
458 458
459 459 node->vc_state |= state;
460 460 return (RCM_SUCCESS);
461 461 }
462 462
463 463 /*
464 464 * vnic_get_info() - Gather usage information for this resource.
465 465 */
466 466 /*ARGSUSED*/
467 467 int
468 468 vnic_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
469 469 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **info)
470 470 {
471 471 link_cache_t *node;
472 472
473 473 rcm_log_message(RCM_TRACE1, "VNIC: get_info(%s)\n", rsrc);
474 474
475 475 (void) mutex_lock(&cache_lock);
476 476 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
477 477 if (node == NULL) {
478 478 rcm_log_message(RCM_INFO,
479 479 _("VNIC: get_info(%s) unrecognized resource\n"), rsrc);
480 480 (void) mutex_unlock(&cache_lock);
481 481 errno = ENOENT;
482 482 return (RCM_FAILURE);
483 483 }
484 484
485 485 *usagep = vnic_usage(node);
486 486 (void) mutex_unlock(&cache_lock);
487 487 if (*usagep == NULL) {
488 488 /* most likely malloc failure */
489 489 rcm_log_message(RCM_ERROR,
490 490 _("VNIC: get_info(%s) malloc failure\n"), rsrc);
491 491 (void) mutex_unlock(&cache_lock);
492 492 errno = ENOMEM;
493 493 return (RCM_FAILURE);
494 494 }
495 495
496 496 /* Set client/role properties */
497 497 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "VNIC");
498 498
499 499 rcm_log_message(RCM_TRACE1, "VNIC: get_info(%s) info = %s\n",
500 500 rsrc, *usagep);
501 501 return (RCM_SUCCESS);
502 502 }
503 503
504 504 /*
505 505 * vnic_suspend() - Nothing to do, always okay
506 506 */
507 507 /*ARGSUSED*/
508 508 static int
509 509 vnic_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
510 510 uint_t flags, char **errorp, rcm_info_t **info)
511 511 {
512 512 rcm_log_message(RCM_TRACE1, "VNIC: suspend(%s)\n", rsrc);
513 513 return (RCM_SUCCESS);
514 514 }
515 515
516 516 /*
517 517 * vnic_resume() - Nothing to do, always okay
518 518 */
519 519 /*ARGSUSED*/
520 520 static int
521 521 vnic_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
522 522 char **errorp, rcm_info_t **info)
523 523 {
524 524 rcm_log_message(RCM_TRACE1, "VNIC: resume(%s)\n", rsrc);
525 525 return (RCM_SUCCESS);
526 526 }
527 527
528 528 /*
529 529 * vnic_consumer_remove()
530 530 *
531 531 * Notify VNIC consumers to remove cache.
532 532 */
533 533 static int
534 534 vnic_consumer_remove(rcm_handle_t *hd, link_cache_t *node, uint_t flags,
535 535 rcm_info_t **info)
536 536 {
537 537 dl_vnic_t *vnic = NULL;
538 538 char rsrc[RCM_LINK_RESOURCE_MAX];
539 539 int ret = RCM_SUCCESS;
540 540
541 541 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_remove (%s)\n",
542 542 node->vc_resource);
543 543
544 544 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
545 545
546 546 /*
547 547 * This will only be called when the offline operation
548 548 * succeeds, so the VNIC consumers must have been offlined
549 549 * at this point.
550 550 */
551 551 assert(vnic->dlv_flags & VNIC_CONSUMER_OFFLINED);
552 552
553 553 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
554 554 RCM_LINK_PREFIX, vnic->dlv_vnic_id);
555 555
556 556 ret = rcm_notify_remove(hd, rsrc, flags, info);
557 557 if (ret != RCM_SUCCESS) {
558 558 rcm_log_message(RCM_WARNING,
559 559 _("VNIC: notify remove failed (%s)\n"), rsrc);
560 560 break;
561 561 }
562 562 }
563 563
564 564 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_remove done\n");
565 565 return (ret);
566 566 }
567 567
568 568 /*
569 569 * vnic_remove() - remove a resource from cache
570 570 */
571 571 /*ARGSUSED*/
572 572 static int
573 573 vnic_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
574 574 char **errorp, rcm_info_t **info)
575 575 {
576 576 link_cache_t *node;
577 577 int rv;
578 578
579 579 rcm_log_message(RCM_TRACE1, "VNIC: remove(%s)\n", rsrc);
580 580
581 581 (void) mutex_lock(&cache_lock);
582 582 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
583 583 if (node == NULL) {
584 584 rcm_log_message(RCM_INFO,
585 585 _("VNIC: remove(%s) unrecognized resource\n"), rsrc);
586 586 (void) mutex_unlock(&cache_lock);
587 587 errno = ENOENT;
588 588 return (RCM_FAILURE);
589 589 }
590 590
591 591 /* remove the cached entry for the resource */
592 592 cache_remove(node);
593 593 (void) mutex_unlock(&cache_lock);
594 594
595 595 rv = vnic_consumer_remove(hd, node, flags, info);
596 596 node_free(node);
597 597 return (rv);
598 598 }
599 599
600 600 /*
601 601 * vnic_notify_event - Project private implementation to receive new resource
602 602 * events. It intercepts all new resource events. If the
603 603 * new resource is a network resource, pass up a notify
604 604 * for it too. The new resource need not be cached, since
605 605 * it is done at register again.
606 606 */
607 607 /*ARGSUSED*/
608 608 static int
609 609 vnic_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
610 610 char **errorp, nvlist_t *nvl, rcm_info_t **info)
611 611 {
612 612 nvpair_t *nvp = NULL;
613 613 datalink_id_t linkid;
614 614 uint64_t id64;
615 615 int rv = RCM_SUCCESS;
616 616
617 617 rcm_log_message(RCM_TRACE1, "VNIC: notify_event(%s)\n", rsrc);
618 618
619 619 if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
620 620 vnic_log_err(DATALINK_INVALID_LINKID, errorp,
621 621 "unrecognized event");
622 622 errno = EINVAL;
623 623 return (RCM_FAILURE);
624 624 }
625 625
626 626 /* Update cache to reflect latest VNICs */
627 627 if (cache_update(hd) < 0) {
628 628 vnic_log_err(DATALINK_INVALID_LINKID, errorp,
629 629 "private Cache update failed");
630 630 return (RCM_FAILURE);
631 631 }
632 632
633 633 /*
634 634 * Try best to recover all configuration.
635 635 */
636 636 rcm_log_message(RCM_DEBUG, "VNIC: process_nvlist\n");
637 637 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
638 638 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
639 639 continue;
640 640
641 641 if (nvpair_value_uint64(nvp, &id64) != 0) {
642 642 vnic_log_err(DATALINK_INVALID_LINKID, errorp,
643 643 "cannot get linkid");
644 644 rv = RCM_FAILURE;
645 645 continue;
646 646 }
647 647
648 648 linkid = (datalink_id_t)id64;
649 649 if (vnic_configure(hd, linkid) != 0) {
650 650 vnic_log_err(linkid, errorp, "configuring failed");
651 651 rv = RCM_FAILURE;
652 652 continue;
653 653 }
654 654
655 655 /* Notify all VNIC consumers */
656 656 if (vnic_consumer_notify(hd, linkid, errorp, flags,
657 657 info) != 0) {
658 658 vnic_log_err(linkid, errorp, "consumer notify failed");
659 659 rv = RCM_FAILURE;
660 660 }
661 661 }
662 662
663 663 rcm_log_message(RCM_TRACE1,
664 664 "VNIC: notify_event: link configuration complete\n");
665 665 return (rv);
666 666 }
667 667
668 668 /*
669 669 * vnic_usage - Determine the usage of a link.
670 670 * The returned buffer is owned by caller, and the caller
671 671 * must free it up when done.
672 672 */
673 673 static char *
674 674 vnic_usage(link_cache_t *node)
675 675 {
676 676 dl_vnic_t *vnic;
677 677 int nvnic;
678 678 char *buf;
679 679 const char *fmt;
680 680 char *sep;
681 681 char errmsg[DLADM_STRSIZE];
682 682 char name[MAXLINKNAMELEN];
683 683 dladm_status_t status;
684 684 size_t bufsz;
685 685
686 686 rcm_log_message(RCM_TRACE2, "VNIC: usage(%s)\n", node->vc_resource);
687 687
688 688 assert(MUTEX_HELD(&cache_lock));
689 689 if ((status = dladm_datalink_id2info(dld_handle, node->vc_linkid, NULL,
690 690 NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
691 691 rcm_log_message(RCM_ERROR,
692 692 _("VNIC: usage(%s) get link name failure(%s)\n"),
693 693 node->vc_resource, dladm_status2str(status, errmsg));
694 694 return (NULL);
695 695 }
696 696
697 697 if (node->vc_state & CACHE_NODE_OFFLINED)
698 698 fmt = _("%1$s offlined");
699 699 else
700 700 fmt = _("%1$s VNICs: ");
701 701
702 702 /* TRANSLATION_NOTE: separator used between VNIC linkids */
703 703 sep = _(", ");
704 704
705 705 nvnic = 0;
706 706 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next)
707 707 nvnic++;
708 708
709 709 /* space for VNICs and separators, plus message */
710 710 bufsz = nvnic * (MAXLINKNAMELEN + strlen(sep)) +
711 711 strlen(fmt) + MAXLINKNAMELEN + 1;
712 712 if ((buf = malloc(bufsz)) == NULL) {
713 713 rcm_log_message(RCM_ERROR,
714 714 _("VNIC: usage(%s) malloc failure(%s)\n"),
715 715 node->vc_resource, strerror(errno));
716 716 return (NULL);
717 717 }
718 718 (void) snprintf(buf, bufsz, fmt, name);
719 719
720 720 if (node->vc_state & CACHE_NODE_OFFLINED) {
721 721 /* Nothing else to do */
722 722 rcm_log_message(RCM_TRACE2, "VNIC: usage (%s) info = %s\n",
723 723 node->vc_resource, buf);
724 724 return (buf);
725 725 }
726 726
727 727 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
728 728 rcm_log_message(RCM_DEBUG, "VNIC:= %u\n", vnic->dlv_vnic_id);
729 729
730 730 if ((status = dladm_datalink_id2info(dld_handle,
731 731 vnic->dlv_vnic_id, NULL, NULL, NULL, name, sizeof (name)))
732 732 != DLADM_STATUS_OK) {
733 733 rcm_log_message(RCM_ERROR,
734 734 _("VNIC: usage(%s) get vnic %u name failure(%s)\n"),
735 735 node->vc_resource, vnic->dlv_vnic_id,
736 736 dladm_status2str(status, errmsg));
737 737 free(buf);
738 738 return (NULL);
739 739 }
740 740
741 741 (void) strlcat(buf, name, bufsz);
742 742 if (vnic->dlv_next != NULL)
743 743 (void) strlcat(buf, sep, bufsz);
744 744 }
745 745
746 746 rcm_log_message(RCM_TRACE2, "VNIC: usage (%s) info = %s\n",
747 747 node->vc_resource, buf);
748 748
749 749 return (buf);
750 750 }
751 751
752 752 /*
753 753 * Cache management routines, all cache management functions should be
754 754 * be called with cache_lock held.
755 755 */
756 756
757 757 /*
758 758 * cache_lookup() - Get a cache node for a resource.
759 759 * Call with cache lock held.
760 760 *
761 761 * This ensures that the cache is consistent with the system state and
762 762 * returns a pointer to the cache element corresponding to the resource.
763 763 */
764 764 static link_cache_t *
765 765 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
766 766 {
767 767 link_cache_t *node;
768 768
769 769 rcm_log_message(RCM_TRACE2, "VNIC: cache lookup(%s)\n", rsrc);
770 770
771 771 assert(MUTEX_HELD(&cache_lock));
772 772 if (options & CACHE_REFRESH) {
773 773 /* drop lock since update locks cache again */
774 774 (void) mutex_unlock(&cache_lock);
775 775 (void) cache_update(hd);
776 776 (void) mutex_lock(&cache_lock);
777 777 }
778 778
779 779 node = cache_head.vc_next;
780 780 for (; node != &cache_tail; node = node->vc_next) {
781 781 if (strcmp(rsrc, node->vc_resource) == 0) {
782 782 rcm_log_message(RCM_TRACE2,
783 783 "VNIC: cache lookup succeeded(%s)\n", rsrc);
784 784 return (node);
785 785 }
786 786 }
787 787 return (NULL);
788 788 }
789 789
790 790 /*
791 791 * node_free - Free a node from the cache
792 792 */
793 793 static void
794 794 node_free(link_cache_t *node)
795 795 {
796 796 dl_vnic_t *vnic, *next;
797 797
798 798 if (node != NULL) {
799 799 free(node->vc_resource);
800 800
801 801 /* free the VNIC list */
802 802 for (vnic = node->vc_vnic; vnic != NULL; vnic = next) {
803 803 next = vnic->dlv_next;
804 804 free(vnic);
805 805 }
806 806 free(node);
807 807 }
808 808 }
809 809
810 810 /*
811 811 * cache_insert - Insert a resource node in cache
812 812 */
813 813 static void
814 814 cache_insert(link_cache_t *node)
815 815 {
816 816 assert(MUTEX_HELD(&cache_lock));
817 817
818 818 /* insert at the head for best performance */
819 819 node->vc_next = cache_head.vc_next;
820 820 node->vc_prev = &cache_head;
821 821
822 822 node->vc_next->vc_prev = node;
823 823 node->vc_prev->vc_next = node;
824 824 }
825 825
826 826 /*
827 827 * cache_remove() - Remove a resource node from cache.
828 828 */
829 829 static void
830 830 cache_remove(link_cache_t *node)
831 831 {
832 832 assert(MUTEX_HELD(&cache_lock));
833 833 node->vc_next->vc_prev = node->vc_prev;
834 834 node->vc_prev->vc_next = node->vc_next;
835 835 node->vc_next = NULL;
836 836 node->vc_prev = NULL;
837 837 }
838 838
839 839 typedef struct vnic_update_arg_s {
840 840 rcm_handle_t *hd;
841 841 int retval;
842 842 } vnic_update_arg_t;
843 843
844 844 /*
845 845 * vnic_update() - Update physical interface properties
846 846 */
847 847 static int
848 848 vnic_update(dladm_handle_t handle, datalink_id_t vnicid, void *arg)
849 849 {
850 850 vnic_update_arg_t *vnic_update_argp = arg;
851 851 rcm_handle_t *hd = vnic_update_argp->hd;
852 852 link_cache_t *node;
853 853 dl_vnic_t *vnic;
854 854 char *rsrc;
855 855 dladm_vnic_attr_t vnic_attr;
856 856 dladm_status_t status;
857 857 char errmsg[DLADM_STRSIZE];
858 858 boolean_t newnode = B_FALSE;
859 859 int ret = -1;
860 860
861 861 rcm_log_message(RCM_TRACE2, "VNIC: vnic_update(%u)\n", vnicid);
862 862
863 863 assert(MUTEX_HELD(&cache_lock));
864 864 status = dladm_vnic_info(handle, vnicid, &vnic_attr, DLADM_OPT_ACTIVE);
865 865 if (status != DLADM_STATUS_OK) {
866 866 rcm_log_message(RCM_TRACE1,
867 867 "VNIC: vnic_update() cannot get vnic information for "
868 868 "%u(%s)\n", vnicid, dladm_status2str(status, errmsg));
869 869 return (DLADM_WALK_CONTINUE);
870 870 }
871 871
872 872 if (vnic_attr.va_link_id == DATALINK_INVALID_LINKID) {
873 873 /*
874 874 * Skip the etherstubs.
875 875 */
876 876 rcm_log_message(RCM_TRACE1,
877 877 "VNIC: vnic_update(): skip the etherstub %u\n", vnicid);
878 878 return (DLADM_WALK_CONTINUE);
879 879 }
880 880
881 881 rsrc = malloc(RCM_LINK_RESOURCE_MAX);
882 882 if (rsrc == NULL) {
883 883 rcm_log_message(RCM_ERROR, _("VNIC: malloc error(%s): %u\n"),
884 884 strerror(errno), vnicid);
885 885 goto done;
886 886 }
887 887
888 888 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
889 889 RCM_LINK_PREFIX, vnic_attr.va_link_id);
890 890
891 891 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
892 892 if (node != NULL) {
893 893 rcm_log_message(RCM_DEBUG,
894 894 "VNIC: %s already registered (vnicid:%d)\n",
895 895 rsrc, vnic_attr.va_vnic_id);
896 896 free(rsrc);
897 897 } else {
898 898 rcm_log_message(RCM_DEBUG,
899 899 "VNIC: %s is a new resource (vnicid:%d)\n",
900 900 rsrc, vnic_attr.va_vnic_id);
901 901 if ((node = calloc(1, sizeof (link_cache_t))) == NULL) {
902 902 free(rsrc);
903 903 rcm_log_message(RCM_ERROR, _("VNIC: calloc: %s\n"),
904 904 strerror(errno));
905 905 goto done;
906 906 }
907 907
908 908 node->vc_resource = rsrc;
909 909 node->vc_vnic = NULL;
910 910 node->vc_linkid = vnic_attr.va_link_id;
911 911 node->vc_state |= CACHE_NODE_NEW;
912 912 newnode = B_TRUE;
913 913 }
914 914
915 915 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
916 916 if (vnic->dlv_vnic_id == vnicid) {
917 917 vnic->dlv_flags &= ~VNIC_STALE;
918 918 break;
919 919 }
920 920 }
921 921
922 922 if (vnic == NULL) {
923 923 if ((vnic = calloc(1, sizeof (dl_vnic_t))) == NULL) {
924 924 rcm_log_message(RCM_ERROR, _("VNIC: malloc: %s\n"),
925 925 strerror(errno));
926 926 if (newnode) {
927 927 free(rsrc);
928 928 free(node);
929 929 }
930 930 goto done;
931 931 }
932 932 vnic->dlv_vnic_id = vnicid;
933 933 vnic->dlv_next = node->vc_vnic;
934 934 vnic->dlv_prev = NULL;
935 935 if (node->vc_vnic != NULL)
936 936 node->vc_vnic->dlv_prev = vnic;
937 937 node->vc_vnic = vnic;
938 938 }
939 939
940 940 node->vc_state &= ~CACHE_NODE_STALE;
941 941
942 942 if (newnode)
943 943 cache_insert(node);
944 944
945 945 rcm_log_message(RCM_TRACE3, "VNIC: vnic_update: succeeded(%u)\n",
946 946 vnicid);
947 947 ret = 0;
948 948 done:
949 949 vnic_update_argp->retval = ret;
950 950 return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
951 951 }
952 952
953 953 /*
954 954 * vnic_update_all() - Determine all VNIC links in the system
955 955 */
956 956 static int
957 957 vnic_update_all(rcm_handle_t *hd)
958 958 {
959 959 vnic_update_arg_t arg = {NULL, 0};
960 960
961 961 rcm_log_message(RCM_TRACE2, "VNIC: vnic_update_all\n");
962 962
963 963 assert(MUTEX_HELD(&cache_lock));
964 964 arg.hd = hd;
965 965 (void) dladm_walk_datalink_id(vnic_update, dld_handle, &arg,
966 966 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
967 967 return (arg.retval);
968 968 }
969 969
970 970 /*
971 971 * cache_update() - Update cache with latest interface info
972 972 */
973 973 static int
974 974 cache_update(rcm_handle_t *hd)
975 975 {
976 976 link_cache_t *node, *nnode;
977 977 dl_vnic_t *vnic;
978 978 int rv;
979 979
980 980 rcm_log_message(RCM_TRACE2, "VNIC: cache_update\n");
981 981
982 982 (void) mutex_lock(&cache_lock);
983 983
984 984 /* first we walk the entire cache, marking each entry stale */
985 985 node = cache_head.vc_next;
986 986 for (; node != &cache_tail; node = node->vc_next) {
987 987 node->vc_state |= CACHE_NODE_STALE;
988 988 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next)
989 989 vnic->dlv_flags |= VNIC_STALE;
990 990 }
991 991
992 992 rv = vnic_update_all(hd);
993 993
994 994 /*
995 995 * Continue to delete all stale nodes from the cache even
996 996 * vnic_update_all() failed. Unregister link that are not offlined
997 997 * and still in cache
998 998 */
999 999 for (node = cache_head.vc_next; node != &cache_tail; node = nnode) {
1000 1000 dl_vnic_t *vnic, *next;
1001 1001
1002 1002 for (vnic = node->vc_vnic; vnic != NULL; vnic = next) {
1003 1003 next = vnic->dlv_next;
1004 1004
1005 1005 /* clear stale VNICs */
1006 1006 if (vnic->dlv_flags & VNIC_STALE) {
1007 1007 if (vnic->dlv_prev != NULL)
1008 1008 vnic->dlv_prev->dlv_next = next;
1009 1009 else
1010 1010 node->vc_vnic = next;
1011 1011
1012 1012 if (next != NULL)
1013 1013 next->dlv_prev = vnic->dlv_prev;
1014 1014 free(vnic);
1015 1015 }
1016 1016 }
1017 1017
1018 1018 nnode = node->vc_next;
1019 1019 if (node->vc_state & CACHE_NODE_STALE) {
1020 1020 (void) rcm_unregister_interest(hd, node->vc_resource,
1021 1021 0);
1022 1022 rcm_log_message(RCM_DEBUG, "VNIC: unregistered %s\n",
1023 1023 node->vc_resource);
1024 1024 assert(node->vc_vnic == NULL);
1025 1025 cache_remove(node);
1026 1026 node_free(node);
1027 1027 continue;
1028 1028 }
1029 1029
1030 1030 if (!(node->vc_state & CACHE_NODE_NEW))
1031 1031 continue;
1032 1032
1033 1033 if (rcm_register_interest(hd, node->vc_resource, 0, NULL) !=
1034 1034 RCM_SUCCESS) {
1035 1035 rcm_log_message(RCM_ERROR,
1036 1036 _("VNIC: failed to register %s\n"),
1037 1037 node->vc_resource);
1038 1038 rv = -1;
1039 1039 } else {
1040 1040 rcm_log_message(RCM_DEBUG, "VNIC: registered %s\n",
1041 1041 node->vc_resource);
1042 1042 node->vc_state &= ~CACHE_NODE_NEW;
1043 1043 }
1044 1044 }
1045 1045
1046 1046 (void) mutex_unlock(&cache_lock);
1047 1047 return (rv);
1048 1048 }
1049 1049
1050 1050 /*
1051 1051 * cache_free() - Empty the cache
1052 1052 */
1053 1053 static void
1054 1054 cache_free()
1055 1055 {
1056 1056 link_cache_t *node;
1057 1057
1058 1058 rcm_log_message(RCM_TRACE2, "VNIC: cache_free\n");
1059 1059
1060 1060 (void) mutex_lock(&cache_lock);
1061 1061 node = cache_head.vc_next;
1062 1062 while (node != &cache_tail) {
1063 1063 cache_remove(node);
1064 1064 node_free(node);
1065 1065 node = cache_head.vc_next;
1066 1066 }
1067 1067 (void) mutex_unlock(&cache_lock);
1068 1068 }
1069 1069
1070 1070 /*
1071 1071 * vnic_log_err() - RCM error log wrapper
1072 1072 */
1073 1073 static void
1074 1074 vnic_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
1075 1075 {
1076 1076 char link[MAXLINKNAMELEN];
1077 1077 char errstr[DLADM_STRSIZE];
1078 1078 dladm_status_t status;
1079 1079 int len;
1080 1080 const char *errfmt;
1081 1081 char *error;
1082 1082
1083 1083 link[0] = '\0';
1084 1084 if (linkid != DATALINK_INVALID_LINKID) {
1085 1085 char rsrc[RCM_LINK_RESOURCE_MAX];
1086 1086
1087 1087 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u",
1088 1088 RCM_LINK_PREFIX, linkid);
1089 1089
1090 1090 rcm_log_message(RCM_ERROR, _("VNIC: %s(%s)\n"), errmsg, rsrc);
1091 1091 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL,
1092 1092 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
1093 1093 rcm_log_message(RCM_WARNING,
1094 1094 _("VNIC: cannot get link name for (%s) %s\n"),
1095 1095 rsrc, dladm_status2str(status, errstr));
1096 1096 }
1097 1097 } else {
1098 1098 rcm_log_message(RCM_ERROR, _("VNIC: %s\n"), errmsg);
1099 1099 }
1100 1100
1101 1101 errfmt = strlen(link) > 0 ? _("VNIC: %s(%s)") : _("VNIC: %s");
1102 1102 len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
1103 1103 if ((error = malloc(len)) != NULL) {
1104 1104 if (strlen(link) > 0)
1105 1105 (void) snprintf(error, len, errfmt, errmsg, link);
1106 1106 else
1107 1107 (void) snprintf(error, len, errfmt, errmsg);
1108 1108 }
1109 1109
1110 1110 if (errorp != NULL)
1111 1111 *errorp = error;
1112 1112 }
1113 1113
1114 1114 /*
1115 1115 * vnic_consumer_online()
1116 1116 *
1117 1117 * Notify online to VNIC consumers.
1118 1118 */
1119 1119 /* ARGSUSED */
1120 1120 static void
1121 1121 vnic_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1122 1122 uint_t flags, rcm_info_t **info)
1123 1123 {
1124 1124 dl_vnic_t *vnic;
1125 1125 char rsrc[RCM_LINK_RESOURCE_MAX];
1126 1126
1127 1127 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_online (%s)\n",
1128 1128 node->vc_resource);
1129 1129
1130 1130 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
1131 1131 if (!(vnic->dlv_flags & VNIC_CONSUMER_OFFLINED))
1132 1132 continue;
1133 1133
1134 1134 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1135 1135 RCM_LINK_PREFIX, vnic->dlv_vnic_id);
1136 1136
1137 1137 if (rcm_notify_online(hd, rsrc, flags, info) == RCM_SUCCESS)
1138 1138 vnic->dlv_flags &= ~VNIC_CONSUMER_OFFLINED;
1139 1139 }
1140 1140
1141 1141 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_online done\n");
1142 1142 }
1143 1143
1144 1144 /*
1145 1145 * vnic_consumer_offline()
1146 1146 *
1147 1147 * Offline VNIC consumers.
1148 1148 */
1149 1149 static int
1150 1150 vnic_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1151 1151 uint_t flags, rcm_info_t **info)
1152 1152 {
1153 1153 dl_vnic_t *vnic;
1154 1154 char rsrc[RCM_LINK_RESOURCE_MAX];
1155 1155 int ret = RCM_SUCCESS;
1156 1156
1157 1157 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_offline (%s)\n",
1158 1158 node->vc_resource);
1159 1159
1160 1160 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
1161 1161 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1162 1162 RCM_LINK_PREFIX, vnic->dlv_vnic_id);
1163 1163
1164 1164 ret = rcm_request_offline(hd, rsrc, flags, info);
1165 1165 if (ret != RCM_SUCCESS)
1166 1166 break;
1167 1167
1168 1168 vnic->dlv_flags |= VNIC_CONSUMER_OFFLINED;
1169 1169 }
1170 1170
1171 1171 if (vnic != NULL)
1172 1172 vnic_consumer_online(hd, node, errorp, flags, info);
1173 1173
1174 1174 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_offline done\n");
1175 1175 return (ret);
1176 1176 }
1177 1177
1178 1178 /*
1179 1179 * Send RCM_RESOURCE_LINK_NEW events to other modules about new VNICs.
1180 1180 * Return 0 on success, -1 on failure.
1181 1181 */
1182 1182 static int
1183 1183 vnic_notify_new_vnic(rcm_handle_t *hd, char *rsrc)
1184 1184 {
1185 1185 link_cache_t *node;
1186 1186 dl_vnic_t *vnic;
1187 1187 nvlist_t *nvl = NULL;
1188 1188 uint64_t id;
1189 1189 int ret = -1;
1190 1190
1191 1191 rcm_log_message(RCM_TRACE2, "VNIC: vnic_notify_new_vnic (%s)\n", rsrc);
1192 1192
1193 1193 (void) mutex_lock(&cache_lock);
1194 1194 if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
1195 1195 (void) mutex_unlock(&cache_lock);
1196 1196 return (0);
1197 1197 }
1198 1198
1199 1199 if (nvlist_alloc(&nvl, 0, 0) != 0) {
1200 1200 (void) mutex_unlock(&cache_lock);
1201 1201 rcm_log_message(RCM_WARNING,
1202 1202 _("VNIC: failed to allocate nvlist\n"));
1203 1203 goto done;
1204 1204 }
1205 1205
1206 1206 for (vnic = node->vc_vnic; vnic != NULL; vnic = vnic->dlv_next) {
1207 1207 rcm_log_message(RCM_TRACE2,
1208 1208 "VNIC: vnic_notify_new_vnic add (%u)\n", vnic->dlv_vnic_id);
1209 1209
1210 1210 id = vnic->dlv_vnic_id;
1211 1211 if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
1212 1212 rcm_log_message(RCM_ERROR,
1213 1213 _("VNIC: failed to construct nvlist\n"));
1214 1214 (void) mutex_unlock(&cache_lock);
1215 1215 goto done;
1216 1216 }
1217 1217 }
1218 1218 (void) mutex_unlock(&cache_lock);
1219 1219
↓ open down ↓ |
1219 lines elided |
↑ open up ↑ |
1220 1220 if (rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW, 0, nvl, NULL) !=
1221 1221 RCM_SUCCESS) {
1222 1222 rcm_log_message(RCM_ERROR,
1223 1223 _("VNIC: failed to notify %s event for %s\n"),
1224 1224 RCM_RESOURCE_LINK_NEW, node->vc_resource);
1225 1225 goto done;
1226 1226 }
1227 1227
1228 1228 ret = 0;
1229 1229 done:
1230 - if (nvl != NULL)
1231 - nvlist_free(nvl);
1230 + nvlist_free(nvl);
1232 1231 return (ret);
1233 1232 }
1234 1233
1235 1234 /*
1236 1235 * vnic_consumer_notify() - Notify consumers of VNICs coming back online.
1237 1236 */
1238 1237 static int
1239 1238 vnic_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
1240 1239 uint_t flags, rcm_info_t **info)
1241 1240 {
1242 1241 char rsrc[RCM_LINK_RESOURCE_MAX];
1243 1242 link_cache_t *node;
1244 1243
1245 1244 /* Check for the interface in the cache */
1246 1245 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX,
1247 1246 linkid);
1248 1247
1249 1248 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_notify(%s)\n", rsrc);
1250 1249
1251 1250 /*
1252 1251 * Inform IP consumers of the new link.
1253 1252 */
1254 1253 if (vnic_notify_new_vnic(hd, rsrc) != 0) {
1255 1254 (void) mutex_lock(&cache_lock);
1256 1255 if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) {
1257 1256 (void) vnic_offline_vnic(node, VNIC_STALE,
1258 1257 CACHE_NODE_STALE);
1259 1258 }
1260 1259 (void) mutex_unlock(&cache_lock);
1261 1260 rcm_log_message(RCM_TRACE2,
1262 1261 "VNIC: vnic_notify_new_vnic failed(%s)\n", rsrc);
1263 1262 return (-1);
1264 1263 }
1265 1264
1266 1265 rcm_log_message(RCM_TRACE2, "VNIC: vnic_consumer_notify succeeded\n");
1267 1266 return (0);
1268 1267 }
1269 1268
1270 1269 typedef struct vnic_up_arg_s {
1271 1270 datalink_id_t linkid;
1272 1271 int retval;
1273 1272 } vnic_up_arg_t;
1274 1273
1275 1274 static int
1276 1275 vnic_up(dladm_handle_t handle, datalink_id_t vnicid, void *arg)
1277 1276 {
1278 1277 vnic_up_arg_t *vnic_up_argp = arg;
1279 1278 dladm_status_t status;
1280 1279 dladm_vnic_attr_t vnic_attr;
1281 1280 char errmsg[DLADM_STRSIZE];
1282 1281
1283 1282 status = dladm_vnic_info(handle, vnicid, &vnic_attr, DLADM_OPT_PERSIST);
1284 1283 if (status != DLADM_STATUS_OK) {
1285 1284 rcm_log_message(RCM_TRACE1,
1286 1285 "VNIC: vnic_up(): cannot get information for VNIC %u "
1287 1286 "(%s)\n", vnicid, dladm_status2str(status, errmsg));
1288 1287 return (DLADM_WALK_CONTINUE);
1289 1288 }
1290 1289
1291 1290 if (vnic_attr.va_link_id != vnic_up_argp->linkid)
1292 1291 return (DLADM_WALK_CONTINUE);
1293 1292
1294 1293 rcm_log_message(RCM_TRACE3, "VNIC: vnic_up(%u)\n", vnicid);
1295 1294 if ((status = dladm_vnic_up(handle, vnicid, 0)) == DLADM_STATUS_OK)
1296 1295 return (DLADM_WALK_CONTINUE);
1297 1296
1298 1297 /*
1299 1298 * Prompt the warning message and continue to UP other VNICs.
1300 1299 */
1301 1300 rcm_log_message(RCM_WARNING,
1302 1301 _("VNIC: VNIC up failed (%u): %s\n"),
1303 1302 vnicid, dladm_status2str(status, errmsg));
1304 1303
1305 1304 vnic_up_argp->retval = -1;
1306 1305 return (DLADM_WALK_CONTINUE);
1307 1306 }
1308 1307
1309 1308 /*
1310 1309 * vnic_configure() - Configure VNICs over a physical link after it attaches
1311 1310 */
1312 1311 static int
1313 1312 vnic_configure(rcm_handle_t *hd, datalink_id_t linkid)
1314 1313 {
1315 1314 char rsrc[RCM_LINK_RESOURCE_MAX];
1316 1315 link_cache_t *node;
1317 1316 vnic_up_arg_t arg = {DATALINK_INVALID_LINKID, 0};
1318 1317
1319 1318 /* Check for the VNICs in the cache */
1320 1319 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
1321 1320
1322 1321 rcm_log_message(RCM_TRACE2, "VNIC: vnic_configure(%s)\n", rsrc);
1323 1322
1324 1323 /* Check if the link is new or was previously offlined */
1325 1324 (void) mutex_lock(&cache_lock);
1326 1325 if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
1327 1326 (!(node->vc_state & CACHE_NODE_OFFLINED))) {
1328 1327 rcm_log_message(RCM_TRACE2,
1329 1328 "VNIC: Skipping configured interface(%s)\n", rsrc);
1330 1329 (void) mutex_unlock(&cache_lock);
1331 1330 return (0);
1332 1331 }
1333 1332 (void) mutex_unlock(&cache_lock);
1334 1333
1335 1334 arg.linkid = linkid;
1336 1335 (void) dladm_walk_datalink_id(vnic_up, dld_handle, &arg,
1337 1336 DATALINK_CLASS_VNIC, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1338 1337
1339 1338 if (arg.retval == 0) {
1340 1339 rcm_log_message(RCM_TRACE2,
1341 1340 "VNIC: vnic_configure succeeded(%s)\n", rsrc);
1342 1341 }
1343 1342 return (arg.retval);
1344 1343 }
↓ open down ↓ |
103 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX