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:
committed by
Matthew Smith
parent
0cef5f5d71
commit
1705a6baef
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user