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); } }
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); }
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; }
/* * 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; }
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; }