File Index
Files and directories
Sign in
FILE

conduit.c

File preview with syntax highlighting.

linux-6.19.14/net/dsa/conduit.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Handling of a conduit device, switching frames via its switch fabric CPU port
  4 *
  5 * Copyright (c) 2017 Savoir-faire Linux Inc.
  6 *	Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  7 */
  8
  9#include <linux/ethtool.h>
 10#include <linux/netdevice.h>
 11#include <linux/netlink.h>
 12#include <net/dsa.h>
 13#include <net/netdev_lock.h>
 14
 15#include "conduit.h"
 16#include "dsa.h"
 17#include "port.h"
 18#include "tag.h"
 19
 20static int dsa_conduit_get_regs_len(struct net_device *dev)
 21{
 22	struct dsa_port *cpu_dp = dev->dsa_ptr;
 23	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
 24	struct dsa_switch *ds = cpu_dp->ds;
 25	int port = cpu_dp->index;
 26	int ret = 0;
 27	int len;
 28
 29	if (ops && ops->get_regs_len) {
 30		netdev_lock_ops(dev);
 31		len = ops->get_regs_len(dev);
 32		netdev_unlock_ops(dev);
 33		if (len < 0)
 34			return len;
 35		ret += len;
 36	}
 37
 38	ret += sizeof(struct ethtool_drvinfo);
 39	ret += sizeof(struct ethtool_regs);
 40
 41	if (ds->ops->get_regs_len) {
 42		len = ds->ops->get_regs_len(ds, port);
 43		if (len < 0)
 44			return len;
 45		ret += len;
 46	}
 47
 48	return ret;
 49}
 50
 51static void dsa_conduit_get_regs(struct net_device *dev,
 52				 struct ethtool_regs *regs, void *data)
 53{
 54	struct dsa_port *cpu_dp = dev->dsa_ptr;
 55	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
 56	struct dsa_switch *ds = cpu_dp->ds;
 57	struct ethtool_drvinfo *cpu_info;
 58	struct ethtool_regs *cpu_regs;
 59	int port = cpu_dp->index;
 60	int len;
 61
 62	if (ops && ops->get_regs_len && ops->get_regs) {
 63		netdev_lock_ops(dev);
 64		len = ops->get_regs_len(dev);
 65		if (len < 0) {
 66			netdev_unlock_ops(dev);
 67			return;
 68		}
 69		regs->len = len;
 70		ops->get_regs(dev, regs, data);
 71		netdev_unlock_ops(dev);
 72		data += regs->len;
 73	}
 74
 75	cpu_info = (struct ethtool_drvinfo *)data;
 76	strscpy(cpu_info->driver, "dsa", sizeof(cpu_info->driver));
 77	data += sizeof(*cpu_info);
 78	cpu_regs = (struct ethtool_regs *)data;
 79	data += sizeof(*cpu_regs);
 80
 81	if (ds->ops->get_regs_len && ds->ops->get_regs) {
 82		len = ds->ops->get_regs_len(ds, port);
 83		if (len < 0)
 84			return;
 85		cpu_regs->len = len;
 86		ds->ops->get_regs(ds, port, cpu_regs, data);
 87	}
 88}
 89
 90static ssize_t dsa_conduit_append_port_stats(struct dsa_switch *ds, int port,
 91					     u64 *data, size_t start)
 92{
 93	int count;
 94
 95	if (!ds->ops->get_sset_count)
 96		return 0;
 97
 98	count = ds->ops->get_sset_count(ds, port, ETH_SS_STATS);
 99	if (count < 0)
100		return count;
101
102	if (ds->ops->get_ethtool_stats)
103		ds->ops->get_ethtool_stats(ds, port, data + start);
104
105	return count;
106}
107
108static void dsa_conduit_get_ethtool_stats(struct net_device *dev,
109					  struct ethtool_stats *stats,
110					  u64 *data)
111{
112	struct dsa_port *dp, *cpu_dp = dev->dsa_ptr;
113	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
114	struct dsa_switch_tree *dst = cpu_dp->dst;
115	int count, mcount = 0;
116
117	if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
118		netdev_lock_ops(dev);
119		mcount = ops->get_sset_count(dev, ETH_SS_STATS);
120		ops->get_ethtool_stats(dev, stats, data);
121		netdev_unlock_ops(dev);
122	}
123
124	list_for_each_entry(dp, &dst->ports, list) {
125		if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))
126			continue;
127
128		count = dsa_conduit_append_port_stats(dp->ds, dp->index,
129						      data, mcount);
130		if (count < 0)
131			return;
132
133		mcount += count;
134	}
135}
136
137static void dsa_conduit_get_ethtool_phy_stats(struct net_device *dev,
138					      struct ethtool_stats *stats,
139					      u64 *data)
140{
141	struct dsa_port *cpu_dp = dev->dsa_ptr;
142	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
143	struct dsa_switch *ds = cpu_dp->ds;
144	int port = cpu_dp->index;
145	int count = 0;
146
147	if (dev->phydev && (!ops || !ops->get_ethtool_phy_stats)) {
148		count = phy_ethtool_get_sset_count(dev->phydev);
149		if (count >= 0)
150			phy_ethtool_get_stats(dev->phydev, stats, data);
151	} else if (ops && ops->get_sset_count && ops->get_ethtool_phy_stats) {
152		netdev_lock_ops(dev);
153		count = ops->get_sset_count(dev, ETH_SS_PHY_STATS);
154		ops->get_ethtool_phy_stats(dev, stats, data);
155		netdev_unlock_ops(dev);
156	}
157
158	if (count < 0)
159		count = 0;
160
161	if (ds->ops->get_ethtool_phy_stats)
162		ds->ops->get_ethtool_phy_stats(ds, port, data + count);
163}
164
165static void dsa_conduit_append_port_sset_count(struct dsa_switch *ds, int port,
166					       int sset, int *count)
167{
168	if (ds->ops->get_sset_count)
169		*count += ds->ops->get_sset_count(ds, port, sset);
170}
171
172static int dsa_conduit_get_sset_count(struct net_device *dev, int sset)
173{
174	struct dsa_port *dp, *cpu_dp = dev->dsa_ptr;
175	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
176	struct dsa_switch_tree *dst = cpu_dp->dst;
177	int count = 0;
178
179	netdev_lock_ops(dev);
180	if (sset == ETH_SS_PHY_STATS && dev->phydev &&
181	    (!ops || !ops->get_ethtool_phy_stats))
182		count = phy_ethtool_get_sset_count(dev->phydev);
183	else if (ops && ops->get_sset_count)
184		count = ops->get_sset_count(dev, sset);
185	netdev_unlock_ops(dev);
186
187	if (count < 0)
188		count = 0;
189
190	list_for_each_entry(dp, &dst->ports, list) {
191		if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))
192			continue;
193
194		dsa_conduit_append_port_sset_count(dp->ds, dp->index, sset,
195						   &count);
196	}
197
198	return count;
199}
200
201static ssize_t dsa_conduit_append_port_strings(struct dsa_switch *ds, int port,
202					       u32 stringset, u8 *data,
203					       size_t start)
204{
205	int len = ETH_GSTRING_LEN;
206	u8 pfx[8], *ndata;
207	int count, i;
208
209	if (!ds->ops->get_strings)
210		return 0;
211
212	snprintf(pfx, sizeof(pfx), "s%.2d_p%.2d", ds->index, port);
213	/* We do not want to be NULL-terminated, since this is a prefix */
214	pfx[sizeof(pfx) - 1] = '_';
215	ndata = data + start * len;
216	/* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
217	 * the output after to prepend our CPU port prefix we
218	 * constructed earlier
219	 */
220	ds->ops->get_strings(ds, port, stringset, ndata);
221	count = ds->ops->get_sset_count(ds, port, stringset);
222	if (count < 0)
223		return count;
224
225	for (i = 0; i < count; i++) {
226		memmove(ndata + (i * len + sizeof(pfx)),
227			ndata + i * len, len - sizeof(pfx));
228		memcpy(ndata + i * len, pfx, sizeof(pfx));
229	}
230
231	return count;
232}
233
234static void dsa_conduit_get_strings(struct net_device *dev, u32 stringset,
235				    u8 *data)
236{
237	struct dsa_port *dp, *cpu_dp = dev->dsa_ptr;
238	const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
239	struct dsa_switch_tree *dst = cpu_dp->dst;
240	int count, mcount = 0;
241
242	netdev_lock_ops(dev);
243	if (stringset == ETH_SS_PHY_STATS && dev->phydev &&
244	    !ops->get_ethtool_phy_stats) {
245		mcount = phy_ethtool_get_sset_count(dev->phydev);
246		if (mcount < 0)
247			mcount = 0;
248		else
249			phy_ethtool_get_strings(dev->phydev, data);
250	} else if (ops->get_sset_count && ops->get_strings) {
251		mcount = ops->get_sset_count(dev, stringset);
252		if (mcount < 0)
253			mcount = 0;
254		ops->get_strings(dev, stringset, data);
255	}
256	netdev_unlock_ops(dev);
257
258	list_for_each_entry(dp, &dst->ports, list) {
259		if (!dsa_port_is_dsa(dp) && !dsa_port_is_cpu(dp))
260			continue;
261
262		count = dsa_conduit_append_port_strings(dp->ds, dp->index,
263							stringset, data,
264							mcount);
265		if (count < 0)
266			return;
267
268		mcount += count;
269	}
270}
271
272/* Deny PTP operations on conduit if there is at least one switch in the tree
273 * that is PTP capable.
274 */
275int __dsa_conduit_hwtstamp_validate(struct net_device *dev,
276				    const struct kernel_hwtstamp_config *config,
277				    struct netlink_ext_ack *extack)
278{
279	struct dsa_port *cpu_dp = dev->dsa_ptr;
280	struct dsa_switch *ds = cpu_dp->ds;
281	struct dsa_switch_tree *dst;
282	struct dsa_port *dp;
283
284	dst = ds->dst;
285
286	list_for_each_entry(dp, &dst->ports, list) {
287		if (dsa_port_supports_hwtstamp(dp)) {
288			NL_SET_ERR_MSG(extack,
289				       "HW timestamping not allowed on DSA conduit when switch supports the operation");
290			return -EBUSY;
291		}
292	}
293
294	return 0;
295}
296
297static int dsa_conduit_ethtool_setup(struct net_device *dev)
298{
299	struct dsa_port *cpu_dp = dev->dsa_ptr;
300	struct dsa_switch *ds = cpu_dp->ds;
301	struct ethtool_ops *ops;
302
303	if (netif_is_lag_master(dev))
304		return 0;
305
306	ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL);
307	if (!ops)
308		return -ENOMEM;
309
310	cpu_dp->orig_ethtool_ops = dev->ethtool_ops;
311	if (cpu_dp->orig_ethtool_ops)
312		memcpy(ops, cpu_dp->orig_ethtool_ops, sizeof(*ops));
313
314	ops->get_regs_len = dsa_conduit_get_regs_len;
315	ops->get_regs = dsa_conduit_get_regs;
316	ops->get_sset_count = dsa_conduit_get_sset_count;
317	ops->get_ethtool_stats = dsa_conduit_get_ethtool_stats;
318	ops->get_strings = dsa_conduit_get_strings;
319	ops->get_ethtool_phy_stats = dsa_conduit_get_ethtool_phy_stats;
320
321	dev->ethtool_ops = ops;
322
323	return 0;
324}
325
326static void dsa_conduit_ethtool_teardown(struct net_device *dev)
327{
328	struct dsa_port *cpu_dp = dev->dsa_ptr;
329
330	if (netif_is_lag_master(dev))
331		return;
332
333	dev->ethtool_ops = cpu_dp->orig_ethtool_ops;
334	cpu_dp->orig_ethtool_ops = NULL;
335}
336
337/* Keep the conduit always promiscuous if the tagging protocol requires that
338 * (garbles MAC DA) or if it doesn't support unicast filtering, case in which
339 * it would revert to promiscuous mode as soon as we call dev_uc_add() on it
340 * anyway.
341 */
342static void dsa_conduit_set_promiscuity(struct net_device *dev, int inc)
343{
344	const struct dsa_device_ops *ops = dev->dsa_ptr->tag_ops;
345
346	if ((dev->priv_flags & IFF_UNICAST_FLT) && !ops->promisc_on_conduit)
347		return;
348
349	ASSERT_RTNL();
350
351	dev_set_promiscuity(dev, inc);
352}
353
354static ssize_t tagging_show(struct device *d, struct device_attribute *attr,
355			    char *buf)
356{
357	struct net_device *dev = to_net_dev(d);
358	struct dsa_port *cpu_dp = dev->dsa_ptr;
359
360	return sysfs_emit(buf, "%s\n",
361		       dsa_tag_protocol_to_str(cpu_dp->tag_ops));
362}
363
364static ssize_t tagging_store(struct device *d, struct device_attribute *attr,
365			     const char *buf, size_t count)
366{
367	const struct dsa_device_ops *new_tag_ops, *old_tag_ops;
368	const char *end = strchrnul(buf, '\n'), *name;
369	struct net_device *dev = to_net_dev(d);
370	struct dsa_port *cpu_dp = dev->dsa_ptr;
371	size_t len = end - buf;
372	int err;
373
374	/* Empty string passed */
375	if (!len)
376		return -ENOPROTOOPT;
377
378	name = kstrndup(buf, len, GFP_KERNEL);
379	if (!name)
380		return -ENOMEM;
381
382	old_tag_ops = cpu_dp->tag_ops;
383	new_tag_ops = dsa_tag_driver_get_by_name(name);
384	kfree(name);
385	/* Bad tagger name? */
386	if (IS_ERR(new_tag_ops))
387		return PTR_ERR(new_tag_ops);
388
389	if (new_tag_ops == old_tag_ops)
390		/* Drop the temporarily held duplicate reference, since
391		 * the DSA switch tree uses this tagger.
392		 */
393		goto out;
394
395	err = dsa_tree_change_tag_proto(cpu_dp->ds->dst, new_tag_ops,
396					old_tag_ops);
397	if (err) {
398		/* On failure the old tagger is restored, so we don't need the
399		 * driver for the new one.
400		 */
401		dsa_tag_driver_put(new_tag_ops);
402		return err;
403	}
404
405	/* On success we no longer need the module for the old tagging protocol
406	 */
407out:
408	dsa_tag_driver_put(old_tag_ops);
409	return count;
410}
411static DEVICE_ATTR_RW(tagging);
412
413static struct attribute *dsa_user_attrs[] = {
414	&dev_attr_tagging.attr,
415	NULL
416};
417
418static const struct attribute_group dsa_group = {
419	.name	= "dsa",
420	.attrs	= dsa_user_attrs,
421};
422
423static void dsa_conduit_reset_mtu(struct net_device *dev)
424{
425	int err;
426
427	err = dev_set_mtu(dev, ETH_DATA_LEN);
428	if (err)
429		netdev_dbg(dev,
430			   "Unable to reset MTU to exclude DSA overheads\n");
431}
432
433int dsa_conduit_setup(struct net_device *dev, struct dsa_port *cpu_dp)
434{
435	const struct dsa_device_ops *tag_ops = cpu_dp->tag_ops;
436	struct dsa_switch *ds = cpu_dp->ds;
437	struct device_link *consumer_link;
438	int mtu, ret;
439
440	mtu = ETH_DATA_LEN + dsa_tag_protocol_overhead(tag_ops);
441
442	/* The DSA conduit must use SET_NETDEV_DEV for this to work. */
443	if (!netif_is_lag_master(dev)) {
444		consumer_link = device_link_add(ds->dev, dev->dev.parent,
445						DL_FLAG_AUTOREMOVE_CONSUMER);
446		if (!consumer_link)
447			netdev_err(dev,
448				   "Failed to create a device link to DSA switch %s\n",
449				   dev_name(ds->dev));
450	}
451
452	/* The switch driver may not implement ->port_change_mtu(), case in
453	 * which dsa_user_change_mtu() will not update the conduit MTU either,
454	 * so we need to do that here.
455	 */
456	ret = dev_set_mtu(dev, mtu);
457	if (ret)
458		netdev_warn(dev, "error %d setting MTU to %d to include DSA overhead\n",
459			    ret, mtu);
460
461	/* If we use a tagging format that doesn't have an ethertype
462	 * field, make sure that all packets from this point on get
463	 * sent to the tag format's receive function.
464	 */
465	wmb();
466
467	dev->dsa_ptr = cpu_dp;
468
469	dsa_conduit_set_promiscuity(dev, 1);
470
471	ret = dsa_conduit_ethtool_setup(dev);
472	if (ret)
473		goto out_err_reset_promisc;
474
475	ret = sysfs_create_group(&dev->dev.kobj, &dsa_group);
476	if (ret)
477		goto out_err_ethtool_teardown;
478
479	return ret;
480
481out_err_ethtool_teardown:
482	dsa_conduit_ethtool_teardown(dev);
483out_err_reset_promisc:
484	dsa_conduit_set_promiscuity(dev, -1);
485	return ret;
486}
487
488void dsa_conduit_teardown(struct net_device *dev)
489{
490	sysfs_remove_group(&dev->dev.kobj, &dsa_group);
491	dsa_conduit_ethtool_teardown(dev);
492	dsa_conduit_reset_mtu(dev);
493	dsa_conduit_set_promiscuity(dev, -1);
494
495	dev->dsa_ptr = NULL;
496
497	/* If we used a tagging format that doesn't have an ethertype
498	 * field, make sure that all packets from this point get sent
499	 * without the tag and go through the regular receive path.
500	 */
501	wmb();
502}
503
504int dsa_conduit_lag_setup(struct net_device *lag_dev, struct dsa_port *cpu_dp,
505			  struct netdev_lag_upper_info *uinfo,
506			  struct netlink_ext_ack *extack)
507{
508	bool conduit_setup = false;
509	int err;
510
511	if (!netdev_uses_dsa(lag_dev)) {
512		err = dsa_conduit_setup(lag_dev, cpu_dp);
513		if (err)
514			return err;
515
516		conduit_setup = true;
517	}
518
519	err = dsa_port_lag_join(cpu_dp, lag_dev, uinfo, extack);
520	if (err) {
521		NL_SET_ERR_MSG_WEAK_MOD(extack, "CPU port failed to join LAG");
522		goto out_conduit_teardown;
523	}
524
525	return 0;
526
527out_conduit_teardown:
528	if (conduit_setup)
529		dsa_conduit_teardown(lag_dev);
530	return err;
531}
532
533/* Tear down a conduit if there isn't any other user port on it,
534 * optionally also destroying LAG information.
535 */
536void dsa_conduit_lag_teardown(struct net_device *lag_dev,
537			      struct dsa_port *cpu_dp)
538{
539	struct net_device *upper;
540	struct list_head *iter;
541
542	dsa_port_lag_leave(cpu_dp, lag_dev);
543
544	netdev_for_each_upper_dev_rcu(lag_dev, upper, iter)
545		if (dsa_user_dev_check(upper))
546			return;
547
548	dsa_conduit_teardown(lag_dev);
549}
~/ Read-only file preview.