Example #1
0
static void
__ni_ifup_pull_in_children(ni_ifworker_t *w, ni_ifworker_array_t *array)
{
	unsigned int i;

	for (i = 0; i < w->children.count; i++) {
		ni_ifworker_t *child = w->children.data[i];

		if (ni_ifworker_array_index(array, child) < 0)
			ni_ifworker_array_append(array, child);
		__ni_ifup_pull_in_children(child, array);
	}
}
Example #2
0
static void
ni_virtual_device_up(ni_fsm_t *fsm, ni_ifworker_t *w)
{
	ni_ifworker_array_t ifmarked;

	ni_assert(fsm && w);

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

	w->target_range.min = NI_FSM_STATE_ADDRCONF_UP;
	w->target_range.max = __NI_FSM_STATE_MAX;

	ni_ifworker_array_append(&ifmarked, w);
	ni_fsm_start_matching_workers(fsm, &ifmarked);

	ni_ifworker_array_destroy(&ifmarked);
}
Example #3
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 #4
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 #5
0
int
ni_do_ifreload(int argc, char **argv)
{
	enum  { OPT_HELP, OPT_IFCONFIG, OPT_PERSISTENT, OPT_TRANSIENT,
#ifdef NI_TEST_HACKS
		OPT_IGNORE_PRIO, OPT_IGNORE_STARTMODE,
#endif
	};

	static struct option ifreload_options[] = {
		{ "help",	no_argument,       NULL, OPT_HELP       },
		{ "transient", 	no_argument,       NULL, OPT_TRANSIENT },
		{ "ifconfig",	required_argument, NULL, OPT_IFCONFIG   },
#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,		no_argument,	   NULL, 0              }
	};
	ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT;
	ni_ifworker_array_t marked = { 0, NULL };
	ni_ifmatcher_t ifmatch;
	ni_bool_t check_prio = TRUE;
	ni_bool_t opt_persistent = FALSE;
	ni_bool_t opt_transient = FALSE;
	int c, status = NI_WICKED_RC_USAGE;
	unsigned int nmarked, i;
	const ni_uint_range_t up_range = {
		.min = NI_FSM_STATE_ADDRCONF_UP,
		.max = __NI_FSM_STATE_MAX
	};
	const char *ptr;
	ni_fsm_t *fsm;

	/* Allow ifreload on all interfaces with a changed config */
	memset(&ifmatch, 0, sizeof(ifmatch));
	ifmatch.require_configured = FALSE;
	ifmatch.allow_persistent = TRUE;
	ifmatch.require_config = FALSE;

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

	/*
	 * 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);
			fsm->worker_timeout = sec * 1000;
		}
	}

	optind = 1;
	while ((c = getopt_long(argc, argv, "", ifreload_options, NULL)) != EOF) {
		switch (c) {
		case OPT_IFCONFIG:
			ni_string_array_append(&opt_ifconfig, optarg);
			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:
			opt_persistent = TRUE;
			break;

		case OPT_TRANSIENT:
			opt_transient = TRUE;
			break;

		default:
		case OPT_HELP:
usage:
			fprintf(stderr,
				"wicked [options] ifreload [ifreload-options] <ifname ...>|all\n"
				"\nSupported ifreload-options:\n"
				"  --help\n"
				"      Show this help text.\n"
				"  --transient\n"
				"      Enable transient interface return codes\n"
				"  --ifconfig <filename>\n"
				"      Read interface configuration(s) from file\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;
		}
	}

	/* at least one argument is required */
	if (optind >= argc) {
		fprintf(stderr, "Missing interface argument\n");
		goto usage;
	} else for (c = optind; c < argc; ++c) {
			if (ni_string_empty(argv[c])) {
				printf("ARG: %s\n", argv[c]);
				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("ifreload: 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;
	}

	status = NI_WICKED_RC_SUCCESS;
	nmarked = 0;
	for (c = optind; c < argc; ++c) {
		ni_ifworker_array_t temp = { 0, NULL };

		/* Getting an array of ifworkers matching argument */
		ifmatch.name = argv[c];
		if (!ni_fsm_get_matching_workers(fsm, &ifmatch, &temp))
			continue;

		for (i = 0; i < temp.count; ++i) {
			ni_ifworker_t *w = temp.data[i];
			ni_netdev_t *dev = w->device;

			/* skip duplicate matches */
			if (ni_ifworker_array_index(&marked, w) != -1)
				continue;

			/* skip unused devices without config */
			if (!ni_ifcheck_worker_config_exists(w) &&
			    !ni_ifcheck_device_configured(dev))
				continue;

			/* skip if config changed somehow */
			if (ni_ifcheck_worker_config_matches(w))
				continue;

			/* Mark persistend when requested */
			if (opt_persistent)
				w->client_state.persistent = TRUE;

			/* Remember all changed devices */
			ni_ifworker_array_append(&marked, w);

			/* Persistent do not go down but up only */
			if (!dev || ni_ifcheck_device_is_persistent(dev))
				continue;

			/* Decide how much down we go */
			if (ni_ifcheck_worker_config_exists(w)) {
				if (!ni_ifcheck_device_configured(dev))
					continue;
				w->target_range.min = NI_FSM_STATE_NONE;
				w->target_range.max = NI_FSM_STATE_DEVICE_READY;
				nmarked++;
			} else
			if (ni_ifcheck_device_configured(dev)) {
				w->target_range.min = NI_FSM_STATE_NONE;
				w->target_range.max = NI_FSM_STATE_DEVICE_DOWN;
				nmarked++;
			}
		}
		ni_ifworker_array_destroy(&temp);
	}

	if (nmarked) {
		/* Run ifdown part of the reload */
		ni_debug_application("Shutting down unneeded devices");
		ni_fsm_start_matching_workers(fsm, &marked);

		/* Execute the down run */
		if (ni_fsm_schedule(fsm) != 0)
			ni_fsm_mainloop(fsm);

	}

	if (marked.count) {

		/* Drop deleted or apply the up range */
		ni_fsm_reset_matching_workers(fsm, &marked, &up_range, FALSE);

		/* And trigger up */
		ni_debug_application("Reloading all changed devices");
		ni_ifup_pull_in_children(&marked);
		nmarked = ni_fsm_start_matching_workers(fsm, &marked);

		ni_ifworker_array_destroy(&marked);
	}

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

		/* Execute the up run */
		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_string_array_destroy(&opt_ifconfig);
	ni_ifworker_array_destroy(&marked);
	return status;
}