Commit af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02a
Committed by
David S. Miller
1 parent
5b9a9ccfad
Exists in
master
and in
7 other branches
net_sched: reintroduce dev->qdisc for use by sch_api
Currently the multiqueue integration with the qdisc API suffers from a few problems: - with multiple queues, all root qdiscs use the same handle. This means they can't be exposed to userspace in a backwards compatible fashion. - all API operations always refer to queue number 0. Newly created qdiscs are automatically shared between all queues, its not possible to address individual queues or restore multiqueue behaviour once a shared qdisc has been attached. - Dumps only contain the root qdisc of queue 0, in case of non-shared qdiscs this means the statistics are incomplete. This patch reintroduces dev->qdisc, which points to the (single) root qdisc from userspace's point of view. Currently it either points to the first (non-shared) default qdisc, or a qdisc shared between all queues. The following patches will introduce a classful dummy qdisc, which will be used as root qdisc and contain the per-queue qdiscs as children. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 5 changed files with 34 additions and 48 deletions Side-by-side Diff
include/linux/netdevice.h
... | ... | @@ -832,6 +832,9 @@ |
832 | 832 | /* Number of TX queues currently active in device */ |
833 | 833 | unsigned int real_num_tx_queues; |
834 | 834 | |
835 | + /* root qdisc from userspace point of view */ | |
836 | + struct Qdisc *qdisc; | |
837 | + | |
835 | 838 | unsigned long tx_queue_len; /* Max frames per queue allowed */ |
836 | 839 | spinlock_t tx_global_lock; |
837 | 840 | /* |
net/core/rtnetlink.c
... | ... | @@ -606,7 +606,6 @@ |
606 | 606 | int type, u32 pid, u32 seq, u32 change, |
607 | 607 | unsigned int flags) |
608 | 608 | { |
609 | - struct netdev_queue *txq; | |
610 | 609 | struct ifinfomsg *ifm; |
611 | 610 | struct nlmsghdr *nlh; |
612 | 611 | const struct net_device_stats *stats; |
... | ... | @@ -637,9 +636,8 @@ |
637 | 636 | if (dev->master) |
638 | 637 | NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); |
639 | 638 | |
640 | - txq = netdev_get_tx_queue(dev, 0); | |
641 | - if (txq->qdisc_sleeping) | |
642 | - NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id); | |
639 | + if (dev->qdisc) | |
640 | + NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc->ops->id); | |
643 | 641 | |
644 | 642 | if (dev->ifalias) |
645 | 643 | NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias); |
net/sched/cls_api.c
... | ... | @@ -168,8 +168,7 @@ |
168 | 168 | |
169 | 169 | /* Find qdisc */ |
170 | 170 | if (!parent) { |
171 | - struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); | |
172 | - q = dev_queue->qdisc_sleeping; | |
171 | + q = dev->qdisc; | |
173 | 172 | parent = q->handle; |
174 | 173 | } else { |
175 | 174 | q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); |
... | ... | @@ -408,7 +407,6 @@ |
408 | 407 | static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) |
409 | 408 | { |
410 | 409 | struct net *net = sock_net(skb->sk); |
411 | - struct netdev_queue *dev_queue; | |
412 | 410 | int t; |
413 | 411 | int s_t; |
414 | 412 | struct net_device *dev; |
415 | 413 | |
... | ... | @@ -427,9 +425,8 @@ |
427 | 425 | if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) |
428 | 426 | return skb->len; |
429 | 427 | |
430 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
431 | 428 | if (!tcm->tcm_parent) |
432 | - q = dev_queue->qdisc_sleeping; | |
429 | + q = dev->qdisc; | |
433 | 430 | else |
434 | 431 | q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); |
435 | 432 | if (!q) |
net/sched/sch_api.c
... | ... | @@ -207,7 +207,7 @@ |
207 | 207 | static void qdisc_list_add(struct Qdisc *q) |
208 | 208 | { |
209 | 209 | if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) |
210 | - list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); | |
210 | + list_add_tail(&q->list, &qdisc_dev(q)->qdisc->list); | |
211 | 211 | } |
212 | 212 | |
213 | 213 | void qdisc_list_del(struct Qdisc *q) |
214 | 214 | |
215 | 215 | |
... | ... | @@ -219,18 +219,12 @@ |
219 | 219 | |
220 | 220 | struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) |
221 | 221 | { |
222 | - unsigned int i; | |
223 | 222 | struct Qdisc *q; |
224 | 223 | |
225 | - for (i = 0; i < dev->num_tx_queues; i++) { | |
226 | - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | |
227 | - struct Qdisc *txq_root = txq->qdisc_sleeping; | |
224 | + q = qdisc_match_from_root(dev->qdisc, handle); | |
225 | + if (q) | |
226 | + goto out; | |
228 | 227 | |
229 | - q = qdisc_match_from_root(txq_root, handle); | |
230 | - if (q) | |
231 | - goto out; | |
232 | - } | |
233 | - | |
234 | 228 | q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); |
235 | 229 | out: |
236 | 230 | return q; |
237 | 231 | |
... | ... | @@ -720,9 +714,14 @@ |
720 | 714 | if (new && i > 0) |
721 | 715 | atomic_inc(&new->refcnt); |
722 | 716 | |
723 | - notify_and_destroy(skb, n, classid, old, new); | |
717 | + qdisc_destroy(old); | |
724 | 718 | } |
725 | 719 | |
720 | + notify_and_destroy(skb, n, classid, dev->qdisc, new); | |
721 | + if (new) | |
722 | + atomic_inc(&new->refcnt); | |
723 | + dev->qdisc = new ? : &noop_qdisc; | |
724 | + | |
726 | 725 | if (dev->flags & IFF_UP) |
727 | 726 | dev_activate(dev); |
728 | 727 | } else { |
... | ... | @@ -974,9 +973,7 @@ |
974 | 973 | q = dev->rx_queue.qdisc_sleeping; |
975 | 974 | } |
976 | 975 | } else { |
977 | - struct netdev_queue *dev_queue; | |
978 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
979 | - q = dev_queue->qdisc_sleeping; | |
976 | + q = dev->qdisc; | |
980 | 977 | } |
981 | 978 | if (!q) |
982 | 979 | return -ENOENT; |
... | ... | @@ -1044,9 +1041,7 @@ |
1044 | 1041 | q = dev->rx_queue.qdisc_sleeping; |
1045 | 1042 | } |
1046 | 1043 | } else { |
1047 | - struct netdev_queue *dev_queue; | |
1048 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
1049 | - q = dev_queue->qdisc_sleeping; | |
1044 | + q = dev->qdisc; | |
1050 | 1045 | } |
1051 | 1046 | |
1052 | 1047 | /* It may be default qdisc, ignore it */ |
... | ... | @@ -1291,8 +1286,7 @@ |
1291 | 1286 | s_q_idx = 0; |
1292 | 1287 | q_idx = 0; |
1293 | 1288 | |
1294 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
1295 | - if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0) | |
1289 | + if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0) | |
1296 | 1290 | goto done; |
1297 | 1291 | |
1298 | 1292 | dev_queue = &dev->rx_queue; |
... | ... | @@ -1323,7 +1317,6 @@ |
1323 | 1317 | static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) |
1324 | 1318 | { |
1325 | 1319 | struct net *net = sock_net(skb->sk); |
1326 | - struct netdev_queue *dev_queue; | |
1327 | 1320 | struct tcmsg *tcm = NLMSG_DATA(n); |
1328 | 1321 | struct nlattr *tca[TCA_MAX + 1]; |
1329 | 1322 | struct net_device *dev; |
... | ... | @@ -1361,7 +1354,6 @@ |
1361 | 1354 | |
1362 | 1355 | /* Step 1. Determine qdisc handle X:0 */ |
1363 | 1356 | |
1364 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
1365 | 1357 | if (pid != TC_H_ROOT) { |
1366 | 1358 | u32 qid1 = TC_H_MAJ(pid); |
1367 | 1359 | |
... | ... | @@ -1372,7 +1364,7 @@ |
1372 | 1364 | } else if (qid1) { |
1373 | 1365 | qid = qid1; |
1374 | 1366 | } else if (qid == 0) |
1375 | - qid = dev_queue->qdisc_sleeping->handle; | |
1367 | + qid = dev->qdisc->handle; | |
1376 | 1368 | |
1377 | 1369 | /* Now qid is genuine qdisc handle consistent |
1378 | 1370 | both with parent and child. |
... | ... | @@ -1383,7 +1375,7 @@ |
1383 | 1375 | pid = TC_H_MAKE(qid, pid); |
1384 | 1376 | } else { |
1385 | 1377 | if (qid == 0) |
1386 | - qid = dev_queue->qdisc_sleeping->handle; | |
1378 | + qid = dev->qdisc->handle; | |
1387 | 1379 | } |
1388 | 1380 | |
1389 | 1381 | /* OK. Locate qdisc */ |
... | ... | @@ -1588,8 +1580,7 @@ |
1588 | 1580 | s_t = cb->args[0]; |
1589 | 1581 | t = 0; |
1590 | 1582 | |
1591 | - dev_queue = netdev_get_tx_queue(dev, 0); | |
1592 | - if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0) | |
1583 | + if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0) | |
1593 | 1584 | goto done; |
1594 | 1585 | |
1595 | 1586 | dev_queue = &dev->rx_queue; |
net/sched/sch_generic.c
... | ... | @@ -623,19 +623,6 @@ |
623 | 623 | } |
624 | 624 | EXPORT_SYMBOL(qdisc_destroy); |
625 | 625 | |
626 | -static bool dev_all_qdisc_sleeping_noop(struct net_device *dev) | |
627 | -{ | |
628 | - unsigned int i; | |
629 | - | |
630 | - for (i = 0; i < dev->num_tx_queues; i++) { | |
631 | - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); | |
632 | - | |
633 | - if (txq->qdisc_sleeping != &noop_qdisc) | |
634 | - return false; | |
635 | - } | |
636 | - return true; | |
637 | -} | |
638 | - | |
639 | 626 | static void attach_one_default_qdisc(struct net_device *dev, |
640 | 627 | struct netdev_queue *dev_queue, |
641 | 628 | void *_unused) |
... | ... | @@ -677,6 +664,7 @@ |
677 | 664 | |
678 | 665 | void dev_activate(struct net_device *dev) |
679 | 666 | { |
667 | + struct netdev_queue *txq; | |
680 | 668 | int need_watchdog; |
681 | 669 | |
682 | 670 | /* No queueing discipline is attached to device; |
683 | 671 | |
... | ... | @@ -685,9 +673,14 @@ |
685 | 673 | virtual interfaces |
686 | 674 | */ |
687 | 675 | |
688 | - if (dev_all_qdisc_sleeping_noop(dev)) | |
676 | + if (dev->qdisc == &noop_qdisc) { | |
689 | 677 | netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); |
690 | 678 | |
679 | + txq = netdev_get_tx_queue(dev, 0); | |
680 | + dev->qdisc = txq->qdisc_sleeping; | |
681 | + atomic_inc(&dev->qdisc->refcnt); | |
682 | + } | |
683 | + | |
691 | 684 | if (!netif_carrier_ok(dev)) |
692 | 685 | /* Delay activation until next carrier-on event */ |
693 | 686 | return; |
... | ... | @@ -777,6 +770,7 @@ |
777 | 770 | |
778 | 771 | void dev_init_scheduler(struct net_device *dev) |
779 | 772 | { |
773 | + dev->qdisc = &noop_qdisc; | |
780 | 774 | netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); |
781 | 775 | dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); |
782 | 776 | |
... | ... | @@ -802,6 +796,9 @@ |
802 | 796 | { |
803 | 797 | netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); |
804 | 798 | shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); |
799 | + qdisc_destroy(dev->qdisc); | |
800 | + dev->qdisc = &noop_qdisc; | |
801 | + | |
805 | 802 | WARN_ON(timer_pending(&dev->watchdog_timer)); |
806 | 803 | } |