linux-cp: Add VPP->Linux synchronization

Part 1 -- notes in https://ipng.ch/s/articles/2021/08/13/vpp-2.html
Add the ability for VPP to copy out (sync) its state from the dataplane
to Linux Interface Pairs, when they exist. Gated by a configuration
flag (linux-cp { lcp-sync }), and by a CLI option to toggle on/off,
synchronize the following events:

- Interface state changes
- Interface MTU changes
- Interface IPv4/IPv6 address add/deletion

In VPP, subints can have any link state and MTU, orthogonal to their
phy. In Linux, setting admin-down on a phy forces its children to be
down as well. Also, in Linux, MTU of children must not exceed that of
the phy. Add a state synchronizer which walks over phy+subints to
ensure Linux and VPP end up in the same consistent state.

Part 2 -- notes in https://ipng.ch/s/articles/2021/08/15/vpp-3.html
Add the ability for VPP to autocreate sub-interfaces of existing Linux
Interface pairs. Gated by a configuration flag
(linux-cp { lcp-auto-subint }), and by a CLI option to toggle on/off,
synchronize the following event:

- Sub-interface creation (dot1q, dot1ad, QinQ and QinAD)

A few other changes:
- Add two functions into netlink.[ch] to delete ip4 and ip6 addresses.
- Remove a spurious logline (printing MTU) in netlink.c.
- Resolve a TODO around vnet_sw_interface_supports_addressing()

Type: improvement
Signed-off-by: Pim van Pelt <pim@ipng.nl>
Change-Id: I34fc070e80af4013be58d7a8cbf64296cc760e4e
Signed-off-by: Pim van Pelt <pim@ipng.nl>
This commit is contained in:
Pim van Pelt
2021-09-09 17:53:09 +00:00
committed by Matthew Smith
parent 0cef5f5d71
commit 1705a6baef
9 changed files with 743 additions and 167 deletions
+1
View File
@@ -27,6 +27,7 @@ include_directories(${LIBMNL_INCLUDE_DIR})
add_vpp_library(lcp
SOURCES
lcp_interface.c
lcp_interface_sync.c
lcp_adj.c
lcp.c
+37
View File
@@ -20,6 +20,7 @@
#include <net/if.h>
#include <plugins/linux-cp/lcp.h>
#include <plugins/linux-cp/lcp_interface.h>
lcp_main_t lcp_main;
@@ -76,6 +77,42 @@ lcp_set_default_ns (u8 *ns)
return 0;
}
void
lcp_set_sync (u8 is_auto)
{
lcp_main_t *lcpm = &lcp_main;
lcpm->lcp_sync = (is_auto != 0);
// If we set to 'on', do a one-off sync of LCP interfaces
if (is_auto)
lcp_itf_pair_sync_state_all ();
}
int
lcp_sync (void)
{
lcp_main_t *lcpm = &lcp_main;
return lcpm->lcp_sync;
}
void
lcp_set_auto_subint (u8 is_auto)
{
lcp_main_t *lcpm = &lcp_main;
lcpm->lcp_auto_subint = (is_auto != 0);
}
int
lcp_auto_subint (void)
{
lcp_main_t *lcpm = &lcp_main;
return lcpm->lcp_auto_subint;
}
/*
* fd.io coding-style-patch-verification: ON
*
+3 -2
View File
@@ -24,8 +24,9 @@ typedef struct lcp_main_s
u16 msg_id_base; /* API message ID base */
u8 *default_namespace; /* default namespace if set */
int default_ns_fd;
/* Set when Unit testing */
u8 test_mode;
u8 lcp_auto_subint; /* Automatically create/delete LCP sub-interfaces */
u8 lcp_sync; /* Automatically sync VPP changes to LCP */
u8 test_mode; /* Set when Unit testing */
} lcp_main_t;
extern lcp_main_t lcp_main;
+62
View File
@@ -111,6 +111,68 @@ VLIB_CLI_COMMAND (lcp_itf_pair_create_command, static) = {
.function = lcp_itf_pair_create_command_fn,
};
static clib_error_t *
lcp_sync_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 (1);
else if (unformat (line_input, "off") ||
unformat (line_input, "disable"))
lcp_set_sync (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_command, static) = {
.path = "lcp lcp-sync",
.short_help = "lcp lcp-sync [on|enable|off|disable]",
.function = lcp_sync_command_fn,
};
static clib_error_t *
lcp_auto_subint_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_auto_subint (1);
else if (unformat (line_input, "off") ||
unformat (line_input, "disable"))
lcp_set_auto_subint (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_auto_subint_command, static) = {
.path = "lcp lcp-auto-subint",
.short_help = "lcp lcp-auto-subint [on|enable|off|disable]",
.function = lcp_auto_subint_command_fn,
};
static clib_error_t *
lcp_default_netns_command_fn (vlib_main_t *vm, unformat_input_t *input,
vlib_cli_command_t *cmd)
File diff suppressed because it is too large Load Diff
+46 -8
View File
@@ -21,6 +21,22 @@
#include <plugins/linux-cp/lcp.h>
extern vlib_log_class_t lcp_itf_pair_logger;
#define LCP_ITF_PAIR_DBG(...) \
vlib_log_debug (lcp_itf_pair_logger, __VA_ARGS__);
#define LCP_ITF_PAIR_INFO(...) \
vlib_log_info (lcp_itf_pair_logger, __VA_ARGS__);
#define LCP_ITF_PAIR_NOTICE(...) \
vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__);
#define LCP_ITF_PAIR_WARN(...) \
vlib_log_warn (lcp_itf_pair_logger, __VA_ARGS__);
#define LCP_ITF_PAIR_ERR(...) vlib_log_err (lcp_itf_pair_logger, __VA_ARGS__);
#define foreach_lcp_itf_pair_flag _ (STALE, 0, "stale")
typedef enum lip_flag_t_
@@ -88,8 +104,6 @@ extern index_t lcp_itf_pair_find_by_vif (u32 vif_index);
extern int lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index,
u8 *host_name, u32 host_index,
lip_host_type_t host_type, u8 *ns);
extern int lcp_itf_pair_add_sub (u32 vif, u8 *host_name, u32 sub_sw_if_index,
u32 phy_sw_if_index, u8 *ns);
extern int lcp_itf_pair_del (u32 phy_sw_if_index);
/**
@@ -144,12 +158,6 @@ lcp_itf_pair_find_by_host (u32 host_sw_if_index)
return (lip_db_by_host[host_sw_if_index]);
}
/**
* manage interface auto creation
*/
void lcp_set_auto_intf (u8 is_auto);
int lcp_auto_intf (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 *);
@@ -160,6 +168,36 @@ typedef struct lcp_itf_pair_vft
} lcp_itf_pair_vft_t;
void lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft);
/**
* sub-interface auto creation/deletion for LCP
*/
void lcp_set_auto_subint (u8 is_auto);
int lcp_auto_subint (void);
/**
* sync state changes from VPP into LCP
*/
void lcp_set_sync (u8 is_auto);
int lcp_sync (void);
/* Set TAP and Linux host link state */
void lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state);
/* Set any VPP L3 addresses on Linux host device */
void lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip);
/* Sync all state from VPP to a specific Linux device, all sub-interfaces
* of a hardware interface, or all interfaces in the system.
*
* Note: in some circumstances, this syncer will (have to) make changes to
* the VPP interface, for example if its MTU is greater than its parent.
* See the function for rationale.
*/
void lcp_itf_pair_sync_state (lcp_itf_pair_t *lip);
void lcp_itf_pair_sync_state_hw (vnet_hw_interface_t *hi);
void lcp_itf_pair_sync_state_all ();
/*
* fd.io coding-style-patch-verification: ON
*
File diff suppressed because it is too large Load Diff
+44 -1
View File
@@ -273,7 +273,6 @@ vnet_netlink_get_link_mtu (int ifindex, u32 *mtu)
*mtu = clib_net_to_host_u32 (msg_mtu);
else
*mtu = msg_mtu;
clib_warning ("mtu: %d", *mtu);
goto done;
}
offset = NLA_ALIGN (attr->nla_len);
@@ -409,6 +408,50 @@ vnet_netlink_add_ip6_route (void *dst, u8 dst_len, void *gw)
return err;
}
clib_error_t *
vnet_netlink_del_ip4_addr (int ifindex, void *addr, int pfx_len)
{
vnet_netlink_msg_t m;
struct ifaddrmsg ifa = { 0 };
clib_error_t *err = 0;
ifa.ifa_family = AF_INET;
ifa.ifa_prefixlen = pfx_len;
ifa.ifa_index = ifindex;
vnet_netlink_msg_init (&m, RTM_DELADDR, NLM_F_REQUEST, &ifa,
sizeof (struct ifaddrmsg));
vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 4);
vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 4);
err = vnet_netlink_msg_send (&m, NULL);
if (err)
err = clib_error_return (0, "del ip4 addr %U", format_clib_error, err);
return err;
}
clib_error_t *
vnet_netlink_del_ip6_addr (int ifindex, void *addr, int pfx_len)
{
vnet_netlink_msg_t m;
struct ifaddrmsg ifa = { 0 };
clib_error_t *err = 0;
ifa.ifa_family = AF_INET6;
ifa.ifa_prefixlen = pfx_len;
ifa.ifa_index = ifindex;
vnet_netlink_msg_init (&m, RTM_DELADDR, NLM_F_REQUEST, &ifa,
sizeof (struct ifaddrmsg));
vnet_netlink_msg_add_rtattr (&m, IFA_LOCAL, addr, 16);
vnet_netlink_msg_add_rtattr (&m, IFA_ADDRESS, addr, 16);
err = vnet_netlink_msg_send (&m, NULL);
if (err)
err = clib_error_return (0, "del ip6 addr %U", format_clib_error, err);
return err;
}
/*
* fd.io coding-style-patch-verification: ON
*
+2
View File
@@ -26,8 +26,10 @@ clib_error_t *vnet_netlink_get_link_mtu (int ifindex, u32 *mtu);
clib_error_t *vnet_netlink_set_link_mtu (int ifindex, int mtu);
clib_error_t *vnet_netlink_add_ip4_addr (int ifindex, void *addr,
int pfx_len);
clib_error_t *vnet_netlink_del_ip4_addr (int ifindex, void *addr, int pfx_len);
clib_error_t *vnet_netlink_add_ip6_addr (int ifindex, void *addr,
int pfx_len);
clib_error_t *vnet_netlink_del_ip6_addr (int ifindex, void *addr, int pfx_len);
clib_error_t *vnet_netlink_add_ip4_route (void *dst, u8 dst_len, void *gw);
clib_error_t *vnet_netlink_add_ip6_route (void *dst, u8 dst_len, void *gw);