linux-cp: Fix looping netlink messages 22/39622/9
authorPim van Pelt <pim@ipng.nl>
Fri, 6 Oct 2023 09:26:33 +0000 (11:26 +0200)
committerMatthew Smith <mgsmith@netgate.com>
Wed, 10 Jan 2024 14:49:25 +0000 (14:49 +0000)
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 <pim@ipng.nl>
src/plugins/linux-cp/lcp.c
src/plugins/linux-cp/lcp.h
src/plugins/linux-cp/lcp_interface_sync.c
src/plugins/linux-cp/lcp_mpls_sync.c
src/plugins/linux-cp/lcp_nl.c

index 33c71e4..561ebb1 100644 (file)
@@ -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
  *
index 4ddaa38..3b6b4ec 100644 (file)
@@ -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
 
 /*
index bd26ebb..ca7638e 100644 (file)
@@ -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",
index d4b0d13..c08fcb4 100644 (file)
@@ -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;
 
index b548d7a..85b6447 100644 (file)
@@ -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);