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