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