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