dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / rcm_daemon / common / aggr_rcm.c
blob24859c2781990f4ce1af6e3990bb17d704b180c7
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * This RCM module adds support to the RCM framework for AGGR links
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <alloca.h>
35 #include <sys/types.h>
36 #include <sys/aggr.h>
37 #include <synch.h>
38 #include <assert.h>
39 #include <strings.h>
40 #include "rcm_module.h"
41 #include <libintl.h>
42 #include <libdllink.h>
43 #include <libdlaggr.h>
46 * Definitions
48 #define _(x) gettext(x)
50 /* Some generic well-knowns and defaults used in this module */
51 #define RCM_LINK_PREFIX "SUNW_datalink" /* RCM datalink name prefix */
52 #define RCM_LINK_RESOURCE_MAX (13 + LINKID_STR_WIDTH)
54 /* AGGR link representation */
55 typedef struct dl_aggr {
56 struct dl_aggr *da_next; /* next AGGR on the system */
57 struct dl_aggr *da_prev; /* prev AGGR on the system */
58 boolean_t da_stale; /* AGGR link is stale? */
59 datalink_id_t da_aggrid;
60 datalink_id_t da_lastport;
61 } dl_aggr_t;
63 /* AGGR Cache state flags */
64 typedef enum {
65 CACHE_NODE_STALE = 0x01, /* stale cached data */
66 CACHE_NODE_NEW = 0x02, /* new cached nodes */
67 CACHE_NODE_OFFLINED = 0x04, /* node offlined */
68 CACHE_AGGR_PORT_OFFLINED = 0x08, /* aggr port offlined */
69 CACHE_AGGR_CONSUMER_OFFLINED = 0x10 /* consumers offlined */
70 } cache_node_state_t;
72 /* Network Cache lookup options */
73 #define CACHE_NO_REFRESH 0x1 /* cache refresh not needed */
74 #define CACHE_REFRESH 0x2 /* refresh cache */
77 * Cache element. It is used to keep a list of links on the system and
78 * their associated aggregations.
80 typedef struct link_cache {
81 struct link_cache *vc_next; /* next cached resource */
82 struct link_cache *vc_prev; /* prev cached resource */
83 char *vc_resource; /* resource name */
84 datalink_id_t vc_linkid; /* linkid */
85 dl_aggr_t *vc_aggr; /* AGGR on this link */
86 cache_node_state_t vc_state; /* cache state flags */
87 } link_cache_t;
90 * Global cache for network AGGRs
92 static link_cache_t cache_head;
93 static link_cache_t cache_tail;
94 static mutex_t cache_lock;
95 static dl_aggr_t aggr_head;
96 static dl_aggr_t aggr_tail;
97 static mutex_t aggr_list_lock;
98 static int events_registered = 0;
100 static dladm_handle_t dld_handle = NULL;
103 * RCM module interface prototypes
105 static int aggr_register(rcm_handle_t *);
106 static int aggr_unregister(rcm_handle_t *);
107 static int aggr_get_info(rcm_handle_t *, char *, id_t, uint_t,
108 char **, char **, nvlist_t *, rcm_info_t **);
109 static int aggr_suspend(rcm_handle_t *, char *, id_t,
110 timespec_t *, uint_t, char **, rcm_info_t **);
111 static int aggr_resume(rcm_handle_t *, char *, id_t, uint_t,
112 char **, rcm_info_t **);
113 static int aggr_offline(rcm_handle_t *, char *, id_t, uint_t,
114 char **, rcm_info_t **);
115 static int aggr_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
116 char **, rcm_info_t **);
117 static int aggr_remove(rcm_handle_t *, char *, id_t, uint_t,
118 char **, rcm_info_t **);
119 static int aggr_notify_event(rcm_handle_t *, char *, id_t, uint_t,
120 char **, nvlist_t *, rcm_info_t **);
121 static int aggr_configure_all(rcm_handle_t *, datalink_id_t,
122 boolean_t *);
124 /* Module private routines */
125 static int cache_update(rcm_handle_t *);
126 static void cache_remove(link_cache_t *);
127 static void cache_insert(link_cache_t *);
128 static void node_free(link_cache_t *);
129 static void aggr_list_remove(dl_aggr_t *);
130 static void aggr_list_insert(dl_aggr_t *);
131 static void aggr_list_free();
132 static link_cache_t *cache_lookup(rcm_handle_t *, char *, char);
133 static int aggr_consumer_offline(rcm_handle_t *, link_cache_t *,
134 char **, uint_t, rcm_info_t **);
135 static int aggr_consumer_online(rcm_handle_t *, link_cache_t *,
136 char **, uint_t, rcm_info_t **);
137 static int aggr_offline_port(link_cache_t *, cache_node_state_t);
138 static int aggr_online_port(link_cache_t *, boolean_t *);
139 static char *aggr_usage(link_cache_t *);
140 static void aggr_log_err(datalink_id_t, char **, char *);
141 static int aggr_consumer_notify(rcm_handle_t *, datalink_id_t,
142 char **, uint_t, rcm_info_t **);
144 /* Module-Private data */
145 static struct rcm_mod_ops aggr_ops =
147 RCM_MOD_OPS_VERSION,
148 aggr_register,
149 aggr_unregister,
150 aggr_get_info,
151 aggr_suspend,
152 aggr_resume,
153 aggr_offline,
154 aggr_undo_offline,
155 aggr_remove,
156 NULL,
157 NULL,
158 aggr_notify_event
162 * rcm_mod_init() - Update registrations, and return the ops structure.
164 struct rcm_mod_ops *
165 rcm_mod_init(void)
167 dladm_status_t status;
168 char errmsg[DLADM_STRSIZE];
170 rcm_log_message(RCM_TRACE1, "AGGR: mod_init\n");
172 cache_head.vc_next = &cache_tail;
173 cache_head.vc_prev = NULL;
174 cache_tail.vc_prev = &cache_head;
175 cache_tail.vc_next = NULL;
176 (void) mutex_init(&cache_lock, 0, NULL);
177 aggr_head.da_next = &aggr_tail;
178 aggr_head.da_prev = NULL;
179 aggr_tail.da_prev = &aggr_head;
180 aggr_tail.da_next = NULL;
181 (void) mutex_init(&aggr_list_lock, 0, NULL);
183 if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
184 rcm_log_message(RCM_WARNING,
185 "AGGR: mod_init failed: cannot open datalink handle: %s\n",
186 dladm_status2str(status, errmsg));
187 return (NULL);
190 /* Return the ops vectors */
191 return (&aggr_ops);
195 * rcm_mod_info() - Return a string describing this module.
197 const char *
198 rcm_mod_info(void)
200 rcm_log_message(RCM_TRACE1, "AGGR: mod_info\n");
202 return ("AGGR module version 1.1");
206 * rcm_mod_fini() - Destroy the network AGGR cache.
209 rcm_mod_fini(void)
211 link_cache_t *node;
213 rcm_log_message(RCM_TRACE1, "AGGR: mod_fini\n");
216 * Note that aggr_unregister() does not seem to be called anywhere,
217 * therefore we free the cache nodes here. In theory we should call
218 * rcm_register_interest() for each node before we free it, the
219 * framework does not provide the rcm_handle to allow us to do so.
221 (void) mutex_lock(&cache_lock);
222 node = cache_head.vc_next;
223 while (node != &cache_tail) {
224 cache_remove(node);
225 node_free(node);
226 node = cache_head.vc_next;
228 (void) mutex_unlock(&cache_lock);
229 (void) mutex_destroy(&cache_lock);
231 aggr_list_free();
232 (void) mutex_destroy(&aggr_list_lock);
234 dladm_close(dld_handle);
235 return (RCM_SUCCESS);
239 * aggr_list_insert - Insert an aggr in the global aggr list
241 static void
242 aggr_list_insert(dl_aggr_t *aggr)
244 assert(MUTEX_HELD(&aggr_list_lock));
246 /* insert at the head for best performance */
247 aggr->da_next = aggr_head.da_next;
248 aggr->da_prev = &aggr_head;
250 aggr->da_next->da_prev = aggr;
251 aggr->da_prev->da_next = aggr;
255 * aggr_list_remove - Remove an aggr from the global aggr list
257 static void
258 aggr_list_remove(dl_aggr_t *aggr)
260 assert(MUTEX_HELD(&aggr_list_lock));
261 aggr->da_next->da_prev = aggr->da_prev;
262 aggr->da_prev->da_next = aggr->da_next;
263 aggr->da_next = NULL;
264 aggr->da_prev = NULL;
267 static void
268 aggr_list_free()
270 dl_aggr_t *aggr;
272 (void) mutex_lock(&aggr_list_lock);
273 aggr = aggr_head.da_next;
274 while (aggr != &aggr_tail) {
275 aggr_list_remove(aggr);
276 free(aggr);
277 aggr = aggr_head.da_next;
279 (void) mutex_unlock(&aggr_list_lock);
283 * aggr_register() - Make sure the cache is properly sync'ed, and its
284 * registrations are in order.
286 static int
287 aggr_register(rcm_handle_t *hd)
289 rcm_log_message(RCM_TRACE1, "AGGR: register\n");
291 if (cache_update(hd) < 0)
292 return (RCM_FAILURE);
295 * Need to register interest in all new resources
296 * getting attached, so we get attach event notifications
298 if (!events_registered) {
299 if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
300 != RCM_SUCCESS) {
301 rcm_log_message(RCM_ERROR,
302 _("AGGR: failed to register %s\n"),
303 RCM_RESOURCE_LINK_NEW);
304 return (RCM_FAILURE);
305 } else {
306 rcm_log_message(RCM_DEBUG, "AGGR: registered %s\n",
307 RCM_RESOURCE_LINK_NEW);
308 events_registered++;
312 return (RCM_SUCCESS);
316 * aggr_unregister() - Walk the cache, unregistering all the networks.
318 static int
319 aggr_unregister(rcm_handle_t *hd)
321 link_cache_t *node;
323 rcm_log_message(RCM_TRACE1, "AGGR: unregister\n");
325 /* Walk the cache, unregistering everything */
326 (void) mutex_lock(&cache_lock);
327 node = cache_head.vc_next;
328 while (node != &cache_tail) {
329 if (rcm_unregister_interest(hd, node->vc_resource, 0)
330 != RCM_SUCCESS) {
331 /* unregister failed for whatever reason */
332 rcm_log_message(RCM_ERROR,
333 _("AGGR: failed to unregister %s\n"),
334 node->vc_resource);
335 (void) mutex_unlock(&cache_lock);
336 return (RCM_FAILURE);
338 cache_remove(node);
339 node_free(node);
340 node = cache_head.vc_next;
342 (void) mutex_unlock(&cache_lock);
344 aggr_list_free();
347 * Unregister interest in all new resources
349 if (events_registered) {
350 if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
351 != RCM_SUCCESS) {
352 rcm_log_message(RCM_ERROR,
353 _("AGGR: failed to unregister %s\n"),
354 RCM_RESOURCE_LINK_NEW);
355 return (RCM_FAILURE);
356 } else {
357 rcm_log_message(RCM_DEBUG, "AGGR: unregistered %s\n",
358 RCM_RESOURCE_LINK_NEW);
359 events_registered--;
363 return (RCM_SUCCESS);
367 * aggr_offline() - Offline AGGRs on a specific link.
369 static int
370 aggr_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
371 char **errorp, rcm_info_t **depend_info)
373 link_cache_t *node;
375 rcm_log_message(RCM_TRACE1, "AGGR: offline(%s)\n", rsrc);
377 /* Lock the cache and lookup the resource */
378 (void) mutex_lock(&cache_lock);
379 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
380 if (node == NULL) {
381 /* should not happen because the resource is registered. */
382 aggr_log_err(DATALINK_INVALID_LINKID, errorp,
383 "offline, unrecognized resource");
384 (void) mutex_unlock(&cache_lock);
385 return (RCM_SUCCESS);
389 * If this given link is the only port in the aggregation, inform
390 * VLANs and IP interfaces on associated AGGRs to be offlined
392 if (node->vc_aggr->da_lastport == node->vc_linkid) {
393 if (aggr_consumer_offline(hd, node, errorp, flags,
394 depend_info) == RCM_SUCCESS) {
395 rcm_log_message(RCM_DEBUG,
396 "AGGR: consumers agreed on offline\n");
397 } else {
398 aggr_log_err(node->vc_linkid, errorp,
399 "consumers offline failed");
400 (void) mutex_unlock(&cache_lock);
401 return (RCM_FAILURE);
405 /* Check if it's a query */
406 if (flags & RCM_QUERY) {
407 rcm_log_message(RCM_TRACE1,
408 "AGGR: offline query succeeded(%s)\n", rsrc);
409 (void) mutex_unlock(&cache_lock);
410 return (RCM_SUCCESS);
413 if (aggr_offline_port(node, CACHE_NODE_OFFLINED) != RCM_SUCCESS) {
414 aggr_log_err(node->vc_linkid, errorp, "offline port failed");
415 (void) mutex_unlock(&cache_lock);
416 return (RCM_FAILURE);
419 rcm_log_message(RCM_TRACE1, "AGGR: Offline succeeded(%s)\n", rsrc);
420 (void) mutex_unlock(&cache_lock);
421 return (RCM_SUCCESS);
425 * aggr_undo_offline() - Undo offline of a previously offlined link.
427 /*ARGSUSED*/
428 static int
429 aggr_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
430 char **errorp, rcm_info_t **depend_info)
432 link_cache_t *node;
433 boolean_t up;
435 rcm_log_message(RCM_TRACE1, "AGGR: online(%s)\n", rsrc);
437 (void) mutex_lock(&cache_lock);
438 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
439 if (node == NULL) {
440 aggr_log_err(DATALINK_INVALID_LINKID, errorp,
441 "undo offline, unrecognized resource");
442 (void) mutex_unlock(&cache_lock);
443 errno = ENOENT;
444 return (RCM_FAILURE);
447 /* Check if no attempt should be made to online the link here */
448 if (!(node->vc_state & CACHE_NODE_OFFLINED)) {
449 aggr_log_err(node->vc_linkid, errorp, "resource not offlined");
450 (void) mutex_unlock(&cache_lock);
451 errno = ENOTSUP;
452 return (RCM_SUCCESS);
455 if (aggr_online_port(node, &up) != RCM_SUCCESS) {
456 aggr_log_err(node->vc_linkid, errorp, "online failed");
457 (void) mutex_unlock(&cache_lock);
458 return (RCM_FAILURE);
462 * Inform VLANs and IP interfaces on associated AGGRs to be online
464 if (!up)
465 goto done;
467 if (aggr_consumer_online(hd, node, errorp, flags, depend_info) ==
468 RCM_SUCCESS) {
469 rcm_log_message(RCM_DEBUG, "AGGR: Consumers agree on online");
470 } else {
471 rcm_log_message(RCM_WARNING,
472 _("AGGR: Consumers online failed (%s)\n"), rsrc);
475 done:
476 node->vc_state &= ~CACHE_NODE_OFFLINED;
477 rcm_log_message(RCM_TRACE1, "AGGR: online succeeded(%s)\n", rsrc);
478 (void) mutex_unlock(&cache_lock);
479 return (RCM_SUCCESS);
482 static int
483 aggr_offline_port(link_cache_t *node, cache_node_state_t state)
485 dl_aggr_t *aggr;
486 dladm_status_t status;
487 char errmsg[DLADM_STRSIZE];
488 dladm_aggr_port_attr_db_t port;
490 rcm_log_message(RCM_TRACE2, "AGGR: aggr_offline_port %s\n",
491 node->vc_resource);
493 aggr = node->vc_aggr;
496 * Try to remove the given port from the AGGR or delete the AGGR
498 if (aggr->da_lastport == node->vc_linkid) {
499 rcm_log_message(RCM_TRACE2, "AGGR: delete aggregation %u\n",
500 aggr->da_aggrid);
501 status = dladm_aggr_delete(dld_handle, aggr->da_aggrid,
502 DLADM_OPT_ACTIVE);
503 } else {
504 rcm_log_message(RCM_TRACE2,
505 "AGGR: remove port (%s) from aggregation %u\n",
506 node->vc_resource, aggr->da_aggrid);
507 port.lp_linkid = node->vc_linkid;
508 status = dladm_aggr_remove(dld_handle, aggr->da_aggrid, 1,
509 &port, DLADM_OPT_ACTIVE);
511 if (status != DLADM_STATUS_OK) {
512 rcm_log_message(RCM_WARNING,
513 _("AGGR: AGGR offline port failed (%u): %s\n"),
514 aggr->da_aggrid, dladm_status2str(status, errmsg));
515 return (RCM_FAILURE);
516 } else {
517 rcm_log_message(RCM_TRACE1,
518 "AGGR: AGGR offline port succeeded (%u)\n",
519 aggr->da_aggrid);
520 node->vc_state |= (CACHE_AGGR_PORT_OFFLINED | state);
521 return (RCM_SUCCESS);
525 static int
526 aggr_online_port(link_cache_t *node, boolean_t *up)
528 dl_aggr_t *aggr;
529 dladm_status_t status;
530 char errmsg[DLADM_STRSIZE];
531 dladm_aggr_port_attr_db_t port;
533 rcm_log_message(RCM_TRACE2, "AGGR: aggr_online_port %s\n",
534 node->vc_resource);
536 *up = B_FALSE;
537 if (!(node->vc_state & CACHE_AGGR_PORT_OFFLINED))
538 return (RCM_SUCCESS);
541 * Either add the port into the AGGR or recreate specific AGGR
542 * depending on whether this link is the only port in the aggregation.
544 aggr = node->vc_aggr;
545 if (aggr->da_lastport == node->vc_linkid) {
546 rcm_log_message(RCM_TRACE2, "AGGR: delete aggregation %u\n",
547 aggr->da_aggrid);
548 status = dladm_aggr_up(dld_handle, aggr->da_aggrid);
549 *up = B_TRUE;
550 } else {
551 rcm_log_message(RCM_TRACE2,
552 "AGGR: add port (%s) to aggregation %u\n",
553 node->vc_resource, aggr->da_aggrid);
554 port.lp_linkid = node->vc_linkid;
555 status = dladm_aggr_add(dld_handle, aggr->da_aggrid, 1, &port,
556 DLADM_OPT_ACTIVE);
558 if (status != DLADM_STATUS_OK) {
559 rcm_log_message(RCM_WARNING,
560 _("AGGR: AGGR online failed (%u): %s\n"),
561 aggr->da_aggrid, dladm_status2str(status, errmsg));
562 *up = B_FALSE;
563 return (RCM_FAILURE);
565 node->vc_state &= ~CACHE_AGGR_PORT_OFFLINED;
566 return (RCM_SUCCESS);
570 * aggr_get_info() - Gather usage information for this resource.
572 /*ARGSUSED*/
574 aggr_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
575 char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
577 link_cache_t *node;
579 rcm_log_message(RCM_TRACE1, "AGGR: get_info(%s)\n", rsrc);
581 (void) mutex_lock(&cache_lock);
582 node = cache_lookup(hd, rsrc, CACHE_REFRESH);
583 if (node == NULL) {
584 rcm_log_message(RCM_INFO,
585 _("AGGR: get_info(%s) unrecognized resource\n"), rsrc);
586 (void) mutex_unlock(&cache_lock);
587 errno = ENOENT;
588 return (RCM_FAILURE);
592 * *usagep will be freed by the caller.
594 *usagep = aggr_usage(node);
595 (void) mutex_unlock(&cache_lock);
597 if (*usagep == NULL) {
598 /* most likely malloc failure */
599 rcm_log_message(RCM_ERROR,
600 _("AGGR: get_info(%s) malloc failure\n"), rsrc);
601 (void) mutex_unlock(&cache_lock);
602 errno = ENOMEM;
603 return (RCM_FAILURE);
606 /* Set client/role properties */
607 (void) nvlist_add_string(props, RCM_CLIENT_NAME, "AGGR");
608 rcm_log_message(RCM_TRACE1, "AGGR: get_info(%s) info = %s\n",
609 rsrc, *usagep);
610 return (RCM_SUCCESS);
614 * aggr_suspend() - Nothing to do, always okay
616 /*ARGSUSED*/
617 static int
618 aggr_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
619 uint_t flags, char **errorp, rcm_info_t **depend_info)
621 rcm_log_message(RCM_TRACE1, "AGGR: suspend(%s)\n", rsrc);
622 return (RCM_SUCCESS);
626 * aggr_resume() - Nothing to do, always okay
628 /*ARGSUSED*/
629 static int
630 aggr_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
631 char **errorp, rcm_info_t **depend_info)
633 rcm_log_message(RCM_TRACE1, "AGGR: resume(%s)\n", rsrc);
634 return (RCM_SUCCESS);
638 * aggr_remove() - remove a resource from cache
640 /*ARGSUSED*/
641 static int
642 aggr_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
643 char **errorp, rcm_info_t **depend_info)
645 link_cache_t *node;
646 char *exported;
647 dl_aggr_t *aggr;
648 int rv = RCM_SUCCESS;
650 rcm_log_message(RCM_TRACE1, "AGGR: remove(%s)\n", rsrc);
652 (void) mutex_lock(&cache_lock);
653 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
654 if (node == NULL) {
655 rcm_log_message(RCM_INFO,
656 _("AGGR: remove(%s) unrecognized resource\n"), rsrc);
657 (void) mutex_unlock(&cache_lock);
658 errno = ENOENT;
659 return (RCM_FAILURE);
662 /* remove the cached entry for the resource */
663 cache_remove(node);
664 (void) mutex_unlock(&cache_lock);
667 * If this link is not the only port in the associated aggregation,
668 * the CACHE_AGGR_CONSUMER_OFFLINED flags won't be set.
670 if (node->vc_state & CACHE_AGGR_CONSUMER_OFFLINED) {
671 aggr = node->vc_aggr;
672 exported = alloca(RCM_LINK_RESOURCE_MAX);
673 (void) snprintf(exported, RCM_LINK_RESOURCE_MAX, "%s/%u",
674 RCM_LINK_PREFIX, aggr->da_aggrid);
675 rv = rcm_notify_remove(hd, exported, flags, depend_info);
676 if (rv != RCM_SUCCESS) {
677 rcm_log_message(RCM_WARNING,
678 _("AGGR: failed to notify remove dependent %s\n"),
679 exported);
683 node_free(node);
684 return (rv);
688 * aggr_notify_event - Project private implementation to receive new resource
689 * events. It intercepts all new resource events. If the
690 * new resource is a network resource, pass up a notify
691 * for it too. The new resource need not be cached, since
692 * it is done at register again.
694 /*ARGSUSED*/
695 static int
696 aggr_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
697 char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
699 nvpair_t *nvp = NULL;
700 datalink_id_t linkid;
701 uint64_t id64;
702 boolean_t up;
703 int rv = RCM_SUCCESS;
705 rcm_log_message(RCM_TRACE1, "AGGR: notify_event(%s)\n", rsrc);
707 if (strcmp(rsrc, RCM_RESOURCE_LINK_NEW) != 0) {
708 aggr_log_err(DATALINK_INVALID_LINKID, errorp,
709 "unrecognized event");
710 errno = EINVAL;
711 return (RCM_FAILURE);
714 /* Update cache to reflect latest AGGRs */
715 if (cache_update(hd) < 0) {
716 aggr_log_err(DATALINK_INVALID_LINKID, errorp,
717 "private Cache update failed");
718 return (RCM_FAILURE);
721 /* Process the nvlist for the event */
722 rcm_log_message(RCM_TRACE1, "AGGR: process_nvlist\n");
723 while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
725 if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) != 0)
726 continue;
728 if (nvpair_value_uint64(nvp, &id64) != 0) {
729 aggr_log_err(DATALINK_INVALID_LINKID, errorp,
730 "cannot get linkid");
731 return (RCM_FAILURE);
734 linkid = (datalink_id_t)id64;
735 if (aggr_configure_all(hd, linkid, &up) != 0) {
736 aggr_log_err(linkid, errorp,
737 "failed configuring AGGR links");
738 rv = RCM_FAILURE;
741 /* Notify all VLAN and IP AGGR consumers */
742 if (up && aggr_consumer_notify(hd, linkid, errorp, flags,
743 depend_info) != 0) {
744 aggr_log_err(linkid, errorp, "consumer notify failed");
745 rv = RCM_FAILURE;
749 rcm_log_message(RCM_TRACE1,
750 "AGGR: notify_event: link configuration complete\n");
751 return (rv);
755 * aggr_usage - Determine the usage of a link.
756 * The returned buffer is owned by caller, and the caller
757 * must free it up when done.
759 static char *
760 aggr_usage(link_cache_t *node)
762 char *buf;
763 const char *fmt;
764 char errmsg[DLADM_STRSIZE];
765 char name[MAXLINKNAMELEN];
766 dladm_status_t status;
767 size_t bufsz;
769 rcm_log_message(RCM_TRACE2, "AGGR: usage(%s)\n", node->vc_resource);
770 assert(MUTEX_HELD(&cache_lock));
772 if (node->vc_state & CACHE_NODE_OFFLINED)
773 fmt = _("%s offlined");
774 else
775 fmt = _("%s is part of AGGR ");
777 if ((status = dladm_datalink_id2info(dld_handle, node->vc_linkid, NULL,
778 NULL, NULL, name, sizeof (name))) != DLADM_STATUS_OK) {
779 rcm_log_message(RCM_ERROR,
780 _("AGGR: usage(%s) get port name failure(%s)\n"),
781 node->vc_resource, dladm_status2str(status, errmsg));
782 return (NULL);
785 /* space for resources and message */
786 bufsz = MAXLINKNAMELEN + strlen(fmt) + strlen(name) + 1;
787 if ((buf = malloc(bufsz)) == NULL) {
788 rcm_log_message(RCM_ERROR,
789 _("AGGR: usage(%s) malloc failure(%s)\n"),
790 node->vc_resource, strerror(errno));
791 return (NULL);
793 (void) snprintf(buf, bufsz, fmt, name);
795 if (node->vc_state & CACHE_NODE_OFFLINED) {
796 /* Nothing else to do */
797 rcm_log_message(RCM_TRACE2, "AGGR: usage (%s) info = %s\n",
798 node->vc_resource, buf);
799 return (buf);
802 if ((status = dladm_datalink_id2info(dld_handle,
803 node->vc_aggr->da_aggrid, NULL, NULL, NULL, name,
804 sizeof (name))) != DLADM_STATUS_OK) {
805 rcm_log_message(RCM_ERROR,
806 _("AGGR: usage(%s) get aggr %u name failure(%s)\n"),
807 node->vc_resource, node->vc_aggr->da_aggrid,
808 dladm_status2str(status, errmsg));
809 (void) free(buf);
810 return (NULL);
813 (void) strlcat(buf, name, bufsz);
815 rcm_log_message(RCM_TRACE2, "AGGR: usage (%s) info = %s\n",
816 node->vc_resource, buf);
817 return (buf);
821 * Cache management routines, all cache management functions should be
822 * be called with cache_lock held.
826 * cache_lookup() - Get a cache node for a resource.
827 * Call with cache lock held.
829 * This ensures that the cache is consistent with the system state and
830 * returns a pointer to the cache element corresponding to the resource.
832 static link_cache_t *
833 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
835 link_cache_t *node;
837 rcm_log_message(RCM_TRACE2, "AGGR: cache lookup(%s)\n", rsrc);
838 assert(MUTEX_HELD(&cache_lock));
840 if (options & CACHE_REFRESH) {
841 /* drop lock since update locks cache again */
842 (void) mutex_unlock(&cache_lock);
843 (void) cache_update(hd);
844 (void) mutex_lock(&cache_lock);
847 node = cache_head.vc_next;
848 for (; node != &cache_tail; node = node->vc_next) {
849 if (strcmp(rsrc, node->vc_resource) == 0) {
850 rcm_log_message(RCM_TRACE2,
851 "AGGR: cache lookup succeeded(%s)\n", rsrc);
852 return (node);
855 return (NULL);
859 * node_free - Free a node from the cache
861 static void
862 node_free(link_cache_t *node)
864 free(node->vc_resource);
865 free(node);
869 * cache_insert - Insert a resource node in cache
871 static void
872 cache_insert(link_cache_t *node)
874 assert(MUTEX_HELD(&cache_lock));
876 /* insert at the head for best performance */
877 node->vc_next = cache_head.vc_next;
878 node->vc_prev = &cache_head;
880 node->vc_next->vc_prev = node;
881 node->vc_prev->vc_next = node;
885 * cache_remove() - Remove a resource node from cache.
886 * Call with the cache_lock held.
888 static void
889 cache_remove(link_cache_t *node)
891 assert(MUTEX_HELD(&cache_lock));
892 node->vc_next->vc_prev = node->vc_prev;
893 node->vc_prev->vc_next = node->vc_next;
894 node->vc_next = NULL;
895 node->vc_prev = NULL;
898 static int
899 aggr_port_update(rcm_handle_t *hd, dl_aggr_t *aggr, datalink_id_t portid)
901 link_cache_t *node;
902 char *rsrc;
903 int ret = -1;
905 rcm_log_message(RCM_TRACE1,
906 "AGGR: aggr_port_update aggr:%u port:%u\n",
907 aggr->da_aggrid, portid);
908 assert(MUTEX_HELD(&cache_lock));
910 rsrc = malloc(RCM_LINK_RESOURCE_MAX);
911 if (rsrc == NULL) {
912 rcm_log_message(RCM_ERROR,
913 _("AGGR: resource malloc error(%s)\n"), strerror(errno));
914 goto done;
917 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
918 RCM_LINK_PREFIX, portid);
920 node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
921 if (node != NULL) {
922 rcm_log_message(RCM_DEBUG,
923 "AGGR: %s already registered (aggrid:%u)\n",
924 rsrc, aggr->da_aggrid);
926 free(rsrc);
927 node->vc_state &= ~CACHE_NODE_STALE;
929 assert(node->vc_linkid == portid);
931 * Update vc_aggr directly as only one aggregation can be
932 * created on one port.
934 node->vc_aggr = aggr;
935 } else {
936 rcm_log_message(RCM_DEBUG,
937 "AGGR: %s is a new resource (aggrid:%u)\n",
938 rsrc, aggr->da_aggrid);
940 node = calloc(1, sizeof (link_cache_t));
941 if (node == NULL) {
942 free(rsrc);
943 rcm_log_message(RCM_ERROR,
944 _("AGGR: calloc: %s\n"), strerror(errno));
945 return (ret);
948 node->vc_resource = rsrc;
949 node->vc_aggr = aggr;
950 node->vc_linkid = portid;
951 node->vc_state |= CACHE_NODE_NEW;
954 cache_insert(node);
957 ret = 0;
958 done:
959 return (ret);
962 typedef struct aggr_update_arg_s {
963 rcm_handle_t *hd;
964 int retval;
965 } aggr_update_arg_t;
968 * aggr_update() - Update physical interface properties
970 static int
971 aggr_update(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
973 aggr_update_arg_t *aggr_update_argp = arg;
974 rcm_handle_t *hd = aggr_update_argp->hd;
975 dladm_aggr_grp_attr_t aggr_attr;
976 dl_aggr_t *aggr;
977 dladm_status_t status;
978 char errmsg[DLADM_STRSIZE];
979 boolean_t exist = B_FALSE;
980 uint32_t i;
981 int ret = -1;
983 rcm_log_message(RCM_TRACE1, "AGGR: aggr_update(%u)\n", aggrid);
985 assert(MUTEX_HELD(&aggr_list_lock));
986 status = dladm_aggr_info(handle, aggrid, &aggr_attr,
987 DLADM_OPT_ACTIVE);
988 if (status != DLADM_STATUS_OK) {
989 rcm_log_message(RCM_TRACE1,
990 "AGGR: cannot get aggr information for %u error(%s)\n",
991 aggrid, dladm_status2str(status, errmsg));
992 return (DLADM_WALK_CONTINUE);
996 * Try to find the aggr from the aggr list.
998 for (aggr = aggr_head.da_next; aggr != &aggr_tail; aggr = aggr->da_next)
999 if (aggr->da_aggrid == aggr_attr.lg_linkid)
1000 break;
1002 if (aggr != NULL) {
1003 exist = B_TRUE;
1004 } else {
1005 if ((aggr = calloc(1, sizeof (dl_aggr_t))) == NULL) {
1006 rcm_log_message(RCM_ERROR, _("AGGR: malloc: %s\n"),
1007 strerror(errno));
1008 goto done;
1012 /* Update aggregation information. */
1013 if (aggr_attr.lg_nports == 1)
1014 aggr->da_lastport = aggr_attr.lg_ports[0].lp_linkid;
1015 else
1016 aggr->da_lastport = DATALINK_INVALID_LINKID;
1017 aggr->da_aggrid = aggr_attr.lg_linkid;
1019 for (i = 0; i < aggr_attr.lg_nports; i++) {
1020 datalink_id_t portid = (aggr_attr.lg_ports[i]).lp_linkid;
1022 if (aggr_port_update(hd, aggr, portid) != 0)
1023 goto done;
1026 if (!exist)
1027 aggr_list_insert(aggr);
1029 aggr->da_stale = B_FALSE;
1030 rcm_log_message(RCM_TRACE3,
1031 "AGGR: aggr_update: succeeded(%u)\n", aggrid);
1033 ret = 0;
1034 done:
1035 if (!exist && ret != 0)
1036 free(aggr);
1037 free(aggr_attr.lg_ports);
1038 aggr_update_argp->retval = ret;
1039 return (ret == 0 ? DLADM_WALK_CONTINUE : DLADM_WALK_TERMINATE);
1043 * aggr_update_all() - Determine all AGGR links in the system
1045 static int
1046 aggr_update_all(rcm_handle_t *hd)
1048 aggr_update_arg_t arg = {NULL, 0};
1050 rcm_log_message(RCM_TRACE2, "AGGR: aggr_update_all\n");
1051 assert(MUTEX_HELD(&cache_lock));
1053 arg.hd = hd;
1054 (void) dladm_walk_datalink_id(aggr_update, dld_handle, &arg,
1055 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_ACTIVE);
1056 return (arg.retval);
1060 * cache_update() - Update cache with latest interface info
1062 static int
1063 cache_update(rcm_handle_t *hd)
1065 link_cache_t *node, *next;
1066 dl_aggr_t *aggr;
1067 int ret = 0;
1069 rcm_log_message(RCM_TRACE2, "AGGR: cache_update\n");
1070 (void) mutex_lock(&aggr_list_lock);
1071 (void) mutex_lock(&cache_lock);
1073 /* first we walk the entire aggr list, marking each entry stale */
1074 for (aggr = aggr_head.da_next; aggr != &aggr_tail; aggr = aggr->da_next)
1075 aggr->da_stale = B_TRUE;
1077 /* then we walk the entire cache, marking each entry stale */
1078 node = cache_head.vc_next;
1079 for (; node != &cache_tail; node = node->vc_next)
1080 node->vc_state |= CACHE_NODE_STALE;
1082 ret = aggr_update_all(hd);
1085 * Even aggr_update_all() fails, continue to delete all the stale
1086 * resources. First, unregister links that are not offlined and
1087 * still in cache.
1089 for (node = cache_head.vc_next; node != &cache_tail; node = next) {
1091 next = node->vc_next;
1092 if (node->vc_state & CACHE_NODE_STALE) {
1093 (void) rcm_unregister_interest(hd, node->vc_resource,
1095 rcm_log_message(RCM_DEBUG,
1096 "AGGR: unregistered %s\n", node->vc_resource);
1097 cache_remove(node);
1098 node_free(node);
1099 continue;
1102 if (!(node->vc_state & CACHE_NODE_NEW))
1103 continue;
1105 if (rcm_register_interest(hd, node->vc_resource, 0,
1107 NULL) != RCM_SUCCESS) {
1108 rcm_log_message(RCM_ERROR,
1109 _("AGGR: failed to register %s\n"),
1110 node->vc_resource);
1111 ret = -1;
1112 } else {
1113 rcm_log_message(RCM_DEBUG, "AGGR: registered %s\n",
1114 node->vc_resource);
1116 node->vc_state &= ~CACHE_NODE_NEW;
1120 aggr = aggr_head.da_next;
1121 while (aggr != &aggr_tail) {
1122 dl_aggr_t *next = aggr->da_next;
1124 /* delete stale AGGRs */
1125 if (aggr->da_stale) {
1126 aggr_list_remove(aggr);
1127 free(aggr);
1129 aggr = next;
1132 done:
1133 (void) mutex_unlock(&cache_lock);
1134 (void) mutex_unlock(&aggr_list_lock);
1135 return (ret);
1139 * aggr_log_err() - RCM error log wrapper
1141 static void
1142 aggr_log_err(datalink_id_t linkid, char **errorp, char *errmsg)
1144 char link[MAXLINKNAMELEN];
1145 char errstr[DLADM_STRSIZE];
1146 dladm_status_t status;
1147 int len;
1148 const char *errfmt;
1149 char *error;
1151 link[0] = '\0';
1152 if (linkid != DATALINK_INVALID_LINKID) {
1153 char rsrc[RCM_LINK_RESOURCE_MAX];
1155 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1156 RCM_LINK_PREFIX, linkid);
1158 rcm_log_message(RCM_ERROR, _("AGGR: %s(%s)\n"), errmsg, rsrc);
1160 if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL,
1161 NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
1162 rcm_log_message(RCM_WARNING,
1163 _("AGGR: cannot get link name of (%s) %s\n"),
1164 rsrc, dladm_status2str(status, errstr));
1166 } else {
1167 rcm_log_message(RCM_ERROR, _("AGGR: %s\n"), errmsg);
1170 errfmt = strlen(link) > 0 ? _("AGGR: %s(%s)") : _("AGGR: %s");
1171 len = strlen(errfmt) + strlen(errmsg) + MAXLINKNAMELEN + 1;
1172 if ((error = malloc(len)) != NULL) {
1173 if (strlen(link) > 0)
1174 (void) sprintf(error, errfmt, errmsg, link);
1175 else
1176 (void) sprintf(error, errfmt, errmsg);
1179 if (errorp != NULL)
1180 *errorp = error;
1184 * aggr_consumer_offline()
1186 * Offline AGGR consumers.
1188 static int
1189 aggr_consumer_offline(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1190 uint_t flags, rcm_info_t **depend_info)
1192 char rsrc[RCM_LINK_RESOURCE_MAX];
1193 int ret;
1195 rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_offline %s\n",
1196 node->vc_resource);
1198 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1199 RCM_LINK_PREFIX, node->vc_aggr->da_aggrid);
1202 * Inform associated VLANs and IP interfaces to be offlined
1204 ret = rcm_request_offline(hd, rsrc, flags, depend_info);
1205 if (ret != RCM_SUCCESS) {
1206 rcm_log_message(RCM_DEBUG,
1207 "AGGR: rcm_request_offline failed (%s)\n", rsrc);
1208 return (ret);
1211 node->vc_state |= CACHE_AGGR_CONSUMER_OFFLINED;
1212 rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_offline done\n");
1213 return (ret);
1217 * aggr_consumer_online()
1219 * online AGGR consumers.
1221 static int
1222 aggr_consumer_online(rcm_handle_t *hd, link_cache_t *node, char **errorp,
1223 uint_t flags, rcm_info_t **depend_info)
1225 char rsrc[RCM_LINK_RESOURCE_MAX];
1226 int ret;
1228 rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_online %s\n",
1229 node->vc_resource);
1231 if (!(node->vc_state & CACHE_AGGR_CONSUMER_OFFLINED)) {
1232 rcm_log_message(RCM_DEBUG,
1233 "AGGR: no consumers offlined (%s)\n", node->vc_resource);
1234 return (RCM_SUCCESS);
1237 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1238 RCM_LINK_PREFIX, node->vc_aggr->da_aggrid);
1240 ret = rcm_notify_online(hd, rsrc, flags, depend_info);
1241 if (ret != RCM_SUCCESS) {
1242 rcm_log_message(RCM_DEBUG,
1243 "AGGR: rcm_notify_online failed (%s)\n", rsrc);
1244 return (ret);
1247 node->vc_state &= ~CACHE_AGGR_CONSUMER_OFFLINED;
1248 rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_online done\n");
1249 return (ret);
1253 * Send RCM_RESOURCE_LINK_NEW events to other modules about new aggregations.
1254 * Return 0 on success, -1 on failure.
1256 static int
1257 aggr_notify_new_aggr(rcm_handle_t *hd, char *rsrc)
1259 link_cache_t *node;
1260 dl_aggr_t *aggr;
1261 nvlist_t *nvl = NULL;
1262 uint64_t id;
1263 boolean_t is_only_port;
1264 int ret = -1;
1266 rcm_log_message(RCM_TRACE2, "AGGR: aggr_notify_new_aggr (%s)\n", rsrc);
1268 /* Check for the interface in the cache */
1269 (void) mutex_lock(&cache_lock);
1270 if ((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) == NULL) {
1271 rcm_log_message(RCM_TRACE1,
1272 "AGGR: aggr_notify_new_aggr() unrecognized resource (%s)\n",
1273 rsrc);
1274 (void) mutex_unlock(&cache_lock);
1275 return (0);
1278 if (nvlist_alloc(&nvl, 0, 0) != 0) {
1279 rcm_log_message(RCM_WARNING,
1280 _("AGGR: failed to allocate nvlist\n"));
1281 (void) mutex_unlock(&cache_lock);
1282 goto done;
1285 aggr = node->vc_aggr;
1286 is_only_port = (aggr->da_lastport == node->vc_linkid);
1288 if (is_only_port) {
1289 rcm_log_message(RCM_TRACE2,
1290 "AGGR: aggr_notify_new_aggr add (%u)\n",
1291 aggr->da_aggrid);
1293 id = aggr->da_aggrid;
1294 if (nvlist_add_uint64(nvl, RCM_NV_LINKID, id) != 0) {
1295 rcm_log_message(RCM_ERROR,
1296 _("AGGR: failed to construct nvlist\n"));
1297 (void) mutex_unlock(&cache_lock);
1298 goto done;
1302 (void) mutex_unlock(&cache_lock);
1305 * If this link is not the only port in the aggregation, the aggregation
1306 * is not new. No need to inform other consumers in that case.
1308 if (is_only_port && rcm_notify_event(hd, RCM_RESOURCE_LINK_NEW,
1309 0, nvl, NULL) != RCM_SUCCESS) {
1310 rcm_log_message(RCM_ERROR,
1311 _("AGGR: failed to notify %s event for %s\n"),
1312 RCM_RESOURCE_LINK_NEW, node->vc_resource);
1313 goto done;
1316 ret = 0;
1317 done:
1318 nvlist_free(nvl);
1319 return (ret);
1323 * aggr_consumer_notify() - Notify consumers of AGGRs coming back online.
1325 static int
1326 aggr_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
1327 uint_t flags, rcm_info_t **depend_info)
1329 char rsrc[RCM_LINK_RESOURCE_MAX];
1330 link_cache_t *node;
1332 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u",
1333 RCM_LINK_PREFIX, linkid);
1335 rcm_log_message(RCM_TRACE1, "AGGR: aggr_consumer_notify(%s)\n", rsrc);
1338 * Inform IP and VLAN consumers to be online.
1340 if (aggr_notify_new_aggr(hd, rsrc) != 0) {
1341 (void) mutex_lock(&cache_lock);
1342 if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL)
1343 (void) aggr_offline_port(node, CACHE_NODE_STALE);
1344 (void) mutex_unlock(&cache_lock);
1345 rcm_log_message(RCM_TRACE1,
1346 "AGGR: aggr_notify_new_aggr failed(%s)\n", rsrc);
1347 return (-1);
1350 rcm_log_message(RCM_TRACE2, "AGGR: aggr_consumer_notify succeeded\n");
1351 return (0);
1354 typedef struct aggr_configure_arg {
1355 datalink_id_t portid;
1356 int retval;
1357 boolean_t up;
1358 } aggr_configure_arg_t;
1360 static int
1361 aggr_configure(dladm_handle_t handle, datalink_id_t aggrid, void *arg)
1363 aggr_configure_arg_t *aggr_configure_argp = arg;
1364 datalink_id_t portid;
1365 dladm_aggr_grp_attr_t aggr_attr;
1366 dladm_aggr_port_attr_db_t port_attr;
1367 dladm_status_t status;
1368 uint32_t flags;
1369 char errmsg[DLADM_STRSIZE];
1370 int i;
1372 status = dladm_datalink_id2info(handle, aggrid, &flags, NULL, NULL,
1373 NULL, 0);
1374 if (status != DLADM_STATUS_OK)
1375 return (DLADM_WALK_CONTINUE);
1377 status = dladm_aggr_info(handle, aggrid, &aggr_attr, DLADM_OPT_PERSIST);
1378 if (status != DLADM_STATUS_OK)
1379 return (DLADM_WALK_CONTINUE);
1381 portid = aggr_configure_argp->portid;
1382 for (i = 0; i < aggr_attr.lg_nports; i++)
1383 if (aggr_attr.lg_ports[i].lp_linkid == portid)
1384 break;
1386 if (i == aggr_attr.lg_nports) {
1388 * The aggregation doesn't contain this port.
1390 free(aggr_attr.lg_ports);
1391 return (DLADM_WALK_CONTINUE);
1395 * If this aggregation already exists, add this port to this
1396 * aggregation, otherwise, bring up this aggregation.
1398 if (flags & DLADM_OPT_ACTIVE) {
1399 rcm_log_message(RCM_TRACE3,
1400 "AGGR: aggr_configure dladm_aggr_add port %u (%u)\n",
1401 portid, aggrid);
1402 port_attr.lp_linkid = portid;
1403 status = dladm_aggr_add(handle, aggrid, 1, &port_attr,
1404 DLADM_OPT_ACTIVE);
1405 } else {
1406 rcm_log_message(RCM_TRACE3,
1407 "AGGR: aggr_configure dladm_aggr_up (%u)\n", aggrid);
1408 status = dladm_aggr_up(handle, aggrid);
1411 if (status != DLADM_STATUS_OK) {
1413 * Print a warning message and continue to UP other AGGRs.
1415 rcm_log_message(RCM_WARNING,
1416 _("AGGR: AGGR online failed (%u): %s\n"),
1417 aggrid, dladm_status2str(status, errmsg));
1418 aggr_configure_argp->retval = -1;
1419 } else if (!(flags & DLADM_OPT_ACTIVE)) {
1420 aggr_configure_argp->up = B_TRUE;
1423 free(aggr_attr.lg_ports);
1424 return (DLADM_WALK_TERMINATE);
1428 * aggr_configure_all() - Configure AGGRs over a physical link after it attaches
1430 static int
1431 aggr_configure_all(rcm_handle_t *hd, datalink_id_t linkid, boolean_t *up)
1433 char rsrc[RCM_LINK_RESOURCE_MAX];
1434 link_cache_t *node;
1435 aggr_configure_arg_t arg = {DATALINK_INVALID_LINKID, 0, B_FALSE};
1437 *up = B_FALSE;
1439 /* Check for the AGGRs in the cache */
1440 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid);
1442 rcm_log_message(RCM_TRACE1, "AGGR: aggr_configure_all(%s)\n", rsrc);
1444 /* Check if the link is new or was previously offlined */
1445 (void) mutex_lock(&cache_lock);
1446 if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) &&
1447 (!(node->vc_state & CACHE_NODE_OFFLINED))) {
1448 rcm_log_message(RCM_TRACE1,
1449 "AGGR: Skipping configured link(%s)\n", rsrc);
1450 (void) mutex_unlock(&cache_lock);
1451 return (0);
1453 (void) mutex_unlock(&cache_lock);
1455 arg.portid = linkid;
1456 (void) dladm_walk_datalink_id(aggr_configure, dld_handle, &arg,
1457 DATALINK_CLASS_AGGR, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST);
1459 if (arg.retval == 0) {
1460 *up = arg.up;
1461 rcm_log_message(RCM_TRACE1,
1462 "AGGR: aggr_configure_all succeeded(%s)\n", rsrc);
1464 return (arg.retval);