This is the first in a series of functions that aims to copy forward interface changes in the VPP dataplane into the linux interfaces. Capture link state changes (set interface state ...) and apply them to Linux. There's an important dissonance here: - When Linux sets a parent interface up, all children also go up. ip link set enp66s0f1 down ip link add link enp66s0f1 name foo type vlan id 1234 ip link set foo down ip link | grep enp66s0f1 9: enp66s0f1: <BROADCAST,MULTICAST> mtu 9000 qdisc mq state DOWN mode DEFAULT group default qlen 1000 61: foo@enp66s0f1: <BROADCAST,MULTICAST,M-DOWN> mtu 9000 qdisc noop state DOWN mode DEFAULT group default qlen 1000 ip link set enp66s0f1 up ip link | grep s0f1 9: enp66s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP mode DEFAULT group default qlen 1000 61: foo@enp66s0f1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc noqueue state UP mode DEFAULT group default qlen 1000 While in VPP this is not so, there each individual interface and sub-interface stands for itself. I think the proper fix here is to walk all sub-interfaces when a phy changes, and force a sync of those from VPP to LCP as well. I'll do that in a followup commit so it's easier to roll back.
259 lines
6.4 KiB
C
259 lines
6.4 KiB
C
/*
|
|
* Copyright 2020 Rubicon Communications, LLC.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <sys/socket.h>
|
|
#include <linux/if.h>
|
|
|
|
#include <vnet/vnet.h>
|
|
#include <vnet/plugin/plugin.h>
|
|
|
|
#include <vlibapi/api.h>
|
|
#include <vlibmemory/api.h>
|
|
#include <vpp/app/version.h>
|
|
#include <vnet/format_fns.h>
|
|
|
|
#include <lcpng/lcpng_interface.h>
|
|
#include <lcpng/lcpng_if.api_enum.h>
|
|
#include <lcpng/lcpng_if.api_types.h>
|
|
|
|
static u16 lcp_msg_id_base;
|
|
#define REPLY_MSG_ID_BASE lcp_msg_id_base
|
|
#include <vlibapi/api_helper_macros.h>
|
|
|
|
static lip_host_type_t
|
|
api_decode_host_type (vl_api_lcp_itf_host_type_t type)
|
|
{
|
|
if (type == LCP_API_ITF_HOST_TUN)
|
|
return LCP_ITF_HOST_TUN;
|
|
|
|
return LCP_ITF_HOST_TAP;
|
|
}
|
|
|
|
static vl_api_lcp_itf_host_type_t
|
|
api_encode_host_type (lip_host_type_t type)
|
|
{
|
|
if (type == LCP_ITF_HOST_TUN)
|
|
return LCP_API_ITF_HOST_TUN;
|
|
|
|
return LCP_API_ITF_HOST_TAP;
|
|
}
|
|
|
|
static int
|
|
vl_api_lcp_itf_pair_add (u32 phy_sw_if_index, lip_host_type_t lip_host_type,
|
|
u8 *mp_host_if_name, size_t sizeof_host_if_name,
|
|
u8 *mp_namespace, size_t sizeof_mp_namespace,
|
|
u32 *host_sw_if_index_p)
|
|
{
|
|
u8 *host_if_name, *netns;
|
|
int host_len, netns_len, rv;
|
|
|
|
host_if_name = netns = 0;
|
|
|
|
/* lcp_itf_pair_create expects vec of u8 */
|
|
host_len = clib_strnlen ((char *) mp_host_if_name, sizeof_host_if_name - 1);
|
|
vec_add (host_if_name, mp_host_if_name, host_len);
|
|
vec_add1 (host_if_name, 0);
|
|
|
|
netns_len = clib_strnlen ((char *) mp_namespace, sizeof_mp_namespace - 1);
|
|
vec_add (netns, mp_namespace, netns_len);
|
|
vec_add1 (netns, 0);
|
|
|
|
rv = lcp_itf_pair_create (phy_sw_if_index, host_if_name, lip_host_type,
|
|
netns, host_sw_if_index_p);
|
|
|
|
vec_free (host_if_name);
|
|
vec_free (netns);
|
|
|
|
return rv;
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_itf_pair_add_del_t_handler (vl_api_lcp_itf_pair_add_del_t *mp)
|
|
{
|
|
u32 phy_sw_if_index;
|
|
vl_api_lcp_itf_pair_add_del_reply_t *rmp;
|
|
lip_host_type_t lip_host_type;
|
|
int rv;
|
|
|
|
if (!vnet_sw_if_index_is_api_valid (mp->sw_if_index))
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
phy_sw_if_index = mp->sw_if_index;
|
|
lip_host_type = api_decode_host_type (mp->host_if_type);
|
|
if (mp->is_add)
|
|
{
|
|
rv =
|
|
vl_api_lcp_itf_pair_add (phy_sw_if_index, lip_host_type,
|
|
mp->host_if_name, sizeof (mp->host_if_name),
|
|
mp->namespace, sizeof (mp->namespace), NULL);
|
|
}
|
|
else
|
|
{
|
|
rv = lcp_itf_pair_delete (phy_sw_if_index);
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_LCP_ITF_PAIR_ADD_DEL_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_itf_pair_add_del_v2_t_handler (vl_api_lcp_itf_pair_add_del_v2_t *mp)
|
|
{
|
|
u32 phy_sw_if_index, host_sw_if_index = ~0;
|
|
vl_api_lcp_itf_pair_add_del_v2_reply_t *rmp;
|
|
lip_host_type_t lip_host_type;
|
|
int rv;
|
|
|
|
if (!vnet_sw_if_index_is_api_valid (mp->sw_if_index))
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
phy_sw_if_index = mp->sw_if_index;
|
|
lip_host_type = api_decode_host_type (mp->host_if_type);
|
|
if (mp->is_add)
|
|
{
|
|
rv = vl_api_lcp_itf_pair_add (phy_sw_if_index, lip_host_type,
|
|
mp->host_if_name,
|
|
sizeof (mp->host_if_name), mp->namespace,
|
|
sizeof (mp->namespace), &host_sw_if_index);
|
|
}
|
|
else
|
|
{
|
|
rv = lcp_itf_pair_delete (phy_sw_if_index);
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO2 (VL_API_LCP_ITF_PAIR_ADD_DEL_V2_REPLY,
|
|
{ rmp->host_sw_if_index = ntohl (host_sw_if_index); });
|
|
}
|
|
|
|
static void
|
|
send_lcp_itf_pair_details (index_t lipi, vl_api_registration_t *rp,
|
|
u32 context)
|
|
{
|
|
vl_api_lcp_itf_pair_details_t *rmp;
|
|
lcp_itf_pair_t *lcp_pair = lcp_itf_pair_get (lipi);
|
|
|
|
REPLY_MACRO_DETAILS4 (
|
|
VL_API_LCP_ITF_PAIR_DETAILS, rp, context, ({
|
|
rmp->phy_sw_if_index = lcp_pair->lip_phy_sw_if_index;
|
|
rmp->host_sw_if_index = lcp_pair->lip_host_sw_if_index;
|
|
rmp->vif_index = lcp_pair->lip_vif_index;
|
|
rmp->host_if_type = api_encode_host_type (lcp_pair->lip_host_type);
|
|
|
|
memcpy_s (rmp->host_if_name, sizeof (rmp->host_if_name),
|
|
lcp_pair->lip_host_name, vec_len (lcp_pair->lip_host_name));
|
|
|
|
clib_strncpy ((char *) rmp->namespace, (char *) lcp_pair->lip_namespace,
|
|
vec_len (lcp_pair->lip_namespace));
|
|
}));
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_itf_pair_get_t_handler (vl_api_lcp_itf_pair_get_t *mp)
|
|
{
|
|
vl_api_lcp_itf_pair_get_reply_t *rmp;
|
|
i32 rv = 0;
|
|
|
|
REPLY_AND_DETAILS_MACRO (
|
|
VL_API_LCP_ITF_PAIR_GET_REPLY, lcp_itf_pair_pool,
|
|
({ send_lcp_itf_pair_details (cursor, rp, mp->context); }));
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_default_ns_set_t_handler(vl_api_lcp_default_ns_set_t *mp) {
|
|
vl_api_lcp_default_ns_set_reply_t *rmp;
|
|
int rv;
|
|
|
|
mp->namespace[LCP_NS_LEN - 1] = 0;
|
|
rv = lcp_set_default_ns(mp->namespace);
|
|
|
|
REPLY_MACRO(VL_API_LCP_DEFAULT_NS_SET_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_default_ns_get_t_handler(vl_api_lcp_default_ns_get_t *mp) {
|
|
lcp_main_t *lcpm = &lcp_main;
|
|
vl_api_lcp_default_ns_get_reply_t *rmp;
|
|
vl_api_registration_t *reg;
|
|
char *ns;
|
|
|
|
reg = vl_api_client_index_to_registration (mp->client_index);
|
|
if (!reg)
|
|
return;
|
|
|
|
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
|
clib_memset (rmp, 0, sizeof (*rmp));
|
|
rmp->_vl_msg_id = (VL_API_LCP_DEFAULT_NS_GET_REPLY + lcpm->msg_id_base);
|
|
rmp->context = mp->context;
|
|
|
|
ns = (char *)lcp_get_default_ns();
|
|
if (ns)
|
|
clib_strncpy ((char *) rmp->namespace, ns, LCP_NS_LEN - 1);
|
|
|
|
vl_api_send_msg (reg, (u8 *) rmp);
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_itf_pair_replace_begin_t_handler (
|
|
vl_api_lcp_itf_pair_replace_begin_t *mp)
|
|
{
|
|
vl_api_lcp_itf_pair_replace_begin_reply_t *rmp;
|
|
int rv;
|
|
|
|
rv = lcp_itf_pair_replace_begin ();
|
|
|
|
REPLY_MACRO (VL_API_LCP_ITF_PAIR_REPLACE_BEGIN_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_lcp_itf_pair_replace_end_t_handler (
|
|
vl_api_lcp_itf_pair_replace_end_t *mp)
|
|
{
|
|
vl_api_lcp_itf_pair_replace_end_reply_t *rmp;
|
|
int rv = 0;
|
|
|
|
rv = lcp_itf_pair_replace_end ();
|
|
|
|
REPLY_MACRO (VL_API_LCP_ITF_PAIR_REPLACE_END_REPLY);
|
|
}
|
|
|
|
/*
|
|
* Set up the API message handling tables
|
|
*/
|
|
#include <lcpng/lcpng_if.api.c>
|
|
|
|
static clib_error_t *
|
|
lcp_plugin_api_hookup (vlib_main_t *vm)
|
|
{
|
|
/* Ask for a correctly-sized block of API message decode slots */
|
|
lcp_msg_id_base = setup_message_id_table ();
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
VLIB_INIT_FUNCTION (lcp_plugin_api_hookup);
|
|
|
|
#include <vpp/app/version.h>
|
|
VLIB_PLUGIN_REGISTER () = {
|
|
.version = VPP_BUILD_VER,
|
|
.description = "Linux Control Plane - Interface Mirror",
|
|
.default_disabled = 1,
|
|
};
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|