From nobody Mon Feb 9 13:36:04 2026 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) (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 3D747283691; Thu, 10 Apr 2025 12:33:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744288439; cv=none; b=H6b2R6Rmy8PbmQwA+9CbrcXzNXB+BrlgsnEgf+wVzYALtjp1OV3mc+seaSy/aLWjxDyyYNAWNHHJqI8J+y0tl4Eq9wd0wS1cbauQmh/BsQv9hlA+pG7Ld8g48aooSDXUqFeiKMUJbj/CCbmXDsInwVdo7XIa9se2qbVMdXVnORI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744288439; c=relaxed/simple; bh=9F9TiGOMnOykci3Ad6t7dD4O0QnGm/UNN27hUrZzFog=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QvcL1ROVkVIFHRKBaF3tL7PMJ6vHIYbd16DlMtCYvikVkqa00vwceiASthuf8p5LyvTMIK5MoXuOTs3OJlNxBC3+mSIqHbS7peVj8ivucDuudgS+ITboK512aw3/7gNI9qfN4zO7O0gQ4TzzTUGiZ8wa1NWsZzn28aQltmUeqKw= 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=G8dgjPxK; arc=none smtp.client-ip=217.70.183.200 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="G8dgjPxK" Received: by mail.gandi.net (Postfix) with ESMTPSA id 498774433D; Thu, 10 Apr 2025 12:33:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1744288435; 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=iGJUReIguyRV9xbIU9xSCriFdgpAnC77rarzBi44MG0=; b=G8dgjPxKC4HU8TuoZ8134TttkhQMtiq2n4a1UyaGTaCriv6hHAJku59LdvdTR3bUjPWDBb uQCEk1ZTOipFIJ2dGb2Kva0emCarEQiLqaeHN9cCZD6E8vYbJLCiJYSKbjUIuhpuJdnBZl fFSkXX2gBjopq3JXlBbiz+oGse7FZ/fdSIhfVbL5ukxH71LLEtuP3VF9ukK9ZIKv5/oP/d pTGjyU+w0+oz/Q7HcMZRrM6qVUrju419ejiYd6qf7dHIh6awSfbvNab7eZIDjQp+RSXMqB pvzLlFuFQ01miacSpkoC3Maq9i9haqHrL+Af1ddbfpDK90bAC+XW/jUmnstRGA== 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 v5 1/4] net: ethtool: Introduce per-PHY DUMP operations Date: Thu, 10 Apr 2025 14:33:46 +0200 Message-ID: <20250410123350.174105-2-maxime.chevallier@bootlin.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250410123350.174105-1-maxime.chevallier@bootlin.com> References: <20250410123350.174105-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: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddvtdekledvucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenucfjughrpefhvfevufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpeforgigihhmvgcuvehhvghvrghllhhivghruceomhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomheqnecuggftrfgrthhtvghrnhepveegtdffleffleevueellefgjeefvedvjefhheegfefgffdvfeetgeevudetffdtnecukfhppedvrgdtudemtggsudelmeekugegheemgeeltddtmeeiheeikeemvdelsgdumeelvghfheemvgektgejnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepvdgrtddumegtsgduleemkegugeehmeegledttdemieehieekmedvlegsudemlegvfhehmegvkegtjedphhgvlhhopehfvgguohhrrgdrhhhomhgvpdhmrghilhhfrhhomhepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdpnhgspghrtghpthhtohepvddupdhrtghpthhtohepuggrvhgvmhesuggrvhgvmhhlohhfthdrnhgvthdprhgtphhtthhopegrnhgurhgvfieslhhunhhnrdgthhdprhgtphhtthhopehkuhgsrgeskhgvrhhnvghlrdhorhhgpdhrtghpthhtohepvgguuhhmr giivghtsehgohhoghhlvgdrtghomhdprhgtphhtthhopehprggsvghnihesrhgvughhrghtrdgtohhmpdhrtghpthhtohephhhkrghllhifvghithdusehgmhgrihhlrdgtohhmpdhrtghpthhtohepmhgrgihimhgvrdgthhgvvhgrlhhlihgvrhessghoohhtlhhinhdrtghomhdprhgtphhtthhopehnvghtuggvvhesvhhgvghrrdhkvghrnhgvlhdrohhrgh 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. Signed-off-by: Maxime Chevallier --- net/ethtool/netlink.c | 162 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index a163d40c6431..343faa6886a3 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 @@ -661,6 +677,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) { --=20 2.49.0