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