summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-01-24 18:46:14 +0100
committerThomas Haller <thaller@redhat.com>2016-01-25 13:33:10 +0100
commit809c547b6c8522570add25581b41b3514a5c5dfb (patch)
tree1970a1d2de53878c25c183262df2cd72c239f2fa
parenta47b2abeb173bf2459c1a96a40d3e2fc126cd62f (diff)
downloadNetworkManager-809c547b6c8522570add25581b41b3514a5c5dfb.tar.gz
platform: handle netlink ACKs in event_handler_recvmsgs() during cache-resync
When reading from netlink-socket fails with NLE_NOMEM, messages were lost. In this case the cache must be resynced and all pending messages from the socket are rejected via "event_handler_recvmsgs (platform, FALSE)". In this case, we don't want to handle the received messages as the cache anyway needs to resync. However, we are still interested in all queued ACKs that are there. We are also interested in RTM_NEWADDR messages which we use to detect kernel support via _support_kernel_extended_ifa_flags_detect().
-rw-r--r--src/platform/nm-linux-platform.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index b9cc7abc52..153ac68642 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -2804,13 +2804,23 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
static void
delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform,
- WaitForNlResponseResult result)
+ WaitForNlResponseResult fallback_result)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
- while (priv->delayed_action.list_wait_for_nl_response->len > 0)
- delayed_action_wait_for_nl_response_complete (platform, priv->delayed_action.list_wait_for_nl_response->len - 1, result);
+ while (priv->delayed_action.list_wait_for_nl_response->len > 0) {
+ const DelayedActionWaitForNlResponseData *data;
+ guint idx = priv->delayed_action.list_wait_for_nl_response->len - 1;
+ WaitForNlResponseResult r;
+
+ data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx);
+
+ /* prefer the result that we already have. */
+ r = data->seq_result ? : fallback_result;
+
+ delayed_action_wait_for_nl_response_complete (platform, idx, r);
+ }
}
nm_assert (!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);
@@ -3461,7 +3471,7 @@ event_seq_check (NMPlatform *platform, struct nl_msg *msg, WaitForNlResponseResu
}
static void
-event_valid_msg (NMPlatform *platform, struct nl_msg *msg)
+event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
nm_auto_nmpobj NMPObject *obj = NULL;
@@ -3477,6 +3487,9 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg)
if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
_support_kernel_extended_ifa_flags_detect (msg);
+ if (!handle_events)
+ return;
+
if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) {
/* The event notifies about a deleted object. We don't need to initialize all
* fields of the object. */
@@ -5528,13 +5541,6 @@ continue_reading:
if (n <= 0)
return n;
- if (!handle_events) {
- /* we read until failure or there is nothing to read (EAGAIN). */
- g_clear_pointer (&buf, free);
- g_clear_pointer (&creds, free);
- goto continue_reading;
- }
-
hdr = (struct nlmsghdr *) buf;
while (nlmsg_ok (hdr, n)) {
gboolean abort_parsing = FALSE;
@@ -5627,7 +5633,9 @@ continue_reading:
/* Valid message (not checking for MULTIPART bit to
* get along with broken kernels. NL_SKIP has no
* effect on this. */
- event_valid_msg (platform, msg);
+
+ event_valid_msg (platform, msg, handle_events);
+
seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
}
@@ -5698,10 +5706,8 @@ event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks)
break;
case -NLE_NOMEM:
_LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache");
- /* Drain the event queue, we've lost events and are out of sync anyway and we'd
- * like to free up some space. We'll read in the status synchronously. */
- delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
event_handler_recvmsgs (platform, FALSE);
+ delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC);
delayed_action_schedule (platform,
DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS |
DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES |