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