aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2009-09-04 02:41:18 -0400
committerDavid S. Miller <davem@davemloft.net>2009-09-06 05:07:03 -0400
commitaf356afa010f3cd2c8b8fcc3bce90f7a7b7ec02a (patch)
tree302d938363bbaec3e69a58e36dbf8a304b24144c
parent5b9a9ccfad8553dbf7a9b17ba78bad70215ed0e2 (diff)
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>
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--net/core/rtnetlink.c6
-rw-r--r--net/sched/cls_api.c7
-rw-r--r--net/sched/sch_api.c41
-rw-r--r--net/sched/sch_generic.c25
5 files changed, 34 insertions, 48 deletions
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 121cbad0aae5..a44118b1b56c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -832,6 +832,9 @@ struct net_device
832 /* Number of TX queues currently active in device */ 832 /* Number of TX queues currently active in device */
833 unsigned int real_num_tx_queues; 833 unsigned int real_num_tx_queues;
834 834
835 /* root qdisc from userspace point of view */
836 struct Qdisc *qdisc;
837
835 unsigned long tx_queue_len; /* Max frames per queue allowed */ 838 unsigned long tx_queue_len; /* Max frames per queue allowed */
836 spinlock_t tx_global_lock; 839 spinlock_t tx_global_lock;
837/* 840/*
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index bbcba2a41018..eb42873f2a3a 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -606,7 +606,6 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
606 int type, u32 pid, u32 seq, u32 change, 606 int type, u32 pid, u32 seq, u32 change,
607 unsigned int flags) 607 unsigned int flags)
608{ 608{
609 struct netdev_queue *txq;
610 struct ifinfomsg *ifm; 609 struct ifinfomsg *ifm;
611 struct nlmsghdr *nlh; 610 struct nlmsghdr *nlh;
612 const struct net_device_stats *stats; 611 const struct net_device_stats *stats;
@@ -637,9 +636,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
637 if (dev->master) 636 if (dev->master)
638 NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex); 637 NLA_PUT_U32(skb, IFLA_MASTER, dev->master->ifindex);
639 638
640 txq = netdev_get_tx_queue(dev, 0); 639 if (dev->qdisc)
641 if (txq->qdisc_sleeping) 640 NLA_PUT_STRING(skb, IFLA_QDISC, dev->qdisc->ops->id);
642 NLA_PUT_STRING(skb, IFLA_QDISC, txq->qdisc_sleeping->ops->id);
643 641
644 if (dev->ifalias) 642 if (dev->ifalias)
645 NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias); 643 NLA_PUT_STRING(skb, IFLA_IFALIAS, dev->ifalias);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index bcfbdb4758c9..6a536949cdc0 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -168,8 +168,7 @@ replay:
168 168
169 /* Find qdisc */ 169 /* Find qdisc */
170 if (!parent) { 170 if (!parent) {
171 struct netdev_queue *dev_queue = netdev_get_tx_queue(dev, 0); 171 q = dev->qdisc;
172 q = dev_queue->qdisc_sleeping;
173 parent = q->handle; 172 parent = q->handle;
174 } else { 173 } else {
175 q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent)); 174 q = qdisc_lookup(dev, TC_H_MAJ(t->tcm_parent));
@@ -408,7 +407,6 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n,
408static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) 407static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
409{ 408{
410 struct net *net = sock_net(skb->sk); 409 struct net *net = sock_net(skb->sk);
411 struct netdev_queue *dev_queue;
412 int t; 410 int t;
413 int s_t; 411 int s_t;
414 struct net_device *dev; 412 struct net_device *dev;
@@ -427,9 +425,8 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
427 if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL) 425 if ((dev = dev_get_by_index(&init_net, tcm->tcm_ifindex)) == NULL)
428 return skb->len; 426 return skb->len;
429 427
430 dev_queue = netdev_get_tx_queue(dev, 0);
431 if (!tcm->tcm_parent) 428 if (!tcm->tcm_parent)
432 q = dev_queue->qdisc_sleeping; 429 q = dev->qdisc;
433 else 430 else
434 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent)); 431 q = qdisc_lookup(dev, TC_H_MAJ(tcm->tcm_parent));
435 if (!q) 432 if (!q)
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 166fcca86e7a..8aa9a0c5a9eb 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -207,7 +207,7 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
207static void qdisc_list_add(struct Qdisc *q) 207static void qdisc_list_add(struct Qdisc *q)
208{ 208{
209 if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) 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
213void qdisc_list_del(struct Qdisc *q) 213void qdisc_list_del(struct Qdisc *q)
@@ -219,17 +219,11 @@ EXPORT_SYMBOL(qdisc_list_del);
219 219
220struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) 220struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
221{ 221{
222 unsigned int i;
223 struct Qdisc *q; 222 struct Qdisc *q;
224 223
225 for (i = 0; i < dev->num_tx_queues; i++) { 224 q = qdisc_match_from_root(dev->qdisc, handle);
226 struct netdev_queue *txq = netdev_get_tx_queue(dev, i); 225 if (q)
227 struct Qdisc *txq_root = txq->qdisc_sleeping; 226 goto out;
228
229 q = qdisc_match_from_root(txq_root, handle);
230 if (q)
231 goto out;
232 }
233 227
234 q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); 228 q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle);
235out: 229out:
@@ -720,9 +714,14 @@ static int qdisc_graft(struct net_device *dev, struct Qdisc *parent,
720 if (new && i > 0) 714 if (new && i > 0)
721 atomic_inc(&new->refcnt); 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 if (dev->flags & IFF_UP) 725 if (dev->flags & IFF_UP)
727 dev_activate(dev); 726 dev_activate(dev);
728 } else { 727 } else {
@@ -974,9 +973,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
974 q = dev->rx_queue.qdisc_sleeping; 973 q = dev->rx_queue.qdisc_sleeping;
975 } 974 }
976 } else { 975 } else {
977 struct netdev_queue *dev_queue; 976 q = dev->qdisc;
978 dev_queue = netdev_get_tx_queue(dev, 0);
979 q = dev_queue->qdisc_sleeping;
980 } 977 }
981 if (!q) 978 if (!q)
982 return -ENOENT; 979 return -ENOENT;
@@ -1044,9 +1041,7 @@ replay:
1044 q = dev->rx_queue.qdisc_sleeping; 1041 q = dev->rx_queue.qdisc_sleeping;
1045 } 1042 }
1046 } else { 1043 } else {
1047 struct netdev_queue *dev_queue; 1044 q = dev->qdisc;
1048 dev_queue = netdev_get_tx_queue(dev, 0);
1049 q = dev_queue->qdisc_sleeping;
1050 } 1045 }
1051 1046
1052 /* It may be default qdisc, ignore it */ 1047 /* It may be default qdisc, ignore it */
@@ -1291,8 +1286,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
1291 s_q_idx = 0; 1286 s_q_idx = 0;
1292 q_idx = 0; 1287 q_idx = 0;
1293 1288
1294 dev_queue = netdev_get_tx_queue(dev, 0); 1289 if (tc_dump_qdisc_root(dev->qdisc, skb, cb, &q_idx, s_q_idx) < 0)
1295 if (tc_dump_qdisc_root(dev_queue->qdisc_sleeping, skb, cb, &q_idx, s_q_idx) < 0)
1296 goto done; 1290 goto done;
1297 1291
1298 dev_queue = &dev->rx_queue; 1292 dev_queue = &dev->rx_queue;
@@ -1323,7 +1317,6 @@ done:
1323static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) 1317static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1324{ 1318{
1325 struct net *net = sock_net(skb->sk); 1319 struct net *net = sock_net(skb->sk);
1326 struct netdev_queue *dev_queue;
1327 struct tcmsg *tcm = NLMSG_DATA(n); 1320 struct tcmsg *tcm = NLMSG_DATA(n);
1328 struct nlattr *tca[TCA_MAX + 1]; 1321 struct nlattr *tca[TCA_MAX + 1];
1329 struct net_device *dev; 1322 struct net_device *dev;
@@ -1361,7 +1354,6 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1361 1354
1362 /* Step 1. Determine qdisc handle X:0 */ 1355 /* Step 1. Determine qdisc handle X:0 */
1363 1356
1364 dev_queue = netdev_get_tx_queue(dev, 0);
1365 if (pid != TC_H_ROOT) { 1357 if (pid != TC_H_ROOT) {
1366 u32 qid1 = TC_H_MAJ(pid); 1358 u32 qid1 = TC_H_MAJ(pid);
1367 1359
@@ -1372,7 +1364,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1372 } else if (qid1) { 1364 } else if (qid1) {
1373 qid = qid1; 1365 qid = qid1;
1374 } else if (qid == 0) 1366 } else if (qid == 0)
1375 qid = dev_queue->qdisc_sleeping->handle; 1367 qid = dev->qdisc->handle;
1376 1368
1377 /* Now qid is genuine qdisc handle consistent 1369 /* Now qid is genuine qdisc handle consistent
1378 both with parent and child. 1370 both with parent and child.
@@ -1383,7 +1375,7 @@ static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
1383 pid = TC_H_MAKE(qid, pid); 1375 pid = TC_H_MAKE(qid, pid);
1384 } else { 1376 } else {
1385 if (qid == 0) 1377 if (qid == 0)
1386 qid = dev_queue->qdisc_sleeping->handle; 1378 qid = dev->qdisc->handle;
1387 } 1379 }
1388 1380
1389 /* OK. Locate qdisc */ 1381 /* OK. Locate qdisc */
@@ -1588,8 +1580,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
1588 s_t = cb->args[0]; 1580 s_t = cb->args[0];
1589 t = 0; 1581 t = 0;
1590 1582
1591 dev_queue = netdev_get_tx_queue(dev, 0); 1583 if (tc_dump_tclass_root(dev->qdisc, skb, tcm, cb, &t, s_t) < 0)
1592 if (tc_dump_tclass_root(dev_queue->qdisc_sleeping, skb, tcm, cb, &t, s_t) < 0)
1593 goto done; 1584 goto done;
1594 1585
1595 dev_queue = &dev->rx_queue; 1586 dev_queue = &dev->rx_queue;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6128e6f24589..a91f079fb47a 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -623,19 +623,6 @@ void qdisc_destroy(struct Qdisc *qdisc)
623} 623}
624EXPORT_SYMBOL(qdisc_destroy); 624EXPORT_SYMBOL(qdisc_destroy);
625 625
626static 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
639static void attach_one_default_qdisc(struct net_device *dev, 626static void attach_one_default_qdisc(struct net_device *dev,
640 struct netdev_queue *dev_queue, 627 struct netdev_queue *dev_queue,
641 void *_unused) 628 void *_unused)
@@ -677,6 +664,7 @@ static void transition_one_qdisc(struct net_device *dev,
677 664
678void dev_activate(struct net_device *dev) 665void dev_activate(struct net_device *dev)
679{ 666{
667 struct netdev_queue *txq;
680 int need_watchdog; 668 int need_watchdog;
681 669
682 /* No queueing discipline is attached to device; 670 /* No queueing discipline is attached to device;
@@ -685,9 +673,14 @@ void dev_activate(struct net_device *dev)
685 virtual interfaces 673 virtual interfaces
686 */ 674 */
687 675
688 if (dev_all_qdisc_sleeping_noop(dev)) 676 if (dev->qdisc == &noop_qdisc) {
689 netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); 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 if (!netif_carrier_ok(dev)) 684 if (!netif_carrier_ok(dev))
692 /* Delay activation until next carrier-on event */ 685 /* Delay activation until next carrier-on event */
693 return; 686 return;
@@ -777,6 +770,7 @@ static void dev_init_scheduler_queue(struct net_device *dev,
777 770
778void dev_init_scheduler(struct net_device *dev) 771void dev_init_scheduler(struct net_device *dev)
779{ 772{
773 dev->qdisc = &noop_qdisc;
780 netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); 774 netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc);
781 dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); 775 dev_init_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
782 776
@@ -802,5 +796,8 @@ void dev_shutdown(struct net_device *dev)
802{ 796{
803 netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); 797 netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc);
804 shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc); 798 shutdown_scheduler_queue(dev, &dev->rx_queue, &noop_qdisc);
799 qdisc_destroy(dev->qdisc);
800 dev->qdisc = &noop_qdisc;
801
805 WARN_ON(timer_pending(&dev->watchdog_timer)); 802 WARN_ON(timer_pending(&dev->watchdog_timer));
806} 803}