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