mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net_sched: sch_cake: Add drop reasons
Add three qdisc-specific drop reasons and use them in sch_cake:
 1) SKB_DROP_REASON_QDISC_OVERLIMIT
    Whenever the total queue limit for a qdisc instance is exceeded
    and a packet is dropped to make room.
 2) SKB_DROP_REASON_QDISC_CONGESTED
    Whenever a packet is dropped by the qdisc AQM algorithm because
    congestion is detected.
 3) SKB_DROP_REASON_CAKE_FLOOD
    Whenever a packet is dropped by the flood protection part of the
    CAKE AQM algorithm (BLUE).
Also use the existing SKB_DROP_REASON_QUEUE_PURGE in cake_clear_tin().
Reasons show up as:
perf record -a -e skb:kfree_skb sleep 1; perf script
          iperf3     665 [005]   848.656964: skb:kfree_skb: skbaddr=0xffff98168a333500 rx_sk=(nil) protocol=34525 location=__dev_queue_xmit+0x10f0 reason: QDISC_OVERLIMIT
         swapper       0 [001]   909.166055: skb:kfree_skb: skbaddr=0xffff98168280cee0 rx_sk=(nil) protocol=34525 location=cake_dequeue+0x5ef reason: QDISC_CONGESTED
Reviewed-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Acked-by: Dave Taht <dave.taht@gmail.com>
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://patch.msgid.link/20241211-cake-drop-reason-v2-1-920afadf4d1b@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
			
			
This commit is contained in:
		
							parent
							
								
									5098462fba
								
							
						
					
					
						commit
						a42d71e322
					
				
					 2 changed files with 41 additions and 20 deletions
				
			
		| 
						 | 
					@ -58,6 +58,9 @@
 | 
				
			||||||
	FN(TC_EGRESS)			\
 | 
						FN(TC_EGRESS)			\
 | 
				
			||||||
	FN(SECURITY_HOOK)		\
 | 
						FN(SECURITY_HOOK)		\
 | 
				
			||||||
	FN(QDISC_DROP)			\
 | 
						FN(QDISC_DROP)			\
 | 
				
			||||||
 | 
						FN(QDISC_OVERLIMIT)		\
 | 
				
			||||||
 | 
						FN(QDISC_CONGESTED)		\
 | 
				
			||||||
 | 
						FN(CAKE_FLOOD)			\
 | 
				
			||||||
	FN(FQ_BAND_LIMIT)		\
 | 
						FN(FQ_BAND_LIMIT)		\
 | 
				
			||||||
	FN(FQ_HORIZON_LIMIT)		\
 | 
						FN(FQ_HORIZON_LIMIT)		\
 | 
				
			||||||
	FN(FQ_FLOW_LIMIT)		\
 | 
						FN(FQ_FLOW_LIMIT)		\
 | 
				
			||||||
| 
						 | 
					@ -314,6 +317,21 @@ enum skb_drop_reason {
 | 
				
			||||||
	 * failed to enqueue to current qdisc)
 | 
						 * failed to enqueue to current qdisc)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	SKB_DROP_REASON_QDISC_DROP,
 | 
						SKB_DROP_REASON_QDISC_DROP,
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @SKB_DROP_REASON_QDISC_OVERLIMIT: dropped by qdisc when a qdisc
 | 
				
			||||||
 | 
						 * instance exceeds its total buffer size limit.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						SKB_DROP_REASON_QDISC_OVERLIMIT,
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @SKB_DROP_REASON_QDISC_CONGESTED: dropped by a qdisc AQM algorithm
 | 
				
			||||||
 | 
						 * due to congestion.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						SKB_DROP_REASON_QDISC_CONGESTED,
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * @SKB_DROP_REASON_CAKE_FLOOD: dropped by the flood protection part of
 | 
				
			||||||
 | 
						 * CAKE qdisc AQM algorithm (BLUE).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						SKB_DROP_REASON_CAKE_FLOOD,
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * @SKB_DROP_REASON_FQ_BAND_LIMIT: dropped by fq qdisc when per band
 | 
						 * @SKB_DROP_REASON_FQ_BAND_LIMIT: dropped by fq qdisc when per band
 | 
				
			||||||
	 * limit is reached.
 | 
						 * limit is reached.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -484,13 +484,14 @@ static bool cobalt_queue_empty(struct cobalt_vars *vars,
 | 
				
			||||||
/* Call this with a freshly dequeued packet for possible congestion marking.
 | 
					/* Call this with a freshly dequeued packet for possible congestion marking.
 | 
				
			||||||
 * Returns true as an instruction to drop the packet, false for delivery.
 | 
					 * Returns true as an instruction to drop the packet, false for delivery.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static bool cobalt_should_drop(struct cobalt_vars *vars,
 | 
					static enum skb_drop_reason cobalt_should_drop(struct cobalt_vars *vars,
 | 
				
			||||||
			       struct cobalt_params *p,
 | 
										       struct cobalt_params *p,
 | 
				
			||||||
			       ktime_t now,
 | 
										       ktime_t now,
 | 
				
			||||||
			       struct sk_buff *skb,
 | 
										       struct sk_buff *skb,
 | 
				
			||||||
			       u32 bulk_flows)
 | 
										       u32 bulk_flows)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool next_due, over_target, drop = false;
 | 
						enum skb_drop_reason reason = SKB_NOT_DROPPED_YET;
 | 
				
			||||||
 | 
						bool next_due, over_target;
 | 
				
			||||||
	ktime_t schedule;
 | 
						ktime_t schedule;
 | 
				
			||||||
	u64 sojourn;
 | 
						u64 sojourn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -533,7 +534,8 @@ static bool cobalt_should_drop(struct cobalt_vars *vars,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (next_due && vars->dropping) {
 | 
						if (next_due && vars->dropping) {
 | 
				
			||||||
		/* Use ECN mark if possible, otherwise drop */
 | 
							/* Use ECN mark if possible, otherwise drop */
 | 
				
			||||||
		drop = !(vars->ecn_marked = INET_ECN_set_ce(skb));
 | 
							if (!(vars->ecn_marked = INET_ECN_set_ce(skb)))
 | 
				
			||||||
 | 
								reason = SKB_DROP_REASON_QDISC_CONGESTED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		vars->count++;
 | 
							vars->count++;
 | 
				
			||||||
		if (!vars->count)
 | 
							if (!vars->count)
 | 
				
			||||||
| 
						 | 
					@ -556,16 +558,17 @@ static bool cobalt_should_drop(struct cobalt_vars *vars,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Simple BLUE implementation.  Lack of ECN is deliberate. */
 | 
						/* Simple BLUE implementation.  Lack of ECN is deliberate. */
 | 
				
			||||||
	if (vars->p_drop)
 | 
						if (vars->p_drop && reason == SKB_NOT_DROPPED_YET &&
 | 
				
			||||||
		drop |= (get_random_u32() < vars->p_drop);
 | 
						    get_random_u32() < vars->p_drop)
 | 
				
			||||||
 | 
							reason = SKB_DROP_REASON_CAKE_FLOOD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Overload the drop_next field as an activity timeout */
 | 
						/* Overload the drop_next field as an activity timeout */
 | 
				
			||||||
	if (!vars->count)
 | 
						if (!vars->count)
 | 
				
			||||||
		vars->drop_next = ktime_add_ns(now, p->interval);
 | 
							vars->drop_next = ktime_add_ns(now, p->interval);
 | 
				
			||||||
	else if (ktime_to_ns(schedule) > 0 && !drop)
 | 
						else if (ktime_to_ns(schedule) > 0 && reason == SKB_NOT_DROPPED_YET)
 | 
				
			||||||
		vars->drop_next = now;
 | 
							vars->drop_next = now;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return drop;
 | 
						return reason;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool cake_update_flowkeys(struct flow_keys *keys,
 | 
					static bool cake_update_flowkeys(struct flow_keys *keys,
 | 
				
			||||||
| 
						 | 
					@ -1528,12 +1531,11 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	flow->dropped++;
 | 
						flow->dropped++;
 | 
				
			||||||
	b->tin_dropped++;
 | 
						b->tin_dropped++;
 | 
				
			||||||
	sch->qstats.drops++;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (q->rate_flags & CAKE_FLAG_INGRESS)
 | 
						if (q->rate_flags & CAKE_FLAG_INGRESS)
 | 
				
			||||||
		cake_advance_shaper(q, b, skb, now, true);
 | 
							cake_advance_shaper(q, b, skb, now, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__qdisc_drop(skb, to_free);
 | 
						qdisc_drop_reason(skb, sch, to_free, SKB_DROP_REASON_QDISC_OVERLIMIT);
 | 
				
			||||||
	sch->q.qlen--;
 | 
						sch->q.qlen--;
 | 
				
			||||||
	qdisc_tree_reduce_backlog(sch, 1, len);
 | 
						qdisc_tree_reduce_backlog(sch, 1, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1926,7 +1928,7 @@ static void cake_clear_tin(struct Qdisc *sch, u16 tin)
 | 
				
			||||||
	q->cur_tin = tin;
 | 
						q->cur_tin = tin;
 | 
				
			||||||
	for (q->cur_flow = 0; q->cur_flow < CAKE_QUEUES; q->cur_flow++)
 | 
						for (q->cur_flow = 0; q->cur_flow < CAKE_QUEUES; q->cur_flow++)
 | 
				
			||||||
		while (!!(skb = cake_dequeue_one(sch)))
 | 
							while (!!(skb = cake_dequeue_one(sch)))
 | 
				
			||||||
			kfree_skb(skb);
 | 
								kfree_skb_reason(skb, SKB_DROP_REASON_QUEUE_PURGE);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sk_buff *cake_dequeue(struct Qdisc *sch)
 | 
					static struct sk_buff *cake_dequeue(struct Qdisc *sch)
 | 
				
			||||||
| 
						 | 
					@ -1934,6 +1936,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
 | 
				
			||||||
	struct cake_sched_data *q = qdisc_priv(sch);
 | 
						struct cake_sched_data *q = qdisc_priv(sch);
 | 
				
			||||||
	struct cake_tin_data *b = &q->tins[q->cur_tin];
 | 
						struct cake_tin_data *b = &q->tins[q->cur_tin];
 | 
				
			||||||
	struct cake_host *srchost, *dsthost;
 | 
						struct cake_host *srchost, *dsthost;
 | 
				
			||||||
 | 
						enum skb_drop_reason reason;
 | 
				
			||||||
	ktime_t now = ktime_get();
 | 
						ktime_t now = ktime_get();
 | 
				
			||||||
	struct cake_flow *flow;
 | 
						struct cake_flow *flow;
 | 
				
			||||||
	struct list_head *head;
 | 
						struct list_head *head;
 | 
				
			||||||
| 
						 | 
					@ -2143,12 +2146,12 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
 | 
				
			||||||
			goto begin;
 | 
								goto begin;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							reason = cobalt_should_drop(&flow->cvars, &b->cparams, now, skb,
 | 
				
			||||||
 | 
										    (b->bulk_flow_count *
 | 
				
			||||||
 | 
										     !!(q->rate_flags &
 | 
				
			||||||
 | 
											CAKE_FLAG_INGRESS)));
 | 
				
			||||||
		/* Last packet in queue may be marked, shouldn't be dropped */
 | 
							/* Last packet in queue may be marked, shouldn't be dropped */
 | 
				
			||||||
		if (!cobalt_should_drop(&flow->cvars, &b->cparams, now, skb,
 | 
							if (reason == SKB_NOT_DROPPED_YET || !flow->head)
 | 
				
			||||||
					(b->bulk_flow_count *
 | 
					 | 
				
			||||||
					 !!(q->rate_flags &
 | 
					 | 
				
			||||||
					    CAKE_FLAG_INGRESS))) ||
 | 
					 | 
				
			||||||
		    !flow->head)
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* drop this packet, get another one */
 | 
							/* drop this packet, get another one */
 | 
				
			||||||
| 
						 | 
					@ -2162,7 +2165,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
 | 
				
			||||||
		b->tin_dropped++;
 | 
							b->tin_dropped++;
 | 
				
			||||||
		qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
 | 
							qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
 | 
				
			||||||
		qdisc_qstats_drop(sch);
 | 
							qdisc_qstats_drop(sch);
 | 
				
			||||||
		kfree_skb(skb);
 | 
							kfree_skb_reason(skb, reason);
 | 
				
			||||||
		if (q->rate_flags & CAKE_FLAG_INGRESS)
 | 
							if (q->rate_flags & CAKE_FLAG_INGRESS)
 | 
				
			||||||
			goto retry;
 | 
								goto retry;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue