int ni_ethtool_set_priv_flags(const char *ifname, ni_ethtool_t *ethtool, const ni_ethtool_priv_flags_t *pflags) { static const ni_ethtool_cmd_info_t NI_ETHTOOL_CMD_SPFLAGS = { ETHTOOL_SPFLAGS, "set priv-flags" }; struct ethtool_value ecmd; unsigned int i, bit; const char *name; ni_bool_t enabled; int ret; if (!pflags || !pflags->names.count) return 1; /* nothing to set */ if (!ethtool->priv_flags && (ret = ni_ethtool_get_priv_flags(ifname, ethtool)) < 0) return ret; if (!ethtool->priv_flags || !ethtool->priv_flags->names.count) return -EOPNOTSUPP; memset(&ecmd, 0, sizeof(ecmd)); ecmd.data = ethtool->priv_flags->bitmap; /* set every single bit separately in case one fails? */ for (i = 0; i < pflags->names.count; ++i) { name = pflags->names.data[i]; if (ni_string_empty(name)) continue; enabled = !!(pflags->bitmap & NI_BIT(i)); bit = ni_string_array_index(ðtool->priv_flags->names, name); if (bit == -1U) { ni_info("%s: unable to set unknown driver private flag '%s'", ifname, name); continue; } ni_debug_verbose(NI_LOG_DEBUG1, NI_TRACE_IFCONFIG, "%s: setting driver private flag '%s' to %s", ifname, name, ni_format_boolean(enabled)); if (enabled) ecmd.data |= NI_BIT(bit); else ecmd.data &= ~NI_BIT(bit); } if (ecmd.data == ethtool->priv_flags->bitmap) return 0; ret = ni_ethtool_call(ifname, &NI_ETHTOOL_CMD_SPFLAGS, &ecmd, NULL); ni_ethtool_set_supported(ethtool, NI_ETHTOOL_SUPP_SET_PRIV_FLAGS, ret != -EOPNOTSUPP); if (ret < 0) return ret; return 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; }
static dbus_bool_t __ni_objectmodel_bonding_set_slaves(ni_dbus_object_t *object, const ni_dbus_property_t *property, const ni_dbus_variant_t *result, DBusError *error) { ni_bonding_t *bond; ni_dbus_variant_t *var; unsigned int i; if (!(bond = __ni_objectmodel_bonding_write_handle(object, error))) return FALSE; if (!ni_dbus_variant_is_dict_array(result)) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - expected dict array", object->path, property->name); return FALSE; } ni_string_free(&bond->primary_slave); ni_string_free(&bond->active_slave); ni_string_array_destroy(&bond->slave_names); for (i = 0, var = result->variant_array_value; i < result->array.len; ++i, ++var) { dbus_bool_t is_primary = FALSE; dbus_bool_t is_active = FALSE; const char *slave_name; if (!ni_dbus_dict_get_string(var, "device", &slave_name)) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - missing device attribute", object->path, property->name); return FALSE; } if (ni_string_array_index(&bond->slave_names, slave_name) != -1) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate slave devices", object->path, property->name); return FALSE; } if (ni_dbus_dict_get_bool(var, "primary", &is_primary) && is_primary) { if (bond->primary_slave) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate primary device", object->path, property->name); return FALSE; } ni_string_dup(&bond->primary_slave, slave_name); } if (ni_dbus_dict_get_bool(var, "active", &is_active) && is_active) { if (bond->active_slave) { dbus_set_error(error, DBUS_ERROR_INVALID_ARGS, "%s.%s property - duplicate active device", object->path, property->name); return FALSE; } ni_string_dup(&bond->active_slave, slave_name); } ni_string_array_append(&bond->slave_names, slave_name); } return TRUE; }