1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <arpa/inet.h> 27 #include <assert.h> 28 #include <libdllink.h> 29 #include <libdlstat.h> 30 #include <libnwam.h> 31 #include <libscf.h> 32 #include <netinet/in.h> 33 #include <stdlib.h> 34 #include <sys/socket.h> 35 #include <sys/time.h> 36 #include <sys/types.h> 37 #include <values.h> 38 39 #include "conditions.h" 40 #include "events.h" 41 #include "objects.h" 42 #include "ncp.h" 43 #include "ncu.h" 44 #include "util.h" 45 46 /* 47 * ncp.c - handles NCP actions. 48 */ 49 50 char active_ncp[NWAM_MAX_NAME_LEN]; 51 nwam_ncp_handle_t active_ncph = NULL; 52 int64_t current_ncu_priority_group = INVALID_PRIORITY_GROUP; 53 /* 54 * active_ncp_mutex protects active_ncp, active_ncph and 55 * current_ncu_priority_group. 56 */ 57 pthread_mutex_t active_ncp_mutex = PTHREAD_MUTEX_INITIALIZER; 58 59 /* 60 * The variable ncu_wait_time specifies how long to wait to obtain a 61 * DHCP lease before giving up on that NCU and moving on to the next/lower 62 * priority-group. 63 */ 64 uint64_t ncu_wait_time = NCU_WAIT_TIME_DEFAULT; 65 66 /* 67 * Specifies if this is the first time the NCP has been enabled. True 68 * on startup so that we can differentiate between when we start up 69 * with a given NCP versus when we are asked to reenable it. 70 */ 71 boolean_t initial_ncp_enable = B_TRUE; 72 73 /* 74 * nwamd_ncp_handle_enable_event() should be called in the event handling 75 * loop in response to an _ENABLE event, triggered as a result of an 76 * nwam_ncp_enable() call from a libnwam consumer. To enable the new NCP, 77 * we first call nwamd_fini_ncus() on the old NCP. This results in enqueueing 78 * of a set of _FINI events for each NCU. These events are handled and in 79 * order to tear down config, (online*, uninitialized) state change events 80 * are created and consumed directly by the fini event handler (these events 81 * are not enqueued as this would result in state events for the old NCP 82 * appearing after the new NCP has been enabled. After the _FINI events are 83 * enqueued, we enqueue an NCP _OBJECT_STATE event for the new NCP. Since 84 * it is enqueued after the _FINI events, we are guaranteed no events for the 85 * old NCP will appear after the new NCP is activated. 86 */ 87 void 88 nwamd_ncp_handle_enable_event(nwamd_event_t event) 89 { 90 char *new_ncp = event->event_object; 91 nwam_ncp_handle_t new_ncph; 92 nwam_error_t err; 93 94 if (new_ncp[0] == '\0') 95 return; 96 97 (void) pthread_mutex_lock(&active_ncp_mutex); 98 if (strcmp(active_ncp, new_ncp) == 0 && !initial_ncp_enable) { 99 nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: " 100 "%s is already active", new_ncp); 101 (void) pthread_mutex_unlock(&active_ncp_mutex); 102 return; 103 } 104 (void) pthread_mutex_unlock(&active_ncp_mutex); 105 106 nlog(LOG_DEBUG, "nwamd_ncp_handle_enable_event: activating NCP %s", 107 new_ncp); 108 109 /* 110 * To activate new NCP, run nwamd_fini_ncus(), reset the active 111 * priority-group, set the active_ncp property and refresh the 112 * daemon. The refresh action will trigger a re-read of the NCUs 113 * for the activated NCP. 114 */ 115 116 nwamd_fini_ncus(); 117 118 if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph)) 119 == NWAM_ENTITY_NOT_FOUND) { 120 err = nwam_ncp_create(new_ncp, 0, &new_ncph); 121 } 122 123 if (err == NWAM_SUCCESS) { 124 nwam_ncp_free(new_ncph); 125 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCP, new_ncp, 126 NWAM_STATE_ONLINE, NWAM_AUX_STATE_ACTIVE); 127 } else if (initial_ncp_enable) { 128 /* 129 * We weren't able to enable the NCP when nwamd starts up, 130 * retry in a few seconds. 131 */ 132 nwamd_event_t retry_event = nwamd_event_init_object_action 133 (NWAM_OBJECT_TYPE_NCP, new_ncp, NULL, NWAM_ACTION_ENABLE); 134 if (retry_event == NULL) { 135 nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: " 136 "could not create retry event to enable %s NCP", 137 new_ncp); 138 return; 139 } 140 141 nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: " 142 "failed to enable %s NCP, retrying in %d seconds", 143 new_ncp, NWAMD_READONLY_RETRY_INTERVAL); 144 nwamd_event_enqueue_timed(retry_event, 145 NWAMD_READONLY_RETRY_INTERVAL); 146 } else { 147 nlog(LOG_ERR, "nwamd_ncp_handle_enable_event: error %s", 148 nwam_strerror(err)); 149 return; 150 } 151 } 152 153 void 154 nwamd_ncp_handle_action_event(nwamd_event_t event) 155 { 156 switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) { 157 case NWAM_ACTION_ENABLE: 158 nwamd_ncp_handle_enable_event(event); 159 break; 160 case NWAM_ACTION_ADD: 161 case NWAM_ACTION_DESTROY: 162 /* nothing to do */ 163 break; 164 default: 165 nlog(LOG_INFO, "nwam_ncp_handle_action_event: " 166 "unexpected action"); 167 nwamd_event_do_not_send(event); 168 break; 169 } 170 } 171 172 /* 173 * The only state events we create are (online, active) events which are 174 * generated as part of an NCP enable action (see above). 175 */ 176 void 177 nwamd_ncp_handle_state_event(nwamd_event_t event) 178 { 179 char *new_ncp = event->event_object; 180 nwam_ncp_handle_t new_ncph, old_ncph; 181 nwam_error_t err; 182 183 /* The NCP to be activated should always exist. */ 184 if ((err = nwam_ncp_read(new_ncp, 0, &new_ncph)) != NWAM_SUCCESS) { 185 nlog(LOG_ERR, "nwamd_ncp_handle_state_event: " 186 "cannot read NCP %s: : %s", new_ncp, nwam_strerror(err)); 187 nwamd_event_do_not_send(event); 188 return; 189 } 190 191 /* 192 * To activate new NCP, reset the active priority-group, set the 193 * active_ncp property and refresh the daemon. The refresh action will 194 * trigger a re-read of the NCUs for the activated NCP. 195 */ 196 (void) pthread_mutex_lock(&active_ncp_mutex); 197 old_ncph = active_ncph; 198 active_ncph = new_ncph; 199 nwam_ncp_free(old_ncph); 200 current_ncu_priority_group = INVALID_PRIORITY_GROUP; 201 (void) strlcpy(active_ncp, event->event_object, 202 sizeof (active_ncp)); 203 (void) pthread_mutex_unlock(&active_ncp_mutex); 204 (void) nwamd_set_string_property(OUR_FMRI, OUR_PG, 205 OUR_ACTIVE_NCP_PROP_NAME, new_ncp); 206 (void) smf_refresh_instance(OUR_FMRI); 207 initial_ncp_enable = B_FALSE; 208 } 209 210 int 211 nwamd_ncp_action(const char *ncp, nwam_action_t action) 212 { 213 nwamd_event_t event = nwamd_event_init_object_action 214 (NWAM_OBJECT_TYPE_NCP, ncp, NULL, action); 215 if (event == NULL) 216 return (1); 217 nwamd_event_enqueue(event); 218 return (0); 219 } 220 221 /* 222 * Below this point are routines handling NCU prioritization 223 * policy for the active NCP. 224 */ 225 226 struct priority_group_cbarg { 227 uint64_t minpriority; 228 uint64_t currpriority; 229 boolean_t found; 230 }; 231 232 /* Callback used to find next pg in NCP that is >= start_pg */ 233 static int 234 find_next_priority_group_cb(nwamd_object_t object, void *data) 235 { 236 struct priority_group_cbarg *cbarg = data; 237 uint64_t priority; 238 nwamd_ncu_t *ncu = object->nwamd_object_data; 239 240 if (ncu->ncu_node.u_link.nwamd_link_activation_mode != 241 NWAM_ACTIVATION_MODE_PRIORITIZED) 242 return (0); 243 244 priority = ncu->ncu_node.u_link.nwamd_link_priority_group; 245 246 if (priority >= cbarg->minpriority && priority < cbarg->currpriority) { 247 cbarg->found = B_TRUE; 248 cbarg->currpriority = priority; 249 } 250 return (0); 251 } 252 253 /* Set current_pg to next pg in NCP that is >= start_pg */ 254 boolean_t 255 nwamd_ncp_find_next_priority_group(int64_t minpriority, 256 int64_t *nextpriorityp) 257 { 258 struct priority_group_cbarg cbarg; 259 260 cbarg.minpriority = minpriority; 261 cbarg.currpriority = MAXINT; 262 cbarg.found = B_FALSE; 263 264 (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, 265 find_next_priority_group_cb, &cbarg); 266 267 if (cbarg.found) { 268 nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: " 269 "next priority group >= %lld is %lld", 270 minpriority, cbarg.currpriority); 271 *nextpriorityp = cbarg.currpriority; 272 return (B_TRUE); 273 } else { 274 nlog(LOG_DEBUG, "nwamd_ncp_find_next_priority_group: " 275 "no priority groups >= %lld exist", minpriority); 276 return (B_FALSE); 277 } 278 } 279 280 /* 281 * Struct for walking NCUs in the selected priority group. We count 282 * how many of the exclusive, all and shared NCUs are online, and 283 * if activate_or_deactivate is true, we either activate or deactivate 284 * (depending on the value of activate) offline/online NCUs. 285 */ 286 struct nwamd_ncu_check_walk_arg { 287 boolean_t manual; /* enable manual NCUs only */ 288 int64_t priority_group; /* interested priority-group for this walk */ 289 uint64_t exclusive_ncus; 290 uint64_t exclusive_online_ncus; 291 uint64_t shared_ncus; 292 uint64_t shared_online_ncus; 293 uint64_t all_ncus; 294 uint64_t all_online_ncus; 295 boolean_t activate_or_deactivate; 296 boolean_t activate; 297 }; 298 299 /* 300 * This function serves a number of purposes: 301 * - it supports activation/deactivation of manual NCUs in the current NCP 302 * (when wa->manual is true, wa->activate determines if we activate or 303 * deactivate the current NCU) 304 * - it supports checking/activation of a particular priority group in 305 * the active NCP. This works as follows: 306 * 307 * Count up numbers of exclusive, shared and all NCUs, and how many of each 308 * are online. If an NCU is waiting for IP address to be assigned, it is 309 * also considered online. If activate_or_deactivate is true, we also 310 * either activate (if activate is true) or deactivate prioritized NCUs 311 * that are offline or online. 312 */ 313 static int 314 nwamd_ncu_check_or_activate(nwamd_object_t object, void *data) 315 { 316 struct nwamd_ncu_check_walk_arg *wa = data; 317 nwamd_ncu_t *ncu; 318 uint64_t priority_group, priority_mode; 319 nwamd_object_t if_obj; 320 nwam_state_t state, if_state; 321 nwam_aux_state_t aux_state, if_aux_state; 322 char *name; 323 324 state = object->nwamd_object_state; 325 aux_state = object->nwamd_object_aux_state; 326 name = object->nwamd_object_name; 327 ncu = object->nwamd_object_data; 328 329 /* skip NCUs in UNINITIALIZED state */ 330 if (state == NWAM_STATE_UNINITIALIZED) { 331 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 332 "skipping uninitialized ncu %s", name); 333 return (0); 334 } 335 if (!wa->manual && wa->priority_group == INVALID_PRIORITY_GROUP) 336 return (0); 337 338 if (ncu->ncu_type != NWAM_NCU_TYPE_LINK) { 339 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 340 "skipping interface NCU %s", name); 341 return (0); 342 } 343 if (!wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode != 344 NWAM_ACTIVATION_MODE_PRIORITIZED) { 345 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 346 "skipping non-prioritized NCU %s", name); 347 return (0); 348 } 349 if (wa->manual && ncu->ncu_node.u_link.nwamd_link_activation_mode != 350 NWAM_ACTIVATION_MODE_MANUAL) { 351 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 352 "skipping non-manual NCU %s", name); 353 return (0); 354 } 355 356 priority_group = ncu->ncu_node.u_link.nwamd_link_priority_group; 357 priority_mode = ncu->ncu_node.u_link.nwamd_link_priority_mode; 358 /* Only work with NCUs in the requested priority-group */ 359 if (!wa->manual && priority_group != wa->priority_group) { 360 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 361 "skipping NCU %s in different priority-group", name); 362 return (0); 363 } 364 /* Get the state of the corresponding interface NCU */ 365 if ((if_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_INTERFACE, 366 ncu->ncu_name)) == NULL) { 367 nlog(LOG_ERR, "nwamd_ncu_check_or_activate: " 368 "interface NCU of %s not found, skipping", name); 369 return (0); 370 } 371 if_state = if_obj->nwamd_object_state; 372 if_aux_state = if_obj->nwamd_object_aux_state; 373 nwamd_object_release(if_obj); 374 375 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: %s ncu %s", 376 wa->activate_or_deactivate ? 377 (wa->activate ? "activating" : "deactivating") : 378 "checking", name); 379 380 if (wa->manual) { 381 if (wa->activate_or_deactivate && wa->activate) { 382 if (state == NWAM_STATE_OFFLINE && ncu->ncu_enabled) { 383 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 384 "moving NCU %s to offline* from offline", 385 name); 386 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 387 name, NWAM_STATE_OFFLINE_TO_ONLINE, 388 NWAM_AUX_STATE_INITIALIZED); 389 } 390 if (state != NWAM_STATE_DISABLED && 391 !ncu->ncu_enabled) { 392 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 393 "moving NCU %s to online* (disabling)", 394 name); 395 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 396 name, NWAM_STATE_ONLINE_TO_OFFLINE, 397 NWAM_AUX_STATE_MANUAL_DISABLE); 398 } 399 } 400 return (0); 401 } 402 switch (priority_mode) { 403 case NWAM_PRIORITY_MODE_EXCLUSIVE: 404 wa->exclusive_ncus++; 405 if (state == NWAM_STATE_ONLINE && 406 (if_state == NWAM_STATE_ONLINE || 407 if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR)) 408 wa->exclusive_online_ncus++; 409 410 /* 411 * For exclusive NCUs, we activate offline NCUs as long 412 * as no other exclusive NCUs are active. 413 */ 414 if (wa->activate_or_deactivate && wa->activate) { 415 if (state == NWAM_STATE_OFFLINE && 416 wa->exclusive_online_ncus == 0) { 417 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 418 "moving NCU %s to offline* from offline", 419 name); 420 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 421 name, NWAM_STATE_OFFLINE_TO_ONLINE, 422 NWAM_AUX_STATE_INITIALIZED); 423 } 424 } 425 if (wa->activate_or_deactivate && !wa->activate) { 426 if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) { 427 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 428 "deactivating NCU %s", name); 429 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 430 name, NWAM_STATE_ONLINE_TO_OFFLINE, 431 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 432 } 433 } 434 /* 435 * If we are activating or checking the priority group and 436 * too many exclusive NCUs are online, take this NCU down. 437 */ 438 if ((wa->activate_or_deactivate && wa->activate) || 439 !wa->activate_or_deactivate) { 440 if (state == NWAM_STATE_ONLINE && 441 if_state == NWAM_STATE_ONLINE && 442 wa->exclusive_online_ncus > 1) { 443 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 444 "moving NCU %s to online* since another " 445 "NCU is already active", 446 name); 447 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 448 name, NWAM_STATE_ONLINE_TO_OFFLINE, 449 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 450 } 451 } 452 break; 453 case NWAM_PRIORITY_MODE_SHARED: 454 wa->shared_ncus++; 455 if (state == NWAM_STATE_ONLINE && 456 (if_state == NWAM_STATE_ONLINE || 457 if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR)) 458 wa->shared_online_ncus++; 459 460 if (wa->activate_or_deactivate && wa->activate) { 461 if (state == NWAM_STATE_OFFLINE) { 462 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 463 "activating NCU %s", name); 464 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 465 name, NWAM_STATE_OFFLINE_TO_ONLINE, 466 NWAM_AUX_STATE_INITIALIZED); 467 } 468 } 469 if (wa->activate_or_deactivate && !wa->activate) { 470 if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) { 471 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 472 "deactivating NCU %s", name); 473 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 474 name, NWAM_STATE_ONLINE_TO_OFFLINE, 475 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 476 } 477 } 478 break; 479 case NWAM_PRIORITY_MODE_ALL: 480 wa->all_ncus++; 481 if (state == NWAM_STATE_ONLINE && 482 (if_state == NWAM_STATE_ONLINE || 483 if_aux_state == NWAM_AUX_STATE_IF_WAITING_FOR_ADDR)) 484 wa->all_online_ncus++; 485 486 /* 487 * For "all" NCUs, activate/deactivate all offline/online 488 * NCUs. 489 */ 490 if (wa->activate_or_deactivate && wa->activate) { 491 if (state == NWAM_STATE_OFFLINE) { 492 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 493 "activating NCU %s", name); 494 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 495 name, NWAM_STATE_OFFLINE_TO_ONLINE, 496 NWAM_AUX_STATE_INITIALIZED); 497 } 498 } 499 if (wa->activate_or_deactivate && !wa->activate) { 500 if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) { 501 nlog(LOG_DEBUG, "nwamd_ncu_check_or_activate: " 502 "deactivating NCU %s", name); 503 nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, 504 name, NWAM_STATE_ONLINE_TO_OFFLINE, 505 NWAM_AUX_STATE_CONDITIONS_NOT_MET); 506 } 507 } 508 509 break; 510 default: 511 nlog(LOG_ERR, "nwamd_ncu_check_or_activate: " 512 "invalid priority-mode"); 513 break; 514 } 515 516 return (0); 517 } 518 519 void 520 nwamd_ncp_activate_priority_group(int64_t priority) 521 { 522 struct nwamd_ncu_check_walk_arg wa; 523 nwamd_event_t check_event, priority_event; 524 525 if (priority == INVALID_PRIORITY_GROUP) 526 return; 527 528 (void) pthread_mutex_lock(&active_ncp_mutex); 529 if (priority == current_ncu_priority_group) { 530 (void) pthread_mutex_unlock(&active_ncp_mutex); 531 return; 532 } 533 (void) pthread_mutex_unlock(&active_ncp_mutex); 534 535 nlog(LOG_DEBUG, "nwamd_ncp_activate_priority_group: " 536 "activating priority group %lld", priority); 537 538 wa.manual = B_FALSE; 539 wa.priority_group = priority; 540 wa.exclusive_ncus = 0; 541 wa.exclusive_online_ncus = 0; 542 wa.shared_ncus = 0; 543 wa.shared_online_ncus = 0; 544 wa.all_ncus = 0; 545 wa.all_online_ncus = 0; 546 wa.activate_or_deactivate = B_TRUE; 547 wa.activate = B_TRUE; 548 549 if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, 550 nwamd_ncu_check_or_activate, &wa) != 0) { 551 nlog(LOG_ERR, "nwamd_ncp_activate_priority_group: " 552 "nwamd_walk_objects() failed"); 553 return; 554 } 555 556 /* 557 * Enqueue event to update current_ncu_priority_group and send to 558 * any event listeners. 559 */ 560 priority_event = nwamd_event_init_priority_group_change(priority); 561 if (priority_event == NULL) 562 return; 563 nwamd_event_enqueue(priority_event); 564 565 /* 566 * Now we've activated a new priority group, enqueue an event 567 * to check up on the state of this priority group. 568 */ 569 check_event = nwamd_event_init_ncu_check(); 570 if (check_event == NULL) 571 return; 572 nwamd_event_enqueue_timed(check_event, ncu_wait_time); 573 } 574 575 void 576 nwamd_ncp_deactivate_priority_group(int64_t priority) 577 { 578 struct nwamd_ncu_check_walk_arg wa; 579 580 if (priority == INVALID_PRIORITY_GROUP) 581 return; 582 583 nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group: " 584 "deactivating priority group %lld", priority); 585 586 wa.manual = B_FALSE; 587 wa.priority_group = priority; 588 wa.exclusive_ncus = 0; 589 wa.exclusive_online_ncus = 0; 590 wa.shared_ncus = 0; 591 wa.shared_online_ncus = 0; 592 wa.all_ncus = 0; 593 wa.all_online_ncus = 0; 594 wa.activate_or_deactivate = B_TRUE; 595 wa.activate = B_FALSE; 596 597 if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, 598 nwamd_ncu_check_or_activate, &wa) != 0) { 599 nlog(LOG_ERR, "nwamd_ncp_deactivate_priority_group: " 600 "nwamd_walk_objects() failed"); 601 return; 602 } 603 } 604 605 /* 606 * This function deactivates all priority groups at level 'priority' and lower 607 * (which is, numerically, all priorities >= priority). 608 */ 609 void 610 nwamd_ncp_deactivate_priority_group_all(int64_t priority) 611 { 612 if (priority == INVALID_PRIORITY_GROUP) 613 return; 614 615 nlog(LOG_DEBUG, "nwamd_ncp_deactivate_priority_group_all: " 616 "deactivating priority group less than or equal to %lld", priority); 617 618 do { 619 nwamd_ncp_deactivate_priority_group(priority); 620 } while (nwamd_ncp_find_next_priority_group(priority + 1, &priority)); 621 } 622 623 /* 624 * Returns 'true' if it found the highest priority group no higher then what 625 * is passed that should be activated and sets *priority to that. 626 */ 627 boolean_t 628 nwamd_ncp_check_priority_group(int64_t *priority) 629 { 630 struct nwamd_ncu_check_walk_arg wa; 631 boolean_t conditions_met = B_FALSE; 632 633 nlog(LOG_DEBUG, "nwamd_ncp_check_priority_group: " 634 "checking priority group %lld", *priority); 635 636 if (*priority == INVALID_PRIORITY_GROUP) { 637 if (!nwamd_ncp_find_next_priority_group(0, priority)) 638 return (B_FALSE); 639 } 640 641 while (!conditions_met) { 642 (void) memset(&wa, 0, sizeof (wa)); 643 wa.manual = B_FALSE; 644 wa.priority_group = *priority; 645 wa.activate_or_deactivate = B_FALSE; 646 647 if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, 648 nwamd_ncu_check_or_activate, &wa) != 0) { 649 nlog(LOG_ERR, "nwamd_ncp_check_priority_group: " 650 "nwamd_walk_objects() failed"); 651 return (B_FALSE); 652 } 653 654 /* 655 * Are activation conditons satisifed? In other words: 656 * - exactly one of the exclusive NCUs is online 657 * - 1 or more shared NCUs are online 658 * - all of the all NCUs are online. 659 * If any of these is untrue, conditions are not satisfied. 660 */ 661 conditions_met = B_TRUE; 662 if (wa.exclusive_ncus > 0 && wa.exclusive_online_ncus != 1) 663 conditions_met = B_FALSE; 664 if (wa.shared_ncus > 0 && wa.shared_online_ncus == 0) 665 conditions_met = B_FALSE; 666 if (wa.all_ncus > 0 && wa.all_ncus != wa.all_online_ncus) 667 conditions_met = B_FALSE; 668 if (wa.exclusive_online_ncus == 0 && 669 wa.shared_online_ncus == 0 && wa.all_online_ncus == 0) 670 conditions_met = B_FALSE; 671 672 if (conditions_met) { 673 return (B_TRUE); 674 } else { 675 /* 676 * If there is a next pg, activate it. If not, do 677 * nothing - we're stuck here unless an event occurs 678 * for our or a higher pg. 679 */ 680 if (!nwamd_ncp_find_next_priority_group 681 (wa.priority_group + 1, priority)) { 682 nlog(LOG_DEBUG, "ran out of prio groups"); 683 return (B_FALSE); 684 } 685 } 686 } 687 return (B_FALSE); 688 } 689 690 void 691 nwamd_ncp_activate_manual_ncus(void) 692 { 693 struct nwamd_ncu_check_walk_arg wa; 694 695 nlog(LOG_DEBUG, "nwamd_ncp_activate_manual_ncus: activating NCUs"); 696 697 wa.manual = B_TRUE; 698 wa.activate_or_deactivate = B_TRUE; 699 wa.activate = B_TRUE; 700 701 if (nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU, 702 nwamd_ncu_check_or_activate, &wa) != 0) { 703 nlog(LOG_ERR, "nwamd_ncp_activate_manual_ncus: " 704 "nwamd_walk_objects() failed"); 705 return; 706 } 707 } 708 709 void 710 nwamd_create_ncu_check_event(uint64_t when) 711 { 712 nwamd_event_t check_event = nwamd_event_init_ncu_check(); 713 if (check_event != NULL) 714 nwamd_event_enqueue_timed(check_event, when); 715 } 716