platform: dump only selected route protocols
When doing a dump of routes, we want to exclude routes having protocols we do not care about. Since the netlink socket has STRICT_CHK enabled, we can request multiple dumps for the protocols we need. While doing 6 dumps is less efficient than doing 1, it normally doesn't matter. However, the new implementation is more efficient when there are e.g. millions of BGP routes that can be excluded from the results.
This commit is contained in:

committed by
Íñigo Huguet

parent
c0ac920f9c
commit
f6411ed941
@@ -3912,7 +3912,7 @@ _new_from_nl_addr(const struct nlmsghdr *nlh, gboolean id_only)
|
||||
RTPROT_UNSPEC, RTPROT_REDIRECT, RTPROT_KERNEL, RTPROT_BOOT, RTPROT_STATIC, RTPROT_RA, \
|
||||
RTPROT_DHCP
|
||||
|
||||
_nm_unused static const guint8 ip_route_tracked_protocols[] = {IP_ROUTE_TRACKED_PROTOCOLS};
|
||||
static const guint8 ip_route_tracked_protocols[] = {IP_ROUTE_TRACKED_PROTOCOLS};
|
||||
|
||||
static gboolean
|
||||
ip_route_is_tracked(guint8 proto, guint8 type)
|
||||
@@ -7905,13 +7905,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;
|
||||
@@ -7930,29 +7928,78 @@ 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 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 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;
|
||||
/* Try to refresh other route protocols ... */
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
|
Reference in New Issue
Block a user