Exemple #1
0
static ni_bool_t
ni_ifdown_stop_device(const char *device_name)
{
	if (!ni_nanny_call_device_disable(device_name)) {
		ni_debug_application("Unable to disable device named %s", device_name);
		return FALSE;
	}

	return TRUE;
}
Exemple #2
0
/*
 * Wickedd is sending us a signal indicating internal device state change.
 * We want to wait for this signal and when it is >= device-up return TRUE.
 * After timeout we fail...
 */
void
ni_state_change_signal_handler(ni_dbus_connection_t *conn, ni_dbus_message_t *msg, void *user_data)
{
	const char *signal_name = dbus_message_get_member(msg);
	const char *object_path = dbus_message_get_path(msg);
	ni_dbus_variant_t argv = NI_DBUS_VARIANT_INIT;
	ni_ifworker_array_t *ifworkers = user_data;
	ni_fsm_state_t cur_state, target_state;
	const char *ifname;
	unsigned int i;

	if (ni_string_empty(object_path))
		return;

	/* Deserialize dbus message */
	if (ni_dbus_message_get_args_variants(msg, &argv, 1) < 0 ||
	    !ni_dbus_variant_is_dict(&argv)) {
		ni_error("Unable to retrieve dict from signal %s,  object_path=%s",
			signal_name, object_path);
		return;
	}

	if (!ni_dbus_dict_get_uint32(&argv, "current-state", &cur_state) ||
	    !ni_dbus_dict_get_uint32(&argv, "target-state", &target_state) ||
	    !ni_dbus_dict_get_string(&argv, "ifname", &ifname)) {
		ni_error("Unable to retrieve dict's values from signal %s,  object_path=%s",
			signal_name, object_path);
		return;
	}

	ni_debug_application("received signal %s; object_path=%s; target_state=%s, state_name=%s",
		signal_name, object_path,  ni_ifworker_state_name(target_state),
		ni_ifworker_state_name(cur_state));

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

		if (cur_state != NI_FSM_STATE_NONE && cur_state != target_state)
			continue;

		if (!ni_string_eq(w->name, ifname))
			continue;

		ni_warn("%s: Device %s", ifname, cur_state == target_state ? "succeeded" : "failed");
		ni_ifworker_array_remove_with_children(ifworkers, w);

	}

	ni_dbus_variant_destroy(&argv);
}
Exemple #3
0
static ni_bool_t
ni_ifdown_stop_policy(const char *policy_name)
{
	/* Default policy name is interface name.
	 * In case of any change other parameters
	 * should be available within ifworker
	 */
	if (!ni_nanny_call_del_policy(policy_name)) {
		ni_debug_application("Unable to delete policy named %s", policy_name);
		return FALSE;
	}

	return TRUE;
}
Exemple #4
0
static ni_bool_t
__do_arp_validate_send(struct arp_handle *handle)
{
	struct in_addr null = { 0 };
	ni_bool_t ret = FALSE;

	if (!handle->hwaddr.len && handle->nprobes) {
		ni_debug_application("%s: arp validate: probing for %s",
				handle->ifname,
				ni_sockaddr_print(&handle->ipaddr));

		handle->nprobes--;
		handle->replies = TRUE;
		if ((ret = ni_arp_send_request(handle->sock, null,
				handle->ipaddr.sin.sin_addr) > 0)) {
			__do_arp_validate_arm_timer(handle);
		}
	} else
	if (!handle->hwaddr.len && handle->nclaims) {
		ni_debug_application("%s: arp validate: claiming %s use",
				handle->ifname,
				ni_sockaddr_print(&handle->ipaddr));

		handle->nclaims--;
		handle->replies = FALSE;
		if ((ret = ni_arp_send_grat_request(handle->sock,
				handle->ipaddr.sin.sin_addr) > 0)) {
			if (handle->nclaims) {
				__do_arp_validate_arm_timer(handle);
			} else if (handle->sock) {
				__do_arp_handle_close(handle);
			}
		}
	}
	return ret;
}
Exemple #5
0
static void
show_exec_info(int argc, char **argv)
{
	ni_stringbuf_t args = NI_STRINGBUF_INIT_DYNAMIC;
	int i;

	for (i = 0; i < argc && argv[i]; ++i) {
		if (i != 0)
			ni_stringbuf_putc(&args, ' ');
		ni_stringbuf_puts(&args, argv[i]);
	}

	ni_debug_application("Executing: %s", args.string);
	ni_stringbuf_destroy(&args);
}
Exemple #6
0
static void
__do_arp_validate_process(ni_arp_socket_t *sock, const ni_arp_packet_t *pkt,
		void *user_data)
{
	struct arp_handle *handle = user_data;
	ni_netconfig_t *nc = ni_global_state_handle(0);
	const ni_netdev_t *ifp;
	ni_bool_t false_alarm = FALSE;
	ni_bool_t found_addr = FALSE;
	const ni_address_t *ap;
	ni_sockaddr_t addr;

	if (!pkt || pkt->op != ARPOP_REPLY || !handle->replies)
		return;

	/* Is it about the address we're validating at all? */
	if (pkt->sip.s_addr != handle->ipaddr.sin.sin_addr.s_addr) {
		ni_debug_application("%s: report about different address",
				handle->ifname);
		return;
	}

	/* Ignore any ARP replies that seem to come from our own
	 * MAC address. Some helpful switches seem to generate
	 * these. */
	if (ni_link_address_equal(&sock->dev_info.hwaddr, &pkt->sha)) {
		ni_debug_application("%s: adress in use by ourself",
				handle->ifname);
		return;
	}

	/* As well as ARP replies that seem to come from our own
	 * host: dup if same address, not a dup if there are two
	 * interfaces connected to the same broadcast domain.
	 */
	ni_sockaddr_set_ipv4(&addr, pkt->sip, 0);
	for (ifp = ni_netconfig_devlist(nc); ifp; ifp = ifp->next) {
		if (ifp->link.ifindex == sock->dev_info.ifindex)
			continue;

		if (!ni_netdev_link_is_up(ifp))
			continue;

		if (!ni_link_address_equal(&ifp->link.hwaddr, &pkt->sha))
			continue;

		/* OK, we have an interface matching the hwaddr,
		 * which will answer arp requests when it is on
		 * the same broadcast domain and causes a false
		 * alarm, except it really has the IP assigned.
		 */
		false_alarm = TRUE;
		for (ap = ifp->addrs; !found_addr && ap; ap = ap->next) {
			if (ap->family != AF_INET)
				continue;
			if (ni_sockaddr_equal(&ap->local_addr, &addr))
				found_addr = TRUE;
		}
	}
	if (false_alarm && !found_addr) {
		ni_debug_application("%s: reply from one of our interfaces",
				handle->ifname);
		return;
	}

	ni_info("%s: adress %s in use by %s reported",
			handle->ifname,
			inet_ntoa(pkt->sip),
			ni_link_address_print(&pkt->sha));
	handle->hwaddr = pkt->sha;
}
Exemple #7
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;
}
Exemple #8
0
static ni_bool_t
ni_ifup_hire_nanny(ni_ifworker_t *w)
{
	xml_node_t *ifcfg = NULL, *policy = NULL;
	ni_netdev_t *dev;
	unsigned int i;
	ni_bool_t rv = FALSE;
	char *pname;

	if (!w)
		return rv;

	ni_debug_application("%s: hiring nanny", w->name);

	/* Create a config duplicate for a policy */
	ifcfg = xml_node_clone(w->config.node, NULL);
	if (!ifcfg)
		goto error;

	pname  = ni_ifpolicy_name_from_ifname(w->name);
	ni_debug_application("%s: converting config into policy '%s'",
			w->name, pname);

	policy = ni_convert_cfg_into_policy_node(ifcfg,
			__ni_ifup_generate_match(w),
			pname, w->config.origin);
	ni_string_free(&pname);
	if (!policy) {
		policy = ifcfg; /* Free cloned config*/
		goto error;
	}

#if 0
	/* Do we need this? */

	/* Add link type to match node*/
	if (dev) {
		ni_debug_application("%s: adding link type (%s) to match",
			w->name, ni_linktype_type_to_name(dev->link.type));
		ni_ifpolicy_match_add_link_type(policy, dev->link.type);
	}

	ni_debug_application("%s: adding minimum device state (%s) to match",
		w->name, ni_ifworker_state_name(w->fsm.state));

	/* Add minimum device state to match node */
	if (!ni_ifpolicy_match_add_min_state(policy, w->fsm.state))
		goto error;
#endif

	dev = w->device;
	if (dev) {
		ni_debug_application("%s: enabling device for nanny", w->name);
		if (!ni_nanny_call_device_enable(w->name))
			goto error;
	}

	ni_debug_application("%s: adding policy %s to nanny", w->name,
		xml_node_get_attr(policy, NI_NANNY_IFPOLICY_NAME));

	if (ni_nanny_addpolicy_node(policy, w->config.origin) <= 0) {
		ni_nanny_call_device_disable(w->name);
		goto error;
	}

	ni_debug_application("%s: nanny hired!", w->name);
	ni_ifworker_success(w);

	/* Append policies for all children in case they contain some special options */
	for (i = 0; i < w->children.count; i++) {
		ni_ifworker_t *child = w->children.data[i];

		if (!ni_ifup_hire_nanny(child))
			ni_error("%s: unable to apply configuration to nanny", child->name);
	}

	rv = TRUE;

error:
	if (!rv)
		ni_ifworker_fail(w, "%s: unable to apply configuration to nanny", w->name);
	xml_node_free(policy);
	return rv;
}
Exemple #9
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;
}
Exemple #10
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 (fsm->worker_timeout == NI_IFWORKER_INFINITE_TIMEOUT)
        ni_debug_application("wait for interfaces infinitely");
    else
        ni_debug_application("wait %u seconds for interfaces",
                             fsm->worker_timeout/1000);

    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;
}