]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/altq/altq/altq_hfsc.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / altq / altq / altq_hfsc.c
1 /*      $FreeBSD$       */
2 /*      $KAME: altq_hfsc.c,v 1.24 2003/12/05 05:40:46 kjc Exp $ */
3
4 /*
5  * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software and
8  * its documentation is hereby granted (including for commercial or
9  * for-profit use), provided that both the copyright notice and this
10  * permission notice appear in all copies of the software, derivative
11  * works, or modified versions, and any portions thereof.
12  *
13  * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF
14  * WHICH MAY HAVE SERIOUS CONSEQUENCES.  CARNEGIE MELLON PROVIDES THIS
15  * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED
16  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED.  IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
22  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
25  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
26  * DAMAGE.
27  *
28  * Carnegie Mellon encourages (but does not require) users of this
29  * software to return any improvements or extensions that they make,
30  * and to grant Carnegie Mellon the rights to redistribute these
31  * changes without encumbrance.
32  */
33 /*
34  * H-FSC is described in Proceedings of SIGCOMM'97,
35  * "A Hierarchical Fair Service Curve Algorithm for Link-Sharing,
36  * Real-Time and Priority Service"
37  * by Ion Stoica, Hui Zhang, and T. S. Eugene Ng.
38  *
39  * Oleg Cherevko <olwi@aq.ml.com.ua> added the upperlimit for link-sharing.
40  * when a class has an upperlimit, the fit-time is computed from the
41  * upperlimit service curve.  the link-sharing scheduler does not schedule
42  * a class whose fit-time exceeds the current time.
43  */
44
45 #if defined(__FreeBSD__) || defined(__NetBSD__)
46 #include "opt_altq.h"
47 #include "opt_inet.h"
48 #ifdef __FreeBSD__
49 #include "opt_inet6.h"
50 #endif
51 #endif /* __FreeBSD__ || __NetBSD__ */
52
53 #ifdef ALTQ_HFSC  /* hfsc is enabled by ALTQ_HFSC option in opt_altq.h */
54
55 #include <sys/param.h>
56 #include <sys/malloc.h>
57 #include <sys/mbuf.h>
58 #include <sys/socket.h>
59 #include <sys/systm.h>
60 #include <sys/errno.h>
61 #include <sys/queue.h>
62 #if 1 /* ALTQ3_COMPAT */
63 #include <sys/sockio.h>
64 #include <sys/proc.h>
65 #include <sys/kernel.h>
66 #endif /* ALTQ3_COMPAT */
67
68 #include <net/if.h>
69 #include <netinet/in.h>
70
71 #include <net/pfvar.h>
72 #include <altq/altq.h>
73 #include <altq/altq_hfsc.h>
74 #ifdef ALTQ3_COMPAT
75 #include <altq/altq_conf.h>
76 #endif
77
78 /*
79  * function prototypes
80  */
81 static int                       hfsc_clear_interface(struct hfsc_if *);
82 static int                       hfsc_request(struct ifaltq *, int, void *);
83 static void                      hfsc_purge(struct hfsc_if *);
84 static struct hfsc_class        *hfsc_class_create(struct hfsc_if *,
85     struct service_curve *, struct service_curve *, struct service_curve *,
86     struct hfsc_class *, int, int, int);
87 static int                       hfsc_class_destroy(struct hfsc_class *);
88 static struct hfsc_class        *hfsc_nextclass(struct hfsc_class *);
89 static int                       hfsc_enqueue(struct ifaltq *, struct mbuf *,
90                                     struct altq_pktattr *);
91 static struct mbuf              *hfsc_dequeue(struct ifaltq *, int);
92
93 static int               hfsc_addq(struct hfsc_class *, struct mbuf *);
94 static struct mbuf      *hfsc_getq(struct hfsc_class *);
95 static struct mbuf      *hfsc_pollq(struct hfsc_class *);
96 static void              hfsc_purgeq(struct hfsc_class *);
97
98 static void              update_cfmin(struct hfsc_class *);
99 static void              set_active(struct hfsc_class *, int);
100 static void              set_passive(struct hfsc_class *);
101
102 static void              init_ed(struct hfsc_class *, int);
103 static void              update_ed(struct hfsc_class *, int);
104 static void              update_d(struct hfsc_class *, int);
105 static void              init_vf(struct hfsc_class *, int);
106 static void              update_vf(struct hfsc_class *, int, u_int64_t);
107 static void              ellist_insert(struct hfsc_class *);
108 static void              ellist_remove(struct hfsc_class *);
109 static void              ellist_update(struct hfsc_class *);
110 struct hfsc_class       *hfsc_get_mindl(struct hfsc_if *, u_int64_t);
111 static void              actlist_insert(struct hfsc_class *);
112 static void              actlist_remove(struct hfsc_class *);
113 static void              actlist_update(struct hfsc_class *);
114
115 static struct hfsc_class        *actlist_firstfit(struct hfsc_class *,
116                                     u_int64_t);
117
118 static __inline u_int64_t       seg_x2y(u_int64_t, u_int64_t);
119 static __inline u_int64_t       seg_y2x(u_int64_t, u_int64_t);
120 static __inline u_int64_t       m2sm(u_int);
121 static __inline u_int64_t       m2ism(u_int);
122 static __inline u_int64_t       d2dx(u_int);
123 static u_int                    sm2m(u_int64_t);
124 static u_int                    dx2d(u_int64_t);
125
126 static void             sc2isc(struct service_curve *, struct internal_sc *);
127 static void             rtsc_init(struct runtime_sc *, struct internal_sc *,
128                             u_int64_t, u_int64_t);
129 static u_int64_t        rtsc_y2x(struct runtime_sc *, u_int64_t);
130 static u_int64_t        rtsc_x2y(struct runtime_sc *, u_int64_t);
131 static void             rtsc_min(struct runtime_sc *, struct internal_sc *,
132                             u_int64_t, u_int64_t);
133
134 static void                      get_class_stats(struct hfsc_classstats *,
135                                     struct hfsc_class *);
136 static struct hfsc_class        *clh_to_clp(struct hfsc_if *, u_int32_t);
137
138
139 #ifdef ALTQ3_COMPAT
140 static struct hfsc_if *hfsc_attach(struct ifaltq *, u_int);
141 static int hfsc_detach(struct hfsc_if *);
142 static int hfsc_class_modify(struct hfsc_class *, struct service_curve *,
143     struct service_curve *, struct service_curve *);
144
145 static int hfsccmd_if_attach(struct hfsc_attach *);
146 static int hfsccmd_if_detach(struct hfsc_interface *);
147 static int hfsccmd_add_class(struct hfsc_add_class *);
148 static int hfsccmd_delete_class(struct hfsc_delete_class *);
149 static int hfsccmd_modify_class(struct hfsc_modify_class *);
150 static int hfsccmd_add_filter(struct hfsc_add_filter *);
151 static int hfsccmd_delete_filter(struct hfsc_delete_filter *);
152 static int hfsccmd_class_stats(struct hfsc_class_stats *);
153
154 altqdev_decl(hfsc);
155 #endif /* ALTQ3_COMPAT */
156
157 /*
158  * macros
159  */
160 #define is_a_parent_class(cl)   ((cl)->cl_children != NULL)
161
162 #define HT_INFINITY     0xffffffffffffffffLL    /* infinite time value */
163
164 #ifdef ALTQ3_COMPAT
165 /* hif_list keeps all hfsc_if's allocated. */
166 static struct hfsc_if *hif_list = NULL;
167 #endif /* ALTQ3_COMPAT */
168
169 int
170 hfsc_pfattach(struct pf_altq *a)
171 {
172         struct ifnet *ifp;
173         int s, error;
174
175         if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL)
176                 return (EINVAL);
177 #ifdef __NetBSD__
178         s = splnet();
179 #else
180         s = splimp();
181 #endif
182         error = altq_attach(&ifp->if_snd, ALTQT_HFSC, a->altq_disc,
183             hfsc_enqueue, hfsc_dequeue, hfsc_request, NULL, NULL);
184         splx(s);
185         return (error);
186 }
187
188 int
189 hfsc_add_altq(struct pf_altq *a)
190 {
191         struct hfsc_if *hif;
192         struct ifnet *ifp;
193
194         if ((ifp = ifunit(a->ifname)) == NULL)
195                 return (EINVAL);
196         if (!ALTQ_IS_READY(&ifp->if_snd))
197                 return (ENODEV);
198
199         hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_NOWAIT | M_ZERO);
200         if (hif == NULL)
201                 return (ENOMEM);
202
203         TAILQ_INIT(&hif->hif_eligible);
204         hif->hif_ifq = &ifp->if_snd;
205
206         /* keep the state in pf_altq */
207         a->altq_disc = hif;
208
209         return (0);
210 }
211
212 int
213 hfsc_remove_altq(struct pf_altq *a)
214 {
215         struct hfsc_if *hif;
216
217         if ((hif = a->altq_disc) == NULL)
218                 return (EINVAL);
219         a->altq_disc = NULL;
220
221         (void)hfsc_clear_interface(hif);
222         (void)hfsc_class_destroy(hif->hif_rootclass);
223
224         free(hif, M_DEVBUF);
225
226         return (0);
227 }
228
229 int
230 hfsc_add_queue(struct pf_altq *a)
231 {
232         struct hfsc_if *hif;
233         struct hfsc_class *cl, *parent;
234         struct hfsc_opts *opts;
235         struct service_curve rtsc, lssc, ulsc;
236
237         if ((hif = a->altq_disc) == NULL)
238                 return (EINVAL);
239
240         opts = &a->pq_u.hfsc_opts;
241
242         if (a->parent_qid == HFSC_NULLCLASS_HANDLE &&
243             hif->hif_rootclass == NULL)
244                 parent = NULL;
245         else if ((parent = clh_to_clp(hif, a->parent_qid)) == NULL)
246                 return (EINVAL);
247
248         if (a->qid == 0)
249                 return (EINVAL);
250
251         if (clh_to_clp(hif, a->qid) != NULL)
252                 return (EBUSY);
253
254         rtsc.m1 = opts->rtsc_m1;
255         rtsc.d  = opts->rtsc_d;
256         rtsc.m2 = opts->rtsc_m2;
257         lssc.m1 = opts->lssc_m1;
258         lssc.d  = opts->lssc_d;
259         lssc.m2 = opts->lssc_m2;
260         ulsc.m1 = opts->ulsc_m1;
261         ulsc.d  = opts->ulsc_d;
262         ulsc.m2 = opts->ulsc_m2;
263
264         cl = hfsc_class_create(hif, &rtsc, &lssc, &ulsc,
265             parent, a->qlimit, opts->flags, a->qid);
266         if (cl == NULL)
267                 return (ENOMEM);
268
269         return (0);
270 }
271
272 int
273 hfsc_remove_queue(struct pf_altq *a)
274 {
275         struct hfsc_if *hif;
276         struct hfsc_class *cl;
277
278         if ((hif = a->altq_disc) == NULL)
279                 return (EINVAL);
280
281         if ((cl = clh_to_clp(hif, a->qid)) == NULL)
282                 return (EINVAL);
283
284         return (hfsc_class_destroy(cl));
285 }
286
287 int
288 hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
289 {
290         struct hfsc_if *hif;
291         struct hfsc_class *cl;
292         struct hfsc_classstats stats;
293         int error = 0;
294
295         if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL)
296                 return (EBADF);
297
298         if ((cl = clh_to_clp(hif, a->qid)) == NULL)
299                 return (EINVAL);
300
301         if (*nbytes < sizeof(stats))
302                 return (EINVAL);
303
304         get_class_stats(&stats, cl);
305
306         if ((error = copyout((caddr_t)&stats, ubuf, sizeof(stats))) != 0)
307                 return (error);
308         *nbytes = sizeof(stats);
309         return (0);
310 }
311
312 /*
313  * bring the interface back to the initial state by discarding
314  * all the filters and classes except the root class.
315  */
316 static int
317 hfsc_clear_interface(struct hfsc_if *hif)
318 {
319         struct hfsc_class       *cl;
320
321 #ifdef ALTQ3_COMPAT
322         /* free the filters for this interface */
323         acc_discard_filters(&hif->hif_classifier, NULL, 1);
324 #endif
325
326         /* clear out the classes */
327         while (hif->hif_rootclass != NULL &&
328             (cl = hif->hif_rootclass->cl_children) != NULL) {
329                 /*
330                  * remove the first leaf class found in the hierarchy
331                  * then start over
332                  */
333                 for (; cl != NULL; cl = hfsc_nextclass(cl)) {
334                         if (!is_a_parent_class(cl)) {
335                                 (void)hfsc_class_destroy(cl);
336                                 break;
337                         }
338                 }
339         }
340
341         return (0);
342 }
343
344 static int
345 hfsc_request(struct ifaltq *ifq, int req, void *arg)
346 {
347         struct hfsc_if  *hif = (struct hfsc_if *)ifq->altq_disc;
348
349         IFQ_LOCK_ASSERT(ifq);
350
351         switch (req) {
352         case ALTRQ_PURGE:
353                 hfsc_purge(hif);
354                 break;
355         }
356         return (0);
357 }
358
359 /* discard all the queued packets on the interface */
360 static void
361 hfsc_purge(struct hfsc_if *hif)
362 {
363         struct hfsc_class *cl;
364
365         for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl))
366                 if (!qempty(cl->cl_q))
367                         hfsc_purgeq(cl);
368         if (ALTQ_IS_ENABLED(hif->hif_ifq))
369                 hif->hif_ifq->ifq_len = 0;
370 }
371
372 struct hfsc_class *
373 hfsc_class_create(struct hfsc_if *hif, struct service_curve *rsc,
374     struct service_curve *fsc, struct service_curve *usc,
375     struct hfsc_class *parent, int qlimit, int flags, int qid)
376 {
377         struct hfsc_class *cl, *p;
378         int i, s;
379
380         if (hif->hif_classes >= HFSC_MAX_CLASSES)
381                 return (NULL);
382
383 #ifndef ALTQ_RED
384         if (flags & HFCF_RED) {
385 #ifdef ALTQ_DEBUG
386                 printf("hfsc_class_create: RED not configured for HFSC!\n");
387 #endif
388                 return (NULL);
389         }
390 #endif
391
392         cl = malloc(sizeof(struct hfsc_class), M_DEVBUF, M_NOWAIT | M_ZERO);
393         if (cl == NULL)
394                 return (NULL);
395
396         cl->cl_q = malloc(sizeof(class_queue_t), M_DEVBUF, M_NOWAIT | M_ZERO);
397         if (cl->cl_q == NULL)
398                 goto err_ret;
399
400         TAILQ_INIT(&cl->cl_actc);
401
402         if (qlimit == 0)
403                 qlimit = 50;  /* use default */
404         qlimit(cl->cl_q) = qlimit;
405         qtype(cl->cl_q) = Q_DROPTAIL;
406         qlen(cl->cl_q) = 0;
407         cl->cl_flags = flags;
408 #ifdef ALTQ_RED
409         if (flags & (HFCF_RED|HFCF_RIO)) {
410                 int red_flags, red_pkttime;
411                 u_int m2;
412
413                 m2 = 0;
414                 if (rsc != NULL && rsc->m2 > m2)
415                         m2 = rsc->m2;
416                 if (fsc != NULL && fsc->m2 > m2)
417                         m2 = fsc->m2;
418                 if (usc != NULL && usc->m2 > m2)
419                         m2 = usc->m2;
420
421                 red_flags = 0;
422                 if (flags & HFCF_ECN)
423                         red_flags |= REDF_ECN;
424 #ifdef ALTQ_RIO
425                 if (flags & HFCF_CLEARDSCP)
426                         red_flags |= RIOF_CLEARDSCP;
427 #endif
428                 if (m2 < 8)
429                         red_pkttime = 1000 * 1000 * 1000; /* 1 sec */
430                 else
431                         red_pkttime = (int64_t)hif->hif_ifq->altq_ifp->if_mtu
432                                 * 1000 * 1000 * 1000 / (m2 / 8);
433                 if (flags & HFCF_RED) {
434                         cl->cl_red = red_alloc(0, 0,
435                             qlimit(cl->cl_q) * 10/100,
436                             qlimit(cl->cl_q) * 30/100,
437                             red_flags, red_pkttime);
438                         if (cl->cl_red != NULL)
439                                 qtype(cl->cl_q) = Q_RED;
440                 }
441 #ifdef ALTQ_RIO
442                 else {
443                         cl->cl_red = (red_t *)rio_alloc(0, NULL,
444                             red_flags, red_pkttime);
445                         if (cl->cl_red != NULL)
446                                 qtype(cl->cl_q) = Q_RIO;
447                 }
448 #endif
449         }
450 #endif /* ALTQ_RED */
451
452         if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0)) {
453                 cl->cl_rsc = malloc(sizeof(struct internal_sc),
454                     M_DEVBUF, M_NOWAIT);
455                 if (cl->cl_rsc == NULL)
456                         goto err_ret;
457                 sc2isc(rsc, cl->cl_rsc);
458                 rtsc_init(&cl->cl_deadline, cl->cl_rsc, 0, 0);
459                 rtsc_init(&cl->cl_eligible, cl->cl_rsc, 0, 0);
460         }
461         if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0)) {
462                 cl->cl_fsc = malloc(sizeof(struct internal_sc),
463                     M_DEVBUF, M_NOWAIT);
464                 if (cl->cl_fsc == NULL)
465                         goto err_ret;
466                 sc2isc(fsc, cl->cl_fsc);
467                 rtsc_init(&cl->cl_virtual, cl->cl_fsc, 0, 0);
468         }
469         if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0)) {
470                 cl->cl_usc = malloc(sizeof(struct internal_sc),
471                     M_DEVBUF, M_NOWAIT);
472                 if (cl->cl_usc == NULL)
473                         goto err_ret;
474                 sc2isc(usc, cl->cl_usc);
475                 rtsc_init(&cl->cl_ulimit, cl->cl_usc, 0, 0);
476         }
477
478         cl->cl_id = hif->hif_classid++;
479         cl->cl_handle = qid;
480         cl->cl_hif = hif;
481         cl->cl_parent = parent;
482
483 #ifdef __NetBSD__
484         s = splnet();
485 #else
486         s = splimp();
487 #endif
488         IFQ_LOCK(hif->hif_ifq);
489         hif->hif_classes++;
490
491         /*
492          * find a free slot in the class table.  if the slot matching
493          * the lower bits of qid is free, use this slot.  otherwise,
494          * use the first free slot.
495          */
496         i = qid % HFSC_MAX_CLASSES;
497         if (hif->hif_class_tbl[i] == NULL)
498                 hif->hif_class_tbl[i] = cl;
499         else {
500                 for (i = 0; i < HFSC_MAX_CLASSES; i++)
501                         if (hif->hif_class_tbl[i] == NULL) {
502                                 hif->hif_class_tbl[i] = cl;
503                                 break;
504                         }
505                 if (i == HFSC_MAX_CLASSES) {
506                         IFQ_UNLOCK(hif->hif_ifq);
507                         splx(s);
508                         goto err_ret;
509                 }
510         }
511
512         if (flags & HFCF_DEFAULTCLASS)
513                 hif->hif_defaultclass = cl;
514
515         if (parent == NULL) {
516                 /* this is root class */
517                 hif->hif_rootclass = cl;
518         } else {
519                 /* add this class to the children list of the parent */
520                 if ((p = parent->cl_children) == NULL)
521                         parent->cl_children = cl;
522                 else {
523                         while (p->cl_siblings != NULL)
524                                 p = p->cl_siblings;
525                         p->cl_siblings = cl;
526                 }
527         }
528         IFQ_UNLOCK(hif->hif_ifq);
529         splx(s);
530
531         return (cl);
532
533  err_ret:
534         if (cl->cl_red != NULL) {
535 #ifdef ALTQ_RIO
536                 if (q_is_rio(cl->cl_q))
537                         rio_destroy((rio_t *)cl->cl_red);
538 #endif
539 #ifdef ALTQ_RED
540                 if (q_is_red(cl->cl_q))
541                         red_destroy(cl->cl_red);
542 #endif
543         }
544         if (cl->cl_fsc != NULL)
545                 free(cl->cl_fsc, M_DEVBUF);
546         if (cl->cl_rsc != NULL)
547                 free(cl->cl_rsc, M_DEVBUF);
548         if (cl->cl_usc != NULL)
549                 free(cl->cl_usc, M_DEVBUF);
550         if (cl->cl_q != NULL)
551                 free(cl->cl_q, M_DEVBUF);
552         free(cl, M_DEVBUF);
553         return (NULL);
554 }
555
556 static int
557 hfsc_class_destroy(struct hfsc_class *cl)
558 {
559         int i, s;
560
561         if (cl == NULL)
562                 return (0);
563
564         if (is_a_parent_class(cl))
565                 return (EBUSY);
566
567 #ifdef __NetBSD__
568         s = splnet();
569 #else
570         s = splimp();
571 #endif
572         IFQ_LOCK(cl->cl_hif->hif_ifq);
573
574 #ifdef ALTQ3_COMPAT
575         /* delete filters referencing to this class */
576         acc_discard_filters(&cl->cl_hif->hif_classifier, cl, 0);
577 #endif /* ALTQ3_COMPAT */
578
579         if (!qempty(cl->cl_q))
580                 hfsc_purgeq(cl);
581
582         if (cl->cl_parent == NULL) {
583                 /* this is root class */
584         } else {
585                 struct hfsc_class *p = cl->cl_parent->cl_children;
586
587                 if (p == cl)
588                         cl->cl_parent->cl_children = cl->cl_siblings;
589                 else do {
590                         if (p->cl_siblings == cl) {
591                                 p->cl_siblings = cl->cl_siblings;
592                                 break;
593                         }
594                 } while ((p = p->cl_siblings) != NULL);
595                 ASSERT(p != NULL);
596         }
597
598         for (i = 0; i < HFSC_MAX_CLASSES; i++)
599                 if (cl->cl_hif->hif_class_tbl[i] == cl) {
600                         cl->cl_hif->hif_class_tbl[i] = NULL;
601                         break;
602                 }
603
604         cl->cl_hif->hif_classes--;
605         IFQ_UNLOCK(cl->cl_hif->hif_ifq);
606         splx(s);
607
608         if (cl->cl_red != NULL) {
609 #ifdef ALTQ_RIO
610                 if (q_is_rio(cl->cl_q))
611                         rio_destroy((rio_t *)cl->cl_red);
612 #endif
613 #ifdef ALTQ_RED
614                 if (q_is_red(cl->cl_q))
615                         red_destroy(cl->cl_red);
616 #endif
617         }
618
619         IFQ_LOCK(cl->cl_hif->hif_ifq);
620         if (cl == cl->cl_hif->hif_rootclass)
621                 cl->cl_hif->hif_rootclass = NULL;
622         if (cl == cl->cl_hif->hif_defaultclass)
623                 cl->cl_hif->hif_defaultclass = NULL;
624         IFQ_UNLOCK(cl->cl_hif->hif_ifq);
625
626         if (cl->cl_usc != NULL)
627                 free(cl->cl_usc, M_DEVBUF);
628         if (cl->cl_fsc != NULL)
629                 free(cl->cl_fsc, M_DEVBUF);
630         if (cl->cl_rsc != NULL)
631                 free(cl->cl_rsc, M_DEVBUF);
632         free(cl->cl_q, M_DEVBUF);
633         free(cl, M_DEVBUF);
634
635         return (0);
636 }
637
638 /*
639  * hfsc_nextclass returns the next class in the tree.
640  *   usage:
641  *      for (cl = hif->hif_rootclass; cl != NULL; cl = hfsc_nextclass(cl))
642  *              do_something;
643  */
644 static struct hfsc_class *
645 hfsc_nextclass(struct hfsc_class *cl)
646 {
647         if (cl->cl_children != NULL)
648                 cl = cl->cl_children;
649         else if (cl->cl_siblings != NULL)
650                 cl = cl->cl_siblings;
651         else {
652                 while ((cl = cl->cl_parent) != NULL)
653                         if (cl->cl_siblings) {
654                                 cl = cl->cl_siblings;
655                                 break;
656                         }
657         }
658
659         return (cl);
660 }
661
662 /*
663  * hfsc_enqueue is an enqueue function to be registered to
664  * (*altq_enqueue) in struct ifaltq.
665  */
666 static int
667 hfsc_enqueue(struct ifaltq *ifq, struct mbuf *m, struct altq_pktattr *pktattr)
668 {
669         struct hfsc_if  *hif = (struct hfsc_if *)ifq->altq_disc;
670         struct hfsc_class *cl;
671         struct pf_mtag *t;
672         int len;
673
674         IFQ_LOCK_ASSERT(ifq);
675
676         /* grab class set by classifier */
677         if ((m->m_flags & M_PKTHDR) == 0) {
678                 /* should not happen */
679                 printf("altq: packet for %s does not have pkthdr\n",
680                     ifq->altq_ifp->if_xname);
681                 m_freem(m);
682                 return (ENOBUFS);
683         }
684         cl = NULL;
685         if ((t = pf_find_mtag(m)) != NULL)
686                 cl = clh_to_clp(hif, t->qid);
687 #ifdef ALTQ3_COMPAT
688         else if ((ifq->altq_flags & ALTQF_CLASSIFY) && pktattr != NULL)
689                 cl = pktattr->pattr_class;
690 #endif
691         if (cl == NULL || is_a_parent_class(cl)) {
692                 cl = hif->hif_defaultclass;
693                 if (cl == NULL) {
694                         m_freem(m);
695                         return (ENOBUFS);
696                 }
697         }
698 #ifdef ALTQ3_COMPAT
699         if (pktattr != NULL)
700                 cl->cl_pktattr = pktattr;  /* save proto hdr used by ECN */
701         else
702 #endif
703                 cl->cl_pktattr = NULL;
704         len = m_pktlen(m);
705         if (hfsc_addq(cl, m) != 0) {
706                 /* drop occurred.  mbuf was freed in hfsc_addq. */
707                 PKTCNTR_ADD(&cl->cl_stats.drop_cnt, len);
708                 return (ENOBUFS);
709         }
710         IFQ_INC_LEN(ifq);
711         cl->cl_hif->hif_packets++;
712
713         /* successfully queued. */
714         if (qlen(cl->cl_q) == 1)
715                 set_active(cl, m_pktlen(m));
716
717         return (0);
718 }
719
720 /*
721  * hfsc_dequeue is a dequeue function to be registered to
722  * (*altq_dequeue) in struct ifaltq.
723  *
724  * note: ALTDQ_POLL returns the next packet without removing the packet
725  *      from the queue.  ALTDQ_REMOVE is a normal dequeue operation.
726  *      ALTDQ_REMOVE must return the same packet if called immediately
727  *      after ALTDQ_POLL.
728  */
729 static struct mbuf *
730 hfsc_dequeue(struct ifaltq *ifq, int op)
731 {
732         struct hfsc_if  *hif = (struct hfsc_if *)ifq->altq_disc;
733         struct hfsc_class *cl;
734         struct mbuf *m;
735         int len, next_len;
736         int realtime = 0;
737         u_int64_t cur_time;
738
739         IFQ_LOCK_ASSERT(ifq);
740
741         if (hif->hif_packets == 0)
742                 /* no packet in the tree */
743                 return (NULL);
744
745         cur_time = read_machclk();
746
747         if (op == ALTDQ_REMOVE && hif->hif_pollcache != NULL) {
748
749                 cl = hif->hif_pollcache;
750                 hif->hif_pollcache = NULL;
751                 /* check if the class was scheduled by real-time criteria */
752                 if (cl->cl_rsc != NULL)
753                         realtime = (cl->cl_e <= cur_time);
754         } else {
755                 /*
756                  * if there are eligible classes, use real-time criteria.
757                  * find the class with the minimum deadline among
758                  * the eligible classes.
759                  */
760                 if ((cl = hfsc_get_mindl(hif, cur_time))
761                     != NULL) {
762                         realtime = 1;
763                 } else {
764 #ifdef ALTQ_DEBUG
765                         int fits = 0;
766 #endif
767                         /*
768                          * use link-sharing criteria
769                          * get the class with the minimum vt in the hierarchy
770                          */
771                         cl = hif->hif_rootclass;
772                         while (is_a_parent_class(cl)) {
773
774                                 cl = actlist_firstfit(cl, cur_time);
775                                 if (cl == NULL) {
776 #ifdef ALTQ_DEBUG
777                                         if (fits > 0)
778                                                 printf("%d fit but none found\n",fits);
779 #endif
780                                         return (NULL);
781                                 }
782                                 /*
783                                  * update parent's cl_cvtmin.
784                                  * don't update if the new vt is smaller.
785                                  */
786                                 if (cl->cl_parent->cl_cvtmin < cl->cl_vt)
787                                         cl->cl_parent->cl_cvtmin = cl->cl_vt;
788 #ifdef ALTQ_DEBUG
789                                 fits++;
790 #endif
791                         }
792                 }
793
794                 if (op == ALTDQ_POLL) {
795                         hif->hif_pollcache = cl;
796                         m = hfsc_pollq(cl);
797                         return (m);
798                 }
799         }
800
801         m = hfsc_getq(cl);
802         if (m == NULL)
803                 panic("hfsc_dequeue:");
804         len = m_pktlen(m);
805         cl->cl_hif->hif_packets--;
806         IFQ_DEC_LEN(ifq);
807         PKTCNTR_ADD(&cl->cl_stats.xmit_cnt, len);
808
809         update_vf(cl, len, cur_time);
810         if (realtime)
811                 cl->cl_cumul += len;
812
813         if (!qempty(cl->cl_q)) {
814                 if (cl->cl_rsc != NULL) {
815                         /* update ed */
816                         next_len = m_pktlen(qhead(cl->cl_q));
817
818                         if (realtime)
819                                 update_ed(cl, next_len);
820                         else
821                                 update_d(cl, next_len);
822                 }
823         } else {
824                 /* the class becomes passive */
825                 set_passive(cl);
826         }
827
828         return (m);
829 }
830
831 static int
832 hfsc_addq(struct hfsc_class *cl, struct mbuf *m)
833 {
834
835 #ifdef ALTQ_RIO
836         if (q_is_rio(cl->cl_q))
837                 return rio_addq((rio_t *)cl->cl_red, cl->cl_q,
838                                 m, cl->cl_pktattr);
839 #endif
840 #ifdef ALTQ_RED
841         if (q_is_red(cl->cl_q))
842                 return red_addq(cl->cl_red, cl->cl_q, m, cl->cl_pktattr);
843 #endif
844         if (qlen(cl->cl_q) >= qlimit(cl->cl_q)) {
845                 m_freem(m);
846                 return (-1);
847         }
848
849         if (cl->cl_flags & HFCF_CLEARDSCP)
850                 write_dsfield(m, cl->cl_pktattr, 0);
851
852         _addq(cl->cl_q, m);
853
854         return (0);
855 }
856
857 static struct mbuf *
858 hfsc_getq(struct hfsc_class *cl)
859 {
860 #ifdef ALTQ_RIO
861         if (q_is_rio(cl->cl_q))
862                 return rio_getq((rio_t *)cl->cl_red, cl->cl_q);
863 #endif
864 #ifdef ALTQ_RED
865         if (q_is_red(cl->cl_q))
866                 return red_getq(cl->cl_red, cl->cl_q);
867 #endif
868         return _getq(cl->cl_q);
869 }
870
871 static struct mbuf *
872 hfsc_pollq(struct hfsc_class *cl)
873 {
874         return qhead(cl->cl_q);
875 }
876
877 static void
878 hfsc_purgeq(struct hfsc_class *cl)
879 {
880         struct mbuf *m;
881
882         if (qempty(cl->cl_q))
883                 return;
884
885         while ((m = _getq(cl->cl_q)) != NULL) {
886                 PKTCNTR_ADD(&cl->cl_stats.drop_cnt, m_pktlen(m));
887                 m_freem(m);
888                 cl->cl_hif->hif_packets--;
889                 IFQ_DEC_LEN(cl->cl_hif->hif_ifq);
890         }
891         ASSERT(qlen(cl->cl_q) == 0);
892
893         update_vf(cl, 0, 0);    /* remove cl from the actlist */
894         set_passive(cl);
895 }
896
897 static void
898 set_active(struct hfsc_class *cl, int len)
899 {
900         if (cl->cl_rsc != NULL)
901                 init_ed(cl, len);
902         if (cl->cl_fsc != NULL)
903                 init_vf(cl, len);
904
905         cl->cl_stats.period++;
906 }
907
908 static void
909 set_passive(struct hfsc_class *cl)
910 {
911         if (cl->cl_rsc != NULL)
912                 ellist_remove(cl);
913
914         /*
915          * actlist is now handled in update_vf() so that update_vf(cl, 0, 0)
916          * needs to be called explicitly to remove a class from actlist
917          */
918 }
919
920 static void
921 init_ed(struct hfsc_class *cl, int next_len)
922 {
923         u_int64_t cur_time;
924
925         cur_time = read_machclk();
926
927         /* update the deadline curve */
928         rtsc_min(&cl->cl_deadline, cl->cl_rsc, cur_time, cl->cl_cumul);
929
930         /*
931          * update the eligible curve.
932          * for concave, it is equal to the deadline curve.
933          * for convex, it is a linear curve with slope m2.
934          */
935         cl->cl_eligible = cl->cl_deadline;
936         if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) {
937                 cl->cl_eligible.dx = 0;
938                 cl->cl_eligible.dy = 0;
939         }
940
941         /* compute e and d */
942         cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
943         cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
944
945         ellist_insert(cl);
946 }
947
948 static void
949 update_ed(struct hfsc_class *cl, int next_len)
950 {
951         cl->cl_e = rtsc_y2x(&cl->cl_eligible, cl->cl_cumul);
952         cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
953
954         ellist_update(cl);
955 }
956
957 static void
958 update_d(struct hfsc_class *cl, int next_len)
959 {
960         cl->cl_d = rtsc_y2x(&cl->cl_deadline, cl->cl_cumul + next_len);
961 }
962
963 static void
964 init_vf(struct hfsc_class *cl, int len)
965 {
966         struct hfsc_class *max_cl, *p;
967         u_int64_t vt, f, cur_time;
968         int go_active;
969
970         cur_time = 0;
971         go_active = 1;
972         for ( ; cl->cl_parent != NULL; cl = cl->cl_parent) {
973
974                 if (go_active && cl->cl_nactive++ == 0)
975                         go_active = 1;
976                 else
977                         go_active = 0;
978
979                 if (go_active) {
980                         max_cl = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead);
981                         if (max_cl != NULL) {
982                                 /*
983                                  * set vt to the average of the min and max
984                                  * classes.  if the parent's period didn't
985                                  * change, don't decrease vt of the class.
986                                  */
987                                 vt = max_cl->cl_vt;
988                                 if (cl->cl_parent->cl_cvtmin != 0)
989                                         vt = (cl->cl_parent->cl_cvtmin + vt)/2;
990
991                                 if (cl->cl_parent->cl_vtperiod !=
992                                     cl->cl_parentperiod || vt > cl->cl_vt)
993                                         cl->cl_vt = vt;
994                         } else {
995                                 /*
996                                  * first child for a new parent backlog period.
997                                  * add parent's cvtmax to vtoff of children
998                                  * to make a new vt (vtoff + vt) larger than
999                                  * the vt in the last period for all children.
1000                                  */
1001                                 vt = cl->cl_parent->cl_cvtmax;
1002                                 for (p = cl->cl_parent->cl_children; p != NULL;
1003                                      p = p->cl_siblings)
1004                                         p->cl_vtoff += vt;
1005                                 cl->cl_vt = 0;
1006                                 cl->cl_parent->cl_cvtmax = 0;
1007                                 cl->cl_parent->cl_cvtmin = 0;
1008                         }
1009                         cl->cl_initvt = cl->cl_vt;
1010
1011                         /* update the virtual curve */
1012                         vt = cl->cl_vt + cl->cl_vtoff;
1013                         rtsc_min(&cl->cl_virtual, cl->cl_fsc, vt, cl->cl_total);
1014                         if (cl->cl_virtual.x == vt) {
1015                                 cl->cl_virtual.x -= cl->cl_vtoff;
1016                                 cl->cl_vtoff = 0;
1017                         }
1018                         cl->cl_vtadj = 0;
1019
1020                         cl->cl_vtperiod++;  /* increment vt period */
1021                         cl->cl_parentperiod = cl->cl_parent->cl_vtperiod;
1022                         if (cl->cl_parent->cl_nactive == 0)
1023                                 cl->cl_parentperiod++;
1024                         cl->cl_f = 0;
1025
1026                         actlist_insert(cl);
1027
1028                         if (cl->cl_usc != NULL) {
1029                                 /* class has upper limit curve */
1030                                 if (cur_time == 0)
1031                                         cur_time = read_machclk();
1032
1033                                 /* update the ulimit curve */
1034                                 rtsc_min(&cl->cl_ulimit, cl->cl_usc, cur_time,
1035                                     cl->cl_total);
1036                                 /* compute myf */
1037                                 cl->cl_myf = rtsc_y2x(&cl->cl_ulimit,
1038                                     cl->cl_total);
1039                                 cl->cl_myfadj = 0;
1040                         }
1041                 }
1042
1043                 if (cl->cl_myf > cl->cl_cfmin)
1044                         f = cl->cl_myf;
1045                 else
1046                         f = cl->cl_cfmin;
1047                 if (f != cl->cl_f) {
1048                         cl->cl_f = f;
1049                         update_cfmin(cl->cl_parent);
1050                 }
1051         }
1052 }
1053
1054 static void
1055 update_vf(struct hfsc_class *cl, int len, u_int64_t cur_time)
1056 {
1057         u_int64_t f, myf_bound, delta;
1058         int go_passive;
1059
1060         go_passive = qempty(cl->cl_q);
1061
1062         for (; cl->cl_parent != NULL; cl = cl->cl_parent) {
1063
1064                 cl->cl_total += len;
1065
1066                 if (cl->cl_fsc == NULL || cl->cl_nactive == 0)
1067                         continue;
1068
1069                 if (go_passive && --cl->cl_nactive == 0)
1070                         go_passive = 1;
1071                 else
1072                         go_passive = 0;
1073
1074                 if (go_passive) {
1075                         /* no more active child, going passive */
1076
1077                         /* update cvtmax of the parent class */
1078                         if (cl->cl_vt > cl->cl_parent->cl_cvtmax)
1079                                 cl->cl_parent->cl_cvtmax = cl->cl_vt;
1080
1081                         /* remove this class from the vt list */
1082                         actlist_remove(cl);
1083
1084                         update_cfmin(cl->cl_parent);
1085
1086                         continue;
1087                 }
1088
1089                 /*
1090                  * update vt and f
1091                  */
1092                 cl->cl_vt = rtsc_y2x(&cl->cl_virtual, cl->cl_total)
1093                     - cl->cl_vtoff + cl->cl_vtadj;
1094
1095                 /*
1096                  * if vt of the class is smaller than cvtmin,
1097                  * the class was skipped in the past due to non-fit.
1098                  * if so, we need to adjust vtadj.
1099                  */
1100                 if (cl->cl_vt < cl->cl_parent->cl_cvtmin) {
1101                         cl->cl_vtadj += cl->cl_parent->cl_cvtmin - cl->cl_vt;
1102                         cl->cl_vt = cl->cl_parent->cl_cvtmin;
1103                 }
1104
1105                 /* update the vt list */
1106                 actlist_update(cl);
1107
1108                 if (cl->cl_usc != NULL) {
1109                         cl->cl_myf = cl->cl_myfadj
1110                             + rtsc_y2x(&cl->cl_ulimit, cl->cl_total);
1111
1112                         /*
1113                          * if myf lags behind by more than one clock tick
1114                          * from the current time, adjust myfadj to prevent
1115                          * a rate-limited class from going greedy.
1116                          * in a steady state under rate-limiting, myf
1117                          * fluctuates within one clock tick.
1118                          */
1119                         myf_bound = cur_time - machclk_per_tick;
1120                         if (cl->cl_myf < myf_bound) {
1121                                 delta = cur_time - cl->cl_myf;
1122                                 cl->cl_myfadj += delta;
1123                                 cl->cl_myf += delta;
1124                         }
1125                 }
1126
1127                 /* cl_f is max(cl_myf, cl_cfmin) */
1128                 if (cl->cl_myf > cl->cl_cfmin)
1129                         f = cl->cl_myf;
1130                 else
1131                         f = cl->cl_cfmin;
1132                 if (f != cl->cl_f) {
1133                         cl->cl_f = f;
1134                         update_cfmin(cl->cl_parent);
1135                 }
1136         }
1137 }
1138
1139 static void
1140 update_cfmin(struct hfsc_class *cl)
1141 {
1142         struct hfsc_class *p;
1143         u_int64_t cfmin;
1144
1145         if (TAILQ_EMPTY(&cl->cl_actc)) {
1146                 cl->cl_cfmin = 0;
1147                 return;
1148         }
1149         cfmin = HT_INFINITY;
1150         TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) {
1151                 if (p->cl_f == 0) {
1152                         cl->cl_cfmin = 0;
1153                         return;
1154                 }
1155                 if (p->cl_f < cfmin)
1156                         cfmin = p->cl_f;
1157         }
1158         cl->cl_cfmin = cfmin;
1159 }
1160
1161 /*
1162  * TAILQ based ellist and actlist implementation
1163  * (ion wanted to make a calendar queue based implementation)
1164  */
1165 /*
1166  * eligible list holds backlogged classes being sorted by their eligible times.
1167  * there is one eligible list per interface.
1168  */
1169
1170 static void
1171 ellist_insert(struct hfsc_class *cl)
1172 {
1173         struct hfsc_if  *hif = cl->cl_hif;
1174         struct hfsc_class *p;
1175
1176         /* check the last entry first */
1177         if ((p = TAILQ_LAST(&hif->hif_eligible, elighead)) == NULL ||
1178             p->cl_e <= cl->cl_e) {
1179                 TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist);
1180                 return;
1181         }
1182
1183         TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) {
1184                 if (cl->cl_e < p->cl_e) {
1185                         TAILQ_INSERT_BEFORE(p, cl, cl_ellist);
1186                         return;
1187                 }
1188         }
1189         ASSERT(0); /* should not reach here */
1190 }
1191
1192 static void
1193 ellist_remove(struct hfsc_class *cl)
1194 {
1195         struct hfsc_if  *hif = cl->cl_hif;
1196
1197         TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist);
1198 }
1199
1200 static void
1201 ellist_update(struct hfsc_class *cl)
1202 {
1203         struct hfsc_if  *hif = cl->cl_hif;
1204         struct hfsc_class *p, *last;
1205
1206         /*
1207          * the eligible time of a class increases monotonically.
1208          * if the next entry has a larger eligible time, nothing to do.
1209          */
1210         p = TAILQ_NEXT(cl, cl_ellist);
1211         if (p == NULL || cl->cl_e <= p->cl_e)
1212                 return;
1213
1214         /* check the last entry */
1215         last = TAILQ_LAST(&hif->hif_eligible, elighead);
1216         ASSERT(last != NULL);
1217         if (last->cl_e <= cl->cl_e) {
1218                 TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist);
1219                 TAILQ_INSERT_TAIL(&hif->hif_eligible, cl, cl_ellist);
1220                 return;
1221         }
1222
1223         /*
1224          * the new position must be between the next entry
1225          * and the last entry
1226          */
1227         while ((p = TAILQ_NEXT(p, cl_ellist)) != NULL) {
1228                 if (cl->cl_e < p->cl_e) {
1229                         TAILQ_REMOVE(&hif->hif_eligible, cl, cl_ellist);
1230                         TAILQ_INSERT_BEFORE(p, cl, cl_ellist);
1231                         return;
1232                 }
1233         }
1234         ASSERT(0); /* should not reach here */
1235 }
1236
1237 /* find the class with the minimum deadline among the eligible classes */
1238 struct hfsc_class *
1239 hfsc_get_mindl(struct hfsc_if *hif, u_int64_t cur_time)
1240 {
1241         struct hfsc_class *p, *cl = NULL;
1242
1243         TAILQ_FOREACH(p, &hif->hif_eligible, cl_ellist) {
1244                 if (p->cl_e > cur_time)
1245                         break;
1246                 if (cl == NULL || p->cl_d < cl->cl_d)
1247                         cl = p;
1248         }
1249         return (cl);
1250 }
1251
1252 /*
1253  * active children list holds backlogged child classes being sorted
1254  * by their virtual time.
1255  * each intermediate class has one active children list.
1256  */
1257
1258 static void
1259 actlist_insert(struct hfsc_class *cl)
1260 {
1261         struct hfsc_class *p;
1262
1263         /* check the last entry first */
1264         if ((p = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead)) == NULL
1265             || p->cl_vt <= cl->cl_vt) {
1266                 TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist);
1267                 return;
1268         }
1269
1270         TAILQ_FOREACH(p, &cl->cl_parent->cl_actc, cl_actlist) {
1271                 if (cl->cl_vt < p->cl_vt) {
1272                         TAILQ_INSERT_BEFORE(p, cl, cl_actlist);
1273                         return;
1274                 }
1275         }
1276         ASSERT(0); /* should not reach here */
1277 }
1278
1279 static void
1280 actlist_remove(struct hfsc_class *cl)
1281 {
1282         TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist);
1283 }
1284
1285 static void
1286 actlist_update(struct hfsc_class *cl)
1287 {
1288         struct hfsc_class *p, *last;
1289
1290         /*
1291          * the virtual time of a class increases monotonically during its
1292          * backlogged period.
1293          * if the next entry has a larger virtual time, nothing to do.
1294          */
1295         p = TAILQ_NEXT(cl, cl_actlist);
1296         if (p == NULL || cl->cl_vt < p->cl_vt)
1297                 return;
1298
1299         /* check the last entry */
1300         last = TAILQ_LAST(&cl->cl_parent->cl_actc, acthead);
1301         ASSERT(last != NULL);
1302         if (last->cl_vt <= cl->cl_vt) {
1303                 TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist);
1304                 TAILQ_INSERT_TAIL(&cl->cl_parent->cl_actc, cl, cl_actlist);
1305                 return;
1306         }
1307
1308         /*
1309          * the new position must be between the next entry
1310          * and the last entry
1311          */
1312         while ((p = TAILQ_NEXT(p, cl_actlist)) != NULL) {
1313                 if (cl->cl_vt < p->cl_vt) {
1314                         TAILQ_REMOVE(&cl->cl_parent->cl_actc, cl, cl_actlist);
1315                         TAILQ_INSERT_BEFORE(p, cl, cl_actlist);
1316                         return;
1317                 }
1318         }
1319         ASSERT(0); /* should not reach here */
1320 }
1321
1322 static struct hfsc_class *
1323 actlist_firstfit(struct hfsc_class *cl, u_int64_t cur_time)
1324 {
1325         struct hfsc_class *p;
1326
1327         TAILQ_FOREACH(p, &cl->cl_actc, cl_actlist) {
1328                 if (p->cl_f <= cur_time)
1329                         return (p);
1330         }
1331         return (NULL);
1332 }
1333
1334 /*
1335  * service curve support functions
1336  *
1337  *  external service curve parameters
1338  *      m: bits/sec
1339  *      d: msec
1340  *  internal service curve parameters
1341  *      sm: (bytes/tsc_interval) << SM_SHIFT
1342  *      ism: (tsc_count/byte) << ISM_SHIFT
1343  *      dx: tsc_count
1344  *
1345  * SM_SHIFT and ISM_SHIFT are scaled in order to keep effective digits.
1346  * we should be able to handle 100K-1Gbps linkspeed with 200Hz-1GHz CPU
1347  * speed.  SM_SHIFT and ISM_SHIFT are selected to have at least 3 effective
1348  * digits in decimal using the following table.
1349  *
1350  *  bits/sec    100Kbps     1Mbps     10Mbps     100Mbps    1Gbps
1351  *  ----------+-------------------------------------------------------
1352  *  bytes/nsec  12.5e-6    125e-6     1250e-6    12500e-6   125000e-6
1353  *  sm(500MHz)  25.0e-6    250e-6     2500e-6    25000e-6   250000e-6
1354  *  sm(200MHz)  62.5e-6    625e-6     6250e-6    62500e-6   625000e-6
1355  *
1356  *  nsec/byte   80000      8000       800        80         8
1357  *  ism(500MHz) 40000      4000       400        40         4
1358  *  ism(200MHz) 16000      1600       160        16         1.6
1359  */
1360 #define SM_SHIFT        24
1361 #define ISM_SHIFT       10
1362
1363 #define SM_MASK         ((1LL << SM_SHIFT) - 1)
1364 #define ISM_MASK        ((1LL << ISM_SHIFT) - 1)
1365
1366 static __inline u_int64_t
1367 seg_x2y(u_int64_t x, u_int64_t sm)
1368 {
1369         u_int64_t y;
1370
1371         /*
1372          * compute
1373          *      y = x * sm >> SM_SHIFT
1374          * but divide it for the upper and lower bits to avoid overflow
1375          */
1376         y = (x >> SM_SHIFT) * sm + (((x & SM_MASK) * sm) >> SM_SHIFT);
1377         return (y);
1378 }
1379
1380 static __inline u_int64_t
1381 seg_y2x(u_int64_t y, u_int64_t ism)
1382 {
1383         u_int64_t x;
1384
1385         if (y == 0)
1386                 x = 0;
1387         else if (ism == HT_INFINITY)
1388                 x = HT_INFINITY;
1389         else {
1390                 x = (y >> ISM_SHIFT) * ism
1391                     + (((y & ISM_MASK) * ism) >> ISM_SHIFT);
1392         }
1393         return (x);
1394 }
1395
1396 static __inline u_int64_t
1397 m2sm(u_int m)
1398 {
1399         u_int64_t sm;
1400
1401         sm = ((u_int64_t)m << SM_SHIFT) / 8 / machclk_freq;
1402         return (sm);
1403 }
1404
1405 static __inline u_int64_t
1406 m2ism(u_int m)
1407 {
1408         u_int64_t ism;
1409
1410         if (m == 0)
1411                 ism = HT_INFINITY;
1412         else
1413                 ism = ((u_int64_t)machclk_freq << ISM_SHIFT) * 8 / m;
1414         return (ism);
1415 }
1416
1417 static __inline u_int64_t
1418 d2dx(u_int d)
1419 {
1420         u_int64_t dx;
1421
1422         dx = ((u_int64_t)d * machclk_freq) / 1000;
1423         return (dx);
1424 }
1425
1426 static u_int
1427 sm2m(u_int64_t sm)
1428 {
1429         u_int64_t m;
1430
1431         m = (sm * 8 * machclk_freq) >> SM_SHIFT;
1432         return ((u_int)m);
1433 }
1434
1435 static u_int
1436 dx2d(u_int64_t dx)
1437 {
1438         u_int64_t d;
1439
1440         d = dx * 1000 / machclk_freq;
1441         return ((u_int)d);
1442 }
1443
1444 static void
1445 sc2isc(struct service_curve *sc, struct internal_sc *isc)
1446 {
1447         isc->sm1 = m2sm(sc->m1);
1448         isc->ism1 = m2ism(sc->m1);
1449         isc->dx = d2dx(sc->d);
1450         isc->dy = seg_x2y(isc->dx, isc->sm1);
1451         isc->sm2 = m2sm(sc->m2);
1452         isc->ism2 = m2ism(sc->m2);
1453 }
1454
1455 /*
1456  * initialize the runtime service curve with the given internal
1457  * service curve starting at (x, y).
1458  */
1459 static void
1460 rtsc_init(struct runtime_sc *rtsc, struct internal_sc * isc, u_int64_t x,
1461     u_int64_t y)
1462 {
1463         rtsc->x =       x;
1464         rtsc->y =       y;
1465         rtsc->sm1 =     isc->sm1;
1466         rtsc->ism1 =    isc->ism1;
1467         rtsc->dx =      isc->dx;
1468         rtsc->dy =      isc->dy;
1469         rtsc->sm2 =     isc->sm2;
1470         rtsc->ism2 =    isc->ism2;
1471 }
1472
1473 /*
1474  * calculate the y-projection of the runtime service curve by the
1475  * given x-projection value
1476  */
1477 static u_int64_t
1478 rtsc_y2x(struct runtime_sc *rtsc, u_int64_t y)
1479 {
1480         u_int64_t       x;
1481
1482         if (y < rtsc->y)
1483                 x = rtsc->x;
1484         else if (y <= rtsc->y + rtsc->dy) {
1485                 /* x belongs to the 1st segment */
1486                 if (rtsc->dy == 0)
1487                         x = rtsc->x + rtsc->dx;
1488                 else
1489                         x = rtsc->x + seg_y2x(y - rtsc->y, rtsc->ism1);
1490         } else {
1491                 /* x belongs to the 2nd segment */
1492                 x = rtsc->x + rtsc->dx
1493                     + seg_y2x(y - rtsc->y - rtsc->dy, rtsc->ism2);
1494         }
1495         return (x);
1496 }
1497
1498 static u_int64_t
1499 rtsc_x2y(struct runtime_sc *rtsc, u_int64_t x)
1500 {
1501         u_int64_t       y;
1502
1503         if (x <= rtsc->x)
1504                 y = rtsc->y;
1505         else if (x <= rtsc->x + rtsc->dx)
1506                 /* y belongs to the 1st segment */
1507                 y = rtsc->y + seg_x2y(x - rtsc->x, rtsc->sm1);
1508         else
1509                 /* y belongs to the 2nd segment */
1510                 y = rtsc->y + rtsc->dy
1511                     + seg_x2y(x - rtsc->x - rtsc->dx, rtsc->sm2);
1512         return (y);
1513 }
1514
1515 /*
1516  * update the runtime service curve by taking the minimum of the current
1517  * runtime service curve and the service curve starting at (x, y).
1518  */
1519 static void
1520 rtsc_min(struct runtime_sc *rtsc, struct internal_sc *isc, u_int64_t x,
1521     u_int64_t y)
1522 {
1523         u_int64_t       y1, y2, dx, dy;
1524
1525         if (isc->sm1 <= isc->sm2) {
1526                 /* service curve is convex */
1527                 y1 = rtsc_x2y(rtsc, x);
1528                 if (y1 < y)
1529                         /* the current rtsc is smaller */
1530                         return;
1531                 rtsc->x = x;
1532                 rtsc->y = y;
1533                 return;
1534         }
1535
1536         /*
1537          * service curve is concave
1538          * compute the two y values of the current rtsc
1539          *      y1: at x
1540          *      y2: at (x + dx)
1541          */
1542         y1 = rtsc_x2y(rtsc, x);
1543         if (y1 <= y) {
1544                 /* rtsc is below isc, no change to rtsc */
1545                 return;
1546         }
1547
1548         y2 = rtsc_x2y(rtsc, x + isc->dx);
1549         if (y2 >= y + isc->dy) {
1550                 /* rtsc is above isc, replace rtsc by isc */
1551                 rtsc->x = x;
1552                 rtsc->y = y;
1553                 rtsc->dx = isc->dx;
1554                 rtsc->dy = isc->dy;
1555                 return;
1556         }
1557
1558         /*
1559          * the two curves intersect
1560          * compute the offsets (dx, dy) using the reverse
1561          * function of seg_x2y()
1562          *      seg_x2y(dx, sm1) == seg_x2y(dx, sm2) + (y1 - y)
1563          */
1564         dx = ((y1 - y) << SM_SHIFT) / (isc->sm1 - isc->sm2);
1565         /*
1566          * check if (x, y1) belongs to the 1st segment of rtsc.
1567          * if so, add the offset.
1568          */
1569         if (rtsc->x + rtsc->dx > x)
1570                 dx += rtsc->x + rtsc->dx - x;
1571         dy = seg_x2y(dx, isc->sm1);
1572
1573         rtsc->x = x;
1574         rtsc->y = y;
1575         rtsc->dx = dx;
1576         rtsc->dy = dy;
1577         return;
1578 }
1579
1580 static void
1581 get_class_stats(struct hfsc_classstats *sp, struct hfsc_class *cl)
1582 {
1583         sp->class_id = cl->cl_id;
1584         sp->class_handle = cl->cl_handle;
1585
1586         if (cl->cl_rsc != NULL) {
1587                 sp->rsc.m1 = sm2m(cl->cl_rsc->sm1);
1588                 sp->rsc.d = dx2d(cl->cl_rsc->dx);
1589                 sp->rsc.m2 = sm2m(cl->cl_rsc->sm2);
1590         } else {
1591                 sp->rsc.m1 = 0;
1592                 sp->rsc.d = 0;
1593                 sp->rsc.m2 = 0;
1594         }
1595         if (cl->cl_fsc != NULL) {
1596                 sp->fsc.m1 = sm2m(cl->cl_fsc->sm1);
1597                 sp->fsc.d = dx2d(cl->cl_fsc->dx);
1598                 sp->fsc.m2 = sm2m(cl->cl_fsc->sm2);
1599         } else {
1600                 sp->fsc.m1 = 0;
1601                 sp->fsc.d = 0;
1602                 sp->fsc.m2 = 0;
1603         }
1604         if (cl->cl_usc != NULL) {
1605                 sp->usc.m1 = sm2m(cl->cl_usc->sm1);
1606                 sp->usc.d = dx2d(cl->cl_usc->dx);
1607                 sp->usc.m2 = sm2m(cl->cl_usc->sm2);
1608         } else {
1609                 sp->usc.m1 = 0;
1610                 sp->usc.d = 0;
1611                 sp->usc.m2 = 0;
1612         }
1613
1614         sp->total = cl->cl_total;
1615         sp->cumul = cl->cl_cumul;
1616
1617         sp->d = cl->cl_d;
1618         sp->e = cl->cl_e;
1619         sp->vt = cl->cl_vt;
1620         sp->f = cl->cl_f;
1621
1622         sp->initvt = cl->cl_initvt;
1623         sp->vtperiod = cl->cl_vtperiod;
1624         sp->parentperiod = cl->cl_parentperiod;
1625         sp->nactive = cl->cl_nactive;
1626         sp->vtoff = cl->cl_vtoff;
1627         sp->cvtmax = cl->cl_cvtmax;
1628         sp->myf = cl->cl_myf;
1629         sp->cfmin = cl->cl_cfmin;
1630         sp->cvtmin = cl->cl_cvtmin;
1631         sp->myfadj = cl->cl_myfadj;
1632         sp->vtadj = cl->cl_vtadj;
1633
1634         sp->cur_time = read_machclk();
1635         sp->machclk_freq = machclk_freq;
1636
1637         sp->qlength = qlen(cl->cl_q);
1638         sp->qlimit = qlimit(cl->cl_q);
1639         sp->xmit_cnt = cl->cl_stats.xmit_cnt;
1640         sp->drop_cnt = cl->cl_stats.drop_cnt;
1641         sp->period = cl->cl_stats.period;
1642
1643         sp->qtype = qtype(cl->cl_q);
1644 #ifdef ALTQ_RED
1645         if (q_is_red(cl->cl_q))
1646                 red_getstats(cl->cl_red, &sp->red[0]);
1647 #endif
1648 #ifdef ALTQ_RIO
1649         if (q_is_rio(cl->cl_q))
1650                 rio_getstats((rio_t *)cl->cl_red, &sp->red[0]);
1651 #endif
1652 }
1653
1654 /* convert a class handle to the corresponding class pointer */
1655 static struct hfsc_class *
1656 clh_to_clp(struct hfsc_if *hif, u_int32_t chandle)
1657 {
1658         int i;
1659         struct hfsc_class *cl;
1660
1661         if (chandle == 0)
1662                 return (NULL);
1663         /*
1664          * first, try optimistically the slot matching the lower bits of
1665          * the handle.  if it fails, do the linear table search.
1666          */
1667         i = chandle % HFSC_MAX_CLASSES;
1668         if ((cl = hif->hif_class_tbl[i]) != NULL && cl->cl_handle == chandle)
1669                 return (cl);
1670         for (i = 0; i < HFSC_MAX_CLASSES; i++)
1671                 if ((cl = hif->hif_class_tbl[i]) != NULL &&
1672                     cl->cl_handle == chandle)
1673                         return (cl);
1674         return (NULL);
1675 }
1676
1677 #ifdef ALTQ3_COMPAT
1678 static struct hfsc_if *
1679 hfsc_attach(ifq, bandwidth)
1680         struct ifaltq *ifq;
1681         u_int bandwidth;
1682 {
1683         struct hfsc_if *hif;
1684
1685         hif = malloc(sizeof(struct hfsc_if), M_DEVBUF, M_WAITOK);
1686         if (hif == NULL)
1687                 return (NULL);
1688         bzero(hif, sizeof(struct hfsc_if));
1689
1690         hif->hif_eligible = ellist_alloc();
1691         if (hif->hif_eligible == NULL) {
1692                 free(hif, M_DEVBUF);
1693                 return NULL;
1694         }
1695
1696         hif->hif_ifq = ifq;
1697
1698         /* add this state to the hfsc list */
1699         hif->hif_next = hif_list;
1700         hif_list = hif;
1701
1702         return (hif);
1703 }
1704
1705 static int
1706 hfsc_detach(hif)
1707         struct hfsc_if *hif;
1708 {
1709         (void)hfsc_clear_interface(hif);
1710         (void)hfsc_class_destroy(hif->hif_rootclass);
1711
1712         /* remove this interface from the hif list */
1713         if (hif_list == hif)
1714                 hif_list = hif->hif_next;
1715         else {
1716                 struct hfsc_if *h;
1717
1718                 for (h = hif_list; h != NULL; h = h->hif_next)
1719                         if (h->hif_next == hif) {
1720                                 h->hif_next = hif->hif_next;
1721                                 break;
1722                         }
1723                 ASSERT(h != NULL);
1724         }
1725
1726         ellist_destroy(hif->hif_eligible);
1727
1728         free(hif, M_DEVBUF);
1729
1730         return (0);
1731 }
1732
1733 static int
1734 hfsc_class_modify(cl, rsc, fsc, usc)
1735         struct hfsc_class *cl;
1736         struct service_curve *rsc, *fsc, *usc;
1737 {
1738         struct internal_sc *rsc_tmp, *fsc_tmp, *usc_tmp;
1739         u_int64_t cur_time;
1740         int s;
1741
1742         rsc_tmp = fsc_tmp = usc_tmp = NULL;
1743         if (rsc != NULL && (rsc->m1 != 0 || rsc->m2 != 0) &&
1744             cl->cl_rsc == NULL) {
1745                 rsc_tmp = malloc(sizeof(struct internal_sc),
1746                     M_DEVBUF, M_WAITOK);
1747                 if (rsc_tmp == NULL)
1748                         return (ENOMEM);
1749         }
1750         if (fsc != NULL && (fsc->m1 != 0 || fsc->m2 != 0) &&
1751             cl->cl_fsc == NULL) {
1752                 fsc_tmp = malloc(sizeof(struct internal_sc),
1753                     M_DEVBUF, M_WAITOK);
1754                 if (fsc_tmp == NULL) {
1755                         free(rsc_tmp);
1756                         return (ENOMEM);
1757                 }
1758         }
1759         if (usc != NULL && (usc->m1 != 0 || usc->m2 != 0) &&
1760             cl->cl_usc == NULL) {
1761                 usc_tmp = malloc(sizeof(struct internal_sc),
1762                     M_DEVBUF, M_WAITOK);
1763                 if (usc_tmp == NULL) {
1764                         free(rsc_tmp);
1765                         free(fsc_tmp);
1766                         return (ENOMEM);
1767                 }
1768         }
1769
1770         cur_time = read_machclk();
1771 #ifdef __NetBSD__
1772         s = splnet();
1773 #else
1774         s = splimp();
1775 #endif
1776         IFQ_LOCK(cl->cl_hif->hif_ifq);
1777
1778         if (rsc != NULL) {
1779                 if (rsc->m1 == 0 && rsc->m2 == 0) {
1780                         if (cl->cl_rsc != NULL) {
1781                                 if (!qempty(cl->cl_q))
1782                                         hfsc_purgeq(cl);
1783                                 free(cl->cl_rsc, M_DEVBUF);
1784                                 cl->cl_rsc = NULL;
1785                         }
1786                 } else {
1787                         if (cl->cl_rsc == NULL)
1788                                 cl->cl_rsc = rsc_tmp;
1789                         sc2isc(rsc, cl->cl_rsc);
1790                         rtsc_init(&cl->cl_deadline, cl->cl_rsc, cur_time,
1791                             cl->cl_cumul);
1792                         cl->cl_eligible = cl->cl_deadline;
1793                         if (cl->cl_rsc->sm1 <= cl->cl_rsc->sm2) {
1794                                 cl->cl_eligible.dx = 0;
1795                                 cl->cl_eligible.dy = 0;
1796                         }
1797                 }
1798         }
1799
1800         if (fsc != NULL) {
1801                 if (fsc->m1 == 0 && fsc->m2 == 0) {
1802                         if (cl->cl_fsc != NULL) {
1803                                 if (!qempty(cl->cl_q))
1804                                         hfsc_purgeq(cl);
1805                                 free(cl->cl_fsc, M_DEVBUF);
1806                                 cl->cl_fsc = NULL;
1807                         }
1808                 } else {
1809                         if (cl->cl_fsc == NULL)
1810                                 cl->cl_fsc = fsc_tmp;
1811                         sc2isc(fsc, cl->cl_fsc);
1812                         rtsc_init(&cl->cl_virtual, cl->cl_fsc, cl->cl_vt,
1813                             cl->cl_total);
1814                 }
1815         }
1816
1817         if (usc != NULL) {
1818                 if (usc->m1 == 0 && usc->m2 == 0) {
1819                         if (cl->cl_usc != NULL) {
1820                                 free(cl->cl_usc, M_DEVBUF);
1821                                 cl->cl_usc = NULL;
1822                                 cl->cl_myf = 0;
1823                         }
1824                 } else {
1825                         if (cl->cl_usc == NULL)
1826                                 cl->cl_usc = usc_tmp;
1827                         sc2isc(usc, cl->cl_usc);
1828                         rtsc_init(&cl->cl_ulimit, cl->cl_usc, cur_time,
1829                             cl->cl_total);
1830                 }
1831         }
1832
1833         if (!qempty(cl->cl_q)) {
1834                 if (cl->cl_rsc != NULL)
1835                         update_ed(cl, m_pktlen(qhead(cl->cl_q)));
1836                 if (cl->cl_fsc != NULL)
1837                         update_vf(cl, 0, cur_time);
1838                 /* is this enough? */
1839         }
1840
1841         IFQ_UNLOCK(cl->cl_hif->hif_ifq);
1842         splx(s);
1843
1844         return (0);
1845 }
1846
1847 /*
1848  * hfsc device interface
1849  */
1850 int
1851 hfscopen(dev, flag, fmt, p)
1852         dev_t dev;
1853         int flag, fmt;
1854 #if (__FreeBSD_version > 500000)
1855         struct thread *p;
1856 #else
1857         struct proc *p;
1858 #endif
1859 {
1860         if (machclk_freq == 0)
1861                 init_machclk();
1862
1863         if (machclk_freq == 0) {
1864                 printf("hfsc: no cpu clock available!\n");
1865                 return (ENXIO);
1866         }
1867
1868         /* everything will be done when the queueing scheme is attached. */
1869         return 0;
1870 }
1871
1872 int
1873 hfscclose(dev, flag, fmt, p)
1874         dev_t dev;
1875         int flag, fmt;
1876 #if (__FreeBSD_version > 500000)
1877         struct thread *p;
1878 #else
1879         struct proc *p;
1880 #endif
1881 {
1882         struct hfsc_if *hif;
1883         int err, error = 0;
1884
1885         while ((hif = hif_list) != NULL) {
1886                 /* destroy all */
1887                 if (ALTQ_IS_ENABLED(hif->hif_ifq))
1888                         altq_disable(hif->hif_ifq);
1889
1890                 err = altq_detach(hif->hif_ifq);
1891                 if (err == 0)
1892                         err = hfsc_detach(hif);
1893                 if (err != 0 && error == 0)
1894                         error = err;
1895         }
1896
1897         return error;
1898 }
1899
1900 int
1901 hfscioctl(dev, cmd, addr, flag, p)
1902         dev_t dev;
1903         ioctlcmd_t cmd;
1904         caddr_t addr;
1905         int flag;
1906 #if (__FreeBSD_version > 500000)
1907         struct thread *p;
1908 #else
1909         struct proc *p;
1910 #endif
1911 {
1912         struct hfsc_if *hif;
1913         struct hfsc_interface *ifacep;
1914         int     error = 0;
1915
1916         /* check super-user privilege */
1917         switch (cmd) {
1918         case HFSC_GETSTATS:
1919                 break;
1920         default:
1921 #if (__FreeBSD_version > 700000)
1922                 if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0)
1923                         return (error);
1924 #elsif (__FreeBSD_version > 400000)
1925                 if ((error = suser(p)) != 0)
1926                         return (error);
1927 #else
1928                 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1929                         return (error);
1930 #endif
1931                 break;
1932         }
1933
1934         switch (cmd) {
1935
1936         case HFSC_IF_ATTACH:
1937                 error = hfsccmd_if_attach((struct hfsc_attach *)addr);
1938                 break;
1939
1940         case HFSC_IF_DETACH:
1941                 error = hfsccmd_if_detach((struct hfsc_interface *)addr);
1942                 break;
1943
1944         case HFSC_ENABLE:
1945         case HFSC_DISABLE:
1946         case HFSC_CLEAR_HIERARCHY:
1947                 ifacep = (struct hfsc_interface *)addr;
1948                 if ((hif = altq_lookup(ifacep->hfsc_ifname,
1949                                        ALTQT_HFSC)) == NULL) {
1950                         error = EBADF;
1951                         break;
1952                 }
1953
1954                 switch (cmd) {
1955
1956                 case HFSC_ENABLE:
1957                         if (hif->hif_defaultclass == NULL) {
1958 #ifdef ALTQ_DEBUG
1959                                 printf("hfsc: no default class\n");
1960 #endif
1961                                 error = EINVAL;
1962                                 break;
1963                         }
1964                         error = altq_enable(hif->hif_ifq);
1965                         break;
1966
1967                 case HFSC_DISABLE:
1968                         error = altq_disable(hif->hif_ifq);
1969                         break;
1970
1971                 case HFSC_CLEAR_HIERARCHY:
1972                         hfsc_clear_interface(hif);
1973                         break;
1974                 }
1975                 break;
1976
1977         case HFSC_ADD_CLASS:
1978                 error = hfsccmd_add_class((struct hfsc_add_class *)addr);
1979                 break;
1980
1981         case HFSC_DEL_CLASS:
1982                 error = hfsccmd_delete_class((struct hfsc_delete_class *)addr);
1983                 break;
1984
1985         case HFSC_MOD_CLASS:
1986                 error = hfsccmd_modify_class((struct hfsc_modify_class *)addr);
1987                 break;
1988
1989         case HFSC_ADD_FILTER:
1990                 error = hfsccmd_add_filter((struct hfsc_add_filter *)addr);
1991                 break;
1992
1993         case HFSC_DEL_FILTER:
1994                 error = hfsccmd_delete_filter((struct hfsc_delete_filter *)addr);
1995                 break;
1996
1997         case HFSC_GETSTATS:
1998                 error = hfsccmd_class_stats((struct hfsc_class_stats *)addr);
1999                 break;
2000
2001         default:
2002                 error = EINVAL;
2003                 break;
2004         }
2005         return error;
2006 }
2007
2008 static int
2009 hfsccmd_if_attach(ap)
2010         struct hfsc_attach *ap;
2011 {
2012         struct hfsc_if *hif;
2013         struct ifnet *ifp;
2014         int error;
2015
2016         if ((ifp = ifunit(ap->iface.hfsc_ifname)) == NULL)
2017                 return (ENXIO);
2018
2019         if ((hif = hfsc_attach(&ifp->if_snd, ap->bandwidth)) == NULL)
2020                 return (ENOMEM);
2021
2022         /*
2023          * set HFSC to this ifnet structure.
2024          */
2025         if ((error = altq_attach(&ifp->if_snd, ALTQT_HFSC, hif,
2026                                  hfsc_enqueue, hfsc_dequeue, hfsc_request,
2027                                  &hif->hif_classifier, acc_classify)) != 0)
2028                 (void)hfsc_detach(hif);
2029
2030         return (error);
2031 }
2032
2033 static int
2034 hfsccmd_if_detach(ap)
2035         struct hfsc_interface *ap;
2036 {
2037         struct hfsc_if *hif;
2038         int error;
2039
2040         if ((hif = altq_lookup(ap->hfsc_ifname, ALTQT_HFSC)) == NULL)
2041                 return (EBADF);
2042
2043         if (ALTQ_IS_ENABLED(hif->hif_ifq))
2044                 altq_disable(hif->hif_ifq);
2045
2046         if ((error = altq_detach(hif->hif_ifq)))
2047                 return (error);
2048
2049         return hfsc_detach(hif);
2050 }
2051
2052 static int
2053 hfsccmd_add_class(ap)
2054         struct hfsc_add_class *ap;
2055 {
2056         struct hfsc_if *hif;
2057         struct hfsc_class *cl, *parent;
2058         int     i;
2059
2060         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2061                 return (EBADF);
2062
2063         if (ap->parent_handle == HFSC_NULLCLASS_HANDLE &&
2064             hif->hif_rootclass == NULL)
2065                 parent = NULL;
2066         else if ((parent = clh_to_clp(hif, ap->parent_handle)) == NULL)
2067                 return (EINVAL);
2068
2069         /* assign a class handle (use a free slot number for now) */
2070         for (i = 1; i < HFSC_MAX_CLASSES; i++)
2071                 if (hif->hif_class_tbl[i] == NULL)
2072                         break;
2073         if (i == HFSC_MAX_CLASSES)
2074                 return (EBUSY);
2075
2076         if ((cl = hfsc_class_create(hif, &ap->service_curve, NULL, NULL,
2077             parent, ap->qlimit, ap->flags, i)) == NULL)
2078                 return (ENOMEM);
2079
2080         /* return a class handle to the user */
2081         ap->class_handle = i;
2082
2083         return (0);
2084 }
2085
2086 static int
2087 hfsccmd_delete_class(ap)
2088         struct hfsc_delete_class *ap;
2089 {
2090         struct hfsc_if *hif;
2091         struct hfsc_class *cl;
2092
2093         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2094                 return (EBADF);
2095
2096         if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL)
2097                 return (EINVAL);
2098
2099         return hfsc_class_destroy(cl);
2100 }
2101
2102 static int
2103 hfsccmd_modify_class(ap)
2104         struct hfsc_modify_class *ap;
2105 {
2106         struct hfsc_if *hif;
2107         struct hfsc_class *cl;
2108         struct service_curve *rsc = NULL;
2109         struct service_curve *fsc = NULL;
2110         struct service_curve *usc = NULL;
2111
2112         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2113                 return (EBADF);
2114
2115         if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL)
2116                 return (EINVAL);
2117
2118         if (ap->sctype & HFSC_REALTIMESC)
2119                 rsc = &ap->service_curve;
2120         if (ap->sctype & HFSC_LINKSHARINGSC)
2121                 fsc = &ap->service_curve;
2122         if (ap->sctype & HFSC_UPPERLIMITSC)
2123                 usc = &ap->service_curve;
2124
2125         return hfsc_class_modify(cl, rsc, fsc, usc);
2126 }
2127
2128 static int
2129 hfsccmd_add_filter(ap)
2130         struct hfsc_add_filter *ap;
2131 {
2132         struct hfsc_if *hif;
2133         struct hfsc_class *cl;
2134
2135         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2136                 return (EBADF);
2137
2138         if ((cl = clh_to_clp(hif, ap->class_handle)) == NULL)
2139                 return (EINVAL);
2140
2141         if (is_a_parent_class(cl)) {
2142 #ifdef ALTQ_DEBUG
2143                 printf("hfsccmd_add_filter: not a leaf class!\n");
2144 #endif
2145                 return (EINVAL);
2146         }
2147
2148         return acc_add_filter(&hif->hif_classifier, &ap->filter,
2149                               cl, &ap->filter_handle);
2150 }
2151
2152 static int
2153 hfsccmd_delete_filter(ap)
2154         struct hfsc_delete_filter *ap;
2155 {
2156         struct hfsc_if *hif;
2157
2158         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2159                 return (EBADF);
2160
2161         return acc_delete_filter(&hif->hif_classifier,
2162                                  ap->filter_handle);
2163 }
2164
2165 static int
2166 hfsccmd_class_stats(ap)
2167         struct hfsc_class_stats *ap;
2168 {
2169         struct hfsc_if *hif;
2170         struct hfsc_class *cl;
2171         struct hfsc_classstats stats, *usp;
2172         int     n, nclasses, error;
2173
2174         if ((hif = altq_lookup(ap->iface.hfsc_ifname, ALTQT_HFSC)) == NULL)
2175                 return (EBADF);
2176
2177         ap->cur_time = read_machclk();
2178         ap->machclk_freq = machclk_freq;
2179         ap->hif_classes = hif->hif_classes;
2180         ap->hif_packets = hif->hif_packets;
2181
2182         /* skip the first N classes in the tree */
2183         nclasses = ap->nskip;
2184         for (cl = hif->hif_rootclass, n = 0; cl != NULL && n < nclasses;
2185              cl = hfsc_nextclass(cl), n++)
2186                 ;
2187         if (n != nclasses)
2188                 return (EINVAL);
2189
2190         /* then, read the next N classes in the tree */
2191         nclasses = ap->nclasses;
2192         usp = ap->stats;
2193         for (n = 0; cl != NULL && n < nclasses; cl = hfsc_nextclass(cl), n++) {
2194
2195                 get_class_stats(&stats, cl);
2196
2197                 if ((error = copyout((caddr_t)&stats, (caddr_t)usp++,
2198                                      sizeof(stats))) != 0)
2199                         return (error);
2200         }
2201
2202         ap->nclasses = n;
2203
2204         return (0);
2205 }
2206
2207 #ifdef KLD_MODULE
2208
2209 static struct altqsw hfsc_sw =
2210         {"hfsc", hfscopen, hfscclose, hfscioctl};
2211
2212 ALTQ_MODULE(altq_hfsc, ALTQT_HFSC, &hfsc_sw);
2213 MODULE_DEPEND(altq_hfsc, altq_red, 1, 1, 1);
2214 MODULE_DEPEND(altq_hfsc, altq_rio, 1, 1, 1);
2215
2216 #endif /* KLD_MODULE */
2217 #endif /* ALTQ3_COMPAT */
2218
2219 #endif /* ALTQ_HFSC */