lkml.org 
[lkml]   [2024]   [Jan]   [3]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH ethtool-next 3/3] ethtool: Introduce a command to list PHYs
    Date
    It is now possible to list all Ethernet PHYs that are present behind a
    given interface, since the following linux commit :
    63d5eaf35ac3 ("net: ethtool: Introduce a command to list PHYs on an interface")

    This command relies on the netlink DUMP command to list them, by allowing to
    pass an interface name/id as a parameter in the DUMP request to only
    list PHYs on one interface.

    Therefore, we introduce a new helper function to prepare a interface-filtered
    dump request (the filter can be empty, to perform an unfiltered dump),
    and then uses it to implement PHY enumeration through the --show-phys
    command.

    Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
    ---
    Makefile.am | 1 +
    ethtool.c | 5 ++
    netlink/extapi.h | 1 +
    netlink/nlsock.c | 24 ++++++++
    netlink/nlsock.h | 2 +
    netlink/phy.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++
    6 files changed, 172 insertions(+)
    create mode 100644 netlink/phy.c

    diff --git a/Makefile.am b/Makefile.am
    index b9e06ad..2434507 100644
    --- a/Makefile.am
    +++ b/Makefile.am
    @@ -48,6 +48,7 @@ ethtool_SOURCES += \
    netlink/desc-rtnl.c netlink/cable_test.c netlink/tunnels.c \
    netlink/plca.c \
    netlink/pse-pd.c \
    + netlink/phy.c \
    uapi/linux/ethtool_netlink.h \
    uapi/linux/netlink.h uapi/linux/genetlink.h \
    uapi/linux/rtnetlink.h uapi/linux/if_link.h \
    diff --git a/ethtool.c b/ethtool.c
    index 4c7c792..b877f2e 100644
    --- a/ethtool.c
    +++ b/ethtool.c
    @@ -6141,6 +6141,11 @@ static const struct option args[] = {
    .help = "Set Power Sourcing Equipment settings",
    .xhelp = " [ podl-pse-admin-control enable|disable ]\n"
    },
    + {
    + .opts = "--show-phys",
    + .nlfunc = nl_get_phy,
    + .help = "List PHYs"
    + },
    {
    .opts = "-h|--help",
    .no_dev = true,
    diff --git a/netlink/extapi.h b/netlink/extapi.h
    index e2d6b71..8f87f26 100644
    --- a/netlink/extapi.h
    +++ b/netlink/extapi.h
    @@ -55,6 +55,7 @@ int nl_get_mm(struct cmd_context *ctx);
    int nl_set_mm(struct cmd_context *ctx);
    int nl_gpse(struct cmd_context *ctx);
    int nl_spse(struct cmd_context *ctx);
    +int nl_get_phy(struct cmd_context *ctx);

    void nl_monitor_usage(void);

    diff --git a/netlink/nlsock.c b/netlink/nlsock.c
    index 0b873a3..510fc63 100644
    --- a/netlink/nlsock.c
    +++ b/netlink/nlsock.c
    @@ -298,6 +298,30 @@ int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd,
    return 0;
    }

    +int nlsock_prep_filtered_dump_request(struct nl_socket *nlsk,
    + unsigned int nlcmd, uint16_t hdr_attrtype,
    + u32 flags)
    +{
    + unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK;
    + struct nl_context *nlctx = nlsk->nlctx;
    + const char *devname = nlctx->ctx->devname;
    + int ret;
    +
    + nlctx->is_dump = true;
    + nlm_flags |= NLM_F_DUMP;
    +
    + if (devname && !strcmp(devname, WILDCARD_DEVNAME))
    + devname = NULL;
    +
    + ret = msg_init(nlctx, &nlsk->msgbuff, nlcmd, nlm_flags);
    + if (ret < 0)
    + return ret;
    + if (ethnla_fill_header(&nlsk->msgbuff, hdr_attrtype, devname, flags))
    + return -EMSGSIZE;
    +
    + return 0;
    +}
    +
    #ifndef TEST_ETHTOOL
    /**
    * nlsock_sendmsg() - send a netlink message to kernel
    diff --git a/netlink/nlsock.h b/netlink/nlsock.h
    index b015f86..6a72966 100644
    --- a/netlink/nlsock.h
    +++ b/netlink/nlsock.h
    @@ -38,6 +38,8 @@ int nlsock_init(struct nl_context *nlctx, struct nl_socket **__nlsk,
    void nlsock_done(struct nl_socket *nlsk);
    int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd,
    uint16_t hdr_attrtype, u32 flags);
    +int nlsock_prep_filtered_dump_request(struct nl_socket *nlsk, unsigned int nlcmd,
    + uint16_t hdr_attrtype, u32 flags);
    ssize_t nlsock_sendmsg(struct nl_socket *nlsk, struct nl_msg_buff *__msgbuff);
    int nlsock_send_get_request(struct nl_socket *nlsk, mnl_cb_t cb);
    int nlsock_process_reply(struct nl_socket *nlsk, mnl_cb_t reply_cb, void *data);
    diff --git a/netlink/phy.c b/netlink/phy.c
    new file mode 100644
    index 0000000..c195cb9
    --- /dev/null
    +++ b/netlink/phy.c
    @@ -0,0 +1,139 @@
    +/*
    + * phy.c - List PHYs on an interface and their parameters
    + *
    + * Implementation of "ethtool --show-phys <dev>"
    + */
    +
    +#include <errno.h>
    +#include <inttypes.h>
    +#include <string.h>
    +#include <stdio.h>
    +
    +#include "../internal.h"
    +#include "../common.h"
    +#include "netlink.h"
    +
    +/* PHY_GET / PHY_DUMP */
    +
    +static const char * phy_upstream_type_to_str(uint8_t upstream_type)
    +{
    + switch (upstream_type) {
    + case PHY_UPSTREAM_PHY: return "PHY";
    + case PHY_UPSTREAM_MAC: return "MAC";
    + default: return "Unknown";
    + }
    +}
    +
    +static int phy_show_upstream(const struct nlattr *nest)
    +{
    + const struct nlattr *tb[ETHTOOL_A_PHY_UPSTREAM_MAX + 1] = {};
    + DECLARE_ATTR_TB_INFO(tb);
    + int ret;
    +
    + ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info);
    + if (ret < 0)
    + return ret;
    +
    + open_json_object("upstream");
    +
    + if (tb[ETHTOOL_A_PHY_UPSTREAM_INDEX])
    + show_u32("upstream_index", "Upstream PHY index: ",
    + tb[ETHTOOL_A_PHY_UPSTREAM_INDEX]);
    +
    + if (tb[ETHTOOL_A_PHY_UPSTREAM_SFP_NAME])
    + print_string(PRINT_ANY, "upstream_sfp_name", "Upstream SFP name: %s\n",
    + mnl_attr_get_str(tb[ETHTOOL_A_PHY_UPSTREAM_SFP_NAME]));
    +
    + close_json_object();
    +
    + return 0;
    +}
    +
    +int phy_reply_cb(const struct nlmsghdr *nlhdr, void *data)
    +{
    + const struct nlattr *tb[ETHTOOL_A_PHY_MAX + 1] = {};
    + struct nl_context *nlctx = data;
    + DECLARE_ATTR_TB_INFO(tb);
    + uint8_t upstream_type;
    + bool silent;
    + int err_ret;
    + int ret;
    +
    + silent = nlctx->is_dump || nlctx->is_monitor;
    + 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_PHY_HEADER]);
    + if (!dev_ok(nlctx))
    + return err_ret;
    +
    + if (silent)
    + print_nl();
    +
    + open_json_object(NULL);
    +
    + print_string(PRINT_ANY, "ifname", "PHY for %s:\n", nlctx->devname);
    +
    + show_u32("phy_index", "PHY index: ", tb[ETHTOOL_A_PHY_INDEX]);
    +
    + print_string(PRINT_ANY, "drvname", "Driver name: %s\n",
    + mnl_attr_get_str(tb[ETHTOOL_A_PHY_DRVNAME]));
    +
    + print_string(PRINT_ANY, "name", "PHY device name: %s\n",
    + mnl_attr_get_str(tb[ETHTOOL_A_PHY_NAME]));
    +
    + if (tb[ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME])
    + print_string(PRINT_ANY, "downstream_sfp_name",
    + "Downstream SFP bus name: %s\n",
    + mnl_attr_get_str(tb[ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME]));
    +
    + show_u32("phy_id", "PHY id: ", tb[ETHTOOL_A_PHY_ID]);
    +
    + upstream_type = mnl_attr_get_u8(tb[ETHTOOL_A_PHY_UPSTREAM_TYPE]);
    + print_string(PRINT_ANY, "upstream_type", "Upstream type: %s\n",
    + phy_upstream_type_to_str(upstream_type));
    +
    + if (tb[ETHTOOL_A_PHY_UPSTREAM]) {
    + err_ret = phy_show_upstream(tb[ETHTOOL_A_PHY_UPSTREAM]);
    + if (err_ret)
    + goto err;
    + }
    +
    + if (!silent)
    + print_nl();
    +
    + close_json_object();
    +
    + return MNL_CB_OK;
    +
    +err:
    + close_json_object();
    + return err_ret;
    +}
    +
    +int nl_get_phy(struct cmd_context *ctx)
    +{
    + struct nl_context *nlctx = ctx->nlctx;
    + struct nl_socket *nlsk = nlctx->ethnl_socket;
    + u32 flags;
    + int ret;
    +
    + if (netlink_cmd_check(ctx, ETHTOOL_MSG_PHY_GET, true))
    + return -EOPNOTSUPP;
    + if (ctx->argc > 0) {
    + fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
    + *ctx->argp);
    + return 1;
    + }
    +
    + ret = nlsock_prep_filtered_dump_request(nlsk, ETHTOOL_MSG_PHY_GET,
    + ETHTOOL_A_PHY_HEADER, flags);
    + if (ret)
    + return ret;
    +
    + new_json_obj(ctx->json);
    + ret = nlsock_send_get_request(nlsk, phy_reply_cb);
    + delete_json_obj();
    + return ret;
    +}
    --
    2.43.0

    \
     
     \ /
      Last update: 2024-01-03 15:31    [W:4.834 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site