Skip to content

Commit 29d2614

Browse files
committed
Merge branch 'sch_sfq-derived-limit'
Octavian Purdila says: ==================== net_sched: sch_sfq: reject a derived limit of 1 Because sfq parameters can influence each other there can be situations where although the user sets a limit of 2 it can be lowered to 1: $ tc qdisc add dev dummy0 handle 1: root sfq limit 2 flows 1 depth 1 $ tc qdisc show dev dummy0 qdisc sfq 1: dev dummy0 root refcnt 2 limit 1p quantum 1514b depth 1 divisor 1024 $ tc qdisc add dev dummy0 handle 1: root sfq limit 2 flows 10 depth 1 divisor 1 $ tc qdisc show dev dummy0 qdisc sfq 2: root refcnt 2 limit 1p quantum 1514b depth 1 divisor 1 As a limit of 1 is invalid, this patch series moves the limit validation to after all configuration changes have been done. To do so, the configuration is done in a temporary work area then applied to the internal state. The patch series also adds new test cases. v3: - remove a couple of unnecessary comments - rearrange local variables to use reverse Christmas tree style declaration order v2: https://lore.kernel.org/all/[email protected]/ - remove tmp struct and directly use local variables v1: https://lore.kernel.org/all/[email protected]/ =================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7f1ff1b + 26e7051 commit 29d2614

File tree

2 files changed

+86
-16
lines changed

2 files changed

+86
-16
lines changed

net/sched/sch_sfq.c

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,15 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
631631
struct red_parms *p = NULL;
632632
struct sk_buff *to_free = NULL;
633633
struct sk_buff *tail = NULL;
634+
unsigned int maxflows;
635+
unsigned int quantum;
636+
unsigned int divisor;
637+
int perturb_period;
638+
u8 headdrop;
639+
u8 maxdepth;
640+
int limit;
641+
u8 flags;
642+
634643

635644
if (opt->nla_len < nla_attr_size(sizeof(*ctl)))
636645
return -EINVAL;
@@ -652,39 +661,64 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,
652661
if (!p)
653662
return -ENOMEM;
654663
}
655-
if (ctl->limit == 1) {
656-
NL_SET_ERR_MSG_MOD(extack, "invalid limit");
657-
return -EINVAL;
658-
}
664+
659665
sch_tree_lock(sch);
666+
667+
limit = q->limit;
668+
divisor = q->divisor;
669+
headdrop = q->headdrop;
670+
maxdepth = q->maxdepth;
671+
maxflows = q->maxflows;
672+
perturb_period = q->perturb_period;
673+
quantum = q->quantum;
674+
flags = q->flags;
675+
676+
/* update and validate configuration */
660677
if (ctl->quantum)
661-
q->quantum = ctl->quantum;
662-
WRITE_ONCE(q->perturb_period, ctl->perturb_period * HZ);
678+
quantum = ctl->quantum;
679+
perturb_period = ctl->perturb_period * HZ;
663680
if (ctl->flows)
664-
q->maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
681+
maxflows = min_t(u32, ctl->flows, SFQ_MAX_FLOWS);
665682
if (ctl->divisor) {
666-
q->divisor = ctl->divisor;
667-
q->maxflows = min_t(u32, q->maxflows, q->divisor);
683+
divisor = ctl->divisor;
684+
maxflows = min_t(u32, maxflows, divisor);
668685
}
669686
if (ctl_v1) {
670687
if (ctl_v1->depth)
671-
q->maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
688+
maxdepth = min_t(u32, ctl_v1->depth, SFQ_MAX_DEPTH);
672689
if (p) {
673-
swap(q->red_parms, p);
674-
red_set_parms(q->red_parms,
690+
red_set_parms(p,
675691
ctl_v1->qth_min, ctl_v1->qth_max,
676692
ctl_v1->Wlog,
677693
ctl_v1->Plog, ctl_v1->Scell_log,
678694
NULL,
679695
ctl_v1->max_P);
680696
}
681-
q->flags = ctl_v1->flags;
682-
q->headdrop = ctl_v1->headdrop;
697+
flags = ctl_v1->flags;
698+
headdrop = ctl_v1->headdrop;
683699
}
684700
if (ctl->limit) {
685-
q->limit = min_t(u32, ctl->limit, q->maxdepth * q->maxflows);
686-
q->maxflows = min_t(u32, q->maxflows, q->limit);
701+
limit = min_t(u32, ctl->limit, maxdepth * maxflows);
702+
maxflows = min_t(u32, maxflows, limit);
687703
}
704+
if (limit == 1) {
705+
sch_tree_unlock(sch);
706+
kfree(p);
707+
NL_SET_ERR_MSG_MOD(extack, "invalid limit");
708+
return -EINVAL;
709+
}
710+
711+
/* commit configuration */
712+
q->limit = limit;
713+
q->divisor = divisor;
714+
q->headdrop = headdrop;
715+
q->maxdepth = maxdepth;
716+
q->maxflows = maxflows;
717+
WRITE_ONCE(q->perturb_period, perturb_period);
718+
q->quantum = quantum;
719+
q->flags = flags;
720+
if (p)
721+
swap(q->red_parms, p);
688722

689723
qlen = sch->q.qlen;
690724
while (sch->q.qlen > q->limit) {

tools/testing/selftests/tc-testing/tc-tests/qdiscs/sfq.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,5 +228,41 @@
228228
"matchCount": "0",
229229
"teardown": [
230230
]
231+
},
232+
{
233+
"id": "7f8f",
234+
"name": "Check that a derived limit of 1 is rejected (limit 2 depth 1 flows 1)",
235+
"category": [
236+
"qdisc",
237+
"sfq"
238+
],
239+
"plugins": {
240+
"requires": "nsPlugin"
241+
},
242+
"setup": [],
243+
"cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfq limit 2 depth 1 flows 1",
244+
"expExitCode": "2",
245+
"verifyCmd": "$TC qdisc show dev $DUMMY",
246+
"matchPattern": "sfq",
247+
"matchCount": "0",
248+
"teardown": []
249+
},
250+
{
251+
"id": "5168",
252+
"name": "Check that a derived limit of 1 is rejected (limit 2 depth 1 divisor 1)",
253+
"category": [
254+
"qdisc",
255+
"sfq"
256+
],
257+
"plugins": {
258+
"requires": "nsPlugin"
259+
},
260+
"setup": [],
261+
"cmdUnderTest": "$TC qdisc add dev $DUMMY handle 1: root sfq limit 2 depth 1 divisor 1",
262+
"expExitCode": "2",
263+
"verifyCmd": "$TC qdisc show dev $DUMMY",
264+
"matchPattern": "sfq",
265+
"matchCount": "0",
266+
"teardown": []
231267
}
232268
]

0 commit comments

Comments
 (0)