From: John Fastabend <john.fastabend@gmail.com>
To: daniel@iogearbox.net, eric.dumazet@gmail.com, jhs@mojatatu.com,
aduyck@mirantis.com, brouer@redhat.com, davem@davemloft.net
Cc: john.r.fastabend@intel.com, netdev@vger.kernel.org,
john.fastabend@gmail.com
Subject: [RFC PATCH 05/12] net: sched: per cpu gso handlers
Date: Wed, 30 Dec 2015 09:52:49 -0800 [thread overview]
Message-ID: <20151230175249.26257.99.stgit@john-Precision-Tower-5810> (raw)
In-Reply-To: <20151230175000.26257.41532.stgit@john-Precision-Tower-5810>
The net sched infrastructure has a gso ptr that points to skb structs
that have failed to be enqueued by the device driver.
This can happen when multiple cores try to push a skb onto the same
underlying hardware queue resulting in lock contention. This case is
handled by a cpu collision handler handle_dev_cpu_collision(). Another
case occurs when the stack overruns the drivers low level tx queues
capacity. Ideally these should be a rare occurrence in a well-tuned
system but they do happen.
To handle this in the lockless case use a per cpu gso field to park
the skb until the conflict can be resolved. Note at this point the
skb has already been popped off the qdisc so it has to be handled
by the infrastructure.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
---
include/net/sch_generic.h | 36 ++++++++++++++++++++++++++++++++++++
net/sched/sch_generic.c | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 9966c17..aa39dd4 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -44,6 +44,10 @@ struct qdisc_size_table {
u16 data[];
};
+struct gso_cell {
+ struct sk_buff *skb;
+};
+
struct Qdisc {
int (*enqueue)(struct sk_buff *skb, struct Qdisc *dev);
struct sk_buff * (*dequeue)(struct Qdisc *dev);
@@ -88,6 +92,7 @@ struct Qdisc {
struct Qdisc *next_sched;
struct sk_buff *gso_skb;
+ struct gso_cell __percpu *gso_cpu_skb;
/*
* For performance sake on SMP, we put highly modified fields at the end
*/
@@ -699,6 +704,22 @@ static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch)
return sch->gso_skb;
}
+static inline struct sk_buff *qdisc_peek_dequeued_cpu(struct Qdisc *sch)
+{
+ struct gso_cell *gso = this_cpu_ptr(sch->gso_cpu_skb);
+
+ if (!gso->skb) {
+ struct sk_buff *skb = sch->dequeue(sch);
+
+ if (skb) {
+ gso->skb = skb;
+ qdisc_qstats_cpu_qlen_inc(sch);
+ }
+ }
+
+ return gso->skb;
+}
+
/* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */
static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch)
{
@@ -714,6 +735,21 @@ static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch)
return skb;
}
+static inline struct sk_buff *qdisc_dequeue_peeked_skb(struct Qdisc *sch)
+{
+ struct gso_cell *gso = this_cpu_ptr(sch->gso_cpu_skb);
+ struct sk_buff *skb = gso->skb;
+
+ if (skb) {
+ gso->skb = NULL;
+ qdisc_qstats_cpu_qlen_dec(sch);
+ } else {
+ skb = sch->dequeue(sch);
+ }
+
+ return skb;
+}
+
static inline void __qdisc_reset_queue(struct Qdisc *sch,
struct sk_buff_head *list)
{
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 37dfa4a..9aeb51f 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -44,8 +44,7 @@ EXPORT_SYMBOL(default_qdisc_ops);
* - ingress filtering is also serialized via qdisc root lock
* - updates to tree and tree walking are only done under the rtnl mutex.
*/
-
-static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
+static inline int __dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
{
q->gso_skb = skb;
q->qstats.requeues++;
@@ -55,6 +54,24 @@ static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
return 0;
}
+static inline int dev_requeue_cpu_skb(struct sk_buff *skb, struct Qdisc *q)
+{
+ this_cpu_ptr(q->gso_cpu_skb)->skb = skb;
+ qdisc_qstats_cpu_requeues_inc(q);
+ qdisc_qstats_cpu_qlen_inc(q);
+ __netif_schedule(q);
+
+ return 0;
+}
+
+static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q)
+{
+ if (q->flags & TCQ_F_NOLOCK)
+ return __dev_requeue_skb(skb, q);
+ else
+ return dev_requeue_cpu_skb(skb, q);
+}
+
static void try_bulk_dequeue_skb(struct Qdisc *q,
struct sk_buff *skb,
const struct netdev_queue *txq,
@@ -666,6 +683,19 @@ static void qdisc_rcu_free(struct rcu_head *head)
free_percpu(qdisc->cpu_qstats);
}
+ if (qdisc->gso_cpu_skb) {
+ int i;
+
+ for_each_possible_cpu(i) {
+ struct gso_cell *cell;
+
+ cell = per_cpu_ptr(qdisc->gso_cpu_skb, i);
+ kfree_skb_list(cell->skb);
+ }
+
+ free_percpu(qdisc->gso_cpu_skb);
+ }
+
kfree((char *) qdisc - qdisc->padded);
}
next prev parent reply other threads:[~2015-12-30 17:53 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-30 17:50 [RFC PATCH 00/12] drop the qdisc lock for pfifo_fast/mq John Fastabend
2015-12-30 17:51 ` [RFC PATCH 01/12] lib: array based lock free queue John Fastabend
2016-01-13 19:28 ` Jesper Dangaard Brouer
2015-12-30 17:51 ` [RFC PATCH 02/12] net: sched: free per cpu bstats John Fastabend
2016-01-04 15:21 ` Daniel Borkmann
2016-01-04 17:32 ` Eric Dumazet
2016-01-04 18:08 ` John Fastabend
2015-12-30 17:51 ` [RFC PATCH 03/12] net: sched: allow qdiscs to handle locking John Fastabend
2015-12-30 17:52 ` [RFC PATCH 04/12] net: sched: provide per cpu qstat helpers John Fastabend
2015-12-30 17:52 ` John Fastabend [this message]
2015-12-30 20:26 ` [RFC PATCH 05/12] net: sched: per cpu gso handlers Jesper Dangaard Brouer
2015-12-30 20:42 ` John Fastabend
2015-12-30 17:53 ` [RFC PATCH 06/12] net: sched: support qdisc_reset on NOLOCK qdisc John Fastabend
2016-01-01 2:30 ` Alexei Starovoitov
2016-01-03 19:37 ` John Fastabend
2016-01-13 16:20 ` David Miller
2016-01-13 18:03 ` John Fastabend
2016-01-15 19:44 ` David Miller
2015-12-30 17:53 ` [RFC PATCH 07/12] net: sched: qdisc_qlen for per cpu logic John Fastabend
2015-12-30 17:53 ` [RFC PATCH 08/12] net: sched: a dflt qdisc may be used with per cpu stats John Fastabend
2015-12-30 17:54 ` [RFC PATCH 09/12] net: sched: pfifo_fast use alf_queue John Fastabend
2016-01-13 16:24 ` David Miller
2016-01-13 18:18 ` John Fastabend
2015-12-30 17:54 ` [RFC PATCH 10/12] net: sched: helper to sum qlen John Fastabend
2015-12-30 17:55 ` [RFC PATCH 11/12] net: sched: add support for TCQ_F_NOLOCK subqueues to sch_mq John Fastabend
2015-12-30 17:55 ` [RFC PATCH 12/12] net: sched: pfifo_fast new option to deque multiple pkts John Fastabend
2015-12-30 18:13 ` John Fastabend
2016-01-06 13:14 ` [RFC PATCH 00/12] drop the qdisc lock for pfifo_fast/mq Jamal Hadi Salim
2016-01-07 23:30 ` John Fastabend
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20151230175249.26257.99.stgit@john-Precision-Tower-5810 \
--to=john.fastabend@gmail.com \
--cc=aduyck@mirantis.com \
--cc=brouer@redhat.com \
--cc=daniel@iogearbox.net \
--cc=davem@davemloft.net \
--cc=eric.dumazet@gmail.com \
--cc=jhs@mojatatu.com \
--cc=john.r.fastabend@intel.com \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox