Skip to content

Commit

Permalink
ifreload: add nanny variant
Browse files Browse the repository at this point in the history
  • Loading branch information
wipawel committed Jul 24, 2014
1 parent e878c49 commit 44a2b27
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 11 deletions.
323 changes: 313 additions & 10 deletions client/ifreload.c
Expand Up @@ -45,8 +45,8 @@
#include "ifup.h"
#include "ifreload.h"

int
ni_do_ifreload(int argc, char **argv)
static int
ni_do_ifreload_direct(int argc, char **argv)
{
enum { OPT_HELP, OPT_IFCONFIG, OPT_PERSISTENT, OPT_TRANSIENT,
OPT_TIMEOUT,
Expand All @@ -56,17 +56,17 @@ ni_do_ifreload(int argc, char **argv)
};

static struct option ifreload_options[] = {
{ "help", no_argument, NULL, OPT_HELP },
{ "ifconfig", required_argument, NULL, OPT_IFCONFIG },
{ "timeout", no_argument, NULL, OPT_TIMEOUT },
{ "transient", no_argument, NULL, OPT_TRANSIENT },
{ "help", no_argument, NULL, OPT_HELP },
{ "ifconfig", required_argument, NULL, OPT_IFCONFIG },
{ "timeout", no_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 },
{ "ignore-prio", no_argument, NULL, OPT_IGNORE_PRIO },
{ "ignore-startmode", no_argument, NULL, OPT_IGNORE_STARTMODE },
#endif
{ "persistent", no_argument, NULL, OPT_PERSISTENT },
{ "persistent", no_argument, NULL, OPT_PERSISTENT },

{ NULL, no_argument, NULL, 0 }
{ NULL, no_argument, NULL, 0 }
};
ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT;
ni_ifworker_array_t up_marked = NI_IFWORKER_ARRAY_INIT;
Expand Down Expand Up @@ -335,3 +335,306 @@ ni_do_ifreload(int argc, char **argv)
ni_ifworker_array_destroy(&up_marked);
return status;
}

static int
ni_do_ifreload_nanny(int argc, char **argv)
{
enum { OPT_HELP, OPT_IFCONFIG, OPT_PERSISTENT, OPT_TRANSIENT,
OPT_TIMEOUT,
#ifdef NI_TEST_HACKS
OPT_IGNORE_PRIO, OPT_IGNORE_STARTMODE,
#endif
};

static struct option ifreload_options[] = {
{ "help", no_argument, NULL, OPT_HELP },
{ "ifconfig", required_argument, NULL, OPT_IFCONFIG },
{ "timeout", no_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, no_argument, NULL, 0 }
};
ni_string_array_t opt_ifconfig = NI_STRING_ARRAY_INIT;
ni_ifworker_array_t up_marked = NI_IFWORKER_ARRAY_INIT;
ni_ifworker_array_t down_marked = NI_IFWORKER_ARRAY_INIT;
ni_ifmatcher_t ifmatch;
ni_bool_t check_prio = TRUE;
ni_bool_t set_persistent = FALSE;
ni_bool_t opt_transient = FALSE;
unsigned int opt_timeout = 0;
int c, status = NI_WICKED_RC_USAGE;
unsigned int nmarked, i;
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);

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:
set_persistent = TRUE;
break;

case OPT_TRANSIENT:
opt_transient = TRUE;
break;

case OPT_TIMEOUT:
if (!strcmp(optarg, "infinite")) {
opt_timeout = NI_IFWORKER_INFINITE_TIMEOUT;
} else if (ni_parse_uint(optarg, &opt_timeout, 10) >= 0) {
opt_timeout *= 1000; /* sec -> msec */
} else {
ni_error("ifup: cannot parse timeout option \"%s\"",
optarg);
goto usage;
}
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;
}

if (opt_timeout)
ni_wait_for_interfaces = opt_timeout; /* One set by user */
else
ni_wait_for_interfaces *= 1000; /* sec -> msec */

if (ni_wait_for_interfaces)
fsm->worker_timeout = ni_wait_for_interfaces;

/* Build the up tree */
if (ni_fsm_build_hierarchy(fsm, TRUE) < 0) {
ni_error("ifreload: unable to build device hierarchy");
/* Severe error we always explicitly return */
status = NI_WICKED_RC_ERROR;
goto cleanup;
}

status = NI_WICKED_RC_SUCCESS;
nmarked = 0;
for (c = optind; c < argc; ++c) {
ifmatch.name = argv[c];

/* Getting an array of ifworkers matching arguments */
ni_fsm_get_matching_workers(fsm, &ifmatch, &down_marked);
}

for (i = 0; i < down_marked.count; ++i) {
ni_ifworker_t *w = down_marked.data[i];
ni_netdev_t *dev = w->device;

/* skip unused devices without config */
if (!ni_ifcheck_worker_config_exists(w) &&
!ni_ifcheck_device_configured(dev)) {
ni_info("skipping %s interface: no configuration exists and "
"device is not configured by wicked", w->name);
continue;
}

/* skip if config has not been changed */
if (ni_ifcheck_worker_config_matches(w)) {
ni_info("skipping %s interface: "
"configuration unchanged", w->name);
continue;
}

/* Remember all changed devices */
ni_ifworker_array_append(&up_marked, w);

/* Do not ifdown non-existing device */
if (!dev) {
ni_info("skipping ifdown operation for %s interface: "
"non-existing device", w->name);
continue;
}

/* Persistent do not go down but up only */
if (ni_ifcheck_device_is_persistent(dev)) {
ni_info("skipping ifdown operation for %s interface: "
"persistent device", w->name);
continue;
}

/* Decide how much down we go */
if (ni_ifcheck_worker_config_exists(w)) {
if (!ni_ifcheck_device_configured(dev)) {
ni_info("skipping ifdown operation for %s interface: "
"device is not configured by wicked", w->name);
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++;
}
}

if (0 == nmarked && 0 == up_marked.count) {
printf("ifreload: no matching interfaces\n");
status = NI_WICKED_RC_SUCCESS;
goto cleanup;
}

/* anything to ifdown? e.g. persistent devices are skipped here */
if (nmarked) {
/* Run ifdown part of the reload */
ni_debug_application("Shutting down unneeded devices");
if (ni_fsm_start_matching_workers(fsm, &down_marked)) {
/* Execute the down run */
if (ni_fsm_schedule(fsm) != 0)
ni_fsm_mainloop(fsm);
}
}
else {
ni_debug_application("No interfaces to be brought down\n");
}

ni_fsm_pull_in_children(&up_marked);
ni_ifworkers_flatten(&up_marked);

/* anything to ifup? */
if (up_marked.count) {
if (!ni_client_create(fsm, &up_marked)) {
/* Severe error we always explicitly return */
status = NI_WICKED_RC_ERROR;
goto cleanup;
}

/* And trigger up */
ni_debug_application("Reloading all changed devices");
if (!ni_ifup_hire_nanny(&up_marked, set_persistent))
status = NI_WICKED_RC_NOT_CONFIGURED;

/* Wait for device-up events */
ni_timer_register(ni_wait_for_interfaces, ni_client_timer_expires, &status);
while (status == NI_WICKED_RC_SUCCESS) {
/* status is already success */
if (0 == up_marked.count)
break;

if (ni_socket_wait(ni_wait_for_interfaces) != 0)
ni_fatal("ni_socket_wait failed");

ni_timer_next_timeout();
}

/* 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;
}
else {
ni_debug_application("No interfaces to be brought up\n");
}

cleanup:
ni_string_array_destroy(&opt_ifconfig);
ni_ifworker_array_destroy(&down_marked);
ni_ifworker_array_destroy(&up_marked);
return status;
}

int
ni_do_ifreload(int argc, char **argv)
{
if (ni_config_use_nanny())
return ni_do_ifreload_nanny(argc, argv);
else
return ni_do_ifreload_direct(argc, argv);
}
2 changes: 1 addition & 1 deletion client/ifup.c
Expand Up @@ -177,7 +177,7 @@ ni_ifup_start_policy(ni_ifworker_t *w)
return rv;
}

static ni_bool_t
ni_bool_t
ni_ifup_hire_nanny(ni_ifworker_array_t *array, ni_bool_t set_persistent)
{
unsigned int i;
Expand Down
1 change: 1 addition & 0 deletions client/ifup.h
Expand Up @@ -30,5 +30,6 @@
extern unsigned int ni_wait_for_interfaces;

extern int ni_do_ifup(int argc, char **argv);
extern ni_bool_t ni_ifup_hire_nanny(ni_ifworker_array_t *, ni_bool_t);

#endif /* __WICKED_CLIENT_IFUP_H__ */
2 changes: 2 additions & 0 deletions client/wicked-client.h
Expand Up @@ -121,6 +121,8 @@ extern ni_device_clientinfo_t * ni_ifconfig_get_client_info(xml_document_t *);
extern void ni_ifconfig_add_client_info(xml_document_t *, ni_device_clientinfo_t *, char *);
extern void ni_ifconfig_del_client_info(xml_document_t *, const char *);

extern void ni_state_change_signal_handler(ni_dbus_connection_t *, ni_dbus_message_t *, void *);
extern void ni_client_timer_expires(void *, const ni_timer_t *);
extern ni_bool_t ni_client_create(ni_fsm_t *, void *);

static inline void
Expand Down

0 comments on commit 44a2b27

Please sign in to comment.