]>
Commit | Line | Data |
---|---|---|
316670eb | 1 | /* |
cb323159 | 2 | * Copyright (c) 2007-2019 Apple Inc. All rights reserved. |
316670eb A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
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. | |
25 | * | |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
27 | */ | |
28 | ||
29 | /* | |
30 | * Copyright (c) 1991-1997 Regents of the University of California. | |
31 | * All rights reserved. | |
32 | * | |
33 | * Redistribution and use in source and binary forms, with or without | |
34 | * modification, are permitted provided that the following conditions | |
35 | * are met: | |
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. | |
48 | * | |
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 | |
59 | * SUCH DAMAGE. | |
60 | */ | |
61 | ||
62 | #include <sys/cdefs.h> | |
63 | #include <sys/param.h> | |
64 | #include <sys/mbuf.h> | |
65 | #include <sys/errno.h> | |
66 | #include <sys/random.h> | |
67 | #include <sys/kernel_types.h> | |
68 | #include <sys/sysctl.h> | |
69 | ||
70 | #include <net/if.h> | |
71 | #include <net/net_osdep.h> | |
72 | #include <net/classq/classq.h> | |
73 | ||
74 | #include <libkern/libkern.h> | |
75 | ||
5ba3f43e | 76 | |
0a7de745 | 77 | u_int32_t classq_verbose = 0; /* more noise if greater than 1 */ |
316670eb | 78 | |
0a7de745 | 79 | SYSCTL_NODE(_net, OID_AUTO, classq, CTLFLAG_RW | CTLFLAG_LOCKED, 0, "classq"); |
316670eb | 80 | |
0a7de745 A |
81 | SYSCTL_UINT(_net_classq, OID_AUTO, verbose, CTLFLAG_RW | CTLFLAG_LOCKED, |
82 | &classq_verbose, 0, "Class queue verbosity level"); | |
316670eb A |
83 | |
84 | void | |
5ba3f43e | 85 | _qinit(class_queue_t *q, int type, int lim, classq_pkt_type_t ptype) |
316670eb | 86 | { |
5ba3f43e A |
87 | switch (ptype) { |
88 | case QP_MBUF: | |
89 | MBUFQ_INIT(&qmbufq(q)); | |
90 | break; | |
91 | ||
92 | ||
93 | default: | |
94 | VERIFY(0); | |
95 | /* NOTREACHED */ | |
96 | } | |
97 | ||
316670eb A |
98 | qlimit(q) = lim; |
99 | qlen(q) = 0; | |
100 | qsize(q) = 0; | |
101 | qtype(q) = type; | |
5ba3f43e | 102 | qptype(q) = ptype; |
316670eb A |
103 | qstate(q) = QS_RUNNING; |
104 | } | |
105 | ||
106 | /* add a packet at the tail of the queue */ | |
107 | void | |
cb323159 | 108 | _addq(class_queue_t *q, classq_pkt_t *pkt) |
316670eb | 109 | { |
5ba3f43e A |
110 | uint32_t size = 0; |
111 | ||
cb323159 A |
112 | ASSERT(pkt->cp_ptype == qptype(q)); |
113 | ||
5ba3f43e A |
114 | switch (qptype(q)) { |
115 | case QP_MBUF: { | |
cb323159 | 116 | struct mbuf *m = pkt->cp_mbuf; |
5ba3f43e A |
117 | MBUFQ_ENQUEUE(&qmbufq(q), m); |
118 | size = m_length(m); | |
119 | break; | |
120 | } | |
121 | ||
122 | ||
123 | default: | |
124 | VERIFY(0); | |
125 | /* NOTREACHED */ | |
cb323159 | 126 | __builtin_unreachable(); |
5ba3f43e A |
127 | } |
128 | ||
316670eb A |
129 | qlen(q)++; |
130 | VERIFY(qlen(q) != 0); | |
5ba3f43e | 131 | qsize(q) += size; |
316670eb A |
132 | } |
133 | ||
134 | /* add one or more packets at the tail of the queue */ | |
135 | void | |
cb323159 | 136 | _addq_multi(class_queue_t *q, classq_pkt_t *pkt_head, classq_pkt_t *pkt_tail, |
316670eb A |
137 | u_int32_t cnt, u_int32_t size) |
138 | { | |
cb323159 A |
139 | ASSERT(pkt_head->cp_ptype == qptype(q)); |
140 | ASSERT(pkt_tail->cp_ptype == qptype(q)); | |
5ba3f43e A |
141 | switch (qptype(q)) { |
142 | case QP_MBUF: { | |
cb323159 A |
143 | struct mbuf *m_head = pkt_head->cp_mbuf; |
144 | struct mbuf *m_tail = pkt_tail->cp_mbuf; | |
5ba3f43e A |
145 | MBUFQ_ENQUEUE_MULTI(&qmbufq(q), m_head, m_tail); |
146 | break; | |
147 | } | |
148 | ||
149 | ||
150 | default: | |
151 | VERIFY(0); | |
152 | /* NOTREACHED */ | |
cb323159 | 153 | __builtin_unreachable(); |
5ba3f43e A |
154 | } |
155 | ||
316670eb A |
156 | qlen(q) += cnt; |
157 | qsize(q) += size; | |
158 | } | |
159 | ||
160 | /* get a packet at the head of the queue */ | |
cb323159 A |
161 | void |
162 | _getq(class_queue_t *q, classq_pkt_t *pkt) | |
316670eb | 163 | { |
5ba3f43e A |
164 | uint32_t pkt_len; |
165 | ||
166 | switch (qptype(q)) { | |
167 | case QP_MBUF: { | |
cb323159 A |
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); | |
5ba3f43e A |
172 | } |
173 | break; | |
174 | } | |
175 | ||
176 | ||
177 | default: | |
178 | VERIFY(0); | |
179 | /* NOTREACHED */ | |
cb323159 | 180 | __builtin_unreachable(); |
5ba3f43e | 181 | } |
316670eb | 182 | |
cb323159 | 183 | if (pkt->cp_mbuf == NULL) { |
316670eb | 184 | VERIFY(qlen(q) == 0); |
0a7de745 | 185 | if (qsize(q) > 0) { |
316670eb | 186 | qsize(q) = 0; |
0a7de745 | 187 | } |
cb323159 | 188 | return; |
316670eb A |
189 | } |
190 | VERIFY(qlen(q) > 0); | |
191 | qlen(q)--; | |
192 | ||
193 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 194 | if (((int)qsize(q) - pkt_len) > 0) { |
5ba3f43e | 195 | qsize(q) -= pkt_len; |
0a7de745 | 196 | } else if (qsize(q) != 0) { |
316670eb | 197 | qsize(q) = 0; |
0a7de745 | 198 | } |
316670eb A |
199 | } |
200 | ||
cb323159 A |
201 | static void |
202 | _getq_flow_or_scidx(class_queue_t *q, classq_pkt_t *pkt, u_int32_t val, | |
203 | boolean_t isflowid) | |
316670eb | 204 | { |
5ba3f43e A |
205 | uint32_t pkt_len; |
206 | ||
207 | switch (qptype(q)) { | |
208 | case QP_MBUF: { | |
209 | struct mbuf *m, *m_tmp; | |
210 | ||
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))) || | |
215 | (!isflowid && | |
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; | |
220 | break; | |
221 | } | |
222 | } | |
cb323159 A |
223 | if (__probable(m != NULL)) { |
224 | CLASSQ_PKT_INIT_MBUF(pkt, m); | |
5ba3f43e | 225 | pkt_len = m_length(m); |
316670eb | 226 | } |
5ba3f43e | 227 | break; |
316670eb A |
228 | } |
229 | ||
316670eb | 230 | |
5ba3f43e A |
231 | default: |
232 | VERIFY(0); | |
233 | /* NOTREACHED */ | |
cb323159 | 234 | __builtin_unreachable(); |
5ba3f43e A |
235 | } |
236 | ||
cb323159 | 237 | if (pkt->cp_mbuf != NULL) { |
316670eb A |
238 | VERIFY(qlen(q) > 0); |
239 | qlen(q)--; | |
240 | ||
241 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 242 | if (((int)qsize(q) - pkt_len) > 0) { |
5ba3f43e | 243 | qsize(q) -= pkt_len; |
0a7de745 | 244 | } else if (qsize(q) != 0) { |
316670eb | 245 | qsize(q) = 0; |
0a7de745 | 246 | } |
316670eb | 247 | } |
39037602 A |
248 | } |
249 | ||
250 | /* get a packet of a specific flow beginning from the head of the queue */ | |
cb323159 A |
251 | void |
252 | _getq_flow(class_queue_t *q, classq_pkt_t *pkt, u_int32_t flow) | |
39037602 | 253 | { |
cb323159 | 254 | return _getq_flow_or_scidx(q, pkt, flow, TRUE); |
39037602 A |
255 | } |
256 | ||
257 | /* Get a packet whose MBUF_SCIDX() < scidx from head of queue */ | |
cb323159 A |
258 | void |
259 | _getq_scidx_lt(class_queue_t *q, classq_pkt_t *pkt, u_int32_t scidx) | |
39037602 | 260 | { |
cb323159 | 261 | return _getq_flow_or_scidx(q, pkt, scidx, FALSE); |
316670eb A |
262 | } |
263 | ||
5ba3f43e | 264 | /* get all packets (chained) starting from the head of the queue */ |
cb323159 A |
265 | void |
266 | _getq_all(class_queue_t *q, classq_pkt_t *first, classq_pkt_t *last, | |
267 | u_int32_t *qlenp, u_int64_t *qsizep) | |
316670eb | 268 | { |
5ba3f43e A |
269 | switch (qptype(q)) { |
270 | case QP_MBUF: | |
cb323159 A |
271 | first->cp_mbuf = MBUFQ_FIRST(&qmbufq(q)); |
272 | if (__probable(first->cp_mbuf != NULL)) { | |
273 | CLASSQ_PKT_INIT_MBUF(first, first->cp_mbuf); | |
274 | } | |
0a7de745 | 275 | if (last != NULL) { |
cb323159 A |
276 | last->cp_mbuf = MBUFQ_LAST(&qmbufq(q)); |
277 | if (__probable(last->cp_mbuf != NULL)) { | |
278 | CLASSQ_PKT_INIT_MBUF(last, last->cp_mbuf); | |
279 | } | |
0a7de745 | 280 | } |
5ba3f43e A |
281 | MBUFQ_INIT(&qmbufq(q)); |
282 | break; | |
316670eb | 283 | |
5ba3f43e A |
284 | |
285 | default: | |
286 | VERIFY(0); | |
287 | /* NOTREACHED */ | |
cb323159 | 288 | __builtin_unreachable(); |
5ba3f43e | 289 | } |
39037602 | 290 | |
0a7de745 | 291 | if (qlenp != NULL) { |
39037602 | 292 | *qlenp = qlen(q); |
0a7de745 A |
293 | } |
294 | if (qsizep != NULL) { | |
39037602 | 295 | *qsizep = qsize(q); |
0a7de745 | 296 | } |
39037602 | 297 | |
316670eb A |
298 | qlen(q) = 0; |
299 | qsize(q) = 0; | |
316670eb A |
300 | } |
301 | ||
5ba3f43e A |
302 | static inline struct mbuf * |
303 | _getq_tail_mbuf(class_queue_t *q) | |
316670eb | 304 | { |
5ba3f43e | 305 | struct mq_head *head = &qmbufq(q); |
316670eb A |
306 | struct mbuf *m = MBUFQ_LAST(head); |
307 | ||
308 | if (m != NULL) { | |
309 | struct mbuf *n = MBUFQ_FIRST(head); | |
310 | ||
311 | while (n != NULL) { | |
312 | struct mbuf *next = MBUFQ_NEXT(n); | |
313 | if (next == m) { | |
314 | MBUFQ_NEXT(n) = NULL; | |
315 | break; | |
316 | } | |
317 | n = next; | |
318 | } | |
319 | VERIFY(n != NULL || | |
320 | (qlen(q) == 1 && m == MBUFQ_FIRST(head))); | |
321 | VERIFY(qlen(q) > 0); | |
322 | --qlen(q); | |
323 | ||
324 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 325 | if (((int)qsize(q) - m_length(m)) > 0) { |
316670eb | 326 | qsize(q) -= m_length(m); |
0a7de745 | 327 | } else if (qsize(q) != 0) { |
316670eb | 328 | qsize(q) = 0; |
0a7de745 | 329 | } |
316670eb A |
330 | |
331 | if (qempty(q)) { | |
39037602 | 332 | VERIFY(m == MBUFQ_FIRST(head)); |
316670eb A |
333 | MBUFQ_INIT(head); |
334 | } else { | |
335 | VERIFY(n != NULL); | |
336 | head->mq_last = &MBUFQ_NEXT(n); | |
337 | } | |
338 | } | |
0a7de745 | 339 | return m; |
316670eb A |
340 | } |
341 | ||
5ba3f43e | 342 | /* drop a packet at the tail of the queue */ |
cb323159 A |
343 | void |
344 | _getq_tail(class_queue_t *q, classq_pkt_t *pkt) | |
5ba3f43e | 345 | { |
5ba3f43e A |
346 | switch (qptype(q)) { |
347 | case QP_MBUF: | |
cb323159 A |
348 | pkt->cp_mbuf = _getq_tail_mbuf(q); |
349 | if (__probable(pkt->cp_mbuf != NULL)) { | |
350 | CLASSQ_PKT_INIT_MBUF(pkt, pkt->cp_mbuf); | |
351 | } | |
5ba3f43e A |
352 | break; |
353 | ||
354 | default: | |
355 | VERIFY(0); | |
356 | /* NOTREACHED */ | |
cb323159 | 357 | __builtin_unreachable(); |
5ba3f43e | 358 | } |
5ba3f43e A |
359 | } |
360 | ||
361 | static inline struct mbuf * | |
362 | _getq_random_mbuf(class_queue_t *q) | |
316670eb | 363 | { |
5ba3f43e | 364 | struct mq_head *head = &qmbufq(q); |
316670eb A |
365 | struct mbuf *m = NULL; |
366 | unsigned int n; | |
367 | u_int32_t rnd; | |
368 | ||
5ba3f43e A |
369 | /* XXX: Add support for Kernel packet when needed */ |
370 | VERIFY((qptype(q) == QP_MBUF)); | |
371 | ||
316670eb A |
372 | n = qlen(q); |
373 | if (n == 0) { | |
374 | VERIFY(MBUFQ_EMPTY(head)); | |
0a7de745 | 375 | if (qsize(q) > 0) { |
316670eb | 376 | qsize(q) = 0; |
0a7de745 A |
377 | } |
378 | return NULL; | |
316670eb A |
379 | } |
380 | ||
381 | m = MBUFQ_FIRST(head); | |
0a7de745 | 382 | read_frandom(&rnd, sizeof(rnd)); |
316670eb A |
383 | n = (rnd % n) + 1; |
384 | ||
385 | if (n == 1) { | |
0a7de745 | 386 | if ((MBUFQ_FIRST(head) = MBUFQ_NEXT(m)) == NULL) { |
316670eb | 387 | (head)->mq_last = &MBUFQ_FIRST(head); |
0a7de745 | 388 | } |
316670eb A |
389 | } else { |
390 | struct mbuf *p = NULL; | |
391 | ||
392 | VERIFY(n > 1); | |
393 | while (n--) { | |
0a7de745 | 394 | if (MBUFQ_NEXT(m) == NULL) { |
316670eb | 395 | break; |
0a7de745 | 396 | } |
316670eb A |
397 | p = m; |
398 | m = MBUFQ_NEXT(m); | |
399 | } | |
400 | VERIFY(p != NULL && MBUFQ_NEXT(p) == m); | |
401 | ||
0a7de745 | 402 | if ((MBUFQ_NEXT(p) = MBUFQ_NEXT(m)) == NULL) { |
316670eb | 403 | (head)->mq_last = &MBUFQ_NEXT(p); |
0a7de745 | 404 | } |
316670eb A |
405 | } |
406 | ||
407 | VERIFY(qlen(q) > 0); | |
408 | --qlen(q); | |
409 | ||
410 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 411 | if (((int)qsize(q) - m_length(m)) > 0) { |
316670eb | 412 | qsize(q) -= m_length(m); |
0a7de745 | 413 | } else if (qsize(q) != 0) { |
316670eb | 414 | qsize(q) = 0; |
0a7de745 | 415 | } |
316670eb A |
416 | |
417 | MBUFQ_NEXT(m) = NULL; | |
418 | ||
0a7de745 | 419 | return m; |
316670eb A |
420 | } |
421 | ||
5ba3f43e | 422 | /* randomly select a packet in the queue */ |
cb323159 A |
423 | void |
424 | _getq_random(class_queue_t *q, classq_pkt_t *pkt) | |
5ba3f43e | 425 | { |
5ba3f43e A |
426 | switch (qptype(q)) { |
427 | case QP_MBUF: | |
cb323159 A |
428 | pkt->cp_mbuf = _getq_random_mbuf(q); |
429 | if (__probable(pkt->cp_mbuf != NULL)) { | |
430 | CLASSQ_PKT_INIT_MBUF(pkt, pkt->cp_mbuf); | |
431 | } | |
5ba3f43e A |
432 | break; |
433 | ||
434 | default: | |
435 | VERIFY(0); | |
436 | /* NOTREACHED */ | |
cb323159 | 437 | __builtin_unreachable(); |
5ba3f43e | 438 | } |
5ba3f43e A |
439 | } |
440 | ||
441 | static inline void | |
442 | _removeq_mbuf(class_queue_t *q, struct mbuf *m) | |
316670eb | 443 | { |
5ba3f43e | 444 | struct mq_head *head = &qmbufq(q); |
316670eb A |
445 | struct mbuf *m0, **mtail; |
446 | ||
447 | m0 = MBUFQ_FIRST(head); | |
0a7de745 | 448 | if (m0 == NULL) { |
316670eb | 449 | return; |
0a7de745 | 450 | } |
316670eb A |
451 | |
452 | if (m0 != m) { | |
cb323159 | 453 | while (m0 != NULL && MBUFQ_NEXT(m0) != m) { |
316670eb A |
454 | m0 = MBUFQ_NEXT(m0); |
455 | } | |
cb323159 A |
456 | if (m0 == NULL) { |
457 | return; | |
458 | } | |
459 | ||
316670eb A |
460 | mtail = &MBUFQ_NEXT(m0); |
461 | } else { | |
462 | mtail = &MBUFQ_FIRST(head); | |
463 | } | |
464 | ||
465 | *mtail = MBUFQ_NEXT(m); | |
0a7de745 | 466 | if (*mtail == NULL) { |
316670eb | 467 | head->mq_last = mtail; |
0a7de745 | 468 | } |
316670eb A |
469 | |
470 | VERIFY(qlen(q) > 0); | |
471 | --qlen(q); | |
472 | ||
473 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 474 | if (((int)qsize(q) - m_length(m)) > 0) { |
316670eb | 475 | qsize(q) -= m_length(m); |
0a7de745 | 476 | } else if (qsize(q) != 0) { |
316670eb | 477 | qsize(q) = 0; |
0a7de745 | 478 | } |
316670eb A |
479 | |
480 | MBUFQ_NEXT(m) = NULL; | |
481 | } | |
482 | ||
5ba3f43e A |
483 | /* remove a packet from the queue */ |
484 | void | |
cb323159 | 485 | _removeq(class_queue_t *q, classq_pkt_t *pkt) |
5ba3f43e A |
486 | { |
487 | switch (qptype(q)) { | |
488 | case QP_MBUF: | |
cb323159 A |
489 | ASSERT(pkt->cp_ptype == QP_MBUF); |
490 | _removeq_mbuf(q, pkt->cp_mbuf); | |
5ba3f43e A |
491 | break; |
492 | ||
493 | default: | |
494 | VERIFY(0); | |
495 | /* NOTREACHED */ | |
cb323159 | 496 | __builtin_unreachable(); |
5ba3f43e A |
497 | } |
498 | } | |
499 | ||
316670eb A |
500 | void |
501 | _flushq(class_queue_t *q) | |
502 | { | |
503 | (void) _flushq_flow(q, 0, NULL, NULL); | |
504 | } | |
505 | ||
5ba3f43e A |
506 | static inline void |
507 | _flushq_flow_mbuf(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, | |
508 | u_int32_t *len) | |
316670eb A |
509 | { |
510 | MBUFQ_HEAD(mq_freeq) freeq; | |
511 | struct mbuf *m, *m_tmp; | |
512 | u_int32_t c = 0, l = 0; | |
513 | ||
514 | MBUFQ_INIT(&freeq); | |
515 | ||
5ba3f43e | 516 | MBUFQ_FOREACH_SAFE(m, &qmbufq(q), m_tmp) { |
316670eb | 517 | if (flow == 0 || ((m->m_flags & M_PKTHDR) && |
39236c6e | 518 | m->m_pkthdr.pkt_flowid == flow)) { |
316670eb | 519 | /* remove it from the class queue */ |
5ba3f43e | 520 | MBUFQ_REMOVE(&qmbufq(q), m); |
316670eb A |
521 | MBUFQ_NEXT(m) = NULL; |
522 | ||
523 | /* and add it to the free queue */ | |
524 | MBUFQ_ENQUEUE(&freeq, m); | |
525 | ||
526 | l += m_length(m); | |
527 | c++; | |
528 | } | |
529 | } | |
530 | VERIFY(c == 0 || !MBUFQ_EMPTY(&freeq)); | |
531 | ||
532 | if (c > 0) { | |
533 | VERIFY(qlen(q) >= c); | |
534 | qlen(q) -= c; | |
535 | ||
536 | /* qsize is an approximation, so adjust if necessary */ | |
0a7de745 | 537 | if (((int)qsize(q) - l) > 0) { |
316670eb | 538 | qsize(q) -= l; |
0a7de745 | 539 | } else if (qsize(q) != 0) { |
316670eb | 540 | qsize(q) = 0; |
0a7de745 | 541 | } |
316670eb A |
542 | } |
543 | ||
0a7de745 | 544 | if (!MBUFQ_EMPTY(&freeq)) { |
316670eb | 545 | m_freem_list(MBUFQ_FIRST(&freeq)); |
0a7de745 | 546 | } |
316670eb | 547 | |
0a7de745 | 548 | if (cnt != NULL) { |
316670eb | 549 | *cnt = c; |
0a7de745 A |
550 | } |
551 | if (len != NULL) { | |
316670eb | 552 | *len = l; |
0a7de745 | 553 | } |
316670eb | 554 | } |
5ba3f43e | 555 | |
cb323159 | 556 | |
5ba3f43e A |
557 | void |
558 | _flushq_flow(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, u_int32_t *len) | |
559 | { | |
560 | switch (qptype(q)) { | |
561 | case QP_MBUF: | |
562 | _flushq_flow_mbuf(q, flow, cnt, len); | |
563 | break; | |
564 | ||
565 | default: | |
566 | VERIFY(0); | |
567 | /* NOTREACHED */ | |
cb323159 | 568 | __builtin_unreachable(); |
5ba3f43e A |
569 | } |
570 | } |