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