]>
git.saurik.com Git - apple/xnu.git/blob - bsd/net/classq/classq.c
2 * Copyright (c) 2007-2019 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@
30 * Copyright (c) 1991-1997 Regents of the University of California.
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the Network Research
44 * Group at Lawrence Berkeley Laboratory.
45 * 4. Neither the name of the University nor of the Laboratory may be used
46 * to endorse or promote products derived from this software without
47 * specific prior written permission.
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62 #include <sys/cdefs.h>
63 #include <sys/param.h>
65 #include <sys/errno.h>
66 #include <sys/random.h>
67 #include <sys/kernel_types.h>
68 #include <sys/sysctl.h>
71 #include <net/net_osdep.h>
72 #include <net/classq/classq.h>
74 #include <libkern/libkern.h>
77 u_int32_t classq_verbose
= 0; /* more noise if greater than 1 */
79 SYSCTL_NODE(_net
, OID_AUTO
, classq
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0, "classq");
81 SYSCTL_UINT(_net_classq
, OID_AUTO
, verbose
, CTLFLAG_RW
| CTLFLAG_LOCKED
,
82 &classq_verbose
, 0, "Class queue verbosity level");
85 _qinit(class_queue_t
*q
, int type
, int lim
, classq_pkt_type_t ptype
)
89 MBUFQ_INIT(&qmbufq(q
));
103 qstate(q
) = QS_RUNNING
;
106 /* add a packet at the tail of the queue */
108 _addq(class_queue_t
*q
, classq_pkt_t
*pkt
)
112 ASSERT(pkt
->cp_ptype
== qptype(q
));
116 struct mbuf
*m
= pkt
->cp_mbuf
;
117 MBUFQ_ENQUEUE(&qmbufq(q
), m
);
126 __builtin_unreachable();
130 VERIFY(qlen(q
) != 0);
134 /* add one or more packets at the tail of the queue */
136 _addq_multi(class_queue_t
*q
, classq_pkt_t
*pkt_head
, classq_pkt_t
*pkt_tail
,
137 u_int32_t cnt
, u_int32_t size
)
139 ASSERT(pkt_head
->cp_ptype
== qptype(q
));
140 ASSERT(pkt_tail
->cp_ptype
== qptype(q
));
143 struct mbuf
*m_head
= pkt_head
->cp_mbuf
;
144 struct mbuf
*m_tail
= pkt_tail
->cp_mbuf
;
145 MBUFQ_ENQUEUE_MULTI(&qmbufq(q
), m_head
, m_tail
);
153 __builtin_unreachable();
160 /* get a packet at the head of the queue */
162 _getq(class_queue_t
*q
, classq_pkt_t
*pkt
)
168 MBUFQ_DEQUEUE(&qmbufq(q
), pkt
->cp_mbuf
);
169 if (__probable(pkt
->cp_mbuf
!= NULL
)) {
170 CLASSQ_PKT_INIT_MBUF(pkt
, pkt
->cp_mbuf
);
171 pkt_len
= m_length(pkt
->cp_mbuf
);
180 __builtin_unreachable();
183 if (pkt
->cp_mbuf
== NULL
) {
184 VERIFY(qlen(q
) == 0);
193 /* qsize is an approximation, so adjust if necessary */
194 if (((int)qsize(q
) - pkt_len
) > 0) {
196 } else if (qsize(q
) != 0) {
202 _getq_flow_or_scidx(class_queue_t
*q
, classq_pkt_t
*pkt
, u_int32_t val
,
209 struct mbuf
*m
, *m_tmp
;
211 MBUFQ_FOREACH_SAFE(m
, &qmbufq(q
), m_tmp
) {
212 if ((isflowid
&& (val
== 0 ||
213 ((m
->m_flags
& M_PKTHDR
) &&
214 m
->m_pkthdr
.pkt_flowid
== val
))) ||
216 MBUF_SCIDX(mbuf_get_service_class(m
)) < val
)) {
217 /* remove it from the class queue */
218 MBUFQ_REMOVE(&qmbufq(q
), m
);
219 MBUFQ_NEXT(m
) = NULL
;
223 if (__probable(m
!= NULL
)) {
224 CLASSQ_PKT_INIT_MBUF(pkt
, m
);
225 pkt_len
= m_length(m
);
234 __builtin_unreachable();
237 if (pkt
->cp_mbuf
!= NULL
) {
241 /* qsize is an approximation, so adjust if necessary */
242 if (((int)qsize(q
) - pkt_len
) > 0) {
244 } else if (qsize(q
) != 0) {
250 /* get a packet of a specific flow beginning from the head of the queue */
252 _getq_flow(class_queue_t
*q
, classq_pkt_t
*pkt
, u_int32_t flow
)
254 return _getq_flow_or_scidx(q
, pkt
, flow
, TRUE
);
257 /* Get a packet whose MBUF_SCIDX() < scidx from head of queue */
259 _getq_scidx_lt(class_queue_t
*q
, classq_pkt_t
*pkt
, u_int32_t scidx
)
261 return _getq_flow_or_scidx(q
, pkt
, scidx
, FALSE
);
264 /* get all packets (chained) starting from the head of the queue */
266 _getq_all(class_queue_t
*q
, classq_pkt_t
*first
, classq_pkt_t
*last
,
267 u_int32_t
*qlenp
, u_int64_t
*qsizep
)
271 first
->cp_mbuf
= MBUFQ_FIRST(&qmbufq(q
));
272 if (__probable(first
->cp_mbuf
!= NULL
)) {
273 CLASSQ_PKT_INIT_MBUF(first
, first
->cp_mbuf
);
276 last
->cp_mbuf
= MBUFQ_LAST(&qmbufq(q
));
277 if (__probable(last
->cp_mbuf
!= NULL
)) {
278 CLASSQ_PKT_INIT_MBUF(last
, last
->cp_mbuf
);
281 MBUFQ_INIT(&qmbufq(q
));
288 __builtin_unreachable();
294 if (qsizep
!= NULL
) {
302 static inline struct mbuf
*
303 _getq_tail_mbuf(class_queue_t
*q
)
305 struct mq_head
*head
= &qmbufq(q
);
306 struct mbuf
*m
= MBUFQ_LAST(head
);
309 struct mbuf
*n
= MBUFQ_FIRST(head
);
312 struct mbuf
*next
= MBUFQ_NEXT(n
);
314 MBUFQ_NEXT(n
) = NULL
;
320 (qlen(q
) == 1 && m
== MBUFQ_FIRST(head
)));
324 /* qsize is an approximation, so adjust if necessary */
325 if (((int)qsize(q
) - m_length(m
)) > 0) {
326 qsize(q
) -= m_length(m
);
327 } else if (qsize(q
) != 0) {
332 VERIFY(m
== MBUFQ_FIRST(head
));
336 head
->mq_last
= &MBUFQ_NEXT(n
);
342 /* drop a packet at the tail of the queue */
344 _getq_tail(class_queue_t
*q
, classq_pkt_t
*pkt
)
348 pkt
->cp_mbuf
= _getq_tail_mbuf(q
);
349 if (__probable(pkt
->cp_mbuf
!= NULL
)) {
350 CLASSQ_PKT_INIT_MBUF(pkt
, pkt
->cp_mbuf
);
357 __builtin_unreachable();
361 static inline struct mbuf
*
362 _getq_random_mbuf(class_queue_t
*q
)
364 struct mq_head
*head
= &qmbufq(q
);
365 struct mbuf
*m
= NULL
;
369 /* XXX: Add support for Kernel packet when needed */
370 VERIFY((qptype(q
) == QP_MBUF
));
374 VERIFY(MBUFQ_EMPTY(head
));
381 m
= MBUFQ_FIRST(head
);
382 read_frandom(&rnd
, sizeof(rnd
));
386 if ((MBUFQ_FIRST(head
) = MBUFQ_NEXT(m
)) == NULL
) {
387 (head
)->mq_last
= &MBUFQ_FIRST(head
);
390 struct mbuf
*p
= NULL
;
394 if (MBUFQ_NEXT(m
) == NULL
) {
400 VERIFY(p
!= NULL
&& MBUFQ_NEXT(p
) == m
);
402 if ((MBUFQ_NEXT(p
) = MBUFQ_NEXT(m
)) == NULL
) {
403 (head
)->mq_last
= &MBUFQ_NEXT(p
);
410 /* qsize is an approximation, so adjust if necessary */
411 if (((int)qsize(q
) - m_length(m
)) > 0) {
412 qsize(q
) -= m_length(m
);
413 } else if (qsize(q
) != 0) {
417 MBUFQ_NEXT(m
) = NULL
;
422 /* randomly select a packet in the queue */
424 _getq_random(class_queue_t
*q
, classq_pkt_t
*pkt
)
428 pkt
->cp_mbuf
= _getq_random_mbuf(q
);
429 if (__probable(pkt
->cp_mbuf
!= NULL
)) {
430 CLASSQ_PKT_INIT_MBUF(pkt
, pkt
->cp_mbuf
);
437 __builtin_unreachable();
442 _removeq_mbuf(class_queue_t
*q
, struct mbuf
*m
)
444 struct mq_head
*head
= &qmbufq(q
);
445 struct mbuf
*m0
, **mtail
;
447 m0
= MBUFQ_FIRST(head
);
453 while (m0
!= NULL
&& MBUFQ_NEXT(m0
) != m
) {
460 mtail
= &MBUFQ_NEXT(m0
);
462 mtail
= &MBUFQ_FIRST(head
);
465 *mtail
= MBUFQ_NEXT(m
);
466 if (*mtail
== NULL
) {
467 head
->mq_last
= mtail
;
473 /* qsize is an approximation, so adjust if necessary */
474 if (((int)qsize(q
) - m_length(m
)) > 0) {
475 qsize(q
) -= m_length(m
);
476 } else if (qsize(q
) != 0) {
480 MBUFQ_NEXT(m
) = NULL
;
483 /* remove a packet from the queue */
485 _removeq(class_queue_t
*q
, classq_pkt_t
*pkt
)
489 ASSERT(pkt
->cp_ptype
== QP_MBUF
);
490 _removeq_mbuf(q
, pkt
->cp_mbuf
);
496 __builtin_unreachable();
501 _flushq(class_queue_t
*q
)
503 (void) _flushq_flow(q
, 0, NULL
, NULL
);
507 _flushq_flow_mbuf(class_queue_t
*q
, u_int32_t flow
, u_int32_t
*cnt
,
510 MBUFQ_HEAD(mq_freeq
) freeq
;
511 struct mbuf
*m
, *m_tmp
;
512 u_int32_t c
= 0, l
= 0;
516 MBUFQ_FOREACH_SAFE(m
, &qmbufq(q
), m_tmp
) {
517 if (flow
== 0 || ((m
->m_flags
& M_PKTHDR
) &&
518 m
->m_pkthdr
.pkt_flowid
== flow
)) {
519 /* remove it from the class queue */
520 MBUFQ_REMOVE(&qmbufq(q
), m
);
521 MBUFQ_NEXT(m
) = NULL
;
523 /* and add it to the free queue */
524 MBUFQ_ENQUEUE(&freeq
, m
);
530 VERIFY(c
== 0 || !MBUFQ_EMPTY(&freeq
));
533 VERIFY(qlen(q
) >= c
);
536 /* qsize is an approximation, so adjust if necessary */
537 if (((int)qsize(q
) - l
) > 0) {
539 } else if (qsize(q
) != 0) {
544 if (!MBUFQ_EMPTY(&freeq
)) {
545 m_freem_list(MBUFQ_FIRST(&freeq
));
558 _flushq_flow(class_queue_t
*q
, u_int32_t flow
, u_int32_t
*cnt
, u_int32_t
*len
)
562 _flushq_flow_mbuf(q
, flow
, cnt
, len
);
568 __builtin_unreachable();