enm.c revision 6ba597c56d749c61b4f783157f63196d7b2445f0
1N/A/*
1N/A * CDDL HEADER START
1N/A *
1N/A * The contents of this file are subject to the terms of the
1N/A * Common Development and Distribution License (the "License").
1N/A * You may not use this file except in compliance with the License.
1N/A *
1N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1N/A * or http://www.opensolaris.org/os/licensing.
1N/A * See the License for the specific language governing permissions
1N/A * and limitations under the License.
1N/A *
1N/A * When distributing Covered Code, include this CDDL HEADER in each
1N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1N/A * If applicable, add the following below this CDDL HEADER, with the
1N/A * fields enclosed by brackets "[]" replaced with your own identifying
1N/A * information: Portions Copyright [yyyy] [name of copyright owner]
1N/A *
1N/A * CDDL HEADER END
1N/A */
1N/A
1N/A/*
1N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
1N/A * Use is subject to license terms.
1N/A */
1N/A
1N/A#include <arpa/inet.h>
1N/A#include <errno.h>
1N/A#include <inet/ip.h>
1N/A#include <inetcfg.h>
1N/A#include <libdladm.h>
1N/A#include <libdllink.h>
1N/A#include <libdlwlan.h>
1N/A#include <libscf.h>
1N/A#include <netinet/in.h>
1N/A#include <netdb.h>
1N/A#include <stdio.h>
1N/A#include <stdlib.h>
1N/A#include <string.h>
1N/A#include <sys/socket.h>
1N/A#include <sys/types.h>
1N/A
1N/A#include <libnwam.h>
1N/A#include "conditions.h"
1N/A#include "events.h"
1N/A#include "objects.h"
1N/A#include "util.h"
1N/A
1N/A/*
1N/A * enm.c - contains routines which handle ENM (external network modifier)
1N/A * abstraction. ENMs represent scripts or services that can be activated either
1N/A * manually or in response to network conditions.
1N/A */
1N/A
1N/A#define CTRUN "/usr/bin/ctrun"
1N/A
1N/Astatic int
1N/Aenm_create_init_fini_event(nwam_enm_handle_t enmh, void *data)
1N/A{
1N/A boolean_t *init = data;
1N/A char *name;
1N/A nwamd_event_t enm_event;
1N/A
1N/A if (nwam_enm_get_name(enmh, &name) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "enm_init_fini: could not get ENM name");
1N/A return (0);
1N/A }
1N/A
1N/A enm_event = nwamd_event_init(*init ?
1N/A NWAM_EVENT_TYPE_OBJECT_INIT : NWAM_EVENT_TYPE_OBJECT_FINI,
1N/A NWAM_OBJECT_TYPE_ENM, 0, name);
1N/A if (enm_event != NULL)
1N/A nwamd_event_enqueue(enm_event);
1N/A free(name);
1N/A
1N/A return (0);
1N/A}
1N/A
1N/A/*
1N/A * Walk all ENMs, creating init events for each.
1N/A */
1N/Avoid
1N/Anwamd_init_enms(void)
1N/A{
1N/A boolean_t init = B_TRUE;
1N/A
1N/A (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL);
1N/A}
1N/A
1N/A/*
1N/A * Walk all ENMs, creating fini events for each.
1N/A */
1N/Avoid
1N/Anwamd_fini_enms(void)
1N/A{
1N/A boolean_t init = B_FALSE;
1N/A
1N/A (void) nwam_walk_enms(enm_create_init_fini_event, &init, 0, NULL);
1N/A}
1N/A
1N/Astatic boolean_t
1N/Aenm_is_enabled(nwam_enm_handle_t enmh)
1N/A{
1N/A nwam_value_t enabledval;
1N/A boolean_t enabled = B_FALSE;
1N/A
1N/A if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ENABLED,
1N/A &enabledval) != NWAM_SUCCESS) {
1N/A /* It's legal for a conditional ENM to not specify "enabled" */
1N/A return (B_FALSE);
1N/A }
1N/A if (nwam_value_get_boolean(enabledval, &enabled) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "enm_is_enabled: could not retrieve "
1N/A "enabled value");
1N/A }
1N/A nwam_value_free(enabledval);
1N/A return (enabled);
1N/A}
1N/A
1N/Astatic int64_t
1N/Aenm_get_activation_mode(nwam_enm_handle_t enmh)
1N/A{
1N/A uint64_t activation;
1N/A int64_t ret;
1N/A nwam_value_t activationval;
1N/A
1N/A if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_ACTIVATION_MODE,
1N/A &activationval) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve "
1N/A "activation mode value");
1N/A return (-1);
1N/A }
1N/A if (nwam_value_get_uint64(activationval, &activation) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "enm_get_activation_mode: could not retrieve "
1N/A "activation mode value");
1N/A ret = -1;
1N/A } else {
1N/A ret = activation;
1N/A }
1N/A nwam_value_free(activationval);
1N/A
1N/A return (ret);
1N/A}
1N/A
1N/Astatic void *
1N/Anwamd_enm_activate_deactivate_thread(void *arg)
1N/A{
1N/A char *object_name = arg;
1N/A nwamd_object_t object;
1N/A nwam_enm_handle_t enmh;
1N/A nwam_value_t scriptval = NULL;
1N/A nwam_state_t state;
1N/A nwam_aux_state_t aux_state;
1N/A char *script;
1N/A boolean_t going_online, disable_succeeded = B_FALSE;
1N/A int ret;
1N/A
1N/A object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name);
1N/A if (object == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: "
1N/A "could not find ENM %s", object_name);
1N/A free(object_name);
1N/A return (NULL);
1N/A }
1N/A /* object_name was malloc() before this thread was created, free() it */
1N/A free(object_name);
1N/A
1N/A enmh = object->nwamd_object_handle;
1N/A
1N/A going_online =
1N/A (object->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE);
1N/A /*
1N/A * We're starting if current state is offline* and stopping otherwise.
1N/A */
1N/A if (nwam_enm_get_prop_value(enmh,
1N/A going_online ? NWAM_ENM_PROP_START : NWAM_ENM_PROP_STOP,
1N/A &scriptval) != NWAM_SUCCESS ||
1N/A nwam_value_get_string(scriptval, &script) != NWAM_SUCCESS) {
1N/A /*
1N/A * If we're stopping, it's not an error for no script to
1N/A * be specified.
1N/A */
1N/A nlog(going_online ? LOG_ERR : LOG_DEBUG,
1N/A "nwamd_enm_activate_deactivate_thread: "
1N/A "no script specified for enm %s",
1N/A object->nwamd_object_name);
1N/A if (going_online) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_METHOD_MISSING;
1N/A } else {
1N/A disable_succeeded = B_TRUE;
1N/A }
1N/A } else {
1N/A char *copy = NULL, *lasts;
1N/A const char **newargv, **argv = NULL;
1N/A int i = 0;
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_activate_deactivate_thread: "
1N/A "running script %s for ENM %s", script,
1N/A object->nwamd_object_name);
1N/A
1N/A /*
1N/A * The script may take a number of arguments. We need to
1N/A * create a string array consisting of the wrapper command
1N/A * (ctrun), ENM script name, arguments and NULL array
1N/A * terminator. Start with an array of size equal to the
1N/A * string length (since the number of arguments will always
1N/A * be less than this) and shrink array to the actual number
1N/A * of arguments when we have parsed the string.
1N/A */
1N/A if ((copy = strdup(script)) == NULL ||
1N/A (argv = calloc(strlen(script), sizeof (char *))) == NULL) {
1N/A ret = 1;
1N/A goto err;
1N/A }
1N/A argv[i++] = CTRUN;
1N/A argv[i++] = strtok_r(copy, " ", &lasts);
1N/A if (argv[1] == NULL) {
1N/A ret = 1;
1N/A goto err;
1N/A }
1N/A
1N/A for (; (argv[i] = strtok_r(NULL, " ", &lasts)) != NULL; i++) {}
1N/A
1N/A newargv = realloc(argv, (i + 1) * sizeof (char *));
1N/A argv = newargv;
1N/A
1N/A ret = nwamd_start_childv(CTRUN, argv);
1N/A
1N/Aerr:
1N/A /*
1N/A * If script execution fails and we're not destroying the
1N/A * object, go to maintenance.
1N/A */
1N/A if (ret != 0) {
1N/A nlog(LOG_ERR, "nwamd_enm_activate_deactivate_thread: "
1N/A "execution of '%s' failed for ENM %s",
1N/A script, object->nwamd_object_name);
1N/A if (object->nwamd_object_aux_state !=
1N/A NWAM_AUX_STATE_UNINITIALIZED) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_METHOD_FAILED;
1N/A } else {
1N/A state = NWAM_STATE_UNINITIALIZED;
1N/A aux_state = NWAM_AUX_STATE_UNINITIALIZED;
1N/A }
1N/A } else {
1N/A if (going_online) {
1N/A state = NWAM_STATE_ONLINE;
1N/A aux_state = NWAM_AUX_STATE_ACTIVE;
1N/A } else {
1N/A disable_succeeded = B_TRUE;
1N/A }
1N/A }
1N/A free(argv);
1N/A free(copy);
1N/A }
1N/A nwam_value_free(scriptval);
1N/A
1N/A if (disable_succeeded) {
1N/A /*
1N/A * If aux state is "manual disable", we know
1N/A * this was a disable request, otherwise it was
1N/A * _fini request or a condition satisfaction
1N/A * failure.
1N/A */
1N/A switch (object->nwamd_object_aux_state) {
1N/A case NWAM_AUX_STATE_MANUAL_DISABLE:
1N/A state = NWAM_STATE_DISABLED;
1N/A aux_state = NWAM_AUX_STATE_MANUAL_DISABLE;
1N/A break;
1N/A case NWAM_AUX_STATE_UNINITIALIZED:
1N/A state = NWAM_STATE_UNINITIALIZED;
1N/A aux_state = NWAM_AUX_STATE_UNINITIALIZED;
1N/A break;
1N/A default:
1N/A state = NWAM_STATE_OFFLINE;
1N/A aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1N/A break;
1N/A }
1N/A }
1N/A
1N/A /* If state/aux state are uninitialized/unintialized, destroy the ENM */
1N/A if (state == NWAM_STATE_UNINITIALIZED &&
1N/A aux_state == NWAM_AUX_STATE_UNINITIALIZED) {
1N/A object->nwamd_object_state = state;
1N/A object->nwamd_object_aux_state = aux_state;
1N/A (void) nwamd_object_release_and_destroy_after_preserve(object);
1N/A } else {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name, state, aux_state);
1N/A (void) nwamd_object_release_after_preserve(object);
1N/A }
1N/A
1N/A return (NULL);
1N/A}
1N/A
1N/A/*
1N/A * Run start/stop method for ENM in a separate thread. The object lock is not
1N/A * held across threads, so we duplicate the object name for the method
1N/A * execution thread. Returns true if thread is successfully launched.
1N/A */
1N/Aboolean_t
1N/Anwamd_enm_run_method(nwamd_object_t object)
1N/A{
1N/A char *name;
1N/A pthread_t script;
1N/A
1N/A /*
1N/A * Launch separate thread to wait for execution of script
1N/A * to complete. Do not hold object lock across threads.
1N/A */
1N/A if ((name = strdup(object->nwamd_object_name)) == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_run_method: %s: out of memory",
1N/A object->nwamd_object_name);
1N/A return (B_FALSE);
1N/A }
1N/A
1N/A if (pthread_create(&script, NULL,
1N/A nwamd_enm_activate_deactivate_thread, name) != 0) {
1N/A nlog(LOG_ERR, "nwamd_enm_run_method: could not create "
1N/A "enm script thread for %s", name);
1N/A free(name);
1N/A return (B_FALSE);
1N/A }
1N/A /* "name" will be freed by the newly-created thread. */
1N/A
1N/A /* detach thread so that it doesn't become a zombie */
1N/A (void) pthread_detach(script);
1N/A
1N/A return (B_TRUE);
1N/A}
1N/A
1N/A/*
1N/A * Activate the ENM, either in response to an enable event or conditions
1N/A * being satisfied.
1N/A */
1N/Astatic void
1N/Anwamd_enm_activate(const char *object_name)
1N/A{
1N/A nwamd_object_t object;
1N/A nwam_value_t fmrival;
1N/A char *fmri, *smf_state;
1N/A int ret;
1N/A nwam_enm_handle_t enmh;
1N/A nwam_state_t state;
1N/A nwam_aux_state_t aux_state;
1N/A nwam_error_t err;
1N/A boolean_t ran_method = B_FALSE;
1N/A
1N/A object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name);
1N/A if (object == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_activate: could not find ENM %s",
1N/A object_name);
1N/A return;
1N/A }
1N/A state = object->nwamd_object_state;
1N/A aux_state = object->nwamd_object_aux_state;
1N/A enmh = object->nwamd_object_handle;
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_activate: activating ENM %s",
1N/A object->nwamd_object_name);
1N/A
1N/A err = nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival);
1N/A switch (err) {
1N/A case NWAM_SUCCESS:
1N/A
1N/A if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "nwamd_enm_activate: could not retrieve "
1N/A "FMRI string for ENM %s",
1N/A object->nwamd_object_name);
1N/A nwam_value_free(fmrival);
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_INVALID_CONFIG;
1N/A break;
1N/A }
1N/A
1N/A if ((smf_state = smf_get_state(fmri)) == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_activate: invalid FMRI %s "
1N/A "for ENM %s", fmri, object->nwamd_object_name);
1N/A nwam_value_free(fmrival);
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_INVALID_CONFIG;
1N/A break;
1N/A }
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_activate: activating %s for ENM %s",
1N/A fmri, object->nwamd_object_name);
1N/A
1N/A if (strcmp(smf_state, SCF_STATE_STRING_ONLINE) == 0)
1N/A ret = smf_restart_instance(fmri);
1N/A else if (strcmp(smf_state, SCF_STATE_STRING_OFFLINE) == 0)
1N/A ret = smf_restart_instance(fmri);
1N/A else if (strcmp(smf_state, SCF_STATE_STRING_DISABLED) == 0)
1N/A ret = smf_enable_instance(fmri, SMF_TEMPORARY);
1N/A else
1N/A ret = smf_restore_instance(fmri);
1N/A
1N/A if (ret == 0) {
1N/A state = NWAM_STATE_ONLINE;
1N/A aux_state = NWAM_AUX_STATE_ACTIVE;
1N/A } else {
1N/A nlog(LOG_ERR, "nwamd_enm_activate: failed to enable "
1N/A "FMRI %s for ENM %s", fmri,
1N/A object->nwamd_object_name);
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_METHOD_FAILED;
1N/A }
1N/A free(smf_state);
1N/A nwam_value_free(fmrival);
1N/A break;
1N/A default:
1N/A /*
1N/A * Must be a method-based ENM with start (and stop) script(s).
1N/A */
1N/A if (!nwamd_enm_run_method(object)) {
1N/A /* Could not launch method execution thread */
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_METHOD_FAILED;
1N/A } else {
1N/A ran_method = B_TRUE;
1N/A }
1N/A break;
1N/A }
1N/A
1N/A if (state != object->nwamd_object_state ||
1N/A aux_state != object->nwamd_object_aux_state) {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name, state, aux_state);
1N/A }
1N/A
1N/A /*
1N/A * If the method thread was created, we drop the lock to the ENM
1N/A * object without decreasing the reference count, ensuring it will not
1N/A * be destroyed until method execution has completed.
1N/A */
1N/A if (ran_method) {
1N/A nwamd_object_release_and_preserve(object);
1N/A } else {
1N/A nwamd_object_release(object);
1N/A }
1N/A}
1N/A
1N/A/* Deactivates the ENM. */
1N/Astatic void
1N/Anwamd_enm_deactivate(const char *object_name)
1N/A{
1N/A nwamd_object_t object;
1N/A nwam_enm_handle_t enmh;
1N/A nwam_value_t fmrival;
1N/A char *fmri, *smf_state;
1N/A int ret;
1N/A nwam_state_t state;
1N/A nwam_aux_state_t aux_state;
1N/A boolean_t destroying = B_FALSE;
1N/A
1N/A object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM, object_name);
1N/A if (object == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_deactivate: could not find ENM %s",
1N/A object_name);
1N/A return;
1N/A }
1N/A
1N/A state = object->nwamd_object_state;
1N/A aux_state = object->nwamd_object_aux_state;
1N/A enmh = object->nwamd_object_handle;
1N/A state = object->nwamd_object_state;
1N/A /* If destroying, we don't care about method failure/config err */
1N/A destroying = (aux_state == NWAM_AUX_STATE_UNINITIALIZED);
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating enm %s",
1N/A object->nwamd_object_name);
1N/A
1N/A if (nwam_enm_get_prop_value(enmh, NWAM_ENM_PROP_FMRI, &fmrival)
1N/A != NWAM_SUCCESS) {
1N/A /*
1N/A * Must be a method-based ENM with start (and stop) script(s).
1N/A * Script execution thread will take care of the rest.
1N/A * If the method thread was created, we drop the lock to the ENM
1N/A * object without decreasing the reference count, ensuring it
1N/A * will not be destroyed until method execution has completed.
1N/A */
1N/A if (nwamd_enm_run_method(object)) {
1N/A nwamd_object_release_and_preserve(object);
1N/A return;
1N/A }
1N/A /* Could not launch method execution thread */
1N/A if (!destroying) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_METHOD_FAILED;
1N/A }
1N/A } else {
1N/A if (nwam_value_get_string(fmrival, &fmri) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR,
1N/A "nwamd_enm_deactivate: could not retrieve "
1N/A "FMRI string for ENM %s",
1N/A object->nwamd_object_name);
1N/A if (!destroying) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state = NWAM_AUX_STATE_INVALID_CONFIG;
1N/A }
1N/A } else {
1N/A if ((smf_state = smf_get_state(fmri)) == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_deactivate: invalid "
1N/A "FMRI %s for ENM %s", fmri,
1N/A object->nwamd_object_name);
1N/A nwam_value_free(fmrival);
1N/A if (!destroying) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state =
1N/A NWAM_AUX_STATE_INVALID_CONFIG;
1N/A }
1N/A goto done;
1N/A }
1N/A free(smf_state);
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_deactivate: deactivating %s "
1N/A "for ENM %s", fmri, object->nwamd_object_name);
1N/A
1N/A ret = smf_disable_instance(fmri, SMF_TEMPORARY);
1N/A
1N/A if (ret != 0) {
1N/A nlog(LOG_ERR, "nwamd_enm_deactivate: "
1N/A "smf_disable_instance(%s) failed for "
1N/A "ENM %s: %s", fmri,
1N/A object->nwamd_object_name,
1N/A scf_strerror(scf_error()));
1N/A if (!destroying) {
1N/A state = NWAM_STATE_MAINTENANCE;
1N/A aux_state =
1N/A NWAM_AUX_STATE_METHOD_FAILED;
1N/A }
1N/A }
1N/A }
1N/A nwam_value_free(fmrival);
1N/A }
1N/Adone:
1N/A if (state == object->nwamd_object_state &&
1N/A aux_state == object->nwamd_object_aux_state) {
1N/A /*
1N/A * If aux state is "manual disable", we know
1N/A * this was a disable request, otherwise it was
1N/A * a _fini request or a condition satisfaction
1N/A * failure.
1N/A */
1N/A switch (object->nwamd_object_aux_state) {
1N/A case NWAM_AUX_STATE_MANUAL_DISABLE:
1N/A state = NWAM_STATE_DISABLED;
1N/A aux_state = NWAM_AUX_STATE_MANUAL_DISABLE;
1N/A break;
1N/A case NWAM_AUX_STATE_UNINITIALIZED:
1N/A state = NWAM_STATE_UNINITIALIZED;
1N/A aux_state = NWAM_AUX_STATE_UNINITIALIZED;
1N/A break;
1N/A default:
1N/A state = NWAM_STATE_OFFLINE;
1N/A aux_state = NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1N/A break;
1N/A }
1N/A }
1N/A
1N/A /* Only change state if we aren't destroying the ENM */
1N/A if (!destroying && (state != object->nwamd_object_state ||
1N/A aux_state != object->nwamd_object_aux_state)) {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name, state, aux_state);
1N/A }
1N/A
1N/A /* If state/aux state are uninitialized/unintialized, destroy the ENM */
1N/A if (state == NWAM_STATE_UNINITIALIZED &&
1N/A aux_state == NWAM_AUX_STATE_UNINITIALIZED) {
1N/A (void) nwamd_object_release_and_destroy(object);
1N/A } else {
1N/A (void) nwamd_object_release(object);
1N/A }
1N/A}
1N/A
1N/A/*
1N/A * Determine whether an ENM should be (de)activated.
1N/A */
1N/A/* ARGSUSED1 */
1N/Astatic int
1N/Anwamd_enm_check(nwamd_object_t object, void *data)
1N/A{
1N/A nwam_enm_handle_t enmh;
1N/A nwam_value_t conditionval;
1N/A int64_t eactivation;
1N/A boolean_t enabled, satisfied;
1N/A char **conditions;
1N/A nwam_state_t state;
1N/A uint_t nelem;
1N/A
1N/A state = object->nwamd_object_state;
1N/A
1N/A enmh = object->nwamd_object_handle;
1N/A
1N/A eactivation = enm_get_activation_mode(enmh);
1N/A if (eactivation == -1)
1N/A return (0);
1N/A
1N/A switch (eactivation) {
1N/A case NWAM_ACTIVATION_MODE_MANUAL:
1N/A enabled = enm_is_enabled(enmh);
1N/A
1N/A if (enabled) {
1N/A nlog(LOG_DEBUG, "nwamd_enm_check: %s is enabled",
1N/A object->nwamd_object_name);
1N/A switch (state) {
1N/A case NWAM_STATE_ONLINE:
1N/A case NWAM_STATE_MAINTENANCE:
1N/A /* Do nothing */
1N/A break;
1N/A default:
1N/A if (nwamd_enm_action(object->nwamd_object_name,
1N/A NWAM_ACTION_ENABLE) != 0) {
1N/A nlog(LOG_ERR,
1N/A "nwamd_enm_check: enable failed "
1N/A "for enm %s",
1N/A object->nwamd_object_name);
1N/A }
1N/A break;
1N/A }
1N/A } else {
1N/A nlog(LOG_DEBUG, "nwamd_enm_check: %s is disabled",
1N/A object->nwamd_object_name);
1N/A switch (state) {
1N/A case NWAM_STATE_ONLINE:
1N/A if (nwamd_enm_action(object->nwamd_object_name,
1N/A NWAM_ACTION_DISABLE) != 0) {
1N/A nlog(LOG_ERR, "nwamd_enm_check: "
1N/A "disable failed for enm %s",
1N/A object->nwamd_object_name);
1N/A }
1N/A break;
1N/A case NWAM_STATE_MAINTENANCE:
1N/A /* Do nothing */
1N/A break;
1N/A case NWAM_STATE_DISABLED:
1N/A /* Do nothing */
1N/A break;
1N/A default:
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name,
1N/A NWAM_STATE_DISABLED,
1N/A NWAM_AUX_STATE_MANUAL_DISABLE);
1N/A break;
1N/A }
1N/A }
1N/A break;
1N/A
1N/A case NWAM_ACTIVATION_MODE_CONDITIONAL_ANY:
1N/A case NWAM_ACTIVATION_MODE_CONDITIONAL_ALL:
1N/A if (nwam_enm_get_prop_value(enmh,
1N/A NWAM_ENM_PROP_CONDITIONS, &conditionval) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "nwamd_enm_check: could not retrieve "
1N/A "condition value");
1N/A break;
1N/A }
1N/A if (nwam_value_get_string_array(conditionval,
1N/A &conditions, &nelem) != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "nwamd_enm_check: could not retrieve "
1N/A "condition value");
1N/A nwam_value_free(conditionval);
1N/A break;
1N/A }
1N/A satisfied = nwamd_check_conditions((uint64_t)eactivation,
1N/A conditions, nelem);
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_check: conditions for enm %s "
1N/A "%s satisfied", object->nwamd_object_name,
1N/A satisfied ? "is" : "is not");
1N/A if (state != NWAM_STATE_ONLINE && satisfied) {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name,
1N/A NWAM_STATE_OFFLINE_TO_ONLINE,
1N/A NWAM_AUX_STATE_METHOD_RUNNING);
1N/A }
1N/A if (state == NWAM_STATE_ONLINE && !satisfied) {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A object->nwamd_object_name,
1N/A NWAM_STATE_ONLINE_TO_OFFLINE,
1N/A NWAM_AUX_STATE_CONDITIONS_NOT_MET);
1N/A }
1N/A nwam_value_free(conditionval);
1N/A break;
1N/A
1N/A }
1N/A return (0);
1N/A}
1N/A
1N/Avoid
1N/Anwamd_enm_check_conditions(void)
1N/A{
1N/A (void) nwamd_walk_objects(NWAM_OBJECT_TYPE_ENM, nwamd_enm_check, NULL);
1N/A}
1N/A
1N/Aint
1N/Anwamd_enm_action(const char *enm, nwam_action_t action)
1N/A{
1N/A nwamd_event_t event = nwamd_event_init_object_action
1N/A (NWAM_OBJECT_TYPE_ENM, enm, NULL, action);
1N/A if (event == NULL)
1N/A return (1);
1N/A nwamd_event_enqueue(event);
1N/A return (0);
1N/A}
1N/A
1N/A/*
1N/A * Event handling functions.
1N/A */
1N/A
1N/A/* Handle ENM initialization/refresh event */
1N/Avoid
1N/Anwamd_enm_handle_init_event(nwamd_event_t event)
1N/A{
1N/A nwamd_object_t object;
1N/A nwam_enm_handle_t enmh;
1N/A nwam_error_t err;
1N/A boolean_t manual_disabled = B_FALSE;
1N/A
1N/A if ((err = nwam_enm_read(event->event_object, 0, &enmh))
1N/A != NWAM_SUCCESS) {
1N/A nlog(LOG_ERR, "nwamd_enm_handle_init_event: could not "
1N/A "read object '%s': %s", event->event_object,
1N/A nwam_strerror(err));
1N/A nwamd_event_do_not_send(event);
1N/A return;
1N/A }
1N/A if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object)) != NULL) {
1N/A nwam_enm_free(object->nwamd_object_handle);
1N/A object->nwamd_object_handle = enmh;
1N/A } else {
1N/A object = nwamd_object_init(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object, enmh, NULL);
1N/A object->nwamd_object_state = NWAM_STATE_OFFLINE;
1N/A object->nwamd_object_aux_state =
1N/A NWAM_AUX_STATE_CONDITIONS_NOT_MET;
1N/A }
1N/A manual_disabled = (enm_get_activation_mode(enmh) ==
1N/A NWAM_ACTIVATION_MODE_MANUAL && !enm_is_enabled(enmh));
1N/A
1N/A /*
1N/A * If this ENM is ONLINE, and not manual and disabled (since in
1N/A * that case it was online but we've just set enabled = false as part
1N/A * of a disable action), then it is still active but refreshing.
1N/A * Change states to re-activate itself.
1N/A */
1N/A if (!manual_disabled &&
1N/A object->nwamd_object_state == NWAM_STATE_ONLINE) {
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
1N/A NWAM_AUX_STATE_METHOD_RUNNING);
1N/A }
1N/A nwamd_object_release(object);
1N/A}
1N/A
1N/A/* Handle ENM finish event */
1N/Avoid
1N/Anwamd_enm_handle_fini_event(nwamd_event_t event)
1N/A{
1N/A nwamd_event_t state_event;
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_handle_fini_event(%s)", event->event_object);
1N/A
1N/A /*
1N/A * Simulate a state event so that the state machine can correctly
1N/A * deactivate the ENM and free up the handle.
1N/A */
1N/A state_event = nwamd_event_init_object_state(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1N/A NWAM_AUX_STATE_UNINITIALIZED);
1N/A if (state_event == NULL) {
1N/A nwamd_event_do_not_send(event);
1N/A return;
1N/A }
1N/A nwamd_enm_handle_state_event(state_event);
1N/A nwamd_event_fini(state_event);
1N/A /*
1N/A * Do not free the handle and object.
1N/A * nwamd_enm_activate_deactivate_thread() and
1N/A * nwamd_enm_deactivate() does this after running the stop script
1N/A * and disabling the FMRI respectively.
1N/A */
1N/A}
1N/A
1N/Avoid
1N/Anwamd_enm_handle_action_event(nwamd_event_t event)
1N/A{
1N/A nwamd_object_t object;
1N/A
1N/A switch (event->event_msg->nwe_data.nwe_object_action.nwe_action) {
1N/A case NWAM_ACTION_ENABLE:
1N/A object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object);
1N/A if (object == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_handle_action_event: "
1N/A "could not find enm %s", event->event_object);
1N/A nwamd_event_do_not_send(event);
1N/A return;
1N/A }
1N/A if (object->nwamd_object_state == NWAM_STATE_ONLINE) {
1N/A nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: "
1N/A "enm %s already online, nothing to do",
1N/A event->event_object);
1N/A nwamd_object_release(object);
1N/A return;
1N/A }
1N/A nwamd_object_release(object);
1N/A
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
1N/A NWAM_AUX_STATE_METHOD_RUNNING);
1N/A break;
1N/A case NWAM_ACTION_DISABLE:
1N/A object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object);
1N/A if (object == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_handle_action_event: "
1N/A "could not find enm %s", event->event_object);
1N/A nwamd_event_do_not_send(event);
1N/A return;
1N/A }
1N/A if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
1N/A nlog(LOG_DEBUG, "nwamd_enm_handle_action_event: "
1N/A "enm %s already disabled, nothing to do",
1N/A event->event_object);
1N/A nwamd_object_release(object);
1N/A return;
1N/A }
1N/A nwamd_object_release(object);
1N/A
1N/A nwamd_object_set_state(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object, NWAM_STATE_ONLINE_TO_OFFLINE,
1N/A NWAM_AUX_STATE_MANUAL_DISABLE);
1N/A break;
1N/A case NWAM_ACTION_ADD:
1N/A case NWAM_ACTION_REFRESH:
1N/A nwamd_enm_handle_init_event(event);
1N/A break;
1N/A case NWAM_ACTION_DESTROY:
1N/A nwamd_enm_handle_fini_event(event);
1N/A break;
1N/A default:
1N/A nlog(LOG_INFO, "nwam_enm_handle_action_event: "
1N/A "unexpected action");
1N/A nwamd_event_do_not_send(event);
1N/A break;
1N/A }
1N/A}
1N/A
1N/Avoid
1N/Anwamd_enm_handle_state_event(nwamd_event_t event)
1N/A{
1N/A nwamd_object_t object;
1N/A nwam_state_t new_state;
1N/A nwam_aux_state_t new_aux_state;
1N/A
1N/A if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_ENM,
1N/A event->event_object)) == NULL) {
1N/A nlog(LOG_ERR, "nwamd_enm_handle_state_event: "
1N/A "state event for nonexistent ENM %s", event->event_object);
1N/A nwamd_event_do_not_send(event);
1N/A return;
1N/A }
1N/A new_state = event->event_msg->nwe_data.nwe_object_state.nwe_state;
1N/A new_aux_state =
1N/A event->event_msg->nwe_data.nwe_object_state.nwe_aux_state;
1N/A
1N/A if (new_state == object->nwamd_object_state &&
1N/A new_aux_state == object->nwamd_object_aux_state) {
1N/A nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: "
1N/A "ENM %s already in state (%s , %s)",
1N/A object->nwamd_object_name, nwam_state_to_string(new_state),
1N/A nwam_aux_state_to_string(new_aux_state));
1N/A nwamd_object_release(object);
1N/A return;
1N/A }
1N/A
1N/A object->nwamd_object_state = new_state;
1N/A object->nwamd_object_aux_state = new_aux_state;
1N/A
1N/A nlog(LOG_DEBUG, "nwamd_enm_handle_state_event: changing state for ENM "
1N/A "%s to (%s , %s)", object->nwamd_object_name,
1N/A nwam_state_to_string(object->nwamd_object_state),
1N/A nwam_aux_state_to_string(object->nwamd_object_aux_state));
1N/A
1N/A nwamd_object_release(object);
1N/A
1N/A /*
1N/A * State machine for ENMs.
1N/A */
1N/A switch (new_state) {
1N/A case NWAM_STATE_OFFLINE_TO_ONLINE:
1N/A nwamd_enm_activate(event->event_object);
1N/A break;
1N/A case NWAM_STATE_ONLINE_TO_OFFLINE:
1N/A nwamd_enm_deactivate(event->event_object);
1N/A break;
1N/A case NWAM_STATE_DISABLED:
1N/A case NWAM_STATE_OFFLINE:
1N/A case NWAM_STATE_UNINITIALIZED:
1N/A case NWAM_STATE_MAINTENANCE:
1N/A case NWAM_STATE_DEGRADED:
1N/A default:
1N/A /* do nothing */
1N/A break;
1N/A }
1N/A}
1N/A