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