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