@@ -5640,6 +5640,7 @@ struct option {
const char *opts;
bool no_dev;
bool json;
+ bool targets_phy;
int (*func)(struct cmd_context *);
nl_chk_t nlchk;
nl_func_t nlfunc;
@@ -6053,12 +6054,14 @@ static const struct option args[] = {
},
{
.opts = "--cable-test",
+ .targets_phy = true,
.json = true,
.nlfunc = nl_cable_test,
.help = "Perform a cable test",
},
{
.opts = "--cable-test-tdr",
+ .targets_phy = true,
.json = true,
.nlfunc = nl_cable_test_tdr,
.help = "Print cable test time domain reflectrometery data",
@@ -6086,11 +6089,13 @@ static const struct option args[] = {
},
{
.opts = "--get-plca-cfg",
+ .targets_phy = true,
.nlfunc = nl_plca_get_cfg,
.help = "Get PLCA configuration",
},
{
.opts = "--set-plca-cfg",
+ .targets_phy = true,
.nlfunc = nl_plca_set_cfg,
.help = "Set PLCA configuration",
.xhelp = " [ enable on|off ]\n"
@@ -6102,6 +6107,7 @@ static const struct option args[] = {
},
{
.opts = "--get-plca-status",
+ .targets_phy = true,
.nlfunc = nl_plca_get_status,
.help = "Get PLCA status information",
},
@@ -6123,12 +6129,14 @@ static const struct option args[] = {
},
{
.opts = "--show-pse",
+ .targets_phy = true,
.json = true,
.nlfunc = nl_gpse,
.help = "Show settings for Power Sourcing Equipment",
},
{
.opts = "--set-pse",
+ .targets_phy = true,
.nlfunc = nl_spse,
.help = "Set Power Sourcing Equipment settings",
.xhelp = " [ podl-pse-admin-control enable|disable ]\n"
@@ -6157,7 +6165,8 @@ static int show_usage(struct cmd_context *ctx __maybe_unused)
fprintf(stdout, "Usage:\n");
for (i = 0; args[i].opts; i++) {
fputs(" ethtool [ FLAGS ] ", stdout);
- fprintf(stdout, "%s %s\t%s\n",
+ fprintf(stdout, "%s%s %s\t%s\n",
+ args[i].targets_phy ? "[ --phy PHY ] " : "",
args[i].opts,
args[i].no_dev ? "\t" : "DEVNAME",
args[i].help);
@@ -6437,6 +6446,16 @@ int main(int argc, char **argp)
argc -= 1;
continue;
}
+ if (*argp && !strcmp(*argp, "--phy")) {
+ char *eptr;
+
+ ctx.phy_index = strtoul(argp[1], &eptr, 0);
+ if (!argp[1][0] || *eptr)
+ exit_bad_args();
+ argp += 2;
+ argc -= 2;
+ continue;
+ }
break;
}
if (*argp && !strcmp(*argp, "--monitor")) {
@@ -6472,6 +6491,10 @@ int main(int argc, char **argp)
}
if (ctx.json && !args[k].json)
exit_bad_args();
+
+ if (!args[k].targets_phy && ctx.phy_index)
+ exit_bad_args();
+
ctx.argc = argc;
ctx.argp = argp;
netlink_run_handler(&ctx, args[k].nlchk, args[k].nlfunc, !args[k].func);
@@ -222,6 +222,7 @@ struct cmd_context {
unsigned long debug; /* debugging mask */
bool json; /* Output JSON, if supported */
bool show_stats; /* include command-specific stats */
+ uint32_t phy_index; /* the phy index this command targets */
#ifdef ETHTOOL_ENABLE_NETLINK
struct nl_context *nlctx; /* netlink context (opaque) */
#endif
@@ -572,8 +572,8 @@ int nl_cable_test_tdr(struct cmd_context *ctx)
if (ret < 0)
return 2;
- if (ethnla_fill_header(msgbuff, ETHTOOL_A_CABLE_TEST_TDR_HEADER,
- ctx->devname, 0))
+ if (ethnla_fill_header_phy(msgbuff, ETHTOOL_A_CABLE_TEST_TDR_HEADER,
+ ctx->devname, ctx->phy_index, 0))
return -EMSGSIZE;
ret = nl_parser(nlctx, tdr_params, NULL, PARSER_GROUP_NEST, NULL);
@@ -138,17 +138,9 @@ struct nlattr *ethnla_nest_start(struct nl_msg_buff *msgbuff, uint16_t type)
return NULL;
}
-/**
- * ethnla_fill_header() - write standard ethtool request header to message
- * @msgbuff: message buffer
- * @type: attribute type for header nest
- * @devname: device name (NULL to omit)
- * @flags: request flags (omitted if 0)
- *
- * Return: pointer to the nest attribute or null of error
- */
-bool ethnla_fill_header(struct nl_msg_buff *msgbuff, uint16_t type,
- const char *devname, uint32_t flags)
+static bool __ethnla_fill_header_phy(struct nl_msg_buff *msgbuff, uint16_t type,
+ const char *devname, uint32_t phy_index,
+ uint32_t flags)
{
struct nlattr *nest;
@@ -159,7 +151,9 @@ bool ethnla_fill_header(struct nl_msg_buff *msgbuff, uint16_t type,
if ((devname &&
ethnla_put_strz(msgbuff, ETHTOOL_A_HEADER_DEV_NAME, devname)) ||
(flags &&
- ethnla_put_u32(msgbuff, ETHTOOL_A_HEADER_FLAGS, flags)))
+ ethnla_put_u32(msgbuff, ETHTOOL_A_HEADER_FLAGS, flags)) ||
+ (phy_index &&
+ ethnla_put_u32(msgbuff, ETHTOOL_A_HEADER_PHY_INDEX, phy_index)))
goto err;
ethnla_nest_end(msgbuff, nest);
@@ -170,6 +164,40 @@ err:
return true;
}
+/**
+ * ethnla_fill_header() - write standard ethtool request header to message
+ * @msgbuff: message buffer
+ * @type: attribute type for header nest
+ * @devname: device name (NULL to omit)
+ * @flags: request flags (omitted if 0)
+ *
+ * Return: pointer to the nest attribute or null of error
+ */
+bool ethnla_fill_header(struct nl_msg_buff *msgbuff, uint16_t type,
+ const char *devname, uint32_t flags)
+{
+ return __ethnla_fill_header_phy(msgbuff, type, devname, 0, flags);
+}
+
+/**
+ * ethnla_fill_header_phy() - write standard ethtool request header to message,
+ * targetting a device's phy
+ * @msgbuff: message buffer
+ * @type: attribute type for header nest
+ * @devname: device name (NULL to omit)
+ * @phy_index: phy index to target
+ * @flags: request flags (omitted if 0)
+ *
+ * Return: pointer to the nest attribute or null of error
+ */
+bool ethnla_fill_header_phy(struct nl_msg_buff *msgbuff, uint16_t type,
+ const char *devname, uint32_t phy_index,
+ uint32_t flags)
+{
+ return __ethnla_fill_header_phy(msgbuff, type, devname, phy_index,
+ flags);
+}
+
/**
* __msg_init() - init a genetlink message, fill netlink and genetlink header
* @msgbuff: message buffer
@@ -47,6 +47,9 @@ bool ethnla_put(struct nl_msg_buff *msgbuff, uint16_t type, size_t len,
struct nlattr *ethnla_nest_start(struct nl_msg_buff *msgbuff, uint16_t type);
bool ethnla_fill_header(struct nl_msg_buff *msgbuff, uint16_t type,
const char *devname, uint32_t flags);
+bool ethnla_fill_header_phy(struct nl_msg_buff *msgbuff, uint16_t type,
+ const char *devname, uint32_t phy_index,
+ uint32_t flags);
/* length of current message */
static inline unsigned int msgbuff_len(const struct nl_msg_buff *msgbuff)
@@ -291,7 +291,8 @@ int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd,
ret = msg_init(nlctx, &nlsk->msgbuff, nlcmd, nlm_flags);
if (ret < 0)
return ret;
- if (ethnla_fill_header(&nlsk->msgbuff, hdr_attrtype, devname, flags))
+ if (ethnla_fill_header_phy(&nlsk->msgbuff, hdr_attrtype, devname,
+ nlctx->ctx->phy_index, flags))
return -EMSGSIZE;
return 0;
@@ -211,8 +211,8 @@ int nl_plca_set_cfg(struct cmd_context *ctx)
NLM_F_REQUEST | NLM_F_ACK);
if (ret < 0)
return 2;
- if (ethnla_fill_header(msgbuff, ETHTOOL_A_PLCA_HEADER,
- ctx->devname, 0))
+ if (ethnla_fill_header_phy(msgbuff, ETHTOOL_A_PLCA_HEADER,
+ ctx->devname, ctx->phy_index, 0))
return -EMSGSIZE;
ret = nl_parser(nlctx, set_plca_params, NULL, PARSER_GROUP_NONE, NULL);
@@ -174,8 +174,8 @@ int nl_spse(struct cmd_context *ctx)
NLM_F_REQUEST | NLM_F_ACK);
if (ret < 0)
return 2;
- if (ethnla_fill_header(msgbuff, ETHTOOL_A_PSE_HEADER,
- ctx->devname, 0))
+ if (ethnla_fill_header_phy(msgbuff, ETHTOOL_A_PSE_HEADER,
+ ctx->devname, ctx->phy_index, 0))
return -EMSGSIZE;
ret = nl_parser(nlctx, spse_params, NULL, PARSER_GROUP_NONE, NULL);
With the introduction of PHY topology and the ability to list PHYs, we can now target some netlink commands to specific PHYs. This is done by passing a PHY index as a request parameter in the netlink GET command. This is useful for PSE-PD, PLCA and Cable-testing operations when multiple PHYs are on the link (e.g. when a PHY is used as an SFP upstream controller, and when there's another PHY within the SFP module). Introduce a new, generic, option "--phy N" that can be used in conjunction with PHY-targetting commands to pass the PHY index for the targetted PHY. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> --- ethtool.c | 25 ++++++++++++++++++++- internal.h | 1 + netlink/cable_test.c | 4 ++-- netlink/msgbuff.c | 52 ++++++++++++++++++++++++++++++++++---------- netlink/msgbuff.h | 3 +++ netlink/nlsock.c | 3 ++- netlink/plca.c | 4 ++-- netlink/pse-pd.c | 4 ++-- 8 files changed, 76 insertions(+), 20 deletions(-)