1da8ae05dSGleb Smirnoff /*- 2772e66a6SGleb Smirnoff * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved. 3772e66a6SGleb Smirnoff * 4772e66a6SGleb Smirnoff * Permission to use, copy, modify, and distribute this software and 5772e66a6SGleb Smirnoff * its documentation is hereby granted (including for commercial or 6772e66a6SGleb Smirnoff * for-profit use), provided that both the copyright notice and this 7772e66a6SGleb Smirnoff * permission notice appear in all copies of the software, derivative 8772e66a6SGleb Smirnoff * works, or modified versions, and any portions thereof. 9772e66a6SGleb Smirnoff * 10772e66a6SGleb Smirnoff * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF 11772e66a6SGleb Smirnoff * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS 12772e66a6SGleb Smirnoff * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED 13772e66a6SGleb Smirnoff * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 14772e66a6SGleb Smirnoff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15772e66a6SGleb Smirnoff * DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 16772e66a6SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17772e66a6SGleb Smirnoff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 18772e66a6SGleb Smirnoff * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 19772e66a6SGleb Smirnoff * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 20772e66a6SGleb Smirnoff * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21772e66a6SGleb Smirnoff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 22772e66a6SGleb Smirnoff * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 23772e66a6SGleb Smirnoff * DAMAGE. 24772e66a6SGleb Smirnoff * 25772e66a6SGleb Smirnoff * Carnegie Mellon encourages (but does not require) users of this 26772e66a6SGleb Smirnoff * software to return any improvements or extensions that they make, 27772e66a6SGleb Smirnoff * and to grant Carnegie Mellon the rights to redistribute these 28772e66a6SGleb Smirnoff * changes without encumbrance. 29da8ae05dSGleb Smirnoff * 30da8ae05dSGleb Smirnoff * $KAME: altq_hfsc.c,v 1.24 2003/12/05 05:40:46 kjc Exp $ 31da8ae05dSGleb Smirnoff * $FreeBSD$ 32772e66a6SGleb Smirnoff */ 33772e66a6SGleb Smirnoff /* 34772e66a6SGleb Smirnoff * H-FSC is described in Proceedings of SIGCOMM'97, 35772e66a6SGleb Smirnoff * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing, 36772e66a6SGleb Smirnoff * Real-Time and Priority Service" 37772e66a6SGleb Smirnoff * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng. 38772e66a6SGleb Smirnoff * 39772e66a6SGleb Smirnoff * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing. 40772e66a6SGleb Smirnoff * when a class has an upperlimit, the fit-time is computed from the 41772e66a6SGleb Smirnoff * upperlimit service curve. the link-sharing scheduler does not schedule 42772e66a6SGleb Smirnoff * a class whose fit-time exceeds the current time. 43772e66a6SGleb Smirnoff */ 44772e66a6SGleb Smirnoff 45772e66a6SGleb Smirnoff #include "opt_altq.h" 46772e66a6SGleb Smirnoff #include "opt_inet.h" 47772e66a6SGleb Smirnoff #include "opt_inet6.h" 48772e66a6SGleb Smirnoff 49772e66a6SGleb Smirnoff #ifdef ALTQ_HFSC /* hfsc is enabled by ALTQ_HFSC option in opt_altq.h */ 50772e66a6SGleb Smirnoff 51772e66a6SGleb Smirnoff #include <sys/param.h> 52772e66a6SGleb Smirnoff #include <sys/malloc.h> 53772e66a6SGleb Smirnoff #include <sys/mbuf.h> 54772e66a6SGleb Smirnoff #include <sys/socket.h> 55772e66a6SGleb Smirnoff #include <sys/systm.h> 56772e66a6SGleb Smirnoff #include <sys/errno.h> 57772e66a6SGleb Smirnoff #include <sys/queue.h> 58772e66a6SGleb Smirnoff #if 1 /* ALTQ3_COMPAT */ 59772e66a6SGleb Smirnoff #include <sys/sockio.h> 60772e66a6SGleb Smirnoff #include <sys/proc.h> 61772e66a6SGleb Smirnoff #include <sys/kernel.h> 62772e66a6SGleb Smirnoff #endif /* ALTQ3_COMPAT */ 63772e66a6SGleb Smirnoff 64772e66a6SGleb Smirnoff #include <net/if.h> 65772e66a6SGleb Smirnoff #include <net/if_var.h> 66*2c2b37adSJustin Hibbits #include <net/if_private.h> 67772e66a6SGleb Smirnoff #include <netinet/in.h> 68772e66a6SGleb Smirnoff 69772e66a6SGleb Smirnoff #include <netpfil/pf/pf.h> 70772e66a6SGleb Smirnoff #include <netpfil/pf/pf_altq.h> 71772e66a6SGleb Smirnoff #include <netpfil/pf/pf_mtag.h> 72772e66a6SGleb Smirnoff #include <net/altq/altq.h> 73772e66a6SGleb Smirnoff #include <net/altq/altq_hfsc.h> 74772e66a6SGleb Smirnoff 75772e66a6SGleb Smirnoff /* 76772e66a6SGleb Smirnoff * function prototypes 77772e66a6SGleb Smirnoff */ 78772e66a6SGleb Smirnoff static int hfsc_clear_interface(struct hfsc_if *); 79772e66a6SGleb Smirnoff static int hfsc_request(struct ifaltq *, int, void *); 80772e66a6SGleb Smirnoff static void hfsc_purge(struct hfsc_if *); 81772e66a6SGleb Smirnoff static struct hfsc_class *hfsc_class_create(struct hfsc_if *, 82772e66a6SGleb Smirnoff struct service_curve *, struct service_curve *, struct service_curve *, 83772e66a6SGleb Smirnoff struct hfsc_class *, int, int, int); 84772e66a6SGleb Smirnoff static int hfsc_class_destroy(struct hfsc_class *); 85772e66a6SGleb Smirnoff static struct hfsc_class *hfsc_nextclass(struct hfsc_class *); 86772e66a6SGleb Smirnoff static int hfsc_enqueue(struct ifaltq *, struct mbuf *, 87772e66a6SGleb Smirnoff struct altq_pktattr *); 88772e66a6SGleb Smirnoff static struct mbuf *hfsc_dequeue(struct ifaltq *, int); 89772e66a6SGleb Smirnoff 90772e66a6SGleb Smirnoff static int hfsc_addq(struct hfsc_class *, struct mbuf *); 91772e66a6SGleb Smirnoff static struct mbuf *hfsc_getq(struct hfsc_class *); 92772e66a6SGleb Smirnoff static struct mbuf *hfsc_pollq(struct hfsc_class *); 93772e66a6SGleb Smirnoff static void hfsc_purgeq(struct hfsc_class *); 94772e66a6SGleb Smirnoff 95772e66a6SGleb Smirnoff static void update_cfmin(struct hfsc_class *); 96772e66a6SGleb Smirnoff static void set_active(struct hfsc_class *, int); 97772e66a6SGleb Smirnoff static void set_passive(struct hfsc_class *); 98772e66a6SGleb Smirnoff 99772e66a6SGleb Smirnoff static void init_ed(struct hfsc_class *, int); 100772e66a6SGleb Smirnoff static void update_ed(struct hfsc_class *, int); 101772e66a6SGleb Smirnoff static void update_d(struct hfsc_class *, int); 102772e66a6SGleb Smirnoff static void init_vf(struct hfsc_class *, int); 103772e66a6SGleb Smirnoff static void update_vf(struct hfsc_class *, int, u_int64_t); 104772e66a6SGleb Smirnoff static void ellist_insert(struct hfsc_class *); 105772e66a6SGleb Smirnoff static void ellist_remove(struct hfsc_class *); 106772e66a6SGleb Smirnoff static void ellist_update(struct hfsc_class *); 107772e66a6SGleb Smirnoff struct hfsc_class *hfsc_get_mindl(struct hfsc_if *, u_int64_t); 108772e66a6SGleb Smirnoff static void actlist_insert(struct hfsc_class *); 109772e66a6SGleb Smirnoff static void actlist_remove(struct hfsc_class *); 110772e66a6SGleb Smirnoff static void actlist_update(struct hfsc_class *); 111772e66a6SGleb Smirnoff 112772e66a6SGleb Smirnoff static struct hfsc_class *actlist_firstfit(struct hfsc_class *, 113772e66a6SGleb Smirnoff u_int64_t); 114772e66a6SGleb Smirnoff 115772e66a6SGleb Smirnoff static __inline u_int64_t seg_x2y(u_int64_t, u_int64_t); 116772e66a6SGleb Smirnoff static __inline u_int64_t seg_y2x(u_int64_t, u_int64_t); 117249cc75fSPatrick Kelsey static __inline u_int64_t m2sm(u_int64_t); 118249cc75fSPatrick Kelsey static __inline u_int64_t m2ism(u_int64_t); 119772e66a6SGleb Smirnoff static __inline u_int64_t d2dx(u_int); 120249cc75fSPatrick Kelsey static u_int64_t sm2m(u_int64_t); 121772e66a6SGleb Smirnoff static u_int dx2d(u_int64_t); 122772e66a6SGleb Smirnoff 123772e66a6SGleb Smirnoff static void sc2isc(struct service_curve *, struct internal_sc *); 124772e66a6SGleb Smirnoff static void rtsc_init(struct runtime_sc *, struct internal_sc *, 125772e66a6SGleb Smirnoff u_int64_t, u_int64_t); 126772e66a6SGleb Smirnoff static u_int64_t rtsc_y2x(struct runtime_sc *, u_int64_t); 127772e66a6SGleb Smirnoff static u_int64_t rtsc_x2y(struct runtime_sc *, u_int64_t); 128772e66a6SGleb Smirnoff static void rtsc_min(struct runtime_sc *, struct internal_sc *, 129772e66a6SGleb Smirnoff u_int64_t, u_int64_t); 130772e66a6SGleb Smirnoff 131249cc75fSPatrick Kelsey static void get_class_stats_v0(struct hfsc_classstats_v0 *, 132249cc75fSPatrick Kelsey struct hfsc_class *); 133249cc75fSPatrick Kelsey static void get_class_stats_v1(struct hfsc_classstats_v1 *, 134772e66a6SGleb Smirnoff struct hfsc_class *); 135772e66a6SGleb Smirnoff static struct hfsc_class *clh_to_clp(struct hfsc_if *, u_int32_t); 136772e66a6SGleb Smirnoff 137772e66a6SGleb Smirnoff /* 138772e66a6SGleb Smirnoff * macros 139772e66a6SGleb Smirnoff */ 140772e66a6SGleb Smirnoff #define is_a_parent_class(cl) ((cl)->cl_children != NULL) 141772e66a6SGleb Smirnoff 142249cc75fSPatrick Kelsey #define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ 143772e66a6SGleb Smirnoff 144772e66a6SGleb Smirnoff int 145772e66a6SGleb Smirnoff hfsc_pfattach(struct pf_altq *a) 146772e66a6SGleb Smirnoff { 147772e66a6SGleb Smirnoff struct ifnet *ifp; 148772e66a6SGleb Smirnoff int s, error; 149772e66a6SGleb Smirnoff 150772e66a6SGleb Smirnoff if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) 151772e66a6SGleb Smirnoff return (EINVAL); 152772e66a6SGleb Smirnoff s = splnet(); 153772e66a6SGleb Smirnoff error = altq_attach(&ifp->if_snd, ALTQT_HFSC, a->altq_disc, 15427b2aa49SKristof Provost hfsc_enqueue, hfsc_dequeue, hfsc_request); 155772e66a6SGleb Smirnoff splx(s); 156772e66a6SGleb Smirnoff return (error); 157772e66a6SGleb Smirnoff } 158772e66a6SGleb Smirnoff 159772e66a6SGleb Smirnoff int 1608f2ac656SPatrick Kelsey hfsc_add_altq(struct ifnet *ifp, struct pf_altq *a) 161772e66a6SGleb Smirnoff { 162772e66a6SGleb Smirnoff struct hfsc_if *hif; 163772e66a6SGleb Smirnoff 1648f2ac656SPatrick Kelsey if (ifp == NULL) 165772e66a6SGleb Smirnoff return (EINVAL); 166772e66a6SGleb Smirnoff if (!ALTQ_IS_READY(&ifp->if_snd)) 167772e66a6SGleb Smirnoff return (ENODEV); 168772e66a6SGleb Smirnoff 169772e66a6SGleb Smirnoff hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_NOWAIT | M_ZERO); 170772e66a6SGleb Smirnoff if (hif == NULL) 171772e66a6SGleb Smirnoff return (ENOMEM); 172772e66a6SGleb Smirnoff 173772e66a6SGleb Smirnoff TAILQ_INIT(&hif->hif_eligible); 174772e66a6SGleb Smirnoff hif->hif_ifq = &ifp->if_snd; 175772e66a6SGleb Smirnoff 176772e66a6SGleb Smirnoff /* keep the state in pf_altq */ 177772e66a6SGleb Smirnoff a->altq_disc = hif; 178772e66a6SGleb Smirnoff 179772e66a6SGleb Smirnoff return (0); 180772e66a6SGleb Smirnoff } 181772e66a6SGleb Smirnoff 182772e66a6SGleb Smirnoff int 183772e66a6SGleb Smirnoff hfsc_remove_altq(struct pf_altq *a) 184772e66a6SGleb Smirnoff { 185772e66a6SGleb Smirnoff struct hfsc_if *hif; 186772e66a6SGleb Smirnoff 187772e66a6SGleb Smirnoff if ((hif = a->altq_disc) == NULL) 188772e66a6SGleb Smirnoff return (EINVAL); 189772e66a6SGleb Smirnoff a->altq_disc = NULL; 190772e66a6SGleb Smirnoff 191772e66a6SGleb Smirnoff (void)hfsc_clear_interface(hif); 192772e66a6SGleb Smirnoff (void)hfsc_class_destroy(hif->hif_rootclass); 193772e66a6SGleb Smirnoff 194772e66a6SGleb Smirnoff free(hif, M_DEVBUF); 195772e66a6SGleb Smirnoff 196772e66a6SGleb Smirnoff return (0); 197772e66a6SGleb Smirnoff } 198772e66a6SGleb Smirnoff 199772e66a6SGleb Smirnoff int 200772e66a6SGleb Smirnoff hfsc_add_queue(struct pf_altq *a) 201772e66a6SGleb Smirnoff { 202772e66a6SGleb Smirnoff struct hfsc_if *hif; 203772e66a6SGleb Smirnoff struct hfsc_class *cl, *parent; 204249cc75fSPatrick Kelsey struct hfsc_opts_v1 *opts; 205772e66a6SGleb Smirnoff struct service_curve rtsc, lssc, ulsc; 206772e66a6SGleb Smirnoff 207772e66a6SGleb Smirnoff if ((hif = a->altq_disc) == NULL) 208772e66a6SGleb Smirnoff return (EINVAL); 209772e66a6SGleb Smirnoff 210772e66a6SGleb Smirnoff opts = &a->pq_u.hfsc_opts; 211772e66a6SGleb Smirnoff 212772e66a6SGleb Smirnoff if (a->parent_qid == HFSC_NULLCLASS_HANDLE && 213772e66a6SGleb Smirnoff hif->hif_rootclass == NULL) 214772e66a6SGleb Smirnoff parent = NULL; 215772e66a6SGleb Smirnoff else if ((parent = clh_to_clp(hif, a->parent_qid)) == NULL) 216772e66a6SGleb Smirnoff return (EINVAL); 217772e66a6SGleb Smirnoff 218772e66a6SGleb Smirnoff if (a->qid == 0) 219772e66a6SGleb Smirnoff return (EINVAL); 220772e66a6SGleb Smirnoff 221772e66a6SGleb Smirnoff if (clh_to_clp(hif, a->qid) != NULL) 222772e66a6SGleb Smirnoff return (EBUSY); 223772e66a6SGleb Smirnoff 224772e66a6SGleb Smirnoff rtsc.m1 = opts->rtsc_m1; 225772e66a6SGleb Smirnoff rtsc.d = opts->rtsc_d; 226772e66a6SGleb Smirnoff rtsc.m2 = opts->rtsc_m2; 227772e66a6SGleb Smirnoff lssc.m1 = opts->lssc_m1; 228772e66a6SGleb Smirnoff lssc.d = opts->lssc_d; 229772e66a6SGleb Smirnoff lssc.m2 = opts->lssc_m2; 230772e66a6SGleb Smirnoff ulsc.m1 = opts->ulsc_m1; 231772e66a6SGleb Smirnoff ulsc.d = opts->ulsc_d; 232772e66a6SGleb Smirnoff ulsc.m2 = opts->ulsc_m2; 233772e66a6SGleb Smirnoff 234772e66a6SGleb Smirnoff cl = hfsc_class_create(hif, &rtsc, &lssc, &ulsc, 235772e66a6SGleb Smirnoff parent, a->qlimit, opts->flags, a->qid); 236772e66a6SGleb Smirnoff if (cl == NULL) 237772e66a6SGleb Smirnoff return (ENOMEM); 238772e66a6SGleb Smirnoff 239772e66a6SGleb Smirnoff return (0); 240772e66a6SGleb Smirnoff } 241772e66a6SGleb Smirnoff 242772e66a6SGleb Smirnoff int 243772e66a6SGleb Smirnoff hfsc_remove_queue(struct pf_altq *a) 244772e66a6SGleb Smirnoff { 245772e66a6SGleb Smirnoff struct hfsc_if *hif; 246772e66a6SGleb Smirnoff struct hfsc_class *cl; 247772e66a6SGleb Smirnoff 248772e66a6SGleb Smirnoff if ((hif = a->altq_disc) == NULL) 249772e66a6SGleb Smirnoff return (EINVAL); 250772e66a6SGleb Smirnoff 251772e66a6SGleb Smirnoff if ((cl = clh_to_clp(hif, a->qid)) == NULL) 252772e66a6SGleb Smirnoff return (EINVAL); 253772e66a6SGleb Smirnoff 254772e66a6SGleb Smirnoff return (hfsc_class_destroy(cl)); 255772e66a6SGleb Smirnoff } 256772e66a6SGleb Smirnoff 257772e66a6SGleb Smirnoff int 258249cc75fSPatrick Kelsey hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes, int version) 259772e66a6SGleb Smirnoff { 260772e66a6SGleb Smirnoff struct hfsc_if *hif; 261772e66a6SGleb Smirnoff struct hfsc_class *cl; 262249cc75fSPatrick Kelsey union { 263249cc75fSPatrick Kelsey struct hfsc_classstats_v0 v0; 264249cc75fSPatrick Kelsey struct hfsc_classstats_v1 v1; 265249cc75fSPatrick Kelsey } stats; 266249cc75fSPatrick Kelsey size_t stats_size; 267772e66a6SGleb Smirnoff int error = 0; 268772e66a6SGleb Smirnoff 269772e66a6SGleb Smirnoff if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL) 270772e66a6SGleb Smirnoff return (EBADF); 271772e66a6SGleb Smirnoff 272772e66a6SGleb Smirnoff if ((cl = clh_to_clp(hif, a->qid)) == NULL) 273772e66a6SGleb Smirnoff return (EINVAL); 274772e66a6SGleb Smirnoff 275249cc75fSPatrick Kelsey if (version > HFSC_STATS_VERSION) 276772e66a6SGleb Smirnoff return (EINVAL); 277772e66a6SGleb Smirnoff 278249cc75fSPatrick Kelsey memset(&stats, 0, sizeof(stats)); 279249cc75fSPatrick Kelsey switch (version) { 280249cc75fSPatrick Kelsey case 0: 281249cc75fSPatrick Kelsey get_class_stats_v0(&stats.v0, cl); 282249cc75fSPatrick Kelsey stats_size = sizeof(struct hfsc_classstats_v0); 283249cc75fSPatrick Kelsey break; 284249cc75fSPatrick Kelsey case 1: 285249cc75fSPatrick Kelsey get_class_stats_v1(&stats.v1, cl); 286249cc75fSPatrick Kelsey stats_size = sizeof(struct hfsc_classstats_v1); 287249cc75fSPatrick Kelsey break; 288249cc75fSPatrick Kelsey } 289772e66a6SGleb Smirnoff 290249cc75fSPatrick Kelsey if (*nbytes < stats_size) 291249cc75fSPatrick Kelsey return (EINVAL); 292249cc75fSPatrick Kelsey 293249cc75fSPatrick Kelsey if ((error = copyout((caddr_t)&stats, ubuf, stats_size)) != 0) 294772e66a6SGleb Smirnoff return (error); 295249cc75fSPatrick Kelsey *nbytes = stats_size; 296772e66a6SGleb Smirnoff return (0); 297772e66a6SGleb Smirnoff } 298772e66a6SGleb Smirnoff 299772e66a6SGleb Smirnoff /* 300772e66a6SGleb Smirnoff * bring the interface back to the initial state by discarding 301772e66a6SGleb Smirnoff * all the filters and classes except the root class. 302772e66a6SGleb Smirnoff */ 303772e66a6SGleb Smirnoff static int 304772e66a6SGleb Smirnoff hfsc_clear_interface(struct hfsc_if *hif) 305772e66a6SGleb Smirnoff { 306772e66a6SGleb Smirnoff struct hfsc_class *cl; 307772e66a6SGleb Smirnoff 308772e66a6SGleb Smirnoff /* clear out the classes */ 309772e66a6SGleb Smirnoff while (hif->hif_rootclass != NULL && 310772e66a6SGleb Smirnoff (cl = hif->hif_rootclass->cl_children) != NULL) { 311772e66a6SGleb Smirnoff /* 312772e66a6SGleb Smirnoff * remove the first leaf class found in the hierarchy 313772e66a6SGleb Smirnoff * then start over 314772e66a6SGleb Smirnoff */ 315772e66a6SGleb Smirnoff for (; cl != NULL; cl = hfsc_nextclass(cl)) { 316772e66a6SGleb Smirnoff if (!is_a_parent_class(cl)) { 317772e66a6SGleb Smirnoff (void)hfsc_class_destroy(cl); 318772e66a6SGleb Smirnoff break; 319772e66a6SGleb Smirnoff } 320772e66a6SGleb Smirnoff } 321772e66a6SGleb Smirnoff } 322772e66a6SGleb Smirnoff 323772e66a6SGleb Smirnoff return (0); 324772e66a6SGleb Smirnoff } 325772e66a6SGleb Smirnoff 326772e66a6SGleb Smirnoff static int 327772e66a6SGleb Smirnoff hfsc_request(struct ifaltq *ifq, int req, void *arg) 328772e66a6SGleb Smirnoff { 329772e66a6SGleb Smirnoff struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 330772e66a6SGleb Smirnoff 331772e66a6SGleb Smirnoff IFQ_LOCK_ASSERT(ifq); 332772e66a6SGleb Smirnoff 333772e66a6SGleb Smirnoff switch (req) { 334772e66a6SGleb Smirnoff case ALTRQ_PURGE: 335772e66a6SGleb Smirnoff hfsc_purge(hif); 336772e66a6SGleb Smirnoff break; 337772e66a6SGleb Smirnoff } 338772e66a6SGleb Smirnoff return (0); 339772e66a6SGleb Smirnoff } 340772e66a6SGleb Smirnoff 341772e66a6SGleb Smirnoff /* discard all the queued packets on the interface */ 342772e66a6SGleb Smirnoff static void 343772e66a6SGleb Smirnoff hfsc_purge(struct hfsc_if *hif) 344772e66a6SGleb Smirnoff { 345772e66a6SGleb Smirnoff struct hfsc_class *cl; 346772e66a6SGleb Smirnoff 347772e66a6SGleb Smirnoff for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl)) 348772e66a6SGleb Smirnoff if (!qempty(cl->cl_q)) 349772e66a6SGleb Smirnoff hfsc_purgeq(cl); 350772e66a6SGleb Smirnoff if (ALTQ_IS_ENABLED(hif->hif_ifq)) 351772e66a6SGleb Smirnoff hif->hif_ifq->ifq_len = 0; 352772e66a6SGleb Smirnoff } 353772e66a6SGleb Smirnoff 354772e66a6SGleb Smirnoff struct hfsc_class * 355772e66a6SGleb Smirnoff hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc, 356772e66a6SGleb Smirnoff struct service_curve *fsc, struct service_curve *usc, 357772e66a6SGleb Smirnoff struct hfsc_class *parent, int qlimit, int flags, int qid) 358772e66a6SGleb Smirnoff { 359772e66a6SGleb Smirnoff struct hfsc_class *cl, *p; 360772e66a6SGleb Smirnoff int i, s; 361772e66a6SGleb Smirnoff 362772e66a6SGleb Smirnoff if (hif->hif_classes >= HFSC_MAX_CLASSES) 363772e66a6SGleb Smirnoff return (NULL); 364772e66a6SGleb Smirnoff 365772e66a6SGleb Smirnoff #ifndef ALTQ_RED 366772e66a6SGleb Smirnoff if (flags & HFCF_RED) { 367772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG 368772e66a6SGleb Smirnoff printf("hfsc_class_create: RED not configured for HFSC!\n"); 369772e66a6SGleb Smirnoff #endif 370772e66a6SGleb Smirnoff return (NULL); 371772e66a6SGleb Smirnoff } 372772e66a6SGleb Smirnoff #endif 3730a70aaf8SLuiz Otavio O Souza #ifndef ALTQ_CODEL 3740a70aaf8SLuiz Otavio O Souza if (flags & HFCF_CODEL) { 3750a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_DEBUG 3760a70aaf8SLuiz Otavio O Souza printf("hfsc_class_create: CODEL not configured for HFSC!\n"); 3770a70aaf8SLuiz Otavio O Souza #endif 3780a70aaf8SLuiz Otavio O Souza return (NULL); 3790a70aaf8SLuiz Otavio O Souza } 3800a70aaf8SLuiz Otavio O Souza #endif 381772e66a6SGleb Smirnoff 382772e66a6SGleb Smirnoff cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_NOWAIT | M_ZERO); 383772e66a6SGleb Smirnoff if (cl == NULL) 384772e66a6SGleb Smirnoff return (NULL); 385772e66a6SGleb Smirnoff 386772e66a6SGleb Smirnoff cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO); 387772e66a6SGleb Smirnoff if (cl->cl_q == NULL) 388772e66a6SGleb Smirnoff goto err_ret; 389772e66a6SGleb Smirnoff 390772e66a6SGleb Smirnoff TAILQ_INIT(&cl->cl_actc); 391772e66a6SGleb Smirnoff 392772e66a6SGleb Smirnoff if (qlimit == 0) 393772e66a6SGleb Smirnoff qlimit = 50; /* use default */ 394772e66a6SGleb Smirnoff qlimit(cl->cl_q) = qlimit; 395772e66a6SGleb Smirnoff qtype(cl->cl_q) = Q_DROPTAIL; 396772e66a6SGleb Smirnoff qlen(cl->cl_q) = 0; 3970a70aaf8SLuiz Otavio O Souza qsize(cl->cl_q) = 0; 398772e66a6SGleb Smirnoff cl->cl_flags = flags; 399772e66a6SGleb Smirnoff #ifdef ALTQ_RED 400772e66a6SGleb Smirnoff if (flags & (HFCF_RED|HFCF_RIO)) { 401772e66a6SGleb Smirnoff int red_flags, red_pkttime; 402772e66a6SGleb Smirnoff u_int m2; 403772e66a6SGleb Smirnoff 404772e66a6SGleb Smirnoff m2 = 0; 405772e66a6SGleb Smirnoff if (rsc != NULL && rsc->m2 > m2) 406772e66a6SGleb Smirnoff m2 = rsc->m2; 407772e66a6SGleb Smirnoff if (fsc != NULL && fsc->m2 > m2) 408772e66a6SGleb Smirnoff m2 = fsc->m2; 409772e66a6SGleb Smirnoff if (usc != NULL && usc->m2 > m2) 410772e66a6SGleb Smirnoff m2 = usc->m2; 411772e66a6SGleb Smirnoff 412772e66a6SGleb Smirnoff red_flags = 0; 413772e66a6SGleb Smirnoff if (flags & HFCF_ECN) 414772e66a6SGleb Smirnoff red_flags |= REDF_ECN; 415772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 416772e66a6SGleb Smirnoff if (flags & HFCF_CLEARDSCP) 417772e66a6SGleb Smirnoff red_flags |= RIOF_CLEARDSCP; 418772e66a6SGleb Smirnoff #endif 419772e66a6SGleb Smirnoff if (m2 < 8) 420772e66a6SGleb Smirnoff red_pkttime = 1000 * 1000 * 1000; /* 1 sec */ 421772e66a6SGleb Smirnoff else 422772e66a6SGleb Smirnoff red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu 423772e66a6SGleb Smirnoff * 1000 * 1000 * 1000 / (m2 / 8); 424772e66a6SGleb Smirnoff if (flags & HFCF_RED) { 425772e66a6SGleb Smirnoff cl->cl_red = red_alloc(0, 0, 426772e66a6SGleb Smirnoff qlimit(cl->cl_q) * 10/100, 427772e66a6SGleb Smirnoff qlimit(cl->cl_q) * 30/100, 428772e66a6SGleb Smirnoff red_flags, red_pkttime); 429772e66a6SGleb Smirnoff if (cl->cl_red != NULL) 430772e66a6SGleb Smirnoff qtype(cl->cl_q) = Q_RED; 431772e66a6SGleb Smirnoff } 432772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 433772e66a6SGleb Smirnoff else { 434772e66a6SGleb Smirnoff cl->cl_red = (red_t *)rio_alloc(0, NULL, 435772e66a6SGleb Smirnoff red_flags, red_pkttime); 436772e66a6SGleb Smirnoff if (cl->cl_red != NULL) 437772e66a6SGleb Smirnoff qtype(cl->cl_q) = Q_RIO; 438772e66a6SGleb Smirnoff } 439772e66a6SGleb Smirnoff #endif 440772e66a6SGleb Smirnoff } 441772e66a6SGleb Smirnoff #endif /* ALTQ_RED */ 4420a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 4430a70aaf8SLuiz Otavio O Souza if (flags & HFCF_CODEL) { 4440a70aaf8SLuiz Otavio O Souza cl->cl_codel = codel_alloc(5, 100, 0); 4450a70aaf8SLuiz Otavio O Souza if (cl->cl_codel != NULL) 4460a70aaf8SLuiz Otavio O Souza qtype(cl->cl_q) = Q_CODEL; 4470a70aaf8SLuiz Otavio O Souza } 4480a70aaf8SLuiz Otavio O Souza #endif 449772e66a6SGleb Smirnoff 450772e66a6SGleb Smirnoff if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) { 451772e66a6SGleb Smirnoff cl->cl_rsc = malloc(sizeof(struct internal_sc), 452772e66a6SGleb Smirnoff M_DEVBUF, M_NOWAIT); 453772e66a6SGleb Smirnoff if (cl->cl_rsc == NULL) 454772e66a6SGleb Smirnoff goto err_ret; 455772e66a6SGleb Smirnoff sc2isc(rsc, cl->cl_rsc); 456772e66a6SGleb Smirnoff rtsc_init(&cl->cl_deadline, cl->cl_rsc, 0, 0); 457772e66a6SGleb Smirnoff rtsc_init(&cl->cl_eligible, cl->cl_rsc, 0, 0); 458772e66a6SGleb Smirnoff } 459772e66a6SGleb Smirnoff if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0)) { 460772e66a6SGleb Smirnoff cl->cl_fsc = malloc(sizeof(struct internal_sc), 461772e66a6SGleb Smirnoff M_DEVBUF, M_NOWAIT); 462772e66a6SGleb Smirnoff if (cl->cl_fsc == NULL) 463772e66a6SGleb Smirnoff goto err_ret; 464772e66a6SGleb Smirnoff sc2isc(fsc, cl->cl_fsc); 465772e66a6SGleb Smirnoff rtsc_init(&cl->cl_virtual, cl->cl_fsc, 0, 0); 466772e66a6SGleb Smirnoff } 467772e66a6SGleb Smirnoff if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0)) { 468772e66a6SGleb Smirnoff cl->cl_usc = malloc(sizeof(struct internal_sc), 469772e66a6SGleb Smirnoff M_DEVBUF, M_NOWAIT); 470772e66a6SGleb Smirnoff if (cl->cl_usc == NULL) 471772e66a6SGleb Smirnoff goto err_ret; 472772e66a6SGleb Smirnoff sc2isc(usc, cl->cl_usc); 473772e66a6SGleb Smirnoff rtsc_init(&cl->cl_ulimit, cl->cl_usc, 0, 0); 474772e66a6SGleb Smirnoff } 475772e66a6SGleb Smirnoff 476772e66a6SGleb Smirnoff cl->cl_id = hif->hif_classid++; 477772e66a6SGleb Smirnoff cl->cl_handle = qid; 478772e66a6SGleb Smirnoff cl->cl_hif = hif; 479772e66a6SGleb Smirnoff cl->cl_parent = parent; 480772e66a6SGleb Smirnoff 481772e66a6SGleb Smirnoff s = splnet(); 482772e66a6SGleb Smirnoff IFQ_LOCK(hif->hif_ifq); 483772e66a6SGleb Smirnoff hif->hif_classes++; 484772e66a6SGleb Smirnoff 485772e66a6SGleb Smirnoff /* 486772e66a6SGleb Smirnoff * find a free slot in the class table. if the slot matching 487772e66a6SGleb Smirnoff * the lower bits of qid is free, use this slot. otherwise, 488772e66a6SGleb Smirnoff * use the first free slot. 489772e66a6SGleb Smirnoff */ 490772e66a6SGleb Smirnoff i = qid % HFSC_MAX_CLASSES; 491772e66a6SGleb Smirnoff if (hif->hif_class_tbl[i] == NULL) 492772e66a6SGleb Smirnoff hif->hif_class_tbl[i] = cl; 493772e66a6SGleb Smirnoff else { 494772e66a6SGleb Smirnoff for (i = 0; i < HFSC_MAX_CLASSES; i++) 495772e66a6SGleb Smirnoff if (hif->hif_class_tbl[i] == NULL) { 496772e66a6SGleb Smirnoff hif->hif_class_tbl[i] = cl; 497772e66a6SGleb Smirnoff break; 498772e66a6SGleb Smirnoff } 499772e66a6SGleb Smirnoff if (i == HFSC_MAX_CLASSES) { 500772e66a6SGleb Smirnoff IFQ_UNLOCK(hif->hif_ifq); 501772e66a6SGleb Smirnoff splx(s); 502772e66a6SGleb Smirnoff goto err_ret; 503772e66a6SGleb Smirnoff } 504772e66a6SGleb Smirnoff } 5058f2ac656SPatrick Kelsey cl->cl_slot = i; 506772e66a6SGleb Smirnoff 507772e66a6SGleb Smirnoff if (flags & HFCF_DEFAULTCLASS) 508772e66a6SGleb Smirnoff hif->hif_defaultclass = cl; 509772e66a6SGleb Smirnoff 510772e66a6SGleb Smirnoff if (parent == NULL) { 511772e66a6SGleb Smirnoff /* this is root class */ 512772e66a6SGleb Smirnoff hif->hif_rootclass = cl; 513772e66a6SGleb Smirnoff } else { 514772e66a6SGleb Smirnoff /* add this class to the children list of the parent */ 515772e66a6SGleb Smirnoff if ((p = parent->cl_children) == NULL) 516772e66a6SGleb Smirnoff parent->cl_children = cl; 517772e66a6SGleb Smirnoff else { 51813890d30SJames Skon /* Put new class at beginning of list */ 51913890d30SJames Skon cl->cl_siblings = parent->cl_children; 52013890d30SJames Skon parent->cl_children = cl; 521772e66a6SGleb Smirnoff } 522772e66a6SGleb Smirnoff } 523772e66a6SGleb Smirnoff IFQ_UNLOCK(hif->hif_ifq); 524772e66a6SGleb Smirnoff splx(s); 525772e66a6SGleb Smirnoff 526772e66a6SGleb Smirnoff return (cl); 527772e66a6SGleb Smirnoff 528772e66a6SGleb Smirnoff err_ret: 529772e66a6SGleb Smirnoff if (cl->cl_red != NULL) { 530772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 531772e66a6SGleb Smirnoff if (q_is_rio(cl->cl_q)) 532772e66a6SGleb Smirnoff rio_destroy((rio_t *)cl->cl_red); 533772e66a6SGleb Smirnoff #endif 534772e66a6SGleb Smirnoff #ifdef ALTQ_RED 535772e66a6SGleb Smirnoff if (q_is_red(cl->cl_q)) 536772e66a6SGleb Smirnoff red_destroy(cl->cl_red); 537772e66a6SGleb Smirnoff #endif 5380a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 5390a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->cl_q)) 5400a70aaf8SLuiz Otavio O Souza codel_destroy(cl->cl_codel); 5410a70aaf8SLuiz Otavio O Souza #endif 542772e66a6SGleb Smirnoff } 543772e66a6SGleb Smirnoff if (cl->cl_fsc != NULL) 544772e66a6SGleb Smirnoff free(cl->cl_fsc, M_DEVBUF); 545772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) 546772e66a6SGleb Smirnoff free(cl->cl_rsc, M_DEVBUF); 547772e66a6SGleb Smirnoff if (cl->cl_usc != NULL) 548772e66a6SGleb Smirnoff free(cl->cl_usc, M_DEVBUF); 549772e66a6SGleb Smirnoff if (cl->cl_q != NULL) 550772e66a6SGleb Smirnoff free(cl->cl_q, M_DEVBUF); 551772e66a6SGleb Smirnoff free(cl, M_DEVBUF); 552772e66a6SGleb Smirnoff return (NULL); 553772e66a6SGleb Smirnoff } 554772e66a6SGleb Smirnoff 555772e66a6SGleb Smirnoff static int 556772e66a6SGleb Smirnoff hfsc_class_destroy(struct hfsc_class *cl) 557772e66a6SGleb Smirnoff { 5588f2ac656SPatrick Kelsey int s; 559772e66a6SGleb Smirnoff 560772e66a6SGleb Smirnoff if (cl == NULL) 561772e66a6SGleb Smirnoff return (0); 562772e66a6SGleb Smirnoff 563772e66a6SGleb Smirnoff if (is_a_parent_class(cl)) 564772e66a6SGleb Smirnoff return (EBUSY); 565772e66a6SGleb Smirnoff 566772e66a6SGleb Smirnoff s = splnet(); 567772e66a6SGleb Smirnoff IFQ_LOCK(cl->cl_hif->hif_ifq); 568772e66a6SGleb Smirnoff 569772e66a6SGleb Smirnoff if (!qempty(cl->cl_q)) 570772e66a6SGleb Smirnoff hfsc_purgeq(cl); 571772e66a6SGleb Smirnoff 572772e66a6SGleb Smirnoff if (cl->cl_parent == NULL) { 573772e66a6SGleb Smirnoff /* this is root class */ 574772e66a6SGleb Smirnoff } else { 575772e66a6SGleb Smirnoff struct hfsc_class *p = cl->cl_parent->cl_children; 576772e66a6SGleb Smirnoff 577772e66a6SGleb Smirnoff if (p == cl) 578772e66a6SGleb Smirnoff cl->cl_parent->cl_children = cl->cl_siblings; 579772e66a6SGleb Smirnoff else do { 580772e66a6SGleb Smirnoff if (p->cl_siblings == cl) { 581772e66a6SGleb Smirnoff p->cl_siblings = cl->cl_siblings; 582772e66a6SGleb Smirnoff break; 583772e66a6SGleb Smirnoff } 584772e66a6SGleb Smirnoff } while ((p = p->cl_siblings) != NULL); 585772e66a6SGleb Smirnoff ASSERT(p != NULL); 586772e66a6SGleb Smirnoff } 587772e66a6SGleb Smirnoff 5888f2ac656SPatrick Kelsey cl->cl_hif->hif_class_tbl[cl->cl_slot] = NULL; 589772e66a6SGleb Smirnoff cl->cl_hif->hif_classes--; 590772e66a6SGleb Smirnoff IFQ_UNLOCK(cl->cl_hif->hif_ifq); 591772e66a6SGleb Smirnoff splx(s); 592772e66a6SGleb Smirnoff 593772e66a6SGleb Smirnoff if (cl->cl_red != NULL) { 594772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 595772e66a6SGleb Smirnoff if (q_is_rio(cl->cl_q)) 596772e66a6SGleb Smirnoff rio_destroy((rio_t *)cl->cl_red); 597772e66a6SGleb Smirnoff #endif 598772e66a6SGleb Smirnoff #ifdef ALTQ_RED 599772e66a6SGleb Smirnoff if (q_is_red(cl->cl_q)) 600772e66a6SGleb Smirnoff red_destroy(cl->cl_red); 601772e66a6SGleb Smirnoff #endif 6020a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 6030a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->cl_q)) 6040a70aaf8SLuiz Otavio O Souza codel_destroy(cl->cl_codel); 6050a70aaf8SLuiz Otavio O Souza #endif 606772e66a6SGleb Smirnoff } 607772e66a6SGleb Smirnoff 608772e66a6SGleb Smirnoff IFQ_LOCK(cl->cl_hif->hif_ifq); 609772e66a6SGleb Smirnoff if (cl == cl->cl_hif->hif_rootclass) 610772e66a6SGleb Smirnoff cl->cl_hif->hif_rootclass = NULL; 611772e66a6SGleb Smirnoff if (cl == cl->cl_hif->hif_defaultclass) 612772e66a6SGleb Smirnoff cl->cl_hif->hif_defaultclass = NULL; 613772e66a6SGleb Smirnoff IFQ_UNLOCK(cl->cl_hif->hif_ifq); 614772e66a6SGleb Smirnoff 615772e66a6SGleb Smirnoff if (cl->cl_usc != NULL) 616772e66a6SGleb Smirnoff free(cl->cl_usc, M_DEVBUF); 617772e66a6SGleb Smirnoff if (cl->cl_fsc != NULL) 618772e66a6SGleb Smirnoff free(cl->cl_fsc, M_DEVBUF); 619772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) 620772e66a6SGleb Smirnoff free(cl->cl_rsc, M_DEVBUF); 621772e66a6SGleb Smirnoff free(cl->cl_q, M_DEVBUF); 622772e66a6SGleb Smirnoff free(cl, M_DEVBUF); 623772e66a6SGleb Smirnoff 624772e66a6SGleb Smirnoff return (0); 625772e66a6SGleb Smirnoff } 626772e66a6SGleb Smirnoff 627772e66a6SGleb Smirnoff /* 628772e66a6SGleb Smirnoff * hfsc_nextclass returns the next class in the tree. 629772e66a6SGleb Smirnoff * usage: 630772e66a6SGleb Smirnoff * for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl)) 631772e66a6SGleb Smirnoff * do_something; 632772e66a6SGleb Smirnoff */ 633772e66a6SGleb Smirnoff static struct hfsc_class * 634772e66a6SGleb Smirnoff hfsc_nextclass(struct hfsc_class *cl) 635772e66a6SGleb Smirnoff { 636772e66a6SGleb Smirnoff if (cl->cl_children != NULL) 637772e66a6SGleb Smirnoff cl = cl->cl_children; 638772e66a6SGleb Smirnoff else if (cl->cl_siblings != NULL) 639772e66a6SGleb Smirnoff cl = cl->cl_siblings; 640772e66a6SGleb Smirnoff else { 641772e66a6SGleb Smirnoff while ((cl = cl->cl_parent) != NULL) 642772e66a6SGleb Smirnoff if (cl->cl_siblings) { 643772e66a6SGleb Smirnoff cl = cl->cl_siblings; 644772e66a6SGleb Smirnoff break; 645772e66a6SGleb Smirnoff } 646772e66a6SGleb Smirnoff } 647772e66a6SGleb Smirnoff 648772e66a6SGleb Smirnoff return (cl); 649772e66a6SGleb Smirnoff } 650772e66a6SGleb Smirnoff 651772e66a6SGleb Smirnoff /* 652772e66a6SGleb Smirnoff * hfsc_enqueue is an enqueue function to be registered to 653772e66a6SGleb Smirnoff * (*altq_enqueue) in struct ifaltq. 654772e66a6SGleb Smirnoff */ 655772e66a6SGleb Smirnoff static int 656772e66a6SGleb Smirnoff hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr) 657772e66a6SGleb Smirnoff { 658772e66a6SGleb Smirnoff struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 659772e66a6SGleb Smirnoff struct hfsc_class *cl; 660772e66a6SGleb Smirnoff struct pf_mtag *t; 661772e66a6SGleb Smirnoff int len; 662772e66a6SGleb Smirnoff 663772e66a6SGleb Smirnoff IFQ_LOCK_ASSERT(ifq); 664772e66a6SGleb Smirnoff 665772e66a6SGleb Smirnoff /* grab class set by classifier */ 666772e66a6SGleb Smirnoff if ((m->m_flags & M_PKTHDR) == 0) { 667772e66a6SGleb Smirnoff /* should not happen */ 668772e66a6SGleb Smirnoff printf("altq: packet for %s does not have pkthdr\n", 669772e66a6SGleb Smirnoff ifq->altq_ifp->if_xname); 670772e66a6SGleb Smirnoff m_freem(m); 671772e66a6SGleb Smirnoff return (ENOBUFS); 672772e66a6SGleb Smirnoff } 673772e66a6SGleb Smirnoff cl = NULL; 674772e66a6SGleb Smirnoff if ((t = pf_find_mtag(m)) != NULL) 675772e66a6SGleb Smirnoff cl = clh_to_clp(hif, t->qid); 676772e66a6SGleb Smirnoff if (cl == NULL || is_a_parent_class(cl)) { 677772e66a6SGleb Smirnoff cl = hif->hif_defaultclass; 678772e66a6SGleb Smirnoff if (cl == NULL) { 679772e66a6SGleb Smirnoff m_freem(m); 680772e66a6SGleb Smirnoff return (ENOBUFS); 681772e66a6SGleb Smirnoff } 682772e66a6SGleb Smirnoff } 683772e66a6SGleb Smirnoff cl->cl_pktattr = NULL; 684772e66a6SGleb Smirnoff len = m_pktlen(m); 685772e66a6SGleb Smirnoff if (hfsc_addq(cl, m) != 0) { 686772e66a6SGleb Smirnoff /* drop occurred. mbuf was freed in hfsc_addq. */ 687772e66a6SGleb Smirnoff PKTCNTR_ADD(&cl->cl_stats.drop_cnt, len); 688772e66a6SGleb Smirnoff return (ENOBUFS); 689772e66a6SGleb Smirnoff } 690772e66a6SGleb Smirnoff IFQ_INC_LEN(ifq); 691772e66a6SGleb Smirnoff cl->cl_hif->hif_packets++; 692772e66a6SGleb Smirnoff 693772e66a6SGleb Smirnoff /* successfully queued. */ 694772e66a6SGleb Smirnoff if (qlen(cl->cl_q) == 1) 695772e66a6SGleb Smirnoff set_active(cl, m_pktlen(m)); 696772e66a6SGleb Smirnoff 697772e66a6SGleb Smirnoff return (0); 698772e66a6SGleb Smirnoff } 699772e66a6SGleb Smirnoff 700772e66a6SGleb Smirnoff /* 701772e66a6SGleb Smirnoff * hfsc_dequeue is a dequeue function to be registered to 702772e66a6SGleb Smirnoff * (*altq_dequeue) in struct ifaltq. 703772e66a6SGleb Smirnoff * 704772e66a6SGleb Smirnoff * note: ALTDQ_POLL returns the next packet without removing the packet 705772e66a6SGleb Smirnoff * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 706772e66a6SGleb Smirnoff * ALTDQ_REMOVE must return the same packet if called immediately 707772e66a6SGleb Smirnoff * after ALTDQ_POLL. 708772e66a6SGleb Smirnoff */ 709772e66a6SGleb Smirnoff static struct mbuf * 710772e66a6SGleb Smirnoff hfsc_dequeue(struct ifaltq *ifq, int op) 711772e66a6SGleb Smirnoff { 712772e66a6SGleb Smirnoff struct hfsc_if *hif = (struct hfsc_if *)ifq->altq_disc; 713772e66a6SGleb Smirnoff struct hfsc_class *cl; 714772e66a6SGleb Smirnoff struct mbuf *m; 715772e66a6SGleb Smirnoff int len, next_len; 716772e66a6SGleb Smirnoff int realtime = 0; 717772e66a6SGleb Smirnoff u_int64_t cur_time; 718772e66a6SGleb Smirnoff 719772e66a6SGleb Smirnoff IFQ_LOCK_ASSERT(ifq); 720772e66a6SGleb Smirnoff 721772e66a6SGleb Smirnoff if (hif->hif_packets == 0) 722772e66a6SGleb Smirnoff /* no packet in the tree */ 723772e66a6SGleb Smirnoff return (NULL); 724772e66a6SGleb Smirnoff 725772e66a6SGleb Smirnoff cur_time = read_machclk(); 726772e66a6SGleb Smirnoff 727772e66a6SGleb Smirnoff if (op == ALTDQ_REMOVE && hif->hif_pollcache != NULL) { 728772e66a6SGleb Smirnoff cl = hif->hif_pollcache; 729772e66a6SGleb Smirnoff hif->hif_pollcache = NULL; 730772e66a6SGleb Smirnoff /* check if the class was scheduled by real-time criteria */ 731772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) 732772e66a6SGleb Smirnoff realtime = (cl->cl_e <= cur_time); 733772e66a6SGleb Smirnoff } else { 734772e66a6SGleb Smirnoff /* 735772e66a6SGleb Smirnoff * if there are eligible classes, use real-time criteria. 736772e66a6SGleb Smirnoff * find the class with the minimum deadline among 737772e66a6SGleb Smirnoff * the eligible classes. 738772e66a6SGleb Smirnoff */ 739772e66a6SGleb Smirnoff if ((cl = hfsc_get_mindl(hif, cur_time)) 740772e66a6SGleb Smirnoff != NULL) { 741772e66a6SGleb Smirnoff realtime = 1; 742772e66a6SGleb Smirnoff } else { 743772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG 744772e66a6SGleb Smirnoff int fits = 0; 745772e66a6SGleb Smirnoff #endif 746772e66a6SGleb Smirnoff /* 747772e66a6SGleb Smirnoff * use link-sharing criteria 748772e66a6SGleb Smirnoff * get the class with the minimum vt in the hierarchy 749772e66a6SGleb Smirnoff */ 750772e66a6SGleb Smirnoff cl = hif->hif_rootclass; 751772e66a6SGleb Smirnoff while (is_a_parent_class(cl)) { 752772e66a6SGleb Smirnoff cl = actlist_firstfit(cl, cur_time); 753772e66a6SGleb Smirnoff if (cl == NULL) { 754772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG 755772e66a6SGleb Smirnoff if (fits > 0) 756772e66a6SGleb Smirnoff printf("%d fit but none found\n",fits); 757772e66a6SGleb Smirnoff #endif 758772e66a6SGleb Smirnoff return (NULL); 759772e66a6SGleb Smirnoff } 760772e66a6SGleb Smirnoff /* 761772e66a6SGleb Smirnoff * update parent's cl_cvtmin. 762772e66a6SGleb Smirnoff * don't update if the new vt is smaller. 763772e66a6SGleb Smirnoff */ 764772e66a6SGleb Smirnoff if (cl->cl_parent->cl_cvtmin < cl->cl_vt) 765772e66a6SGleb Smirnoff cl->cl_parent->cl_cvtmin = cl->cl_vt; 766772e66a6SGleb Smirnoff #ifdef ALTQ_DEBUG 767772e66a6SGleb Smirnoff fits++; 768772e66a6SGleb Smirnoff #endif 769772e66a6SGleb Smirnoff } 770772e66a6SGleb Smirnoff } 771772e66a6SGleb Smirnoff 772772e66a6SGleb Smirnoff if (op == ALTDQ_POLL) { 773772e66a6SGleb Smirnoff hif->hif_pollcache = cl; 774772e66a6SGleb Smirnoff m = hfsc_pollq(cl); 775772e66a6SGleb Smirnoff return (m); 776772e66a6SGleb Smirnoff } 777772e66a6SGleb Smirnoff } 778772e66a6SGleb Smirnoff 779772e66a6SGleb Smirnoff m = hfsc_getq(cl); 780772e66a6SGleb Smirnoff if (m == NULL) 781772e66a6SGleb Smirnoff panic("hfsc_dequeue:"); 782772e66a6SGleb Smirnoff len = m_pktlen(m); 783772e66a6SGleb Smirnoff cl->cl_hif->hif_packets--; 784772e66a6SGleb Smirnoff IFQ_DEC_LEN(ifq); 785772e66a6SGleb Smirnoff PKTCNTR_ADD(&cl->cl_stats.xmit_cnt, len); 786772e66a6SGleb Smirnoff 787772e66a6SGleb Smirnoff update_vf(cl, len, cur_time); 788772e66a6SGleb Smirnoff if (realtime) 789772e66a6SGleb Smirnoff cl->cl_cumul += len; 790772e66a6SGleb Smirnoff 791772e66a6SGleb Smirnoff if (!qempty(cl->cl_q)) { 792772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) { 793772e66a6SGleb Smirnoff /* update ed */ 794772e66a6SGleb Smirnoff next_len = m_pktlen(qhead(cl->cl_q)); 795772e66a6SGleb Smirnoff 796772e66a6SGleb Smirnoff if (realtime) 797772e66a6SGleb Smirnoff update_ed(cl, next_len); 798772e66a6SGleb Smirnoff else 799772e66a6SGleb Smirnoff update_d(cl, next_len); 800772e66a6SGleb Smirnoff } 801772e66a6SGleb Smirnoff } else { 802772e66a6SGleb Smirnoff /* the class becomes passive */ 803772e66a6SGleb Smirnoff set_passive(cl); 804772e66a6SGleb Smirnoff } 805772e66a6SGleb Smirnoff 806772e66a6SGleb Smirnoff return (m); 807772e66a6SGleb Smirnoff } 808772e66a6SGleb Smirnoff 809772e66a6SGleb Smirnoff static int 810772e66a6SGleb Smirnoff hfsc_addq(struct hfsc_class *cl, struct mbuf *m) 811772e66a6SGleb Smirnoff { 812772e66a6SGleb Smirnoff 813772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 814772e66a6SGleb Smirnoff if (q_is_rio(cl->cl_q)) 815772e66a6SGleb Smirnoff return rio_addq((rio_t *)cl->cl_red, cl->cl_q, 816772e66a6SGleb Smirnoff m, cl->cl_pktattr); 817772e66a6SGleb Smirnoff #endif 818772e66a6SGleb Smirnoff #ifdef ALTQ_RED 819772e66a6SGleb Smirnoff if (q_is_red(cl->cl_q)) 820772e66a6SGleb Smirnoff return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr); 821772e66a6SGleb Smirnoff #endif 8220a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 8230a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->cl_q)) 8240a70aaf8SLuiz Otavio O Souza return codel_addq(cl->cl_codel, cl->cl_q, m); 8250a70aaf8SLuiz Otavio O Souza #endif 826772e66a6SGleb Smirnoff if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) { 827772e66a6SGleb Smirnoff m_freem(m); 828772e66a6SGleb Smirnoff return (-1); 829772e66a6SGleb Smirnoff } 830772e66a6SGleb Smirnoff 831772e66a6SGleb Smirnoff if (cl->cl_flags & HFCF_CLEARDSCP) 832772e66a6SGleb Smirnoff write_dsfield(m, cl->cl_pktattr, 0); 833772e66a6SGleb Smirnoff 834772e66a6SGleb Smirnoff _addq(cl->cl_q, m); 835772e66a6SGleb Smirnoff 836772e66a6SGleb Smirnoff return (0); 837772e66a6SGleb Smirnoff } 838772e66a6SGleb Smirnoff 839772e66a6SGleb Smirnoff static struct mbuf * 840772e66a6SGleb Smirnoff hfsc_getq(struct hfsc_class *cl) 841772e66a6SGleb Smirnoff { 842772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 843772e66a6SGleb Smirnoff if (q_is_rio(cl->cl_q)) 844772e66a6SGleb Smirnoff return rio_getq((rio_t *)cl->cl_red, cl->cl_q); 845772e66a6SGleb Smirnoff #endif 846772e66a6SGleb Smirnoff #ifdef ALTQ_RED 847772e66a6SGleb Smirnoff if (q_is_red(cl->cl_q)) 848772e66a6SGleb Smirnoff return red_getq(cl->cl_red, cl->cl_q); 849772e66a6SGleb Smirnoff #endif 8500a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 8510a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->cl_q)) 8520a70aaf8SLuiz Otavio O Souza return codel_getq(cl->cl_codel, cl->cl_q); 8530a70aaf8SLuiz Otavio O Souza #endif 854772e66a6SGleb Smirnoff return _getq(cl->cl_q); 855772e66a6SGleb Smirnoff } 856772e66a6SGleb Smirnoff 857772e66a6SGleb Smirnoff static struct mbuf * 858772e66a6SGleb Smirnoff hfsc_pollq(struct hfsc_class *cl) 859772e66a6SGleb Smirnoff { 860772e66a6SGleb Smirnoff return qhead(cl->cl_q); 861772e66a6SGleb Smirnoff } 862772e66a6SGleb Smirnoff 863772e66a6SGleb Smirnoff static void 864772e66a6SGleb Smirnoff hfsc_purgeq(struct hfsc_class *cl) 865772e66a6SGleb Smirnoff { 866772e66a6SGleb Smirnoff struct mbuf *m; 867772e66a6SGleb Smirnoff 868772e66a6SGleb Smirnoff if (qempty(cl->cl_q)) 869772e66a6SGleb Smirnoff return; 870772e66a6SGleb Smirnoff 871772e66a6SGleb Smirnoff while ((m = _getq(cl->cl_q)) != NULL) { 872772e66a6SGleb Smirnoff PKTCNTR_ADD(&cl->cl_stats.drop_cnt, m_pktlen(m)); 873772e66a6SGleb Smirnoff m_freem(m); 874772e66a6SGleb Smirnoff cl->cl_hif->hif_packets--; 875772e66a6SGleb Smirnoff IFQ_DEC_LEN(cl->cl_hif->hif_ifq); 876772e66a6SGleb Smirnoff } 877772e66a6SGleb Smirnoff ASSERT(qlen(cl->cl_q) == 0); 878772e66a6SGleb Smirnoff 879772e66a6SGleb Smirnoff update_vf(cl, 0, 0); /* remove cl from the actlist */ 880772e66a6SGleb Smirnoff set_passive(cl); 881772e66a6SGleb Smirnoff } 882772e66a6SGleb Smirnoff 883772e66a6SGleb Smirnoff static void 884772e66a6SGleb Smirnoff set_active(struct hfsc_class *cl, int len) 885772e66a6SGleb Smirnoff { 886772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) 887772e66a6SGleb Smirnoff init_ed(cl, len); 888772e66a6SGleb Smirnoff if (cl->cl_fsc != NULL) 889772e66a6SGleb Smirnoff init_vf(cl, len); 890772e66a6SGleb Smirnoff 891772e66a6SGleb Smirnoff cl->cl_stats.period++; 892772e66a6SGleb Smirnoff } 893772e66a6SGleb Smirnoff 894772e66a6SGleb Smirnoff static void 895772e66a6SGleb Smirnoff set_passive(struct hfsc_class *cl) 896772e66a6SGleb Smirnoff { 897772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) 898772e66a6SGleb Smirnoff ellist_remove(cl); 899772e66a6SGleb Smirnoff 900772e66a6SGleb Smirnoff /* 901772e66a6SGleb Smirnoff * actlist is now handled in update_vf() so that update_vf(cl, 0, 0) 902772e66a6SGleb Smirnoff * needs to be called explicitly to remove a class from actlist 903772e66a6SGleb Smirnoff */ 904772e66a6SGleb Smirnoff } 905772e66a6SGleb Smirnoff 906772e66a6SGleb Smirnoff static void 907772e66a6SGleb Smirnoff init_ed(struct hfsc_class *cl, int next_len) 908772e66a6SGleb Smirnoff { 909772e66a6SGleb Smirnoff u_int64_t cur_time; 910772e66a6SGleb Smirnoff 911772e66a6SGleb Smirnoff cur_time = read_machclk(); 912772e66a6SGleb Smirnoff 913772e66a6SGleb Smirnoff /* update the deadline curve */ 914772e66a6SGleb Smirnoff rtsc_min(&cl->cl_deadline, cl->cl_rsc, cur_time, cl->cl_cumul); 915772e66a6SGleb Smirnoff 916772e66a6SGleb Smirnoff /* 917772e66a6SGleb Smirnoff * update the eligible curve. 918772e66a6SGleb Smirnoff * for concave, it is equal to the deadline curve. 919772e66a6SGleb Smirnoff * for convex, it is a linear curve with slope m2. 920772e66a6SGleb Smirnoff */ 921772e66a6SGleb Smirnoff cl->cl_eligible = cl->cl_deadline; 922772e66a6SGleb Smirnoff if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) { 923772e66a6SGleb Smirnoff cl->cl_eligible.dx = 0; 924772e66a6SGleb Smirnoff cl->cl_eligible.dy = 0; 925772e66a6SGleb Smirnoff } 926772e66a6SGleb Smirnoff 927772e66a6SGleb Smirnoff /* compute e and d */ 928772e66a6SGleb Smirnoff cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 929772e66a6SGleb Smirnoff cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 930772e66a6SGleb Smirnoff 931772e66a6SGleb Smirnoff ellist_insert(cl); 932772e66a6SGleb Smirnoff } 933772e66a6SGleb Smirnoff 934772e66a6SGleb Smirnoff static void 935772e66a6SGleb Smirnoff update_ed(struct hfsc_class *cl, int next_len) 936772e66a6SGleb Smirnoff { 937772e66a6SGleb Smirnoff cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul); 938772e66a6SGleb Smirnoff cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 939772e66a6SGleb Smirnoff 940772e66a6SGleb Smirnoff ellist_update(cl); 941772e66a6SGleb Smirnoff } 942772e66a6SGleb Smirnoff 943772e66a6SGleb Smirnoff static void 944772e66a6SGleb Smirnoff update_d(struct hfsc_class *cl, int next_len) 945772e66a6SGleb Smirnoff { 946772e66a6SGleb Smirnoff cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len); 947772e66a6SGleb Smirnoff } 948772e66a6SGleb Smirnoff 949772e66a6SGleb Smirnoff static void 950772e66a6SGleb Smirnoff init_vf(struct hfsc_class *cl, int len) 951772e66a6SGleb Smirnoff { 952772e66a6SGleb Smirnoff struct hfsc_class *max_cl, *p; 953772e66a6SGleb Smirnoff u_int64_t vt, f, cur_time; 954772e66a6SGleb Smirnoff int go_active; 955772e66a6SGleb Smirnoff 956772e66a6SGleb Smirnoff cur_time = 0; 957772e66a6SGleb Smirnoff go_active = 1; 958772e66a6SGleb Smirnoff for ( ; cl->cl_parent != NULL; cl = cl->cl_parent) { 959772e66a6SGleb Smirnoff if (go_active && cl->cl_nactive++ == 0) 960772e66a6SGleb Smirnoff go_active = 1; 961772e66a6SGleb Smirnoff else 962772e66a6SGleb Smirnoff go_active = 0; 963772e66a6SGleb Smirnoff 964772e66a6SGleb Smirnoff if (go_active) { 965772e66a6SGleb Smirnoff max_cl = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead); 966772e66a6SGleb Smirnoff if (max_cl != NULL) { 967772e66a6SGleb Smirnoff /* 968772e66a6SGleb Smirnoff * set vt to the average of the min and max 969772e66a6SGleb Smirnoff * classes. if the parent's period didn't 970772e66a6SGleb Smirnoff * change, don't decrease vt of the class. 971772e66a6SGleb Smirnoff */ 972772e66a6SGleb Smirnoff vt = max_cl->cl_vt; 973772e66a6SGleb Smirnoff if (cl->cl_parent->cl_cvtmin != 0) 974772e66a6SGleb Smirnoff vt = (cl->cl_parent->cl_cvtmin + vt)/2; 975772e66a6SGleb Smirnoff 976772e66a6SGleb Smirnoff if (cl->cl_parent->cl_vtperiod != 977772e66a6SGleb Smirnoff cl->cl_parentperiod || vt > cl->cl_vt) 978772e66a6SGleb Smirnoff cl->cl_vt = vt; 979772e66a6SGleb Smirnoff } else { 980772e66a6SGleb Smirnoff /* 981772e66a6SGleb Smirnoff * first child for a new parent backlog period. 982772e66a6SGleb Smirnoff * add parent's cvtmax to vtoff of children 983772e66a6SGleb Smirnoff * to make a new vt (vtoff + vt) larger than 984772e66a6SGleb Smirnoff * the vt in the last period for all children. 985772e66a6SGleb Smirnoff */ 986772e66a6SGleb Smirnoff vt = cl->cl_parent->cl_cvtmax; 987772e66a6SGleb Smirnoff for (p = cl->cl_parent->cl_children; p != NULL; 988772e66a6SGleb Smirnoff p = p->cl_siblings) 989772e66a6SGleb Smirnoff p->cl_vtoff += vt; 990772e66a6SGleb Smirnoff cl->cl_vt = 0; 991772e66a6SGleb Smirnoff cl->cl_parent->cl_cvtmax = 0; 992772e66a6SGleb Smirnoff cl->cl_parent->cl_cvtmin = 0; 993772e66a6SGleb Smirnoff } 994772e66a6SGleb Smirnoff cl->cl_initvt = cl->cl_vt; 995772e66a6SGleb Smirnoff 996772e66a6SGleb Smirnoff /* update the virtual curve */ 997772e66a6SGleb Smirnoff vt = cl->cl_vt + cl->cl_vtoff; 998772e66a6SGleb Smirnoff rtsc_min(&cl->cl_virtual, cl->cl_fsc, vt, cl->cl_total); 999772e66a6SGleb Smirnoff if (cl->cl_virtual.x == vt) { 1000772e66a6SGleb Smirnoff cl->cl_virtual.x -= cl->cl_vtoff; 1001772e66a6SGleb Smirnoff cl->cl_vtoff = 0; 1002772e66a6SGleb Smirnoff } 1003772e66a6SGleb Smirnoff cl->cl_vtadj = 0; 1004772e66a6SGleb Smirnoff 1005772e66a6SGleb Smirnoff cl->cl_vtperiod++; /* increment vt period */ 1006772e66a6SGleb Smirnoff cl->cl_parentperiod = cl->cl_parent->cl_vtperiod; 1007772e66a6SGleb Smirnoff if (cl->cl_parent->cl_nactive == 0) 1008772e66a6SGleb Smirnoff cl->cl_parentperiod++; 1009772e66a6SGleb Smirnoff cl->cl_f = 0; 1010772e66a6SGleb Smirnoff 1011772e66a6SGleb Smirnoff actlist_insert(cl); 1012772e66a6SGleb Smirnoff 1013772e66a6SGleb Smirnoff if (cl->cl_usc != NULL) { 1014772e66a6SGleb Smirnoff /* class has upper limit curve */ 1015772e66a6SGleb Smirnoff if (cur_time == 0) 1016772e66a6SGleb Smirnoff cur_time = read_machclk(); 1017772e66a6SGleb Smirnoff 1018772e66a6SGleb Smirnoff /* update the ulimit curve */ 1019772e66a6SGleb Smirnoff rtsc_min(&cl->cl_ulimit, cl->cl_usc, cur_time, 1020772e66a6SGleb Smirnoff cl->cl_total); 1021772e66a6SGleb Smirnoff /* compute myf */ 1022772e66a6SGleb Smirnoff cl->cl_myf = rtsc_y2x(&cl->cl_ulimit, 1023772e66a6SGleb Smirnoff cl->cl_total); 1024772e66a6SGleb Smirnoff cl->cl_myfadj = 0; 1025772e66a6SGleb Smirnoff } 1026772e66a6SGleb Smirnoff } 1027772e66a6SGleb Smirnoff 1028772e66a6SGleb Smirnoff if (cl->cl_myf > cl->cl_cfmin) 1029772e66a6SGleb Smirnoff f = cl->cl_myf; 1030772e66a6SGleb Smirnoff else 1031772e66a6SGleb Smirnoff f = cl->cl_cfmin; 1032772e66a6SGleb Smirnoff if (f != cl->cl_f) { 1033772e66a6SGleb Smirnoff cl->cl_f = f; 1034772e66a6SGleb Smirnoff update_cfmin(cl->cl_parent); 1035772e66a6SGleb Smirnoff } 1036772e66a6SGleb Smirnoff } 1037772e66a6SGleb Smirnoff } 1038772e66a6SGleb Smirnoff 1039772e66a6SGleb Smirnoff static void 1040772e66a6SGleb Smirnoff update_vf(struct hfsc_class *cl, int len, u_int64_t cur_time) 1041772e66a6SGleb Smirnoff { 1042772e66a6SGleb Smirnoff u_int64_t f, myf_bound, delta; 1043772e66a6SGleb Smirnoff int go_passive; 1044772e66a6SGleb Smirnoff 1045772e66a6SGleb Smirnoff go_passive = qempty(cl->cl_q); 1046772e66a6SGleb Smirnoff 1047772e66a6SGleb Smirnoff for (; cl->cl_parent != NULL; cl = cl->cl_parent) { 1048772e66a6SGleb Smirnoff cl->cl_total += len; 1049772e66a6SGleb Smirnoff 1050772e66a6SGleb Smirnoff if (cl->cl_fsc == NULL || cl->cl_nactive == 0) 1051772e66a6SGleb Smirnoff continue; 1052772e66a6SGleb Smirnoff 1053772e66a6SGleb Smirnoff if (go_passive && --cl->cl_nactive == 0) 1054772e66a6SGleb Smirnoff go_passive = 1; 1055772e66a6SGleb Smirnoff else 1056772e66a6SGleb Smirnoff go_passive = 0; 1057772e66a6SGleb Smirnoff 1058772e66a6SGleb Smirnoff if (go_passive) { 1059772e66a6SGleb Smirnoff /* no more active child, going passive */ 1060772e66a6SGleb Smirnoff 1061772e66a6SGleb Smirnoff /* update cvtmax of the parent class */ 1062772e66a6SGleb Smirnoff if (cl->cl_vt > cl->cl_parent->cl_cvtmax) 1063772e66a6SGleb Smirnoff cl->cl_parent->cl_cvtmax = cl->cl_vt; 1064772e66a6SGleb Smirnoff 1065772e66a6SGleb Smirnoff /* remove this class from the vt list */ 1066772e66a6SGleb Smirnoff actlist_remove(cl); 1067772e66a6SGleb Smirnoff 1068772e66a6SGleb Smirnoff update_cfmin(cl->cl_parent); 1069772e66a6SGleb Smirnoff 1070772e66a6SGleb Smirnoff continue; 1071772e66a6SGleb Smirnoff } 1072772e66a6SGleb Smirnoff 1073772e66a6SGleb Smirnoff /* 1074772e66a6SGleb Smirnoff * update vt and f 1075772e66a6SGleb Smirnoff */ 1076772e66a6SGleb Smirnoff cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total) 1077772e66a6SGleb Smirnoff - cl->cl_vtoff + cl->cl_vtadj; 1078772e66a6SGleb Smirnoff 1079772e66a6SGleb Smirnoff /* 1080772e66a6SGleb Smirnoff * if vt of the class is smaller than cvtmin, 1081772e66a6SGleb Smirnoff * the class was skipped in the past due to non-fit. 1082772e66a6SGleb Smirnoff * if so, we need to adjust vtadj. 1083772e66a6SGleb Smirnoff */ 1084772e66a6SGleb Smirnoff if (cl->cl_vt < cl->cl_parent->cl_cvtmin) { 1085772e66a6SGleb Smirnoff cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt; 1086772e66a6SGleb Smirnoff cl->cl_vt = cl->cl_parent->cl_cvtmin; 1087772e66a6SGleb Smirnoff } 1088772e66a6SGleb Smirnoff 1089772e66a6SGleb Smirnoff /* update the vt list */ 1090772e66a6SGleb Smirnoff actlist_update(cl); 1091772e66a6SGleb Smirnoff 1092772e66a6SGleb Smirnoff if (cl->cl_usc != NULL) { 1093772e66a6SGleb Smirnoff cl->cl_myf = cl->cl_myfadj 1094772e66a6SGleb Smirnoff + rtsc_y2x(&cl->cl_ulimit, cl->cl_total); 1095772e66a6SGleb Smirnoff 1096772e66a6SGleb Smirnoff /* 1097772e66a6SGleb Smirnoff * if myf lags behind by more than one clock tick 1098772e66a6SGleb Smirnoff * from the current time, adjust myfadj to prevent 1099772e66a6SGleb Smirnoff * a rate-limited class from going greedy. 1100772e66a6SGleb Smirnoff * in a steady state under rate-limiting, myf 1101772e66a6SGleb Smirnoff * fluctuates within one clock tick. 1102772e66a6SGleb Smirnoff */ 1103772e66a6SGleb Smirnoff myf_bound = cur_time - machclk_per_tick; 1104772e66a6SGleb Smirnoff if (cl->cl_myf < myf_bound) { 1105772e66a6SGleb Smirnoff delta = cur_time - cl->cl_myf; 1106772e66a6SGleb Smirnoff cl->cl_myfadj += delta; 1107772e66a6SGleb Smirnoff cl->cl_myf += delta; 1108772e66a6SGleb Smirnoff } 1109772e66a6SGleb Smirnoff } 1110772e66a6SGleb Smirnoff 1111772e66a6SGleb Smirnoff /* cl_f is max(cl_myf, cl_cfmin) */ 1112772e66a6SGleb Smirnoff if (cl->cl_myf > cl->cl_cfmin) 1113772e66a6SGleb Smirnoff f = cl->cl_myf; 1114772e66a6SGleb Smirnoff else 1115772e66a6SGleb Smirnoff f = cl->cl_cfmin; 1116772e66a6SGleb Smirnoff if (f != cl->cl_f) { 1117772e66a6SGleb Smirnoff cl->cl_f = f; 1118772e66a6SGleb Smirnoff update_cfmin(cl->cl_parent); 1119772e66a6SGleb Smirnoff } 1120772e66a6SGleb Smirnoff } 1121772e66a6SGleb Smirnoff } 1122772e66a6SGleb Smirnoff 1123772e66a6SGleb Smirnoff static void 1124772e66a6SGleb Smirnoff update_cfmin(struct hfsc_class *cl) 1125772e66a6SGleb Smirnoff { 1126772e66a6SGleb Smirnoff struct hfsc_class *p; 1127772e66a6SGleb Smirnoff u_int64_t cfmin; 1128772e66a6SGleb Smirnoff 1129772e66a6SGleb Smirnoff if (TAILQ_EMPTY(&cl->cl_actc)) { 1130772e66a6SGleb Smirnoff cl->cl_cfmin = 0; 1131772e66a6SGleb Smirnoff return; 1132772e66a6SGleb Smirnoff } 1133772e66a6SGleb Smirnoff cfmin = HT_INFINITY; 1134772e66a6SGleb Smirnoff TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) { 1135772e66a6SGleb Smirnoff if (p->cl_f == 0) { 1136772e66a6SGleb Smirnoff cl->cl_cfmin = 0; 1137772e66a6SGleb Smirnoff return; 1138772e66a6SGleb Smirnoff } 1139772e66a6SGleb Smirnoff if (p->cl_f < cfmin) 1140772e66a6SGleb Smirnoff cfmin = p->cl_f; 1141772e66a6SGleb Smirnoff } 1142772e66a6SGleb Smirnoff cl->cl_cfmin = cfmin; 1143772e66a6SGleb Smirnoff } 1144772e66a6SGleb Smirnoff 1145772e66a6SGleb Smirnoff /* 1146772e66a6SGleb Smirnoff * TAILQ based ellist and actlist implementation 1147772e66a6SGleb Smirnoff * (ion wanted to make a calendar queue based implementation) 1148772e66a6SGleb Smirnoff */ 1149772e66a6SGleb Smirnoff /* 1150772e66a6SGleb Smirnoff * eligible list holds backlogged classes being sorted by their eligible times. 1151772e66a6SGleb Smirnoff * there is one eligible list per interface. 1152772e66a6SGleb Smirnoff */ 1153772e66a6SGleb Smirnoff 1154772e66a6SGleb Smirnoff static void 1155772e66a6SGleb Smirnoff ellist_insert(struct hfsc_class *cl) 1156772e66a6SGleb Smirnoff { 1157772e66a6SGleb Smirnoff struct hfsc_if *hif = cl->cl_hif; 1158772e66a6SGleb Smirnoff struct hfsc_class *p; 1159772e66a6SGleb Smirnoff 1160772e66a6SGleb Smirnoff /* check the last entry first */ 1161772e66a6SGleb Smirnoff if ((p = TAILQ_LAST(&hif->hif_eligible, elighead)) == NULL || 1162772e66a6SGleb Smirnoff p->cl_e <= cl->cl_e) { 1163772e66a6SGleb Smirnoff TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist); 1164772e66a6SGleb Smirnoff return; 1165772e66a6SGleb Smirnoff } 1166772e66a6SGleb Smirnoff 1167772e66a6SGleb Smirnoff TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) { 1168772e66a6SGleb Smirnoff if (cl->cl_e < p->cl_e) { 1169772e66a6SGleb Smirnoff TAILQ_INSERT_BEFORE(p, cl, cl_ellist); 1170772e66a6SGleb Smirnoff return; 1171772e66a6SGleb Smirnoff } 1172772e66a6SGleb Smirnoff } 1173772e66a6SGleb Smirnoff ASSERT(0); /* should not reach here */ 1174772e66a6SGleb Smirnoff } 1175772e66a6SGleb Smirnoff 1176772e66a6SGleb Smirnoff static void 1177772e66a6SGleb Smirnoff ellist_remove(struct hfsc_class *cl) 1178772e66a6SGleb Smirnoff { 1179772e66a6SGleb Smirnoff struct hfsc_if *hif = cl->cl_hif; 1180772e66a6SGleb Smirnoff 1181772e66a6SGleb Smirnoff TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1182772e66a6SGleb Smirnoff } 1183772e66a6SGleb Smirnoff 1184772e66a6SGleb Smirnoff static void 1185772e66a6SGleb Smirnoff ellist_update(struct hfsc_class *cl) 1186772e66a6SGleb Smirnoff { 1187772e66a6SGleb Smirnoff struct hfsc_if *hif = cl->cl_hif; 1188772e66a6SGleb Smirnoff struct hfsc_class *p, *last; 1189772e66a6SGleb Smirnoff 1190772e66a6SGleb Smirnoff /* 1191772e66a6SGleb Smirnoff * the eligible time of a class increases monotonically. 1192772e66a6SGleb Smirnoff * if the next entry has a larger eligible time, nothing to do. 1193772e66a6SGleb Smirnoff */ 1194772e66a6SGleb Smirnoff p = TAILQ_NEXT(cl, cl_ellist); 1195772e66a6SGleb Smirnoff if (p == NULL || cl->cl_e <= p->cl_e) 1196772e66a6SGleb Smirnoff return; 1197772e66a6SGleb Smirnoff 1198772e66a6SGleb Smirnoff /* check the last entry */ 1199772e66a6SGleb Smirnoff last = TAILQ_LAST(&hif->hif_eligible, elighead); 1200772e66a6SGleb Smirnoff ASSERT(last != NULL); 1201772e66a6SGleb Smirnoff if (last->cl_e <= cl->cl_e) { 1202772e66a6SGleb Smirnoff TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1203772e66a6SGleb Smirnoff TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist); 1204772e66a6SGleb Smirnoff return; 1205772e66a6SGleb Smirnoff } 1206772e66a6SGleb Smirnoff 1207772e66a6SGleb Smirnoff /* 1208772e66a6SGleb Smirnoff * the new position must be between the next entry 1209772e66a6SGleb Smirnoff * and the last entry 1210772e66a6SGleb Smirnoff */ 1211772e66a6SGleb Smirnoff while ((p = TAILQ_NEXT(p, cl_ellist)) != NULL) { 1212772e66a6SGleb Smirnoff if (cl->cl_e < p->cl_e) { 1213772e66a6SGleb Smirnoff TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist); 1214772e66a6SGleb Smirnoff TAILQ_INSERT_BEFORE(p, cl, cl_ellist); 1215772e66a6SGleb Smirnoff return; 1216772e66a6SGleb Smirnoff } 1217772e66a6SGleb Smirnoff } 1218772e66a6SGleb Smirnoff ASSERT(0); /* should not reach here */ 1219772e66a6SGleb Smirnoff } 1220772e66a6SGleb Smirnoff 1221772e66a6SGleb Smirnoff /* find the class with the minimum deadline among the eligible classes */ 1222772e66a6SGleb Smirnoff struct hfsc_class * 1223772e66a6SGleb Smirnoff hfsc_get_mindl(struct hfsc_if *hif, u_int64_t cur_time) 1224772e66a6SGleb Smirnoff { 1225772e66a6SGleb Smirnoff struct hfsc_class *p, *cl = NULL; 1226772e66a6SGleb Smirnoff 1227772e66a6SGleb Smirnoff TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) { 1228772e66a6SGleb Smirnoff if (p->cl_e > cur_time) 1229772e66a6SGleb Smirnoff break; 1230772e66a6SGleb Smirnoff if (cl == NULL || p->cl_d < cl->cl_d) 1231772e66a6SGleb Smirnoff cl = p; 1232772e66a6SGleb Smirnoff } 1233772e66a6SGleb Smirnoff return (cl); 1234772e66a6SGleb Smirnoff } 1235772e66a6SGleb Smirnoff 1236772e66a6SGleb Smirnoff /* 1237772e66a6SGleb Smirnoff * active children list holds backlogged child classes being sorted 1238772e66a6SGleb Smirnoff * by their virtual time. 1239772e66a6SGleb Smirnoff * each intermediate class has one active children list. 1240772e66a6SGleb Smirnoff */ 1241772e66a6SGleb Smirnoff 1242772e66a6SGleb Smirnoff static void 1243772e66a6SGleb Smirnoff actlist_insert(struct hfsc_class *cl) 1244772e66a6SGleb Smirnoff { 1245772e66a6SGleb Smirnoff struct hfsc_class *p; 1246772e66a6SGleb Smirnoff 1247772e66a6SGleb Smirnoff /* check the last entry first */ 1248772e66a6SGleb Smirnoff if ((p = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead)) == NULL 1249772e66a6SGleb Smirnoff || p->cl_vt <= cl->cl_vt) { 1250772e66a6SGleb Smirnoff TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist); 1251772e66a6SGleb Smirnoff return; 1252772e66a6SGleb Smirnoff } 1253772e66a6SGleb Smirnoff 1254772e66a6SGleb Smirnoff TAILQ_FOREACH(p, &cl->cl_parent->cl_actc, cl_actlist) { 1255772e66a6SGleb Smirnoff if (cl->cl_vt < p->cl_vt) { 1256772e66a6SGleb Smirnoff TAILQ_INSERT_BEFORE(p, cl, cl_actlist); 1257772e66a6SGleb Smirnoff return; 1258772e66a6SGleb Smirnoff } 1259772e66a6SGleb Smirnoff } 1260772e66a6SGleb Smirnoff ASSERT(0); /* should not reach here */ 1261772e66a6SGleb Smirnoff } 1262772e66a6SGleb Smirnoff 1263772e66a6SGleb Smirnoff static void 1264772e66a6SGleb Smirnoff actlist_remove(struct hfsc_class *cl) 1265772e66a6SGleb Smirnoff { 1266772e66a6SGleb Smirnoff TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1267772e66a6SGleb Smirnoff } 1268772e66a6SGleb Smirnoff 1269772e66a6SGleb Smirnoff static void 1270772e66a6SGleb Smirnoff actlist_update(struct hfsc_class *cl) 1271772e66a6SGleb Smirnoff { 1272772e66a6SGleb Smirnoff struct hfsc_class *p, *last; 1273772e66a6SGleb Smirnoff 1274772e66a6SGleb Smirnoff /* 1275772e66a6SGleb Smirnoff * the virtual time of a class increases monotonically during its 1276772e66a6SGleb Smirnoff * backlogged period. 1277772e66a6SGleb Smirnoff * if the next entry has a larger virtual time, nothing to do. 1278772e66a6SGleb Smirnoff */ 1279772e66a6SGleb Smirnoff p = TAILQ_NEXT(cl, cl_actlist); 1280772e66a6SGleb Smirnoff if (p == NULL || cl->cl_vt < p->cl_vt) 1281772e66a6SGleb Smirnoff return; 1282772e66a6SGleb Smirnoff 1283772e66a6SGleb Smirnoff /* check the last entry */ 1284772e66a6SGleb Smirnoff last = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead); 1285772e66a6SGleb Smirnoff ASSERT(last != NULL); 1286772e66a6SGleb Smirnoff if (last->cl_vt <= cl->cl_vt) { 1287772e66a6SGleb Smirnoff TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1288772e66a6SGleb Smirnoff TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist); 1289772e66a6SGleb Smirnoff return; 1290772e66a6SGleb Smirnoff } 1291772e66a6SGleb Smirnoff 1292772e66a6SGleb Smirnoff /* 1293772e66a6SGleb Smirnoff * the new position must be between the next entry 1294772e66a6SGleb Smirnoff * and the last entry 1295772e66a6SGleb Smirnoff */ 1296772e66a6SGleb Smirnoff while ((p = TAILQ_NEXT(p, cl_actlist)) != NULL) { 1297772e66a6SGleb Smirnoff if (cl->cl_vt < p->cl_vt) { 1298772e66a6SGleb Smirnoff TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist); 1299772e66a6SGleb Smirnoff TAILQ_INSERT_BEFORE(p, cl, cl_actlist); 1300772e66a6SGleb Smirnoff return; 1301772e66a6SGleb Smirnoff } 1302772e66a6SGleb Smirnoff } 1303772e66a6SGleb Smirnoff ASSERT(0); /* should not reach here */ 1304772e66a6SGleb Smirnoff } 1305772e66a6SGleb Smirnoff 1306772e66a6SGleb Smirnoff static struct hfsc_class * 1307772e66a6SGleb Smirnoff actlist_firstfit(struct hfsc_class *cl, u_int64_t cur_time) 1308772e66a6SGleb Smirnoff { 1309772e66a6SGleb Smirnoff struct hfsc_class *p; 1310772e66a6SGleb Smirnoff 1311772e66a6SGleb Smirnoff TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) { 1312772e66a6SGleb Smirnoff if (p->cl_f <= cur_time) 1313772e66a6SGleb Smirnoff return (p); 1314772e66a6SGleb Smirnoff } 1315772e66a6SGleb Smirnoff return (NULL); 1316772e66a6SGleb Smirnoff } 1317772e66a6SGleb Smirnoff 1318772e66a6SGleb Smirnoff /* 1319772e66a6SGleb Smirnoff * service curve support functions 1320772e66a6SGleb Smirnoff * 1321772e66a6SGleb Smirnoff * external service curve parameters 1322772e66a6SGleb Smirnoff * m: bits/sec 1323772e66a6SGleb Smirnoff * d: msec 1324772e66a6SGleb Smirnoff * internal service curve parameters 1325249cc75fSPatrick Kelsey * sm: (bytes/machclk tick) << SM_SHIFT 1326249cc75fSPatrick Kelsey * ism: (machclk ticks/byte) << ISM_SHIFT 1327249cc75fSPatrick Kelsey * dx: machclk ticks 1328772e66a6SGleb Smirnoff * 1329249cc75fSPatrick Kelsey * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits. we 1330249cc75fSPatrick Kelsey * should be able to handle 100K-100Gbps linkspeed with 256 MHz machclk 1331249cc75fSPatrick Kelsey * frequency and at least 3 effective digits in decimal. 1332772e66a6SGleb Smirnoff * 1333772e66a6SGleb Smirnoff */ 1334772e66a6SGleb Smirnoff #define SM_SHIFT 24 1335249cc75fSPatrick Kelsey #define ISM_SHIFT 14 1336772e66a6SGleb Smirnoff 1337772e66a6SGleb Smirnoff #define SM_MASK ((1LL << SM_SHIFT) - 1) 1338772e66a6SGleb Smirnoff #define ISM_MASK ((1LL << ISM_SHIFT) - 1) 1339772e66a6SGleb Smirnoff 1340772e66a6SGleb Smirnoff static __inline u_int64_t 1341772e66a6SGleb Smirnoff seg_x2y(u_int64_t x, u_int64_t sm) 1342772e66a6SGleb Smirnoff { 1343772e66a6SGleb Smirnoff u_int64_t y; 1344772e66a6SGleb Smirnoff 1345772e66a6SGleb Smirnoff /* 1346772e66a6SGleb Smirnoff * compute 1347772e66a6SGleb Smirnoff * y = x * sm >> SM_SHIFT 1348772e66a6SGleb Smirnoff * but divide it for the upper and lower bits to avoid overflow 1349772e66a6SGleb Smirnoff */ 1350772e66a6SGleb Smirnoff y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT); 1351772e66a6SGleb Smirnoff return (y); 1352772e66a6SGleb Smirnoff } 1353772e66a6SGleb Smirnoff 1354772e66a6SGleb Smirnoff static __inline u_int64_t 1355772e66a6SGleb Smirnoff seg_y2x(u_int64_t y, u_int64_t ism) 1356772e66a6SGleb Smirnoff { 1357772e66a6SGleb Smirnoff u_int64_t x; 1358772e66a6SGleb Smirnoff 1359772e66a6SGleb Smirnoff if (y == 0) 1360772e66a6SGleb Smirnoff x = 0; 1361772e66a6SGleb Smirnoff else if (ism == HT_INFINITY) 1362772e66a6SGleb Smirnoff x = HT_INFINITY; 1363772e66a6SGleb Smirnoff else { 1364772e66a6SGleb Smirnoff x = (y >> ISM_SHIFT) * ism 1365772e66a6SGleb Smirnoff + (((y & ISM_MASK) * ism) >> ISM_SHIFT); 1366772e66a6SGleb Smirnoff } 1367772e66a6SGleb Smirnoff return (x); 1368772e66a6SGleb Smirnoff } 1369772e66a6SGleb Smirnoff 1370772e66a6SGleb Smirnoff static __inline u_int64_t 1371249cc75fSPatrick Kelsey m2sm(u_int64_t m) 1372772e66a6SGleb Smirnoff { 1373772e66a6SGleb Smirnoff u_int64_t sm; 1374772e66a6SGleb Smirnoff 1375249cc75fSPatrick Kelsey sm = (m << SM_SHIFT) / 8 / machclk_freq; 1376772e66a6SGleb Smirnoff return (sm); 1377772e66a6SGleb Smirnoff } 1378772e66a6SGleb Smirnoff 1379772e66a6SGleb Smirnoff static __inline u_int64_t 1380249cc75fSPatrick Kelsey m2ism(u_int64_t m) 1381772e66a6SGleb Smirnoff { 1382772e66a6SGleb Smirnoff u_int64_t ism; 1383772e66a6SGleb Smirnoff 1384772e66a6SGleb Smirnoff if (m == 0) 1385772e66a6SGleb Smirnoff ism = HT_INFINITY; 1386772e66a6SGleb Smirnoff else 1387772e66a6SGleb Smirnoff ism = ((u_int64_t)machclk_freq << ISM_SHIFT) * 8 / m; 1388772e66a6SGleb Smirnoff return (ism); 1389772e66a6SGleb Smirnoff } 1390772e66a6SGleb Smirnoff 1391772e66a6SGleb Smirnoff static __inline u_int64_t 1392772e66a6SGleb Smirnoff d2dx(u_int d) 1393772e66a6SGleb Smirnoff { 1394772e66a6SGleb Smirnoff u_int64_t dx; 1395772e66a6SGleb Smirnoff 1396772e66a6SGleb Smirnoff dx = ((u_int64_t)d * machclk_freq) / 1000; 1397772e66a6SGleb Smirnoff return (dx); 1398772e66a6SGleb Smirnoff } 1399772e66a6SGleb Smirnoff 1400249cc75fSPatrick Kelsey static u_int64_t 1401772e66a6SGleb Smirnoff sm2m(u_int64_t sm) 1402772e66a6SGleb Smirnoff { 1403772e66a6SGleb Smirnoff u_int64_t m; 1404772e66a6SGleb Smirnoff 1405772e66a6SGleb Smirnoff m = (sm * 8 * machclk_freq) >> SM_SHIFT; 1406249cc75fSPatrick Kelsey return (m); 1407772e66a6SGleb Smirnoff } 1408772e66a6SGleb Smirnoff 1409772e66a6SGleb Smirnoff static u_int 1410772e66a6SGleb Smirnoff dx2d(u_int64_t dx) 1411772e66a6SGleb Smirnoff { 1412772e66a6SGleb Smirnoff u_int64_t d; 1413772e66a6SGleb Smirnoff 1414772e66a6SGleb Smirnoff d = dx * 1000 / machclk_freq; 1415772e66a6SGleb Smirnoff return ((u_int)d); 1416772e66a6SGleb Smirnoff } 1417772e66a6SGleb Smirnoff 1418772e66a6SGleb Smirnoff static void 1419772e66a6SGleb Smirnoff sc2isc(struct service_curve *sc, struct internal_sc *isc) 1420772e66a6SGleb Smirnoff { 1421772e66a6SGleb Smirnoff isc->sm1 = m2sm(sc->m1); 1422772e66a6SGleb Smirnoff isc->ism1 = m2ism(sc->m1); 1423772e66a6SGleb Smirnoff isc->dx = d2dx(sc->d); 1424772e66a6SGleb Smirnoff isc->dy = seg_x2y(isc->dx, isc->sm1); 1425772e66a6SGleb Smirnoff isc->sm2 = m2sm(sc->m2); 1426772e66a6SGleb Smirnoff isc->ism2 = m2ism(sc->m2); 1427772e66a6SGleb Smirnoff } 1428772e66a6SGleb Smirnoff 1429772e66a6SGleb Smirnoff /* 1430772e66a6SGleb Smirnoff * initialize the runtime service curve with the given internal 1431772e66a6SGleb Smirnoff * service curve starting at (x, y). 1432772e66a6SGleb Smirnoff */ 1433772e66a6SGleb Smirnoff static void 1434772e66a6SGleb Smirnoff rtsc_init(struct runtime_sc *rtsc, struct internal_sc * isc, u_int64_t x, 1435772e66a6SGleb Smirnoff u_int64_t y) 1436772e66a6SGleb Smirnoff { 1437772e66a6SGleb Smirnoff rtsc->x = x; 1438772e66a6SGleb Smirnoff rtsc->y = y; 1439772e66a6SGleb Smirnoff rtsc->sm1 = isc->sm1; 1440772e66a6SGleb Smirnoff rtsc->ism1 = isc->ism1; 1441772e66a6SGleb Smirnoff rtsc->dx = isc->dx; 1442772e66a6SGleb Smirnoff rtsc->dy = isc->dy; 1443772e66a6SGleb Smirnoff rtsc->sm2 = isc->sm2; 1444772e66a6SGleb Smirnoff rtsc->ism2 = isc->ism2; 1445772e66a6SGleb Smirnoff } 1446772e66a6SGleb Smirnoff 1447772e66a6SGleb Smirnoff /* 1448772e66a6SGleb Smirnoff * calculate the y-projection of the runtime service curve by the 1449772e66a6SGleb Smirnoff * given x-projection value 1450772e66a6SGleb Smirnoff */ 1451772e66a6SGleb Smirnoff static u_int64_t 1452772e66a6SGleb Smirnoff rtsc_y2x(struct runtime_sc *rtsc, u_int64_t y) 1453772e66a6SGleb Smirnoff { 1454772e66a6SGleb Smirnoff u_int64_t x; 1455772e66a6SGleb Smirnoff 1456772e66a6SGleb Smirnoff if (y < rtsc->y) 1457772e66a6SGleb Smirnoff x = rtsc->x; 1458772e66a6SGleb Smirnoff else if (y <= rtsc->y + rtsc->dy) { 1459772e66a6SGleb Smirnoff /* x belongs to the 1st segment */ 1460772e66a6SGleb Smirnoff if (rtsc->dy == 0) 1461772e66a6SGleb Smirnoff x = rtsc->x + rtsc->dx; 1462772e66a6SGleb Smirnoff else 1463772e66a6SGleb Smirnoff x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1); 1464772e66a6SGleb Smirnoff } else { 1465772e66a6SGleb Smirnoff /* x belongs to the 2nd segment */ 1466772e66a6SGleb Smirnoff x = rtsc->x + rtsc->dx 1467772e66a6SGleb Smirnoff + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2); 1468772e66a6SGleb Smirnoff } 1469772e66a6SGleb Smirnoff return (x); 1470772e66a6SGleb Smirnoff } 1471772e66a6SGleb Smirnoff 1472772e66a6SGleb Smirnoff static u_int64_t 1473772e66a6SGleb Smirnoff rtsc_x2y(struct runtime_sc *rtsc, u_int64_t x) 1474772e66a6SGleb Smirnoff { 1475772e66a6SGleb Smirnoff u_int64_t y; 1476772e66a6SGleb Smirnoff 1477772e66a6SGleb Smirnoff if (x <= rtsc->x) 1478772e66a6SGleb Smirnoff y = rtsc->y; 1479772e66a6SGleb Smirnoff else if (x <= rtsc->x + rtsc->dx) 1480772e66a6SGleb Smirnoff /* y belongs to the 1st segment */ 1481772e66a6SGleb Smirnoff y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1); 1482772e66a6SGleb Smirnoff else 1483772e66a6SGleb Smirnoff /* y belongs to the 2nd segment */ 1484772e66a6SGleb Smirnoff y = rtsc->y + rtsc->dy 1485772e66a6SGleb Smirnoff + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2); 1486772e66a6SGleb Smirnoff return (y); 1487772e66a6SGleb Smirnoff } 1488772e66a6SGleb Smirnoff 1489772e66a6SGleb Smirnoff /* 1490772e66a6SGleb Smirnoff * update the runtime service curve by taking the minimum of the current 1491772e66a6SGleb Smirnoff * runtime service curve and the service curve starting at (x, y). 1492772e66a6SGleb Smirnoff */ 1493772e66a6SGleb Smirnoff static void 1494772e66a6SGleb Smirnoff rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u_int64_t x, 1495772e66a6SGleb Smirnoff u_int64_t y) 1496772e66a6SGleb Smirnoff { 1497772e66a6SGleb Smirnoff u_int64_t y1, y2, dx, dy; 1498772e66a6SGleb Smirnoff 1499772e66a6SGleb Smirnoff if (isc->sm1 <= isc->sm2) { 1500772e66a6SGleb Smirnoff /* service curve is convex */ 1501772e66a6SGleb Smirnoff y1 = rtsc_x2y(rtsc, x); 1502772e66a6SGleb Smirnoff if (y1 < y) 1503772e66a6SGleb Smirnoff /* the current rtsc is smaller */ 1504772e66a6SGleb Smirnoff return; 1505772e66a6SGleb Smirnoff rtsc->x = x; 1506772e66a6SGleb Smirnoff rtsc->y = y; 1507772e66a6SGleb Smirnoff return; 1508772e66a6SGleb Smirnoff } 1509772e66a6SGleb Smirnoff 1510772e66a6SGleb Smirnoff /* 1511772e66a6SGleb Smirnoff * service curve is concave 1512772e66a6SGleb Smirnoff * compute the two y values of the current rtsc 1513772e66a6SGleb Smirnoff * y1: at x 1514772e66a6SGleb Smirnoff * y2: at (x + dx) 1515772e66a6SGleb Smirnoff */ 1516772e66a6SGleb Smirnoff y1 = rtsc_x2y(rtsc, x); 1517772e66a6SGleb Smirnoff if (y1 <= y) { 1518772e66a6SGleb Smirnoff /* rtsc is below isc, no change to rtsc */ 1519772e66a6SGleb Smirnoff return; 1520772e66a6SGleb Smirnoff } 1521772e66a6SGleb Smirnoff 1522772e66a6SGleb Smirnoff y2 = rtsc_x2y(rtsc, x + isc->dx); 1523772e66a6SGleb Smirnoff if (y2 >= y + isc->dy) { 1524772e66a6SGleb Smirnoff /* rtsc is above isc, replace rtsc by isc */ 1525772e66a6SGleb Smirnoff rtsc->x = x; 1526772e66a6SGleb Smirnoff rtsc->y = y; 1527772e66a6SGleb Smirnoff rtsc->dx = isc->dx; 1528772e66a6SGleb Smirnoff rtsc->dy = isc->dy; 1529772e66a6SGleb Smirnoff return; 1530772e66a6SGleb Smirnoff } 1531772e66a6SGleb Smirnoff 1532772e66a6SGleb Smirnoff /* 1533772e66a6SGleb Smirnoff * the two curves intersect 1534772e66a6SGleb Smirnoff * compute the offsets (dx, dy) using the reverse 1535772e66a6SGleb Smirnoff * function of seg_x2y() 1536772e66a6SGleb Smirnoff * seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y) 1537772e66a6SGleb Smirnoff */ 1538772e66a6SGleb Smirnoff dx = ((y1 - y) << SM_SHIFT) / (isc->sm1 - isc->sm2); 1539772e66a6SGleb Smirnoff /* 1540772e66a6SGleb Smirnoff * check if (x, y1) belongs to the 1st segment of rtsc. 1541772e66a6SGleb Smirnoff * if so, add the offset. 1542772e66a6SGleb Smirnoff */ 1543772e66a6SGleb Smirnoff if (rtsc->x + rtsc->dx > x) 1544772e66a6SGleb Smirnoff dx += rtsc->x + rtsc->dx - x; 1545772e66a6SGleb Smirnoff dy = seg_x2y(dx, isc->sm1); 1546772e66a6SGleb Smirnoff 1547772e66a6SGleb Smirnoff rtsc->x = x; 1548772e66a6SGleb Smirnoff rtsc->y = y; 1549772e66a6SGleb Smirnoff rtsc->dx = dx; 1550772e66a6SGleb Smirnoff rtsc->dy = dy; 1551772e66a6SGleb Smirnoff return; 1552772e66a6SGleb Smirnoff } 1553772e66a6SGleb Smirnoff 1554772e66a6SGleb Smirnoff static void 1555249cc75fSPatrick Kelsey get_class_stats_v0(struct hfsc_classstats_v0 *sp, struct hfsc_class *cl) 1556249cc75fSPatrick Kelsey { 1557249cc75fSPatrick Kelsey sp->class_id = cl->cl_id; 1558249cc75fSPatrick Kelsey sp->class_handle = cl->cl_handle; 1559249cc75fSPatrick Kelsey 1560249cc75fSPatrick Kelsey #define SATU32(x) (u_int32_t)uqmin((x), UINT_MAX) 1561249cc75fSPatrick Kelsey 1562249cc75fSPatrick Kelsey if (cl->cl_rsc != NULL) { 1563249cc75fSPatrick Kelsey sp->rsc.m1 = SATU32(sm2m(cl->cl_rsc->sm1)); 1564249cc75fSPatrick Kelsey sp->rsc.d = dx2d(cl->cl_rsc->dx); 1565249cc75fSPatrick Kelsey sp->rsc.m2 = SATU32(sm2m(cl->cl_rsc->sm2)); 1566249cc75fSPatrick Kelsey } else { 1567249cc75fSPatrick Kelsey sp->rsc.m1 = 0; 1568249cc75fSPatrick Kelsey sp->rsc.d = 0; 1569249cc75fSPatrick Kelsey sp->rsc.m2 = 0; 1570249cc75fSPatrick Kelsey } 1571249cc75fSPatrick Kelsey if (cl->cl_fsc != NULL) { 1572249cc75fSPatrick Kelsey sp->fsc.m1 = SATU32(sm2m(cl->cl_fsc->sm1)); 1573249cc75fSPatrick Kelsey sp->fsc.d = dx2d(cl->cl_fsc->dx); 1574249cc75fSPatrick Kelsey sp->fsc.m2 = SATU32(sm2m(cl->cl_fsc->sm2)); 1575249cc75fSPatrick Kelsey } else { 1576249cc75fSPatrick Kelsey sp->fsc.m1 = 0; 1577249cc75fSPatrick Kelsey sp->fsc.d = 0; 1578249cc75fSPatrick Kelsey sp->fsc.m2 = 0; 1579249cc75fSPatrick Kelsey } 1580249cc75fSPatrick Kelsey if (cl->cl_usc != NULL) { 1581249cc75fSPatrick Kelsey sp->usc.m1 = SATU32(sm2m(cl->cl_usc->sm1)); 1582249cc75fSPatrick Kelsey sp->usc.d = dx2d(cl->cl_usc->dx); 1583249cc75fSPatrick Kelsey sp->usc.m2 = SATU32(sm2m(cl->cl_usc->sm2)); 1584249cc75fSPatrick Kelsey } else { 1585249cc75fSPatrick Kelsey sp->usc.m1 = 0; 1586249cc75fSPatrick Kelsey sp->usc.d = 0; 1587249cc75fSPatrick Kelsey sp->usc.m2 = 0; 1588249cc75fSPatrick Kelsey } 1589249cc75fSPatrick Kelsey 1590249cc75fSPatrick Kelsey #undef SATU32 1591249cc75fSPatrick Kelsey 1592249cc75fSPatrick Kelsey sp->total = cl->cl_total; 1593249cc75fSPatrick Kelsey sp->cumul = cl->cl_cumul; 1594249cc75fSPatrick Kelsey 1595249cc75fSPatrick Kelsey sp->d = cl->cl_d; 1596249cc75fSPatrick Kelsey sp->e = cl->cl_e; 1597249cc75fSPatrick Kelsey sp->vt = cl->cl_vt; 1598249cc75fSPatrick Kelsey sp->f = cl->cl_f; 1599249cc75fSPatrick Kelsey 1600249cc75fSPatrick Kelsey sp->initvt = cl->cl_initvt; 1601249cc75fSPatrick Kelsey sp->vtperiod = cl->cl_vtperiod; 1602249cc75fSPatrick Kelsey sp->parentperiod = cl->cl_parentperiod; 1603249cc75fSPatrick Kelsey sp->nactive = cl->cl_nactive; 1604249cc75fSPatrick Kelsey sp->vtoff = cl->cl_vtoff; 1605249cc75fSPatrick Kelsey sp->cvtmax = cl->cl_cvtmax; 1606249cc75fSPatrick Kelsey sp->myf = cl->cl_myf; 1607249cc75fSPatrick Kelsey sp->cfmin = cl->cl_cfmin; 1608249cc75fSPatrick Kelsey sp->cvtmin = cl->cl_cvtmin; 1609249cc75fSPatrick Kelsey sp->myfadj = cl->cl_myfadj; 1610249cc75fSPatrick Kelsey sp->vtadj = cl->cl_vtadj; 1611249cc75fSPatrick Kelsey 1612249cc75fSPatrick Kelsey sp->cur_time = read_machclk(); 1613249cc75fSPatrick Kelsey sp->machclk_freq = machclk_freq; 1614249cc75fSPatrick Kelsey 1615249cc75fSPatrick Kelsey sp->qlength = qlen(cl->cl_q); 1616249cc75fSPatrick Kelsey sp->qlimit = qlimit(cl->cl_q); 1617249cc75fSPatrick Kelsey sp->xmit_cnt = cl->cl_stats.xmit_cnt; 1618249cc75fSPatrick Kelsey sp->drop_cnt = cl->cl_stats.drop_cnt; 1619249cc75fSPatrick Kelsey sp->period = cl->cl_stats.period; 1620249cc75fSPatrick Kelsey 1621249cc75fSPatrick Kelsey sp->qtype = qtype(cl->cl_q); 1622249cc75fSPatrick Kelsey #ifdef ALTQ_RED 1623249cc75fSPatrick Kelsey if (q_is_red(cl->cl_q)) 1624249cc75fSPatrick Kelsey red_getstats(cl->cl_red, &sp->red[0]); 1625249cc75fSPatrick Kelsey #endif 1626249cc75fSPatrick Kelsey #ifdef ALTQ_RIO 1627249cc75fSPatrick Kelsey if (q_is_rio(cl->cl_q)) 1628249cc75fSPatrick Kelsey rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); 1629249cc75fSPatrick Kelsey #endif 1630249cc75fSPatrick Kelsey #ifdef ALTQ_CODEL 1631249cc75fSPatrick Kelsey if (q_is_codel(cl->cl_q)) 1632249cc75fSPatrick Kelsey codel_getstats(cl->cl_codel, &sp->codel); 1633249cc75fSPatrick Kelsey #endif 1634249cc75fSPatrick Kelsey } 1635249cc75fSPatrick Kelsey 1636249cc75fSPatrick Kelsey static void 1637249cc75fSPatrick Kelsey get_class_stats_v1(struct hfsc_classstats_v1 *sp, struct hfsc_class *cl) 1638772e66a6SGleb Smirnoff { 1639772e66a6SGleb Smirnoff sp->class_id = cl->cl_id; 1640772e66a6SGleb Smirnoff sp->class_handle = cl->cl_handle; 1641772e66a6SGleb Smirnoff 1642772e66a6SGleb Smirnoff if (cl->cl_rsc != NULL) { 1643772e66a6SGleb Smirnoff sp->rsc.m1 = sm2m(cl->cl_rsc->sm1); 1644772e66a6SGleb Smirnoff sp->rsc.d = dx2d(cl->cl_rsc->dx); 1645772e66a6SGleb Smirnoff sp->rsc.m2 = sm2m(cl->cl_rsc->sm2); 1646772e66a6SGleb Smirnoff } else { 1647772e66a6SGleb Smirnoff sp->rsc.m1 = 0; 1648772e66a6SGleb Smirnoff sp->rsc.d = 0; 1649772e66a6SGleb Smirnoff sp->rsc.m2 = 0; 1650772e66a6SGleb Smirnoff } 1651772e66a6SGleb Smirnoff if (cl->cl_fsc != NULL) { 1652772e66a6SGleb Smirnoff sp->fsc.m1 = sm2m(cl->cl_fsc->sm1); 1653772e66a6SGleb Smirnoff sp->fsc.d = dx2d(cl->cl_fsc->dx); 1654772e66a6SGleb Smirnoff sp->fsc.m2 = sm2m(cl->cl_fsc->sm2); 1655772e66a6SGleb Smirnoff } else { 1656772e66a6SGleb Smirnoff sp->fsc.m1 = 0; 1657772e66a6SGleb Smirnoff sp->fsc.d = 0; 1658772e66a6SGleb Smirnoff sp->fsc.m2 = 0; 1659772e66a6SGleb Smirnoff } 1660772e66a6SGleb Smirnoff if (cl->cl_usc != NULL) { 1661772e66a6SGleb Smirnoff sp->usc.m1 = sm2m(cl->cl_usc->sm1); 1662772e66a6SGleb Smirnoff sp->usc.d = dx2d(cl->cl_usc->dx); 1663772e66a6SGleb Smirnoff sp->usc.m2 = sm2m(cl->cl_usc->sm2); 1664772e66a6SGleb Smirnoff } else { 1665772e66a6SGleb Smirnoff sp->usc.m1 = 0; 1666772e66a6SGleb Smirnoff sp->usc.d = 0; 1667772e66a6SGleb Smirnoff sp->usc.m2 = 0; 1668772e66a6SGleb Smirnoff } 1669772e66a6SGleb Smirnoff 1670772e66a6SGleb Smirnoff sp->total = cl->cl_total; 1671772e66a6SGleb Smirnoff sp->cumul = cl->cl_cumul; 1672772e66a6SGleb Smirnoff 1673772e66a6SGleb Smirnoff sp->d = cl->cl_d; 1674772e66a6SGleb Smirnoff sp->e = cl->cl_e; 1675772e66a6SGleb Smirnoff sp->vt = cl->cl_vt; 1676772e66a6SGleb Smirnoff sp->f = cl->cl_f; 1677772e66a6SGleb Smirnoff 1678772e66a6SGleb Smirnoff sp->initvt = cl->cl_initvt; 1679772e66a6SGleb Smirnoff sp->vtperiod = cl->cl_vtperiod; 1680772e66a6SGleb Smirnoff sp->parentperiod = cl->cl_parentperiod; 1681772e66a6SGleb Smirnoff sp->nactive = cl->cl_nactive; 1682772e66a6SGleb Smirnoff sp->vtoff = cl->cl_vtoff; 1683772e66a6SGleb Smirnoff sp->cvtmax = cl->cl_cvtmax; 1684772e66a6SGleb Smirnoff sp->myf = cl->cl_myf; 1685772e66a6SGleb Smirnoff sp->cfmin = cl->cl_cfmin; 1686772e66a6SGleb Smirnoff sp->cvtmin = cl->cl_cvtmin; 1687772e66a6SGleb Smirnoff sp->myfadj = cl->cl_myfadj; 1688772e66a6SGleb Smirnoff sp->vtadj = cl->cl_vtadj; 1689772e66a6SGleb Smirnoff 1690772e66a6SGleb Smirnoff sp->cur_time = read_machclk(); 1691772e66a6SGleb Smirnoff sp->machclk_freq = machclk_freq; 1692772e66a6SGleb Smirnoff 1693772e66a6SGleb Smirnoff sp->qlength = qlen(cl->cl_q); 1694772e66a6SGleb Smirnoff sp->qlimit = qlimit(cl->cl_q); 1695772e66a6SGleb Smirnoff sp->xmit_cnt = cl->cl_stats.xmit_cnt; 1696772e66a6SGleb Smirnoff sp->drop_cnt = cl->cl_stats.drop_cnt; 1697772e66a6SGleb Smirnoff sp->period = cl->cl_stats.period; 1698772e66a6SGleb Smirnoff 1699772e66a6SGleb Smirnoff sp->qtype = qtype(cl->cl_q); 1700772e66a6SGleb Smirnoff #ifdef ALTQ_RED 1701772e66a6SGleb Smirnoff if (q_is_red(cl->cl_q)) 1702772e66a6SGleb Smirnoff red_getstats(cl->cl_red, &sp->red[0]); 1703772e66a6SGleb Smirnoff #endif 1704772e66a6SGleb Smirnoff #ifdef ALTQ_RIO 1705772e66a6SGleb Smirnoff if (q_is_rio(cl->cl_q)) 1706772e66a6SGleb Smirnoff rio_getstats((rio_t *)cl->cl_red, &sp->red[0]); 1707772e66a6SGleb Smirnoff #endif 17080a70aaf8SLuiz Otavio O Souza #ifdef ALTQ_CODEL 17090a70aaf8SLuiz Otavio O Souza if (q_is_codel(cl->cl_q)) 17100a70aaf8SLuiz Otavio O Souza codel_getstats(cl->cl_codel, &sp->codel); 17110a70aaf8SLuiz Otavio O Souza #endif 1712772e66a6SGleb Smirnoff } 1713772e66a6SGleb Smirnoff 1714772e66a6SGleb Smirnoff /* convert a class handle to the corresponding class pointer */ 1715772e66a6SGleb Smirnoff static struct hfsc_class * 1716772e66a6SGleb Smirnoff clh_to_clp(struct hfsc_if *hif, u_int32_t chandle) 1717772e66a6SGleb Smirnoff { 1718772e66a6SGleb Smirnoff int i; 1719772e66a6SGleb Smirnoff struct hfsc_class *cl; 1720772e66a6SGleb Smirnoff 1721772e66a6SGleb Smirnoff if (chandle == 0) 1722772e66a6SGleb Smirnoff return (NULL); 1723772e66a6SGleb Smirnoff /* 1724772e66a6SGleb Smirnoff * first, try optimistically the slot matching the lower bits of 1725772e66a6SGleb Smirnoff * the handle. if it fails, do the linear table search. 1726772e66a6SGleb Smirnoff */ 1727772e66a6SGleb Smirnoff i = chandle % HFSC_MAX_CLASSES; 1728772e66a6SGleb Smirnoff if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle) 1729772e66a6SGleb Smirnoff return (cl); 1730772e66a6SGleb Smirnoff for (i = 0; i < HFSC_MAX_CLASSES; i++) 1731772e66a6SGleb Smirnoff if ((cl = hif->hif_class_tbl[i]) != NULL && 1732772e66a6SGleb Smirnoff cl->cl_handle == chandle) 1733772e66a6SGleb Smirnoff return (cl); 1734772e66a6SGleb Smirnoff return (NULL); 1735772e66a6SGleb Smirnoff } 1736772e66a6SGleb Smirnoff 1737772e66a6SGleb Smirnoff #endif /* ALTQ_HFSC */ 1738