ncp.c revision f6da83d4178694e7113b71d1e452f15b296f73d8
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
#include <assert.h>
#include <libdllink.h>
#include <libdlstat.h>
#include <libnwam.h>
#include <libscf.h>
#include <stdlib.h>
#include <values.h>
#include "conditions.h"
#include "events.h"
#include "objects.h"
#include "ncp.h"
#include "ncu.h"
#include "util.h"
/*
* ncp.c - handles NCP actions.
*/
char active_ncp[NWAM_MAX_NAME_LEN];
/*
* active_ncp_mutex protects active_ncp, active_ncph and
* current_ncu_priority_group.
*/
/*
* The variable ncu_wait_time specifies how long to wait to obtain a
* priority-group.
*/
/*
* Specifies if this is the first time the NCP has been enabled. True
* on startup so that we can differentiate between when we start up
* with a given NCP versus when we are asked to reenable it.
*/
/*
* nwamd_ncp_handle_enable_event() should be called in the event handling
* loop in response to an _ENABLE event, triggered as a result of an
* nwam_ncp_enable() call from a libnwam consumer. To enable the new NCP,
* we first call nwamd_fini_ncus() on the old NCP. This results in enqueueing
* of a set of _FINI events for each NCU. These events are handled and in
* order to tear down config, (online*, uninitialized) state change events
* are created and consumed directly by the fini event handler (these events
* are not enqueued as this would result in state events for the old NCP
* appearing after the new NCP has been enabled. After the _FINI events are
* enqueued, we enqueue an NCP _OBJECT_STATE event for the new NCP. Since
* it is enqueued after the _FINI events, we are guaranteed no events for the
* old NCP will appear after the new NCP is activated.
*/
void
{
if (new_ncp[0] == '\0')
return;
(void) pthread_mutex_lock(&active_ncp_mutex);
"%s is already active", new_ncp);
(void) pthread_mutex_unlock(&active_ncp_mutex);
return;
}
(void) pthread_mutex_unlock(&active_ncp_mutex);
new_ncp);
/*
* To activate new NCP, run nwamd_fini_ncus(), reset the active
* priority-group, set the active_ncp property and refresh the
* daemon. The refresh action will trigger a re-read of the NCUs
* for the activated NCP.
*/
== NWAM_ENTITY_NOT_FOUND) {
}
if (err == NWAM_SUCCESS) {
} else if (initial_ncp_enable) {
/*
* We weren't able to enable the NCP when nwamd starts up,
* retry in a few seconds.
*/
if (retry_event == NULL) {
"could not create retry event to enable %s NCP",
new_ncp);
return;
}
"failed to enable %s NCP, retrying in %d seconds",
} else {
nwam_strerror(err));
return;
}
}
void
{
case NWAM_ACTION_ENABLE:
break;
case NWAM_ACTION_ADD:
case NWAM_ACTION_DESTROY:
/* nothing to do */
break;
default:
"unexpected action");
break;
}
}
/*
* The only state events we create are (online, active) events which are
* generated as part of an NCP enable action (see above).
*/
void
{
/* The NCP to be activated should always exist. */
return;
}
/*
* To activate new NCP, reset the active priority-group, set the
* active_ncp property and refresh the daemon. The refresh action will
* trigger a re-read of the NCUs for the activated NCP.
*/
(void) pthread_mutex_lock(&active_ncp_mutex);
sizeof (active_ncp));
(void) pthread_mutex_unlock(&active_ncp_mutex);
(void) smf_refresh_instance(OUR_FMRI);
}
int
{
return (1);
return (0);
}
/*
* Below this point are routines handling NCU prioritization
* policy for the active NCP.
*/
struct priority_group_cbarg {
};
/* Callback used to find next pg in NCP that is >= start_pg */
static int
{
return (0);
}
return (0);
}
/* Set current_pg to next pg in NCP that is >= start_pg */
{
struct priority_group_cbarg cbarg;
"next priority group >= %lld is %lld",
return (B_TRUE);
} else {
"no priority groups >= %lld exist", minpriority);
return (B_FALSE);
}
}
/*
* Struct for walking NCUs in the selected priority group. We count
* how many of the exclusive, all and shared NCUs are online, and
* if activate_or_deactivate is true, we either activate or deactivate
*/
struct nwamd_ncu_check_walk_arg {
};
/*
* This function serves a number of purposes:
* - it supports activation/deactivation of manual NCUs in the current NCP
* (when wa->manual is true, wa->activate determines if we activate or
* deactivate the current NCU)
* - it supports checking/activation of a particular priority group in
* the active NCP. This works as follows:
*
* Count up numbers of exclusive, shared and all NCUs, and how many of each
* are online. If an NCU is waiting for IP address to be assigned, it is
* also considered online. If activate_or_deactivate is true, we also
* either activate (if activate is true) or deactivate prioritized NCUs
* that are offline or online.
*/
static int
{
char *name;
/* skip NCUs in UNINITIALIZED state */
if (state == NWAM_STATE_UNINITIALIZED) {
"skipping uninitialized ncu %s", name);
return (0);
}
return (0);
"skipping interface NCU %s", name);
return (0);
}
"skipping non-prioritized NCU %s", name);
return (0);
}
"skipping non-manual NCU %s", name);
return (0);
}
/* Only work with NCUs in the requested priority-group */
"skipping NCU %s in different priority-group", name);
return (0);
}
/* Get the state of the corresponding interface NCU */
"interface NCU of %s not found, skipping", name);
return (0);
}
"checking", name);
"moving NCU %s to offline* from offline",
name);
}
if (state != NWAM_STATE_DISABLED &&
!ncu->ncu_enabled) {
"moving NCU %s to online* (disabling)",
name);
}
}
return (0);
}
switch (priority_mode) {
wa->exclusive_ncus++;
if (state == NWAM_STATE_ONLINE &&
(if_state == NWAM_STATE_ONLINE ||
/*
* For exclusive NCUs, we activate offline NCUs as long
* as no other exclusive NCUs are active.
*/
if (state == NWAM_STATE_OFFLINE &&
wa->exclusive_online_ncus == 0) {
"moving NCU %s to offline* from offline",
name);
}
}
if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
"deactivating NCU %s", name);
}
}
/*
* If we are activating or checking the priority group and
* too many exclusive NCUs are online, take this NCU down.
*/
!wa->activate_or_deactivate) {
if (state == NWAM_STATE_ONLINE &&
if_state == NWAM_STATE_ONLINE &&
"moving NCU %s to online* since another "
"NCU is already active",
name);
}
}
break;
wa->shared_ncus++;
if (state == NWAM_STATE_ONLINE &&
(if_state == NWAM_STATE_ONLINE ||
wa->shared_online_ncus++;
if (state == NWAM_STATE_OFFLINE) {
"activating NCU %s", name);
}
}
if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
"deactivating NCU %s", name);
}
}
break;
case NWAM_PRIORITY_MODE_ALL:
if (state == NWAM_STATE_ONLINE &&
(if_state == NWAM_STATE_ONLINE ||
wa->all_online_ncus++;
/*
* For "all" NCUs, activate/deactivate all offline/online
* NCUs.
*/
if (state == NWAM_STATE_OFFLINE) {
"activating NCU %s", name);
}
}
if (aux_state != NWAM_AUX_STATE_CONDITIONS_NOT_MET) {
"deactivating NCU %s", name);
}
}
break;
default:
"invalid priority-mode");
break;
}
return (0);
}
void
{
struct nwamd_ncu_check_walk_arg wa;
if (priority == INVALID_PRIORITY_GROUP)
return;
(void) pthread_mutex_lock(&active_ncp_mutex);
if (priority == current_ncu_priority_group) {
(void) pthread_mutex_unlock(&active_ncp_mutex);
return;
}
(void) pthread_mutex_unlock(&active_ncp_mutex);
"activating priority group %lld", priority);
wa.exclusive_ncus = 0;
wa.exclusive_online_ncus = 0;
wa.shared_ncus = 0;
wa.shared_online_ncus = 0;
wa.all_online_ncus = 0;
nwamd_ncu_check_or_activate, &wa) != 0) {
"nwamd_walk_objects() failed");
return;
}
/*
* Enqueue event to update current_ncu_priority_group and send to
* any event listeners.
*/
if (priority_event == NULL)
return;
/*
* Now we've activated a new priority group, enqueue an event
* to check up on the state of this priority group.
*/
if (check_event == NULL)
return;
}
void
{
struct nwamd_ncu_check_walk_arg wa;
if (priority == INVALID_PRIORITY_GROUP)
return;
"deactivating priority group %lld", priority);
wa.exclusive_ncus = 0;
wa.exclusive_online_ncus = 0;
wa.shared_ncus = 0;
wa.shared_online_ncus = 0;
wa.all_online_ncus = 0;
nwamd_ncu_check_or_activate, &wa) != 0) {
"nwamd_walk_objects() failed");
return;
}
}
/*
* This function deactivates all priority groups at level 'priority' and lower
* (which is, numerically, all priorities >= priority).
*/
void
{
if (priority == INVALID_PRIORITY_GROUP)
return;
"deactivating priority group less than or equal to %lld", priority);
do {
}
/*
* Returns 'true' if it found the highest priority group no higher then what
* is passed that should be activated and sets *priority to that.
*/
{
struct nwamd_ncu_check_walk_arg wa;
"checking priority group %lld", *priority);
if (*priority == INVALID_PRIORITY_GROUP) {
if (!nwamd_ncp_find_next_priority_group(0, priority))
return (B_FALSE);
}
while (!conditions_met) {
nwamd_ncu_check_or_activate, &wa) != 0) {
"nwamd_walk_objects() failed");
return (B_FALSE);
}
/*
* Are activation conditons satisifed? In other words:
* - exactly one of the exclusive NCUs is online
* - 1 or more shared NCUs are online
* - all of the all NCUs are online.
* If any of these is untrue, conditions are not satisfied.
*/
if (wa.exclusive_online_ncus == 0 &&
if (conditions_met) {
return (B_TRUE);
} else {
/*
* If there is a next pg, activate it. If not, do
* nothing - we're stuck here unless an event occurs
* for our or a higher pg.
*/
return (B_FALSE);
}
}
}
return (B_FALSE);
}
void
{
struct nwamd_ncu_check_walk_arg wa;
nwamd_ncu_check_or_activate, &wa) != 0) {
"nwamd_walk_objects() failed");
return;
}
}
void
{
if (check_event != NULL)
}