From: Felix Fietkau Date: Wed, 25 Nov 2020 18:03:46 +0100 Subject: [PATCH] net/fq_impl: bulk-free packets from a flow on overmemory 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 --- --- a/include/net/fq_impl.h +++ b/include/net/fq_impl.h @@ -11,17 +11,25 @@ /* 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(s 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) {