[Cake] cake infinite loop(?) with hfsc on one-armed router

Toke Høiland-Jørgensen toke at toke.dk
Sat Jan 5 05:06:59 EST 2019


Pete Heist <pete at heistp.net> writes:

>> On Jan 4, 2019, at 11:34 PM, Toke Høiland-Jørgensen <toke at toke.dk> wrote:
>> 
>> Pete Heist <pete at heistp.net> writes:
>> 
>> This basically means that we can't use CAKE as a leaf qdisc with GSO
>> splitting as it stands currently. I *think* the solution is for CAKE to
>> notify its parents; could you try the patch below and see if it helps?
>
> Aha, good news. :)
>
> I’m probably not currently in a position to try it on my old kernels with the out of tree build:
>
> On 3.16.7:

Hmm, try this version for 3.16 - probably doesn't work on later kernels.
I'll look into a proper backport once you've confirmed that it works :)

-Toke

diff --git a/net/sched/sch_cake.c b/net/sched/sch_cake.c
index b910cd5c56f7..ef3acdbb8429 100644
--- a/net/sched/sch_cake.c
+++ b/net/sched/sch_cake.c
@@ -1617,6 +1617,44 @@ static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t,
 
 static void cake_reconfigure(struct Qdisc *sch);
 
+
+static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
+{
+	struct Qdisc *q;
+
+	if (!(root->flags & TCQ_F_BUILTIN) &&
+	    root->handle == handle)
+		return root;
+
+	list_for_each_entry(q, &root->list, list) {
+		if (q->handle == handle)
+			return q;
+	}
+	return NULL;
+}
+
+void adjust_parent_qlen(struct Qdisc *sch, unsigned int n,
+			       unsigned int len)
+{
+	u32 parentid;
+	if (n == 0 && len == 0)
+		return;
+	rcu_read_lock();
+	while ((parentid = sch->parent)) {
+		if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
+			break;
+
+		sch = qdisc_match_from_root(qdisc_dev(sch), TC_H_MAJ(parentid));
+		if (sch == NULL) {
+			WARN_ON_ONCE(parentid != TC_H_ROOT);
+			break;
+		}
+		sch->q.qlen += n;
+		sch->qstats.backlog += len;
+	}
+	rcu_read_unlock();
+}
+
 static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 			struct sk_buff **to_free)
 {
@@ -1667,7 +1705,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 	if (skb_is_gso(skb) && q->rate_flags & CAKE_FLAG_SPLIT_GSO) {
 		struct sk_buff *segs, *nskb;
 		netdev_features_t features = netif_skb_features(skb);
-		unsigned int slen = 0;
+		unsigned int slen = 0, numsegs = 0;
 
 		segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK);
 		if (IS_ERR_OR_NULL(segs))
@@ -1684,6 +1722,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 
 			sch->q.qlen++;
 			slen += segs->len;
+			numsegs++;
 			q->buffer_used += segs->truesize;
 			b->packets++;
 			segs = nskb;
@@ -1696,7 +1735,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
 		sch->qstats.backlog += slen;
 		q->avg_window_bytes += slen;
 
-		qdisc_tree_reduce_backlog(sch, 1, len);
+		adjust_parent_qlen(sch, numsegs - 1, slen - len);
 		consume_skb(skb);
 	} else {
 		/* not splitting */


More information about the Cake mailing list