enm.c revision 6ba597c56d749c61b4f783157f63196d7b2445f0
/*
* 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
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <errno.h>
#include <inetcfg.h>
#include <libdladm.h>
#include <libdllink.h>
#include <libdlwlan.h>
#include <libscf.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libnwam.h>
#include "conditions.h"
#include "events.h"
#include "objects.h"
#include "util.h"
/*
* enm.c - contains routines which handle ENM (external network modifier)
* abstraction. ENMs represent scripts or services that can be activated either
* manually or in response to network conditions.
*/
static int
{
char *name;
return (0);
}
NWAM_OBJECT_TYPE_ENM, 0, name);
return (0);
}
/*
* Walk all ENMs, creating init events for each.
*/
void
nwamd_init_enms(void)
{
}
/*
* Walk all ENMs, creating fini events for each.
*/
void
nwamd_fini_enms(void)
{
}
static boolean_t
{
&enabledval) != NWAM_SUCCESS) {
/* It's legal for a conditional ENM to not specify "enabled" */
return (B_FALSE);
}
"enabled value");
}
return (enabled);
}
static int64_t
{
&activationval) != NWAM_SUCCESS) {
"activation mode value");
return (-1);
}
"activation mode value");
ret = -1;
} else {
ret = activation;
}
return (ret);
}
static void *
{
char *object_name = arg;
char *script;
int ret;
"could not find ENM %s", object_name);
return (NULL);
}
/* object_name was malloc() before this thread was created, free() it */
/*
* We're starting if current state is offline* and stopping otherwise.
*/
&scriptval) != NWAM_SUCCESS ||
/*
* If we're stopping, it's not an error for no script to
* be specified.
*/
"nwamd_enm_activate_deactivate_thread: "
"no script specified for enm %s",
if (going_online) {
} else {
}
} else {
int i = 0;
"running script %s for ENM %s", script,
/*
* The script may take a number of arguments. We need to
* create a string array consisting of the wrapper command
* (ctrun), ENM script name, arguments and NULL array
* terminator. Start with an array of size equal to the
* string length (since the number of arguments will always
* be less than this) and shrink array to the actual number
* of arguments when we have parsed the string.
*/
ret = 1;
goto err;
}
ret = 1;
goto err;
}
err:
/*
* If script execution fails and we're not destroying the
* object, go to maintenance.
*/
if (ret != 0) {
"execution of '%s' failed for ENM %s",
if (object->nwamd_object_aux_state !=
} else {
}
} else {
if (going_online) {
} else {
}
}
}
if (disable_succeeded) {
/*
* If aux state is "manual disable", we know
* this was a disable request, otherwise it was
* _fini request or a condition satisfaction
* failure.
*/
switch (object->nwamd_object_aux_state) {
break;
break;
default:
break;
}
}
/* If state/aux state are uninitialized/unintialized, destroy the ENM */
if (state == NWAM_STATE_UNINITIALIZED &&
} else {
}
return (NULL);
}
/*
* held across threads, so we duplicate the object name for the method
* execution thread. Returns true if thread is successfully launched.
*/
{
char *name;
/*
* Launch separate thread to wait for execution of script
* to complete. Do not hold object lock across threads.
*/
return (B_FALSE);
}
nwamd_enm_activate_deactivate_thread, name) != 0) {
"enm script thread for %s", name);
return (B_FALSE);
}
/* "name" will be freed by the newly-created thread. */
/* detach thread so that it doesn't become a zombie */
(void) pthread_detach(script);
return (B_TRUE);
}
/*
* Activate the ENM, either in response to an enable event or conditions
* being satisfied.
*/
static void
nwamd_enm_activate(const char *object_name)
{
int ret;
return;
}
switch (err) {
case NWAM_SUCCESS:
"FMRI string for ENM %s",
break;
}
break;
}
else
if (ret == 0) {
} else {
"FMRI %s for ENM %s", fmri,
}
break;
default:
/*
* Must be a method-based ENM with start (and stop) script(s).
*/
if (!nwamd_enm_run_method(object)) {
/* Could not launch method execution thread */
} else {
ran_method = B_TRUE;
}
break;
}
}
/*
* If the method thread was created, we drop the lock to the ENM
* object without decreasing the reference count, ensuring it will not
* be destroyed until method execution has completed.
*/
if (ran_method) {
} else {
}
}
/* Deactivates the ENM. */
static void
nwamd_enm_deactivate(const char *object_name)
{
int ret;
return;
}
!= NWAM_SUCCESS) {
/*
* Must be a method-based ENM with start (and stop) script(s).
* Script execution thread will take care of the rest.
* If the method thread was created, we drop the lock to the ENM
* object without decreasing the reference count, ensuring it
* will not be destroyed until method execution has completed.
*/
if (nwamd_enm_run_method(object)) {
return;
}
/* Could not launch method execution thread */
if (!destroying) {
}
} else {
"nwamd_enm_deactivate: could not retrieve "
"FMRI string for ENM %s",
if (!destroying) {
}
} else {
"FMRI %s for ENM %s", fmri,
if (!destroying) {
}
goto done;
}
if (ret != 0) {
"smf_disable_instance(%s) failed for "
"ENM %s: %s", fmri,
scf_strerror(scf_error()));
if (!destroying) {
}
}
}
}
done:
/*
* If aux state is "manual disable", we know
* this was a disable request, otherwise it was
* a _fini request or a condition satisfaction
* failure.
*/
switch (object->nwamd_object_aux_state) {
break;
break;
default:
break;
}
}
/* Only change state if we aren't destroying the ENM */
}
/* If state/aux state are uninitialized/unintialized, destroy the ENM */
if (state == NWAM_STATE_UNINITIALIZED &&
(void) nwamd_object_release_and_destroy(object);
} else {
(void) nwamd_object_release(object);
}
}
/*
* Determine whether an ENM should be (de)activated.
*/
/* ARGSUSED1 */
static int
{
char **conditions;
if (eactivation == -1)
return (0);
switch (eactivation) {
if (enabled) {
switch (state) {
case NWAM_STATE_ONLINE:
case NWAM_STATE_MAINTENANCE:
/* Do nothing */
break;
default:
NWAM_ACTION_ENABLE) != 0) {
"nwamd_enm_check: enable failed "
"for enm %s",
}
break;
}
} else {
switch (state) {
case NWAM_STATE_ONLINE:
NWAM_ACTION_DISABLE) != 0) {
"disable failed for enm %s",
}
break;
case NWAM_STATE_MAINTENANCE:
/* Do nothing */
break;
case NWAM_STATE_DISABLED:
/* Do nothing */
break;
default:
break;
}
}
break;
"condition value");
break;
}
"condition value");
break;
}
conditions, nelem);
}
}
break;
}
return (0);
}
void
{
}
int
{
return (1);
return (0);
}
/*
* Event handling functions.
*/
/* Handle ENM initialization/refresh event */
void
{
!= NWAM_SUCCESS) {
nwam_strerror(err));
return;
}
} else {
}
/*
* If this ENM is ONLINE, and not manual and disabled (since in
* that case it was online but we've just set enabled = false as part
* of a disable action), then it is still active but refreshing.
* Change states to re-activate itself.
*/
if (!manual_disabled &&
}
}
/* Handle ENM finish event */
void
{
/*
* Simulate a state event so that the state machine can correctly
* deactivate the ENM and free up the handle.
*/
if (state_event == NULL) {
return;
}
/*
* Do not free the handle and object.
* nwamd_enm_activate_deactivate_thread() and
* nwamd_enm_deactivate() does this after running the stop script
* and disabling the FMRI respectively.
*/
}
void
{
case NWAM_ACTION_ENABLE:
return;
}
"enm %s already online, nothing to do",
return;
}
break;
case NWAM_ACTION_DISABLE:
return;
}
"enm %s already disabled, nothing to do",
return;
}
break;
case NWAM_ACTION_ADD:
case NWAM_ACTION_REFRESH:
break;
case NWAM_ACTION_DESTROY:
break;
default:
"unexpected action");
break;
}
}
void
{
return;
}
"ENM %s already in state (%s , %s)",
return;
}
/*
* State machine for ENMs.
*/
switch (new_state) {
break;
break;
case NWAM_STATE_DISABLED:
case NWAM_STATE_OFFLINE:
case NWAM_STATE_UNINITIALIZED:
case NWAM_STATE_MAINTENANCE:
case NWAM_STATE_DEGRADED:
default:
/* do nothing */
break;
}
}