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