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