net/fq_impl: bulk-free packets from a flow on overmemory
authorFelix Fietkau <nbd@nbd.name>
Fri, 18 Dec 2020 18:47:13 +0000 (19:47 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 21 Jan 2021 12:33:15 +0000 (13:33 +0100)
This is similar to what sch_fq_codel does. It also amortizes the worst
case cost of a follow-up patch that changes the selection of the biggest
flow for dropping packets

Signed-off-by: Felix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20201218184718.93650-1-nbd@nbd.name
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/fq_impl.h

index e73d74d2fabfbadd44c2611a2ea71576725fb68c..06d2a79233c9e9964d45a20cdffd2bae5887f2db 100644 (file)
 
 /* functions that are embedded into includer */
 
+
+static void
+__fq_adjust_removal(struct fq *fq, struct fq_flow *flow, unsigned int packets,
+                   unsigned int bytes, unsigned int truesize)
+{
+       struct fq_tin *tin = flow->tin;
+
+       tin->backlog_bytes -= bytes;
+       tin->backlog_packets -= packets;
+       flow->backlog -= bytes;
+       fq->backlog -= packets;
+       fq->memory_usage -= truesize;
+}
+
 static void fq_adjust_removal(struct fq *fq,
                              struct fq_flow *flow,
                              struct sk_buff *skb)
 {
-       struct fq_tin *tin = flow->tin;
-
-       tin->backlog_bytes -= skb->len;
-       tin->backlog_packets--;
-       flow->backlog -= skb->len;
-       fq->backlog--;
-       fq->memory_usage -= skb->truesize;
+       __fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize);
 }
 
 static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
@@ -59,6 +67,34 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq,
        return skb;
 }
 
+static int fq_flow_drop(struct fq *fq, struct fq_flow *flow,
+                       fq_skb_free_t free_func)
+{
+       unsigned int packets = 0, bytes = 0, truesize = 0;
+       struct fq_tin *tin = flow->tin;
+       struct sk_buff *skb;
+       int pending;
+
+       lockdep_assert_held(&fq->lock);
+
+       pending = min_t(int, 32, skb_queue_len(&flow->queue) / 2);
+       do {
+               skb = __skb_dequeue(&flow->queue);
+               if (!skb)
+                       break;
+
+               packets++;
+               bytes += skb->len;
+               truesize += skb->truesize;
+               free_func(fq, tin, flow, skb);
+       } while (packets < pending);
+
+       __fq_adjust_removal(fq, flow, packets, bytes, truesize);
+       fq_rejigger_backlog(fq, flow);
+
+       return packets;
+}
+
 static struct sk_buff *fq_tin_dequeue(struct fq *fq,
                                      struct fq_tin *tin,
                                      fq_tin_dequeue_t dequeue_func)
@@ -190,12 +226,9 @@ static void fq_tin_enqueue(struct fq *fq,
                if (!flow)
                        return;
 
-               skb = fq_flow_dequeue(fq, flow);
-               if (!skb)
+               if (!fq_flow_drop(fq, flow, free_func))
                        return;
 
-               free_func(fq, flow->tin, flow, skb);
-
                flow->tin->overlimit++;
                fq->overlimit++;
                if (oom) {