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>
161 lines
4.3 KiB
C
161 lines
4.3 KiB
C
/*
|
|
* Copyright (c) 2023 Cisco and/or its affiliates.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <linux-cp/lcp_interface.h>
|
|
|
|
#include <vnet/plugin/plugin.h>
|
|
#include <vnet/mpls/mpls.h>
|
|
#include <vppinfra/linux/netns.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
vlib_log_class_t lcp_mpls_sync_logger;
|
|
|
|
#define LCP_MPLS_SYNC_DBG(...) \
|
|
vlib_log_debug (lcp_mpls_sync_logger, __VA_ARGS__);
|
|
|
|
void
|
|
lcp_mpls_sync_pair_add_cb (lcp_itf_pair_t *lip)
|
|
{
|
|
u8 phy_is_enabled = mpls_sw_interface_is_enabled (lip->lip_phy_sw_if_index);
|
|
LCP_MPLS_SYNC_DBG ("pair_add_cb: mpls enabled %u, parent %U", phy_is_enabled,
|
|
format_lcp_itf_pair, lip);
|
|
if (phy_is_enabled)
|
|
mpls_sw_interface_enable_disable (&mpls_main, lip->lip_host_sw_if_index,
|
|
1);
|
|
}
|
|
|
|
void
|
|
lcp_mpls_sync_state_cb (struct mpls_main_t *mm, uword opaque, u32 sw_if_index,
|
|
u32 is_enable)
|
|
{
|
|
lcp_itf_pair_t *lip;
|
|
index_t lipi;
|
|
int curr_ns_fd = -1;
|
|
int vif_ns_fd = -1;
|
|
int ctl_fd = -1;
|
|
u8 *ctl_path = NULL;
|
|
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: called for sw_if_index %u", sw_if_index);
|
|
|
|
// If device is LCP PHY, sync state to host tap.
|
|
lipi = lcp_itf_pair_find_by_phy (sw_if_index);
|
|
if (INDEX_INVALID != lipi)
|
|
{
|
|
lip = lcp_itf_pair_get (lipi);
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: mpls enabled %u parent %U", is_enable,
|
|
format_lcp_itf_pair, lip);
|
|
mpls_sw_interface_enable_disable (&mpls_main, lip->lip_host_sw_if_index,
|
|
is_enable);
|
|
return;
|
|
}
|
|
|
|
// If device is LCP host, toggle MPLS XC feature.
|
|
lipi = lcp_itf_pair_find_by_host (sw_if_index);
|
|
if (INDEX_INVALID == lipi)
|
|
return;
|
|
lip = lcp_itf_pair_get (lipi);
|
|
|
|
vnet_feature_enable_disable ("mpls-input", "linux-cp-xc-mpls", sw_if_index,
|
|
is_enable, NULL, 0);
|
|
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: mpls xc state %u parent %U", is_enable,
|
|
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 (lip->lip_namespace)
|
|
{
|
|
curr_ns_fd = clib_netns_open (NULL /* self */);
|
|
vif_ns_fd = clib_netns_open (lip->lip_namespace);
|
|
if (vif_ns_fd != -1)
|
|
clib_setns (vif_ns_fd);
|
|
}
|
|
|
|
ctl_path = format (NULL, "/proc/sys/net/mpls/conf/%s/input%c",
|
|
lip->lip_host_name, NULL);
|
|
if (NULL == ctl_path)
|
|
{
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: failed to format sysctl");
|
|
goto SYNC_CLEANUP;
|
|
}
|
|
|
|
ctl_fd = open ((char *) ctl_path, O_WRONLY);
|
|
if (ctl_fd < 0)
|
|
{
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: failed to open %s for writing",
|
|
ctl_path);
|
|
goto SYNC_CLEANUP;
|
|
}
|
|
|
|
if (fdformat (ctl_fd, "%u", is_enable) < 1)
|
|
{
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: failed to write to %s", ctl_path);
|
|
goto SYNC_CLEANUP;
|
|
}
|
|
|
|
LCP_MPLS_SYNC_DBG ("sync_state_cb: set mpls input for %s",
|
|
lip->lip_host_name);
|
|
|
|
SYNC_CLEANUP:
|
|
if (ctl_fd > -1)
|
|
close (ctl_fd);
|
|
|
|
if (NULL != ctl_path)
|
|
vec_free (ctl_path);
|
|
|
|
if (vif_ns_fd != -1)
|
|
close (vif_ns_fd);
|
|
|
|
if (curr_ns_fd != -1)
|
|
{
|
|
clib_setns (curr_ns_fd);
|
|
close (curr_ns_fd);
|
|
}
|
|
}
|
|
|
|
static clib_error_t *
|
|
lcp_mpls_sync_init (vlib_main_t *vm)
|
|
{
|
|
lcp_itf_pair_vft_t mpls_sync_itf_pair_vft = {
|
|
.pair_add_fn = lcp_mpls_sync_pair_add_cb,
|
|
};
|
|
lcp_itf_pair_register_vft (&mpls_sync_itf_pair_vft);
|
|
|
|
mpls_interface_state_change_add_callback (lcp_mpls_sync_state_cb, 0);
|
|
|
|
lcp_mpls_sync_logger = vlib_log_register_class ("linux-cp", "mpls-sync");
|
|
|
|
return NULL;
|
|
}
|
|
|
|
VLIB_INIT_FUNCTION (lcp_mpls_sync_init) = {
|
|
.runs_after = VLIB_INITS ("lcp_interface_init", "mpls_init"),
|
|
};
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|