aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorAkeel Ali <akeelapi@gmail.com>2025-01-09 12:01:13 -0500
committerMatthew Smith <mgsmith@netgate.com>2025-02-26 15:39:58 +0000
commit9543e29708524accce591eab3aa23270ab44ae1a (patch)
treef56465c95800058c98b210a5653db23b6c385fae /src/plugins
parent1cdebd8ca18bdf38af95047b1e9daf520e03030c (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.api36
-rw-r--r--src/plugins/linux-cp/lcp_api.c34
-rw-r--r--src/plugins/linux-cp/lcp_cli.c56
-rw-r--r--src/plugins/linux-cp/lcp_interface.c47
-rw-r--r--src/plugins/linux-cp/lcp_interface.h13
-rw-r--r--src/plugins/linux-cp/lcp_node.c116
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 (&ethertypes);
+ 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,
+ &ethertype))
+ 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 (&ethertypes);
+ 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 = &ethernet_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 = &ethernet_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;