Skip to content

Instantly share code, notes, and snippets.

@bentech
Created September 19, 2019 12:38
Show Gist options
  • Save bentech/97d4969c9aa0337dcc3958f3e44c2b27 to your computer and use it in GitHub Desktop.
Save bentech/97d4969c9aa0337dcc3958f3e44c2b27 to your computer and use it in GitHub Desktop.
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