merge: branch 'bg/route-dump'

platform: dump only selected route protocols

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1978
This commit is contained in:
Íñigo Huguet 2024-08-06 10:16:13 +00:00
commit 63f2401ebe

View file

@ -3908,10 +3908,16 @@ _new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only)
return g_steal_pointer(&obj);
}
#define IP_ROUTE_TRACKED_PROTOCOLS \
RTPROT_UNSPEC, RTPROT_REDIRECT, RTPROT_KERNEL, RTPROT_BOOT, RTPROT_STATIC, RTPROT_RA, \
RTPROT_DHCP
static const guint8 ip_route_tracked_protocols[] = {IP_ROUTE_TRACKED_PROTOCOLS};
static gboolean
ip_route_is_tracked(guint8 proto, guint8 type)
{
if (proto > RTPROT_STATIC && !NM_IN_SET(proto, RTPROT_DHCP, RTPROT_RA)) {
if (!NM_IN_SET(proto, IP_ROUTE_TRACKED_PROTOCOLS)) {
/* We ignore certain rtm_protocol, because NetworkManager would only ever
* configure certain protocols. Other routes are not configured by NetworkManager
* and we don't track them in the platform cache.
@ -5604,6 +5610,7 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob
nm_assert(
NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
nm_assert(NM_IN_SET(nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
nm_assert(NM_IN_SET(rtmsg.rtm_protocol, IP_ROUTE_TRACKED_PROTOCOLS));
if (NM_FLAGS_HAS(obj->ip_route.r_rtm_flags, ((unsigned) (RTNH_F_ONLINK)))) {
if (IS_IPv4 && obj->ip4_route.gateway == 0) {
@ -7899,13 +7906,11 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags);
const RefreshAllInfo *refresh_all_info = refresh_all_type_get_info(refresh_all_type);
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
int *out_refresh_all_in_progress;
int *out_refresh_all_in_progress;
out_refresh_all_in_progress =
&priv->delayed_action.refresh_all_in_progress[refresh_all_type];
nm_assert(*out_refresh_all_in_progress >= 0);
*out_refresh_all_in_progress += 1;
/* clear any delayed action that request a refresh of this object type. */
priv->delayed_action.flags &= ~iflags;
@ -7924,29 +7929,94 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action
}
}
event_handler_read_netlink(platform, refresh_all_info->protocol, FALSE);
/* Routes are handled specially because we want to request only routes
* for protocols we track. The reason is that there might be millions of
* BGP routes we don't track and it would be very inefficient to dump them
* all. Therefore, perform separate dumps, each for a specific protocol we
* track. */
if (NM_IN_SET(refresh_all_type,
REFRESH_ALL_TYPE_RTNL_IP4_ROUTES,
REFRESH_ALL_TYPE_RTNL_IP6_ROUTES)) {
struct rtmsg rtm = {
.rtm_family = refresh_all_info->addr_family_for_dump,
};
guint retry_count = 0;
guint i;
if (refresh_all_info->protocol == NMP_NETLINK_ROUTE) {
nlmsg = _nl_msg_new_dump_rtnl(refresh_all_info->obj_type,
refresh_all_info->addr_family_for_dump);
for (i = 0; i < G_N_ELEMENTS(ip_route_tracked_protocols); i++) {
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
if (retry_count > 0) {
/* Try again previous protocol */
i--;
}
/* If we try to request a new dump while the previous is still
* in progress, kernel returns -EBUSY. Complete the previous
* dump by reading from the socket. */
event_handler_read_netlink(platform, refresh_all_info->protocol, FALSE);
nlmsg = nlmsg_alloc_new(0, RTM_GETROUTE, NLM_F_DUMP);
if (!nlmsg)
goto next_after_fail;
rtm.rtm_protocol = ip_route_tracked_protocols[i];
if (nlmsg_append_struct(nlmsg, &rtm) < 0)
g_return_if_fail(FALSE);
*out_refresh_all_in_progress += 1;
if (_netlink_send_nlmsg(platform,
refresh_all_info->protocol,
nlmsg,
NULL,
NULL,
DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS,
out_refresh_all_in_progress)
< 0) {
*out_refresh_all_in_progress -= 1;
retry_count++;
if (retry_count > 4) {
_LOGE("failed dumping IPv%c routes with protocol %u, cache might be "
"inconsistent",
nm_utils_addr_family_to_char(rtm.rtm_family),
rtm.rtm_protocol);
retry_count = 0;
/* Give up and try the next protocol */
}
} else {
retry_count = 0;
}
}
} else {
nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES);
nlmsg = _nl_msg_new_dump_genl_families();
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
*out_refresh_all_in_progress += 1;
event_handler_read_netlink(platform, refresh_all_info->protocol, FALSE);
if (refresh_all_info->protocol == NMP_NETLINK_ROUTE) {
nlmsg = _nl_msg_new_dump_rtnl(refresh_all_info->obj_type,
refresh_all_info->addr_family_for_dump);
} else {
nm_assert(refresh_all_type == REFRESH_ALL_TYPE_GENL_FAMILIES);
nlmsg = _nl_msg_new_dump_genl_families();
}
if (!nlmsg)
goto next_after_fail;
if (_netlink_send_nlmsg(platform,
refresh_all_info->protocol,
nlmsg,
NULL,
NULL,
DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS,
out_refresh_all_in_progress)
< 0)
goto next_after_fail;
}
if (!nlmsg)
goto next_after_fail;
if (_netlink_send_nlmsg(platform,
refresh_all_info->protocol,
nlmsg,
NULL,
NULL,
DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS,
out_refresh_all_in_progress)
< 0)
goto next_after_fail;
continue;
next_after_fail:
nm_assert(*out_refresh_all_in_progress > 0);