network: read the minimum and maximum MTU of the interface, and adjust requested MTU based on these values

This commit is contained in:
Yu Watanabe
2021-06-06 14:46:58 +09:00
parent 7558f9e717
commit 717ba5fc90
3 changed files with 54 additions and 12 deletions

View File

@@ -2012,7 +2012,7 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
}
static int link_update_mtu(Link *link, sd_netlink_message *message) {
uint32_t mtu;
uint32_t mtu, min_mtu = 0, max_mtu = UINT32_MAX;
int r;
assert(link);
@@ -2024,16 +2024,34 @@ static int link_update_mtu(Link *link, sd_netlink_message *message) {
if (r < 0)
return log_link_debug_errno(link, r, "rtnl: failed to read MTU in RTM_NEWLINK message: %m");
if (mtu == 0 || link->mtu == mtu)
r = sd_netlink_message_read_u32(message, IFLA_MIN_MTU, &min_mtu);
if (r < 0 && r != -ENODATA)
return log_link_debug_errno(link, r, "rtnl: failed to read minimum MTU in RTM_NEWLINK message: %m");
r = sd_netlink_message_read_u32(message, IFLA_MAX_MTU, &max_mtu);
if (r < 0 && r != -ENODATA)
return log_link_debug_errno(link, r, "rtnl: failed to read maximum MTU in RTM_NEWLINK message: %m");
if (mtu == 0)
return 0;
if (max_mtu == 0)
max_mtu = UINT32_MAX;
link->min_mtu = min_mtu;
link->max_mtu = max_mtu;
if (link->original_mtu == 0) {
link->original_mtu = mtu;
log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu);
log_link_debug(link, "Saved original MTU %" PRIu32" (min: %"PRIu32", max: %"PRIu32")",
link->original_mtu, link->min_mtu, link->max_mtu);
}
if (link->mtu != 0)
log_link_debug(link, "MTU is changed: %"PRIu32" → %"PRIu32, link->mtu, mtu);
if (link->mtu == mtu)
return 0;
log_link_debug(link, "MTU is changed: %"PRIu32" → %"PRIu32" (min: %"PRIu32", max: %"PRIu32")",
link->mtu, mtu, link->min_mtu, link->max_mtu);
link->mtu = mtu;

View File

@@ -58,6 +58,9 @@ typedef struct Link {
struct ether_addr permanent_mac;
struct in6_addr ipv6ll_address;
uint32_t mtu;
uint32_t min_mtu;
uint32_t max_mtu;
uint32_t original_mtu;
sd_device *sd_device;
char *driver;
@@ -114,7 +117,6 @@ typedef struct Link {
Address *dhcp_address, *dhcp_address_old;
Set *dhcp_routes, *dhcp_routes_old;
char *lease_file;
uint32_t original_mtu;
unsigned dhcp4_messages;
sd_ipv4acd *dhcp_acd;
bool dhcp4_route_failed:1;

View File

@@ -677,16 +677,38 @@ int link_request_to_set_master(Link *link) {
int link_request_to_set_mtu(Link *link, uint32_t mtu) {
Request *req = NULL; /* avoid false maybe-uninitialized warning */
const char *origin;
uint32_t min_mtu;
int r;
assert(link);
assert(link->network);
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
* MTU bytes to IPV6_MTU_MIN. */
if (mtu < IPV6_MIN_MTU && link_ipv6_enabled(link)) {
log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as IPv6 is enabled "
"and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes");
mtu = IPV6_MIN_MTU;
min_mtu = link->min_mtu;
origin = "the minimum MTU of the interface";
if (link_ipv6_enabled(link)) {
/* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up
* MTU bytes to IPV6_MTU_MIN. */
if (min_mtu < IPV6_MIN_MTU) {
min_mtu = IPV6_MIN_MTU;
origin = "the minimum IPv6 MTU";
}
if (min_mtu < link->network->ipv6_mtu) {
min_mtu = link->network->ipv6_mtu;
origin = "the requested IPv6 MTU in IPv6MTUBytes=";
}
}
if (mtu < min_mtu) {
log_link_warning(link, "Bumping the requested MTU %"PRIu32" to %s (%"PRIu32")",
mtu, origin, min_mtu);
mtu = min_mtu;
}
if (mtu > link->max_mtu) {
log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".",
mtu, link->max_mtu);
mtu = link->max_mtu;
}
if (link->mtu == mtu)