platform: track refresh-all actions that are in progress
We aim to keep the platform cache up-to-date only via the netlink events. However, due to kernel shortcomings we often have to resync by re-requesting the data, which especially for routes and addresses means a full dump (as you cannot request only specific route/address information). Thus it makes sense to avoid expensive dumps whenever we can. We schedule dumps via "delayed-actions" and that is already smart so that muliple schedulings are combined. However, before requesting a new dump, we clear the flag that indicates that a dump is scheduled. Thus, while processing the result of of a dump, we would re-schedule anew which can be necessary in some cases. In certain cases, we don't require a full resync, when we are in the middle of processing a dump, because that one dump will provide us with the full picture. Thus, we can avoid scheduling a new dump if - we already scheduled a delayed action - we are in the middle or processing a dump. This can now be checked via delayed_action_refresh_all_in_progress().
This commit is contained in:
@@ -176,13 +176,22 @@
|
|||||||
* Forward declarations and enums
|
* Forward declarations and enums
|
||||||
******************************************************************/
|
******************************************************************/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DELAYED_ACTION_IDX_REFRESH_ALL_LINKS,
|
||||||
|
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES,
|
||||||
|
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES,
|
||||||
|
DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES,
|
||||||
|
DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES,
|
||||||
|
_DELAYED_ACTION_IDX_REFRESH_ALL_NUM,
|
||||||
|
};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
DELAYED_ACTION_TYPE_NONE = 0,
|
DELAYED_ACTION_TYPE_NONE = 0,
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << 0),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_LINKS),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << 1),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << 2),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << 3),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << 4),
|
DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES = (1LL << DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES),
|
||||||
DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5),
|
DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5),
|
||||||
DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6),
|
DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6),
|
||||||
DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7),
|
DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7),
|
||||||
@@ -2342,6 +2351,7 @@ typedef struct {
|
|||||||
WaitForNlResponseResult seq_result;
|
WaitForNlResponseResult seq_result;
|
||||||
gint64 timeout_abs_ns;
|
gint64 timeout_abs_ns;
|
||||||
WaitForNlResponseResult *out_seq_result;
|
WaitForNlResponseResult *out_seq_result;
|
||||||
|
gint *out_refresh_all_in_progess;
|
||||||
} DelayedActionWaitForNlResponseData;
|
} DelayedActionWaitForNlResponseData;
|
||||||
|
|
||||||
typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
|
typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
|
||||||
@@ -2352,6 +2362,7 @@ struct _NMLinuxPlatformPrivate {
|
|||||||
#ifdef NM_MORE_LOGGING
|
#ifdef NM_MORE_LOGGING
|
||||||
guint32 nlh_seq_last_handled;
|
guint32 nlh_seq_last_handled;
|
||||||
#endif
|
#endif
|
||||||
|
guint32 nlh_seq_last_seen;
|
||||||
NMPCache *cache;
|
NMPCache *cache;
|
||||||
GIOChannel *event_channel;
|
GIOChannel *event_channel;
|
||||||
guint event_id;
|
guint event_id;
|
||||||
@@ -2362,10 +2373,18 @@ struct _NMLinuxPlatformPrivate {
|
|||||||
GUdevClient *udev_client;
|
GUdevClient *udev_client;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
/* which delayed actions are scheduled, as marked in @flags.
|
||||||
|
* Some types have additional arguments in the fields below. */
|
||||||
DelayedActionType flags;
|
DelayedActionType flags;
|
||||||
|
|
||||||
|
/* counter that a refresh all action is in progress, separated
|
||||||
|
* by type. */
|
||||||
|
gint refresh_all_in_progess[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
|
||||||
|
|
||||||
GPtrArray *list_master_connected;
|
GPtrArray *list_master_connected;
|
||||||
GPtrArray *list_refresh_link;
|
GPtrArray *list_refresh_link;
|
||||||
GArray *list_wait_for_nl_response;
|
GArray *list_wait_for_nl_response;
|
||||||
|
|
||||||
gint is_handling;
|
gint is_handling;
|
||||||
} delayed_action;
|
} delayed_action;
|
||||||
|
|
||||||
@@ -2740,6 +2759,16 @@ delayed_action_refresh_to_object_type (DelayedActionType action_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_all_to_idx, DelayedActionType, guint,
|
||||||
|
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (0),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS, DELAYED_ACTION_IDX_REFRESH_ALL_LINKS),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ADDRESSES),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ADDRESSES),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP4_ROUTES),
|
||||||
|
NM_UTILS_LOOKUP_ITEM (DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, DELAYED_ACTION_IDX_REFRESH_ALL_IP6_ROUTES),
|
||||||
|
NM_UTILS_LOOKUP_ITEM_IGNORE_OTHER (),
|
||||||
|
);
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
delayed_action_to_string (DelayedActionType action_type)
|
delayed_action_to_string (DelayedActionType action_type)
|
||||||
{
|
{
|
||||||
@@ -2807,6 +2836,24 @@ delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
delayed_action_refresh_all_in_progress (NMPlatform *platform, DelayedActionType action_type)
|
||||||
|
{
|
||||||
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
|
|
||||||
|
nm_assert (nm_utils_is_power_of_two (action_type));
|
||||||
|
nm_assert (NM_FLAGS_ANY (action_type, DELAYED_ACTION_TYPE_REFRESH_ALL));
|
||||||
|
nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL));
|
||||||
|
|
||||||
|
if (NM_FLAGS_ANY (priv->delayed_action.flags, action_type))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (action_type)] > 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
|
delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
|
||||||
guint idx,
|
guint idx,
|
||||||
@@ -2827,6 +2874,10 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
|
|||||||
priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE;
|
priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE;
|
||||||
if (data->out_seq_result)
|
if (data->out_seq_result)
|
||||||
*data->out_seq_result = seq_result;
|
*data->out_seq_result = seq_result;
|
||||||
|
if (data->out_refresh_all_in_progess) {
|
||||||
|
nm_assert (*data->out_refresh_all_in_progess > 0);
|
||||||
|
*data->out_refresh_all_in_progess -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
|
g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
|
||||||
}
|
}
|
||||||
@@ -3032,12 +3083,14 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp
|
|||||||
static void
|
static void
|
||||||
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
|
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
|
||||||
guint32 seq_number,
|
guint32 seq_number,
|
||||||
WaitForNlResponseResult *out_seq_result)
|
WaitForNlResponseResult *out_seq_result,
|
||||||
|
gint *out_refresh_all_in_progess)
|
||||||
{
|
{
|
||||||
DelayedActionWaitForNlResponseData data = {
|
DelayedActionWaitForNlResponseData data = {
|
||||||
.seq_number = seq_number,
|
.seq_number = seq_number,
|
||||||
.timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)),
|
.timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)),
|
||||||
.out_seq_result = out_seq_result,
|
.out_seq_result = out_seq_result,
|
||||||
|
.out_refresh_all_in_progess = out_refresh_all_in_progess,
|
||||||
};
|
};
|
||||||
|
|
||||||
delayed_action_schedule (platform,
|
delayed_action_schedule (platform,
|
||||||
@@ -3352,7 +3405,8 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
|
|||||||
static int
|
static int
|
||||||
_nl_send_auto_with_seq (NMPlatform *platform,
|
_nl_send_auto_with_seq (NMPlatform *platform,
|
||||||
struct nl_msg *nlmsg,
|
struct nl_msg *nlmsg,
|
||||||
WaitForNlResponseResult *out_seq_result)
|
WaitForNlResponseResult *out_seq_result,
|
||||||
|
gint *out_refresh_all_in_progess)
|
||||||
{
|
{
|
||||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
guint32 seq;
|
guint32 seq;
|
||||||
@@ -3367,7 +3421,7 @@ _nl_send_auto_with_seq (NMPlatform *platform,
|
|||||||
|
|
||||||
if (nle >= 0) {
|
if (nle >= 0) {
|
||||||
nle = 0;
|
nle = 0;
|
||||||
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result);
|
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_refresh_all_in_progess);
|
||||||
} else
|
} else
|
||||||
_LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle);
|
_LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle);
|
||||||
|
|
||||||
@@ -3401,7 +3455,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha
|
|||||||
0,
|
0,
|
||||||
0);
|
0);
|
||||||
if (nlmsg)
|
if (nlmsg)
|
||||||
_nl_send_auto_with_seq (platform, nlmsg, NULL);
|
_nl_send_auto_with_seq (platform, nlmsg, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -3432,6 +3486,11 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
|
|||||||
.rtgen_family = klass->addr_family,
|
.rtgen_family = klass->addr_family,
|
||||||
};
|
};
|
||||||
int nle;
|
int nle;
|
||||||
|
gint *out_refresh_all_in_progess;
|
||||||
|
|
||||||
|
out_refresh_all_in_progess = &priv->delayed_action.refresh_all_in_progess[delayed_action_refresh_all_to_idx (iflags)];
|
||||||
|
nm_assert (*out_refresh_all_in_progess >= 0);
|
||||||
|
*out_refresh_all_in_progess += 1;
|
||||||
|
|
||||||
/* clear any delayed action that request a refresh of this object type. */
|
/* clear any delayed action that request a refresh of this object type. */
|
||||||
priv->delayed_action.flags &= ~iflags;
|
priv->delayed_action.flags &= ~iflags;
|
||||||
@@ -3456,7 +3515,10 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
|
|||||||
if (nle < 0)
|
if (nle < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_nl_send_auto_with_seq (platform, nlmsg, NULL);
|
if (_nl_send_auto_with_seq (platform, nlmsg, NULL, out_refresh_all_in_progess) < 0) {
|
||||||
|
nm_assert (*out_refresh_all_in_progess > 0);
|
||||||
|
*out_refresh_all_in_progess -= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3467,6 +3529,38 @@ do_request_one_type (NMPlatform *platform, NMPObjectType obj_type)
|
|||||||
delayed_action_handle_all (platform, FALSE);
|
delayed_action_handle_all (platform, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number)
|
||||||
|
{
|
||||||
|
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||||
|
DelayedActionWaitForNlResponseData *data;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
(void) delayed_action_refresh_all_in_progress;
|
||||||
|
|
||||||
|
if (NM_IN_SET (seq_number, 0, priv->nlh_seq_last_seen))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
|
||||||
|
nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
|
||||||
|
|
||||||
|
for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) {
|
||||||
|
data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
|
||||||
|
|
||||||
|
if (data->seq_number == priv->nlh_seq_last_seen) {
|
||||||
|
if (data->out_refresh_all_in_progess) {
|
||||||
|
nm_assert (*data->out_refresh_all_in_progess > 0);
|
||||||
|
*data->out_refresh_all_in_progess -= 1;
|
||||||
|
data->out_refresh_all_in_progess = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->nlh_seq_last_seen = seq_number;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result)
|
event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResult seq_result)
|
||||||
{
|
{
|
||||||
@@ -3698,7 +3792,7 @@ do_add_link_with_lookup (NMPlatform *platform,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
|
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
_LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)",
|
_LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)",
|
||||||
name,
|
name,
|
||||||
@@ -3749,7 +3843,7 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
|
|||||||
|
|
||||||
event_handler_read_netlink (platform, FALSE);
|
event_handler_read_netlink (platform, FALSE);
|
||||||
|
|
||||||
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
|
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
_LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
|
_LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
|
||||||
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
|
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
|
||||||
@@ -3802,7 +3896,7 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
|
|||||||
|
|
||||||
event_handler_read_netlink (platform, FALSE);
|
event_handler_read_netlink (platform, FALSE);
|
||||||
|
|
||||||
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
|
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
_LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
|
_LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
|
||||||
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
|
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
|
||||||
@@ -3863,7 +3957,7 @@ do_change_link (NMPlatform *platform,
|
|||||||
return NM_PLATFORM_ERROR_UNSPECIFIED;
|
return NM_PLATFORM_ERROR_UNSPECIFIED;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result);
|
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
|
||||||
if (nle < 0) {
|
if (nle < 0) {
|
||||||
_LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
|
_LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
|
||||||
ifindex,
|
ifindex,
|
||||||
@@ -5743,6 +5837,15 @@ continue_reading:
|
|||||||
|
|
||||||
seq_number = nlmsg_hdr (msg)->nlmsg_seq;
|
seq_number = nlmsg_hdr (msg)->nlmsg_seq;
|
||||||
|
|
||||||
|
/* check whether the seq number is different from before, and
|
||||||
|
* whether the previous number (@nlh_seq_last_seen) is a pending
|
||||||
|
* refresh-all request. In that case, the pending request is thereby
|
||||||
|
* completed.
|
||||||
|
*
|
||||||
|
* We must do that before processing the message with event_valid_msg(),
|
||||||
|
* because we must track the completion of the pending request before that. */
|
||||||
|
event_seq_check_refresh_all (platform, seq_number);
|
||||||
|
|
||||||
if (process_valid_msg) {
|
if (process_valid_msg) {
|
||||||
/* Valid message (not checking for MULTIPART bit to
|
/* Valid message (not checking for MULTIPART bit to
|
||||||
* get along with broken kernels. NL_SKIP has no
|
* get along with broken kernels. NL_SKIP has no
|
||||||
|
Reference in New Issue
Block a user