Compare commits

..

10 Commits

Author SHA1 Message Date
6f5cde1aff Add lcp_itf_pair_get_v2(), as it is used by sFlow plugin 2024-11-02 13:52:13 +01:00
61386a1c63 backport gerrit 40379 from upstream 2024-06-27 17:43:54 +02:00
25b2999485 Backport https://gerrit.fd.io/r/c/vpp/+/40441 2024-04-01 23:07:56 +02:00
cb78074e46 Fix logline tag 2024-03-23 10:04:10 +01:00
0d864a71fe Update README.md 2024-03-09 12:21:21 +01:00
e19f45e29c Update README.md 2024-03-08 23:53:51 +01:00
a960d64a87 Add the ability to skip address sync on unnumbered interfaces 2024-03-05 22:59:55 +01:00
c8dc522fe9 Avoid creating a duplicate LIP 2024-03-05 22:59:55 +01:00
4b9c556f08 Update README.md
fix path.
closes #12
2024-03-03 00:52:03 +01:00
7e482adb4f Update README.md
Add places to find help, considering issues in this repo will not be handled.
2024-02-20 01:25:31 +01:00
10 changed files with 201 additions and 26 deletions

View File

@ -13,28 +13,30 @@ See previous work:
* [netlink listener](https://gerrit.fd.io/r/c/vpp/+/31122)
My work is intended to be re-submitted for review as a cleanup/rewrite of the
existing Linux CP interface mirror and netlink syncer.
existing Linux CP interface mirror and netlink syncer. I will use this repo
to make rapid prototyping progress, sometimes with other software engineers.
Follow along on [my blog](https://ipng.ch/s/articles/) for my findings while
I work towards a completed plugin that can copy VPP configuration into Linux
interfaces, and copy Linux configuration changes into VPP (ie. a fully
bidirectional pipe between Linux and VPP).
When the code is complete, this plugin should be able to work seamlessly with
a higher level controlplane like [FRR](https://frrouting.org/) or
[Bird](https://bird.network.cz/), for example as a BGP/OSPF speaking ISP router.
I work towards feature completion. When the code is complete, this plugin should
be able to work seamlessly with a higher level controlplane like [FRR](https://frrouting.org/)
or [Bird](https://bird.network.cz/), for example as a BGP/OSPF speaking ISP router.
## WARNING!!
The only reason that this code is here, is so that I can make some progress
Users should use the `linux-cp` plugin that natively ships with VPP since 2022.
The only reason that this code is still here, is so that I can make some progress
iterating on the Linux CP plugin, and share my findings with some interested
folks. The goal is NOT to use this plugin anywhere other than a bench. I
intend to contribute the plugin back upstream as soon as it's peer reviewed!
intend to contribute any changes submitted to this copy of the plugin back
upstream as soon as they have had some mileage and peer review!
***Pull Requests and Issues will be immediately closed without warning***
VPP's code lives at [fd.io](https://gerrit.fd.io/r/c/vpp), and this copy is
shared only for convenience purposes.
shared only for convenience purposes. If you do require support, you can
discuss your case on the VPP Developer mailinglist at vpp-dev@lists.fd.io
or alternatively you can ask for a commercial support quote at sales@ipng.ch.
## Functionality
@ -158,7 +160,7 @@ wget http://deb.debian.org/debian/pool/main/libn/libnl3/libnl3_3.7.0-0.2.debian.
tar xzf libnl3_3.7.0.orig.tar.gz
cd libnl-3.7.0
tar xf libnl3_3.7.0-0.2.debian.tar.xz
tar xf ../libnl3_3.7.0-0.2.debian.tar.xz
sudo apt install dpkg-dev debhelper dh-exec cdbs bison flex automake autoconf \
dh-autoreconf pkg-config

42
lcpng.c
View File

@ -95,6 +95,26 @@ lcp_sync (void)
return lcpm->lcp_sync;
}
void
lcp_set_sync_unnumbered (u8 is_sync)
{
lcp_main_t *lcpm = &lcp_main;
lcpm->lcp_sync_unnumbered = (is_sync != 0);
// If we set to 'on', do a one-off sync of LCP interfaces
if (is_sync)
lcp_itf_pair_sync_state_all ();
}
int
lcp_sync_unnumbered (void)
{
lcp_main_t *lcpm = &lcp_main;
return lcpm->lcp_sync_unnumbered;
}
void
lcp_set_auto_subint (u8 is_auto)
{
@ -111,6 +131,28 @@ lcp_auto_subint (void)
return lcpm->lcp_auto_subint;
}
void
lcp_set_default_num_queues (u16 num_queues, u8 is_tx)
{
lcp_main_t *lcpm = &lcp_main;
if (is_tx)
lcpm->num_tx_queues = num_queues;
else
lcpm->num_rx_queues = num_queues;
}
u16
lcp_get_default_num_queues (u8 is_tx)
{
lcp_main_t *lcpm = &lcp_main;
if (is_tx)
return lcpm->num_tx_queues;
return lcpm->num_rx_queues ?: vlib_num_workers ();
}
/*
* fd.io coding-style-patch-verification: ON
*

11
lcpng.h
View File

@ -26,6 +26,9 @@ typedef struct lcp_main_s
int default_ns_fd;
u8 lcp_auto_subint; /* Automatically create/delete LCP sub-interfaces */
u8 lcp_sync; /* Automatically sync VPP changes to LCP */
u8 lcp_sync_unnumbered; /* Automatically sync unnumbered interfaces to LCP */
u16 num_rx_queues;
u16 num_tx_queues;
/* Set when Unit testing */
u8 test_mode;
} lcp_main_t;
@ -39,11 +42,17 @@ int lcp_set_default_ns (u8 *ns);
u8 *lcp_get_default_ns (void); /* Returns NULL or shared string */
int lcp_get_default_ns_fd (void);
/*
/**
* Sync state from VPP into all LCP devices
*/
void lcp_itf_pair_sync_state_all ();
/**
* Get/Set the default queue number for LCP host taps.
*/
void lcp_set_default_num_queues (u16 num_queues, u8 is_tx);
u16 lcp_get_default_num_queues (u8 is_tx);
#endif
/*

View File

@ -101,13 +101,28 @@ define lcp_itf_pair_add_del_v2_reply
@param context - sender context, to match reply w/ request
@param sw_if_index - interface to use as filter (~0 == "all")
*/
define lcp_itf_pair_get
autoendian define lcp_itf_pair_get
{
u32 client_index;
u32 context;
u32 cursor;
};
define lcp_itf_pair_get_reply
autoendian define lcp_itf_pair_get_reply
{
u32 context;
i32 retval;
u32 cursor;
};
autoendian define lcp_itf_pair_get_v2
{
u32 client_index;
u32 context;
u32 cursor;
vl_api_interface_index_t sw_if_index [default=0xffffffff];
};
autoendian define lcp_itf_pair_get_v2_reply
{
u32 context;
i32 retval;

View File

@ -133,11 +133,11 @@ send_lcp_itf_pair_details (index_t lipi, vl_api_registration_t *rp,
vl_api_lcp_itf_pair_details_t *rmp;
lcp_itf_pair_t *lcp_pair = lcp_itf_pair_get (lipi);
REPLY_MACRO_DETAILS4 (
REPLY_MACRO_DETAILS4_END (
VL_API_LCP_ITF_PAIR_DETAILS, rp, context, ({
rmp->phy_sw_if_index = ntohl (lcp_pair->lip_phy_sw_if_index);
rmp->host_sw_if_index = ntohl (lcp_pair->lip_host_sw_if_index);
rmp->vif_index = ntohl (lcp_pair->lip_vif_index);
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),
@ -156,11 +156,44 @@ 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 (
REPLY_AND_DETAILS_MACRO_END (
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_itf_pair_get_v2_t_handler (vl_api_lcp_itf_pair_get_v2_t *mp)
{
vl_api_lcp_itf_pair_get_v2_reply_t *rmp;
i32 rv = 0;
if (mp->sw_if_index == ~0)
{
// Does this actually work?
REPLY_AND_DETAILS_MACRO_END (
VL_API_LCP_ITF_PAIR_GET_REPLY, lcp_itf_pair_pool,
({ send_lcp_itf_pair_details (cursor, rp, mp->context); }));
}
else
{
VALIDATE_SW_IF_INDEX_END (mp);
u32 pair_index = lcp_itf_pair_find_by_phy (mp->sw_if_index);
if (pair_index == INDEX_INVALID)
{
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
goto bad_sw_if_index;
}
send_lcp_itf_pair_details (
pair_index, vl_api_client_index_to_registration (mp->client_index),
mp->context);
BAD_SW_IF_INDEX_LABEL;
REPLY_MACRO2_END (VL_API_LCP_ITF_PAIR_GET_V2_REPLY,
({ rmp->cursor = ~0; }));
}
}
static void
vl_api_lcp_default_ns_set_t_handler (vl_api_lcp_default_ns_set_t *mp)
{

View File

@ -142,6 +142,37 @@ VLIB_CLI_COMMAND (lcp_sync_command, static) = {
.function = lcp_sync_command_fn,
};
static clib_error_t *
lcp_sync_unnumbered_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
if (!unformat_user (input, unformat_line_input, line_input))
return 0;
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "on") || unformat (line_input, "enable"))
lcp_set_sync_unnumbered (1);
else if (unformat (line_input, "off") ||
unformat (line_input, "disable"))
lcp_set_sync_unnumbered (0);
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, line_input);
}
unformat_free (line_input);
return 0;
}
VLIB_CLI_COMMAND (lcp_sync_unnumbered_command, static) = {
.path = "lcp lcp-sync-unnumbered",
.short_help = "lcp lcp-sync-unnumbered [on|enable|off|disable]",
.function = lcp_sync_unnumbered_command_fn,
};
static clib_error_t *
lcp_auto_subint_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)

View File

@ -109,7 +109,22 @@ lcp_itf_pair_sync_state (lcp_itf_pair_t *lip)
/* Linux will remove IPv6 addresses on children when the parent state
* goes down, so we ensure all IPv4/IPv6 addresses are synced.
*/
lcp_itf_set_interface_addr (lip);
if (sw->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
{
if (lcp_sync_unnumbered ())
{
lcp_itf_set_interface_addr (lip);
}
else
{
LCP_IF_NOTICE ("sync_state: not syncing addresses on unnumbered %U",
format_lcp_itf_pair, lip);
}
}
else
{
lcp_itf_set_interface_addr (lip);
}
if (vif_ns_fd != -1)
close (vif_ns_fd);

View File

@ -133,6 +133,8 @@ lcp_itf_pair_show (u32 phy_sw_if_index)
vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
lcp_auto_subint () ? "on" : "off");
vlib_cli_output (vm, "lcp lcp-sync %s\n", lcp_sync () ? "on" : "off");
vlib_cli_output (vm, "lcp lcp-sync-unnumbered %s\n",
lcp_sync_unnumbered () ? "on" : "off");
if (phy_sw_if_index == ~0)
{
@ -261,7 +263,10 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name,
vec_validate_init_empty (lip_db_by_host, host_sw_if_index, INDEX_INVALID);
lip_db_by_phy[phy_sw_if_index] = lipi;
lip_db_by_host[host_sw_if_index] = lipi;
hash_set (lip_db_by_vif, host_index, lipi);
if (clib_strcmp ((char *) ns, (char *) lcp_get_default_ns ()) == 0)
{
hash_set (lip_db_by_vif, host_index, lipi);
}
lip->lip_host_sw_if_index = host_sw_if_index;
lip->lip_phy_sw_if_index = phy_sw_if_index;
@ -550,6 +555,7 @@ static clib_error_t *
lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
{
u8 *default_ns;
u32 tmp;
default_ns = NULL;
@ -569,6 +575,10 @@ lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
lcp_set_auto_subint (1 /* is_auto */);
else if (unformat (input, "lcp-sync"))
lcp_set_sync (1 /* is_auto */);
else if (unformat (input, "num-rx-queues %d", &tmp))
lcp_set_default_num_queues (tmp, 0 /* is_tx */);
else if (unformat (input, "num-tx-queues %d", &tmp))
lcp_set_default_num_queues (tmp, 1 /* is_tx */);
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
@ -782,6 +792,14 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
const vnet_sw_interface_t *sw;
const vnet_hw_interface_t *hw;
lcp_itf_pair_t *lip;
index_t lipi;
lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index);
if (lipi != INDEX_INVALID)
{
LCP_IF_ERROR ("pair_create: already created");
return VNET_API_ERROR_VALUE_EXIST;
}
if (!vnet_sw_if_index_is_api_valid (phy_sw_if_index))
{
@ -983,8 +1001,10 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
else
{
tap_create_if_args_t args = {
.num_rx_queues = clib_max (1, vlib_num_workers ()),
.num_tx_queues = 1,
.num_rx_queues =
clib_max (1, lcp_get_default_num_queues (0 /* is_tx */)),
.num_tx_queues =
clib_max (1, lcp_get_default_num_queues (1 /* is_tx */)),
.id = ~0,
.sw_if_index = ~0,
.rx_ring_sz = 256,
@ -1078,7 +1098,7 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name,
vnet_sw_interface_admin_up (vnm, host_sw_if_index);
if (lcp_sync ())
{
lip = lcp_itf_pair_get (lcp_itf_pair_find_by_vif (vif_index));
lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index));
lcp_itf_pair_sync_state (lip);
}
/*
@ -1225,6 +1245,8 @@ lcp_itf_pair_init (vlib_main_t *vm)
tcp_punt_unknown (vm, 0, 1);
tcp_punt_unknown (vm, 1, 1);
lcp_main.lcp_sync_unnumbered = 1;
return NULL;
}

View File

@ -166,6 +166,12 @@ int lcp_auto_subint (void);
void lcp_set_sync (u8 is_auto);
int lcp_sync (void);
/**
* sync address of unnumbered interfaces from VPP into LCP
*/
void lcp_set_sync_unnumbered (u8 is_sync);
int lcp_sync_unnumbered (void);
typedef void (*lcp_itf_pair_add_cb_t) (lcp_itf_pair_t *);
typedef void (*lcp_itf_pair_del_cb_t) (lcp_itf_pair_t *);

View File

@ -1149,7 +1149,7 @@ lcp_nl_neigh_add (struct rtnl_neigh *rn)
if ((rna = rtnl_neigh_get_dst (rn)) == NULL)
{
LCP_NL_DBG ("neigh_del: ignore missing neighbor %U", format_nl_object,
LCP_NL_DBG ("neigh_add: ignore missing neighbor %U", format_nl_object,
rn);
return;
}