Created
September 19, 2019 12:38
-
-
Save bentech/97d4969c9aa0337dcc3958f3e44c2b27 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From bebc5277c0fb8ed30f6e2e74cd623aa7c2f79712 Mon Sep 17 00:00:00 2001 | |
From: Ben Swanson <[email protected]> | |
Date: Thu, 19 Sep 2019 11:54:14 +0100 | |
Subject: [PATCH] ip4vfallback | |
--- | |
src/libsystemd-network/sd-dhcp-client.c | 8 ++-- | |
src/network/networkd-dhcp4.c | 16 +++++++- | |
src/network/networkd-ipv4ll.c | 2 +- | |
src/network/networkd-link.c | 49 +++++++++++++++-------- | |
src/network/networkd-link.h | 3 ++ | |
src/network/networkd-network-gperf.gperf | 2 +- | |
src/network/networkd-network.c | 16 +++++++- | |
src/network/networkd-util.c | 51 ++++++++++-------------- | |
src/network/networkd-util.h | 17 +++++--- | |
src/network/test-network-tables.c | 3 +- | |
10 files changed, 105 insertions(+), 62 deletions(-) | |
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c | |
index ff434f8ce7..f9232dcbc1 100644 | |
--- a/src/libsystemd-network/sd-dhcp-client.c | |
+++ b/src/libsystemd-network/sd-dhcp-client.c | |
@@ -30,6 +30,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 6 | |
+ | |
#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) | |
#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) | |
@@ -1050,7 +1052,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; | |
} | |
@@ -1058,7 +1060,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; | |
@@ -1068,7 +1070,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 34c1f63568..07ad583a9c 100644 | |
--- a/src/network/networkd-dhcp4.c | |
+++ b/src/network/networkd-dhcp4.c | |
@@ -516,6 +516,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; | |
@@ -528,8 +529,21 @@ 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."); | |
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c | |
index a710240f94..0363909ab5 100644 | |
--- a/src/network/networkd-ipv4ll.c | |
+++ b/src/network/networkd-ipv4ll.c | |
@@ -198,7 +198,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 4afcf843bd..ef0d02cfca 100644 | |
--- a/src/network/networkd-link.c | |
+++ b/src/network/networkd-link.c | |
@@ -66,7 +66,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) | |
@@ -81,6 +81,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); | |
@@ -728,39 +746,36 @@ void link_check_ready(Link *link) { | |
if (!link->network) | |
return; | |
+ | |
+ SET_FOREACH(a, link->addresses, i) | |
+ if (!address_is_ready(a)) | |
+ return; | |
+ | |
if (!link->static_routes_configured) | |
return; | |
if (!link->routing_policy_rules_configured) | |
return; | |
- if (link_ipv4ll_enabled(link)) | |
- if (!link->ipv4ll_address || | |
- !link->ipv4ll_route) | |
- return; | |
+ if (link_ipv4ll_enabled(link) && !(link->ipv4ll_address && link->ipv4ll_route)) | |
+ return; | |
if (!link->network->bridge) { | |
if (link_ipv6ll_enabled(link)) | |
if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0) | |
return; | |
- | |
- if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && | |
- !link->dhcp4_configured) || | |
- (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && | |
- !link->dhcp6_configured) || | |
- (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && | |
- !link->dhcp4_configured && !link->dhcp6_configured)) | |
+ if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && | |
+ !(link->dhcp4_configured || link->dhcp6_configured) && | |
+ !(link_ipv4ll_fallback_enabled(link) && link->ipv4ll_address && link->ipv4ll_route)) | |
+ /* When DHCP is enabled, at least one protocol must provide an address, or | |
+ * an IPv4ll fallback address must be configured. */ | |
return; | |
if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) | |
return; | |
} | |
- SET_FOREACH(a, link->addresses, i) | |
- if (!address_is_ready(a)) | |
- return; | |
- | |
if (link->state != LINK_STATE_CONFIGURED) | |
link_enter_configured(link); | |
@@ -2784,7 +2799,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 7e22dfd504..0124a4462a 100644 | |
--- a/src/network/networkd-link.h | |
+++ b/src/network/networkd-link.h | |
@@ -156,6 +156,9 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address); | |
int link_set_mtu(Link *link, uint32_t mtu); | |
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_promote_secondaries(Link *link); | |
int dhcp6_configure(Link *link); | |
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf | |
index 6ad5257f79..6775949e67 100644 | |
--- a/src/network/networkd-network-gperf.gperf | |
+++ b/src/network/networkd-network-gperf.gperf | |
@@ -49,7 +49,7 @@ Network.Tunnel, config_parse_tunnel, | |
Network.VRF, config_parse_netdev, 0, 0 | |
Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) | |
Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) | |
-Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) | |
+Network.LinkLocalAddressing, config_parse_link_local_address_family_boolean, 0, offsetof(Network, link_local) | |
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) | |
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) | |
Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) | |
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c | |
index 429aac5e6c..be21c868d1 100644 | |
--- a/src/network/networkd-network.c | |
+++ b/src/network/networkd-network.c | |
@@ -784,6 +784,7 @@ int config_parse_ipv4ll( | |
void *userdata) { | |
AddressFamilyBoolean *link_local = data; | |
+ int r; | |
assert(filename); | |
assert(lvalue); | |
@@ -794,7 +795,20 @@ int config_parse_ipv4ll( | |
* config_parse_address_family_boolean(), except that it | |
* applies only to IPv4 */ | |
- SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue)); | |
+ r = parse_boolean(rvalue); | |
+ if (r < 0) { | |
+ log_syntax(unit, LOG_ERR, filename, line, r, | |
+ "Failed to parse %s=%s, ignoring assignment. " | |
+ "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.", | |
+ lvalue, rvalue, lvalue); | |
+ return 0; | |
+ } | |
+ | |
+ SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r); | |
+ | |
+ log_syntax(unit, LOG_WARNING, filename, line, 0, | |
+ "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.", | |
+ lvalue, rvalue, address_family_boolean_to_string(*link_local)); | |
return 0; | |
} | |
diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c | |
index 9b6bc12858..107424b233 100644 | |
--- a/src/network/networkd-util.c | |
+++ b/src/network/networkd-util.c | |
@@ -8,38 +8,27 @@ | |
#include "string-util.h" | |
#include "util.h" | |
-const char *address_family_boolean_to_string(AddressFamilyBoolean b) { | |
- if (IN_SET(b, ADDRESS_FAMILY_YES, ADDRESS_FAMILY_NO)) | |
- return yes_no(b == ADDRESS_FAMILY_YES); | |
+static const char * const address_family_boolean_table[_ADDRESS_FAMILY_BOOLEAN_MAX] = { | |
+ [ADDRESS_FAMILY_NO] = "no", | |
+ [ADDRESS_FAMILY_YES] = "yes", | |
+ [ADDRESS_FAMILY_IPV4] = "ipv4", | |
+ [ADDRESS_FAMILY_IPV6] = "ipv6", | |
+}; | |
+ | |
+static const char * const link_local_address_family_boolean_table[_ADDRESS_FAMILY_BOOLEAN_MAX] = { | |
+ [ADDRESS_FAMILY_NO] = "no", | |
+ [ADDRESS_FAMILY_YES] = "yes", | |
+ [ADDRESS_FAMILY_IPV4] = "ipv4", | |
+ [ADDRESS_FAMILY_IPV6] = "ipv6", | |
+ [ADDRESS_FAMILY_FALLBACK] = "fallback", | |
+ [ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback", | |
+}; | |
+ | |
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family_boolean, AddressFamilyBoolean, ADDRESS_FAMILY_YES); | |
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family_boolean, AddressFamilyBoolean, ADDRESS_FAMILY_YES); | |
+DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family_boolean, link_local_address_family_boolean, | |
+ AddressFamilyBoolean, "Failed to parse option"); | |
- if (b == ADDRESS_FAMILY_IPV4) | |
- return "ipv4"; | |
- if (b == ADDRESS_FAMILY_IPV6) | |
- return "ipv6"; | |
- | |
- return NULL; | |
-} | |
- | |
-AddressFamilyBoolean address_family_boolean_from_string(const char *s) { | |
- int r; | |
- | |
- /* Make this a true superset of a boolean */ | |
- | |
- r = parse_boolean(s); | |
- if (r > 0) | |
- return ADDRESS_FAMILY_YES; | |
- if (r == 0) | |
- return ADDRESS_FAMILY_NO; | |
- | |
- if (streq(s, "ipv4")) | |
- return ADDRESS_FAMILY_IPV4; | |
- if (streq(s, "ipv6")) | |
- return ADDRESS_FAMILY_IPV6; | |
- | |
- return _ADDRESS_FAMILY_BOOLEAN_INVALID; | |
-} | |
- | |
-DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option"); | |
int config_parse_address_family_boolean_with_kernel( | |
const char* unit, | |
diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h | |
index 0fb41caaf6..5c1de8b60f 100644 | |
--- a/src/network/networkd-util.h | |
+++ b/src/network/networkd-util.h | |
@@ -7,18 +7,23 @@ | |
typedef enum AddressFamilyBoolean { | |
/* This is a bitmask, though it usually doesn't feel that way! */ | |
- ADDRESS_FAMILY_NO = 0, | |
- ADDRESS_FAMILY_IPV4 = 1, | |
- ADDRESS_FAMILY_IPV6 = 2, | |
- ADDRESS_FAMILY_YES = 3, | |
+ 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; | |
-CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean); | |
+CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family_boolean); | |
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean_with_kernel); | |
const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; | |
-AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; | |
+AddressFamilyBoolean address_family_boolean_from_string(const char *s) _pure_; | |
+ | |
+const char *link_local_address_family_boolean_to_string(AddressFamilyBoolean b) _const_; | |
+AddressFamilyBoolean link_local_address_family_boolean_from_string(const char *s) _pure_; | |
int kernel_route_expiration_supported(void); | |
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c | |
index 11cd7faa8b..4597c85c84 100644 | |
--- a/src/network/test-network-tables.c | |
+++ b/src/network/test-network-tables.c | |
@@ -12,7 +12,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); | |
@@ -38,5 +37,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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment