From: LetzteInstanz Date: Tue, 13 Apr 2021 11:57:19 +0000 (+0300) Subject: wait-online: wait for address family X-Git-Tag: v249-rc1~420^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=6dc4531d165c7aeb6816f7545a4c47aacb52ff48;p=thirdparty%2Fsystemd.git wait-online: wait for address family This introduce -4 and -6 commandline options. --- diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml index 6d2c71d8c7b..31aa02218af 100644 --- a/man/systemd-networkd-wait-online.service.xml +++ b/man/systemd-networkd-wait-online.service.xml @@ -85,6 +85,34 @@ + + + + + Waiting for an IPv4 address of each network interface to be configured. If this + option is specified with , then + systemd-networkd-wait-online exits with success when at least one interface + becomes online and has an IPv4 address. The option is applied only for the operational state + degraded or above. If neither nor + is specified, then the value from + RequiredFamilyForOnline= in the corresponding .network + file is used if present. + + + + + + + Waiting for an IPv6 address of each network interface to be configured. If this + option is specified with , then + systemd-networkd-wait-online exits with success when at least one interface + becomes online and has an IPv6 address. The option is applied only for the operational state + degraded or above. If neither nor + is specified, then the value from + RequiredFamilyForOnline= in the corresponding .network + file is used if present. + + diff --git a/src/network/wait-online/link.c b/src/network/wait-online/link.c index f2d556f099e..5a33d563c24 100644 --- a/src/network/wait-online/link.c +++ b/src/network/wait-online/link.c @@ -97,7 +97,8 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { } int link_update_monitor(Link *l) { - _cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *state = NULL; + _cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *required_family = NULL, + *ipv4_address_state = NULL, *ipv6_address_state = NULL, *state = NULL; int r, ret = 0; assert(l); @@ -135,6 +136,47 @@ int link_update_monitor(Link *l) { l->operational_state = s; } + r = sd_network_link_get_required_family_for_online(l->ifindex, &required_family); + if (r < 0) + ret = log_link_debug_errno(l, r, "Failed to get required address family, ignoring: %m"); + else if (isempty(required_family)) + l->required_family = ADDRESS_FAMILY_NO; + else { + AddressFamily f; + + f = link_required_address_family_from_string(required_family); + if (f < 0) + ret = log_link_debug_errno(l, f, "Failed to parse required address family, ignoring: %m"); + else + l->required_family = f; + } + + r = sd_network_link_get_ipv4_address_state(l->ifindex, &ipv4_address_state); + if (r < 0) + ret = log_link_debug_errno(l, r, "Failed to get IPv4 address state, ignoring: %m"); + else { + LinkAddressState s; + + s = link_address_state_from_string(ipv4_address_state); + if (s < 0) + ret = log_link_debug_errno(l, s, "Failed to parse IPv4 address state, ignoring: %m"); + else + l->ipv4_address_state = s; + } + + r = sd_network_link_get_ipv6_address_state(l->ifindex, &ipv6_address_state); + if (r < 0) + ret = log_link_debug_errno(l, r, "Failed to get IPv6 address state, ignoring: %m"); + else { + LinkAddressState s; + + s = link_address_state_from_string(ipv6_address_state); + if (s < 0) + ret = log_link_debug_errno(l, s, "Failed to parse IPv6 address state, ignoring: %m"); + else + l->ipv6_address_state = s; + } + r = sd_network_link_get_setup_state(l->ifindex, &state); if (r < 0) ret = log_link_debug_errno(l, r, "Failed to get setup state, ignoring: %m"); diff --git a/src/network/wait-online/link.h b/src/network/wait-online/link.h index 3aa83572938..3072a91e565 100644 --- a/src/network/wait-online/link.h +++ b/src/network/wait-online/link.h @@ -19,6 +19,9 @@ struct Link { bool required_for_online; LinkOperationalStateRange required_operstate; LinkOperationalState operational_state; + AddressFamily required_family; + LinkAddressState ipv4_address_state; + LinkAddressState ipv6_address_state; char *state; }; diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 1438b27445c..8238b704648 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -32,6 +32,13 @@ static bool manager_ignore_link(Manager *m, Link *link) { } static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange s) { + AddressFamily required_family; + bool needs_ipv4; + bool needs_ipv6; + + assert(m); + assert(l); + /* This returns the following: * -EAGAIN: not processed by udev or networkd * 0: operstate is not enough @@ -60,7 +67,35 @@ static int manager_link_is_online(Manager *m, Link *l, LinkOperationalStateRange return 0; } + required_family = m->required_family > 0 ? m->required_family : l->required_family; + needs_ipv4 = required_family & ADDRESS_FAMILY_IPV4; + needs_ipv6 = required_family & ADDRESS_FAMILY_IPV6; + + if (s.min >= LINK_OPERSTATE_DEGRADED) { + if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_DEGRADED) + goto ipv4_not_ready; + + if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_DEGRADED) + goto ipv6_not_ready; + } + + if (s.min >= LINK_OPERSTATE_ROUTABLE) { + if (needs_ipv4 && l->ipv4_address_state < LINK_ADDRESS_STATE_ROUTABLE) + goto ipv4_not_ready; + + if (needs_ipv6 && l->ipv6_address_state < LINK_ADDRESS_STATE_ROUTABLE) + goto ipv6_not_ready; + } + return 1; + +ipv4_not_ready: + log_link_debug(l, "No routable or link-local IPv4 address is configured."); + return 0; + +ipv6_not_ready: + log_link_debug(l, "No routable or link-local IPv6 address is configured."); + return 0; } bool manager_configured(Manager *m) { @@ -298,6 +333,7 @@ static int manager_network_monitor_listen(Manager *m) { int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, LinkOperationalStateRange required_operstate, + AddressFamily required_family, bool any, usec_t timeout) { _cleanup_(manager_freep) Manager *m = NULL; int r; @@ -312,6 +348,7 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, .interfaces = interfaces, .ignore = ignore, .required_operstate = required_operstate, + .required_family = required_family, .any = any, }; diff --git a/src/network/wait-online/manager.h b/src/network/wait-online/manager.h index 9892a43dc98..f2e091638c4 100644 --- a/src/network/wait-online/manager.h +++ b/src/network/wait-online/manager.h @@ -21,6 +21,7 @@ struct Manager { char **ignore; LinkOperationalStateRange required_operstate; + AddressFamily required_family; bool any; sd_netlink *rtnl; @@ -35,6 +36,7 @@ struct Manager { Manager* manager_free(Manager *m); int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, LinkOperationalStateRange required_operstate, + AddressFamily required_family, bool any, usec_t timeout); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); diff --git a/src/network/wait-online/wait-online.c b/src/network/wait-online/wait-online.c index ca0116e7f30..bbf51b6d3b6 100644 --- a/src/network/wait-online/wait-online.c +++ b/src/network/wait-online/wait-online.c @@ -19,6 +19,7 @@ static usec_t arg_timeout = 120 * USEC_PER_SEC; static Hashmap *arg_interfaces = NULL; static char **arg_ignore = NULL; static LinkOperationalStateRange arg_required_operstate = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID }; +static AddressFamily arg_required_family = ADDRESS_FAMILY_NO; static bool arg_any = false; STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_freep); @@ -42,6 +43,8 @@ static int help(void) { " --ignore=INTERFACE Don't take these interfaces into account\n" " -o --operational-state=MIN_OPERSTATE[:MAX_OPERSTATE]\n" " Required operational state\n" + " -4 --ipv4 Requires at least one IPv4 address\n" + " -6 --ipv6 Requires at least one IPv6 address\n" " --any Wait until at least one of the interfaces is online\n" " --timeout=SECS Maximum time to wait for network connectivity\n" "\nSee the %s for details.\n", @@ -111,6 +114,8 @@ static int parse_argv(int argc, char *argv[]) { { "interface", required_argument, NULL, 'i' }, { "ignore", required_argument, NULL, ARG_IGNORE }, { "operational-state", required_argument, NULL, 'o' }, + { "ipv4", no_argument, NULL, '4' }, + { "ipv6", no_argument, NULL, '6' }, { "any", no_argument, NULL, ARG_ANY }, { "timeout", required_argument, NULL, ARG_TIMEOUT }, {} @@ -121,7 +126,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hi:qo:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hi:qo:46", options, NULL)) >= 0) switch (c) { @@ -159,6 +164,15 @@ static int parse_argv(int argc, char *argv[]) { break; } + + case '4': + arg_required_family |= ADDRESS_FAMILY_IPV4; + break; + + case '6': + arg_required_family |= ADDRESS_FAMILY_IPV6; + break; + case ARG_ANY: arg_any = true; break; @@ -197,7 +211,7 @@ static int run(int argc, char *argv[]) { assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); - r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_any, arg_timeout); + r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_required_family, arg_any, arg_timeout); if (r < 0) return log_error_errno(r, "Could not create manager: %m");