diff --git a/src/basic/missing.h b/src/basic/missing.h index 953b0f413e2..9fe750ae288 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1057,6 +1057,10 @@ struct input_mask { #define IPV6_MIN_MTU 1280 #endif +#ifndef IPV4_MIN_MTU +#define IPV4_MIN_MTU 68 +#endif + #ifndef IFF_MULTI_QUEUE #define IFF_MULTI_QUEUE 0x100 #endif diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 8398bdf117d..fbb32f3dc58 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -11,12 +11,14 @@ #include #include #include +#include #include "alloc-util.h" #include "errno-list.h" #include "extract-word.h" #include "locale-util.h" #include "macro.h" +#include "missing.h" #include "parse-util.h" #include "process-util.h" #include "string-util.h" @@ -93,6 +95,30 @@ int parse_ifindex(const char *s, int *ret) { return 0; } +int parse_mtu(int family, const char *s, uint32_t *ret) { + uint64_t u; + size_t m; + int r; + + r = parse_size(s, 1024, &u); + if (r < 0) + return r; + + if (u > UINT32_MAX) + return -ERANGE; + + if (family == AF_INET6) + m = IPV6_MIN_MTU; /* This is 1280 */ + else + m = IPV4_MIN_MTU; /* For all other protocols, including 'unspecified' we assume the IPv4 minimal MTU */ + + if (u < m) + return -ERANGE; + + *ret = (uint32_t) u; + return 0; +} + int parse_size(const char *t, uint64_t base, uint64_t *size) { /* Soo, sometimes we want to parse IEC binary suffixes, and diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 74c30b55706..742063c9a40 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -22,6 +22,7 @@ int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s, int *ret); +int parse_mtu(int family, const char *s, uint32_t *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index b14d1d21c6d..36b11030b0e 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -40,7 +40,7 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { } int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, - const struct ether_addr *mac, unsigned mtu) { + const struct ether_addr *mac, uint32_t mtu) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; int r; @@ -72,7 +72,7 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, return r; } - if (mtu > 0) { + if (mtu != 0) { r = sd_netlink_message_append_u32(message, IFLA_MTU, mtu); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 70eda91b038..c39ded34294 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -40,7 +40,7 @@ static inline bool rtnl_message_type_is_routing_policy_rule(uint16_t type) { } int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name); -int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu); +int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu); int rtnl_log_parse_error(int r); int rtnl_log_create_error(int r); diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index 3ef611d165a..54149bde0fd 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -40,7 +40,7 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; const char *mac = "98:fe:94:3f:c6:18", *name = "test"; char buffer[ETHER_ADDR_TO_STRING_MAX]; - unsigned int mtu = 1450, mtu_out; + uint32_t mtu = 1450, mtu_out; const char *name_out; struct ether_addr mac_out; @@ -66,7 +66,7 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) { static void test_link_get(sd_netlink *rtnl, int ifindex) { sd_netlink_message *m; sd_netlink_message *r; - unsigned int mtu = 1500; + uint32_t mtu = 1500; const char *str_data; uint8_t u8_data; uint32_t u32_data; diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c index 175acb4cfbc..4e865553ec0 100644 --- a/src/network/netdev/geneve.c +++ b/src/network/netdev/geneve.c @@ -66,7 +66,7 @@ static int netdev_geneve_create(NetDev *netdev) { return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m"); } - if (netdev->mtu) { + if (netdev->mtu != 0) { r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m"); diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index ba6268fa66e..c0d4375a990 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -40,7 +40,7 @@ Match.Architecture, config_parse_net_condition, CONDITI NetDev.Description, config_parse_string, 0, offsetof(NetDev, description) NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname) NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind) -NetDev.MTUBytes, config_parse_iec_size, 0, offsetof(NetDev, mtu) +NetDev.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(NetDev, mtu) NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac) VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id) VLAN.GVRP, config_parse_tristate, 0, offsetof(VLan, gvrp) @@ -50,7 +50,7 @@ VLAN.ReorderHeader, config_parse_tristate, 0, MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode) -IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags) +IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags) Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local) Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote) Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos) diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 2b01d4190f9..0d0671d37bc 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -91,7 +91,7 @@ typedef struct NetDev { char *description; char *ifname; struct ether_addr *mac; - size_t mtu; + uint32_t mtu; int ifindex; LIST_HEAD(netdev_join_callback, callbacks); diff --git a/src/network/netdev/tuntap.c b/src/network/netdev/tuntap.c index 1d037f2985f..3dd962440db 100644 --- a/src/network/netdev/tuntap.c +++ b/src/network/netdev/tuntap.c @@ -144,7 +144,7 @@ static void tuntap_done(NetDev *netdev) { static int tuntap_verify(NetDev *netdev, const char *filename) { assert(netdev); - if (netdev->mtu) + if (netdev->mtu != 0) log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind)); if (netdev->mac) diff --git a/src/network/networkctl.c b/src/network/networkctl.c index b666913e623..29899a9ba74 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -821,7 +821,7 @@ static int link_status_one( } if (info->has_mtu) - printf(" MTU: %u\n", info->mtu); + printf(" MTU: %" PRIu32 "\n", info->mtu); (void) dump_addresses(rtnl, " Address: ", info->ifindex); (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 6f5dcb843a3..fae750be203 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1757,7 +1757,7 @@ int link_up(Link *link) { for this interface, or if it is a bridge slave, then disable IPv6 else enable it. */ (void) link_enable_ipv6(link); - if (link->network->mtu) { + if (link->network->mtu != 0) { /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */ if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) { @@ -2486,7 +2486,7 @@ static int link_set_ipv6_mtu(Link *link) { p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/mtu"); - xsprintf(buf, "%u", link->network->ipv6_mtu); + xsprintf(buf, "%" PRIu32, link->network->ipv6_mtu); r = write_string_file(p, buf, 0); if (r < 0) @@ -3229,7 +3229,7 @@ int link_update(Link *link, sd_netlink_message *m) { r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu); if (r >= 0 && mtu > 0) { link->mtu = mtu; - if (!link->original_mtu) { + if (link->original_mtu == 0) { link->original_mtu = mtu; log_link_debug(link, "Saved original MTU: %" PRIu32, link->original_mtu); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index c17ac3f3ce7..a3ea1f8bf82 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -88,7 +88,7 @@ typedef struct Link { sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; char *lease_file; - uint16_t original_mtu; + uint32_t original_mtu; unsigned dhcp4_messages; bool dhcp4_configured; bool dhcp6_configured; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index ba5c5db70d1..e828fe8c6c3 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -31,7 +31,7 @@ Match.KernelCommandLine, config_parse_net_condition, Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(Network, match_kernel_version) Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, match_arch) Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac) -Link.MTUBytes, config_parse_iec_size, 0, offsetof(Network, mtu) +Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(Network, mtu) Link.ARP, config_parse_tristate, 0, offsetof(Network, arp) Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged) Link.RequiredForOnline, config_parse_bool, 0, offsetof(Network, required_for_online) @@ -69,7 +69,7 @@ Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp) -Network.IPv6MTUBytes, config_parse_ipv6_mtu, 0, 0 +Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, 0 Network.ActiveSlave, config_parse_bool, 0, offsetof(Network, active_slave) Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave) Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 03dfd4e510b..e25909374f8 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -1417,42 +1417,6 @@ int config_parse_dhcp_route_table(const char *unit, return 0; } -int config_parse_ipv6_mtu( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - Network *network = data; - uint32_t mtu; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - - r = safe_atou32(rvalue, &mtu); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 MTU, ignoring assignment: %s", rvalue); - return 0; - } - - if (mtu < IPV6_MIN_MTU) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 MTU for interface. Allowed minimum MTU is 1280 bytes, ignoring: %s", rvalue); - return 0; - } - - network->ipv6_mtu = mtu; - - return 0; -} - DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting"); static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index f58c2d32d36..fc3dd65a4a3 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -33,8 +33,6 @@ #define BRIDGE_VLAN_BITMAP_MAX 4096 #define BRIDGE_VLAN_BITMAP_LEN (BRIDGE_VLAN_BITMAP_MAX / 32) -#define IPV6_MIN_MTU 1280 - typedef enum DHCPClientIdentifier { DHCP_CLIENT_ID_MAC, DHCP_CLIENT_ID_DUID, @@ -200,7 +198,7 @@ struct Network { int ipv6_hop_limit; int ipv6_proxy_ndp; int proxy_arp; - unsigned ipv6_mtu; + uint32_t ipv6_mtu; bool ipv6_accept_ra_use_dns; bool active_slave; @@ -212,7 +210,7 @@ struct Network { IPv6PrivacyExtensions ipv6_privacy_extensions; struct ether_addr *mac; - size_t mtu; + uint32_t mtu; int arp; bool unmanaged; bool configure_without_carrier; @@ -292,7 +290,6 @@ int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsign int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dhcp_route_table(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_ipv6_mtu(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Legacy IPv4LL support */ int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index a5b38604cae..45885618901 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -1158,3 +1158,38 @@ int config_parse_join_controllers( return 0; } + +int config_parse_mtu( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + uint32_t *mtu = data; + int r; + + assert(rvalue); + assert(mtu); + + r = parse_mtu(ltype, rvalue, mtu); + if (r == -ERANGE) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Maximum transfer unit (MTU) value out of range. Permitted range is %" PRIu32 "…%" PRIu32 ", ignoring: %s", + (uint32_t) (ltype == AF_INET6 ? IPV6_MIN_MTU : IPV4_MIN_MTU), (uint32_t) UINT32_MAX, + rvalue); + return 0; + } + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse MTU value '%s', ignoring: %m", rvalue); + return 0; + } + + return 0; +} diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 150fa07e7eb..094b9cbc447 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -146,6 +146,7 @@ int config_parse_personality(GENERIC_PARSER_ARGS); int config_parse_ifname(GENERIC_PARSER_ARGS); int config_parse_ip_port(GENERIC_PARSER_ARGS); int config_parse_join_controllers(GENERIC_PARSER_ARGS); +int config_parse_mtu(GENERIC_PARSER_ARGS); typedef enum Disabled { DISABLED_CONFIGURATION, diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 37dbb0ce7a9..a04ab9c9aa4 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "alloc-util.h" #include "errno-list.h" @@ -757,6 +758,27 @@ static void test_parse_syscall_and_errno(void) { assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL); } +static void test_parse_mtu(void) { + uint32_t mtu = 0; + + assert_se(parse_mtu(AF_UNSPEC, "1500", &mtu) >= 0 && mtu == 1500); + assert_se(parse_mtu(AF_UNSPEC, "1400", &mtu) >= 0 && mtu == 1400); + assert_se(parse_mtu(AF_UNSPEC, "65535", &mtu) >= 0 && mtu == 65535); + assert_se(parse_mtu(AF_UNSPEC, "65536", &mtu) >= 0 && mtu == 65536); + assert_se(parse_mtu(AF_UNSPEC, "4294967295", &mtu) >= 0 && mtu == 4294967295); + assert_se(parse_mtu(AF_UNSPEC, "500", &mtu) >= 0 && mtu == 500); + assert_se(parse_mtu(AF_UNSPEC, "1280", &mtu) >= 0 && mtu == 1280); + assert_se(parse_mtu(AF_INET6, "1280", &mtu) >= 0 && mtu == 1280); + assert_se(parse_mtu(AF_INET6, "1279", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_UNSPEC, "4294967296", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_INET6, "4294967296", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_INET6, "68", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_UNSPEC, "68", &mtu) >= 0 && mtu == 68); + assert_se(parse_mtu(AF_UNSPEC, "67", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_UNSPEC, "0", &mtu) == -ERANGE); + assert_se(parse_mtu(AF_UNSPEC, "", &mtu) == -EINVAL); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -779,6 +801,7 @@ int main(int argc, char *argv[]) { test_parse_dev(); test_parse_errno(); test_parse_syscall_and_errno(); + test_parse_mtu(); return 0; } diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index b4c3a45cf30..8bfa998dacf 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -35,7 +35,7 @@ Link.MACAddress, config_parse_hwaddr, 0, Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy) Link.Name, config_parse_ifname, 0, offsetof(link_config, name) Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias) -Link.MTUBytes, config_parse_iec_size, 0, offsetof(link_config, mtu) +Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu) Link.BitsPerSecond, config_parse_si_size, 0, offsetof(link_config, speed) Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex) Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 48f6c577586..c4fab4e63b1 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -169,7 +169,7 @@ static int load_link(link_config_ctx *ctx, const char *filename) { else log_debug("Parsed configuration file %s", filename); - if (link->mtu > UINT_MAX || link->speed > UINT_MAX) + if (link->speed > UINT_MAX) return -ERANGE; link->filename = strdup(filename); @@ -466,7 +466,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu); if (r < 0) - return log_warning_errno(r, "Could not set Alias, MACAddress or MTU on %s: %m", old_name); + return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name); *name = new_name; diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 699e54c8373..9f411328105 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -55,7 +55,7 @@ struct link_config { NamePolicy *name_policy; char *name; char *alias; - size_t mtu; + uint32_t mtu; size_t speed; Duplex duplex; int autonegotiation;