diff options
Diffstat (limited to 'src/network/networkd-setlink.c')
-rw-r--r-- | src/network/networkd-setlink.c | 171 |
1 files changed, 93 insertions, 78 deletions
diff --git a/src/network/networkd-setlink.c b/src/network/networkd-setlink.c index 011ea1f..058bc00 100644 --- a/src/network/networkd-setlink.c +++ b/src/network/networkd-setlink.c @@ -103,6 +103,19 @@ static int link_set_bridge_handler(sd_netlink *rtnl, sd_netlink_message *m, Requ } static int link_set_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { + int r; + + assert(link); + + r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); + if (r <= 0) + return r; + + link->bridge_vlan_set = true; + return 0; +} + +static int link_del_bridge_vlan_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ false, NULL); } @@ -160,19 +173,7 @@ static int link_unset_master_handler(sd_netlink *rtnl, sd_netlink_message *m, Re } static int link_set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, void *userdata) { - int r; - - r = set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler); - if (r <= 0) - return r; - - /* The kernel resets ipv6 mtu after changing device mtu; - * we must set this here, after we've set device mtu */ - r = link_set_ipv6_mtu(link); - if (r < 0) - log_link_warning_errno(link, r, "Failed to set IPv6 MTU, ignoring: %m"); - - return 0; + return set_link_handler_internal(rtnl, m, req, link, /* ignore = */ true, get_link_default_handler); } static int link_configure_fill_message( @@ -326,29 +327,14 @@ static int link_configure_fill_message( return r; break; case REQUEST_TYPE_SET_LINK_BRIDGE_VLAN: - r = sd_rtnl_message_link_set_family(req, AF_BRIDGE); - if (r < 0) - return r; - - r = sd_netlink_message_open_container(req, IFLA_AF_SPEC); + r = bridge_vlan_set_message(link, req, /* is_set = */ true); if (r < 0) return r; - - if (link->master_ifindex <= 0) { - /* master needs BRIDGE_FLAGS_SELF flag */ - r = sd_netlink_message_append_u16(req, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF); - if (r < 0) - return r; - } - - r = bridge_vlan_append_info(link, req, link->network->pvid, link->network->br_vid_bitmap, link->network->br_untagged_bitmap); - if (r < 0) - return r; - - r = sd_netlink_message_close_container(req); + break; + case REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN: + r = bridge_vlan_set_message(link, req, /* is_set = */ false); if (r < 0) return r; - break; case REQUEST_TYPE_SET_LINK_CAN: r = can_set_netlink_message(link, req); @@ -430,6 +416,8 @@ static int link_configure(Link *link, Request *req) { r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->master_ifindex); else if (IN_SET(req->type, REQUEST_TYPE_SET_LINK_CAN, REQUEST_TYPE_SET_LINK_IPOIB)) r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_NEWLINK, link->ifindex); + else if (req->type == REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN) + r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_DELLINK, link->ifindex); else r = sd_rtnl_message_new_link(link->manager->rtnl, &m, RTM_SETLINK, link->ifindex); if (r < 0) @@ -453,6 +441,43 @@ static bool netdev_is_ready(NetDev *netdev) { return true; } +static uint32_t link_adjust_mtu(Link *link, uint32_t mtu) { + const char *origin; + uint32_t min_mtu; + + assert(link); + assert(link->network); + + 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; + } + + return mtu; +} + static int link_is_ready_to_set_link(Link *link, Request *req) { int r; @@ -480,9 +505,11 @@ static int link_is_ready_to_set_link(Link *link, Request *req) { if (link->network->keep_master && link->master_ifindex <= 0 && !streq_ptr(link->kind, "bridge")) return false; - break; + case REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN: + return link->bridge_vlan_set; + case REQUEST_TYPE_SET_LINK_CAN: /* Do not check link->set_flags_messages here, as it is ok even if link->flags * is outdated, and checking the counter causes a deadlock. */ @@ -568,13 +595,24 @@ static int link_is_ready_to_set_link(Link *link, Request *req) { })) return false; - /* Changing FD mode may affect MTU. */ + /* Changing FD mode may affect MTU. + * See https://docs.kernel.org/networking/can.html#can-fd-flexible-data-rate-driver-support + * MTU = 16 (CAN_MTU) => Classical CAN device + * MTU = 72 (CANFD_MTU) => CAN FD capable device */ if (ordered_set_contains(link->manager->request_queue, &(const Request) { .link = link, .type = REQUEST_TYPE_SET_LINK_CAN, })) return false; + + /* Now, it is ready to set MTU, but before setting, adjust requested MTU. */ + uint32_t mtu = link_adjust_mtu(link, PTR_TO_UINT32(req->userdata)); + if (mtu == link->mtu) + return -EALREADY; /* Not necessary to set the same value. */ + + req->userdata = UINT32_TO_PTR(mtu); + return true; } default: break; @@ -712,10 +750,14 @@ int link_request_to_set_bridge(Link *link) { } int link_request_to_set_bridge_vlan(Link *link) { + int r; + assert(link); assert(link->network); - if (!link->network->use_br_vlan) + /* If nothing configured, use the default vlan ID. */ + if (memeqzero(link->network->bridge_vlan_bitmap, BRIDGE_VLAN_BITMAP_LEN * sizeof(uint32_t)) && + link->network->bridge_vlan_pvid == BRIDGE_VLAN_KEEP_PVID) return 0; if (!link->network->bridge && !streq_ptr(link->kind, "bridge")) { @@ -731,9 +773,21 @@ int link_request_to_set_bridge_vlan(Link *link) { return 0; } - return link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, - link_set_bridge_vlan_handler, - NULL); + link->bridge_vlan_set = false; + + r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_BRIDGE_VLAN, + link_set_bridge_vlan_handler, + NULL); + if (r < 0) + return r; + + r = link_request_set_link(link, REQUEST_TYPE_DEL_LINK_BRIDGE_VLAN, + link_del_bridge_vlan_handler, + NULL); + if (r < 0) + return r; + + return 0; } int link_request_to_set_can(Link *link) { @@ -847,51 +901,12 @@ int link_request_to_set_master(Link *link) { } int link_request_to_set_mtu(Link *link, uint32_t mtu) { - const char *origin; - uint32_t min_mtu, max_mtu; Request *req; int r; assert(link); - assert(link->network); - - 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; - } - - max_mtu = link->max_mtu; - if (link->iftype == ARPHRD_CAN) - /* The maximum MTU may be changed when FD mode is changed. - * See https://docs.kernel.org/networking/can.html#can-fd-flexible-data-rate-driver-support - * MTU = 16 (CAN_MTU) => Classical CAN device - * MTU = 72 (CANFD_MTU) => CAN FD capable device - * So, even if the current maximum is 16, we should not reduce the requested value now. */ - max_mtu = MAX(max_mtu, 72u); - - if (mtu > max_mtu) { - log_link_warning(link, "Reducing the requested MTU %"PRIu32" to the interface's maximum MTU %"PRIu32".", - mtu, max_mtu); - mtu = max_mtu; - } - if (link->mtu == mtu) + if (mtu == 0) return 0; r = link_request_set_link(link, REQUEST_TYPE_SET_LINK_MTU, |