aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-12-11 10:54:33 -0500
committerDavid S. Miller <davem@davemloft.net>2012-12-12 00:16:47 -0500
commit1abbe1394a84c10919e32242318e715b04d7e33b (patch)
treeec3930413339cd3c77498c133b41475737494279
parentcae49ede00ec3d0cda290b03fee55b72b49efc11 (diff)
pkt_sched: avoid requeues if possible
With BQL being deployed, we can more likely have following behavior : We dequeue a packet from qdisc in dequeue_skb(), then we realize target tx queue is in XOFF state in sch_direct_xmit(), and we have to hold the skb into gso_skb for later. This shows in stats (tc -s qdisc dev eth0) as requeues. Problem of these requeues is that high priority packets can not be dequeued as long as this (possibly low prio and big TSO packet) is not removed from gso_skb. At 1Gbps speed, a full size TSO packet is 500 us of extra latency. In some cases, we know that all packets dequeued from a qdisc are for a particular and known txq : - If device is non multi queue - For all MQ/MQPRIO slave qdiscs This patch introduces a new qdisc flag, TCQ_F_ONETXQUEUE to mark this capability, so that dequeue_skb() is allowed to dequeue a packet only if the associated txq is not stopped. This indeed reduce latencies for high prio packets (or improve fairness with sfq/fq_codel), and almost remove qdisc 'requeues'. Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Jamal Hadi Salim <jhs@mojatatu.com> Cc: John Fastabend <john.r.fastabend@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/sch_generic.h7
-rw-r--r--net/sched/sch_api.c2
-rw-r--r--net/sched/sch_generic.c11
-rw-r--r--net/sched/sch_mq.c4
-rw-r--r--net/sched/sch_mqprio.c4
5 files changed, 22 insertions, 6 deletions
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 4616f468d59..1540f9c2fcf 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -50,6 +50,13 @@ struct Qdisc {
50#define TCQ_F_INGRESS 2 50#define TCQ_F_INGRESS 2
51#define TCQ_F_CAN_BYPASS 4 51#define TCQ_F_CAN_BYPASS 4
52#define TCQ_F_MQROOT 8 52#define TCQ_F_MQROOT 8
53#define TCQ_F_ONETXQUEUE 0x10 /* dequeue_skb() can assume all skbs are for
54 * q->dev_queue : It can test
55 * netif_xmit_frozen_or_stopped() before
56 * dequeueing next packet.
57 * Its true for MQ/MQPRIO slaves, or non
58 * multiqueue device.
59 */
53#define TCQ_F_WARN_NONWC (1 << 16) 60#define TCQ_F_WARN_NONWC (1 << 16)
54 int padded; 61 int padded;
55 const struct Qdisc_ops *ops; 62 const struct Qdisc_ops *ops;
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 4799c4840c1..d84f7e734cd 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -833,6 +833,8 @@ qdisc_create(struct net_device *dev, struct netdev_queue *dev_queue,
833 goto err_out3; 833 goto err_out3;
834 } 834 }
835 lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock); 835 lockdep_set_class(qdisc_lock(sch), &qdisc_tx_lock);
836 if (!netif_is_multiqueue(dev))
837 sch->flags |= TCQ_F_ONETXQUEUE;
836 } 838 }
837 839
838 sch->handle = handle; 840 sch->handle = handle;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index aefc1504dc8..5d81a447851 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -53,20 +53,19 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
53static inline struct sk_buff *dequeue_skb(struct Qdisc *q) 53static inline struct sk_buff *dequeue_skb(struct Qdisc *q)
54{ 54{
55 struct sk_buff *skb = q->gso_skb; 55 struct sk_buff *skb = q->gso_skb;
56 const struct netdev_queue *txq = q->dev_queue;
56 57
57 if (unlikely(skb)) { 58 if (unlikely(skb)) {
58 struct net_device *dev = qdisc_dev(q);
59 struct netdev_queue *txq;
60
61 /* check the reason of requeuing without tx lock first */ 59 /* check the reason of requeuing without tx lock first */
62 txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); 60 txq = netdev_get_tx_queue(txq->dev, skb_get_queue_mapping(skb));
63 if (!netif_xmit_frozen_or_stopped(txq)) { 61 if (!netif_xmit_frozen_or_stopped(txq)) {
64 q->gso_skb = NULL; 62 q->gso_skb = NULL;
65 q->q.qlen--; 63 q->q.qlen--;
66 } else 64 } else
67 skb = NULL; 65 skb = NULL;
68 } else { 66 } else {
69 skb = q->dequeue(q); 67 if (!(q->flags & TCQ_F_ONETXQUEUE) || !netif_xmit_frozen_or_stopped(txq))
68 skb = q->dequeue(q);
70 } 69 }
71 70
72 return skb; 71 return skb;
@@ -686,6 +685,8 @@ static void attach_one_default_qdisc(struct net_device *dev,
686 netdev_info(dev, "activation failed\n"); 685 netdev_info(dev, "activation failed\n");
687 return; 686 return;
688 } 687 }
688 if (!netif_is_multiqueue(dev))
689 qdisc->flags |= TCQ_F_ONETXQUEUE;
689 } 690 }
690 dev_queue->qdisc_sleeping = qdisc; 691 dev_queue->qdisc_sleeping = qdisc;
691} 692}
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
index 0a4b2f9a009..5da78a19ac9 100644
--- a/net/sched/sch_mq.c
+++ b/net/sched/sch_mq.c
@@ -63,6 +63,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
63 if (qdisc == NULL) 63 if (qdisc == NULL)
64 goto err; 64 goto err;
65 priv->qdiscs[ntx] = qdisc; 65 priv->qdiscs[ntx] = qdisc;
66 qdisc->flags |= TCQ_F_ONETXQUEUE;
66 } 67 }
67 68
68 sch->flags |= TCQ_F_MQROOT; 69 sch->flags |= TCQ_F_MQROOT;
@@ -150,7 +151,8 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
150 dev_deactivate(dev); 151 dev_deactivate(dev);
151 152
152 *old = dev_graft_qdisc(dev_queue, new); 153 *old = dev_graft_qdisc(dev_queue, new);
153 154 if (new)
155 new->flags |= TCQ_F_ONETXQUEUE;
154 if (dev->flags & IFF_UP) 156 if (dev->flags & IFF_UP)
155 dev_activate(dev); 157 dev_activate(dev);
156 return 0; 158 return 0;
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index d1831ca966d..accec33c454 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -132,6 +132,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
132 goto err; 132 goto err;
133 } 133 }
134 priv->qdiscs[i] = qdisc; 134 priv->qdiscs[i] = qdisc;
135 qdisc->flags |= TCQ_F_ONETXQUEUE;
135 } 136 }
136 137
137 /* If the mqprio options indicate that hardware should own 138 /* If the mqprio options indicate that hardware should own
@@ -205,6 +206,9 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
205 206
206 *old = dev_graft_qdisc(dev_queue, new); 207 *old = dev_graft_qdisc(dev_queue, new);
207 208
209 if (new)
210 new->flags |= TCQ_F_ONETXQUEUE;
211
208 if (dev->flags & IFF_UP) 212 if (dev->flags & IFF_UP)
209 dev_activate(dev); 213 dev_activate(dev);
210 214