From 1705a6baefe205bb6792b547c7376eee3f328a71 Mon Sep 17 00:00:00 2001 From: Pim van Pelt Date: Thu, 9 Sep 2021 17:53:09 +0000 Subject: 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 Change-Id: I34fc070e80af4013be58d7a8cbf64296cc760e4e Signed-off-by: Pim van Pelt --- src/plugins/linux-cp/lcp_interface.c | 262 ++++++++++++++--------------------- 1 file changed, 106 insertions(+), 156 deletions(-) (limited to 'src/plugins/linux-cp/lcp_interface.c') diff --git a/src/plugins/linux-cp/lcp_interface.c b/src/plugins/linux-cp/lcp_interface.c index d044635334f..3dbcb5987a1 100644 --- a/src/plugins/linux-cp/lcp_interface.c +++ b/src/plugins/linux-cp/lcp_interface.c @@ -39,7 +39,7 @@ #include #include -static vlib_log_class_t lcp_itf_pair_logger; +vlib_log_class_t lcp_itf_pair_logger; /** * Pool of LIP objects @@ -73,14 +73,6 @@ lcp_itf_pair_register_vft (lcp_itf_pair_vft_t *lcp_itf_vft) vec_add1 (lcp_itf_vfts, *lcp_itf_vft); } -#define LCP_ITF_PAIR_DBG(...) \ - vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__); - -#define LCP_ITF_PAIR_INFO(...) \ - vlib_log_notice (lcp_itf_pair_logger, __VA_ARGS__); - -#define LCP_ITF_PAIR_ERR(...) vlib_log_err (lcp_itf_pair_logger, __VA_ARGS__); - u8 * format_lcp_itf_pair (u8 *s, va_list *args) { @@ -139,6 +131,9 @@ lcp_itf_pair_show (u32 phy_sw_if_index) ns = lcp_get_default_ns (); vlib_cli_output (vm, "lcp default netns '%s'\n", ns ? (char *) ns : ""); + 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"); if (phy_sw_if_index == ~0) { @@ -157,6 +152,8 @@ lcp_itf_pair_get (u32 index) { if (!lcp_itf_pair_pool) return NULL; + if (index == INDEX_INVALID) + return NULL; return pool_elt_at_index (lcp_itf_pair_pool, index); } @@ -174,25 +171,6 @@ lcp_itf_pair_find_by_vif (u32 vif_index) return INDEX_INVALID; } -int -lcp_itf_pair_add_sub (u32 vif, u8 *host_if_name, u32 sub_sw_if_index, - u32 phy_sw_if_index, u8 *ns) -{ - lcp_itf_pair_t *lip; - - lip = lcp_itf_pair_get (lcp_itf_pair_find_by_phy (phy_sw_if_index)); - if (!lip) - { - LCP_ITF_PAIR_DBG ("lcp_itf_pair_add_sub: can't find LCP of parent %U", - format_vnet_sw_if_index_name, vnet_get_main (), - phy_sw_if_index); - return VNET_API_ERROR_INVALID_SW_IF_INDEX; - } - - return lcp_itf_pair_add (lip->lip_host_sw_if_index, sub_sw_if_index, - host_if_name, vif, lip->lip_host_type, ns); -} - const char *lcp_itf_l3_feat_names[N_LCP_ITF_HOST][N_AF] = { [LCP_ITF_HOST_TAP] = { [AF_IP4] = "linux-cp-xc-ip4", @@ -248,17 +226,23 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name, index_t lipi; lcp_itf_pair_t *lip; + if (host_sw_if_index == ~0) + { + LCP_ITF_PAIR_ERR ("pair_add: Cannot add LIP - invalid host"); + return VNET_API_ERROR_INVALID_SW_IF_INDEX; + } + lipi = lcp_itf_pair_find_by_phy (phy_sw_if_index); + if (lipi != INDEX_INVALID) + return VNET_API_ERROR_VALUE_EXIST; + LCP_ITF_PAIR_INFO ("add: host:%U phy:%U, host_if:%v vif:%d ns:%s", format_vnet_sw_if_index_name, vnet_get_main (), host_sw_if_index, format_vnet_sw_if_index_name, vnet_get_main (), phy_sw_if_index, host_name, host_index, ns); - if (lipi != INDEX_INVALID) - return VNET_API_ERROR_VALUE_EXIST; - /* * Create a new pair. */ @@ -279,9 +263,6 @@ lcp_itf_pair_add (u32 host_sw_if_index, u32 phy_sw_if_index, u8 *host_name, lip->lip_vif_index = host_index; lip->lip_namespace = vec_dup (ns); - if (lip->lip_host_sw_if_index == ~0) - return 0; - /* * First use of this host interface. * Enable the x-connect feature on the host to send @@ -421,10 +402,11 @@ lcp_itf_pair_del (u32 phy_sw_if_index) lip = lcp_itf_pair_get (lipi); - LCP_ITF_PAIR_INFO ("pair delete: {%U, %U, %v}", format_vnet_sw_if_index_name, - vnet_get_main (), lip->lip_phy_sw_if_index, - format_vnet_sw_if_index_name, vnet_get_main (), - lip->lip_host_sw_if_index, lip->lip_host_name); + LCP_ITF_PAIR_NOTICE ( + "pair_del: host:%U phy:%U host_if:%s vif:%d ns:%s", + format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_host_sw_if_index, + format_vnet_sw_if_index_name, vnet_get_main (), lip->lip_phy_sw_if_index, + lip->lip_host_name, lip->lip_vif_index, lip->lip_namespace); /* invoke registered callbacks for pair deletion */ vec_foreach (vft, lcp_itf_vfts) @@ -475,24 +457,45 @@ lcp_itf_pair_delete_by_index (index_t lipi) { u32 host_sw_if_index; lcp_itf_pair_t *lip; - u8 *host_name; + u8 *host_name, *ns; lip = lcp_itf_pair_get (lipi); host_name = vec_dup (lip->lip_host_name); host_sw_if_index = lip->lip_host_sw_if_index; + ns = vec_dup (lip->lip_namespace); lcp_itf_pair_del (lip->lip_phy_sw_if_index); if (vnet_sw_interface_is_sub (vnet_get_main (), host_sw_if_index)) { + int curr_ns_fd = -1; + int vif_ns_fd = -1; + if (ns) + { + curr_ns_fd = clib_netns_open (NULL /* self */); + vif_ns_fd = clib_netns_open ((u8 *) ns); + if (vif_ns_fd != -1) + clib_setns (vif_ns_fd); + } + lcp_netlink_del_link ((const char *) host_name); + if (vif_ns_fd != -1) + close (vif_ns_fd); + + if (curr_ns_fd != -1) + { + clib_setns (curr_ns_fd); + close (curr_ns_fd); + } + vnet_delete_sub_interface (host_sw_if_index); } else tap_delete_if (vlib_get_main (), host_sw_if_index); vec_free (host_name); + vec_free (ns); } int @@ -539,58 +542,16 @@ lcp_itf_pair_walk (lcp_itf_pair_walk_cb_t cb, void *ctx) }; } -typedef struct lcp_itf_pair_names_t_ -{ - u8 *lipn_host_name; - u8 *lipn_phy_name; - u8 *lipn_namespace; - u32 lipn_phy_sw_if_index; -} lcp_itf_pair_names_t; - -static lcp_itf_pair_names_t *lipn_names; - static clib_error_t * lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input) { - u8 *host, *phy; - u8 *ns; u8 *default_ns; - host = phy = ns = default_ns = NULL; + default_ns = NULL; while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT) { - vec_reset_length (host); - - if (unformat (input, "pair %s %s %s", &phy, &host, &ns)) - { - lcp_itf_pair_names_t *lipn; - - if (vec_len (ns) > LCP_NS_LEN) - { - return clib_error_return (0, - "linux-cp namespace must" - " be less than %d characters", - LCP_NS_LEN); - } - - vec_add2 (lipn_names, lipn, 1); - - lipn->lipn_host_name = vec_dup (host); - lipn->lipn_phy_name = vec_dup (phy); - lipn->lipn_namespace = vec_dup (ns); - } - else if (unformat (input, "pair %v %v", &phy, &host)) - { - lcp_itf_pair_names_t *lipn; - - vec_add2 (lipn_names, lipn, 1); - - lipn->lipn_host_name = vec_dup (host); - lipn->lipn_phy_name = vec_dup (phy); - lipn->lipn_namespace = 0; - } - else if (unformat (input, "default netns %v", &default_ns)) + if (unformat (input, "default netns %v", &default_ns)) { vec_add1 (default_ns, 0); if (lcp_set_default_ns (default_ns) < 0) @@ -601,14 +562,14 @@ lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input) LCP_NS_LEN); } } - else if (unformat (input, "interface-auto-create")) - lcp_set_auto_intf (1 /* is_auto */); + else if (unformat (input, "lcp-auto-subint")) + lcp_set_auto_subint (1 /* is_auto */); + else if (unformat (input, "lcp-sync")) + lcp_set_sync (1 /* is_auto */); else return clib_error_return (0, "interfaces not found"); } - vec_free (host); - vec_free (phy); vec_free (default_ns); return NULL; @@ -653,7 +614,7 @@ lcp_validate_if_name (u8 *name) return 1; } -static void +void lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state) { int curr_ns_fd, vif_ns_fd; @@ -671,6 +632,8 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state) clib_setns (vif_ns_fd); } + /* Set the same link state on the netlink interface + */ vnet_netlink_set_link_state (lip->lip_vif_index, state); if (vif_ns_fd != -1) @@ -685,6 +648,58 @@ lcp_itf_set_link_state (const lcp_itf_pair_t *lip, u8 state) return; } +void +lcp_itf_set_interface_addr (const lcp_itf_pair_t *lip) +{ + ip4_main_t *im4 = &ip4_main; + ip6_main_t *im6 = &ip6_main; + ip_lookup_main_t *lm4 = &im4->lookup_main; + ip_lookup_main_t *lm6 = &im6->lookup_main; + ip_interface_address_t *ia = 0; + int vif_ns_fd = -1; + int curr_ns_fd = -1; + + if (!lip) + return; + + if (lip->lip_namespace) + { + curr_ns_fd = clib_netns_open (NULL /* self */); + vif_ns_fd = clib_netns_open (lip->lip_namespace); + if (vif_ns_fd != -1) + clib_setns (vif_ns_fd); + } + + /* Sync any IP4 addressing info into LCP */ + foreach_ip_interface_address ( + lm4, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({ + ip4_address_t *r4 = ip_interface_address_get_address (lm4, ia); + LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip4 %U/%d", + format_lcp_itf_pair, lip, format_ip4_address, r4, + ia->address_length); + vnet_netlink_add_ip4_addr (lip->lip_vif_index, r4, ia->address_length); + })); + + /* Sync any IP6 addressing info into LCP */ + foreach_ip_interface_address ( + lm6, ia, lip->lip_phy_sw_if_index, 1 /* honor unnumbered */, ({ + ip6_address_t *r6 = ip_interface_address_get_address (lm6, ia); + LCP_ITF_PAIR_NOTICE ("set_interface_addr: %U add ip6 %U/%d", + format_lcp_itf_pair, lip, format_ip6_address, r6, + ia->address_length); + vnet_netlink_add_ip6_addr (lip->lip_vif_index, r6, ia->address_length); + })); + + if (vif_ns_fd != -1) + close (vif_ns_fd); + + if (curr_ns_fd != -1) + { + clib_setns (curr_ns_fd); + close (curr_ns_fd); + } +} + typedef struct { u32 vlan; @@ -792,9 +807,8 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, u16 vlan, proto; u32 parent_vif_index; - // TODO(pim) replace with vnet_sw_interface_supports_addressing() - if (sw->type == VNET_SW_INTERFACE_TYPE_SUB && - sw->sub.eth.flags.exact_match == 0) + err = vnet_sw_interface_supports_addressing (vnm, phy_sw_if_index); + if (err) { LCP_ITF_PAIR_ERR ("pair_create: can't create LCP for a " "sub-interface without exact-match set"); @@ -921,7 +935,7 @@ lcp_itf_pair_create (u32 phy_sw_if_index, u8 *host_if_name, outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm, lip->lip_host_sw_if_index); err = clib_error_return ( - 0, "failed to create tap subinti: %d.%d. on %U", outer_vlan, + 0, "failed to create tap subint: %d.%d. on %U", outer_vlan, inner_vlan, format_vnet_sw_if_index_name, vnm, lip->lip_host_sw_if_index); } @@ -1107,70 +1121,6 @@ lcp_itf_pair_replace_end (void) return (0); } -static uword -lcp_itf_pair_process (vlib_main_t *vm, vlib_node_runtime_t *rt, - vlib_frame_t *f) -{ - uword *event_data = 0; - uword *lipn_index; - - while (1) - { - vlib_process_wait_for_event (vm); - - vlib_process_get_events (vm, &event_data); - - vec_foreach (lipn_index, event_data) - { - lcp_itf_pair_names_t *lipn; - - lipn = &lipn_names[*lipn_index]; - lcp_itf_pair_create (lipn->lipn_phy_sw_if_index, - lipn->lipn_host_name, LCP_ITF_HOST_TAP, - lipn->lipn_namespace, NULL); - } - - vec_reset_length (event_data); - } - - return 0; -} - -VLIB_REGISTER_NODE (lcp_itf_pair_process_node, static) = { - .function = lcp_itf_pair_process, - .name = "linux-cp-itf-process", - .type = VLIB_NODE_TYPE_PROCESS, -}; - -static clib_error_t * -lcp_itf_phy_add (vnet_main_t *vnm, u32 sw_if_index, u32 is_create) -{ - lcp_itf_pair_names_t *lipn; - vlib_main_t *vm = vlib_get_main (); - vnet_hw_interface_t *hw; - - if (!is_create || vnet_sw_interface_is_sub (vnm, sw_if_index)) - return NULL; - - hw = vnet_get_sup_hw_interface (vnm, sw_if_index); - - vec_foreach (lipn, lipn_names) - { - if (!vec_cmp (hw->name, lipn->lipn_phy_name)) - { - lipn->lipn_phy_sw_if_index = sw_if_index; - - vlib_process_signal_event (vm, lcp_itf_pair_process_node.index, 0, - lipn - lipn_names); - break; - } - } - - return NULL; -} - -VNET_SW_INTERFACE_ADD_DEL_FUNCTION (lcp_itf_phy_add); - static clib_error_t * lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags) { -- cgit 1.2.3-korg