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