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) * [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 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 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 I work towards feature completion. When the code is complete, this plugin should
interfaces, and copy Linux configuration changes into VPP (ie. a fully be able to work seamlessly with a higher level controlplane like [FRR](https://frrouting.org/)
bidirectional pipe between Linux and VPP). or [Bird](https://bird.network.cz/), for example as a BGP/OSPF speaking ISP router.
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!! ## 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 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 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*** ***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 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 ## 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 tar xzf libnl3_3.7.0.orig.tar.gz
cd libnl-3.7.0 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 \ sudo apt install dpkg-dev debhelper dh-exec cdbs bison flex automake autoconf \
dh-autoreconf pkg-config dh-autoreconf pkg-config

42
lcpng.c
View File

@ -95,6 +95,26 @@ lcp_sync (void)
return lcpm->lcp_sync; 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 void
lcp_set_auto_subint (u8 is_auto) lcp_set_auto_subint (u8 is_auto)
{ {
@ -111,6 +131,28 @@ lcp_auto_subint (void)
return lcpm->lcp_auto_subint; 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 * 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; int default_ns_fd;
u8 lcp_auto_subint; /* Automatically create/delete LCP sub-interfaces */ u8 lcp_auto_subint; /* Automatically create/delete LCP sub-interfaces */
u8 lcp_sync; /* Automatically sync VPP changes to LCP */ 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 */ /* Set when Unit testing */
u8 test_mode; u8 test_mode;
} lcp_main_t; } 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 */ u8 *lcp_get_default_ns (void); /* Returns NULL or shared string */
int lcp_get_default_ns_fd (void); int lcp_get_default_ns_fd (void);
/* /**
* Sync state from VPP into all LCP devices * Sync state from VPP into all LCP devices
*/ */
void lcp_itf_pair_sync_state_all (); 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 #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 context - sender context, to match reply w/ request
@param sw_if_index - interface to use as filter (~0 == "all") @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 client_index;
u32 context; u32 context;
u32 cursor; 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; u32 context;
i32 retval; 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; vl_api_lcp_itf_pair_details_t *rmp;
lcp_itf_pair_t *lcp_pair = lcp_itf_pair_get (lipi); 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, ({ VL_API_LCP_ITF_PAIR_DETAILS, rp, context, ({
rmp->phy_sw_if_index = ntohl (lcp_pair->lip_phy_sw_if_index); rmp->phy_sw_if_index = lcp_pair->lip_phy_sw_if_index;
rmp->host_sw_if_index = ntohl (lcp_pair->lip_host_sw_if_index); rmp->host_sw_if_index = lcp_pair->lip_host_sw_if_index;
rmp->vif_index = ntohl (lcp_pair->lip_vif_index); rmp->vif_index = lcp_pair->lip_vif_index;
rmp->host_if_type = api_encode_host_type (lcp_pair->lip_host_type); rmp->host_if_type = api_encode_host_type (lcp_pair->lip_host_type);
memcpy_s (rmp->host_if_name, sizeof (rmp->host_if_name), 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; vl_api_lcp_itf_pair_get_reply_t *rmp;
i32 rv = 0; i32 rv = 0;
REPLY_AND_DETAILS_MACRO ( REPLY_AND_DETAILS_MACRO_END (
VL_API_LCP_ITF_PAIR_GET_REPLY, lcp_itf_pair_pool, VL_API_LCP_ITF_PAIR_GET_REPLY, lcp_itf_pair_pool,
({ send_lcp_itf_pair_details (cursor, rp, mp->context); })); ({ 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 static void
vl_api_lcp_default_ns_set_t_handler (vl_api_lcp_default_ns_set_t *mp) 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, .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 * static clib_error_t *
lcp_auto_subint_command_fn (vlib_main_t *vm, unformat_input_t *input, lcp_auto_subint_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd) 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 /* Linux will remove IPv6 addresses on children when the parent state
* goes down, so we ensure all IPv4/IPv6 addresses are synced. * 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) if (vif_ns_fd != -1)
close (vif_ns_fd); 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", vlib_cli_output (vm, "lcp lcp-auto-subint %s\n",
lcp_auto_subint () ? "on" : "off"); 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 %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) 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); 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_phy[phy_sw_if_index] = lipi;
lip_db_by_host[host_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_host_sw_if_index = host_sw_if_index;
lip->lip_phy_sw_if_index = phy_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) lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
{ {
u8 *default_ns; u8 *default_ns;
u32 tmp;
default_ns = NULL; 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 */); lcp_set_auto_subint (1 /* is_auto */);
else if (unformat (input, "lcp-sync")) else if (unformat (input, "lcp-sync"))
lcp_set_sync (1 /* is_auto */); 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 else
return clib_error_return (0, "unknown input `%U'", return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input); 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_sw_interface_t *sw;
const vnet_hw_interface_t *hw; const vnet_hw_interface_t *hw;
lcp_itf_pair_t *lip; 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)) 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 else
{ {
tap_create_if_args_t args = { tap_create_if_args_t args = {
.num_rx_queues = clib_max (1, vlib_num_workers ()), .num_rx_queues =
.num_tx_queues = 1, 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, .id = ~0,
.sw_if_index = ~0, .sw_if_index = ~0,
.rx_ring_sz = 256, .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); vnet_sw_interface_admin_up (vnm, host_sw_if_index);
if (lcp_sync ()) 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); 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, 0, 1);
tcp_punt_unknown (vm, 1, 1); tcp_punt_unknown (vm, 1, 1);
lcp_main.lcp_sync_unnumbered = 1;
return NULL; return NULL;
} }

View File

@ -166,6 +166,12 @@ int lcp_auto_subint (void);
void lcp_set_sync (u8 is_auto); void lcp_set_sync (u8 is_auto);
int lcp_sync (void); 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_add_cb_t) (lcp_itf_pair_t *);
typedef void (*lcp_itf_pair_del_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) 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); rn);
return; return;
} }