From: Bruce Richardson <bruce.richardson@intel.com>
To: dev@dpdk.org
Cc: stephen@networkplumber.org,
Bruce Richardson <bruce.richardson@intel.com>
Subject: [PATCH v3] app/testpmd: add explicit link autonegotiation control
Date: Tue, 10 Nov 2026 12:16:57 +0000 [thread overview]
Message-ID: <20261110121658.1536152-1-bruce.richardson@intel.com> (raw)
In-Reply-To: <20261103155033.3740814-1-bruce.richardson@intel.com>
When a particular speed was specified for a port in testpmd, the flags
passed to the underlying API call always included the
RTE_ETH_LINK_SPEED_FIXED flag. This flag is not a mandatory part of the
bitmap when setting speeds, and is used to disable autonegotiation.
It's possible to have a link report only a single speed while
still have negotiation enabled, so testpmd needs to be extended to
support setting a speed both with and without the flag.
This patch does so by adding optional "autoneg on|off" setting after
speed and duplex settings specified by the user. This new option adjusts
the presence or absence of the FIXED speed bit in the ethdev
configuration structure "rte_eth_conf.link_speeds" bitmap. For backward
compatibility, the default value is "autoneg off" for fixed speeds if
not specified, meaning that the RTE_ETH_LINK_SPEED_FIXED flag is set on
the speed value by default.
Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
---
V3:
* change type of new function to bool from uint32_t since value is only
used as a flag
* Use proper ".. note::" syntax for newly added note in the testpmd docs
V2:
* changed syntax to more closely match that of ethtool, adding
autoneg on|off at the end of the command.
* increased compatibility by ensuring that when no autoneg value is
specified, a numeric speed sets the fixed flag (autoneg off), while an
"auto" speed keeps autoneg on.
---
app/test-pmd/cmdline.c | 91 +++++++++++++++++++--
doc/guides/rel_notes/release_26_11.rst | 6 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 11 ++-
3 files changed, 99 insertions(+), 9 deletions(-)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 51078a2a73..cdee12a507 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -726,8 +726,8 @@ static void cmd_help_long_parsed(void *parsed_result,
"port config (port_id|all)"
" speed (10|100|1000|2500|5000|10000|25000|40000|50000|"
"100000|200000|400000|800000|auto)"
- " duplex (half|full|auto)\n"
- " Set speed and duplex for all ports or port_id\n\n"
+ " duplex (half|full|auto) [autoneg (on|off)]\n"
+ " Set speed and duplex; optionally enable or disable link autonegotiation\n\n"
"port config (port_id|all) loopback (mode)\n"
" Set loopback mode for all ports or port_id\n\n"
@@ -1395,10 +1395,22 @@ struct cmd_config_speed_all {
cmdline_fixed_string_t item2;
cmdline_fixed_string_t value1;
cmdline_fixed_string_t value2;
+ cmdline_fixed_string_t autoneg;
+ cmdline_fixed_string_t autoneg_value;
};
+static bool
+link_speed_is_fixed(const char *speed, const char *autoneg)
+{
+ if (autoneg == NULL)
+ /* if no flag specified, set fixed speed if speed is not "auto" */
+ return strcmp(speed, "auto") != 0;
+
+ return strcmp(autoneg, "off") == 0;
+}
+
static int
-parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
+parse_and_check_speed_duplex(char *speedstr, char *duplexstr, bool fixed, uint32_t *speed)
{
int duplex;
@@ -1455,8 +1467,13 @@ parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
}
}
- if (*speed != RTE_ETH_LINK_SPEED_AUTONEG)
+ if (fixed) {
+ if (*speed == RTE_ETH_LINK_SPEED_AUTONEG) {
+ fprintf(stderr, "A fixed link requires a specific speed\n");
+ return -1;
+ }
*speed |= RTE_ETH_LINK_SPEED_FIXED;
+ }
return 0;
}
@@ -1464,9 +1481,11 @@ parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
static void
cmd_config_speed_all_parsed(void *parsed_result,
__rte_unused struct cmdline *cl,
- __rte_unused void *data)
+ void *data)
{
struct cmd_config_speed_all *res = parsed_result;
+ /* data is used to identify command variant with/without explicit autoneg setting */
+ const char *autoneg = data != NULL ? res->autoneg_value : NULL;
uint32_t link_speed;
portid_t pid;
@@ -1476,7 +1495,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
}
if (parse_and_check_speed_duplex(res->value1, res->value2,
- &link_speed) < 0)
+ link_speed_is_fixed(res->value1, autoneg), &link_speed) < 0)
return;
RTE_ETH_FOREACH_DEV(pid) {
@@ -1504,6 +1523,10 @@ static cmdline_parse_token_string_t cmd_config_speed_all_item2 =
static cmdline_parse_token_string_t cmd_config_speed_all_value2 =
TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value2,
"half#full#auto");
+static cmdline_parse_token_string_t cmd_config_speed_all_autoneg_token =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, autoneg, "autoneg");
+static cmdline_parse_token_string_t cmd_config_speed_all_autoneg_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, autoneg_value, "on#off");
static cmdline_parse_inst_t cmd_config_speed_all = {
.f = cmd_config_speed_all_parsed,
@@ -1524,6 +1547,27 @@ static cmdline_parse_inst_t cmd_config_speed_all = {
},
};
+static cmdline_parse_inst_t cmd_config_speed_all_autoneg = {
+ .f = cmd_config_speed_all_parsed,
+ .data = &cmd_config_speed_all_autoneg,
+ .help_str = "port config all speed "
+ "10|100|1000|2500|5000|10000|25000|40000|50000|"
+ "100000|200000|400000|800000|auto "
+ "duplex half|full|auto autoneg on|off",
+ .tokens = {
+ (void *)&cmd_config_speed_all_port,
+ (void *)&cmd_config_speed_all_keyword,
+ (void *)&cmd_config_speed_all_all,
+ (void *)&cmd_config_speed_all_item1,
+ (void *)&cmd_config_speed_all_value1,
+ (void *)&cmd_config_speed_all_item2,
+ (void *)&cmd_config_speed_all_value2,
+ (void *)&cmd_config_speed_all_autoneg_token,
+ (void *)&cmd_config_speed_all_autoneg_value,
+ NULL,
+ },
+};
+
/* *** configure speed for specific port *** */
struct cmd_config_speed_specific {
cmdline_fixed_string_t port;
@@ -1533,14 +1577,18 @@ struct cmd_config_speed_specific {
cmdline_fixed_string_t item2;
cmdline_fixed_string_t value1;
cmdline_fixed_string_t value2;
+ cmdline_fixed_string_t autoneg;
+ cmdline_fixed_string_t autoneg_value;
};
static void
cmd_config_speed_specific_parsed(void *parsed_result,
__rte_unused struct cmdline *cl,
- __rte_unused void *data)
+ void *data)
{
struct cmd_config_speed_specific *res = parsed_result;
+ /* data is used to identify command variant with/without explicit autoneg setting */
+ const char *autoneg = data != NULL ? res->autoneg_value : NULL;
uint32_t link_speed;
if (port_id_is_invalid(res->id, ENABLED_WARN))
@@ -1552,7 +1600,7 @@ cmd_config_speed_specific_parsed(void *parsed_result,
}
if (parse_and_check_speed_duplex(res->value1, res->value2,
- &link_speed) < 0)
+ link_speed_is_fixed(res->value1, autoneg), &link_speed) < 0)
return;
ports[res->id].dev_conf.link_speeds = link_speed;
@@ -1582,6 +1630,10 @@ static cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
static cmdline_parse_token_string_t cmd_config_speed_specific_value2 =
TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value2,
"half#full#auto");
+static cmdline_parse_token_string_t cmd_config_speed_specific_autoneg_token =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, autoneg, "autoneg");
+static cmdline_parse_token_string_t cmd_config_speed_specific_autoneg_value =
+ TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, autoneg_value, "on#off");
static cmdline_parse_inst_t cmd_config_speed_specific = {
.f = cmd_config_speed_specific_parsed,
@@ -1602,6 +1654,27 @@ static cmdline_parse_inst_t cmd_config_speed_specific = {
},
};
+static cmdline_parse_inst_t cmd_config_speed_specific_autoneg = {
+ .f = cmd_config_speed_specific_parsed,
+ .data = &cmd_config_speed_specific_autoneg,
+ .help_str = "port config <port_id> speed "
+ "10|100|1000|2500|5000|10000|25000|40000|50000|"
+ "100000|200000|400000|800000|auto "
+ "duplex half|full|auto autoneg on|off",
+ .tokens = {
+ (void *)&cmd_config_speed_specific_port,
+ (void *)&cmd_config_speed_specific_keyword,
+ (void *)&cmd_config_speed_specific_id,
+ (void *)&cmd_config_speed_specific_item1,
+ (void *)&cmd_config_speed_specific_value1,
+ (void *)&cmd_config_speed_specific_item2,
+ (void *)&cmd_config_speed_specific_value2,
+ (void *)&cmd_config_speed_specific_autoneg_token,
+ (void *)&cmd_config_speed_specific_autoneg_value,
+ NULL,
+ },
+};
+
static int
parse_speed_lanes_cfg(portid_t pid, uint32_t lanes)
{
@@ -14357,7 +14430,9 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
&cmd_operate_detach_device,
&cmd_set_port_setup_on,
&cmd_config_speed_all,
+ &cmd_config_speed_all_autoneg,
&cmd_config_speed_specific,
+ &cmd_config_speed_specific_autoneg,
&cmd_config_speed_lanes_all,
&cmd_config_speed_lanes_specific,
&cmd_show_speed_lanes,
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 8ca8379cc6..29fccf09e3 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -340,6 +340,12 @@ New Features
Added ``dpdk-validate-bpf`` tool to pre-validate eBPF programs
for compatibility with the ``lib/bpf`` execution context.
+* **Added explicit link autonegotiation control in testpmd.**
+
+ Added an optional ``autoneg on|off`` setting after ``duplex`` in the port speed configuration command.
+ For compatibility with older behavior, if unspecified,
+ auto-negotiation is disabled by default for numeric speeds, and enabled for "auto" speed selection.
+
Removed Items
-------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index a967bbef76..866f8057c1 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2167,7 +2167,16 @@ port config - speed
Set the speed and duplex mode for all ports or a specific port::
testpmd> port config (port_id|all) speed (10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|800000|auto) \
- duplex (half|full|auto)
+ duplex (half|full|auto) [autoneg (on|off)]
+
+With ``autoneg on``, the selected speed is advertised with link autonegotiation enabled.
+With ``autoneg off``, link autonegotiation is disabled and the selected speed is forced.
+If ``autoneg`` parameter is omitted for a numeric speed, link autonegotiation is disabled.
+The ``auto`` speed advertises all supported speeds and enables link autonegotiation if ``autoneg`` is omitted.
+
+.. note ::
+
+ Combining ``auto`` speed with ``autoneg off`` is an error.
port config - queues/descriptors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--
2.55.0
next prev parent reply other threads:[~2026-11-10 12:17 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-03 15:50 [PATCH] app/test-pmd: add explicit parameter for fixed link speeds Bruce Richardson
2026-11-04 12:29 ` Stephen Hemminger
2026-11-04 13:39 ` Bruce Richardson
2026-11-09 15:59 ` [PATCH v2] app/testpmd: add explicit link autonegotiation control Bruce Richardson
2026-11-09 17:45 ` Stephen Hemminger
2026-11-10 12:16 ` Bruce Richardson [this message]
2026-11-10 16:59 ` [PATCH v3] " Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261110121658.1536152-1-bruce.richardson@intel.com \
--to=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
--cc=stephen@networkplumber.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox