From 8bc17bb3f707c99b6c9ad295563c92b38141a1f4 Mon Sep 17 00:00:00 2001 From: Susant Sahani Date: Wed, 1 May 2019 12:13:23 +0530 Subject: [PATCH] networkd: Option to use LinkLocalAddressing only when DHCP fails When LinkLocalAddressing=fallback or LinkLocalAddressing=ipv4-fallback then IPv4LL will be started only when DHCP fails. Closes #9648. --- man/systemd.network.xml | 13 ++++++++++--- src/libsystemd-network/sd-dhcp-client.c | 12 ++++++++---- src/network/networkd-dhcp4.c | 18 +++++++++++++++++- src/network/networkd-ipv4ll.c | 2 +- src/network/networkd-link.c | 22 ++++++++++++++++++++-- src/network/networkd-link.h | 3 +++ src/network/networkd-util.c | 8 ++++++++ src/network/networkd-util.h | 10 ++++++---- src/network/test-network-tables.c | 2 +- 9 files changed, 74 insertions(+), 16 deletions(-) diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 604eea4c18..b86bcf03ef 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -326,9 +326,16 @@ LinkLocalAddressing= Enables link-local address autoconfiguration. Accepts yes, - no, ipv4, or ipv6. If - Bridge= is set, defaults to no, and if not, - defaults to ipv6. + no, ipv4, ipv6, + fallback, or ipv4-fallback. If + fallback or ipv4-fallback is specified, then an IPv4 + link-local address is configured only when DHCPv4 fails. If fallback, + an IPv6 link-local address is always configured, and if ipv4-fallback, + the address is not configured. Note that, the fallback mechanism works only when DHCPv4 + client is enabled, that is, it requires DHCP=yes or + DHCP=ipv4. If Bridge= is set, defaults to + no, and if not, defaults to ipv6. + diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 97e1dd3702..f10ae3ed3b 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -32,6 +32,8 @@ #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) +#define MAX_CLIENT_ATTEMPT 64 + #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) @@ -1050,8 +1052,10 @@ static int client_timeout_resend( case DHCP_STATE_REQUESTING: case DHCP_STATE_BOUND: - if (client->attempt < 64) + if (client->attempt < MAX_CLIENT_ATTEMPT) client->attempt *= 2; + else + goto error; next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC; @@ -1079,7 +1083,7 @@ static int client_timeout_resend( client->state = DHCP_STATE_SELECTING; client->attempt = 1; } else { - if (client->attempt >= 64) + if (client->attempt >= MAX_CLIENT_ATTEMPT) goto error; } @@ -1087,7 +1091,7 @@ static int client_timeout_resend( case DHCP_STATE_SELECTING: r = client_send_discover(client); - if (r < 0 && client->attempt >= 64) + if (r < 0 && client->attempt >= MAX_CLIENT_ATTEMPT) goto error; break; @@ -1097,7 +1101,7 @@ static int client_timeout_resend( case DHCP_STATE_RENEWING: case DHCP_STATE_REBINDING: r = client_send_request(client); - if (r < 0 && client->attempt >= 64) + if (r < 0 && client->attempt >= MAX_CLIENT_ATTEMPT) goto error; if (client->state == DHCP_STATE_INIT_REBOOT) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 301d9c67b9..c630359027 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -511,6 +511,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { return 0; } + static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { Link *link = userdata; int r = 0; @@ -523,9 +524,24 @@ static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { return; switch (event) { - case SD_DHCP_CLIENT_EVENT_EXPIRED: case SD_DHCP_CLIENT_EVENT_STOP: + + if (link_ipv4ll_fallback_enabled(link)) { + assert(link->ipv4ll); + + log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address"); + + r = sd_ipv4ll_start(link->ipv4ll); + if (r < 0) { + log_link_warning(link, "Could not acquire IPv4 link-local address: %m"); + return; + } + } + + _fallthrough_; + case SD_DHCP_CLIENT_EVENT_EXPIRED: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: + if (link->network->dhcp_critical) { log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it."); return; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 829dc48a0a..fb4bf266a6 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -197,7 +197,7 @@ int ipv4ll_configure(Link *link) { assert(link); assert(link->network); - assert(link->network->link_local & ADDRESS_FAMILY_IPV4); + assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)); if (!link->ipv4ll) { r = sd_ipv4ll_new(&link->ipv4ll); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index c56b4dfceb..695c9e4baf 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -110,7 +110,7 @@ static bool link_dhcp4_server_enabled(Link *link) { return link->network->dhcp_server; } -static bool link_ipv4ll_enabled(Link *link) { +bool link_ipv4ll_enabled(Link *link) { assert(link); if (link->flags & IFF_LOOPBACK) @@ -128,6 +128,24 @@ static bool link_ipv4ll_enabled(Link *link) { return link->network->link_local & ADDRESS_FAMILY_IPV4; } +bool link_ipv4ll_fallback_enabled(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + if (STRPTR_IN_SET(link->kind, "vrf", "wireguard")) + return false; + + if (link->network->bond) + return false; + + return link->network->link_local & ADDRESS_FAMILY_FALLBACK_IPV4; +} + static bool link_ipv6ll_enabled(Link *link) { assert(link); @@ -3114,7 +3132,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - if (link_ipv4ll_enabled(link)) { + if (link_ipv4ll_enabled(link) || link_ipv4ll_fallback_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) return r; diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7d8808e400..b43401afc6 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -160,6 +160,9 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu, bool force); int ipv4ll_configure(Link *link); +bool link_ipv4ll_enabled(Link *link); +bool link_ipv4ll_fallback_enabled(Link *link); + int dhcp4_configure(Link *link); int dhcp4_set_client_identifier(Link *link); int dhcp4_set_promote_secondaries(Link *link); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index a088d25981..d0994df32f 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -16,6 +16,10 @@ const char *address_family_boolean_to_string(AddressFamilyBoolean b) { return "ipv4"; if (b == ADDRESS_FAMILY_IPV6) return "ipv6"; + if (b == ADDRESS_FAMILY_FALLBACK) + return "fallback"; + if (b == ADDRESS_FAMILY_FALLBACK) + return "ipv4-fallback"; return NULL; } @@ -35,6 +39,10 @@ AddressFamilyBoolean address_family_boolean_from_string(const char *s) { return ADDRESS_FAMILY_IPV4; if (streq(s, "ipv6")) return ADDRESS_FAMILY_IPV6; + if (streq(s, "fallback")) + return ADDRESS_FAMILY_FALLBACK; + if (streq(s, "ipv4-fallback")) + return ADDRESS_FAMILY_FALLBACK_IPV4; return _ADDRESS_FAMILY_BOOLEAN_INVALID; } diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index 9c472cfd50..c04cc3bd4a 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -7,10 +7,12 @@ typedef enum AddressFamilyBoolean { /* This is a bitmask, though it usually doesn't feel that way! */ - ADDRESS_FAMILY_NO = 0, - ADDRESS_FAMILY_IPV4 = 1 << 0, - ADDRESS_FAMILY_IPV6 = 1 << 1, - ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6, + ADDRESS_FAMILY_NO = 0, + ADDRESS_FAMILY_IPV4 = 1 << 0, + ADDRESS_FAMILY_IPV6 = 1 << 1, + ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6, + ADDRESS_FAMILY_FALLBACK_IPV4 = 1 << 2, + ADDRESS_FAMILY_FALLBACK = ADDRESS_FAMILY_FALLBACK_IPV4 | ADDRESS_FAMILY_IPV6, _ADDRESS_FAMILY_BOOLEAN_MAX, _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, } AddressFamilyBoolean; diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index 6b110b7110..711954e4a2 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -14,7 +14,6 @@ #include "test-tables.h" int main(int argc, char **argv) { - test_table(address_family_boolean, ADDRESS_FAMILY_BOOLEAN); test_table(bond_ad_select, NETDEV_BOND_AD_SELECT); test_table(bond_arp_all_targets, NETDEV_BOND_ARP_ALL_TARGETS); test_table(bond_arp_validate, NETDEV_BOND_ARP_VALIDATE); @@ -42,6 +41,7 @@ int main(int argc, char **argv) { test_table_sparse(ipvlan_mode, NETDEV_IPVLAN_MODE); test_table_sparse(macvlan_mode, NETDEV_MACVLAN_MODE); + test_table_sparse(address_family_boolean, ADDRESS_FAMILY_BOOLEAN); return EXIT_SUCCESS; }