| .. | .. |
|---|
| 113 | 113 | |
|---|
| 114 | 114 | #define QFQ_MTU_SHIFT 16 /* to support TSO/GSO */ |
|---|
| 115 | 115 | #define QFQ_MIN_LMAX 512 /* see qfq_slot_insert */ |
|---|
| 116 | +#define QFQ_MAX_LMAX (1UL << QFQ_MTU_SHIFT) |
|---|
| 116 | 117 | |
|---|
| 117 | 118 | #define QFQ_MAX_AGG_CLASSES 8 /* max num classes per aggregate allowed */ |
|---|
| 118 | 119 | |
|---|
| .. | .. |
|---|
| 214 | 215 | return container_of(clc, struct qfq_class, common); |
|---|
| 215 | 216 | } |
|---|
| 216 | 217 | |
|---|
| 218 | +static struct netlink_range_validation lmax_range = { |
|---|
| 219 | + .min = QFQ_MIN_LMAX, |
|---|
| 220 | + .max = QFQ_MAX_LMAX, |
|---|
| 221 | +}; |
|---|
| 222 | + |
|---|
| 217 | 223 | 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), |
|---|
| 220 | 226 | }; |
|---|
| 221 | 227 | |
|---|
| 222 | 228 | /* |
|---|
| .. | .. |
|---|
| 375 | 381 | u32 lmax) |
|---|
| 376 | 382 | { |
|---|
| 377 | 383 | 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; |
|---|
| 379 | 385 | |
|---|
| 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); |
|---|
| 380 | 391 | if (new_agg == NULL) { /* create new aggregate */ |
|---|
| 381 | 392 | new_agg = kzalloc(sizeof(*new_agg), GFP_ATOMIC); |
|---|
| 382 | 393 | if (new_agg == NULL) |
|---|
| .. | .. |
|---|
| 408 | 419 | } |
|---|
| 409 | 420 | |
|---|
| 410 | 421 | err = nla_parse_nested_deprecated(tb, TCA_QFQ_MAX, tca[TCA_OPTIONS], |
|---|
| 411 | | - qfq_policy, NULL); |
|---|
| 422 | + qfq_policy, extack); |
|---|
| 412 | 423 | if (err < 0) |
|---|
| 413 | 424 | return err; |
|---|
| 414 | 425 | |
|---|
| 415 | | - if (tb[TCA_QFQ_WEIGHT]) { |
|---|
| 426 | + if (tb[TCA_QFQ_WEIGHT]) |
|---|
| 416 | 427 | 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 |
|---|
| 422 | 429 | weight = 1; |
|---|
| 423 | 430 | |
|---|
| 424 | 431 | if (tb[TCA_QFQ_LMAX]) { |
|---|
| 425 | 432 | 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"); |
|---|
| 428 | 439 | return -EINVAL; |
|---|
| 429 | 440 | } |
|---|
| 430 | | - } else |
|---|
| 431 | | - lmax = psched_mtu(qdisc_dev(sch)); |
|---|
| 441 | + } |
|---|
| 432 | 442 | |
|---|
| 433 | 443 | inv_w = ONE_FP / weight; |
|---|
| 434 | 444 | weight = ONE_FP / inv_w; |
|---|
| .. | .. |
|---|
| 969 | 979 | } |
|---|
| 970 | 980 | |
|---|
| 971 | 981 | /* 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) |
|---|
| 974 | 984 | { |
|---|
| 975 | | - qdisc_dequeue_peeked(cl->qdisc); |
|---|
| 985 | + struct sk_buff *skb = qdisc_dequeue_peeked(cl->qdisc); |
|---|
| 986 | + |
|---|
| 987 | + if (!skb) |
|---|
| 988 | + return NULL; |
|---|
| 976 | 989 | |
|---|
| 977 | 990 | cl->deficit -= (int) len; |
|---|
| 978 | 991 | |
|---|
| .. | .. |
|---|
| 982 | 995 | cl->deficit += agg->lmax; |
|---|
| 983 | 996 | list_move_tail(&cl->alist, &agg->active); |
|---|
| 984 | 997 | } |
|---|
| 998 | + |
|---|
| 999 | + return skb; |
|---|
| 985 | 1000 | } |
|---|
| 986 | 1001 | |
|---|
| 987 | 1002 | static inline struct sk_buff *qfq_peek_skb(struct qfq_aggregate *agg, |
|---|
| .. | .. |
|---|
| 1127 | 1142 | if (!skb) |
|---|
| 1128 | 1143 | return NULL; |
|---|
| 1129 | 1144 | |
|---|
| 1130 | | - qdisc_qstats_backlog_dec(sch, skb); |
|---|
| 1131 | 1145 | 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); |
|---|
| 1132 | 1155 | qdisc_bstats_update(sch, skb); |
|---|
| 1133 | 1156 | |
|---|
| 1134 | | - agg_dequeue(in_serv_agg, cl, len); |
|---|
| 1135 | 1157 | /* If lmax is lowered, through qfq_change_class, for a class |
|---|
| 1136 | 1158 | * owning pending packets with larger size than the new value |
|---|
| 1137 | 1159 | * of lmax, then the following condition may hold. |
|---|