From nobody Mon Feb 9 06:25:23 2026 Received: from relay5-d.mail.gandi.net (relay5-d.mail.gandi.net [217.70.183.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 63D1E27587B; Tue, 15 Apr 2025 08:52:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707124; cv=none; b=TZzFBDW/W9JSootiwbWs3fSZVv5OY4U93wPnRlKMd07ii9trgOdfG16nJzBhQQRBkIoUezHLqu+k7diaGmG9PH6P73UwAcAT/9smovmqn1Qhug8TQgnIuAAGc6cpePqZcwZFC0Q0MDXZBmexi0RzI9ak8sMzVtO+83JA10s7HbY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744707124; c=relaxed/simple; bh=HL0ZhZs1zQgnE7zPtvO9WCZUoFooDrSuef/24Z9yYz4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m/tWCTg3FC6/WWHViqL2dlMyvNUsZFEYXc2BZ1BA0p+dzQLZ3wAyaEsZ/GjbHTNXe41EUuaGJxMOoQlgUzB2PkSUIFYh/iSw+ruB1cKgV3khSD/N/bhninTAmHnTJCX07OI0fjb3ylyqEu4mRj6F/I1cVMwl0zJ76s8mGggEnyE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=jdcLNPU3; arc=none smtp.client-ip=217.70.183.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="jdcLNPU3" Received: by mail.gandi.net (Postfix) with ESMTPSA id 87451432FD; Tue, 15 Apr 2025 08:51:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1744707119; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=khKzl4zs7a80fLcDBgFBWkoB0YVlx2T1g/7fauNksCI=; b=jdcLNPU36Dns8snFhjipqW3ScdRpq21z7zTYm0paDnyNjJBNbhDoBp8JyTqUv6qYyeVNQu VHWSHmRv6KoUiOyOMJ5c5w4O9cbTMtn5GFOM36/nFYEugGpEpzSnsNlqFHmrTz3kkutxXW L7x/2VcDLWJ3b9jiLYI7E1NbWUoSPaFBUUFeI5lgqNKsTO1d20BG40PDj7aljD4zlAVbq0 UOnFJaqfS44A6K07u1wgE8ZDIASVkhVweKkQp8mN7otY7ArYObSq4fMIC1I8AVGsEHIQ4+ 7DG9N5Oee1n0MfpIwynARH7y58ik7IWVT8M1Euq5/jnW9aV2zmyEO7etgWb0cA== From: Maxime Chevallier To: davem@davemloft.net, Andrew Lunn , Jakub Kicinski , Eric Dumazet , Paolo Abeni , Heiner Kallweit Cc: Maxime Chevallier , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, thomas.petazzoni@bootlin.com, linux-arm-kernel@lists.infradead.org, Christophe Leroy , Herve Codina , Florian Fainelli , Russell King , Vladimir Oltean , =?UTF-8?q?K=C3=B6ry=20Maincent?= , Oleksij Rempel , Simon Horman , Romain Gantois , Piergiorgio Beruto Subject: [PATCH net-next v6 1/2] net: ethtool: Introduce per-PHY DUMP operations Date: Tue, 15 Apr 2025 10:51:53 +0200 Message-ID: <20250415085155.132963-2-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250415085155.132963-1-maxime.chevallier@bootlin.com> References: <20250415085155.132963-1-maxime.chevallier@bootlin.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-GND-State: clean X-GND-Score: -100 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddvvdeftdegucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeforgigihhmvgcuvehhvghvrghllhhivghruceomhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomheqnecuggftrfgrthhtvghrnhepfeehheeuheefffeuhefgvdejieeugeejieevffejudeuueevhffffeduueevgfdvnecuffhomhgrihhnpehprghttghhrdhnvghtnecukfhppedvrgdtudemtggsudelmeekugegheemgeeltddtmeeiheeikeemvdelsgdumeelvghfheemvgektgejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepvdgrtddumegtsgduleemkegugeehmeegledttdemieehieekmedvlegsudemlegvfhehmegvkegtjedphhgvlhhopehfvgguohhrrgdrhhhomhgvpdhmrghilhhfrhhomhepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdpnhgspghrtghpthhtohepvddupdhrtghpthhtohepuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvthdprhgtphhtthhopegrnhgurhgvfieslhhunhhnrdgthhdprhgtphhtthhopehkuhgsrgeskhgvrhhnv ghlrdhorhhgpdhrtghpthhtohepvgguuhhmrgiivghtsehgohhoghhlvgdrtghomhdprhgtphhtthhopehprggsvghnihesrhgvughhrghtrdgtohhmpdhrtghpthhtohephhhkrghllhifvghithdusehgmhgrihhlrdgtohhmpdhrtghpthhtohepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdprhgtphhtthhopehnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrgh X-GND-Sasl: maxime.chevallier@bootlin.com Content-Type: text/plain; charset="utf-8" ethnl commands that target a phy_device need a DUMP implementation that will fill the reply for every PHY behind a netdev. We therefore need to iterate over the dev->topo to list them. When multiple PHYs are behind the same netdev, it's also useful to perform DUMP with a filter on a given netdev, to get the capability of every PHY. Implement dedicated genl ->start(), ->dumpit() and ->done() operations for PHY-targetting command, allowing filtered dumps and using a dump context that keep track of the PHY iteration for multi-message dump. PSE-PD and PLCA are converted to this new set of ops along the way. Signed-off-by: Maxime Chevallier --- V6: Squashed PSE and PLCA into this patch. net/ethtool/netlink.c | 180 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 171 insertions(+), 9 deletions(-) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 977beeaaa2f9..afb609ed515a 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -357,6 +357,16 @@ struct ethnl_dump_ctx { unsigned long pos_ifindex; }; =20 +/** + * struct ethnl_perphy_dump_ctx - context for dumpit() PHY-aware callbacks + * @ethnl_ctx: generic ethnl context + * @pos_phyindex: iterator position for multi-msg DUMP + */ +struct ethnl_perphy_dump_ctx { + struct ethnl_dump_ctx ethnl_ctx; + unsigned long pos_phyindex; +}; + static const struct ethnl_request_ops * ethnl_default_requests[__ETHTOOL_MSG_USER_CNT] =3D { [ETHTOOL_MSG_STRSET_GET] =3D ðnl_strset_request_ops, @@ -407,6 +417,12 @@ static struct ethnl_dump_ctx *ethnl_dump_context(struc= t netlink_callback *cb) return (struct ethnl_dump_ctx *)cb->ctx; } =20 +static struct ethnl_perphy_dump_ctx * +ethnl_perphy_dump_context(struct netlink_callback *cb) +{ + return (struct ethnl_perphy_dump_ctx *)cb->ctx; +} + /** * ethnl_default_parse() - Parse request message * @req_info: pointer to structure to put data into @@ -662,6 +678,152 @@ static int ethnl_default_start(struct netlink_callbac= k *cb) return ret; } =20 +/* perphy ->start() handler for GET requests */ +static int ethnl_perphy_start(struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *phy_ctx =3D ethnl_perphy_dump_context(cb); + const struct genl_dumpit_info *info =3D genl_dumpit_info(cb); + struct ethnl_dump_ctx *ctx =3D &phy_ctx->ethnl_ctx; + struct ethnl_reply_data *reply_data; + const struct ethnl_request_ops *ops; + struct ethnl_req_info *req_info; + struct genlmsghdr *ghdr; + int ret; + + BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); + + ghdr =3D nlmsg_data(cb->nlh); + ops =3D ethnl_default_requests[ghdr->cmd]; + if (WARN_ONCE(!ops, "cmd %u has no ethnl_request_ops\n", ghdr->cmd)) + return -EOPNOTSUPP; + req_info =3D kzalloc(ops->req_info_size, GFP_KERNEL); + if (!req_info) + return -ENOMEM; + reply_data =3D kmalloc(ops->reply_data_size, GFP_KERNEL); + if (!reply_data) { + ret =3D -ENOMEM; + goto free_req_info; + } + + /* Don't ignore the dev even for DUMP requests */ + ret =3D ethnl_default_parse(req_info, &info->info, ops, false); + if (ret < 0) + goto free_reply_data; + + ctx->ops =3D ops; + ctx->req_info =3D req_info; + ctx->reply_data =3D reply_data; + ctx->pos_ifindex =3D 0; + + return 0; + +free_reply_data: + kfree(reply_data); +free_req_info: + kfree(req_info); + + return ret; +} + +static int ethnl_perphy_dump_one_dev(struct sk_buff *skb, + struct net_device *dev, + struct ethnl_perphy_dump_ctx *ctx, + const struct genl_info *info) +{ + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + struct phy_device_node *pdn; + int ret =3D 0; + + if (!dev->link_topo) + return 0; + + xa_for_each_start(&dev->link_topo->phys, ctx->pos_phyindex, pdn, + ctx->pos_phyindex) { + ethnl_ctx->req_info->phy_index =3D ctx->pos_phyindex; + + /* We can re-use the original dump_one as ->prepare_data in + * commands use ethnl_req_get_phydev(), which gets the PHY from + * the req_info->phy_index + */ + ret =3D ethnl_default_dump_one(skb, dev, ethnl_ctx, info); + if (ret) + break; + } + + return ret; +} + +static int ethnl_perphy_dump_all_dev(struct sk_buff *skb, + struct ethnl_perphy_dump_ctx *ctx, + const struct genl_info *info) +{ + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + struct net *net =3D sock_net(skb->sk); + struct net_device *dev; + int ret =3D 0; + + rcu_read_lock(); + for_each_netdev_dump(net, dev, ethnl_ctx->pos_ifindex) { + dev_hold(dev); + rcu_read_unlock(); + + /* per-PHY commands use ethnl_req_get_phydev(), which needs the + * net_device in the req_info + */ + ethnl_ctx->req_info->dev =3D dev; + ret =3D ethnl_perphy_dump_one_dev(skb, dev, ctx, info); + + rcu_read_lock(); + dev_put(dev); + + if (ret < 0 && ret !=3D -EOPNOTSUPP) { + if (likely(skb->len)) + ret =3D skb->len; + break; + } + ret =3D 0; + } + rcu_read_unlock(); + + return ret; +} + +/* perphy ->dumpit() handler for GET requests. */ +static int ethnl_perphy_dumpit(struct sk_buff *skb, + struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *ctx =3D ethnl_perphy_dump_context(cb); + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + int ret =3D 0; + + if (ethnl_ctx->req_info->dev) { + ret =3D ethnl_perphy_dump_one_dev(skb, ethnl_ctx->req_info->dev, + ctx, genl_info_dump(cb)); + + if (ret < 0 && ret !=3D -EOPNOTSUPP && likely(skb->len)) + ret =3D skb->len; + + netdev_put(ethnl_ctx->req_info->dev, + ðnl_ctx->req_info->dev_tracker); + } else { + ret =3D ethnl_perphy_dump_all_dev(skb, ctx, genl_info_dump(cb)); + } + + return ret; +} + +/* perphy ->done() handler for GET requests */ +static int ethnl_perphy_done(struct netlink_callback *cb) +{ + struct ethnl_perphy_dump_ctx *ctx =3D ethnl_perphy_dump_context(cb); + struct ethnl_dump_ctx *ethnl_ctx =3D &ctx->ethnl_ctx; + + kfree(ethnl_ctx->reply_data); + kfree(ethnl_ctx->req_info); + + return 0; +} + /* default ->done() handler for GET requests */ static int ethnl_default_done(struct netlink_callback *cb) { @@ -1200,9 +1362,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PSE_GET, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_pse_get_policy, .maxattr =3D ARRAY_SIZE(ethnl_pse_get_policy) - 1, }, @@ -1224,9 +1386,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PLCA_GET_CFG, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_plca_get_cfg_policy, .maxattr =3D ARRAY_SIZE(ethnl_plca_get_cfg_policy) - 1, }, @@ -1240,9 +1402,9 @@ static const struct genl_ops ethtool_genl_ops[] =3D { { .cmd =3D ETHTOOL_MSG_PLCA_GET_STATUS, .doit =3D ethnl_default_doit, - .start =3D ethnl_default_start, - .dumpit =3D ethnl_default_dumpit, - .done =3D ethnl_default_done, + .start =3D ethnl_perphy_start, + .dumpit =3D ethnl_perphy_dumpit, + .done =3D ethnl_perphy_done, .policy =3D ethnl_plca_get_status_policy, .maxattr =3D ARRAY_SIZE(ethnl_plca_get_status_policy) - 1, }, --=20 2.49.0