mirror of
https://github.com/systemd/systemd.git
synced 2024-11-23 18:23:32 +08:00
Merge pull request #34736 from yuwata/network-mtu
network: wait for IPv6 MTU being synced to link MTU
This commit is contained in:
commit
11a8cb490f
@ -10,6 +10,7 @@
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
@ -193,3 +194,29 @@ int sysctl_read_ip_property(int af, const char *ifname, const char *property, ch
|
||||
|
||||
return sysctl_read(p, ret);
|
||||
}
|
||||
|
||||
int sysctl_read_ip_property_int(int af, const char *ifname, const char *property, int *ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = sysctl_read_ip_property(af, ifname, property, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return safe_atoi(s, ret);
|
||||
}
|
||||
|
||||
int sysctl_read_ip_property_uint32(int af, const char *ifname, const char *property, uint32_t *ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = sysctl_read_ip_property(af, ifname, property, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return safe_atou32(s, ret);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ static inline int sysctl_write(const char *property, const char *value) {
|
||||
}
|
||||
|
||||
int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret);
|
||||
int sysctl_read_ip_property_int(int af, const char *ifname, const char *property, int *ret);
|
||||
int sysctl_read_ip_property_uint32(int af, const char *ifname, const char *property, uint32_t *ret);
|
||||
int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value, Hashmap **shadow);
|
||||
static inline int sysctl_write_ip_property_boolean(int af, const char *ifname, const char *property, bool value, Hashmap **shadow) {
|
||||
return sysctl_write_ip_property(af, ifname, property, one_zero(value), shadow);
|
||||
|
@ -288,6 +288,7 @@ static Link *link_free(Link *link) {
|
||||
network_unref(link->network);
|
||||
|
||||
sd_event_source_disable_unref(link->carrier_lost_timer);
|
||||
sd_event_source_disable_unref(link->ipv6_mtu_wait_synced_event_source);
|
||||
|
||||
return mfree(link);
|
||||
}
|
||||
@ -1869,8 +1870,6 @@ static int link_carrier_lost(Link *link) {
|
||||
}
|
||||
|
||||
static int link_admin_state_up(Link *link) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* This is called every time an interface admin state changes to up;
|
||||
@ -1886,9 +1885,7 @@ static int link_admin_state_up(Link *link) {
|
||||
|
||||
/* We set the ipv6 mtu after the device mtu, but the kernel resets
|
||||
* ipv6 mtu on NETDEV_UP, so we need to reset it. */
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
|
||||
(void) link_set_ipv6_mtu(link, LOG_INFO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2439,12 +2436,9 @@ static int link_update_mtu(Link *link, sd_netlink_message *message) {
|
||||
|
||||
link->mtu = mtu;
|
||||
|
||||
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
|
||||
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
/* The kernel resets IPv6 MTU after changing device MTU. So, we need to re-set IPv6 MTU again. */
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m");
|
||||
}
|
||||
(void) link_set_ipv6_mtu_async(link);
|
||||
|
||||
if (link->dhcp_client) {
|
||||
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
|
||||
|
@ -74,6 +74,9 @@ typedef struct Link {
|
||||
sd_device *dev;
|
||||
char *driver;
|
||||
|
||||
sd_event_source *ipv6_mtu_wait_synced_event_source;
|
||||
unsigned ipv6_mtu_wait_trial_count;
|
||||
|
||||
/* bridge vlan */
|
||||
uint16_t bridge_vlan_pvid;
|
||||
bool bridge_vlan_pvid_is_untagged;
|
||||
|
@ -1083,9 +1083,7 @@ static int ndisc_router_process_mtu(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
link->ndisc_mtu = mtu;
|
||||
|
||||
r = link_set_ipv6_mtu(link, LOG_DEBUG);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Failed to apply IPv6 MTU (%"PRIu32"), ignoring: %m", mtu);
|
||||
(void) link_set_ipv6_mtu(link, LOG_DEBUG);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -16,23 +16,26 @@
|
||||
#include "strv.h"
|
||||
#include "sysctl-util.h"
|
||||
|
||||
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096U
|
||||
#define ROUTES_DEFAULT_MAX_PER_FAMILY 4096
|
||||
|
||||
unsigned routes_max(void) {
|
||||
static thread_local unsigned cached = 0;
|
||||
_cleanup_free_ char *s4 = NULL, *s6 = NULL;
|
||||
unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
||||
int val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
||||
|
||||
if (cached > 0)
|
||||
return cached;
|
||||
|
||||
if (sysctl_read_ip_property(AF_INET, NULL, "route/max_size", &s4) >= 0)
|
||||
if (safe_atou(s4, &val4) >= 0 && val4 == 2147483647U)
|
||||
/* The kernel internally stores these maximum size in int. */
|
||||
|
||||
if (sysctl_read_ip_property_int(AF_INET, /* ifname = */ NULL, "route/max_size", &val4) >= 0)
|
||||
if (val4 == INT_MAX)
|
||||
/* This is the default "no limit" value in the kernel */
|
||||
val4 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
||||
|
||||
if (sysctl_read_ip_property(AF_INET6, NULL, "route/max_size", &s6) >= 0)
|
||||
(void) safe_atou(s6, &val6);
|
||||
if (sysctl_read_ip_property_int(AF_INET6, /* ifname = */ NULL, "route/max_size", &val6) >= 0)
|
||||
if (val6 == INT_MAX)
|
||||
/* This is the default "no limit" value in the kernel */
|
||||
val6 = ROUTES_DEFAULT_MAX_PER_FAMILY;
|
||||
|
||||
cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) +
|
||||
MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6);
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "af-list.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "missing_network.h"
|
||||
@ -503,6 +504,7 @@ static int link_set_ipv6_proxy_ndp(Link *link) {
|
||||
|
||||
int link_set_ipv6_mtu(Link *link, int log_level) {
|
||||
uint32_t mtu = 0;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
@ -510,6 +512,14 @@ int link_set_ipv6_mtu(Link *link, int log_level) {
|
||||
if (!link_is_configured_for_family(link, AF_INET6))
|
||||
return 0;
|
||||
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
return 0;
|
||||
|
||||
if (sd_event_source_get_enabled(link->ipv6_mtu_wait_synced_event_source, /* ret = */ NULL) > 0) {
|
||||
log_link_debug(link, "Waiting for IPv6 MTU is synced to link MTU, delaying to set IPv6 MTU.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(link->network);
|
||||
|
||||
if (link->network->ndisc_use_mtu)
|
||||
@ -526,7 +536,88 @@ int link_set_ipv6_mtu(Link *link, int log_level) {
|
||||
mtu = link->mtu;
|
||||
}
|
||||
|
||||
return sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
|
||||
r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", mtu, manager_get_sysctl_shadow(link->manager));
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to set IPv6 MTU to %"PRIu32": %m", mtu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata);
|
||||
|
||||
static int link_set_ipv6_mtu_async_impl(Link *link) {
|
||||
uint32_t current_mtu;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* When the link MTU is updated, it seems that the kernel IPv6 MTU of the interface is asynchronously
|
||||
* reset to the link MTU. Hence, we need to check if it is already reset, and wait for a while if not. */
|
||||
|
||||
if (++link->ipv6_mtu_wait_trial_count >= 10) {
|
||||
log_link_debug(link, "Timed out waiting for IPv6 MTU being synced to link MTU, proceeding anyway.");
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1; /* done */
|
||||
}
|
||||
|
||||
/* Check if IPv6 MTU is synced. */
|
||||
r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", ¤t_mtu);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
|
||||
|
||||
if (current_mtu == link->mtu) {
|
||||
/* Already synced. Update IPv6 MTU now. */
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1; /* done */
|
||||
}
|
||||
|
||||
/* If not, set up a timer event source. */
|
||||
r = event_reset_time_relative(
|
||||
link->manager->event, &link->ipv6_mtu_wait_synced_event_source,
|
||||
CLOCK_BOOTTIME, 100 * USEC_PER_MSEC, 0,
|
||||
ipv6_mtu_wait_synced_handler, link,
|
||||
/* priority = */ 0, "ipv6-mtu-wait-synced", /* force = */ true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to configure timer event source for waiting for IPv6 MTU being synced: %m");
|
||||
|
||||
/* Check again. */
|
||||
r = sysctl_read_ip_property_uint32(AF_INET6, link->ifname, "mtu", ¤t_mtu);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to read IPv6 MTU: %m");
|
||||
|
||||
if (current_mtu == link->mtu) {
|
||||
/* Synced while setting up the timer event source. Disable it and update IPv6 MTU now. */
|
||||
r = sd_event_source_set_enabled(link->ipv6_mtu_wait_synced_event_source, SD_EVENT_OFF);
|
||||
if (r < 0)
|
||||
log_link_debug_errno(link, r, "Failed to disable timer event source for IPv6 MTU, ignoring: %m");
|
||||
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1; /* done */
|
||||
}
|
||||
|
||||
log_link_debug(link, "IPv6 MTU is not synced to the link MTU after it is changed. Waiting for a while.");
|
||||
return 0; /* waiting */
|
||||
}
|
||||
|
||||
static int ipv6_mtu_wait_synced_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
(void) link_set_ipv6_mtu_async_impl(ASSERT_PTR(userdata));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int link_set_ipv6_mtu_async(Link *link) {
|
||||
assert(link);
|
||||
|
||||
link->ipv6_mtu_wait_trial_count = 0;
|
||||
return link_set_ipv6_mtu_async_impl(link);
|
||||
}
|
||||
|
||||
static int link_set_ipv4_accept_local(Link *link) {
|
||||
@ -616,9 +707,7 @@ int link_set_sysctl(Link *link) {
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
|
||||
|
||||
r = link_set_ipv6_mtu(link, LOG_INFO);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 MTU, ignoring: %m");
|
||||
(void) link_set_ipv6_mtu(link, LOG_INFO);
|
||||
|
||||
r = link_set_ipv6ll_stable_secret(link);
|
||||
if (r < 0)
|
||||
|
@ -42,6 +42,7 @@ void manager_set_sysctl(Manager *manager);
|
||||
int link_get_ip_forwarding(Link *link, int family);
|
||||
int link_set_sysctl(Link *link);
|
||||
int link_set_ipv6_mtu(Link *link, int log_level);
|
||||
int link_set_ipv6_mtu_async(Link *link);
|
||||
|
||||
const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_;
|
||||
IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
|
||||
|
Loading…
Reference in New Issue
Block a user