]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/sched/sch_teql.c
Merge tag 'drm-misc-fixes-2018-11-14' of git://anongit.freedesktop.org/drm/drm-misc...
[mirror_ubuntu-jammy-kernel.git] / net / sched / sch_teql.c
CommitLineData
1da177e4
LT
1/* net/sched/sch_teql.c "True" (or "trivial") link equalizer.
2 *
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version
6 * 2 of the License, or (at your option) any later version.
7 *
8 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
9 */
10
11#include <linux/module.h>
1da177e4
LT
12#include <linux/types.h>
13#include <linux/kernel.h>
5a0e3ad6 14#include <linux/slab.h>
1da177e4 15#include <linux/string.h>
1da177e4 16#include <linux/errno.h>
14c85021 17#include <linux/if_arp.h>
1da177e4 18#include <linux/netdevice.h>
1da177e4 19#include <linux/init.h>
1da177e4
LT
20#include <linux/skbuff.h>
21#include <linux/moduleparam.h>
0ba48053
PM
22#include <net/dst.h>
23#include <net/neighbour.h>
1da177e4
LT
24#include <net/pkt_sched.h>
25
26/*
27 How to setup it.
28 ----------------
29
30 After loading this module you will find a new device teqlN
31 and new qdisc with the same name. To join a slave to the equalizer
32 you should just set this qdisc on a device f.e.
33
34 # tc qdisc add dev eth0 root teql0
35 # tc qdisc add dev eth1 root teql0
36
37 That's all. Full PnP 8)
38
39 Applicability.
40 --------------
41
42 1. Slave devices MUST be active devices, i.e., they must raise the tbusy
43 signal and generate EOI events. If you want to equalize virtual devices
44 like tunnels, use a normal eql device.
45 2. This device puts no limitations on physical slave characteristics
46 f.e. it will equalize 9600baud line and 100Mb ethernet perfectly :-)
47 Certainly, large difference in link speeds will make the resulting
48 eqalized link unusable, because of huge packet reordering.
49 I estimate an upper useful difference as ~10 times.
50 3. If the slave requires address resolution, only protocols using
51 neighbour cache (IPv4/IPv6) will work over the equalized link.
52 Other protocols are still allowed to use the slave device directly,
53 which will not break load balancing, though native slave
54 traffic will have the highest priority. */
55
cc7ec456 56struct teql_master {
1da177e4
LT
57 struct Qdisc_ops qops;
58 struct net_device *dev;
59 struct Qdisc *slaves;
60 struct list_head master_list;
1ac9ad13
ED
61 unsigned long tx_bytes;
62 unsigned long tx_packets;
63 unsigned long tx_errors;
64 unsigned long tx_dropped;
1da177e4
LT
65};
66
cc7ec456 67struct teql_sched_data {
1da177e4
LT
68 struct Qdisc *next;
69 struct teql_master *m;
1da177e4
LT
70 struct sk_buff_head q;
71};
72
cc7ec456 73#define NEXT_SLAVE(q) (((struct teql_sched_data *)qdisc_priv(q))->next)
1da177e4 74
cc7ec456 75#define FMASK (IFF_BROADCAST | IFF_POINTOPOINT)
1da177e4
LT
76
77/* "teql*" qdisc routines */
78
79static int
520ac30f 80teql_enqueue(struct sk_buff *skb, struct Qdisc *sch, struct sk_buff **to_free)
1da177e4 81{
5ce2d488 82 struct net_device *dev = qdisc_dev(sch);
1da177e4
LT
83 struct teql_sched_data *q = qdisc_priv(sch);
84
4cd8c9e8
KK
85 if (q->q.qlen < dev->tx_queue_len) {
86 __skb_queue_tail(&q->q, skb);
9871e50e 87 return NET_XMIT_SUCCESS;
1da177e4
LT
88 }
89
520ac30f 90 return qdisc_drop(skb, sch, to_free);
1da177e4
LT
91}
92
1da177e4 93static struct sk_buff *
cc7ec456 94teql_dequeue(struct Qdisc *sch)
1da177e4
LT
95{
96 struct teql_sched_data *dat = qdisc_priv(sch);
b0e1e646 97 struct netdev_queue *dat_queue;
1da177e4 98 struct sk_buff *skb;
46e5da40 99 struct Qdisc *q;
1da177e4
LT
100
101 skb = __skb_dequeue(&dat->q);
e8a0464c 102 dat_queue = netdev_get_tx_queue(dat->m->dev, 0);
46e5da40
JF
103 q = rcu_dereference_bh(dat_queue->qdisc);
104
1da177e4 105 if (skb == NULL) {
46e5da40 106 struct net_device *m = qdisc_dev(q);
1da177e4
LT
107 if (m) {
108 dat->m->slaves = sch;
109 netif_wake_queue(m);
110 }
9190b3b3
ED
111 } else {
112 qdisc_bstats_update(sch, skb);
1da177e4 113 }
46e5da40 114 sch->q.qlen = dat->q.qlen + q->q.qlen;
1da177e4
LT
115 return skb;
116}
117
8e3af978 118static struct sk_buff *
cc7ec456 119teql_peek(struct Qdisc *sch)
8e3af978
JP
120{
121 /* teql is meant to be used as root qdisc */
122 return NULL;
123}
124
1da177e4 125static void
cc7ec456 126teql_reset(struct Qdisc *sch)
1da177e4
LT
127{
128 struct teql_sched_data *dat = qdisc_priv(sch);
129
130 skb_queue_purge(&dat->q);
131 sch->q.qlen = 0;
1da177e4
LT
132}
133
134static void
cc7ec456 135teql_destroy(struct Qdisc *sch)
1da177e4
LT
136{
137 struct Qdisc *q, *prev;
138 struct teql_sched_data *dat = qdisc_priv(sch);
139 struct teql_master *master = dat->m;
140
cc7ec456
ED
141 prev = master->slaves;
142 if (prev) {
1da177e4
LT
143 do {
144 q = NEXT_SLAVE(prev);
145 if (q == sch) {
146 NEXT_SLAVE(prev) = NEXT_SLAVE(q);
147 if (q == master->slaves) {
148 master->slaves = NEXT_SLAVE(q);
149 if (q == master->slaves) {
e8a0464c 150 struct netdev_queue *txq;
83874000 151 spinlock_t *root_lock;
e8a0464c
DM
152
153 txq = netdev_get_tx_queue(master->dev, 0);
1da177e4 154 master->slaves = NULL;
83874000 155
46e5da40 156 root_lock = qdisc_root_sleeping_lock(rtnl_dereference(txq->qdisc));
83874000 157 spin_lock_bh(root_lock);
46e5da40 158 qdisc_reset(rtnl_dereference(txq->qdisc));
83874000 159 spin_unlock_bh(root_lock);
1da177e4
LT
160 }
161 }
162 skb_queue_purge(&dat->q);
1da177e4
LT
163 break;
164 }
10297b99 165
1da177e4
LT
166 } while ((prev = q) != master->slaves);
167 }
168}
169
e63d7dfd
AA
170static int teql_qdisc_init(struct Qdisc *sch, struct nlattr *opt,
171 struct netlink_ext_ack *extack)
1da177e4 172{
5ce2d488 173 struct net_device *dev = qdisc_dev(sch);
cc7ec456 174 struct teql_master *m = (struct teql_master *)sch->ops;
1da177e4
LT
175 struct teql_sched_data *q = qdisc_priv(sch);
176
177 if (dev->hard_header_len > m->dev->hard_header_len)
178 return -EINVAL;
179
180 if (m->dev == dev)
181 return -ELOOP;
182
183 q->m = m;
184
185 skb_queue_head_init(&q->q);
186
187 if (m->slaves) {
188 if (m->dev->flags & IFF_UP) {
f64f9e71
JP
189 if ((m->dev->flags & IFF_POINTOPOINT &&
190 !(dev->flags & IFF_POINTOPOINT)) ||
191 (m->dev->flags & IFF_BROADCAST &&
192 !(dev->flags & IFF_BROADCAST)) ||
193 (m->dev->flags & IFF_MULTICAST &&
194 !(dev->flags & IFF_MULTICAST)) ||
195 dev->mtu < m->dev->mtu)
1da177e4
LT
196 return -EINVAL;
197 } else {
198 if (!(dev->flags&IFF_POINTOPOINT))
199 m->dev->flags &= ~IFF_POINTOPOINT;
200 if (!(dev->flags&IFF_BROADCAST))
201 m->dev->flags &= ~IFF_BROADCAST;
202 if (!(dev->flags&IFF_MULTICAST))
203 m->dev->flags &= ~IFF_MULTICAST;
204 if (dev->mtu < m->dev->mtu)
205 m->dev->mtu = dev->mtu;
206 }
207 q->next = NEXT_SLAVE(m->slaves);
208 NEXT_SLAVE(m->slaves) = sch;
209 } else {
210 q->next = sch;
211 m->slaves = sch;
212 m->dev->mtu = dev->mtu;
213 m->dev->flags = (m->dev->flags&~FMASK)|(dev->flags&FMASK);
214 }
215 return 0;
216}
217
1da177e4
LT
218
219static int
f7e57044
ED
220__teql_resolve(struct sk_buff *skb, struct sk_buff *skb_res,
221 struct net_device *dev, struct netdev_queue *txq,
dbedbe6d 222 struct dst_entry *dst)
1da177e4 223{
dbedbe6d
DM
224 struct neighbour *n;
225 int err = 0;
1da177e4 226
dbedbe6d
DM
227 n = dst_neigh_lookup_skb(dst, skb);
228 if (!n)
229 return -ENOENT;
230
231 if (dst->dev != dev) {
232 struct neighbour *mn;
233
234 mn = __neigh_lookup_errno(n->tbl, n->primary_key, dev);
235 neigh_release(n);
236 if (IS_ERR(mn))
237 return PTR_ERR(mn);
238 n = mn;
1da177e4 239 }
dbedbe6d 240
1da177e4
LT
241 if (neigh_event_send(n, skb_res) == 0) {
242 int err;
0ed8ddf4 243 char haddr[MAX_ADDR_LEN];
0c4e8581 244
0ed8ddf4 245 neigh_ha_snapshot(haddr, n, dev);
d8b9605d
JP
246 err = dev_hard_header(skb, dev, ntohs(tc_skb_protocol(skb)),
247 haddr, NULL, skb->len);
0c4e8581 248
dbedbe6d
DM
249 if (err < 0)
250 err = -EINVAL;
251 } else {
252 err = (skb_res == NULL) ? -EAGAIN : 1;
1da177e4
LT
253 }
254 neigh_release(n);
dbedbe6d 255 return err;
1da177e4
LT
256}
257
3b04ddde 258static inline int teql_resolve(struct sk_buff *skb,
f7e57044
ED
259 struct sk_buff *skb_res,
260 struct net_device *dev,
261 struct netdev_queue *txq)
1da177e4 262{
f7e57044 263 struct dst_entry *dst = skb_dst(skb);
f7e57044
ED
264 int res;
265
46e5da40 266 if (rcu_access_pointer(txq->qdisc) == &noop_qdisc)
4f9f8311
EP
267 return -ENODEV;
268
f7e57044 269 if (!dev->header_ops || !dst)
1da177e4 270 return 0;
f7e57044
ED
271
272 rcu_read_lock();
dbedbe6d 273 res = __teql_resolve(skb, skb_res, dev, txq, dst);
f7e57044
ED
274 rcu_read_unlock();
275
276 return res;
1da177e4
LT
277}
278
6fef4c0c 279static netdev_tx_t teql_master_xmit(struct sk_buff *skb, struct net_device *dev)
1da177e4 280{
2941a486 281 struct teql_master *master = netdev_priv(dev);
1da177e4
LT
282 struct Qdisc *start, *q;
283 int busy;
284 int nores;
4e3ab47a 285 int subq = skb_get_queue_mapping(skb);
1da177e4
LT
286 struct sk_buff *skb_res = NULL;
287
288 start = master->slaves;
289
290restart:
291 nores = 0;
292 busy = 0;
293
cc7ec456
ED
294 q = start;
295 if (!q)
1da177e4
LT
296 goto drop;
297
298 do {
5ce2d488 299 struct net_device *slave = qdisc_dev(q);
61294e2e 300 struct netdev_queue *slave_txq = netdev_get_tx_queue(slave, 0);
10297b99 301
e8a0464c 302 if (slave_txq->qdisc_sleeping != q)
1da177e4 303 continue;
73466498 304 if (netif_xmit_stopped(netdev_get_tx_queue(slave, subq)) ||
f25f4e44 305 !netif_running(slave)) {
1da177e4
LT
306 busy = 1;
307 continue;
308 }
309
f7e57044 310 switch (teql_resolve(skb, skb_res, slave, slave_txq)) {
1da177e4 311 case 0:
c3f26a26 312 if (__netif_tx_trylock(slave_txq)) {
c0f84d0d
ED
313 unsigned int length = qdisc_pkt_len(skb);
314
73466498 315 if (!netif_xmit_frozen_or_stopped(slave_txq) &&
fa2dbdc2
DM
316 netdev_start_xmit(skb, slave, slave_txq, false) ==
317 NETDEV_TX_OK) {
c3f26a26 318 __netif_tx_unlock(slave_txq);
1da177e4
LT
319 master->slaves = NEXT_SLAVE(q);
320 netif_wake_queue(dev);
1ac9ad13
ED
321 master->tx_packets++;
322 master->tx_bytes += length;
6ed10654 323 return NETDEV_TX_OK;
1da177e4 324 }
c3f26a26 325 __netif_tx_unlock(slave_txq);
1da177e4 326 }
73466498 327 if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)))
1da177e4
LT
328 busy = 1;
329 break;
330 case 1:
331 master->slaves = NEXT_SLAVE(q);
6ed10654 332 return NETDEV_TX_OK;
1da177e4
LT
333 default:
334 nores = 1;
335 break;
336 }
bbe735e4 337 __skb_pull(skb, skb_network_offset(skb));
1da177e4
LT
338 } while ((q = NEXT_SLAVE(q)) != start);
339
340 if (nores && skb_res == NULL) {
341 skb_res = skb;
342 goto restart;
343 }
344
345 if (busy) {
346 netif_stop_queue(dev);
5b548140 347 return NETDEV_TX_BUSY;
1da177e4 348 }
1ac9ad13 349 master->tx_errors++;
1da177e4
LT
350
351drop:
1ac9ad13 352 master->tx_dropped++;
1da177e4 353 dev_kfree_skb(skb);
6ed10654 354 return NETDEV_TX_OK;
1da177e4
LT
355}
356
357static int teql_master_open(struct net_device *dev)
358{
cc7ec456 359 struct Qdisc *q;
2941a486 360 struct teql_master *m = netdev_priv(dev);
1da177e4 361 int mtu = 0xFFFE;
cc7ec456 362 unsigned int flags = IFF_NOARP | IFF_MULTICAST;
1da177e4
LT
363
364 if (m->slaves == NULL)
365 return -EUNATCH;
366
367 flags = FMASK;
368
369 q = m->slaves;
370 do {
5ce2d488 371 struct net_device *slave = qdisc_dev(q);
1da177e4
LT
372
373 if (slave == NULL)
374 return -EUNATCH;
375
376 if (slave->mtu < mtu)
377 mtu = slave->mtu;
378 if (slave->hard_header_len > LL_MAX_HEADER)
379 return -EINVAL;
380
381 /* If all the slaves are BROADCAST, master is BROADCAST
382 If all the slaves are PtP, master is PtP
383 Otherwise, master is NBMA.
384 */
385 if (!(slave->flags&IFF_POINTOPOINT))
386 flags &= ~IFF_POINTOPOINT;
387 if (!(slave->flags&IFF_BROADCAST))
388 flags &= ~IFF_BROADCAST;
389 if (!(slave->flags&IFF_MULTICAST))
390 flags &= ~IFF_MULTICAST;
391 } while ((q = NEXT_SLAVE(q)) != m->slaves);
392
393 m->dev->mtu = mtu;
394 m->dev->flags = (m->dev->flags&~FMASK) | flags;
395 netif_start_queue(m->dev);
396 return 0;
397}
398
399static int teql_master_close(struct net_device *dev)
400{
401 netif_stop_queue(dev);
402 return 0;
403}
404
bc1f4470 405static void teql_master_stats64(struct net_device *dev,
406 struct rtnl_link_stats64 *stats)
1ac9ad13
ED
407{
408 struct teql_master *m = netdev_priv(dev);
409
410 stats->tx_packets = m->tx_packets;
411 stats->tx_bytes = m->tx_bytes;
412 stats->tx_errors = m->tx_errors;
413 stats->tx_dropped = m->tx_dropped;
1ac9ad13
ED
414}
415
1da177e4
LT
416static int teql_master_mtu(struct net_device *dev, int new_mtu)
417{
2941a486 418 struct teql_master *m = netdev_priv(dev);
1da177e4
LT
419 struct Qdisc *q;
420
1da177e4
LT
421 q = m->slaves;
422 if (q) {
423 do {
5ce2d488 424 if (new_mtu > qdisc_dev(q)->mtu)
1da177e4 425 return -EINVAL;
cc7ec456 426 } while ((q = NEXT_SLAVE(q)) != m->slaves);
1da177e4
LT
427 }
428
429 dev->mtu = new_mtu;
430 return 0;
431}
432
61294e2e
SH
433static const struct net_device_ops teql_netdev_ops = {
434 .ndo_open = teql_master_open,
435 .ndo_stop = teql_master_close,
436 .ndo_start_xmit = teql_master_xmit,
1ac9ad13 437 .ndo_get_stats64 = teql_master_stats64,
61294e2e
SH
438 .ndo_change_mtu = teql_master_mtu,
439};
440
1da177e4
LT
441static __init void teql_master_setup(struct net_device *dev)
442{
2941a486 443 struct teql_master *master = netdev_priv(dev);
1da177e4
LT
444 struct Qdisc_ops *ops = &master->qops;
445
446 master->dev = dev;
447 ops->priv_size = sizeof(struct teql_sched_data);
10297b99 448
1da177e4
LT
449 ops->enqueue = teql_enqueue;
450 ops->dequeue = teql_dequeue;
8e3af978 451 ops->peek = teql_peek;
1da177e4
LT
452 ops->init = teql_qdisc_init;
453 ops->reset = teql_reset;
454 ops->destroy = teql_destroy;
455 ops->owner = THIS_MODULE;
456
61294e2e 457 dev->netdev_ops = &teql_netdev_ops;
1da177e4
LT
458 dev->type = ARPHRD_VOID;
459 dev->mtu = 1500;
91572088
JW
460 dev->min_mtu = 68;
461 dev->max_mtu = 65535;
1da177e4
LT
462 dev->tx_queue_len = 100;
463 dev->flags = IFF_NOARP;
464 dev->hard_header_len = LL_MAX_HEADER;
02875878 465 netif_keep_dst(dev);
1da177e4
LT
466}
467
468static LIST_HEAD(master_dev_list);
469static int max_equalizers = 1;
470module_param(max_equalizers, int, 0);
471MODULE_PARM_DESC(max_equalizers, "Max number of link equalizers");
472
473static int __init teql_init(void)
474{
475 int i;
476 int err = -ENODEV;
477
478 for (i = 0; i < max_equalizers; i++) {
479 struct net_device *dev;
480 struct teql_master *master;
481
c835a677
TG
482 dev = alloc_netdev(sizeof(struct teql_master), "teql%d",
483 NET_NAME_UNKNOWN, teql_master_setup);
1da177e4
LT
484 if (!dev) {
485 err = -ENOMEM;
486 break;
487 }
488
489 if ((err = register_netdev(dev))) {
490 free_netdev(dev);
491 break;
492 }
493
2941a486 494 master = netdev_priv(dev);
1da177e4
LT
495
496 strlcpy(master->qops.id, dev->name, IFNAMSIZ);
497 err = register_qdisc(&master->qops);
498
499 if (err) {
500 unregister_netdev(dev);
501 free_netdev(dev);
502 break;
503 }
504
505 list_add_tail(&master->master_list, &master_dev_list);
506 }
507 return i ? 0 : err;
508}
509
10297b99 510static void __exit teql_exit(void)
1da177e4
LT
511{
512 struct teql_master *master, *nxt;
513
514 list_for_each_entry_safe(master, nxt, &master_dev_list, master_list) {
515
516 list_del(&master->master_list);
517
518 unregister_qdisc(&master->qops);
519 unregister_netdev(master->dev);
520 free_netdev(master->dev);
521 }
522}
523
524module_init(teql_init);
525module_exit(teql_exit);
526
527MODULE_LICENSE("GPL");