diff options
author | 2025-01-09 12:01:13 -0500 | |
---|---|---|
committer | 2025-02-26 15:39:58 +0000 | |
commit | 9543e29708524accce591eab3aa23270ab44ae1a (patch) | |
tree | f56465c95800058c98b210a5653db23b6c385fae /src/plugins | |
parent | 1cdebd8ca18bdf38af95047b1e9daf520e03030c (diff) |
linux-cp: Add support for LACP packets
This patch adds support to mirror LACP packets between host and phy.
It is needed for the Sonic-VPP project to support LAG and allow Sonic
to run LACP in the control plane.
The change has 3 parts:
(1) Converted lip_punt_node to lip_punt_xc_inline, which now supports
the creation of two distinct nodes: lip_punt_node and lip_punt_xc_node.
lip_punt_node retains its original punt functionality.
lip_punt_xc_node supports both punt and x-connect between host & phy.
(2) Add 2 new API (and corresponding CLI) to the linux-cp plugin:
(A) lcp_ethertype_enable ("lcp ethertype enable <ethertype>")
(B) lcp_ethertype_get ("show lcp ethertype")
(3) Add UT to test the new functionality and API/CLI for LACP and LLDP.
Type: improvement
Change-Id: Iab66e3b29351dcf2c471babd4f1ef4bdd19da46e
Signed-off-by: Akeel Ali <akeelapi@gmail.com>
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/linux-cp/lcp.api | 36 | ||||
-rw-r--r-- | src/plugins/linux-cp/lcp_api.c | 34 | ||||
-rw-r--r-- | src/plugins/linux-cp/lcp_cli.c | 56 | ||||
-rw-r--r-- | src/plugins/linux-cp/lcp_interface.c | 47 | ||||
-rw-r--r-- | src/plugins/linux-cp/lcp_interface.h | 13 | ||||
-rw-r--r-- | src/plugins/linux-cp/lcp_node.c | 116 |
6 files changed, 276 insertions, 26 deletions
diff --git a/src/plugins/linux-cp/lcp.api b/src/plugins/linux-cp/lcp.api index e7eaa5a3669..8b0fdb5eb53 100644 --- a/src/plugins/linux-cp/lcp.api +++ b/src/plugins/linux-cp/lcp.api @@ -177,6 +177,42 @@ autoendian define lcp_itf_pair_details option in_progress; }; +/** \brief Enable linux-cp-punt-xc for a given ethertype + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request + @param ethertype - the ethertype to enable +*/ +autoreply define lcp_ethertype_enable +{ + u32 client_index; + u32 context; + u16 ethertype; +}; + +/** \brief Get the enabled ethertypes for linux-cp-punt-xc + @param client_index - opaque cookie to identify the sender + @param context - sender context, to match reply w/ request +*/ +define lcp_ethertype_get +{ + u32 client_index; + u32 context; +}; + +/** \brief Reply to get the enabled ethertypes for linux-cp-punt-xc + @param context - sender context, to match reply w/ request + @param retval - return code for the request + @param count - number of enabled ethertypes + @param ethertypes - array of enabled ethertypes +*/ +define lcp_ethertype_get_reply +{ + u32 context; + i32 retval; + u16 count; + u16 ethertypes[count]; +}; + service { rpc lcp_itf_pair_get returns lcp_itf_pair_get_reply stream lcp_itf_pair_details; diff --git a/src/plugins/linux-cp/lcp_api.c b/src/plugins/linux-cp/lcp_api.c index 74421230e9d..0db502988d7 100644 --- a/src/plugins/linux-cp/lcp_api.c +++ b/src/plugins/linux-cp/lcp_api.c @@ -280,6 +280,40 @@ vl_api_lcp_itf_pair_replace_end_t_handler ( REPLY_MACRO (VL_API_LCP_ITF_PAIR_REPLACE_END_REPLY); } +static void +vl_api_lcp_ethertype_enable_t_handler (vl_api_lcp_ethertype_enable_t *mp) +{ + vl_api_lcp_ethertype_enable_reply_t *rmp; + int rv; + + rv = lcp_ethertype_enable (mp->ethertype); + + REPLY_MACRO (VL_API_LCP_ETHERTYPE_ENABLE_REPLY); +} + +static void +vl_api_lcp_ethertype_get_t_handler (vl_api_lcp_ethertype_get_t *mp) +{ + vl_api_lcp_ethertype_get_reply_t *rmp; + ethernet_type_t *ethertypes = vec_new (ethernet_type_t, 0); + u16 count = 0; + int rv = 0; + + rv = lcp_ethertype_get_enabled (ðertypes); + if (!rv) + count = vec_len (ethertypes); + + REPLY_MACRO3 (VL_API_LCP_ETHERTYPE_GET_REPLY, sizeof (u16) * count, ({ + rmp->count = htons (count); + for (int i = 0; i < count; i++) + { + rmp->ethertypes[i] = htons (ethertypes[i]); + } + })); + + vec_free (ethertypes); +} + /* * Set up the API message handling tables */ diff --git a/src/plugins/linux-cp/lcp_cli.c b/src/plugins/linux-cp/lcp_cli.c index 0dcf600b301..e89afd2a753 100644 --- a/src/plugins/linux-cp/lcp_cli.c +++ b/src/plugins/linux-cp/lcp_cli.c @@ -337,6 +337,62 @@ VLIB_CLI_COMMAND (lcp_itf_pair_show_cmd_node, static) = { .is_mp_safe = 1, }; +static clib_error_t * +lcp_ethertype_enable_cmd (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + ethernet_type_t ethertype; + int rv; + + if (!unformat (input, "%U", unformat_ethernet_type_host_byte_order, + ðertype)) + return clib_error_return (0, "Invalid ethertype"); + + rv = lcp_ethertype_enable (ethertype); + if (rv) + return clib_error_return (0, "Failed to enable ethertype (%d)", rv); + + return 0; +} + +VLIB_CLI_COMMAND (lcp_ethertype_enable_command, static) = { + .path = "lcp ethertype enable", + .short_help = + "lcp ethertype enable (<hex_ethertype_num>|<uc_ethertype_name>)", + .function = lcp_ethertype_enable_cmd, +}; + +static clib_error_t * +lcp_ethertype_show_cmd (vlib_main_t *vm, unformat_input_t *input, + vlib_cli_command_t *cmd) +{ + ethernet_type_t *ethertypes = vec_new (ethernet_type_t, 0); + ethernet_type_t *etype; + int rv; + + rv = lcp_ethertype_get_enabled (ðertypes); + if (rv) + { + vec_free (ethertypes); + return clib_error_return (0, "Failed to get enabled ethertypes (%d)", + rv); + } + + vec_foreach (etype, ethertypes) + { + vlib_cli_output (vm, "0x%04x", *etype); + } + + vec_free (ethertypes); + return 0; +} + +VLIB_CLI_COMMAND (lcp_ethertype_show_command, static) = { + .path = "show lcp ethertype", + .short_help = "show lcp ethertype", + .function = lcp_ethertype_show_cmd, +}; + clib_error_t * lcp_cli_init (vlib_main_t *vm) { diff --git a/src/plugins/linux-cp/lcp_interface.c b/src/plugins/linux-cp/lcp_interface.c index 9a6b9b11be5..31864f791af 100644 --- a/src/plugins/linux-cp/lcp_interface.c +++ b/src/plugins/linux-cp/lcp_interface.c @@ -1230,6 +1230,53 @@ lcp_itf_pair_link_up_down (vnet_main_t *vnm, u32 hw_if_index, u32 flags) return 0; } +int +lcp_ethertype_enable (ethernet_type_t ethertype) +{ + ethernet_main_t *em = ðernet_main; + ethernet_type_info_t *eti; + vlib_main_t *vm = vlib_get_main (); + vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "linux-cp-punt-xc"); + + if (!node) + return VNET_API_ERROR_UNIMPLEMENTED; + + eti = ethernet_get_type_info (em, ethertype); + if (!eti) + return VNET_API_ERROR_INVALID_VALUE; + + if (eti->node_index != ~0 && eti->node_index != node->index) + return VNET_API_ERROR_INVALID_REGISTRATION; + + ethernet_register_input_type (vm, ethertype, node->index); + return 0; +} + +int +lcp_ethertype_get_enabled (ethernet_type_t **ethertypes_vec) +{ + ethernet_main_t *em = ðernet_main; + ethernet_type_info_t *eti; + vlib_main_t *vm = vlib_get_main (); + vlib_node_t *node = vlib_get_node_by_name (vm, (u8 *) "linux-cp-punt-xc"); + + if (!ethertypes_vec) + return VNET_API_ERROR_INVALID_ARGUMENT; + + if (!node) + return VNET_API_ERROR_UNIMPLEMENTED; + + vec_foreach (eti, em->type_infos) + { + if (eti->node_index == node->index) + { + vec_add1 (*ethertypes_vec, eti->type); + } + } + + return 0; +} + VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (lcp_itf_pair_link_up_down); static clib_error_t * diff --git a/src/plugins/linux-cp/lcp_interface.h b/src/plugins/linux-cp/lcp_interface.h index cfcd3925a15..8cf6d3f4da1 100644 --- a/src/plugins/linux-cp/lcp_interface.h +++ b/src/plugins/linux-cp/lcp_interface.h @@ -18,6 +18,7 @@ #include <vnet/dpo/dpo.h> #include <vnet/adj/adj.h> #include <vnet/ip/ip_types.h> +#include <vnet/ethernet/ethernet.h> #include <plugins/linux-cp/lcp.h> @@ -198,6 +199,18 @@ 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 (); +/** + * Enable linux-cp-punt-xc for a given ethertype. + * @param ethertype - ethertype to enable + */ +int lcp_ethertype_enable (ethernet_type_t ethertype); + +/** + * Get the list of ethertypes enabled for linux-cp-punt-xc. + * @param ethertypes_vec - pointer to a vector to store the list of ethertypes + */ +int lcp_ethertype_get_enabled (ethernet_type_t **ethertypes_vec); + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/plugins/linux-cp/lcp_node.c b/src/plugins/linux-cp/lcp_node.c index 241cc5e4bff..9fa1aa5bd66 100644 --- a/src/plugins/linux-cp/lcp_node.c +++ b/src/plugins/linux-cp/lcp_node.c @@ -39,40 +39,51 @@ typedef enum { -#define _(sym, str) LIP_PUNT_NEXT_##sym, +#define _(sym, str) LIP_PUNT_XC_NEXT_##sym, foreach_lip_punt #undef _ - LIP_PUNT_N_NEXT, -} lip_punt_next_t; + LIP_PUNT_XC_N_NEXT, +} lip_punt_xc_next_t; -typedef struct lip_punt_trace_t_ +typedef struct lip_punt_xc_trace_t_ { + bool is_xc; u32 phy_sw_if_index; u32 host_sw_if_index; -} lip_punt_trace_t; +} lip_punt_xc_trace_t; /* packet trace format function */ static u8 * -format_lip_punt_trace (u8 *s, va_list *args) +format_lip_punt_xc_trace (u8 *s, va_list *args) { CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - lip_punt_trace_t *t = va_arg (*args, lip_punt_trace_t *); + lip_punt_xc_trace_t *t = va_arg (*args, lip_punt_xc_trace_t *); - s = - format (s, "lip-punt: %u -> %u", t->phy_sw_if_index, t->host_sw_if_index); + if (t->is_xc) + { + s = format (s, "lip-xc: %u -> %u", t->host_sw_if_index, + t->phy_sw_if_index); + } + else + { + s = format (s, "lip-punt: %u -> %u", t->phy_sw_if_index, + t->host_sw_if_index); + } return s; } /** * Pass punted packets from the PHY to the HOST. + * Conditionally x-connect packets from the HOST to the PHY. */ -VLIB_NODE_FN (lip_punt_node) -(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +static_always_inline u32 +lip_punt_xc_inline (vlib_main_t *vm, vlib_node_runtime_t *node, + vlib_frame_t *frame, bool check_xc) { u32 n_left_from, *from, *to_next, n_left_to_next; - lip_punt_next_t next_index; + lip_punt_xc_next_t next_index; next_index = node->cached_next_index; n_left_from = frame->n_vectors; @@ -89,6 +100,7 @@ VLIB_NODE_FN (lip_punt_node) u32 next0 = ~0; u32 bi0, lipi0; u32 sw_if_index0; + bool is_xc0 = 0; u8 len0; bi0 = to_next[0] = from[0]; @@ -97,18 +109,33 @@ VLIB_NODE_FN (lip_punt_node) to_next += 1; n_left_from -= 1; n_left_to_next -= 1; - next0 = LIP_PUNT_NEXT_DROP; + next0 = LIP_PUNT_XC_NEXT_DROP; b0 = vlib_get_buffer (vm, bi0); sw_if_index0 = vnet_buffer (b0)->sw_if_index[VLIB_RX]; lipi0 = lcp_itf_pair_find_by_phy (sw_if_index0); - if (PREDICT_FALSE (lipi0 == INDEX_INVALID)) - goto trace0; + + /* + * lip_punt_node: expect sw_if_index0 is phy in an itf pair + * lip_punt_xc_node: if sw_if_index0 is not phy, expect it is host + */ + if (!check_xc && (PREDICT_FALSE (lipi0 == INDEX_INVALID))) + { + goto trace0; + } + else if (check_xc && (lipi0 == INDEX_INVALID)) + { + is_xc0 = 1; + lipi0 = lcp_itf_pair_find_by_host (sw_if_index0); + if (PREDICT_FALSE (lipi0 == INDEX_INVALID)) + goto trace0; + } lip0 = lcp_itf_pair_get (lipi0); - next0 = LIP_PUNT_NEXT_IO; - vnet_buffer (b0)->sw_if_index[VLIB_TX] = lip0->lip_host_sw_if_index; + next0 = LIP_PUNT_XC_NEXT_IO; + vnet_buffer (b0)->sw_if_index[VLIB_TX] = + is_xc0 ? lip0->lip_phy_sw_if_index : lip0->lip_host_sw_if_index; if (PREDICT_TRUE (lip0->lip_host_type == LCP_ITF_HOST_TAP)) { @@ -129,10 +156,22 @@ VLIB_NODE_FN (lip_punt_node) trace0: if (PREDICT_FALSE ((b0->flags & VLIB_BUFFER_IS_TRACED))) { - lip_punt_trace_t *t = vlib_add_trace (vm, node, b0, sizeof (*t)); - t->phy_sw_if_index = sw_if_index0; - t->host_sw_if_index = - (lipi0 == INDEX_INVALID) ? ~0 : lip0->lip_host_sw_if_index; + lip_punt_xc_trace_t *t = + vlib_add_trace (vm, node, b0, sizeof (*t)); + + t->is_xc = is_xc0; + if (is_xc0) + { + t->phy_sw_if_index = + (lipi0 == INDEX_INVALID) ? ~0 : lip0->lip_phy_sw_if_index; + t->host_sw_if_index = sw_if_index0; + } + else + { + t->phy_sw_if_index = sw_if_index0; + t->host_sw_if_index = + (lipi0 == INDEX_INVALID) ? ~0 : lip0->lip_host_sw_if_index; + } } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next, @@ -145,16 +184,41 @@ VLIB_NODE_FN (lip_punt_node) return frame->n_vectors; } +VLIB_NODE_FN (lip_punt_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return (lip_punt_xc_inline (vm, node, frame, false /* xc */)); +} + +VLIB_NODE_FN (lip_punt_xc_node) +(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) +{ + return (lip_punt_xc_inline (vm, node, frame, true /* xc */)); +} + VLIB_REGISTER_NODE (lip_punt_node) = { .name = "linux-cp-punt", .vector_size = sizeof (u32), - .format_trace = format_lip_punt_trace, + .format_trace = format_lip_punt_xc_trace, + .type = VLIB_NODE_TYPE_INTERNAL, + + .n_next_nodes = LIP_PUNT_XC_N_NEXT, + .next_nodes = { + [LIP_PUNT_XC_NEXT_DROP] = "error-drop", + [LIP_PUNT_XC_NEXT_IO] = "interface-output", + }, +}; + +VLIB_REGISTER_NODE (lip_punt_xc_node) = { + .name = "linux-cp-punt-xc", + .vector_size = sizeof (u32), + .format_trace = format_lip_punt_xc_trace, .type = VLIB_NODE_TYPE_INTERNAL, - .n_next_nodes = LIP_PUNT_N_NEXT, + .n_next_nodes = LIP_PUNT_XC_N_NEXT, .next_nodes = { - [LIP_PUNT_NEXT_DROP] = "error-drop", - [LIP_PUNT_NEXT_IO] = "interface-output", + [LIP_PUNT_XC_NEXT_DROP] = "error-drop", + [LIP_PUNT_XC_NEXT_IO] = "interface-output", }, }; @@ -190,7 +254,7 @@ VLIB_NODE_FN (lcp_punt_l3_node) (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame) { u32 n_left_from, *from, *to_next, n_left_to_next; - lip_punt_next_t next_index; + lip_punt_xc_next_t next_index; next_index = node->cached_next_index; n_left_from = frame->n_vectors; |