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