dpdk-testpmd: call get/set link settings interface

Message ID 20240403225333.16260-1-mpazdan@arista.com (mailing list archive)
State New
Delegated to: Ferruh Yigit
Headers
Series dpdk-testpmd: call get/set link settings interface |

Checks

Context Check Description
ci/checkpatch warning coding style issues
ci/loongarch-compilation fail ninja build failure
ci/iol-testing fail build patch failure
ci/Intel-compilation fail Compilation issues

Commit Message

Marek Pazdan April 3, 2024, 10:53 p.m. UTC
  Add cmdline options for utilizing get/set link settings API
added before in patch this patch depends on. Purpose of this
change is to provide mechanism for testing link settings interface
API.

Signed-off-by: Marek Pazdan <mpazdan@arista.com>
---
Depends-on: patch-139082 ("lib: add get/set link settings interface")
---
 app/test-pmd/cmdline.c          |   9 +
 app/test-pmd/cmdline_settings.c | 516 ++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_settings.h |  14 +
 app/test-pmd/meson.build        |   1 +
 app/test-pmd/testpmd.h          |   1 +
 app/test-pmd/util.c             |  10 +
 6 files changed, 551 insertions(+)
 create mode 100644 app/test-pmd/cmdline_settings.c
 create mode 100644 app/test-pmd/cmdline_settings.h
  

Comments

Ferruh Yigit April 4, 2024, 9:14 a.m. UTC | #1
On 4/3/2024 11:53 PM, Marek Pazdan wrote:
> Add cmdline options for utilizing get/set link settings API
> added before in patch this patch depends on. Purpose of this
> change is to provide mechanism for testing link settings interface
> API.
> 
> Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> ---
> Depends-on: patch-139082 ("lib: add get/set link settings interface")
> 

Hi Marek,

This patch is based on your previous patch that adds
'rte_eth_dev_get_link_settings()', but it is unlikely that dependent
patch will be accepted because it is duplication of existing APIs in DPDK.
Please follow discussions in that thread.
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b7759e38a8..7fdd134467 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -65,6 +65,7 @@ 
 #include "cmdline_cman.h"
 #include "cmdline_mtr.h"
 #include "cmdline_tm.h"
+#include "cmdline_settings.h"
 #include "bpf_cmd.h"
 
 static struct cmdline *testpmd_cl;
@@ -255,6 +256,9 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) flow_ctrl"
 			"	Show flow control info of a port.\n\n"
 
+			"show port (port_id) link settings"
+			"	Show link settings of a port.\n\n"
+
 			"dump_physmem\n"
 			"    Dumps all physical memory segment layouts\n\n"
 
@@ -661,6 +665,9 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"(max_thresh) (prob_inv)]\n"
 			"    Set congestion management configuration\n\n"
 
+			"set port (port_id) link settings advertising (bitmap_str)"
+			"	Set link advertising settings of a port.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -13219,6 +13226,8 @@  static cmdline_parse_ctx_t builtin_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_show,
+	(cmdline_parse_inst_t *)&cmd_link_settings_show,
+	(cmdline_parse_inst_t *)&cmd_link_settings_set_advertising,
 	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
 	(cmdline_parse_inst_t *)&cmd_queue_priority_flow_control_set,
 	(cmdline_parse_inst_t *)&cmd_config_dcb,
diff --git a/app/test-pmd/cmdline_settings.c b/app/test-pmd/cmdline_settings.c
new file mode 100644
index 0000000000..4db6bd4e9a
--- /dev/null
+++ b/app/test-pmd/cmdline_settings.c
@@ -0,0 +1,516 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Arista Networks, Inc.  All rights reserved.
+ * Arista Networks, Inc. Confidential and Proprietary
+ */
+
+#include <stdio.h>
+#include <rte_ethdev.h>
+
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_num.h>
+
+#include "testpmd.h"
+
+/* *** GET CURRENT ETHERNET LINK SETTINGS *** */
+struct cmd_link_settings_show {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t link;
+	cmdline_fixed_string_t settings;
+};
+
+cmdline_parse_token_string_t cmd_ls_show_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				show, "show");
+cmdline_parse_token_string_t cmd_ls_show_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				port, "port");
+cmdline_parse_token_num_t cmd_ls_show_portid =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_settings_show,
+				port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_ls_show_link =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				link, "link");
+cmdline_parse_token_string_t cmd_ls_show_settings =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				settings, "settings");
+
+/* Print link capability flags (supported, advertised or lp_advertised).
+ * Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
+ */
+static void dump_link_caps(const char *prefix, const char *an_prefix,
+		const uint32_t *mask, int link_mode_only)
+{
+	static const struct {
+		int same_line; /* print on same line as previous */
+		unsigned int bit_index;
+		const char *name;
+	} mode_defs[] = {
+		{ 0, RTE_LINK_MODE_10baseT_Half_BIT,
+		  "10baseT/Half" },
+		{ 1, RTE_LINK_MODE_10baseT_Full_BIT,
+		  "10baseT/Full" },
+		{ 0, RTE_LINK_MODE_100baseT_Half_BIT,
+		  "100baseT/Half" },
+		{ 1, RTE_LINK_MODE_100baseT_Full_BIT,
+		  "100baseT/Full" },
+		{ 0, RTE_LINK_MODE_100baseT1_Full_BIT,
+		  "100baseT1/Full" },
+		{ 0, RTE_LINK_MODE_1000baseT_Half_BIT,
+		  "1000baseT/Half" },
+		{ 1, RTE_LINK_MODE_1000baseT_Full_BIT,
+		  "1000baseT/Full" },
+		{ 0, RTE_LINK_MODE_1000baseT1_Full_BIT,
+		  "1000baseT1/Full" },
+		{ 0, RTE_LINK_MODE_1000baseKX_Full_BIT,
+		  "1000baseKX/Full" },
+		{ 0, RTE_LINK_MODE_2500baseX_Full_BIT,
+		  "2500baseX/Full" },
+		{ 0, RTE_LINK_MODE_10000baseT_Full_BIT,
+		  "10000baseT/Full" },
+		{ 0, RTE_LINK_MODE_10000baseKX4_Full_BIT,
+		  "10000baseKX4/Full" },
+		{ 0, RTE_LINK_MODE_10000baseKR_Full_BIT,
+		  "10000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseR_FEC_BIT,
+		  "10000baseR_FEC" },
+		{ 0, RTE_LINK_MODE_20000baseMLD2_Full_BIT,
+		  "20000baseMLD2/Full" },
+		{ 0, RTE_LINK_MODE_20000baseKR2_Full_BIT,
+		  "20000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_40000baseKR4_Full_BIT,
+		  "40000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseCR4_Full_BIT,
+		  "40000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseSR4_Full_BIT,
+		  "40000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseLR4_Full_BIT,
+		  "40000baseLR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseKR4_Full_BIT,
+		  "56000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseCR4_Full_BIT,
+		  "56000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseSR4_Full_BIT,
+		  "56000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseLR4_Full_BIT,
+		  "56000baseLR4/Full" },
+		{ 0, RTE_LINK_MODE_25000baseCR_Full_BIT,
+		  "25000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_25000baseKR_Full_BIT,
+		  "25000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_25000baseSR_Full_BIT,
+		  "25000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseCR2_Full_BIT,
+		  "50000baseCR2/Full" },
+		{ 0, RTE_LINK_MODE_50000baseKR2_Full_BIT,
+		  "50000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseKR4_Full_BIT,
+		  "100000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseSR4_Full_BIT,
+		  "100000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseCR4_Full_BIT,
+		  "100000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+		  "100000baseLR4_ER4/Full" },
+		{ 0, RTE_LINK_MODE_50000baseSR2_Full_BIT,
+		  "50000baseSR2/Full" },
+		{ 0, RTE_LINK_MODE_1000baseX_Full_BIT,
+		  "1000baseX/Full" },
+		{ 0, RTE_LINK_MODE_10000baseCR_Full_BIT,
+		  "10000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseSR_Full_BIT,
+		  "10000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseLR_Full_BIT,
+		  "10000baseLR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseLRM_Full_BIT,
+		  "10000baseLRM/Full" },
+		{ 0, RTE_LINK_MODE_10000baseER_Full_BIT,
+		  "10000baseER/Full" },
+		{ 0, RTE_LINK_MODE_2500baseT_Full_BIT,
+		  "2500baseT/Full" },
+		{ 0, RTE_LINK_MODE_5000baseT_Full_BIT,
+		  "5000baseT/Full" },
+		{ 0, RTE_LINK_MODE_50000baseKR_Full_BIT,
+		  "50000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseSR_Full_BIT,
+		  "50000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseCR_Full_BIT,
+		  "50000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+		  "50000baseLR_ER_FR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseDR_Full_BIT,
+		  "50000baseDR/Full" },
+		{ 0, RTE_LINK_MODE_100000baseKR2_Full_BIT,
+		  "100000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseSR2_Full_BIT,
+		  "100000baseSR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseCR2_Full_BIT,
+		  "100000baseCR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+		  "100000baseLR2_ER2_FR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseDR2_Full_BIT,
+		  "100000baseDR2/Full" },
+		{ 0, RTE_LINK_MODE_200000baseKR4_Full_BIT,
+		  "200000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseSR4_Full_BIT,
+		  "200000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
+		  "200000baseLR4_ER4_FR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseDR4_Full_BIT,
+		  "200000baseDR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseCR4_Full_BIT,
+		  "200000baseCR4/Full" },
+	};
+	int indent;
+	int did1;
+	int new_line_pend;
+	int fecreported = 0;
+
+	/* Indent just like the separate functions used to */
+	indent = strlen(prefix) + 14;
+	if (indent < 24)
+		indent = 24;
+
+	fprintf(stdout, "       %s link modes:%*s", prefix,
+		indent - (int)strlen(prefix) - 12, "");
+	did1 = 0;
+	new_line_pend = 0;
+	for (uint32_t i = 0; i < RTE_DIM(mode_defs); i++) {
+		if (did1 && !mode_defs[i].same_line)
+			new_line_pend = 1;
+		if (get_bit(mask, mode_defs[i].bit_index)) {
+			if (new_line_pend) {
+				fprintf(stdout, "\n");
+				fprintf(stdout, "       %*s", indent, "");
+				new_line_pend = 0;
+			}
+			did1++;
+			fprintf(stdout, "%s ", mode_defs[i].name);
+		}
+	}
+	if (did1 == 0)
+		fprintf(stdout, "Not reported");
+	fprintf(stdout, "\n");
+
+	if (!link_mode_only) {
+		fprintf(stdout, "       %s pause frame use: ", prefix);
+		if (get_bit(mask, RTE_LINK_MODE_Pause_BIT)) {
+			fprintf(stdout, "Symmetric");
+			if (get_bit(mask, RTE_LINK_MODE_Asym_Pause_BIT))
+				fprintf(stdout, " Receive-only");
+			fprintf(stdout, "\n");
+		} else {
+			if (get_bit(mask, RTE_LINK_MODE_Asym_Pause_BIT))
+				fprintf(stdout, "Transmit-only\n");
+			else
+				fprintf(stdout, "No\n");
+		}
+
+		fprintf(stdout, "       %s auto-negotiation: ", an_prefix);
+		if (get_bit(mask, RTE_LINK_MODE_Autoneg_BIT))
+			fprintf(stdout, "Yes\n");
+		else
+			fprintf(stdout, "No\n");
+
+		fprintf(stdout, "       %s FEC modes:", prefix);
+		if (get_bit(mask, RTE_LINK_MODE_FEC_NONE_BIT)) {
+			fprintf(stdout, " None");
+			fecreported = 1;
+		}
+		if (get_bit(mask, RTE_LINK_MODE_FEC_BASER_BIT)) {
+			fprintf(stdout, " BaseR");
+			fecreported = 1;
+		}
+		if (get_bit(mask, RTE_LINK_MODE_FEC_RS_BIT)) {
+			fprintf(stdout, " RS");
+			fecreported = 1;
+		}
+		if (!fecreported)
+			fprintf(stdout, " Not reported");
+		fprintf(stdout, "\n");
+	}
+}
+
+static void
+dump_supported(const struct rte_link_settings *link_settings)
+{
+	fprintf(stdout, "       Supported ports: [ ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_TP_BIT))
+		fprintf(stdout, "TP ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_AUI_BIT))
+		fprintf(stdout, "AUI ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_BNC_BIT))
+		fprintf(stdout, "BNC ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_MII_BIT))
+		fprintf(stdout, "MII ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_FIBRE_BIT))
+		fprintf(stdout, "FIBRE ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_Backplane_BIT))
+		fprintf(stdout, "Backplane ");
+	fprintf(stdout, "]\n");
+
+	dump_link_caps("Supported", "Supports",
+		       link_settings->link_modes.supported, 0);
+}
+
+
+
+static void
+cmd_link_settings_show_parsed(void *parsed_result,
+			      __rte_unused struct cmdline *cl,
+			      __rte_unused void *data)
+{
+	struct cmd_link_settings_show *res = parsed_result;
+	static const char *info_border = "*********************";
+	struct rte_link_settings link_settings;
+	int ret;
+
+	memset(&link_settings, 0x00, sizeof(link_settings));
+	ret = rte_eth_dev_get_link_settings(res->port_id, &link_settings);
+	if (ret != 0) {
+		fprintf(stderr,
+			"Failed to get current link settings: err = %d\n",
+			ret);
+		return;
+	}
+
+	printf("\n%s Link settings for port %-2d %s\n",
+		info_border, res->port_id, info_border);
+
+	dump_supported(&link_settings);
+	dump_link_caps("Advertised", "Advertised",
+			link_settings.link_modes.advertising, 0);
+
+	bool show_lp_advertising = false;
+	for (uint32_t idx = 0; idx < RTE_DIM(link_settings.link_modes.lp_advertising); idx++) {
+		if (link_settings.link_modes.lp_advertising[idx] != 0) {
+			show_lp_advertising = true;
+			break;
+		}
+	}
+
+	if (show_lp_advertising) {
+		dump_link_caps("Link partner advertised",
+				"Link partner advertised",
+				link_settings.link_modes.lp_advertising, 0);
+	}
+
+	fprintf(stdout, "       Speed: ");
+	if (link_settings.base.link.link_speed == 0
+	    || link_settings.base.link.link_speed == (uint16_t)(-1)
+	    || link_settings.base.link.link_speed == (uint32_t)(-1))
+		fprintf(stdout, "Unknown!\n");
+	else
+		fprintf(stdout, "%uMb/s\n", link_settings.base.link.link_speed);
+
+	fprintf(stdout, "       Duplex: ");
+	switch (link_settings.base.link.link_duplex) {
+	case RTE_ETH_LINK_HALF_DUPLEX:
+		fprintf(stdout, "Half\n");
+		break;
+	case RTE_ETH_LINK_FULL_DUPLEX:
+		fprintf(stdout, "Full\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_settings.base.link.link_duplex);
+		break;
+	};
+
+	fprintf(stdout, "       Port: ");
+	switch (link_settings.base.port) {
+	case RTE_PORT_TP:
+		fprintf(stdout, "Twisted Pair\n");
+		break;
+	case RTE_PORT_AUI:
+		fprintf(stdout, "AUI\n");
+		break;
+	case RTE_PORT_BNC:
+		fprintf(stdout, "BNC\n");
+		break;
+	case RTE_PORT_MII:
+		fprintf(stdout, "MII\n");
+		break;
+	case RTE_PORT_FIBRE:
+		fprintf(stdout, "FIBRE\n");
+		break;
+	case RTE_PORT_DA:
+		fprintf(stdout, "Direct Attach Copper\n");
+		break;
+	case RTE_PORT_NONE:
+		fprintf(stdout, "None\n");
+		break;
+	case RTE_PORT_OTHER:
+		fprintf(stdout, "Other\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_settings.base.port);
+		break;
+	};
+
+	fprintf(stdout, "       PHYAD: %d\n", link_settings.base.phy_address);
+
+	fprintf(stdout, "       Auto-negotiation: %s\n",
+		(link_settings.base.link.link_autoneg == RTE_AUTONEG_DISABLE) ?
+		"off" : "on");
+
+	if (link_settings.base.port == RTE_PORT_TP) {
+		fprintf(stdout, "       MDI-X: ");
+		if (link_settings.base.eth_tp_mdix_ctrl == RTE_TP_MDI) {
+			fprintf(stdout, "off (forced)\n");
+		} else if (link_settings.base.eth_tp_mdix_ctrl
+			   == RTE_TP_MDI_X) {
+			fprintf(stdout, "on (forced)\n");
+		} else {
+			switch (link_settings.base.eth_tp_mdix) {
+			case RTE_TP_MDI:
+				fprintf(stdout, "off");
+				break;
+			case RTE_TP_MDI_X:
+				fprintf(stdout, "on");
+				break;
+			default:
+				fprintf(stdout, "Unknown");
+				break;
+			}
+			if (link_settings.base.eth_tp_mdix_ctrl
+			    == RTE_TP_MDI_AUTO)
+				fprintf(stdout, " (auto)");
+			fprintf(stdout, "\n");
+		}
+	}
+}
+
+cmdline_parse_inst_t cmd_link_settings_show = {
+	.f = cmd_link_settings_show_parsed,
+	.data = NULL,
+	.help_str = "show port <port_id> link settings",
+	.tokens = {
+		(void *)&cmd_ls_show_show,
+		(void *)&cmd_ls_show_port,
+		(void *)&cmd_ls_show_portid,
+		(void *)&cmd_ls_show_link,
+		(void *)&cmd_ls_show_settings,
+		NULL,
+	},
+};
+
+static int parse_hex_u32_bitmap(const char *s,
+				unsigned int nbits, uint32_t *result)
+{
+	const unsigned int nwords = RTE_DIV_ROUND_UP(nbits, 32);
+	size_t slen = strlen(s);
+	size_t i;
+
+	/* ignore optional '0x' prefix */
+	if ((slen > 2) && (strncasecmp(s, "0x", 2) == 0)) {
+		slen -= 2;
+		s += 2;
+	}
+
+	if (slen > 8 * nwords)  /* up to 2 digits per byte */
+		return -1;
+
+	memset(result, 0, 4 * nwords);
+	for (i = 0; i < slen; ++i) {
+		const unsigned int shift = (slen - 1 - i) * 4;
+		uint32_t *dest = &result[shift / 32];
+		uint32_t nibble;
+
+		if ('a' <= s[i] && s[i] <= 'f')
+			nibble = 0xa + (s[i] - 'a');
+		else if ('A' <= s[i] && s[i] <= 'F')
+			nibble = 0xa + (s[i] - 'A');
+		else if ('0' <= s[i] && s[i] <= '9')
+			nibble = (s[i] - '0');
+		else
+			return -1;
+
+		*dest |= (nibble << (shift % 32));
+	}
+
+	return 0;
+}
+
+/* *** SET ETHERNET LINK SETTINGS *** */
+struct cmd_link_settings_set {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t link;
+	cmdline_fixed_string_t settings;
+	cmdline_fixed_string_t advertising;
+	cmdline_multi_string_t bitmap_str;
+};
+
+cmdline_parse_token_string_t cmd_ls_set_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				set, "set");
+cmdline_parse_token_string_t cmd_ls_set_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				port, "port");
+cmdline_parse_token_num_t cmd_ls_set_portid =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_settings_set,
+				port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_ls_set_link =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				link, "link");
+cmdline_parse_token_string_t cmd_ls_set_settings =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				settings, "settings");
+cmdline_parse_token_string_t cmd_ls_set_advertising =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				advertising, "advertising");
+cmdline_parse_token_string_t cmd_ls_set_bitmap_str =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				bitmap_str, TOKEN_STRING_MULTI);
+
+static void
+cmd_link_settings_set_advertising_parsed(void *parsed_result,
+			      __rte_unused struct cmdline *cl,
+			      __rte_unused void *data)
+{
+	struct cmd_link_settings_set *res = parsed_result;
+	struct rte_link_settings link_settings;
+	int ret;
+
+	if (parse_hex_u32_bitmap(res->bitmap_str,
+				__RTE_LINK_MODE_MASK_NBITS,
+				link_settings.link_modes.advertising)) {
+		fprintf(stderr, "cannot parse bitmap_str\n");
+		return;
+
+	}
+
+	link_settings.base.link.link_autoneg = RTE_AUTONEG_ENABLE;
+
+	ret = rte_eth_dev_set_link_settings(res->port_id, &link_settings);
+	if (ret != 0) {
+		fprintf(stderr,
+			"Failed to set link settings: err = %d\n",
+			ret);
+	}
+}
+
+cmdline_parse_inst_t cmd_link_settings_set_advertising = {
+	.f = cmd_link_settings_set_advertising_parsed,
+	.data = NULL,
+	.help_str = "set port <port_id> link settings advertising <bitmap_str>"
+		" Bitmap_str - bitmap respresentation of advertising speeds",
+	.tokens = {
+		(void *)&cmd_ls_set_set,
+		(void *)&cmd_ls_set_port,
+		(void *)&cmd_ls_set_portid,
+		(void *)&cmd_ls_set_link,
+		(void *)&cmd_ls_set_settings,
+		(void *)&cmd_ls_set_advertising,
+		(void *)&cmd_ls_set_bitmap_str,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_settings.h b/app/test-pmd/cmdline_settings.h
new file mode 100644
index 0000000000..1bcd75f7ef
--- /dev/null
+++ b/app/test-pmd/cmdline_settings.h
@@ -0,0 +1,14 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Arista Networks, Inc.  All rights reserved.
+ * Arista Networks, Inc. Confidential and Proprietary
+ */
+
+#ifndef _CMDLINE_SETTINGS_H
+#define _CMDLINE_SETTINGS_H
+
+/* Link settings CLI */
+extern cmdline_parse_inst_t cmd_link_settings_show;
+extern cmdline_parse_inst_t cmd_link_settings_set_advertising;
+
+#endif /* _CMDLINE_SETTINGS_H */
+
diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build
index 719f875be0..7aadc2ec42 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -11,6 +11,7 @@  sources = files(
         'cmdline_flow.c',
         'cmdline_mtr.c',
         'cmdline_tm.c',
+        'cmdline_settings.c',
         'cmd_flex_item.c',
         'config.c',
         'csumonly.c',
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 0afae7d771..1873b45d23 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1187,6 +1187,7 @@  void eth_set_allmulticast_mode(uint16_t port, int enable);
 int eth_link_get_nowait_print_err(uint16_t port_id, struct rte_eth_link *link);
 int eth_macaddr_get_print_err(uint16_t port_id,
 			struct rte_ether_addr *mac_addr);
+int get_bit(const uint32_t *ptr, uint32_t pos);
 
 /* Functions to display the set of MAC addresses added to a port*/
 void show_macs(portid_t port_id);
diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c
index bf9b639d95..4d26776cc7 100644
--- a/app/test-pmd/util.c
+++ b/app/test-pmd/util.c
@@ -17,6 +17,8 @@ 
 
 #define MAX_STRING_LEN 8192
 
+#define UINT_32_BIT_WIDTH (CHAR_BIT * sizeof(uint32_t))
+
 #define MKDUMPSTR(buf, buf_size, cur_len, ...) \
 do { \
 	if (cur_len >= buf_size) \
@@ -525,3 +527,11 @@  eth_macaddr_get_print_err(uint16_t port_id, struct rte_ether_addr *mac_addr)
 
 	return ret;
 }
+
+int
+get_bit(const uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / UINT_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % UINT_32_BIT_WIDTH;
+	return (ptr[byte_idx] >> bit_idx) & 0x1;
+}