Commit af356afa010f3cd2c8b8fcc3bce90f7a7b7ec02a

Authored by Patrick McHardy
Committed by David S. Miller
1 parent 5b9a9ccfad

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);
... ... @@ -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)
... ... @@ -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 }