2 * Copyright (c) 2011-2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
33 #include <sys/cdefs.h>
34 #include <sys/param.h>
35 #include <sys/malloc.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
39 #include <sys/kernel.h>
40 #include <sys/syslog.h>
42 #include <kern/zalloc.h>
45 #include <net/net_osdep.h>
47 #include <net/pktsched/pktsched_tcq.h>
48 #include <netinet/in.h>
54 static int tcq_enqueue_ifclassq(struct ifclassq
*, classq_pkt_t
*, boolean_t
*);
55 static void tcq_dequeue_tc_ifclassq(struct ifclassq
*, mbuf_svc_class_t
,
57 static int tcq_request_ifclassq(struct ifclassq
*, cqrq_t
, void *);
58 static int tcq_clear_interface(struct tcq_if
*);
59 static struct tcq_class
*tcq_class_create(struct tcq_if
*, int, u_int32_t
,
60 int, u_int32_t
, classq_pkt_type_t
);
61 static int tcq_class_destroy(struct tcq_if
*, struct tcq_class
*);
62 static int tcq_destroy_locked(struct tcq_if
*);
63 static inline int tcq_addq(struct tcq_class
*, pktsched_pkt_t
*,
65 static inline void tcq_getq(struct tcq_class
*, pktsched_pkt_t
*);
66 static void tcq_purgeq(struct tcq_if
*, struct tcq_class
*, u_int32_t
,
67 u_int32_t
*, u_int32_t
*);
68 static void tcq_purge_sc(struct tcq_if
*, cqrq_purge_sc_t
*);
69 static void tcq_updateq(struct tcq_if
*, struct tcq_class
*, cqev_t
);
70 static int tcq_throttle(struct tcq_if
*, cqrq_throttle_t
*);
71 static int tcq_resumeq(struct tcq_if
*, struct tcq_class
*);
72 static int tcq_suspendq(struct tcq_if
*, struct tcq_class
*);
73 static int tcq_stat_sc(struct tcq_if
*, cqrq_stat_sc_t
*);
74 static void tcq_dequeue_cl(struct tcq_if
*, struct tcq_class
*,
75 mbuf_svc_class_t
, pktsched_pkt_t
*);
76 static inline struct tcq_class
*tcq_clh_to_clp(struct tcq_if
*, u_int32_t
);
77 static const char *tcq_style(struct tcq_if
*);
79 #define TCQ_ZONE_MAX 32 /* maximum elements in zone */
80 #define TCQ_ZONE_NAME "pktsched_tcq" /* zone name */
82 static unsigned int tcq_size
; /* size of zone element */
83 static struct zone
*tcq_zone
; /* zone for tcq */
85 #define TCQ_CL_ZONE_MAX 32 /* maximum elements in zone */
86 #define TCQ_CL_ZONE_NAME "pktsched_tcq_cl" /* zone name */
88 static unsigned int tcq_cl_size
; /* size of zone element */
89 static struct zone
*tcq_cl_zone
; /* zone for tcq_class */
94 tcq_size
= sizeof(struct tcq_if
);
95 tcq_zone
= zinit(tcq_size
, TCQ_ZONE_MAX
* tcq_size
,
97 if (tcq_zone
== NULL
) {
98 panic("%s: failed allocating %s", __func__
, TCQ_ZONE_NAME
);
101 zone_change(tcq_zone
, Z_EXPAND
, TRUE
);
102 zone_change(tcq_zone
, Z_CALLERACCT
, TRUE
);
104 tcq_cl_size
= sizeof(struct tcq_class
);
105 tcq_cl_zone
= zinit(tcq_cl_size
, TCQ_CL_ZONE_MAX
* tcq_cl_size
,
106 0, TCQ_CL_ZONE_NAME
);
107 if (tcq_cl_zone
== NULL
) {
108 panic("%s: failed allocating %s", __func__
, TCQ_CL_ZONE_NAME
);
111 zone_change(tcq_cl_zone
, Z_EXPAND
, TRUE
);
112 zone_change(tcq_cl_zone
, Z_CALLERACCT
, TRUE
);
116 tcq_alloc(struct ifnet
*ifp
, int how
)
120 tif
= (how
== M_WAITOK
) ? zalloc(tcq_zone
) : zalloc_noblock(tcq_zone
);
125 bzero(tif
, tcq_size
);
126 tif
->tif_maxpri
= -1;
127 tif
->tif_ifq
= &ifp
->if_snd
;
129 if (pktsched_verbose
) {
130 log(LOG_DEBUG
, "%s: %s scheduler allocated\n",
131 if_name(ifp
), tcq_style(tif
));
138 tcq_destroy(struct tcq_if
*tif
)
140 struct ifclassq
*ifq
= tif
->tif_ifq
;
144 err
= tcq_destroy_locked(tif
);
151 tcq_destroy_locked(struct tcq_if
*tif
)
153 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
155 (void) tcq_clear_interface(tif
);
157 if (pktsched_verbose
) {
158 log(LOG_DEBUG
, "%s: %s scheduler destroyed\n",
159 if_name(TCQIF_IFP(tif
)), tcq_style(tif
));
162 zfree(tcq_zone
, tif
);
168 * bring the interface back to the initial state by discarding
169 * all the filters and classes.
172 tcq_clear_interface(struct tcq_if
*tif
)
174 struct tcq_class
*cl
;
177 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
179 /* clear out the classes */
180 for (pri
= 0; pri
<= tif
->tif_maxpri
; pri
++) {
181 if ((cl
= tif
->tif_classes
[pri
]) != NULL
) {
182 tcq_class_destroy(tif
, cl
);
189 /* discard all the queued packets on the interface */
191 tcq_purge(struct tcq_if
*tif
)
193 struct tcq_class
*cl
;
196 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
198 for (pri
= 0; pri
<= tif
->tif_maxpri
; pri
++) {
199 if ((cl
= tif
->tif_classes
[pri
]) != NULL
&& !qempty(&cl
->cl_q
)) {
200 tcq_purgeq(tif
, cl
, 0, NULL
, NULL
);
203 VERIFY(IFCQ_LEN(tif
->tif_ifq
) == 0);
207 tcq_purge_sc(struct tcq_if
*tif
, cqrq_purge_sc_t
*pr
)
209 struct ifclassq
*ifq
= tif
->tif_ifq
;
212 IFCQ_LOCK_ASSERT_HELD(ifq
);
214 VERIFY(pr
->sc
== MBUF_SC_UNSPEC
|| MBUF_VALID_SC(pr
->sc
));
215 VERIFY(pr
->flow
!= 0);
217 if (pr
->sc
!= MBUF_SC_UNSPEC
) {
218 i
= MBUF_SCIDX(pr
->sc
);
219 VERIFY(i
< IFCQ_SC_MAX
);
221 tcq_purgeq(tif
, ifq
->ifcq_disc_slots
[i
].cl
,
222 pr
->flow
, &pr
->packets
, &pr
->bytes
);
229 for (i
= 0; i
< IFCQ_SC_MAX
; i
++) {
230 tcq_purgeq(tif
, ifq
->ifcq_disc_slots
[i
].cl
,
231 pr
->flow
, &cnt
, &len
);
239 tcq_event(struct tcq_if
*tif
, cqev_t ev
)
241 struct tcq_class
*cl
;
244 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
246 for (pri
= 0; pri
<= tif
->tif_maxpri
; pri
++) {
247 if ((cl
= tif
->tif_classes
[pri
]) != NULL
) {
248 tcq_updateq(tif
, cl
, ev
);
254 tcq_add_queue(struct tcq_if
*tif
, int priority
, u_int32_t qlimit
,
255 int flags
, u_int32_t qid
, struct tcq_class
**clp
, classq_pkt_type_t ptype
)
257 struct tcq_class
*cl
;
259 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
261 /* check parameters */
262 if (priority
>= TCQ_MAXPRI
) {
265 if (tif
->tif_classes
[priority
] != NULL
) {
268 if (tcq_clh_to_clp(tif
, qid
) != NULL
) {
272 cl
= tcq_class_create(tif
, priority
, qlimit
, flags
, qid
, ptype
);
284 static struct tcq_class
*
285 tcq_class_create(struct tcq_if
*tif
, int pri
, u_int32_t qlimit
,
286 int flags
, u_int32_t qid
, classq_pkt_type_t ptype
)
289 struct ifclassq
*ifq
;
290 struct tcq_class
*cl
;
292 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
295 ifp
= TCQIF_IFP(tif
);
297 if ((cl
= tif
->tif_classes
[pri
]) != NULL
) {
298 /* modify the class instead of creating a new one */
299 if (!qempty(&cl
->cl_q
)) {
300 tcq_purgeq(tif
, cl
, 0, NULL
, NULL
);
303 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
304 sfb_destroy(cl
->cl_sfb
);
306 cl
->cl_qalg
.ptr
= NULL
;
307 qtype(&cl
->cl_q
) = Q_DROPTAIL
;
308 qstate(&cl
->cl_q
) = QS_RUNNING
;
309 VERIFY(qptype(&cl
->cl_q
) == ptype
);
311 cl
= zalloc(tcq_cl_zone
);
316 bzero(cl
, tcq_cl_size
);
319 tif
->tif_classes
[pri
] = cl
;
320 if (flags
& TQCF_DEFAULTCLASS
) {
321 tif
->tif_default
= cl
;
323 if (qlimit
== 0 || qlimit
> IFCQ_MAXLEN(ifq
)) {
324 qlimit
= IFCQ_MAXLEN(ifq
);
326 qlimit
= DEFAULT_QLIMIT
; /* use default */
329 _qinit(&cl
->cl_q
, Q_DROPTAIL
, qlimit
, ptype
);
330 cl
->cl_flags
= flags
;
332 if (pri
> tif
->tif_maxpri
) {
333 tif
->tif_maxpri
= pri
;
338 if (flags
& TQCF_SFB
) {
340 if (flags
& TQCF_ECN
) {
341 cl
->cl_qflags
|= SFBF_ECN
;
343 if (flags
& TQCF_FLOWCTL
) {
344 cl
->cl_qflags
|= SFBF_FLOWCTL
;
346 if (flags
& TQCF_DELAYBASED
) {
347 cl
->cl_qflags
|= SFBF_DELAYBASED
;
349 if (!(cl
->cl_flags
& TQCF_LAZY
)) {
350 cl
->cl_sfb
= sfb_alloc(ifp
, cl
->cl_handle
,
351 qlimit(&cl
->cl_q
), cl
->cl_qflags
);
353 if (cl
->cl_sfb
!= NULL
|| (cl
->cl_flags
& TQCF_LAZY
)) {
354 qtype(&cl
->cl_q
) = Q_SFB
;
358 if (pktsched_verbose
) {
359 log(LOG_DEBUG
, "%s: %s created qid=%d pri=%d qlimit=%d "
360 "flags=%b\n", if_name(ifp
), tcq_style(tif
),
361 cl
->cl_handle
, cl
->cl_pri
, qlimit
, flags
, TQCF_BITS
);
368 tcq_remove_queue(struct tcq_if
*tif
, u_int32_t qid
)
370 struct tcq_class
*cl
;
372 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
374 if ((cl
= tcq_clh_to_clp(tif
, qid
)) == NULL
) {
378 return tcq_class_destroy(tif
, cl
);
382 tcq_class_destroy(struct tcq_if
*tif
, struct tcq_class
*cl
)
384 struct ifclassq
*ifq
= tif
->tif_ifq
;
389 IFCQ_LOCK_ASSERT_HELD(ifq
);
391 if (!qempty(&cl
->cl_q
)) {
392 tcq_purgeq(tif
, cl
, 0, NULL
, NULL
);
395 tif
->tif_classes
[cl
->cl_pri
] = NULL
;
396 if (tif
->tif_maxpri
== cl
->cl_pri
) {
397 for (pri
= cl
->cl_pri
; pri
>= 0; pri
--) {
398 if (tif
->tif_classes
[pri
] != NULL
) {
399 tif
->tif_maxpri
= pri
;
404 tif
->tif_maxpri
= -1;
408 if (tif
->tif_default
== cl
) {
409 tif
->tif_default
= NULL
;
412 if (cl
->cl_qalg
.ptr
!= NULL
) {
413 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
414 sfb_destroy(cl
->cl_sfb
);
416 cl
->cl_qalg
.ptr
= NULL
;
417 qtype(&cl
->cl_q
) = Q_DROPTAIL
;
418 qstate(&cl
->cl_q
) = QS_RUNNING
;
421 if (pktsched_verbose
) {
422 log(LOG_DEBUG
, "%s: %s destroyed qid=%d pri=%d\n",
423 if_name(TCQIF_IFP(tif
)), tcq_style(tif
),
424 cl
->cl_handle
, cl
->cl_pri
);
427 zfree(tcq_cl_zone
, cl
);
432 tcq_enqueue(struct tcq_if
*tif
, struct tcq_class
*cl
, pktsched_pkt_t
*pkt
,
435 struct ifclassq
*ifq
= tif
->tif_ifq
;
438 IFCQ_LOCK_ASSERT_HELD(ifq
);
439 VERIFY(cl
== NULL
|| cl
->cl_tif
== tif
);
442 cl
= tcq_clh_to_clp(tif
, 0);
444 cl
= tif
->tif_default
;
446 IFCQ_CONVERT_LOCK(ifq
);
447 return CLASSQEQ_DROP
;
452 VERIFY(pkt
->pktsched_ptype
== qptype(&cl
->cl_q
));
453 len
= pktsched_get_pkt_len(pkt
);
455 ret
= tcq_addq(cl
, pkt
, t
);
456 if ((ret
!= 0) && (ret
!= CLASSQEQ_SUCCESS_FC
)) {
457 VERIFY(ret
== CLASSQEQ_DROP
||
458 ret
== CLASSQEQ_DROP_FC
||
459 ret
== CLASSQEQ_DROP_SP
);
460 PKTCNTR_ADD(&cl
->cl_dropcnt
, 1, len
);
461 IFCQ_DROP_ADD(ifq
, 1, len
);
465 IFCQ_INC_BYTES(ifq
, len
);
467 /* successfully queued. */
472 * note: CLASSQDQ_POLL returns the next packet without removing the packet
473 * from the queue. CLASSQDQ_REMOVE is a normal dequeue operation.
474 * CLASSQDQ_REMOVE must return the same packet if called immediately
475 * after CLASSQDQ_POLL.
478 tcq_dequeue_tc(struct tcq_if
*tif
, mbuf_svc_class_t sc
, pktsched_pkt_t
*pkt
)
480 tcq_dequeue_cl(tif
, NULL
, sc
, pkt
);
484 tcq_dequeue_cl(struct tcq_if
*tif
, struct tcq_class
*cl
, mbuf_svc_class_t sc
,
487 struct ifclassq
*ifq
= tif
->tif_ifq
;
490 IFCQ_LOCK_ASSERT_HELD(ifq
);
491 pkt
->pktsched_pkt_mbuf
= NULL
;
494 cl
= tcq_clh_to_clp(tif
, MBUF_SCIDX(sc
));
500 if (qempty(&cl
->cl_q
)) {
504 VERIFY(!IFCQ_IS_EMPTY(ifq
));
507 if (pkt
->pktsched_pkt_mbuf
!= NULL
) {
508 len
= pktsched_get_pkt_len(pkt
);
510 IFCQ_DEC_BYTES(ifq
, len
);
511 if (qempty(&cl
->cl_q
)) {
514 PKTCNTR_ADD(&cl
->cl_xmitcnt
, 1, len
);
515 IFCQ_XMIT_ADD(ifq
, 1, len
);
520 tcq_addq(struct tcq_class
*cl
, pktsched_pkt_t
*pkt
, struct pf_mtag
*t
)
522 struct tcq_if
*tif
= cl
->cl_tif
;
523 struct ifclassq
*ifq
= tif
->tif_ifq
;
525 IFCQ_LOCK_ASSERT_HELD(ifq
);
527 if (q_is_sfb(&cl
->cl_q
)) {
528 if (cl
->cl_sfb
== NULL
) {
529 struct ifnet
*ifp
= TCQIF_IFP(tif
);
531 VERIFY(cl
->cl_flags
& TQCF_LAZY
);
532 cl
->cl_flags
&= ~TQCF_LAZY
;
533 IFCQ_CONVERT_LOCK(ifq
);
535 cl
->cl_sfb
= sfb_alloc(ifp
, cl
->cl_handle
,
536 qlimit(&cl
->cl_q
), cl
->cl_qflags
);
537 if (cl
->cl_sfb
== NULL
) {
538 /* fall back to droptail */
539 qtype(&cl
->cl_q
) = Q_DROPTAIL
;
540 cl
->cl_flags
&= ~TQCF_SFB
;
541 cl
->cl_qflags
&= ~(SFBF_ECN
| SFBF_FLOWCTL
);
543 log(LOG_ERR
, "%s: %s SFB lazy allocation "
544 "failed for qid=%d pri=%d, falling back "
545 "to DROPTAIL\n", if_name(ifp
),
546 tcq_style(tif
), cl
->cl_handle
,
548 } else if (tif
->tif_throttle
!= IFNET_THROTTLE_OFF
) {
549 /* if there's pending throttling, set it */
550 cqrq_throttle_t tr
= { 1, tif
->tif_throttle
};
551 int err
= tcq_throttle(tif
, &tr
);
553 if (err
== EALREADY
) {
557 tr
.level
= IFNET_THROTTLE_OFF
;
558 (void) tcq_throttle(tif
, &tr
);
562 if (cl
->cl_sfb
!= NULL
) {
563 return sfb_addq(cl
->cl_sfb
, &cl
->cl_q
, pkt
, t
);
565 } else if (qlen(&cl
->cl_q
) >= qlimit(&cl
->cl_q
)) {
566 IFCQ_CONVERT_LOCK(ifq
);
567 return CLASSQEQ_DROP
;
571 if (cl
->cl_flags
& TQCF_CLEARDSCP
) {
572 /* not supported for non-BSD stack packets */
573 VERIFY(pkt
->pktsched_ptype
== QP_MBUF
);
575 write_dsfield(m
, t
, 0);
578 VERIFY(pkt
->pktsched_ptype
== qptype(&cl
->cl_q
));
579 _addq(&cl
->cl_q
, &pkt
->pktsched_pkt
);
585 tcq_getq(struct tcq_class
*cl
, pktsched_pkt_t
*pkt
)
587 classq_pkt_t p
= CLASSQ_PKT_INITIALIZER(p
);
589 IFCQ_LOCK_ASSERT_HELD(cl
->cl_tif
->tif_ifq
);
591 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
592 return sfb_getq(cl
->cl_sfb
, &cl
->cl_q
, pkt
);
595 _getq(&cl
->cl_q
, &p
);
596 return pktsched_pkt_encap(pkt
, &p
);
600 tcq_purgeq(struct tcq_if
*tif
, struct tcq_class
*cl
, u_int32_t flow
,
601 u_int32_t
*packets
, u_int32_t
*bytes
)
603 struct ifclassq
*ifq
= tif
->tif_ifq
;
604 u_int32_t cnt
= 0, len
= 0, qlen
;
606 IFCQ_LOCK_ASSERT_HELD(ifq
);
608 if ((qlen
= qlen(&cl
->cl_q
)) == 0) {
612 IFCQ_CONVERT_LOCK(ifq
);
613 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
614 sfb_purgeq(cl
->cl_sfb
, &cl
->cl_q
, flow
, &cnt
, &len
);
616 _flushq_flow(&cl
->cl_q
, flow
, &cnt
, &len
);
620 VERIFY(qlen(&cl
->cl_q
) == (qlen
- cnt
));
622 PKTCNTR_ADD(&cl
->cl_dropcnt
, cnt
, len
);
623 IFCQ_DROP_ADD(ifq
, cnt
, len
);
625 VERIFY(((signed)IFCQ_LEN(ifq
) - cnt
) >= 0);
626 IFCQ_LEN(ifq
) -= cnt
;
628 if (pktsched_verbose
) {
629 log(LOG_DEBUG
, "%s: %s purge qid=%d pri=%d "
630 "qlen=[%d,%d] cnt=%d len=%d flow=0x%x\n",
631 if_name(TCQIF_IFP(tif
)), tcq_style(tif
),
632 cl
->cl_handle
, cl
->cl_pri
, qlen
, qlen(&cl
->cl_q
),
637 if (packets
!= NULL
) {
646 tcq_updateq(struct tcq_if
*tif
, struct tcq_class
*cl
, cqev_t ev
)
648 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
650 if (pktsched_verbose
) {
651 log(LOG_DEBUG
, "%s: %s update qid=%d pri=%d event=%s\n",
652 if_name(TCQIF_IFP(tif
)), tcq_style(tif
),
653 cl
->cl_handle
, cl
->cl_pri
, ifclassq_ev2str(ev
));
656 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
657 return sfb_updateq(cl
->cl_sfb
, ev
);
662 tcq_get_class_stats(struct tcq_if
*tif
, u_int32_t qid
,
663 struct tcq_classstats
*sp
)
665 struct tcq_class
*cl
;
667 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
669 if ((cl
= tcq_clh_to_clp(tif
, qid
)) == NULL
) {
673 sp
->class_handle
= cl
->cl_handle
;
674 sp
->priority
= cl
->cl_pri
;
675 sp
->qlength
= qlen(&cl
->cl_q
);
676 sp
->qlimit
= qlimit(&cl
->cl_q
);
677 sp
->period
= cl
->cl_period
;
678 sp
->xmitcnt
= cl
->cl_xmitcnt
;
679 sp
->dropcnt
= cl
->cl_dropcnt
;
681 sp
->qtype
= qtype(&cl
->cl_q
);
682 sp
->qstate
= qstate(&cl
->cl_q
);
684 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
685 sfb_getstats(cl
->cl_sfb
, &sp
->sfb
);
692 tcq_stat_sc(struct tcq_if
*tif
, cqrq_stat_sc_t
*sr
)
694 struct ifclassq
*ifq
= tif
->tif_ifq
;
695 struct tcq_class
*cl
;
698 IFCQ_LOCK_ASSERT_HELD(ifq
);
700 VERIFY(sr
->sc
== MBUF_SC_UNSPEC
|| MBUF_VALID_SC(sr
->sc
));
702 i
= MBUF_SCIDX(sr
->sc
);
703 VERIFY(i
< IFCQ_SC_MAX
);
705 cl
= ifq
->ifcq_disc_slots
[i
].cl
;
706 sr
->packets
= qlen(&cl
->cl_q
);
707 sr
->bytes
= qsize(&cl
->cl_q
);
712 /* convert a class handle to the corresponding class pointer */
713 static inline struct tcq_class
*
714 tcq_clh_to_clp(struct tcq_if
*tif
, u_int32_t chandle
)
716 struct tcq_class
*cl
;
719 IFCQ_LOCK_ASSERT_HELD(tif
->tif_ifq
);
721 for (idx
= tif
->tif_maxpri
; idx
>= 0; idx
--) {
722 if ((cl
= tif
->tif_classes
[idx
]) != NULL
&&
723 cl
->cl_handle
== chandle
) {
732 tcq_style(struct tcq_if
*tif
)
739 * tcq_enqueue_ifclassq is an enqueue function to be registered to
740 * (*ifcq_enqueue) in struct ifclassq.
743 tcq_enqueue_ifclassq(struct ifclassq
*ifq
, classq_pkt_t
*p
, boolean_t
*pdrop
)
748 struct pf_mtag
*t
= NULL
;
750 IFCQ_LOCK_ASSERT_HELD(ifq
);
752 if (p
->cp_ptype
== QP_MBUF
) {
753 struct mbuf
*m
= p
->cp_mbuf
;
754 if (!(m
->m_flags
& M_PKTHDR
)) {
755 /* should not happen */
756 log(LOG_ERR
, "%s: packet does not have pkthdr\n",
757 if_name(ifq
->ifcq_ifp
));
758 IFCQ_CONVERT_LOCK(ifq
);
760 *p
= CLASSQ_PKT_INITIALIZER(*p
);
765 i
= MBUF_SCIDX(mbuf_get_service_class(m
));
767 VERIFY((u_int32_t
)i
< IFCQ_SC_MAX
);
769 pktsched_pkt_encap(&pkt
, p
);
771 ret
= tcq_enqueue(ifq
->ifcq_disc
,
772 ifq
->ifcq_disc_slots
[i
].cl
, &pkt
, t
);
774 if ((ret
!= 0) && (ret
!= CLASSQEQ_SUCCESS_FC
)) {
775 pktsched_free_pkt(&pkt
);
785 case CLASSQEQ_DROP_FC
:
788 case CLASSQEQ_DROP_SP
:
791 case CLASSQEQ_SUCCESS_FC
:
794 case CLASSQEQ_SUCCESS
:
799 __builtin_unreachable();
805 * tcq_dequeue_tc_ifclassq is a dequeue function to be registered to
806 * (*ifcq_dequeue) in struct ifclass.
808 * note: CLASSQDQ_POLL returns the next packet without removing the packet
809 * from the queue. CLASSQDQ_REMOVE is a normal dequeue operation.
810 * CLASSQDQ_REMOVE must return the same packet if called immediately
811 * after CLASSQDQ_POLL.
814 tcq_dequeue_tc_ifclassq(struct ifclassq
*ifq
, mbuf_svc_class_t sc
,
818 u_int32_t i
= MBUF_SCIDX(sc
);
820 VERIFY((u_int32_t
)i
< IFCQ_SC_MAX
);
822 _PKTSCHED_PKT_INIT(&pkt
);
823 (tcq_dequeue_cl(ifq
->ifcq_disc
, ifq
->ifcq_disc_slots
[i
].cl
, sc
, &pkt
));
824 *cpkt
= pkt
.pktsched_pkt
;
828 tcq_request_ifclassq(struct ifclassq
*ifq
, cqrq_t req
, void *arg
)
830 struct tcq_if
*tif
= (struct tcq_if
*)ifq
->ifcq_disc
;
833 IFCQ_LOCK_ASSERT_HELD(ifq
);
840 case CLASSQRQ_PURGE_SC
:
841 tcq_purge_sc(tif
, (cqrq_purge_sc_t
*)arg
);
845 tcq_event(tif
, (cqev_t
)arg
);
848 case CLASSQRQ_THROTTLE
:
849 err
= tcq_throttle(tif
, (cqrq_throttle_t
*)arg
);
852 case CLASSQRQ_STAT_SC
:
853 err
= tcq_stat_sc(tif
, (cqrq_stat_sc_t
*)arg
);
860 tcq_setup_ifclassq(struct ifclassq
*ifq
, u_int32_t flags
,
861 classq_pkt_type_t ptype
)
863 struct ifnet
*ifp
= ifq
->ifcq_ifp
;
864 struct tcq_class
*cl0
, *cl1
, *cl2
, *cl3
;
866 u_int32_t maxlen
= 0, qflags
= 0;
869 IFCQ_LOCK_ASSERT_HELD(ifq
);
870 VERIFY(ifq
->ifcq_disc
== NULL
);
871 VERIFY(ifq
->ifcq_type
== PKTSCHEDT_NONE
);
873 if (flags
& PKTSCHEDF_QALG_SFB
) {
876 if (flags
& PKTSCHEDF_QALG_ECN
) {
879 if (flags
& PKTSCHEDF_QALG_FLOWCTL
) {
880 qflags
|= TQCF_FLOWCTL
;
882 if (flags
& PKTSCHEDF_QALG_DELAYBASED
) {
883 qflags
|= TQCF_DELAYBASED
;
886 tif
= tcq_alloc(ifp
, M_WAITOK
);
891 if ((maxlen
= IFCQ_MAXLEN(ifq
)) == 0) {
892 maxlen
= if_sndq_maxlen
;
895 if ((err
= tcq_add_queue(tif
, 0, maxlen
,
896 qflags
| TQCF_LAZY
, SCIDX_BK
, &cl0
, ptype
)) != 0) {
900 if ((err
= tcq_add_queue(tif
, 1, maxlen
,
901 qflags
| TQCF_DEFAULTCLASS
, SCIDX_BE
, &cl1
, ptype
)) != 0) {
905 if ((err
= tcq_add_queue(tif
, 2, maxlen
,
906 qflags
| TQCF_LAZY
, SCIDX_VI
, &cl2
, ptype
)) != 0) {
910 if ((err
= tcq_add_queue(tif
, 3, maxlen
,
911 qflags
, SCIDX_VO
, &cl3
, ptype
)) != 0) {
915 err
= ifclassq_attach(ifq
, PKTSCHEDT_TCQ
, tif
,
916 tcq_enqueue_ifclassq
, NULL
, tcq_dequeue_tc_ifclassq
,
917 NULL
, NULL
, tcq_request_ifclassq
);
919 /* cache these for faster lookup */
921 /* Map {BK_SYS,BK} to TC_BK */
922 ifq
->ifcq_disc_slots
[SCIDX_BK_SYS
].qid
= SCIDX_BK
;
923 ifq
->ifcq_disc_slots
[SCIDX_BK_SYS
].cl
= cl0
;
925 ifq
->ifcq_disc_slots
[SCIDX_BK
].qid
= SCIDX_BK
;
926 ifq
->ifcq_disc_slots
[SCIDX_BK
].cl
= cl0
;
928 /* Map {BE,RD,OAM} to TC_BE */
929 ifq
->ifcq_disc_slots
[SCIDX_BE
].qid
= SCIDX_BE
;
930 ifq
->ifcq_disc_slots
[SCIDX_BE
].cl
= cl1
;
932 ifq
->ifcq_disc_slots
[SCIDX_RD
].qid
= SCIDX_BE
;
933 ifq
->ifcq_disc_slots
[SCIDX_RD
].cl
= cl1
;
935 ifq
->ifcq_disc_slots
[SCIDX_OAM
].qid
= SCIDX_BE
;
936 ifq
->ifcq_disc_slots
[SCIDX_OAM
].cl
= cl1
;
938 /* Map {AV,RV,VI} to TC_VI */
939 ifq
->ifcq_disc_slots
[SCIDX_AV
].qid
= SCIDX_VI
;
940 ifq
->ifcq_disc_slots
[SCIDX_AV
].cl
= cl2
;
942 ifq
->ifcq_disc_slots
[SCIDX_RV
].qid
= SCIDX_VI
;
943 ifq
->ifcq_disc_slots
[SCIDX_RV
].cl
= cl2
;
945 ifq
->ifcq_disc_slots
[SCIDX_VI
].qid
= SCIDX_VI
;
946 ifq
->ifcq_disc_slots
[SCIDX_VI
].cl
= cl2
;
948 /* Map {VO,CTL} to TC_VO */
949 ifq
->ifcq_disc_slots
[SCIDX_VO
].qid
= SCIDX_VO
;
950 ifq
->ifcq_disc_slots
[SCIDX_VO
].cl
= cl3
;
952 ifq
->ifcq_disc_slots
[SCIDX_CTL
].qid
= SCIDX_VO
;
953 ifq
->ifcq_disc_slots
[SCIDX_CTL
].cl
= cl3
;
958 (void) tcq_destroy_locked(tif
);
965 tcq_teardown_ifclassq(struct ifclassq
*ifq
)
967 struct tcq_if
*tif
= ifq
->ifcq_disc
;
970 IFCQ_LOCK_ASSERT_HELD(ifq
);
971 VERIFY(tif
!= NULL
&& ifq
->ifcq_type
== PKTSCHEDT_TCQ
);
973 (void) tcq_destroy_locked(tif
);
975 ifq
->ifcq_disc
= NULL
;
976 for (i
= 0; i
< IFCQ_SC_MAX
; i
++) {
977 ifq
->ifcq_disc_slots
[i
].qid
= 0;
978 ifq
->ifcq_disc_slots
[i
].cl
= NULL
;
981 return ifclassq_detach(ifq
);
985 tcq_getqstats_ifclassq(struct ifclassq
*ifq
, u_int32_t slot
,
986 struct if_ifclassq_stats
*ifqs
)
988 struct tcq_if
*tif
= ifq
->ifcq_disc
;
990 IFCQ_LOCK_ASSERT_HELD(ifq
);
991 VERIFY(ifq
->ifcq_type
== PKTSCHEDT_TCQ
);
993 if (slot
>= IFCQ_SC_MAX
) {
997 return tcq_get_class_stats(tif
, ifq
->ifcq_disc_slots
[slot
].qid
,
998 &ifqs
->ifqs_tcq_stats
);
1002 tcq_throttle(struct tcq_if
*tif
, cqrq_throttle_t
*tr
)
1004 struct ifclassq
*ifq
= tif
->tif_ifq
;
1005 struct tcq_class
*cl
;
1008 IFCQ_LOCK_ASSERT_HELD(ifq
);
1011 tr
->level
= tif
->tif_throttle
;
1015 if (tr
->level
== tif
->tif_throttle
) {
1019 /* Current throttling levels only involve BK_SYS class */
1020 cl
= ifq
->ifcq_disc_slots
[SCIDX_BK_SYS
].cl
;
1022 switch (tr
->level
) {
1023 case IFNET_THROTTLE_OFF
:
1024 err
= tcq_resumeq(tif
, cl
);
1027 case IFNET_THROTTLE_OPPORTUNISTIC
:
1028 err
= tcq_suspendq(tif
, cl
);
1036 if (err
== 0 || err
== ENXIO
) {
1037 if (pktsched_verbose
) {
1038 log(LOG_DEBUG
, "%s: %s throttling %slevel set %d->%d\n",
1039 if_name(TCQIF_IFP(tif
)), tcq_style(tif
),
1040 (err
== 0) ? "" : "lazy ", tif
->tif_throttle
,
1043 tif
->tif_throttle
= tr
->level
;
1047 tcq_purgeq(tif
, cl
, 0, NULL
, NULL
);
1050 log(LOG_ERR
, "%s: %s unable to set throttling level "
1051 "%d->%d [error=%d]\n", if_name(TCQIF_IFP(tif
)),
1052 tcq_style(tif
), tif
->tif_throttle
, tr
->level
, err
);
1059 tcq_resumeq(struct tcq_if
*tif
, struct tcq_class
*cl
)
1061 struct ifclassq
*ifq
= tif
->tif_ifq
;
1066 IFCQ_LOCK_ASSERT_HELD(ifq
);
1068 if (q_is_sfb(&cl
->cl_q
) && cl
->cl_sfb
!= NULL
) {
1069 err
= sfb_suspendq(cl
->cl_sfb
, &cl
->cl_q
, FALSE
);
1073 qstate(&cl
->cl_q
) = QS_RUNNING
;
1080 tcq_suspendq(struct tcq_if
*tif
, struct tcq_class
*cl
)
1082 struct ifclassq
*ifq
= tif
->tif_ifq
;
1087 IFCQ_LOCK_ASSERT_HELD(ifq
);
1089 if (q_is_sfb(&cl
->cl_q
)) {
1090 if (cl
->cl_sfb
!= NULL
) {
1091 err
= sfb_suspendq(cl
->cl_sfb
, &cl
->cl_q
, TRUE
);
1093 VERIFY(cl
->cl_flags
& TQCF_LAZY
);
1094 err
= ENXIO
; /* delayed throttling */
1098 if (err
== 0 || err
== ENXIO
) {
1099 qstate(&cl
->cl_q
) = QS_SUSPENDED
;