Example #1
0
static int
ni_factory_device_up(ni_fsm_t *fsm, ni_ifworker_t *w)
{
	ni_ifworker_array_t ifmarked = NI_IFWORKER_ARRAY_INIT;
	ni_ifmarker_t ifmarker;

	ni_assert(fsm && w);
	memset(&ifmarker, 0, sizeof(ifmarker));

	ifmarker.target_range.min = NI_FSM_STATE_ADDRCONF_UP;
	ifmarker.target_range.max = __NI_FSM_STATE_MAX;
	ifmarker.persistent = w->control.persistent;

	ni_ifworker_array_append(&ifmarked, w);
	ni_fsm_pull_in_children(&ifmarked);

	ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker);
	ni_ifworker_array_destroy(&ifmarked);

	return 0;
}
Example #2
0
/*
 * Bring up the device
 */
static int
ni_managed_device_up(ni_managed_device_t *mdev, const char *origin)
{
	ni_fsm_t *fsm = mdev->nanny->fsm;
	ni_ifworker_t *w = mdev->worker;
	unsigned int previous_state;
	unsigned int target_state;
	ni_security_id_t security_id = NI_SECURITY_ID_INIT;
	ni_ifworker_array_t ifmarked = NI_IFWORKER_ARRAY_INIT;
	ni_ifmarker_t ifmarker;
	int rv = -NI_ERROR_DEVICE_NOT_COMPATIBLE;

	memset(&ifmarker, 0, sizeof(ifmarker));

	switch (w->type) {
	case NI_IFWORKER_TYPE_NETDEV:
		mdev->max_fail_count = 3;
		if (w->device->link.type == NI_IFTYPE_WIRELESS) {
			const char *essid;

			ni_security_id_init(&security_id, "wireless");
			if ((essid = ni_managed_device_get_essid(mdev->selected_config)) != NULL)
				ni_security_id_set_attr(&security_id, "essid", essid);
		}

		target_state = NI_FSM_STATE_ADDRCONF_UP;
		break;

	case NI_IFWORKER_TYPE_MODEM:
		mdev->max_fail_count = 1;

		ni_security_id_init(&security_id, "modem");
		if (w->modem->identify.equipment)
			ni_security_id_set_attr(&security_id, "equipment-id", w->modem->identify.equipment);

		target_state = NI_FSM_STATE_LINK_UP;
		break;

	default:
		goto failed;
	}

	if (ni_security_id_valid(&security_id))
		ni_managed_device_set_security_id(mdev, &security_id);

	ni_ifworker_set_completion_callback(w, ni_managed_device_up_done, mdev->nanny);

	ni_ifworker_set_config(w, mdev->selected_config, origin);

	ifmarker.target_range.min = target_state;
	ifmarker.target_range.max = __NI_FSM_STATE_MAX;
	ifmarker.persistent = w->control.persistent;

	ni_ifworker_array_append(&ifmarked, w);
	ni_fsm_pull_in_children(&ifmarked);

	/* Binding: this validates the XML configuration document,
	 * resolves any references to other devices (if there are any),
	 * and retrieves any keys/passwords etc via the prompt callback.
	 * Inside the prompt callback, we record all secrets for tracking
	 */
	ni_secret_array_destroy(&mdev->secrets);

	previous_state = mdev->state;
	mdev->state = NI_MANAGED_STATE_BINDING;
	if ((rv = ni_ifworker_bind_early(w, fsm, TRUE)) < 0)
		goto failed;

	if (mdev->missing_secrets) {
		/* FIXME: Emit an event listing the secrets we're missing.
		 */
		mdev->state = previous_state;
		return -1;
	}

	mdev->state = NI_MANAGED_STATE_STARTING;
	ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker);
	ni_ifworker_array_destroy(&ifmarked);

	return 0;

failed:
	ni_error("%s: cannot start device: %s", w->name, ni_strerror(rv));
	mdev->state = NI_MANAGED_STATE_FAILED;
	return -1;
}
Example #3
0
int
ni_do_ifdown(int argc, char **argv)
{
	enum  { OPT_HELP, OPT_FORCE, OPT_DELETE, OPT_NO_DELETE, OPT_TIMEOUT };
	static struct option ifdown_options[] = {
		{ "help",	no_argument, NULL,		OPT_HELP },
		{ "force",	required_argument, NULL,	OPT_FORCE },
		{ "delete",	no_argument, NULL,	OPT_DELETE },
		{ "no-delete",	no_argument, NULL,	OPT_NO_DELETE },
		{ "timeout",	required_argument, NULL,	OPT_TIMEOUT },
		{ NULL }
	};
	ni_ifmatcher_t ifmatch;
	ni_ifmarker_t ifmarker;
	ni_ifworker_array_t ifmarked;
	ni_string_array_t ifnames = NI_STRING_ARRAY_INIT;
	unsigned int nmarked, max_state = NI_FSM_STATE_DEVICE_DOWN;
	unsigned int timeout = NI_IFWORKER_DEFAULT_TIMEOUT;
	ni_stringbuf_t sb = NI_STRINGBUF_INIT_DYNAMIC;
	ni_fsm_t *fsm;
	int c, status = NI_WICKED_RC_USAGE;

	fsm = ni_fsm_new();
	ni_assert(fsm);
	ni_fsm_require_register_type("reachable", ni_ifworker_reachability_check_new);

	/* Allow ifdown only on non-persistent interfaces previously configured by ifup */
	memset(&ifmatch, 0, sizeof(ifmatch));
	memset(&ifmarker, 0, sizeof(ifmarker));
	memset(&ifmarked, 0, sizeof(ifmarked));

	ifmatch.require_configured = TRUE;
	ifmatch.allow_persistent = FALSE;
	ifmatch.require_config = FALSE;

	ifmarker.target_range.min = NI_FSM_STATE_DEVICE_DOWN;
	ifmarker.target_range.max = __NI_FSM_STATE_MAX - 2;

	optind = 1;
	while ((c = getopt_long(argc, argv, "", ifdown_options, NULL)) != EOF) {
		switch (c) {
		case OPT_FORCE:
			if (!ni_ifworker_state_from_name(optarg, &max_state) ||
			    !ni_ifworker_state_in_range(&ifmarker.target_range, max_state)) {
				ni_error("ifdown: wrong force option \"%s\"", optarg);
				goto usage;
			}
			/* Allow ifdown on persistent, unconfigured interfaces */
			ifmatch.require_configured = FALSE;
			ifmatch.allow_persistent = TRUE;
			ifmatch.require_config = FALSE;
			break;

		case OPT_DELETE:
			max_state = NI_FSM_STATE_DEVICE_DOWN;
			/* Allow ifdown on persistent, unconfigured interfaces */
			ifmatch.require_configured = FALSE;
			ifmatch.allow_persistent = TRUE;
			ifmatch.require_config = FALSE;
			break;

		case OPT_NO_DELETE:
			max_state = NI_FSM_STATE_DEVICE_READY;
			/* Allow ifdown only on non-persistent interfaces previously configured by ifup */
			ifmatch.require_configured = TRUE;
			ifmatch.allow_persistent = FALSE;
			ifmatch.require_config = FALSE;
			break;

		case OPT_TIMEOUT:
			if (!strcmp(optarg, "infinite")) {
				timeout = NI_IFWORKER_INFINITE_TIMEOUT;
			} else if (ni_parse_uint(optarg, &timeout, 10) >= 0) {
				timeout *= 1000; /* sec -> msec */
			} else {
				ni_error("ifdown: cannot parse timeout option \"%s\"", optarg);
				goto usage;
			}
			break;

		default:
		case OPT_HELP:
usage:
			ni_client_get_state_strings(&sb, &ifmarker.target_range);
			fprintf(stderr,
				"wicked [options] ifdown [ifdown-options] <ifname ...>|all\n"
				"\nSupported ifdown-options:\n"
				"  --help\n"
				"      Show this help text.\n"
				"  --force <state>\n"
				"      Force putting interface into the <state> state. Despite of persistent mode being set. Possible states:\n"
				"  %s\n"
				"  --delete\n"
				"      Delete device. Despite of persistent mode being set\n"
				"  --no-delete\n"
				"      Do not attempt to delete a device, neither physical nor virtual\n"
				"  --timeout <nsec>\n"
				"      Timeout after <nsec> seconds\n",
				sb.string
				);
			ni_stringbuf_destroy(&sb);
			return status;
		}
	}

	if (optind >= argc) {
		fprintf(stderr, "Missing interface argument\n");
		goto usage;
	}

	ifmarker.target_range.min = NI_FSM_STATE_NONE;
	ifmarker.target_range.max = max_state;

	fsm->worker_timeout = ni_fsm_find_max_timeout(fsm, timeout);

	if (!ni_fsm_create_client(fsm)) {
		/* Severe error we always explicitly return */
		return NI_WICKED_RC_ERROR;
	}

	if (!ni_fsm_refresh_state(fsm)) {
		/* Severe error we always explicitly return */
		return NI_WICKED_RC_ERROR;
	}

	/* Get workers that match given criteria */
	nmarked = 0;
	while (optind < argc) {
		ifmatch.name = argv[optind++];
		ifmatch.ifdown = TRUE;
		ni_fsm_get_matching_workers(fsm, &ifmatch, &ifmarked);

		if (ni_string_eq(ifmatch.name, "all") ||
		    ni_string_empty(ifmatch.name)) {
			ni_string_array_destroy(&ifnames);
			break;
		}

		if (ni_string_array_index(&ifnames, ifmatch.name) == -1)
			ni_string_array_append(&ifnames, ifmatch.name);
	}

	/* Mark and start selected workers */
	if (ifmarked.count) {
		if (ni_config_use_nanny()) {
			/* Disable devices and delete all related policies from nanny */
			ni_ifdown_fire_nanny(&ifmarked);
		}

		/* Start workers to perform actual ifdown */
		nmarked = ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker);
	}

	if (nmarked == 0) {
		ni_note("ifdown: no matching interfaces");
		status = NI_WICKED_RC_SUCCESS;
	} else {
		if (ni_fsm_schedule(fsm) != 0)
			ni_fsm_mainloop(fsm);

		status = ni_ifstatus_shutdown_result(fsm, &ifnames, &ifmarked);
	}

	ni_string_array_destroy(&ifnames);
	ni_ifworker_array_destroy(&ifmarked);
	return status;
}
Example #4
0
static int
ni_do_ifup_direct(int argc, char **argv)
{
	enum  { OPT_HELP, OPT_IFCONFIG, OPT_CONTROL_MODE, OPT_STAGE, OPT_TIMEOUT,
		OPT_SKIP_ACTIVE, OPT_SKIP_ORIGIN, OPT_PERSISTENT, OPT_TRANSIENT,
#ifdef NI_TEST_HACKS
		OPT_IGNORE_PRIO, OPT_IGNORE_STARTMODE,
#endif
	};

	static struct option ifup_options[] = {
		{ "help",	no_argument,       NULL,	OPT_HELP },
		{ "ifconfig",	required_argument, NULL,	OPT_IFCONFIG },
		{ "mode",	required_argument, NULL,	OPT_CONTROL_MODE },
		{ "boot-stage",	required_argument, NULL,	OPT_STAGE },
		{ "skip-active",required_argument, NULL,	OPT_SKIP_ACTIVE },
		{ "skip-origin",required_argument, NULL,	OPT_SKIP_ORIGIN },
		{ "timeout",	required_argument, NULL,	OPT_TIMEOUT },
		{ "transient", 	no_argument,		NULL,	OPT_TRANSIENT },
#ifdef NI_TEST_HACKS
		{ "ignore-prio",no_argument, NULL,	OPT_IGNORE_PRIO },
		{ "ignore-startmode",no_argument, NULL,	OPT_IGNORE_STARTMODE },
#endif
		{ "persistent",	no_argument, NULL,	OPT_PERSISTENT },
		{ NULL }
	};

	ni_ifmatcher_t ifmatch;
	ni_ifmarker_t ifmarker;
	ni_ifworker_array_t ifmarked;
	ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT;
	ni_bool_t check_prio = TRUE;
	ni_bool_t opt_transient = FALSE;
	unsigned int nmarked;
	ni_fsm_t *fsm;
	int c, status = NI_WICKED_RC_USAGE;
	unsigned int timeout = 0;
	const char *ptr;

	fsm = ni_fsm_new();
	ni_assert(fsm);
	ni_fsm_require_register_type("reachable", ni_ifworker_reachability_check_new);

	memset(&ifmatch, 0, sizeof(ifmatch));
	memset(&ifmarker, 0, sizeof(ifmarker));
	memset(&ifmarked, 0, sizeof(ifmarked));

	/* Allow ifup on all interfaces we have config for */
	ifmatch.require_configured = FALSE;
	ifmatch.allow_persistent = TRUE;
	ifmatch.require_config = TRUE;

	ifmarker.target_range.min = NI_FSM_STATE_ADDRCONF_UP;
	ifmarker.target_range.max = __NI_FSM_STATE_MAX;

	/*
	 * Workaround to consider WAIT_FOR_INTERFACES variable
	 * in network/config (bnc#863371, bnc#862530 timeouts).
	 * Correct would be to get it from compat layer, but
	 * the network/config is sourced in systemd service...
	 */
	if ((ptr = getenv("WAIT_FOR_INTERFACES"))) {
		unsigned int sec;

		if (ni_parse_uint(ptr, &sec, 10) == 0 &&
		    (sec * 1000 > fsm->worker_timeout)) {
			ni_debug_application("wait %u sec for interfaces", sec);
			timeout = sec * 1000;
		}
	}

	optind = 1;
	while ((c = getopt_long(argc, argv, "", ifup_options, NULL)) != EOF) {
		switch (c) {
		case OPT_IFCONFIG:
			ni_string_array_append(&opt_ifconfig, optarg);
			break;

		case OPT_CONTROL_MODE:
			ifmatch.mode = optarg;
			break;

		case OPT_STAGE:
			ifmatch.boot_stage= optarg;
			break;

		case OPT_TIMEOUT:
			if (!strcmp(optarg, "infinite")) {
				timeout = NI_IFWORKER_INFINITE_TIMEOUT;
			} else if (ni_parse_uint(optarg, &timeout, 10) >= 0) {
				timeout *= 1000; /* sec -> msec */
			} else {
				ni_error("ifup: cannot parse timeout option \"%s\"", optarg);
				goto usage;
			}
			break;

		case OPT_SKIP_ORIGIN:
			ifmatch.skip_origin = optarg;
			break;

		case OPT_SKIP_ACTIVE:
			ifmatch.skip_active = TRUE;
			break;

#ifdef NI_TEST_HACKS
		case OPT_IGNORE_PRIO:
			check_prio = FALSE;
			break;

		case OPT_IGNORE_STARTMODE:
			ifmatch.ignore_startmode = TRUE;
			break;
#endif

		case OPT_PERSISTENT:
			ifmarker.persistent = TRUE;
			break;

		case OPT_TRANSIENT:
			opt_transient = TRUE;
			break;

		default:
		case OPT_HELP:
usage:
			fprintf(stderr,
				"wicked [options] ifup [ifup-options] <ifname ...>|all\n"
				"\nSupported ifup-options:\n"
				"  --help\n"
				"      Show this help text.\n"
				"  --transient\n"
				"      Enable transient interface return codes\n"
				"  --ifconfig <pathname>\n"
				"      Read interface configuration(s) from file/directory rather than using system config\n"
				"  --mode <label>\n"
				"      Only touch interfaces with matching control <mode>\n"
				"  --boot-stage <label>\n"
				"      Only touch interfaces with matching <boot-stage>\n"
				"  --skip-active\n"
				"      Do not touch running interfaces\n"
				"  --skip-origin <name>\n"
				"      Skip interfaces that have a configuration origin of <name>\n"
				"      Usually, you would use this with the name \"firmware\" to avoid\n"
				"      touching interfaces that have been set up via firmware (like iBFT) previously\n"
				"  --timeout <nsec>\n"
				"      Timeout after <nsec> seconds\n"
#ifdef NI_TEST_HACKS
				"  --ignore-prio\n"
				"      Ignore checking the config origin priorities\n"
				"  --ignore-startmode\n"
				"      Ignore checking the STARTMODE=off and STARTMODE=manual configs\n"
#endif
				"  --persistent\n"
				"      Set interface into persistent mode (no regular ifdown allowed)\n"
				);
			goto cleanup;
		}
	}

	if (optind >= argc) {
		fprintf(stderr, "Missing interface argument\n");
		goto usage;
	}

	if (!ni_fsm_create_client(fsm)) {
		/* Severe error we always explicitly return */
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}

	if (!ni_fsm_refresh_state(fsm)) {
		/* Severe error we always explicitly return */
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}

	if (opt_ifconfig.count == 0) {
		const ni_string_array_t *sources = ni_config_sources("ifconfig");

		if (sources && sources->count)
			ni_string_array_copy(&opt_ifconfig, sources);

		if (opt_ifconfig.count == 0) {
			ni_error("ifup: unable to load interface config source list");
			status = NI_WICKED_RC_NOT_CONFIGURED;
			goto cleanup;
		}
	}

	if (!ni_ifconfig_load(fsm, opt_global_rootdir, &opt_ifconfig, check_prio, TRUE)) {
		status = NI_WICKED_RC_NOT_CONFIGURED;
		goto cleanup;
	}

	/* Client waits for device-up events for WAIT_FOR_INTERFACES */
	if (timeout)
		ni_wait_for_interfaces = timeout; /* One set by user */
	else
		ni_wait_for_interfaces *= 1000;   /* in msec */

	if (ni_fsm_build_hierarchy(fsm) < 0) {
		ni_error("ifup: unable to build device hierarchy");
		/* Severe error we always explicitly return */
		status = NI_WICKED_RC_ERROR;
		goto cleanup;
	}

	/* Get workers that match given criteria */
	nmarked = 0;
	while (optind < argc) {
		ifmatch.name = argv[optind++];

		if (!strcmp(ifmatch.name, "boot")) {
			ifmatch.name = "all";
			ifmatch.mode = "boot";
		}

		ni_fsm_get_matching_workers(fsm, &ifmatch, &ifmarked);
	}

	ni_ifup_pull_in_children(&ifmarked);

	/* Mark and start selected workers */
	if (ifmarked.count)
		nmarked = ni_fsm_mark_matching_workers(fsm, &ifmarked, &ifmarker);

	if (nmarked == 0) {
		printf("ifup: no matching interfaces\n");
		status = NI_WICKED_RC_SUCCESS;
	} else {
		if (ni_fsm_schedule(fsm) != 0)
			ni_fsm_mainloop(fsm);

		/* No error if all interfaces were good */
		status = ni_fsm_fail_count(fsm) ?
			NI_WICKED_RC_ERROR : NI_WICKED_RC_SUCCESS;

		/* Do not report any transient errors to systemd (e.g. dhcp
		 * or whatever not ready in time) -- returning an error may
		 * cause to stop the network completely.
		 */
		if (!opt_transient)
			status = NI_LSB_RC_SUCCESS;
	}

cleanup:
	ni_ifworker_array_destroy(&ifmarked);
	ni_string_array_destroy(&opt_ifconfig);
	return status;
}