diff options
-rw-r--r-- | sys/net/fq_codel.c | 141 | ||||
-rw-r--r-- | sys/net/fq_codel.h | 1 |
2 files changed, 142 insertions, 0 deletions
diff --git a/sys/net/fq_codel.c b/sys/net/fq_codel.c index eca603450de..56df011d258 100644 --- a/sys/net/fq_codel.c +++ b/sys/net/fq_codel.c @@ -138,6 +138,24 @@ static const struct ifq_ops fqcodel_ops = { const struct ifq_ops * const ifq_fqcodel_ops = &fqcodel_ops; +void *fqcodel_pf_alloc(struct ifnet *); +int fqcodel_pf_addqueue(void *, struct pf_queuespec *); +void fqcodel_pf_free(void *); +int fqcodel_pf_qstats(struct pf_queuespec *, void *, int *); + +/* + * pf queue glue. + */ + +static const struct pfq_ops fqcodel_pf_ops = { + fqcodel_pf_alloc, + fqcodel_pf_addqueue, + fqcodel_pf_free, + fqcodel_pf_qstats +}; + +const struct pfq_ops * const pfq_fqcodel_ops = &fqcodel_pf_ops; + /* Default aggregate queue depth */ static const unsigned int fqcodel_qlimit = 1024; @@ -653,6 +671,129 @@ fqcodel_purge(struct ifqueue *ifq, struct mbuf_list *ml) codel_purge(&fqc->flows[i].cd, ml); } +void * +fqcodel_pf_alloc(struct ifnet *ifp) +{ + struct fqcodel *fqc; + + fqc = malloc(sizeof(struct fqcodel), M_DEVBUF, M_WAITOK | M_ZERO); + + return (fqc); +} + +int +fqcodel_pf_addqueue(void *arg, struct pf_queuespec *qs) +{ + struct ifnet *ifp = qs->kif->pfik_ifp; + struct fqcodel *fqc = arg; + + KASSERT(qs->parent_qid == 0); + + if (qs->flowqueue.flows == 0 || qs->flowqueue.flows > M_FLOWID_MASK) + return (EINVAL); + + fqc->nflows = qs->flowqueue.flows; + fqc->quantum = qs->flowqueue.quantum; + if (qs->qlimit > 0) + fqc->qlimit = qs->qlimit; + else + fqc->qlimit = fqcodel_qlimit; + if (fqc->quantum > 0) + fqc->flags |= FQCF_FIXED_QUANTUM; + else + fqc->quantum = ifp->if_mtu + max_linkhdr; + + codel_initparams(&fqc->cparams, qs->flowqueue.target, + qs->flowqueue.interval, fqc->quantum); + + fqc->flows = mallocarray(fqc->nflows, sizeof(struct flow), + M_DEVBUF, M_WAITOK | M_ZERO); + +#ifdef FQCODEL_DEBUG + { + unsigned int i; + + for (i = 0; i < fqc->nflows; i++) + fqc->flows[i].id = i; + } +#endif + + DPRINTF("fq-codel on %s: %d queues %d deep, quantum %d target %llums " + "interval %llums\n", ifp->if_xname, fqc->nflows, fqc->qlimit, + fqc->quantum, fqc->cparams.target / 1000000, + fqc->cparams.interval / 1000000); + + return (0); +} + +void +fqcodel_pf_free(void *arg) +{ + struct fqcodel *fqc = arg; + + codel_freeparams(&fqc->cparams); + free(fqc->flows, M_DEVBUF, fqc->nflows * sizeof(struct flow)); + free(fqc, M_DEVBUF, sizeof(struct fqcodel)); +} + +int +fqcodel_pf_qstats(struct pf_queuespec *qs, void *ubuf, int *nbytes) +{ + struct ifnet *ifp = qs->kif->pfik_ifp; + struct fqcodel_stats stats; + struct fqcodel *fqc; + unsigned int i, qlen; + int error = 0; + + if (ifp == NULL) + return (EBADF); + + if (*nbytes < sizeof(stats)) + return (EINVAL); + + memset(&stats, 0, sizeof(stats)); + + /* XXX: multi-q? */ + fqc = ifq_q_enter(&ifp->if_snd, ifq_fqcodel_ops); + if (fqc == NULL) + return (EBADF); + + stats.xmit_cnt = fqc->xmit_cnt; + stats.drop_cnt = fqc->drop_cnt; + + stats.qlength = ifq_len(&ifp->if_snd); + stats.qlimit = fqc->qlimit; + + stats.flows = stats.maxqlen = stats.minqlen = 0; + stats.qlensum = stats.qlensumsq = 0; + + for (i = 0; i < fqc->nflows; i++) { + qlen = codel_qlength(&fqc->flows[i].cd); + if (qlen == 0) + continue; + if (stats.minqlen == 0) + stats.minqlen = qlen; + else + stats.minqlen = MIN(stats.minqlen, qlen); + if (stats.maxqlen == 0) + stats.maxqlen = qlen; + else + stats.maxqlen = MAX(stats.maxqlen, qlen); + stats.flows++; + + stats.qlensum += qlen; + stats.qlensumsq += (uint64_t)qlen * (uint64_t)qlen; + } + + ifq_q_leave(&ifp->if_snd, fqc); + + if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0) + return (error); + + *nbytes = sizeof(stats); + return (0); +} + unsigned int fqcodel_idx(unsigned int nqueues, const struct mbuf *m) { diff --git a/sys/net/fq_codel.h b/sys/net/fq_codel.h index 7d79f5bcc7e..7b4d0844187 100644 --- a/sys/net/fq_codel.h +++ b/sys/net/fq_codel.h @@ -46,6 +46,7 @@ struct fqcodel_stats { #ifdef _KERNEL extern const struct ifq_ops * const ifq_fqcodel_ops; +extern const struct pfq_ops * const pfq_fqcodel_ops; #endif /* _KERNEL */ #endif /* _NET_FQ_CODEL_H_ */ |