Commit bc0ce2ba authored by Toke Høiland-Jørgensen's avatar Toke Høiland-Jørgensen Committed by Paolo Abeni
Browse files

net/sched: sch_cake: Factor out config variables into separate struct



Factor out all the user-configurable variables into a separate struct
and embed it into struct cake_sched_data. This is done in preparation
for sharing the configuration across multiple instances of cake in an mq
setup.

No functional change is intended with this patch.

Reviewed-by: default avatarJamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: default avatarWillem de Bruijn <willemb@google.com>
Signed-off-by: default avatarToke Høiland-Jørgensen <toke@redhat.com>
Link: https://patch.msgid.link/20260109-mq-cake-sub-qdisc-v8-2-8d613fece5d8@redhat.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 8b27fd66
Loading
Loading
Loading
Loading
+133 −112
Original line number Diff line number Diff line
@@ -197,40 +197,42 @@ struct cake_tin_data {
	u32	way_collisions;
}; /* number of tins is small, so size of this struct doesn't matter much */

struct cake_sched_config {
	u64		rate_bps;
	u64		interval;
	u64		target;
	u32		buffer_config_limit;
	u32		fwmark_mask;
	u16		fwmark_shft;
	s16		rate_overhead;
	u16		rate_mpu;
	u16		rate_flags;
	u8		tin_mode;
	u8		flow_mode;
	u8		atm_mode;
	u8		ack_filter;
};

struct cake_sched_data {
	struct tcf_proto __rcu *filter_list; /* optional external classifier */
	struct tcf_block *block;
	struct cake_tin_data *tins;
	struct cake_sched_config *config;

	struct cake_heap_entry overflow_heap[CAKE_QUEUES * CAKE_MAX_TINS];
	u16		overflow_timeout;

	u16		tin_cnt;
	u8		tin_mode;
	u8		flow_mode;
	u8		ack_filter;
	u8		atm_mode;

	u32		fwmark_mask;
	u16		fwmark_shft;

	/* time_next = time_this + ((len * rate_ns) >> rate_shft) */
	u16		rate_shft;
	ktime_t		time_next_packet;
	ktime_t		failsafe_next_packet;
	u64		rate_ns;
	u64		rate_bps;
	u16		rate_flags;
	s16		rate_overhead;
	u16		rate_mpu;
	u64		interval;
	u64		target;
	u16		rate_shft;
	u16		overflow_timeout;
	u16		tin_cnt;

	/* resource tracking */
	u32		buffer_used;
	u32		buffer_max_used;
	u32		buffer_limit;
	u32		buffer_config_limit;

	/* indices for dequeue */
	u16		cur_tin;
@@ -1198,7 +1200,7 @@ static bool cake_tcph_may_drop(const struct tcphdr *tcph,
static struct sk_buff *cake_ack_filter(struct cake_sched_data *q,
				       struct cake_flow *flow)
{
	bool aggressive = q->ack_filter == CAKE_ACK_AGGRESSIVE;
	bool aggressive = q->config->ack_filter == CAKE_ACK_AGGRESSIVE;
	struct sk_buff *elig_ack = NULL, *elig_ack_prev = NULL;
	struct sk_buff *skb_check, *skb_prev = NULL;
	const struct ipv6hdr *ipv6h, *ipv6h_check;
@@ -1358,15 +1360,17 @@ static u64 cake_ewma(u64 avg, u64 sample, u32 shift)
	return avg;
}

static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)
static u32 cake_calc_overhead(struct cake_sched_data *qd, u32 len, u32 off)
{
	struct cake_sched_config *q = qd->config;

	if (q->rate_flags & CAKE_FLAG_OVERHEAD)
		len -= off;

	if (q->max_netlen < len)
		q->max_netlen = len;
	if (q->min_netlen > len)
		q->min_netlen = len;
	if (qd->max_netlen < len)
		qd->max_netlen = len;
	if (qd->min_netlen > len)
		qd->min_netlen = len;

	len += q->rate_overhead;

@@ -1385,10 +1389,10 @@ static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)
		len += (len + 63) / 64;
	}

	if (q->max_adjlen < len)
		q->max_adjlen = len;
	if (q->min_adjlen > len)
		q->min_adjlen = len;
	if (qd->max_adjlen < len)
		qd->max_adjlen = len;
	if (qd->min_adjlen > len)
		qd->min_adjlen = len;

	return len;
}
@@ -1586,7 +1590,7 @@ static unsigned int cake_drop(struct Qdisc *sch, struct sk_buff **to_free)
	flow->dropped++;
	b->tin_dropped++;

	if (q->rate_flags & CAKE_FLAG_INGRESS)
	if (q->config->rate_flags & CAKE_FLAG_INGRESS)
		cake_advance_shaper(q, b, skb, now, true);

	qdisc_drop_reason(skb, sch, to_free, SKB_DROP_REASON_QDISC_OVERLIMIT);
@@ -1656,7 +1660,8 @@ static u8 cake_handle_diffserv(struct sk_buff *skb, bool wash)
static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
					     struct sk_buff *skb)
{
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_sched_data *qd = qdisc_priv(sch);
	struct cake_sched_config *q = qd->config;
	u32 tin, mark;
	bool wash;
	u8 dscp;
@@ -1673,24 +1678,24 @@ static struct cake_tin_data *cake_select_tin(struct Qdisc *sch,
	if (q->tin_mode == CAKE_DIFFSERV_BESTEFFORT)
		tin = 0;

	else if (mark && mark <= q->tin_cnt)
		tin = q->tin_order[mark - 1];
	else if (mark && mark <= qd->tin_cnt)
		tin = qd->tin_order[mark - 1];

	else if (TC_H_MAJ(skb->priority) == sch->handle &&
		 TC_H_MIN(skb->priority) > 0 &&
		 TC_H_MIN(skb->priority) <= q->tin_cnt)
		tin = q->tin_order[TC_H_MIN(skb->priority) - 1];
		 TC_H_MIN(skb->priority) <= qd->tin_cnt)
		tin = qd->tin_order[TC_H_MIN(skb->priority) - 1];

	else {
		if (!wash)
			dscp = cake_handle_diffserv(skb, wash);
		tin = q->tin_index[dscp];
		tin = qd->tin_index[dscp];

		if (unlikely(tin >= q->tin_cnt))
		if (unlikely(tin >= qd->tin_cnt))
			tin = 0;
	}

	return &q->tins[tin];
	return &qd->tins[tin];
}

static u32 cake_classify(struct Qdisc *sch, struct cake_tin_data **t,
@@ -1746,7 +1751,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
	bool same_flow = false;

	/* choose flow to insert into */
	idx = cake_classify(sch, &b, skb, q->flow_mode, &ret);
	idx = cake_classify(sch, &b, skb, q->config->flow_mode, &ret);
	if (idx == 0) {
		if (ret & __NET_XMIT_BYPASS)
			qdisc_qstats_drop(sch);
@@ -1781,7 +1786,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
	if (unlikely(len > b->max_skblen))
		b->max_skblen = len;

	if (qdisc_pkt_segs(skb) > 1 && q->rate_flags & CAKE_FLAG_SPLIT_GSO) {
	if (qdisc_pkt_segs(skb) > 1 && q->config->rate_flags & CAKE_FLAG_SPLIT_GSO) {
		struct sk_buff *segs, *nskb;
		netdev_features_t features = netif_skb_features(skb);
		unsigned int slen = 0, numsegs = 0;
@@ -1823,7 +1828,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
		get_cobalt_cb(skb)->adjusted_len = cake_overhead(q, skb);
		flow_queue_add(flow, skb);

		if (q->ack_filter)
		if (q->config->ack_filter)
			ack = cake_ack_filter(q, flow);

		if (ack) {
@@ -1832,7 +1837,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
			ack_pkt_len = qdisc_pkt_len(ack);
			b->bytes += ack_pkt_len;
			q->buffer_used += skb->truesize - ack->truesize;
			if (q->rate_flags & CAKE_FLAG_INGRESS)
			if (q->config->rate_flags & CAKE_FLAG_INGRESS)
				cake_advance_shaper(q, b, ack, now, true);

			qdisc_tree_reduce_backlog(sch, 1, ack_pkt_len);
@@ -1855,7 +1860,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
		cake_heapify_up(q, b->overflow_idx[idx]);

	/* incoming bandwidth capacity estimate */
	if (q->rate_flags & CAKE_FLAG_AUTORATE_INGRESS) {
	if (q->config->rate_flags & CAKE_FLAG_AUTORATE_INGRESS) {
		u64 packet_interval = \
			ktime_to_ns(ktime_sub(now, q->last_packet_time));

@@ -1887,7 +1892,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
			if (ktime_after(now,
					ktime_add_ms(q->last_reconfig_time,
						     250))) {
				q->rate_bps = (q->avg_peak_bandwidth * 15) >> 4;
				q->config->rate_bps = (q->avg_peak_bandwidth * 15) >> 4;
				cake_reconfigure(sch);
			}
		}
@@ -1907,7 +1912,7 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
		flow->set = CAKE_SET_SPARSE;
		b->sparse_flow_count++;

		flow->deficit = cake_get_flow_quantum(b, flow, q->flow_mode);
		flow->deficit = cake_get_flow_quantum(b, flow, q->config->flow_mode);
	} else if (flow->set == CAKE_SET_SPARSE_WAIT) {
		/* this flow was empty, accounted as a sparse flow, but actually
		 * in the bulk rotation.
@@ -1916,8 +1921,8 @@ static s32 cake_enqueue(struct sk_buff *skb, struct Qdisc *sch,
		b->sparse_flow_count--;
		b->bulk_flow_count++;

		cake_inc_srchost_bulk_flow_count(b, flow, q->flow_mode);
		cake_inc_dsthost_bulk_flow_count(b, flow, q->flow_mode);
		cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
		cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
	}

	if (q->buffer_used > q->buffer_max_used)
@@ -2104,8 +2109,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
				b->sparse_flow_count--;
				b->bulk_flow_count++;

				cake_inc_srchost_bulk_flow_count(b, flow, q->flow_mode);
				cake_inc_dsthost_bulk_flow_count(b, flow, q->flow_mode);
				cake_inc_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
				cake_inc_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);

				flow->set = CAKE_SET_BULK;
			} else {
@@ -2117,7 +2122,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
			}
		}

		flow->deficit += cake_get_flow_quantum(b, flow, q->flow_mode);
		flow->deficit += cake_get_flow_quantum(b, flow, q->config->flow_mode);
		list_move_tail(&flow->flowchain, &b->old_flows);

		goto retry;
@@ -2141,8 +2146,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
				if (flow->set == CAKE_SET_BULK) {
					b->bulk_flow_count--;

					cake_dec_srchost_bulk_flow_count(b, flow, q->flow_mode);
					cake_dec_dsthost_bulk_flow_count(b, flow, q->flow_mode);
					cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
					cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);

					b->decaying_flow_count++;
				} else if (flow->set == CAKE_SET_SPARSE ||
@@ -2160,8 +2165,8 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
				else if (flow->set == CAKE_SET_BULK) {
					b->bulk_flow_count--;

					cake_dec_srchost_bulk_flow_count(b, flow, q->flow_mode);
					cake_dec_dsthost_bulk_flow_count(b, flow, q->flow_mode);
					cake_dec_srchost_bulk_flow_count(b, flow, q->config->flow_mode);
					cake_dec_dsthost_bulk_flow_count(b, flow, q->config->flow_mode);
				} else
					b->decaying_flow_count--;

@@ -2172,14 +2177,14 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)

		reason = cobalt_should_drop(&flow->cvars, &b->cparams, now, skb,
					    (b->bulk_flow_count *
					     !!(q->rate_flags &
					     !!(q->config->rate_flags &
						CAKE_FLAG_INGRESS)));
		/* Last packet in queue may be marked, shouldn't be dropped */
		if (reason == SKB_NOT_DROPPED_YET || !flow->head)
			break;

		/* drop this packet, get another one */
		if (q->rate_flags & CAKE_FLAG_INGRESS) {
		if (q->config->rate_flags & CAKE_FLAG_INGRESS) {
			len = cake_advance_shaper(q, b, skb,
						  now, true);
			flow->deficit -= len;
@@ -2190,7 +2195,7 @@ static struct sk_buff *cake_dequeue(struct Qdisc *sch)
		qdisc_tree_reduce_backlog(sch, 1, qdisc_pkt_len(skb));
		qdisc_qstats_drop(sch);
		qdisc_dequeue_drop(sch, skb, reason);
		if (q->rate_flags & CAKE_FLAG_INGRESS)
		if (q->config->rate_flags & CAKE_FLAG_INGRESS)
			goto retry;
	}

@@ -2312,7 +2317,7 @@ static int cake_config_besteffort(struct Qdisc *sch)
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_tin_data *b = &q->tins[0];
	u32 mtu = psched_mtu(qdisc_dev(sch));
	u64 rate = q->rate_bps;
	u64 rate = q->config->rate_bps;

	q->tin_cnt = 1;

@@ -2320,7 +2325,7 @@ static int cake_config_besteffort(struct Qdisc *sch)
	q->tin_order = normal_order;

	cake_set_rate(b, rate, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	b->tin_quantum = 65535;

	return 0;
@@ -2331,7 +2336,7 @@ static int cake_config_precedence(struct Qdisc *sch)
	/* convert high-level (user visible) parameters into internal format */
	struct cake_sched_data *q = qdisc_priv(sch);
	u32 mtu = psched_mtu(qdisc_dev(sch));
	u64 rate = q->rate_bps;
	u64 rate = q->config->rate_bps;
	u32 quantum = 256;
	u32 i;

@@ -2342,8 +2347,8 @@ static int cake_config_precedence(struct Qdisc *sch)
	for (i = 0; i < q->tin_cnt; i++) {
		struct cake_tin_data *b = &q->tins[i];

		cake_set_rate(b, rate, mtu, us_to_ns(q->target),
			      us_to_ns(q->interval));
		cake_set_rate(b, rate, mtu, us_to_ns(q->config->target),
			      us_to_ns(q->config->interval));

		b->tin_quantum = max_t(u16, 1U, quantum);

@@ -2420,7 +2425,7 @@ static int cake_config_diffserv8(struct Qdisc *sch)

	struct cake_sched_data *q = qdisc_priv(sch);
	u32 mtu = psched_mtu(qdisc_dev(sch));
	u64 rate = q->rate_bps;
	u64 rate = q->config->rate_bps;
	u32 quantum = 256;
	u32 i;

@@ -2434,8 +2439,8 @@ static int cake_config_diffserv8(struct Qdisc *sch)
	for (i = 0; i < q->tin_cnt; i++) {
		struct cake_tin_data *b = &q->tins[i];

		cake_set_rate(b, rate, mtu, us_to_ns(q->target),
			      us_to_ns(q->interval));
		cake_set_rate(b, rate, mtu, us_to_ns(q->config->target),
			      us_to_ns(q->config->interval));

		b->tin_quantum = max_t(u16, 1U, quantum);

@@ -2464,7 +2469,7 @@ static int cake_config_diffserv4(struct Qdisc *sch)

	struct cake_sched_data *q = qdisc_priv(sch);
	u32 mtu = psched_mtu(qdisc_dev(sch));
	u64 rate = q->rate_bps;
	u64 rate = q->config->rate_bps;
	u32 quantum = 1024;

	q->tin_cnt = 4;
@@ -2475,13 +2480,13 @@ static int cake_config_diffserv4(struct Qdisc *sch)

	/* class characteristics */
	cake_set_rate(&q->tins[0], rate, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	cake_set_rate(&q->tins[1], rate >> 4, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	cake_set_rate(&q->tins[2], rate >> 1, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	cake_set_rate(&q->tins[3], rate >> 2, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));

	/* bandwidth-sharing weights */
	q->tins[0].tin_quantum = quantum;
@@ -2501,7 +2506,7 @@ static int cake_config_diffserv3(struct Qdisc *sch)
 */
	struct cake_sched_data *q = qdisc_priv(sch);
	u32 mtu = psched_mtu(qdisc_dev(sch));
	u64 rate = q->rate_bps;
	u64 rate = q->config->rate_bps;
	u32 quantum = 1024;

	q->tin_cnt = 3;
@@ -2512,11 +2517,11 @@ static int cake_config_diffserv3(struct Qdisc *sch)

	/* class characteristics */
	cake_set_rate(&q->tins[0], rate, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	cake_set_rate(&q->tins[1], rate >> 4, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));
	cake_set_rate(&q->tins[2], rate >> 2, mtu,
		      us_to_ns(q->target), us_to_ns(q->interval));
		      us_to_ns(q->config->target), us_to_ns(q->config->interval));

	/* bandwidth-sharing weights */
	q->tins[0].tin_quantum = quantum;
@@ -2528,7 +2533,8 @@ static int cake_config_diffserv3(struct Qdisc *sch)

static void cake_reconfigure(struct Qdisc *sch)
{
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_sched_data *qd = qdisc_priv(sch);
	struct cake_sched_config *q = qd->config;
	int c, ft;

	switch (q->tin_mode) {
@@ -2554,28 +2560,28 @@ static void cake_reconfigure(struct Qdisc *sch)
		break;
	}

	for (c = q->tin_cnt; c < CAKE_MAX_TINS; c++) {
	for (c = qd->tin_cnt; c < CAKE_MAX_TINS; c++) {
		cake_clear_tin(sch, c);
		q->tins[c].cparams.mtu_time = q->tins[ft].cparams.mtu_time;
		qd->tins[c].cparams.mtu_time = qd->tins[ft].cparams.mtu_time;
	}

	q->rate_ns   = q->tins[ft].tin_rate_ns;
	q->rate_shft = q->tins[ft].tin_rate_shft;
	qd->rate_ns   = qd->tins[ft].tin_rate_ns;
	qd->rate_shft = qd->tins[ft].tin_rate_shft;

	if (q->buffer_config_limit) {
		q->buffer_limit = q->buffer_config_limit;
		qd->buffer_limit = q->buffer_config_limit;
	} else if (q->rate_bps) {
		u64 t = q->rate_bps * q->interval;

		do_div(t, USEC_PER_SEC / 4);
		q->buffer_limit = max_t(u32, t, 4U << 20);
		qd->buffer_limit = max_t(u32, t, 4U << 20);
	} else {
		q->buffer_limit = ~0;
		qd->buffer_limit = ~0;
	}

	sch->flags &= ~TCQ_F_CAN_BYPASS;

	q->buffer_limit = min(q->buffer_limit,
	qd->buffer_limit = min(qd->buffer_limit,
			       max(sch->limit * psched_mtu(qdisc_dev(sch)),
				   q->buffer_config_limit));
}
@@ -2583,7 +2589,8 @@ static void cake_reconfigure(struct Qdisc *sch)
static int cake_change(struct Qdisc *sch, struct nlattr *opt,
		       struct netlink_ext_ack *extack)
{
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_sched_data *qd = qdisc_priv(sch);
	struct cake_sched_config *q = qd->config;
	struct nlattr *tb[TCA_CAKE_MAX + 1];
	u16 rate_flags;
	u8 flow_mode;
@@ -2637,19 +2644,19 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,
			   nla_get_s32(tb[TCA_CAKE_OVERHEAD]));
		rate_flags |= CAKE_FLAG_OVERHEAD;

		q->max_netlen = 0;
		q->max_adjlen = 0;
		q->min_netlen = ~0;
		q->min_adjlen = ~0;
		qd->max_netlen = 0;
		qd->max_adjlen = 0;
		qd->min_netlen = ~0;
		qd->min_adjlen = ~0;
	}

	if (tb[TCA_CAKE_RAW]) {
		rate_flags &= ~CAKE_FLAG_OVERHEAD;

		q->max_netlen = 0;
		q->max_adjlen = 0;
		q->min_netlen = ~0;
		q->min_adjlen = ~0;
		qd->max_netlen = 0;
		qd->max_adjlen = 0;
		qd->min_netlen = ~0;
		qd->min_adjlen = ~0;
	}

	if (tb[TCA_CAKE_MPU])
@@ -2705,7 +2712,7 @@ static int cake_change(struct Qdisc *sch, struct nlattr *opt,

	WRITE_ONCE(q->rate_flags, rate_flags);
	WRITE_ONCE(q->flow_mode, flow_mode);
	if (q->tins) {
	if (qd->tins) {
		sch_tree_lock(sch);
		cake_reconfigure(sch);
		sch_tree_unlock(sch);
@@ -2721,14 +2728,20 @@ static void cake_destroy(struct Qdisc *sch)
	qdisc_watchdog_cancel(&q->watchdog);
	tcf_block_put(q->block);
	kvfree(q->tins);
	kvfree(q->config);
}

static int cake_init(struct Qdisc *sch, struct nlattr *opt,
		     struct netlink_ext_ack *extack)
{
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_sched_data *qd = qdisc_priv(sch);
	struct cake_sched_config *q;
	int i, j, err;

	q = kzalloc(sizeof(*q), GFP_KERNEL);
	if (!q)
		return -ENOMEM;

	sch->limit = 10240;
	sch->flags |= TCQ_F_DEQUEUE_DROPS;

@@ -2742,33 +2755,36 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
			       * for 5 to 10% of interval
			       */
	q->rate_flags |= CAKE_FLAG_SPLIT_GSO;
	q->cur_tin = 0;
	q->cur_flow  = 0;
	qd->cur_tin = 0;
	qd->cur_flow  = 0;
	qd->config = q;

	qdisc_watchdog_init(&q->watchdog, sch);
	qdisc_watchdog_init(&qd->watchdog, sch);

	if (opt) {
		err = cake_change(sch, opt, extack);

		if (err)
			return err;
			goto err;
	}

	err = tcf_block_get(&q->block, &q->filter_list, sch, extack);
	err = tcf_block_get(&qd->block, &qd->filter_list, sch, extack);
	if (err)
		return err;
		goto err;

	quantum_div[0] = ~0;
	for (i = 1; i <= CAKE_QUEUES; i++)
		quantum_div[i] = 65535 / i;

	q->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
	qd->tins = kvcalloc(CAKE_MAX_TINS, sizeof(struct cake_tin_data),
			    GFP_KERNEL);
	if (!q->tins)
		return -ENOMEM;
	if (!qd->tins) {
		err = -ENOMEM;
		goto err;
	}

	for (i = 0; i < CAKE_MAX_TINS; i++) {
		struct cake_tin_data *b = q->tins + i;
		struct cake_tin_data *b = qd->tins + i;

		INIT_LIST_HEAD(&b->new_flows);
		INIT_LIST_HEAD(&b->old_flows);
@@ -2784,22 +2800,27 @@ static int cake_init(struct Qdisc *sch, struct nlattr *opt,
			INIT_LIST_HEAD(&flow->flowchain);
			cobalt_vars_init(&flow->cvars);

			q->overflow_heap[k].t = i;
			q->overflow_heap[k].b = j;
			qd->overflow_heap[k].t = i;
			qd->overflow_heap[k].b = j;
			b->overflow_idx[j] = k;
		}
	}

	cake_reconfigure(sch);
	q->avg_peak_bandwidth = q->rate_bps;
	q->min_netlen = ~0;
	q->min_adjlen = ~0;
	qd->avg_peak_bandwidth = q->rate_bps;
	qd->min_netlen = ~0;
	qd->min_adjlen = ~0;
	return 0;
err:
	kvfree(qd->config);
	qd->config = NULL;
	return err;
}

static int cake_dump(struct Qdisc *sch, struct sk_buff *skb)
{
	struct cake_sched_data *q = qdisc_priv(sch);
	struct cake_sched_data *qd = qdisc_priv(sch);
	struct cake_sched_config *q = qd->config;
	struct nlattr *opts;
	u16 rate_flags;
	u8 flow_mode;