@@ -49,6 +49,7 @@ ethtool_SOURCES += \
netlink/plca.c \
netlink/pse-pd.c \
netlink/phy.c \
+ netlink/tsconfig.c \
uapi/linux/ethtool_netlink.h \
uapi/linux/netlink.h uapi/linux/genetlink.h \
uapi/linux/rtnetlink.h uapi/linux/if_link.h \
@@ -347,6 +347,16 @@ ethtool \- query or control network driver and hardware settings
.BI qualifier
.IR precise|approx ]
.HP
+.B ethtool \-\-get\-hwtimestamp\-cfg
+.I devname
+.HP
+.B ethtool \-\-set\-hwtimestamp\-cfg
+.I devname
+.RB [ index
+.IR N
+.BI qualifier
+.IR precise|approx ]
+.HP
.B ethtool \-x|\-\-show\-rxfh\-indir|\-\-show\-rxfh
.I devname
.HP
@@ -1249,6 +1259,21 @@ Qualifier of the ptp hardware clock. Mainly "precise" the default one is
for IEEE 1588 quality and "approx" is for NICs DMA point.
.RE
.TP
+.B \-\-get\-hwtimestamp\-cfg
+Show the selected time stamping PTP hardware clock configuration.
+.TP
+.B \-\-set\-hwtimestamp\-cfg
+Select the device's time stamping PTP hardware clock.
+.RS 4
+.TP
+.BI index \ N
+Index of the ptp hardware clock
+.TP
+.BI qualifier \ precise | approx
+Qualifier of the ptp hardware clock. Mainly "precise" the default one is
+for IEEE 1588 quality and "approx" is for NICs DMA point.
+.RE
+.TP
.B \-x \-\-show\-rxfh\-indir \-\-show\-rxfh
Retrieves the receive flow hash indirection table and/or RSS hash key.
.TP
@@ -5977,6 +5977,17 @@ static const struct option args[] = {
.help = "Show time stamping capabilities",
.xhelp = " [ index N qualifier precise|approx ]\n"
},
+ {
+ .opts = "--get-hwtimestamp-cfg",
+ .nlfunc = nl_gtsconfig,
+ .help = "Get selected hardware time stamping"
+ },
+ {
+ .opts = "--set-hwtimestamp-cfg",
+ .nlfunc = nl_stsconfig,
+ .help = "Select hardware time stamping",
+ .xhelp = " [ index N qualifier precise|approx ]\n"
+ },
{
.opts = "-x|--show-rxfh-indir|--show-rxfh",
.json = true,
@@ -36,6 +36,8 @@ int nl_spause(struct cmd_context *ctx);
int nl_geee(struct cmd_context *ctx);
int nl_seee(struct cmd_context *ctx);
int nl_tsinfo(struct cmd_context *ctx);
+int nl_gtsconfig(struct cmd_context *ctx);
+int nl_stsconfig(struct cmd_context *ctx);
int nl_cable_test(struct cmd_context *ctx);
int nl_cable_test_tdr(struct cmd_context *ctx);
int nl_gtunnels(struct cmd_context *ctx);
@@ -114,6 +116,8 @@ nl_get_eeprom_page(struct cmd_context *ctx __maybe_unused,
#define nl_geee NULL
#define nl_seee NULL
#define nl_tsinfo NULL
+#define nl_gtsconfig NULL
+#define nl_stsconfig NULL
#define nl_cable_test NULL
#define nl_cable_test_tdr NULL
#define nl_gtunnels NULL
new file mode 100644
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ts.h - netlink timestamping
+ *
+ * Copyright (c) 2025 Bootlin, Kory Maincent <kory.maincent@bootlin.com>
+ */
+
+#ifndef ETHTOOL_NETLINK_TS_H__
+#define ETHTOOL_NETLINK_TS_H__
+
+const char *tsinfo_hwprov_qualifier_names(u32 val);
+int tsinfo_show_hwprov(const struct nlattr *nest);
+int tsinfo_qualifier_parser(struct nl_context *nlctx,
+ uint16_t type __maybe_unused,
+ const void *data __maybe_unused,
+ struct nl_msg_buff *msgbuff __maybe_unused,
+ void *dest);
+int tsinfo_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
+ const char *label, const char *if_empty,
+ unsigned int stringset_id);
+
+#endif /* ETHTOOL_NETLINK_TS_H__ */
new file mode 100644
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * tsconfig.c - netlink implementation of hardware timestamping
+ * configuration
+ *
+ * Implementation of "ethtool --get-hwtimestamp-cfg <dev>" and
+ * "ethtool --set-hwtimestamp-cfg <dev> ..."
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "../internal.h"
+#include "../common.h"
+#include "netlink.h"
+#include "bitset.h"
+#include "parser.h"
+#include "ts.h"
+
+/* TSCONFIG_GET */
+
+int tsconfig_reply_cb(const struct nlmsghdr *nlhdr, void *data)
+{
+ const struct nlattr *tb[ETHTOOL_A_TSCONFIG_MAX + 1] = {};
+ DECLARE_ATTR_TB_INFO(tb);
+ struct nl_context *nlctx = data;
+ bool silent;
+ int err_ret;
+ int ret;
+
+ silent = nlctx->is_dump;
+ err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
+ ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
+ if (ret < 0)
+ return err_ret;
+ nlctx->devname = get_dev_name(tb[ETHTOOL_A_TSCONFIG_HEADER]);
+ if (!dev_ok(nlctx))
+ return err_ret;
+
+ if (silent)
+ print_nl();
+ printf("Time stamping configuration for %s:\n", nlctx->devname);
+
+ if (!tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER])
+ return MNL_CB_OK;
+
+ ret = tsinfo_show_hwprov(tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER]);
+ if (ret < 0)
+ return err_ret;
+
+ ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSCONFIG_TX_TYPES],
+ "Hardware Transmit Timestamp Mode", " none",
+ ETH_SS_TS_TX_TYPES);
+ if (ret < 0)
+ return err_ret;
+
+ ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSCONFIG_RX_FILTERS],
+ "Hardware Receive Filter Mode", " none",
+ ETH_SS_TS_RX_FILTERS);
+ if (ret < 0)
+ return err_ret;
+
+ ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSCONFIG_HWTSTAMP_FLAGS],
+ "Hardware Flags", " none",
+ ETH_SS_TS_FLAGS);
+ if (ret < 0)
+ return err_ret;
+
+ return MNL_CB_OK;
+}
+
+int nl_gtsconfig(struct cmd_context *ctx)
+{
+ struct nl_context *nlctx = ctx->nlctx;
+ struct nl_socket *nlsk = nlctx->ethnl_socket;
+ int ret;
+
+ if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSINFO_GET, true))
+ return -EOPNOTSUPP;
+ if (ctx->argc > 0) {
+ fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
+ *ctx->argp);
+ return 1;
+ }
+
+ ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TSCONFIG_GET,
+ ETHTOOL_A_TSCONFIG_HEADER, 0);
+ if (ret < 0)
+ return ret;
+ return nlsock_send_get_request(nlsk, tsconfig_reply_cb);
+}
+
+/* TSCONFIG_SET */
+
+static const struct param_parser stsconfig_params[] = {
+ {
+ .arg = "index",
+ .type = ETHTOOL_A_TS_HWTSTAMP_PROVIDER_INDEX,
+ .group = ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER,
+ .handler = nl_parse_direct_u32,
+ .min_argc = 1,
+ },
+ {
+ .arg = "qualifier",
+ .type = ETHTOOL_A_TS_HWTSTAMP_PROVIDER_QUALIFIER,
+ .group = ETHTOOL_A_TSCONFIG_HWTSTAMP_PROVIDER,
+ .handler = tsinfo_qualifier_parser,
+ .min_argc = 1,
+ },
+ {}
+};
+
+int nl_stsconfig(struct cmd_context *ctx)
+{
+ struct nl_context *nlctx = ctx->nlctx;
+ struct nl_msg_buff *msgbuff;
+ struct nl_socket *nlsk;
+ int ret;
+
+ if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSCONFIG_SET, false))
+ return -EOPNOTSUPP;
+
+ nlctx->cmd = "--set-hwtstamp-cfg";
+ nlctx->argp = ctx->argp;
+ nlctx->argc = ctx->argc;
+ nlctx->devname = ctx->devname;
+ nlsk = nlctx->ethnl_socket;
+ msgbuff = &nlsk->msgbuff;
+
+ ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_TSCONFIG_SET,
+ NLM_F_REQUEST | NLM_F_ACK);
+ if (ret < 0)
+ return ret;
+ if (ethnla_fill_header(msgbuff, ETHTOOL_A_TSCONFIG_HEADER,
+ ctx->devname, 0))
+ return -EMSGSIZE;
+
+ ret = nl_parser(nlctx, stsconfig_params, NULL, PARSER_GROUP_NEST, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = nlsock_sendmsg(nlsk, NULL);
+ if (ret < 0)
+ return ret;
+
+ ret = nlsock_process_reply(nlsk, tsconfig_reply_cb, nlctx);
+ if (ret == 0)
+ return 0;
+ else
+ return nlctx->exit_code ?: 1;
+}
@@ -14,10 +14,11 @@
#include "netlink.h"
#include "bitset.h"
#include "parser.h"
+#include "ts.h"
/* TSINFO_GET */
-static const char *tsinfo_hwprov_qualifier_names(u32 val)
+const char *tsinfo_hwprov_qualifier_names(u32 val)
{
switch (val) {
case HWTSTAMP_PROVIDER_QUALIFIER_PRECISE:
@@ -29,7 +30,7 @@ static const char *tsinfo_hwprov_qualifier_names(u32 val)
}
}
-static int tsinfo_show_hwprov(const struct nlattr *nest)
+int tsinfo_show_hwprov(const struct nlattr *nest)
{
const struct nlattr *tb[ETHTOOL_A_TS_HWTSTAMP_PROVIDER_MAX + 1] = {};
DECLARE_ATTR_TB_INFO(tb);
@@ -117,9 +118,9 @@ static void tsinfo_dump_cb(unsigned int idx, const char *name, bool val,
printf("\tbit%u\n", idx);
}
-static int tsinfo_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
- const char *label, const char *if_empty,
- unsigned int stringset_id)
+int tsinfo_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
+ const char *label, const char *if_empty,
+ unsigned int stringset_id)
{
const struct stringset *strings = NULL;
int ret;
@@ -205,11 +206,11 @@ int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
return MNL_CB_OK;
}
-static int tsinfo_qualifier_parser(struct nl_context *nlctx,
- uint16_t type __maybe_unused,
- const void *data __maybe_unused,
- struct nl_msg_buff *msgbuff __maybe_unused,
- void *dest __maybe_unused)
+int tsinfo_qualifier_parser(struct nl_context *nlctx,
+ uint16_t type __maybe_unused,
+ const void *data __maybe_unused,
+ struct nl_msg_buff *msgbuff __maybe_unused,
+ void *dest __maybe_unused)
{
const char *arg = *nlctx->argp;
u32 val;
Add support for the tsconfig command to get and set the hardware timestamp configuration. Currently, only allows selecting the hardware timestamp provider within a network interface topology. The configuration of tx_types and rx_filter is already handled by the linuxptp tool, so ethtool should not modify these parameters. Signed-off-by: Kory Maincent <kory.maincent@bootlin.com> --- Makefile.am | 1 + ethtool.8.in | 25 +++++++++ ethtool.c | 11 ++++ netlink/extapi.h | 4 ++ netlink/ts.h | 22 ++++++++ netlink/tsconfig.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++ netlink/tsinfo.c | 21 ++++---- 7 files changed, 227 insertions(+), 10 deletions(-)