Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/net/dsa/conduit.c
49603 views
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 <[email protected]>
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
20
static 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
51
static 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
90
static 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
108
static 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
137
static 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
165
static 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
172
static 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
201
static 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
234
static 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
*/
275
int __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
297
static 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
326
static 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
*/
342
static 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
354
static 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
364
static 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
*/
407
out:
408
dsa_tag_driver_put(old_tag_ops);
409
return count;
410
}
411
static DEVICE_ATTR_RW(tagging);
412
413
static struct attribute *dsa_user_attrs[] = {
414
&dev_attr_tagging.attr,
415
NULL
416
};
417
418
static const struct attribute_group dsa_group = {
419
.name = "dsa",
420
.attrs = dsa_user_attrs,
421
};
422
423
static 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
433
int 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
481
out_err_ethtool_teardown:
482
dsa_conduit_ethtool_teardown(dev);
483
out_err_reset_promisc:
484
dsa_conduit_set_promiscuity(dev, -1);
485
return ret;
486
}
487
488
void 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
504
int 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
527
out_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
*/
536
void 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
}
550
551