Due to a poorly chosen initial state, we might jump immediately into a CONTROL state bypassing the DROPPING one when the initial state is DROPPING. The fix is easy: the initial state must be something neutral, so that we would transition INITIAL->DROPPING right off the bat in the beggining of the loop and then perfrom a DROPPING->CONTROL transition and either CONTROL->DROPPING and restart the loop or CONTROL->RECOVERY/ACCEPTING.
The change in codel_state_change is necessary because valid transitions are only INITIAL->DROPPING and DROPPING->CONTROL in this case. Does this look good? diff --git sys/net/fq_codel.c sys/net/fq_codel.c index 1c380f49f3d..c7fe38a7094 100644 --- sys/net/fq_codel.c +++ sys/net/fq_codel.c @@ -370,11 +370,11 @@ codel_next_packet(struct codel *cd, struct codel_params *cp, int64_t now, *drop = 1; } return (m); } -enum { ACCEPTING, FIRSTDROP, DROPPING, CONTROL, RECOVERY }; +enum { INITIAL, ACCEPTING, FIRSTDROP, DROPPING, CONTROL, RECOVERY }; static inline int codel_state_change(struct codel *cd, int64_t now, struct mbuf *m, int drop, int state) { @@ -383,11 +383,11 @@ codel_state_change(struct codel *cd, int64_t now, struct mbuf *m, int drop, if (cd->dropping) { if (!drop) return (RECOVERY); else if (now >= cd->next) - return (state == CONTROL ? DROPPING : CONTROL); + return (state == DROPPING ? CONTROL : DROPPING); } else if (drop) return (FIRSTDROP); if (m == NULL) return (RECOVERY); @@ -403,11 +403,11 @@ codel_dequeue(struct codel *cd, struct codel_params *cp, int64_t now, unsigned short delta; int drop, state, done = 0; *dpkts = *dbytes = 0; - state = cd->dropping ? DROPPING : ACCEPTING; + state = INITIAL; while (!done) { m = codel_next_packet(cd, cp, now, &drop); state = codel_state_change(cd, now, m, drop, state);