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