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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 nvlist_free(nvl); 1220d62bc4baSyz147064 return (ret); 1221d62bc4baSyz147064 } 1222d62bc4baSyz147064 1223d62bc4baSyz147064 /* 1224d62bc4baSyz147064 * vlan_consumer_notify() - Notify consumers of VLANs coming back online. 1225d62bc4baSyz147064 */ 1226d62bc4baSyz147064 static int 1227d62bc4baSyz147064 vlan_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp, 1228d62bc4baSyz147064 uint_t flags, rcm_info_t **info) 1229d62bc4baSyz147064 { 1230d62bc4baSyz147064 char rsrc[RCM_LINK_RESOURCE_MAX]; 1231d62bc4baSyz147064 link_cache_t *node; 1232d62bc4baSyz147064 1233d62bc4baSyz147064 /* Check for the interface in the cache */ 1234d62bc4baSyz147064 (void) snprintf(rsrc, RCM_LINK_RESOURCE_MAX, "%s/%u", RCM_LINK_PREFIX, 1235d62bc4baSyz147064 linkid); 1236d62bc4baSyz147064 1237d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify(%s)\n", rsrc); 1238d62bc4baSyz147064 1239d62bc4baSyz147064 /* 1240d62bc4baSyz147064 * Inform IP consumers of the new link. 1241d62bc4baSyz147064 */ 1242d62bc4baSyz147064 if (vlan_notify_new_vlan(hd, rsrc) != 0) { 1243d62bc4baSyz147064 (void) mutex_lock(&cache_lock); 1244d62bc4baSyz147064 if ((node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH)) != NULL) { 1245d62bc4baSyz147064 (void) vlan_offline_vlan(node, VLAN_STALE, 1246d62bc4baSyz147064 CACHE_NODE_STALE); 1247d62bc4baSyz147064 } 1248d62bc4baSyz147064 (void) mutex_unlock(&cache_lock); 1249d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, 1250d62bc4baSyz147064 "VLAN: vlan_notify_new_vlan failed(%s)\n", rsrc); 1251d62bc4baSyz147064 return (-1); 1252d62bc4baSyz147064 } 1253d62bc4baSyz147064 1254d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, "VLAN: vlan_consumer_notify succeeded\n"); 1255d62bc4baSyz147064 return (0); 1256d62bc4baSyz147064 } 1257d62bc4baSyz147064 1258d62bc4baSyz147064 typedef struct vlan_up_arg_s { 1259d62bc4baSyz147064 datalink_id_t linkid; 1260d62bc4baSyz147064 int retval; 1261d62bc4baSyz147064 } vlan_up_arg_t; 1262d62bc4baSyz147064 1263d62bc4baSyz147064 static int 12644ac67f02SAnurag S. Maskey vlan_up(dladm_handle_t handle, datalink_id_t vlanid, void *arg) 1265d62bc4baSyz147064 { 1266d62bc4baSyz147064 vlan_up_arg_t *vlan_up_argp = arg; 1267d62bc4baSyz147064 dladm_status_t status; 1268d62bc4baSyz147064 dladm_vlan_attr_t vlan_attr; 1269d62bc4baSyz147064 char errmsg[DLADM_STRSIZE]; 1270d62bc4baSyz147064 12714ac67f02SAnurag S. Maskey status = dladm_vlan_info(handle, vlanid, &vlan_attr, DLADM_OPT_PERSIST); 1272d62bc4baSyz147064 if (status != DLADM_STATUS_OK) { 1273d62bc4baSyz147064 rcm_log_message(RCM_TRACE1, 1274d62bc4baSyz147064 "VLAN: vlan_up(): cannot get information for VLAN %u " 1275d62bc4baSyz147064 "(%s)\n", vlanid, dladm_status2str(status, errmsg)); 1276d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1277d62bc4baSyz147064 } 1278d62bc4baSyz147064 1279d62bc4baSyz147064 if (vlan_attr.dv_linkid != vlan_up_argp->linkid) 1280d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1281d62bc4baSyz147064 1282d62bc4baSyz147064 rcm_log_message(RCM_TRACE3, "VLAN: vlan_up(%u)\n", vlanid); 12834ac67f02SAnurag S. Maskey if ((status = dladm_vlan_up(handle, vlanid)) == DLADM_STATUS_OK) 1284d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1285d62bc4baSyz147064 1286d62bc4baSyz147064 /* 1287d62bc4baSyz147064 * Prompt the warning message and continue to UP other VLANs. 1288d62bc4baSyz147064 */ 1289d62bc4baSyz147064 rcm_log_message(RCM_WARNING, 1290d62bc4baSyz147064 _("VLAN: VLAN up failed (%u): %s\n"), 1291d62bc4baSyz147064 vlanid, dladm_status2str(status, errmsg)); 1292d62bc4baSyz147064 1293d62bc4baSyz147064 vlan_up_argp->retval = -1; 1294d62bc4baSyz147064 return (DLADM_WALK_CONTINUE); 1295d62bc4baSyz147064 } 1296d62bc4baSyz147064 1297d62bc4baSyz147064 /* 1298d62bc4baSyz147064 * vlan_configure() - Configure VLANs over a physical link after it attaches 1299d62bc4baSyz147064 */ 1300d62bc4baSyz147064 static int 1301d62bc4baSyz147064 vlan_configure(rcm_handle_t *hd, datalink_id_t linkid) 1302d62bc4baSyz147064 { 1303d62bc4baSyz147064 char rsrc[RCM_LINK_RESOURCE_MAX]; 1304d62bc4baSyz147064 link_cache_t *node; 1305d62bc4baSyz147064 vlan_up_arg_t arg = {DATALINK_INVALID_LINKID, 0}; 1306d62bc4baSyz147064 1307d62bc4baSyz147064 /* Check for the VLANs in the cache */ 1308d62bc4baSyz147064 (void) snprintf(rsrc, sizeof (rsrc), "%s/%u", RCM_LINK_PREFIX, linkid); 1309d62bc4baSyz147064 1310d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, "VLAN: vlan_configure(%s)\n", rsrc); 1311d62bc4baSyz147064 1312d62bc4baSyz147064 /* Check if the link is new or was previously offlined */ 1313d62bc4baSyz147064 (void) mutex_lock(&cache_lock); 1314d62bc4baSyz147064 if (((node = cache_lookup(hd, rsrc, CACHE_REFRESH)) != NULL) && 1315d62bc4baSyz147064 (!(node->vc_state & CACHE_NODE_OFFLINED))) { 1316d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, 1317d62bc4baSyz147064 "VLAN: Skipping configured interface(%s)\n", rsrc); 1318d62bc4baSyz147064 (void) mutex_unlock(&cache_lock); 1319d62bc4baSyz147064 return (0); 1320d62bc4baSyz147064 } 1321d62bc4baSyz147064 (void) mutex_unlock(&cache_lock); 1322d62bc4baSyz147064 1323d62bc4baSyz147064 arg.linkid = linkid; 13244ac67f02SAnurag S. Maskey (void) dladm_walk_datalink_id(vlan_up, dld_handle, &arg, 13254ac67f02SAnurag S. Maskey DATALINK_CLASS_VLAN, DATALINK_ANY_MEDIATYPE, DLADM_OPT_PERSIST); 1326d62bc4baSyz147064 1327d62bc4baSyz147064 if (arg.retval == 0) { 1328d62bc4baSyz147064 rcm_log_message(RCM_TRACE2, 1329d62bc4baSyz147064 "VLAN: vlan_configure succeeded(%s)\n", rsrc); 1330d62bc4baSyz147064 } 1331d62bc4baSyz147064 return (arg.retval); 1332d62bc4baSyz147064 } 1333