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