static int set_ethtool_ring(const ni_netdev_ref_t *ref, ni_ethtool_t *ethtool, struct ethtool_args *args) { ni_ethtool_ring_t *ring; char *key = NULL, *val = NULL; int ret = -1, n; if (!(ring = ni_ethtool_ring_new())) return ret; for (n = 0; n < args->argc && args->argv[n]; ++n) { key = args->argv[n++]; if (n < args->argc) val = args->argv[n]; else break; if (ni_string_eq(key, "tx")) { ni_parse_uint(val, &ring->tx, 10); } else if (ni_string_eq(key, "rx")) { ni_parse_uint(val, &ring->rx, 10); } else if (ni_string_eq(key, "rx-jumbo") || ni_string_eq(key, "rx_jumbo")) { ni_parse_uint(val, &ring->rx_jumbo, 10); } else if (ni_string_eq(key, "rx-mini") || ni_string_eq(key, "rx_mini")) { ni_parse_uint(val, &ring->rx_mini, 10); } else { val = key; key = NULL; break; } key = NULL; val = NULL; } if (key) { if (val) fprintf(stderr, "%s: cannot parse ring '%s' argument '%s'\n", ref->name, key, val); else fprintf(stderr, "%s: missing ring '%s' value argument\n", ref->name, key); } else { if (val) fprintf(stderr, "%s: unknown ring setting name '%s'\n", ref->name, val); else ret = ni_ethtool_set_ring(ref, ethtool, ring); } ni_ethtool_ring_free(ring); return ret; }
static int __ni_dhcp6_lease_ia_data_from_xml(ni_dhcp6_ia_t *ia, const xml_node_t *node) { const char *iadr_name; const xml_node_t *child; ni_dhcp6_ia_addr_t *iadr; int ret; if (ia->type == NI_DHCP6_OPTION_IA_PD) { iadr_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_PREFIX); } else { iadr_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_ADDRESS); } for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "interface-id")) { if (ni_parse_uint(child->cdata, &ia->iaid, 10) != 0) return -1; } else if (ni_string_eq(child->name, "acquired")) { int64_t acquired; if (ni_parse_int64(child->cdata, &acquired, 10)) return -1; ia->acquired.tv_sec = acquired; ia->acquired.tv_usec = 0; } else if (ni_string_eq(child->name, "renewal-time") && ia->type != NI_DHCP6_OPTION_IA_TA) { if (ni_parse_uint(child->cdata, &ia->renewal_time, 10) != 0) return -1; } else if (ni_string_eq(child->name, "rebind-time") && ia->type != NI_DHCP6_OPTION_IA_TA) { if (ni_parse_uint(child->cdata, &ia->rebind_time, 10) != 0) return -1; } else if (ni_string_eq(child->name, iadr_name)) { iadr = ni_dhcp6_ia_addr_new(in6addr_any, 0); ret = __ni_dhcp6_lease_ia_addr_from_xml(iadr, ia->type, child); if (ret) { ni_dhcp6_ia_addr_free(iadr); if (ret < 0) return ret; } else { ni_dhcp6_ia_addr_list_append(&ia->addrs, iadr); } } else if (ni_string_eq(child->name, "status")) { if (__ni_dhcp6_lease_status_from_xml(&ia->status, child) < 0) return -1; } } return 0; }
static int set_ethtool_channels(const ni_netdev_ref_t *ref, ni_ethtool_t *ethtool, struct ethtool_args *args) { ni_ethtool_channels_t *channels; char *key = NULL, *val = NULL; int ret = -1, n; if (!(channels = ni_ethtool_channels_new())) return ret; for (n = 0; n < args->argc && args->argv[n]; ++n) { key = args->argv[n++]; if (n < args->argc) val = args->argv[n]; else break; if (ni_string_eq(key, "tx")) { ni_parse_uint(val, &channels->tx, 10); } else if (ni_string_eq(key, "rx")) { ni_parse_uint(val, &channels->rx, 10); } else if (ni_string_eq(key, "other")) { ni_parse_uint(val, &channels->other, 10); } else if (ni_string_eq(key, "combined")) { ni_parse_uint(val, &channels->combined, 10); } else { val = key; key = NULL; break; } key = NULL; val = NULL; } if (key) { if (val) fprintf(stderr, "%s: cannot parse channels '%s' argument '%s'\n", ref->name, key, val); else fprintf(stderr, "%s: missing channels '%s' value argument\n", ref->name, key); } else { if (val) fprintf(stderr, "%s: unknown channels setting name '%s'\n", ref->name, val); else ret = ni_ethtool_set_channels(ref, ethtool, channels); } ni_ethtool_channels_free(channels); return ret; }
static int __ni_dhcp6_lease_ia_addr_from_xml(ni_dhcp6_ia_addr_t *iadr, unsigned int type, const xml_node_t *node) { const xml_node_t *child; const char *name; ni_sockaddr_t addr; unsigned int value; name = (type == NI_DHCP6_OPTION_IA_PD) ? "prefix" : "address"; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, name) && child->cdata) { if (type == NI_DHCP6_OPTION_IA_PD) { if (!ni_sockaddr_prefix_parse(child->cdata, &addr, &value) || value == 0 || value > 128 || addr.ss_family != AF_INET6) return -1; iadr->addr = addr.six.sin6_addr; iadr->plen = value; } else { if (ni_sockaddr_parse(&addr, child->cdata, AF_INET6) != 0) return -1; iadr->addr = addr.six.sin6_addr; iadr->plen = 0; } } else if (ni_string_eq(child->name, "preferred-lft") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0) return -1; iadr->preferred_lft = value; } else if (ni_string_eq(child->name, "valid-lft") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0) return -1; iadr->valid_lft = value; } else if (ni_string_eq(child->name, "status")) { if (__ni_dhcp6_lease_status_from_xml(&iadr->status, child) < 0) return -1; } } ni_sockaddr_set_ipv6(&addr, iadr->addr, 0); if (ni_sockaddr_is_ipv6_specified(&addr)) return 0; else return 1; }
/* * Extract interface index from object path. * Path names must be NI_OBJECTMODEL_OBJECT_PATH "/" <something> "/Interface/" <index> */ static ni_netdev_t * ni_objectmodel_addrconf_path_to_device(const char *path) { unsigned int ifindex; ni_netconfig_t *nc; char cc; if (strncmp(path, NI_OBJECTMODEL_OBJECT_PATH, strlen(NI_OBJECTMODEL_OBJECT_PATH))) return NULL; path += strlen(NI_OBJECTMODEL_OBJECT_PATH); if (*path++ != '/') return NULL; while ((cc = *path++) != '/') { if (cc == '\0') return NULL; } if (strncmp(path, "Interface/", 10)) return NULL; path += 10; if (ni_parse_uint(path, &ifindex, 10) < 0) return NULL; nc = ni_global_state_handle(1); if (nc == NULL) { ni_error("%s: unable to refresh interfaces", __func__); return NULL; } return ni_netdev_by_index(nc, ifindex); }
static int set_ethtool_eee(const ni_netdev_ref_t *ref, ni_ethtool_t *ethtool, struct ethtool_args *args) { ni_ethtool_eee_t *eee; char *key = NULL, *val = NULL; ni_bool_t enabled; int ret = -1, n; if (!(eee = ni_ethtool_eee_new())) return ret; for (n = 0; n < args->argc && args->argv[n]; ++n) { key = args->argv[n++]; if (n < args->argc) val = args->argv[n]; else break; if (ni_string_eq(key, "eee")) { if (ni_parse_boolean(val, &enabled) != 0) break; ni_tristate_set(&eee->status.enabled, enabled); } else if (ni_string_eq(key, "tx-lpi")) { if (ni_parse_boolean(val, &enabled) != 0) break; ni_tristate_set(&eee->tx_lpi.enabled, enabled); } else if (ni_string_eq(key, "tx-timer")) { ni_parse_uint(val, &eee->tx_lpi.timer, 10); } else if (ni_string_eq(key, "advertise")) { if (!set_ethtool_link_advertise(val, &eee->speed.advertising)) break; } else { val = key; key = NULL; break; } key = NULL; val = NULL; } if (key) { if (val) fprintf(stderr, "%s: cannot parse eee '%s' argument '%s'\n", ref->name, key, val); else fprintf(stderr, "%s: missing eee '%s' value argument\n", ref->name, key); } else { if (val) fprintf(stderr, "%s: unknown eee setting name '%s'\n", ref->name, val); else ret = ni_ethtool_set_eee(ref, ethtool, eee); } ni_ethtool_eee_free(eee); return ret; }
static ni_bool_t ni_iaid_map_node_to_iaid(const xml_node_t *node, unsigned int *iaid) { if (!node || !iaid) return FALSE; return ni_parse_uint(node->cdata, iaid, 0) == 0; }
static ni_bool_t __match_uint(unsigned int device_value, const char *query_string) { unsigned int query_value; if (ni_parse_uint(query_string, &query_value, 0) < 0) return FALSE; return device_value == query_value; }
/* * utils to parse lease or a lease data group from xml */ static int __ni_addrconf_lease_info_from_xml(ni_addrconf_lease_t *lease, const xml_node_t *node) { ni_bool_t update = FALSE; xml_node_t *child; int value; if (!lease || !node) return -1; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "family")) { if ((value = ni_addrfamily_name_to_type(child->cdata)) == -1) return -1; lease->family = value; } else if (ni_string_eq(child->name, "type")) { if ((value = ni_addrconf_name_to_type(child->cdata)) == -1) return -1; lease->type = value; } else if (ni_string_eq(child->name, "owner")) { if (!ni_string_empty(child->cdata)) ni_string_dup(&lease->owner, child->cdata); } else if (ni_string_eq(child->name, "uuid")) { if (ni_uuid_parse(&lease->uuid, child->cdata) != 0) return -1; } else if (ni_string_eq(child->name, "update")) { if (ni_parse_uint(child->cdata, &lease->update, 16) != 0) return -1; update = TRUE; } if (ni_string_eq(child->name, "acquired")) { if (ni_parse_uint(child->cdata, &lease->time_acquired, 10) != 0) return -1; } } if (!update) lease->update = ni_config_addrconf_update_mask(lease->type, lease->family); return 0; }
void ni_config_parse_fslocation(ni_config_fslocation_t *fsloc, xml_node_t *node) { const char *attrval; if ((attrval = xml_node_get_attr(node, "path")) != NULL) ni_string_dup(&fsloc->path, attrval); if ((attrval = xml_node_get_attr(node, "mode")) != NULL) ni_parse_uint(attrval, &fsloc->mode, 8); }
ni_bool_t xml_node_get_attr_uint(const xml_node_t *node, const char *name, unsigned int *valp) { const char *value; if (!valp || !(value = xml_node_get_attr(node, name))) return FALSE; if (ni_parse_uint(value, valp, 10) < 0) return FALSE; return TRUE; }
int ni_parse_uint_maybe_mapped(const char *input, const ni_intmap_t *map, unsigned int *result, int base) { if (!map || !input || !result) return -1; if (ni_parse_uint_mapped(input, map, result) == 0) return 0; if (ni_parse_uint(input, result, base) < 0) return -1; if (ni_format_uint_mapped(*result, map) == NULL) return 1; return 0; }
/* * dhcp6 lease data from xml */ static int __ni_dhcp6_lease_status_from_xml(ni_dhcp6_status_t *status, const xml_node_t *node) { const xml_node_t *child; unsigned int value; ni_dhcp6_status_clear(status); for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "code")) { if (ni_parse_uint(child->cdata, &value, 10) != 0 || value > 0xffff) return -1; status->code = value; } else if (ni_string_eq(child->name, "message") && child->cdata) { ni_string_dup(&status->message, child->cdata); } } return 0; }
static int set_ethtool_link_settings(const ni_netdev_ref_t *ref, ni_ethtool_t *ethtool, struct ethtool_args *args) { ni_ethtool_link_settings_t *link; char *key = NULL, *val = NULL; unsigned int value; ni_bool_t enabled; int ret = -1, n; if (!(link = ni_ethtool_link_settings_new())) return ret; for (n = 0; n < args->argc && args->argv[n]; ++n) { key = args->argv[n++]; if (n < args->argc) val = args->argv[n]; else break; if (ni_string_eq(key, "autoneg")) { if (ni_parse_boolean(val, &enabled) != 0) break; ni_tristate_set(&link->autoneg, enabled); } else if (ni_string_eq(key, "speed")) { if (ni_parse_uint(val, &value, 10) != 0) break; link->speed = value; } else if (ni_string_eq(key, "duplex")) { if (!ni_ethtool_link_duplex_type(val, &value)) break; link->duplex = value; } else if (ni_string_eq(key, "port")) { if (!ni_ethtool_link_port_type(val, &value)) break; link->port = value; } else if (ni_string_eq(key, "mdix")) { if (!ni_ethtool_link_mdix_type(val, &value)) break; link->tp_mdix = value; } else if (ni_string_eq(key, "phy-address")) { if (ni_parse_uint(val, &value, 10) != 0) break; link->phy_address = value; } else if (ni_string_eq(key, "transceiver")) { if (!ni_ethtool_link_xcvr_type(val, &value)) break; link->transceiver = value; } else if (ni_string_eq(key, "advertise")) { if (!set_ethtool_link_advertise(val, &link->advertising)) break; } else { val = key; key = NULL; break; } key = NULL; val = NULL; } if (key) { if (val) fprintf(stderr, "%s: cannot parse link '%s' argument '%s'\n", ref->name, key, val); else fprintf(stderr, "%s: missing link '%s' value argument\n", ref->name, key); } else { if (val) fprintf(stderr, "%s: unknown link setting name '%s'\n", ref->name, val); else ret = ni_ethtool_set_link_settings(ref, ethtool, link); } ni_ethtool_link_settings_free(link); return ret; }
int ni_dhcp6_lease_data_from_xml(ni_addrconf_lease_t *lease, const xml_node_t *node, const char *ifname) { const char *ia_na_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_NA); const char *ia_ta_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_TA); const char *ia_pd_name = ni_dhcp6_option_name(NI_DHCP6_OPTION_IA_PD); unsigned int value; ni_sockaddr_t addr; xml_node_t *child; if (!lease || !node) return -1; lease->dhcp6.rapid_commit = FALSE; for (child = node->children; child; child = child->next) { if (ni_string_eq(child->name, "client-id") && child->cdata) { if (!ni_duid_parse_hex(&lease->dhcp6.client_id, child->cdata)) return -1; } else if (ni_string_eq(child->name, "server-id") && child->cdata) { if (!ni_duid_parse_hex(&lease->dhcp6.server_id, child->cdata)) return -1; } else if (ni_string_eq(child->name, "server-address") && child->cdata) { if (ni_sockaddr_parse(&addr, child->cdata, AF_INET6) < 0) return -1; lease->dhcp6.server_addr = addr.six.sin6_addr; } else if (ni_string_eq(child->name, "server-preference") && child->cdata) { if (ni_parse_uint(child->cdata, &value, 10) != 0 || value > 255) return -1; lease->dhcp6.server_pref = value; } else if (ni_string_eq(child->name, "rapid-commit")) { lease->dhcp6.rapid_commit = TRUE; } else if (ni_string_eq(child->name, "hostname") && child->cdata) { ni_string_dup(&lease->hostname, child->cdata); } if (ni_string_eq(child->name, ia_na_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_NA, child) < 0) return -1; } else if (ni_string_eq(child->name, ia_ta_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_TA, child) < 0) return -1; } else if (ni_string_eq(child->name, ia_pd_name)) { if (__ni_dhcp6_lease_ia_type_from_xml(&lease->dhcp6.ia_list, NI_DHCP6_OPTION_IA_PD, child) < 0) return -1; } else if (ni_string_eq(child->name, "boot")) { if (__ni_dhcp6_lease_boot_from_xml(lease, child) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_DNS_DATA_NODE)) { if (ni_addrconf_lease_dns_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_NTP_DATA_NODE)) { if (ni_addrconf_lease_ntp_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_SIP_DATA_NODE)) { if (ni_addrconf_lease_sip_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_PTZ_DATA_NODE)) { if (ni_addrconf_lease_ptz_data_from_xml(lease, child, ifname) < 0) return -1; } else if (ni_string_eq(child->name, NI_ADDRCONF_LEASE_XML_OPTS_DATA_NODE)) { if (ni_addrconf_lease_opts_data_from_xml(lease, child, ifname) < 0) return -1; } } return 0; }
static ni_bool_t dhcp4_tester_req_xml_init(ni_dhcp4_request_t *req, xml_document_t *doc) { xml_node_t *xml, *child; const char *type; xml = xml_document_root(doc); if (xml && !xml->name && xml->children) xml = xml->children; if (!xml || !ni_string_eq(xml->name, "request")) { ni_error("Invalid dhcp4 request xml '%s'", xml ? xml_node_location(xml) : NULL); return FALSE; } type = xml_node_get_attr(xml, "type"); if (ni_string_eq(type, "offer")) { req->dry_run = NI_DHCP4_RUN_OFFER; } else if (ni_string_eq(type, "lease")) { req->dry_run = NI_DHCP4_RUN_LEASE; } for (child = xml->children; child; child = child->next) { if (ni_string_eq(child->name, "uuid")) { if (ni_uuid_parse(&req->uuid, child->cdata) != 0) goto failure; } else if (ni_string_eq(child->name, "acquire-timeout")) { if (ni_parse_uint(child->cdata, &req->acquire_timeout, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "hostname")) { if (!ni_check_domain_name(child->cdata, ni_string_len(child->cdata), 0)) goto failure; ni_string_dup(&req->hostname, child->cdata); } else if (ni_string_eq(child->name, "clientid")) { ni_opaque_t duid; if (ni_parse_hex(child->cdata, duid.data, sizeof(duid.data)) <= 0) goto failure; ni_string_dup(&req->clientid, child->cdata); } else if(ni_string_eq(child->name, "start-delay")) { if (ni_parse_uint(child->cdata, &req->start_delay, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "lease-time")) { if (ni_parse_uint(child->cdata, &req->lease_time, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "recover-lease")) { if (ni_parse_boolean(child->cdata, &req->recover_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "release-lease")) { if (ni_parse_boolean(child->cdata, &req->release_lease) != 0) goto failure; } } return TRUE; failure: if (child) { ni_error("Cannot parse dhcp4 request '%s': %s", child->name, xml_node_location(child)); } return FALSE; }
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; }
int ni_do_arp(int argc, char **argv) { static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "quiet", no_argument, NULL, OPT_QUIET }, { "verbose", no_argument, NULL, OPT_VERBOSE }, { "verify", required_argument, NULL, OPT_VERIFY }, { "notify", required_argument, NULL, OPT_NOTIFY }, { "interval", required_argument, NULL, OPT_TIMEOUT }, { NULL, no_argument, NULL, 0 } }; int c, status = NI_WICKED_RC_USAGE; unsigned int opt_verbose = OPT_VERBOSE; unsigned int opt_nprobes; unsigned int opt_nclaims; struct arp_handle handle; memset(&handle, 0, sizeof(handle)); handle.nprobes = opt_nprobes = 3; handle.nclaims = opt_nclaims = 0; handle.timeout = 200; optind = 1; while ((c = getopt_long(argc, argv, "", options, NULL)) != EOF) { switch (c) { case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "wicked %s [options ...] <ifname> <IP address>\n" "\n" "Supported options:\n" " --help\n" " Show this help text.\n" " --quiet\n" " Return exit status only\n" " --verbose\n" " Show a result info (default)\n" "\n" " --verify <count>\n" " Verify IP for duplicates on the network (DAD);\n" " Returns 4, when duplicate IP address exists.\n" " --notify <count>\n" " Notify about IP address use (gratuitous ARP)\n" " --interval <msec>\n" " Packet sending interval in msec\n" , argv[0] ); goto cleanup; case OPT_QUIET: case OPT_VERBOSE: opt_verbose = c; break; case OPT_VERIFY: if (ni_parse_uint(optarg, &opt_nprobes, 10)) { ni_error("%s: Cannot parse verify count '%s'", argv[0], optarg); goto cleanup; } handle.nprobes = opt_nprobes; break; case OPT_NOTIFY: if (ni_parse_uint(optarg, &opt_nclaims, 10)) { ni_error("%s: Cannot parse notify count '%s'", argv[0], optarg); goto cleanup; } handle.nclaims = opt_nclaims; break; case OPT_TIMEOUT: if (ni_parse_uint(optarg, &handle.timeout, 10)) { ni_error("%s %s: Cannot parse interval '%s'", argv[0], argv[1], optarg); goto cleanup; } break; } } if (optind + 2 != argc) goto usage; if (!handle.nprobes && !handle.nclaims) { ni_error("%s: nothing to send", argv[0]); goto cleanup; } handle.ifname = argv[optind++]; if (ni_string_empty(handle.ifname)) goto cleanup; if (ni_sockaddr_parse(&handle.ipaddr, argv[optind], AF_INET) != 0) { ni_error("%s: cannot parse '%s' as IPv4 address", argv[0], argv[optind]); goto cleanup; } status = __do_arp_validate(&handle); if (opt_verbose) { if (handle.hwaddr.len) { printf("%s: IP address %s is in use by %s\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr), ni_link_address_print(&handle.hwaddr)); } else { if (opt_nprobes) { printf("%s: No duplicates for IP address %s detected\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr)); } if (opt_nclaims) { printf("%s: Notified neighbours about IP address %s\n", handle.ifname, ni_sockaddr_print(&handle.ipaddr)); } } } cleanup: 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; }
static int set_ethtool_coalesce(const ni_netdev_ref_t *ref, ni_ethtool_t *ethtool, struct ethtool_args *args) { ni_ethtool_coalesce_t *coalesce; char *key = NULL, *val = NULL; ni_bool_t enabled; int ret = -1, n; if (!(coalesce = ni_ethtool_coalesce_new())) return ret; for (n = 0; n < args->argc && args->argv[n]; ++n) { key = args->argv[n++]; if (n < args->argc) val = args->argv[n]; else break; if (ni_string_eq(key, "adaptive-rx")) { if (ni_parse_boolean(val, &enabled) != 0) break; ni_tristate_set(&coalesce->adaptive_rx, enabled); } else if (ni_string_eq(key, "adaptive-tx")) { if (ni_parse_boolean(val, &enabled) != 0) break; ni_tristate_set(&coalesce->adaptive_tx, enabled); } else if (ni_string_eq(key, "rx-usecs")) { ni_parse_uint(val, &coalesce->rx_usecs, 10); } else if (ni_string_eq(key, "rx-frames")) { ni_parse_uint(val, &coalesce->rx_frames, 10); } else if (ni_string_eq(key, "rx-usecs-irq")) { ni_parse_uint(val, &coalesce->rx_usecs_irq, 10); } else if (ni_string_eq(key, "rx-frames-irq")) { ni_parse_uint(val, &coalesce->rx_frames_irq, 10); } else if (ni_string_eq(key, "tx-usecs")) { ni_parse_uint(val, &coalesce->tx_usecs, 10); } else if (ni_string_eq(key, "tx-frames")) { ni_parse_uint(val, &coalesce->tx_frames, 10); } else if (ni_string_eq(key, "tx-usecs-irq")) { ni_parse_uint(val, &coalesce->tx_usecs_irq, 10); } else if (ni_string_eq(key, "tx-frames-irq")) { ni_parse_uint(val, &coalesce->rx_frames_irq, 10); } else if (ni_string_eq(key, "stats-block-usecs")) { ni_parse_uint(val, &coalesce->stats_block_usecs, 10); } else if (ni_string_eq(key, "pkt-rate-low")) { ni_parse_uint(val, &coalesce->pkt_rate_low, 10); } else if (ni_string_eq(key, "rx-usecs-low")) { ni_parse_uint(val, &coalesce->rx_usecs_low, 10); } else if (ni_string_eq(key, "rx-frames-low")) { ni_parse_uint(val, &coalesce->rx_frames_low, 10); } else if (ni_string_eq(key, "tx-usecs-low")) { ni_parse_uint(val, &coalesce->tx_usecs_low, 10); } else if (ni_string_eq(key, "tx-frames-low")) { ni_parse_uint(val, &coalesce->tx_frames_low, 10); } else if (ni_string_eq(key, "pkt-rate-high")) { ni_parse_uint(val, &coalesce->pkt_rate_high, 10); } else if (ni_string_eq(key, "rx-usecs-high")) { ni_parse_uint(val, &coalesce->rx_usecs_high, 10); } else if (ni_string_eq(key, "rx-frames-high")) { ni_parse_uint(val, &coalesce->rx_frames_high, 10); } else if (ni_string_eq(key, "tx-usecs-high")) { ni_parse_uint(val, &coalesce->tx_usecs_high, 10); } else if (ni_string_eq(key, "tx-frames-high")) { ni_parse_uint(val, &coalesce->tx_frames_high, 10); } else if (ni_string_eq(key, "sample_interval")) { ni_parse_uint(val, &coalesce->sample_interval, 10); } else { val = key; key = NULL; break; } key = NULL; val = NULL; } if (key) { if (val) fprintf(stderr, "%s: cannot parse coalesce '%s' argument '%s'\n", ref->name, key, val); else fprintf(stderr, "%s: missing coalesce '%s' value argument\n", ref->name, key); } else { if (val) fprintf(stderr, "%s: unknown coalesce setting name '%s'\n", ref->name, val); else ret = ni_ethtool_set_coalesce(ref, ethtool, coalesce); } ni_ethtool_coalesce_free(coalesce); return ret; }
static int __ni_addrconf_lease_addr_from_xml(ni_address_t **ap_list, unsigned int family, const xml_node_t *node) { const xml_node_t *child; ni_sockaddr_t addr; unsigned int plen; ni_address_t *ap; if (!(child = xml_node_get_child(node, "local"))) return 1; if (ni_sockaddr_prefix_parse(child->cdata, &addr, &plen)) return -1; if (family != addr.ss_family || (family == AF_INET && plen > 32) || (family == AF_INET6 && plen > 128)) return -1; if (!(ap = ni_address_new(family, plen, &addr, NULL))) return -1; if ((child = xml_node_get_child(node, "peer"))) { if (ni_sockaddr_parse(&ap->peer_addr, child->cdata, family) != 0) goto failure; } if ((child = xml_node_get_child(node, "anycast"))) { if (ni_sockaddr_parse(&ap->anycast_addr, child->cdata, family) != 0) goto failure; } if ((child = xml_node_get_child(node, "broadcast"))) { if (ni_sockaddr_parse(&ap->bcast_addr, child->cdata, family) != 0) goto failure; } if (family == AF_INET && (child = xml_node_get_child(node, "label"))) { ni_string_dup(&ap->label, child->cdata); } if ((child = xml_node_get_child(node, "cache-info"))) { xml_node_t *cnode; unsigned int lft; if ((cnode = xml_node_get_child(child, "preferred-lifetime"))) { if (ni_parse_uint(child->cdata, &lft, 10) != 0) goto failure; ap->ipv6_cache_info.preferred_lft = lft; } if ((cnode = xml_node_get_child(child, "valid-lifetime"))) { if (ni_parse_uint(child->cdata, &lft, 10) != 0) goto failure; ap->ipv6_cache_info.valid_lft = lft; } } ni_address_list_append(ap_list, ap); return 0; failure: ni_address_free(ap); return -1; }
static ni_bool_t ni_dhcp4_tester_req_xml_init(ni_dhcp4_request_t *req, xml_document_t *doc) { xml_node_t *xml, *child; const char *type; xml = xml_document_root(doc); if (xml && !xml->name && xml->children) xml = xml->children; if (!xml || !ni_string_eq(xml->name, "request")) { ni_error("Invalid dhcp4 request xml '%s'", xml ? xml_node_location(xml) : NULL); return FALSE; } type = xml_node_get_attr(xml, "type"); if (ni_string_eq(type, "offer")) { req->dry_run = NI_DHCP4_RUN_OFFER; } else if (ni_string_eq(type, "lease")) { req->dry_run = NI_DHCP4_RUN_LEASE; } for (child = xml->children; child; child = child->next) { if (ni_string_eq(child->name, "uuid")) { if (ni_uuid_parse(&req->uuid, child->cdata) != 0) goto failure; } else if (ni_string_eq(child->name, "acquire-timeout")) { if (ni_parse_uint(child->cdata, &req->acquire_timeout, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "hostname")) { if (!ni_check_domain_name(child->cdata, ni_string_len(child->cdata), 0)) goto failure; ni_string_dup(&req->hostname, child->cdata); } else if (ni_string_eq(child->name, "fqdn")) { const xml_node_t *ptr; for (ptr = child->children; ptr; ptr = ptr->next) { if (ni_string_eq(ptr->name, "enabled")) { ni_bool_t b; if (ni_parse_boolean(ptr->cdata, &b) == 0) ni_tristate_set(&req->fqdn.enabled, b); else if (ni_string_eq(ptr->cdata, "default")) req->fqdn.enabled = NI_TRISTATE_DEFAULT; else goto failure; } else if (ni_string_eq(ptr->name, "update")) { if (!ni_dhcp_fqdn_update_name_to_mode(ptr->cdata, &req->fqdn.update)) goto failure; } else if (ni_string_eq(ptr->name, "encode")) { if (ni_parse_boolean(ptr->cdata, &req->fqdn.encode) != 0) goto failure; } else if (ni_string_eq(ptr->name, "qualify")) { if (ni_parse_boolean(ptr->cdata, &req->fqdn.qualify) != 0) goto failure; } } } else if (ni_string_eq(child->name, "clientid")) { ni_opaque_t duid; if (ni_parse_hex(child->cdata, duid.data, sizeof(duid.data)) <= 0) goto failure; ni_string_dup(&req->clientid, child->cdata); } else if(ni_string_eq(child->name, "start-delay")) { if (ni_parse_uint(child->cdata, &req->start_delay, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "lease-time")) { if (ni_parse_uint(child->cdata, &req->lease_time, 10) != 0) goto failure; } else if (ni_string_eq(child->name, "recover-lease")) { if (ni_parse_boolean(child->cdata, &req->recover_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "release-lease")) { if (ni_parse_boolean(child->cdata, &req->release_lease) != 0) goto failure; } else if (ni_string_eq(child->name, "request-options")) { xml_node_t *opt; for (opt = child->children; opt; opt = opt->next) { if (ni_string_empty(opt->cdata)) continue; ni_string_array_append(&req->request_options, opt->cdata); } } } return TRUE; failure: if (child) { ni_error("Cannot parse dhcp4 request '%s': %s", child->name, xml_node_location(child)); } return FALSE; }
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 main(int argc, char **argv) { dhcp4_tester_t * tester = NULL; int c, status = NI_WICKED_RC_USAGE; ni_log_init(); program_name = ni_basename(argv[0]); while ((c = getopt_long(argc, argv, "+", options, NULL)) != EOF) { switch (c) { /* common */ case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "%s [options]\n" "This command understands the following options\n" " --help\n" " --version\n" " --config filename\n" " Read configuration file <filename> instead of system default.\n" " --log-level level\n" " Set log level to <error|warning|notice|info|debug>.\n" " --log-target target\n" " Set log destination to <stderr|syslog>.\n" " --debug facility\n" " Enable debugging for debug <facility>.\n" " Use '--debug help' for a list of facilities.\n" " --foreground\n" " Do not background the service.\n" " --recover\n" " Enable automatic recovery of daemon's state.\n" " --systemd\n" " Enables behavior required by systemd service\n" "\n" " --test [test-options] <ifname>\n" " test-options:\n" " --test-request <request.xml>\n" " --test-timeout <timeout in sec> (default: 20+10)\n" " --test-output <output file name>\n" " --test-format <leaseinfo|lease-xml>\n" , program_name); return status; case OPT_VERSION: printf("%s %s\n", program_name, PACKAGE_VERSION); return NI_WICKED_RC_SUCCESS; case OPT_CONFIGFILE: if (!ni_set_global_config_path(optarg)) { fprintf(stderr, "Unable to set config file '%s': %m\n", optarg); return NI_WICKED_RC_ERROR; } break; case OPT_DEBUG: if (!strcmp(optarg, "help")) { printf("Supported debug facilities:\n"); ni_debug_help(); return NI_WICKED_RC_SUCCESS; } if (ni_enable_debug(optarg) < 0) { fprintf(stderr, "Bad debug facility \"%s\"\n", optarg); goto usage; } break; case OPT_LOG_LEVEL: if (!ni_log_level_set(optarg)) { fprintf(stderr, "Bad log level \%s\"\n", optarg); goto usage; } break; case OPT_LOG_TARGET: opt_log_target = optarg; break; /* daemon */ case OPT_FOREGROUND: opt_foreground = TRUE; break; /* specific */ case OPT_RECOVER: opt_recover_state = TRUE; break; case OPT_SYSTEMD: opt_systemd = TRUE; break; /* test run */ case OPT_TEST: opt_foreground = TRUE; tester = dhcp4_tester_init(); break; case OPT_TEST_REQUEST: if (!tester || ni_string_empty(optarg)) goto usage; tester->request = optarg; break; case OPT_TEST_TIMEOUT: if (!tester || ni_parse_uint(optarg, &tester->timeout, 0) < 0) goto usage; break; case OPT_TEST_OUTPUT: if (!tester || ni_string_empty(optarg)) goto usage; tester->output = optarg; break; case OPT_TEST_OUTFMT: if (!tester || !dhcp4_tester_set_outfmt(optarg, &tester->outfmt)) goto usage; break; } }
int ni_do_test_dhcp4(const char *caller, int argc, char **argv) { enum { OPT_HELP = 'h', OPT_TEST_TIMEOUT = 't', OPT_TEST_REQUEST = 'r', OPT_TEST_OUTPUT = 'o', OPT_TEST_OUTFMT = 'F', }; static struct option options[] = { { "help", no_argument, NULL, OPT_HELP }, { "request", required_argument, NULL, OPT_TEST_REQUEST}, { "timeout", required_argument, NULL, OPT_TEST_TIMEOUT}, { "output", required_argument, NULL, OPT_TEST_OUTPUT }, { "format", required_argument, NULL, OPT_TEST_OUTFMT }, { NULL, no_argument, NULL, 0 } }; int opt = 0, status = NI_WICKED_RC_USAGE; char *program = NULL; ni_dhcp4_tester_t *tester; ni_string_printf(&program, "%s %s", caller ? caller : "wicked", argv[0] ? argv[0] : "test"); argv[0] = program; tester = ni_dhcp4_tester_init(); if (tester == NULL) { fprintf(stderr, "Error: %s: unable to initialize dhcp4 tester\n", program); status = NI_WICKED_RC_ERROR; goto cleanup; } optind = 1; while ((opt = getopt_long(argc, argv, "+hr:t:o:F:", options, NULL)) != EOF) { switch (opt) { case OPT_HELP: status = NI_WICKED_RC_SUCCESS; default: usage: fprintf(stderr, "\nUsage:\n" " %s [options] <ifname>\n" "\n" "Options:\n" " --help, -h show this help text and exit.\n" "\n" " --timeout, -t <timeout in sec> (default: 20+10)\n" " --request, -r <request.xml>\n" " --output, -o <output file name>\n" " --format, -F <leaseinfo|lease-xml>\n" "\n", program); goto cleanup; case OPT_TEST_TIMEOUT: if (ni_string_empty(optarg)) goto usage; if (ni_parse_uint(optarg, &tester->timeout, 0) < 0) { fprintf(stderr, "%s: unable to parse timeout option '%s'\n", program, optarg); status = NI_WICKED_RC_ERROR; goto cleanup; } break; case OPT_TEST_REQUEST: if (ni_string_empty(optarg)) goto usage; tester->request = optarg; break; case OPT_TEST_OUTPUT: if (ni_string_empty(optarg)) goto usage; tester->output = optarg; break; case OPT_TEST_OUTFMT: if (ni_string_empty(optarg)) goto usage; if (!ni_dhcp4_tester_set_outfmt(optarg, &tester->outfmt)) { fprintf(stderr, "%s: unable to parse output format option '%s'\n", program, optarg); status = NI_WICKED_RC_ERROR; goto cleanup; } break; } } if (optind >= argc || ni_string_empty(argv[optind])) { fprintf(stderr, "Error: %s: missing interface name argument\n", program); goto usage; } else if (optind + 1 != argc) { fprintf(stderr, "Error: %s: multiple interface names not supported\n", program); goto cleanup; } ni_netconfig_set_family_filter(ni_global_state_handle(0), AF_INET); ni_netconfig_set_discover_filter(ni_global_state_handle(0), NI_NETCONFIG_DISCOVER_LINK_EXTERN); tester->ifname = argv[optind]; status = ni_dhcp4_tester_run(tester); cleanup: ni_string_free(&program); return status; }