* Re: [PATCH] app/test-pmd: add explicit parameter for fixed link speeds
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-10 12:16 ` [PATCH v3] " Bruce Richardson
2 siblings, 1 reply; 7+ messages in thread
From: Stephen Hemminger @ 2026-11-04 12:29 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev, Aman Singh
On Tue, 3 Nov 2026 15:50:33 +0000
Bruce Richardson <bruce.richardson@intel.com> wrote:
> 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 an optional "fixed" keyword after the speed
> specified by the user. The presence or absense of the keyword adjusts
> the presence or absense of the FIXED speed bit in the ethdev
> configuration structure "rte_eth_conf.link_speeds" bitmap.
>
> Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> ---
In general it looked ok to me. But I would like testpmd and ethtool have same syntax
to follow the principle of "least surprise" for users.
The AI review with its issues and that encouragement was:
Review: [PATCH] app/test-pmd: add explicit parameter for fixed link
speeds (patchwork 172601)
Applies to main (26.11-rc2), builds with -Dwerror=true.
Warning (should fix)
--------------------
1. Syntax should follow ethtool rather than invent "fixed".
ethtool has autoneg as a separate on/off setting:
ethtool -s eth0 speed 10000 duplex full autoneg off
With autoneg on, a given speed/duplex limits what gets advertised
(the kernel's ethnl_auto_linkmodes()). That is the same as this
patch's default, so the semantics are right; only the keyword and
its position need to change:
port config (port_id|all) speed (...|auto) duplex (half|full|auto)
[autoneg (on|off)]
autoneg off -> set RTE_ETH_LINK_SPEED_FIXED
autoneg on -> clear it
absent -> leave autoneg alone. ethtool keeps the current
setting, so keep the FIXED bit already in
ports[pid].dev_conf.link_speeds. The default
dev_conf is autoneg, so a fresh port behaves as
posted.
speed auto + autoneg off -> error, as now.
Putting the optional tokens last leaves the existing
"speed N duplex D" prefix alone. Users who know ethtool can guess
it. Untested sketch for the all-ports case:
struct cmd_config_speed_all {
...
cmdline_fixed_string_t item3; /* "autoneg" */
cmdline_fixed_string_t value3; /* "on#off" */
};
static cmdline_parse_token_string_t cmd_config_speed_all_item3 =
TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item3,
"autoneg");
static cmdline_parse_token_string_t cmd_config_speed_all_value3 =
TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value3,
"on#off");
The second cmdline_parse_inst_t still needs the two extra tokens.
In the handler, res->item3[0] == '\0' means autoneg was not given.
The cmdline library zeroes the result buffer, so the
".data = &cmd_config_speed_all_fixed" self-reference used as a flag
can go. Same for the per-port instance.
2. Default behaviour of an existing command changes silently.
Before this patch "port config 0 speed 10000 duplex full" set
RTE_ETH_LINK_SPEED_FIXED. After it, the same command leaves autoneg
enabled and advertises only 10G. Existing scripts and test plans
(DTS, vendor validation) keep parsing but now do something
different. Whether the user sees a difference depends on the PMD.
The new default is correct (it matches ethtool), but the release
note puts it under New Features. Give the behaviour change its own
sentence, e.g.:
Speed settings no longer disable autonegotiation by default;
add ``autoneg off`` to force the speed.
3. --eth-link-speed is now inconsistent with the runtime command.
parse_link_speed() in parameters.c still starts from
RTE_ETH_LINK_SPEED_FIXED, and run_app.rst calls it "a forced link
speed". So the startup option forces the speed and the runtime
command no longer does. Either add a matching option (e.g.
--eth-link-autoneg=on|off), or at minimum document it in the speed
command section:
The ``--eth-link-speed`` command line option always disables
autonegotiation.
Info (consider)
---------------
4. testpmd_funcs.rst: the patch leaves three blank lines before
"port config - queues/descriptors"; one is enough. "Support for
these settings depends on the driver and hardware." adds nothing
and can go.
5. Commit message: "absense" (twice) -> "absence"; "still have
negotiation enabled" -> "still have autonegotiation enabled".
^ permalink raw reply [flat|nested] 7+ messages in thread* Re: [PATCH] app/test-pmd: add explicit parameter for fixed link speeds
2026-11-04 12:29 ` Stephen Hemminger
@ 2026-11-04 13:39 ` Bruce Richardson
0 siblings, 0 replies; 7+ messages in thread
From: Bruce Richardson @ 2026-11-04 13:39 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: dev, Aman Singh
On Wed, Nov 04, 2026 at 01:29:49PM +0100, Stephen Hemminger wrote:
> On Tue, 3 Nov 2026 15:50:33 +0000
> Bruce Richardson <bruce.richardson@intel.com> wrote:
>
> > 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 an optional "fixed" keyword after the speed
> > specified by the user. The presence or absense of the keyword adjusts
> > the presence or absense of the FIXED speed bit in the ethdev
> > configuration structure "rte_eth_conf.link_speeds" bitmap.
> >
> > Signed-off-by: Bruce Richardson <bruce.richardson@intel.com>
> > ---
>
> In general it looked ok to me. But I would like testpmd and ethtool have same syntax
> to follow the principle of "least surprise" for users.
>
> The AI review with its issues and that encouragement was:
>
> Review: [PATCH] app/test-pmd: add explicit parameter for fixed link
> speeds (patchwork 172601)
>
> Applies to main (26.11-rc2), builds with -Dwerror=true.
>
> Warning (should fix)
> --------------------
>
> 1. Syntax should follow ethtool rather than invent "fixed".
>
> ethtool has autoneg as a separate on/off setting:
>
> ethtool -s eth0 speed 10000 duplex full autoneg off
>
> With autoneg on, a given speed/duplex limits what gets advertised
> (the kernel's ethnl_auto_linkmodes()). That is the same as this
> patch's default, so the semantics are right; only the keyword and
> its position need to change:
>
> port config (port_id|all) speed (...|auto) duplex (half|full|auto)
> [autoneg (on|off)]
>
> autoneg off -> set RTE_ETH_LINK_SPEED_FIXED
> autoneg on -> clear it
> absent -> leave autoneg alone. ethtool keeps the current
> setting, so keep the FIXED bit already in
> ports[pid].dev_conf.link_speeds. The default
> dev_conf is autoneg, so a fresh port behaves as
> posted.
> speed auto + autoneg off -> error, as now.
>
> Putting the optional tokens last leaves the existing
> "speed N duplex D" prefix alone. Users who know ethtool can guess
> it. Untested sketch for the all-ports case:
>
> struct cmd_config_speed_all {
> ...
> cmdline_fixed_string_t item3; /* "autoneg" */
> cmdline_fixed_string_t value3; /* "on#off" */
> };
>
> static cmdline_parse_token_string_t cmd_config_speed_all_item3 =
> TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item3,
> "autoneg");
> static cmdline_parse_token_string_t cmd_config_speed_all_value3 =
> TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value3,
> "on#off");
>
> The second cmdline_parse_inst_t still needs the two extra tokens.
> In the handler, res->item3[0] == '\0' means autoneg was not given.
> The cmdline library zeroes the result buffer, so the
> ".data = &cmd_config_speed_all_fixed" self-reference used as a flag
> can go. Same for the per-port instance.
>
Ack, will rework to use the autoneg syntax.
> 2. Default behaviour of an existing command changes silently.
>
> Before this patch "port config 0 speed 10000 duplex full" set
> RTE_ETH_LINK_SPEED_FIXED. After it, the same command leaves autoneg
> enabled and advertises only 10G. Existing scripts and test plans
> (DTS, vendor validation) keep parsing but now do something
> different. Whether the user sees a difference depends on the PMD.
>
> The new default is correct (it matches ethtool), but the release
> note puts it under New Features. Give the behaviour change its own
> sentence, e.g.:
>
> Speed settings no longer disable autonegotiation by default;
> add ``autoneg off`` to force the speed.
>
This becomes moot if we rework the syntax. However, when making the
original change, I had AI do an analysis - only 5 drivers in tree actually
take account of the FIXED flag in turning on/off autoneg. Hopefully, adding
testpmd support will allow that list to increase, because nearly all
drivers just ignore it.
Interestingly, AI also flagged that there is a further set of 5 drivers
which would reject the existing testpmd command as it currently stands
since they reject any speed selection with the FIXED flag set.
> 3. --eth-link-speed is now inconsistent with the runtime command.
>
> parse_link_speed() in parameters.c still starts from
> RTE_ETH_LINK_SPEED_FIXED, and run_app.rst calls it "a forced link
> speed". So the startup option forces the speed and the runtime
> command no longer does. Either add a matching option (e.g.
> --eth-link-autoneg=on|off), or at minimum document it in the speed
> command section:
>
> The ``--eth-link-speed`` command line option always disables
> autonegotiation.
>
If we rework this also becomes largely moot, though the option of a
non-fixed link speed flag is a possibility for the future.
> Info (consider)
> ---------------
>
> 4. testpmd_funcs.rst: the patch leaves three blank lines before
> "port config - queues/descriptors"; one is enough. "Support for
> these settings depends on the driver and hardware." adds nothing
> and can go.
>
> 5. Commit message: "absense" (twice) -> "absence"; "still have
> negotiation enabled" -> "still have autonegotiation enabled".
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2] app/testpmd: add explicit link autonegotiation control
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-09 15:59 ` Bruce Richardson
2026-11-09 17:45 ` Stephen Hemminger
2026-11-10 12:16 ` [PATCH v3] " Bruce Richardson
2 siblings, 1 reply; 7+ messages in thread
From: Bruce Richardson @ 2026-11-09 15:59 UTC (permalink / raw)
To: dev; +Cc: stephen, Bruce Richardson
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>
---
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 | 90 +++++++++++++++++++--
doc/guides/rel_notes/release_26_11.rst | 6 ++
doc/guides/testpmd_app_ug/testpmd_funcs.rst | 8 +-
3 files changed, 95 insertions(+), 9 deletions(-)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 51078a2a73..676ed18aca 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,21 @@ 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 uint32_t
+link_speed_fixed_bit(const char *speed, const char *autoneg)
+{
+ if (autoneg == NULL)
+ return strcmp(speed, "auto") == 0 ? 0 : RTE_ETH_LINK_SPEED_FIXED;
+
+ return strcmp(autoneg, "off") == 0 ? RTE_ETH_LINK_SPEED_FIXED : 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 +1466,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 +1480,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 +1494,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
}
if (parse_and_check_speed_duplex(res->value1, res->value2,
- &link_speed) < 0)
+ link_speed_fixed_bit(res->value1, autoneg) != 0, &link_speed) < 0)
return;
RTE_ETH_FOREACH_DEV(pid) {
@@ -1504,6 +1522,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 +1546,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 +1576,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 +1599,7 @@ cmd_config_speed_specific_parsed(void *parsed_result,
}
if (parse_and_check_speed_duplex(res->value1, res->value2,
- &link_speed) < 0)
+ link_speed_fixed_bit(res->value1, autoneg) != 0, &link_speed) < 0)
return;
ports[res->id].dev_conf.link_speeds = link_speed;
@@ -1582,6 +1629,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 +1653,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 +14429,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..6bac4d2763 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2167,7 +2167,13 @@ 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
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v2] app/testpmd: add explicit link autonegotiation control
2026-11-09 15:59 ` [PATCH v2] app/testpmd: add explicit link autonegotiation control Bruce Richardson
@ 2026-11-09 17:45 ` Stephen Hemminger
0 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-11-09 17:45 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev
On Mon, 9 Nov 2026 15:59:35 +0000
Bruce Richardson <bruce.richardson@intel.com> wrote:
> 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>
> ---
> 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.
> ---
Looked ok to me, but AI decided that it was pickier than me.
Review: [PATCH v2] app/testpmd: add explicit link autonegotiation control
Applied on 26.11-rc2, testpmd builds with -Dwerror=true. Parser
behaviour checked against lib/cmdline: the 7-token and 9-token
instances share a prefix, but match_inst() rejects the short
instance when trailing tokens remain, so there is no ambiguity.
Semantics match rte_ethdev.h (FIXED is bit 0, AUTONEG is 0).
Warning
-------
link_speed_fixed_bit() returns a uint32_t bit, but both callers
immediately reduce it to bool:
link_speed_fixed_bit(res->value1, autoneg) != 0, &link_speed) < 0)
Make it a predicate and drop the "!= 0" at both call sites:
static bool
link_speed_is_fixed(const char *speed, const char *autoneg)
{
if (autoneg == NULL)
return strcmp(speed, "auto") != 0;
return strcmp(autoneg, "off") == 0;
}
if (parse_and_check_speed_duplex(res->value1, res->value2,
link_speed_is_fixed(res->value1, autoneg), &link_speed) < 0)
Info
----
testpmd_funcs.rst: "NOTE: Combining ``auto`` speed with ``autoneg
off`` is an error." is plain text. The file uses the ``.. note::``
directive everywhere else (17 instances); use it here too.
Review-Result: WARNING
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3] app/testpmd: add explicit link autonegotiation control
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-09 15:59 ` [PATCH v2] app/testpmd: add explicit link autonegotiation control Bruce Richardson
@ 2026-11-10 12:16 ` Bruce Richardson
2026-11-10 16:59 ` Stephen Hemminger
2 siblings, 1 reply; 7+ messages in thread
From: Bruce Richardson @ 2026-11-10 12:16 UTC (permalink / raw)
To: dev; +Cc: stephen, Bruce Richardson
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
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v3] app/testpmd: add explicit link autonegotiation control
2026-11-10 12:16 ` [PATCH v3] " Bruce Richardson
@ 2026-11-10 16:59 ` Stephen Hemminger
0 siblings, 0 replies; 7+ messages in thread
From: Stephen Hemminger @ 2026-11-10 16:59 UTC (permalink / raw)
To: Bruce Richardson; +Cc: dev
On Tue, 10 Nov 2026 12:16:57 +0000
Bruce Richardson <bruce.richardson@intel.com> wrote:
> 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>
> ---
Applied to next-net and resolved merge conflict and minor docbook whitespace
^ permalink raw reply [flat|nested] 7+ messages in thread