diff options
author | Thomas Haller <thaller@redhat.com> | 2016-01-24 18:46:14 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2016-01-25 13:33:10 +0100 |
commit | 809c547b6c8522570add25581b41b3514a5c5dfb (patch) | |
tree | 1970a1d2de53878c25c183262df2cd72c239f2fa | |
parent | a47b2abeb173bf2459c1a96a40d3e2fc126cd62f (diff) | |
download | NetworkManager-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.c | 36 |
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 | |