hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/net/sched/sch_qfq.c
....@@ -113,6 +113,7 @@
113113
114114 #define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */
115115 #define QFQ_MIN_LMAX 512 /* see qfq_slot_insert */
116
+#define QFQ_MAX_LMAX (1UL << QFQ_MTU_SHIFT)
116117
117118 #define QFQ_MAX_AGG_CLASSES 8 /* max num classes per aggregate allowed */
118119
....@@ -214,9 +215,14 @@
214215 return container_of(clc, struct qfq_class, common);
215216 }
216217
218
+static struct netlink_range_validation lmax_range = {
219
+ .min = QFQ_MIN_LMAX,
220
+ .max = QFQ_MAX_LMAX,
221
+};
222
+
217223 static const struct nla_policy qfq_policy[TCA_QFQ_MAX + 1] = {
218
- [TCA_QFQ_WEIGHT] = { .type = NLA_U32 },
219
- [TCA_QFQ_LMAX] = { .type = NLA_U32 },
224
+ [TCA_QFQ_WEIGHT] = NLA_POLICY_RANGE(NLA_U32, 1, QFQ_MAX_WEIGHT),
225
+ [TCA_QFQ_LMAX] = NLA_POLICY_FULL_RANGE(NLA_U32, &lmax_range),
220226 };
221227
222228 /*
....@@ -375,8 +381,13 @@
375381 u32 lmax)
376382 {
377383 struct qfq_sched *q = qdisc_priv(sch);
378
- struct qfq_aggregate *new_agg = qfq_find_agg(q, lmax, weight);
384
+ struct qfq_aggregate *new_agg;
379385
386
+ /* 'lmax' can range from [QFQ_MIN_LMAX, pktlen + stab overhead] */
387
+ if (lmax > QFQ_MAX_LMAX)
388
+ return -EINVAL;
389
+
390
+ new_agg = qfq_find_agg(q, lmax, weight);
380391 if (new_agg == NULL) { /* create new aggregate */
381392 new_agg = kzalloc(sizeof(*new_agg), GFP_ATOMIC);
382393 if (new_agg == NULL)
....@@ -408,27 +419,26 @@
408419 }
409420
410421 err = nla_parse_nested_deprecated(tb, TCA_QFQ_MAX, tca[TCA_OPTIONS],
411
- qfq_policy, NULL);
422
+ qfq_policy, extack);
412423 if (err < 0)
413424 return err;
414425
415
- if (tb[TCA_QFQ_WEIGHT]) {
426
+ if (tb[TCA_QFQ_WEIGHT])
416427 weight = nla_get_u32(tb[TCA_QFQ_WEIGHT]);
417
- if (!weight || weight > (1UL << QFQ_MAX_WSHIFT)) {
418
- pr_notice("qfq: invalid weight %u\n", weight);
419
- return -EINVAL;
420
- }
421
- } else
428
+ else
422429 weight = 1;
423430
424431 if (tb[TCA_QFQ_LMAX]) {
425432 lmax = nla_get_u32(tb[TCA_QFQ_LMAX]);
426
- if (lmax < QFQ_MIN_LMAX || lmax > (1UL << QFQ_MTU_SHIFT)) {
427
- pr_notice("qfq: invalid max length %u\n", lmax);
433
+ } else {
434
+ /* MTU size is user controlled */
435
+ lmax = psched_mtu(qdisc_dev(sch));
436
+ if (lmax < QFQ_MIN_LMAX || lmax > QFQ_MAX_LMAX) {
437
+ NL_SET_ERR_MSG_MOD(extack,
438
+ "MTU size out of bounds for qfq");
428439 return -EINVAL;
429440 }
430
- } else
431
- lmax = psched_mtu(qdisc_dev(sch));
441
+ }
432442
433443 inv_w = ONE_FP / weight;
434444 weight = ONE_FP / inv_w;
....@@ -969,10 +979,13 @@
969979 }
970980
971981 /* Dequeue head packet of the head class in the DRR queue of the aggregate. */
972
-static void agg_dequeue(struct qfq_aggregate *agg,
973
- struct qfq_class *cl, unsigned int len)
982
+static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg,
983
+ struct qfq_class *cl, unsigned int len)
974984 {
975
- qdisc_dequeue_peeked(cl->qdisc);
985
+ struct sk_buff *skb = qdisc_dequeue_peeked(cl->qdisc);
986
+
987
+ if (!skb)
988
+ return NULL;
976989
977990 cl->deficit -= (int) len;
978991
....@@ -982,6 +995,8 @@
982995 cl->deficit += agg->lmax;
983996 list_move_tail(&cl->alist, &agg->active);
984997 }
998
+
999
+ return skb;
9851000 }
9861001
9871002 static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg,
....@@ -1127,11 +1142,18 @@
11271142 if (!skb)
11281143 return NULL;
11291144
1130
- qdisc_qstats_backlog_dec(sch, skb);
11311145 sch->q.qlen--;
1146
+
1147
+ skb = agg_dequeue(in_serv_agg, cl, len);
1148
+
1149
+ if (!skb) {
1150
+ sch->q.qlen++;
1151
+ return NULL;
1152
+ }
1153
+
1154
+ qdisc_qstats_backlog_dec(sch, skb);
11321155 qdisc_bstats_update(sch, skb);
11331156
1134
- agg_dequeue(in_serv_agg, cl, len);
11351157 /* If lmax is lowered, through qfq_change_class, for a class
11361158 * owning pending packets with larger size than the new value
11371159 * of lmax, then the following condition may hold.