From 2c9b128e1b3732f9dd62699922480f9206a02b2d Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Fri, 6 Oct 2023 11:26:33 +0200 Subject: linux-cp: Fix looping netlink messages Signal when consuming a batch of netlink messages, in order to inhibit lcp_sync from generating new netlink messages. This avoids link up/down state changess from triggering an infinite loop. Do this in the regular case of nl_route_process_msgs() and in the special case of re-synchronizing in lcp_nl_recv_dump_replies(). Type: fix Change-Id: I419d3f9aa350c119b3778b644c65165cb4cc1bef Signed-off-by: Pim van Pelt --- src/plugins/linux-cp/lcp.c | 16 ++++++++++++++++ src/plugins/linux-cp/lcp.h | 9 +++++++++ src/plugins/linux-cp/lcp_interface_sync.c | 11 ++++++----- src/plugins/linux-cp/lcp_mpls_sync.c | 2 ++ src/plugins/linux-cp/lcp_nl.c | 13 ++++++++++++- 5 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/plugins/linux-cp/lcp.c b/src/plugins/linux-cp/lcp.c index 33c71e44143..561ebb152ae 100644 --- a/src/plugins/linux-cp/lcp.c +++ b/src/plugins/linux-cp/lcp.c @@ -145,6 +145,22 @@ lcp_get_del_dynamic_on_link_down (void) return lcpm->del_dynamic_on_link_down; } +void +lcp_set_netlink_processing_active (u8 is_processing) +{ + lcp_main_t *lcpm = &lcp_main; + + lcpm->netlink_processing_active = (is_processing != 0); +} + +u8 +lcp_get_netlink_processing_active (void) +{ + lcp_main_t *lcpm = &lcp_main; + + return lcpm->netlink_processing_active; +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/linux-cp/lcp.h b/src/plugins/linux-cp/lcp.h index 4ddaa3898d6..3b6b4ec00d4 100644 --- a/src/plugins/linux-cp/lcp.h +++ b/src/plugins/linux-cp/lcp.h @@ -29,6 +29,8 @@ typedef struct lcp_main_s u8 del_static_on_link_down; /* Delete static routes when link goes down */ u8 del_dynamic_on_link_down; /* Delete dynamic routes when link goes down */ u8 test_mode; /* Set when Unit testing */ + u8 netlink_processing_active; /* Set while a batch of Netlink messages are + being processed */ } lcp_main_t; extern lcp_main_t lcp_main; @@ -52,6 +54,13 @@ u8 lcp_get_del_static_on_link_down (void); void lcp_set_del_dynamic_on_link_down (u8 is_del); u8 lcp_get_del_dynamic_on_link_down (void); +/** + * Get/Set when we're processing a batch of netlink messages. + * This is used to avoid looping messages between lcp-sync and netlink. + */ +void lcp_set_netlink_processing_active (u8 is_processing); +u8 lcp_get_netlink_processing_active (void); + #endif /* diff --git a/src/plugins/linux-cp/lcp_interface_sync.c b/src/plugins/linux-cp/lcp_interface_sync.c index bd26ebbc354..ca7638e1799 100644 --- a/src/plugins/linux-cp/lcp_interface_sync.c +++ b/src/plugins/linux-cp/lcp_interface_sync.c @@ -37,7 +37,7 @@ lcp_itf_pair_sync_state (lcp_itf_pair_t *lip) u32 mtu; u32 netlink_mtu; - if (!lcp_sync ()) + if (!lcp_sync () || lcp_get_netlink_processing_active ()) return; sw = @@ -176,7 +176,7 @@ lcp_itf_admin_state_change (vnet_main_t *vnm, u32 sw_if_index, u32 flags) vnet_hw_interface_t *hi; vnet_sw_interface_t *si; - if (!lcp_sync ()) + if (!lcp_sync () || lcp_get_netlink_processing_active ()) return 0; LCP_ITF_PAIR_DBG ("admin_state_change: sw %U %u", @@ -223,7 +223,8 @@ lcp_itf_mtu_change (vnet_main_t *vnm, u32 sw_if_index, u32 flags) { vnet_sw_interface_t *si; vnet_hw_interface_t *hi; - if (!lcp_sync ()) + + if (!lcp_sync () || lcp_get_netlink_processing_active ()) return NULL; LCP_ITF_PAIR_DBG ("mtu_change: sw %U %u", format_vnet_sw_if_index_name, vnm, @@ -271,7 +272,7 @@ lcp_itf_ip4_add_del_interface_addr (ip4_main_t *im, uword opaque, int curr_ns_fd = -1; int vif_ns_fd = -1; - if (!lcp_sync ()) + if (!lcp_sync () || lcp_get_netlink_processing_active ()) return; LCP_ITF_PAIR_DBG ("ip4_addr_%s: si:%U %U/%u", is_del ? "del" : "add", @@ -320,7 +321,7 @@ lcp_itf_ip6_add_del_interface_addr (ip6_main_t *im, uword opaque, int curr_ns_fd = -1; int vif_ns_fd = -1; - if (!lcp_sync ()) + if (!lcp_sync () || lcp_get_netlink_processing_active ()) return; LCP_ITF_PAIR_DBG ("ip6_addr_%s: si:%U %U/%u", is_del ? "del" : "add", diff --git a/src/plugins/linux-cp/lcp_mpls_sync.c b/src/plugins/linux-cp/lcp_mpls_sync.c index d4b0d13b907..c08fcb4d1d9 100644 --- a/src/plugins/linux-cp/lcp_mpls_sync.c +++ b/src/plugins/linux-cp/lcp_mpls_sync.c @@ -77,6 +77,8 @@ lcp_mpls_sync_state_cb (struct mpls_main_t *mm, uword opaque, u32 sw_if_index, format_lcp_itf_pair, lip); // If syncing is enabled, sync Linux state as well. + // This can happen regardless of lcp_get_netlink_processing_active(), + // provided it does not generate Netlink messages. if (!lcp_sync ()) return; diff --git a/src/plugins/linux-cp/lcp_nl.c b/src/plugins/linux-cp/lcp_nl.c index b548d7afa39..85b6447007a 100644 --- a/src/plugins/linux-cp/lcp_nl.c +++ b/src/plugins/linux-cp/lcp_nl.c @@ -348,6 +348,8 @@ nl_route_process_msgs (void) nl_msg_info_t *msg_info; int err, n_msgs = 0; + lcp_set_netlink_processing_active (1); + /* process a batch of messages. break if we hit our limit */ vec_foreach (msg_info, nm->nl_msg_queue) { @@ -365,6 +367,8 @@ nl_route_process_msgs (void) NL_DBG ("Processed %u messages", n_msgs); + lcp_set_netlink_processing_active (0); + return n_msgs; } @@ -441,10 +445,15 @@ lcp_nl_recv_dump_replies (nl_sock_type_t sock_type, int msg_limit, int done = 0; int n_msgs = 0; + lcp_set_netlink_processing_active (1); + continue_reading: n_bytes = nl_recv (sk_route, &nla, &buf, /* creds */ NULL); if (n_bytes <= 0) - return n_bytes; + { + lcp_set_netlink_processing_active (0); + return n_bytes; + } hdr = (struct nlmsghdr *) buf; while (nlmsg_ok (hdr, n_bytes)) @@ -521,6 +530,8 @@ continue_reading: goto continue_reading; out: + lcp_set_netlink_processing_active (0); + nlmsg_free (msg); free (buf); -- cgit 1.2.3-korg