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>
return lcpm->del_dynamic_on_link_down;
}
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
*
/*
* fd.io coding-style-patch-verification: ON
*
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 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;
} lcp_main_t;
extern lcp_main_t lcp_main;
void lcp_set_del_dynamic_on_link_down (u8 is_del);
u8 lcp_get_del_dynamic_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);
+
u32 mtu;
u32 netlink_mtu;
u32 mtu;
u32 netlink_mtu;
+ if (!lcp_sync () || lcp_get_netlink_processing_active ())
vnet_hw_interface_t *hi;
vnet_sw_interface_t *si;
vnet_hw_interface_t *hi;
vnet_sw_interface_t *si;
+ if (!lcp_sync () || lcp_get_netlink_processing_active ())
return 0;
LCP_ITF_PAIR_DBG ("admin_state_change: sw %U %u",
return 0;
LCP_ITF_PAIR_DBG ("admin_state_change: sw %U %u",
{
vnet_sw_interface_t *si;
vnet_hw_interface_t *hi;
{
vnet_sw_interface_t *si;
vnet_hw_interface_t *hi;
+
+ 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,
return NULL;
LCP_ITF_PAIR_DBG ("mtu_change: sw %U %u", format_vnet_sw_if_index_name, vnm,
int curr_ns_fd = -1;
int vif_ns_fd = -1;
int curr_ns_fd = -1;
int vif_ns_fd = -1;
+ if (!lcp_sync () || lcp_get_netlink_processing_active ())
return;
LCP_ITF_PAIR_DBG ("ip4_addr_%s: si:%U %U/%u", is_del ? "del" : "add",
return;
LCP_ITF_PAIR_DBG ("ip4_addr_%s: si:%U %U/%u", is_del ? "del" : "add",
int curr_ns_fd = -1;
int vif_ns_fd = -1;
int curr_ns_fd = -1;
int vif_ns_fd = -1;
+ if (!lcp_sync () || lcp_get_netlink_processing_active ())
return;
LCP_ITF_PAIR_DBG ("ip6_addr_%s: si:%U %U/%u", is_del ? "del" : "add",
return;
LCP_ITF_PAIR_DBG ("ip6_addr_%s: si:%U %U/%u", is_del ? "del" : "add",
format_lcp_itf_pair, lip);
// If syncing is enabled, sync Linux state as well.
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;
if (!lcp_sync ())
return;
nl_msg_info_t *msg_info;
int err, n_msgs = 0;
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)
{
/* process a batch of messages. break if we hit our limit */
vec_foreach (msg_info, nm->nl_msg_queue)
{
NL_DBG ("Processed %u messages", n_msgs);
NL_DBG ("Processed %u messages", n_msgs);
+ lcp_set_netlink_processing_active (0);
+
int done = 0;
int n_msgs = 0;
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)
continue_reading:
n_bytes = nl_recv (sk_route, &nla, &buf, /* creds */ NULL);
if (n_bytes <= 0)
+ {
+ lcp_set_netlink_processing_active (0);
+ return n_bytes;
+ }
hdr = (struct nlmsghdr *) buf;
while (nlmsg_ok (hdr, n_bytes))
hdr = (struct nlmsghdr *) buf;
while (nlmsg_ok (hdr, n_bytes))
goto continue_reading;
out:
goto continue_reading;
out:
+ lcp_set_netlink_processing_active (0);
+
nlmsg_free (msg);
free (buf);
nlmsg_free (msg);
free (buf);