/*
- * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <libkern/libkern.h>
+
u_int32_t classq_verbose = 0; /* more noise if greater than 1 */
SYSCTL_NODE(_net, OID_AUTO, classq, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "classq");
&classq_verbose, 0, "Class queue verbosity level");
void
-_qinit(class_queue_t *q, int type, int lim)
+_qinit(class_queue_t *q, int type, int lim, classq_pkt_type_t ptype)
{
- MBUFQ_INIT(&q->mbufq);
+ switch (ptype) {
+ case QP_MBUF:
+ MBUFQ_INIT(&qmbufq(q));
+ break;
+
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
qlimit(q) = lim;
qlen(q) = 0;
qsize(q) = 0;
qtype(q) = type;
+ qptype(q) = ptype;
qstate(q) = QS_RUNNING;
}
/* add a packet at the tail of the queue */
void
-_addq(class_queue_t *q, struct mbuf *m)
+_addq(class_queue_t *q, void *pkt)
{
- MBUFQ_ENQUEUE(&q->mbufq, m);
+ uint32_t size = 0;
+
+ switch (qptype(q)) {
+ case QP_MBUF: {
+ struct mbuf *m = pkt;
+ MBUFQ_ENQUEUE(&qmbufq(q), m);
+ size = m_length(m);
+ break;
+ }
+
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
qlen(q)++;
VERIFY(qlen(q) != 0);
- qsize(q) += m_length(m);
+ qsize(q) += size;
}
/* add one or more packets at the tail of the queue */
void
-_addq_multi(class_queue_t *q, struct mbuf *m_head, struct mbuf *m_tail,
+_addq_multi(class_queue_t *q, void *pkt_head, void *pkt_tail,
u_int32_t cnt, u_int32_t size)
{
- MBUFQ_ENQUEUE_MULTI(&q->mbufq, m_head, m_tail);
+ switch (qptype(q)) {
+ case QP_MBUF: {
+ struct mbuf *m_head = pkt_head;
+ struct mbuf *m_tail = pkt_tail;
+ MBUFQ_ENQUEUE_MULTI(&qmbufq(q), m_head, m_tail);
+ break;
+ }
+
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
qlen(q) += cnt;
qsize(q) += size;
}
/* get a packet at the head of the queue */
-struct mbuf *
+void *
_getq(class_queue_t *q)
{
- struct mbuf *m;
+ void *pkt = NULL;
+ uint32_t pkt_len;
+
+ switch (qptype(q)) {
+ case QP_MBUF: {
+ struct mbuf *m;
+ MBUFQ_DEQUEUE(&qmbufq(q), m);
+ if (m != NULL) {
+ pkt_len = m_length(m);
+ pkt = m;
+ }
+ break;
+ }
+
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
- MBUFQ_DEQUEUE(&q->mbufq, m);
- if (m == NULL) {
+ if (pkt == NULL) {
VERIFY(qlen(q) == 0);
if (qsize(q) > 0)
qsize(q) = 0;
qlen(q)--;
/* qsize is an approximation, so adjust if necessary */
- if (((int)qsize(q) - m_length(m)) > 0)
- qsize(q) -= m_length(m);
+ if (((int)qsize(q) - pkt_len) > 0)
+ qsize(q) -= pkt_len;
else if (qsize(q) != 0)
qsize(q) = 0;
- return (m);
+ return (pkt);
}
-static struct mbuf *
+static void *
_getq_flow_or_scidx(class_queue_t *q, u_int32_t val, boolean_t isflowid)
{
- struct mbuf *m, *m_tmp;
-
- MBUFQ_FOREACH_SAFE(m, &q->mbufq, m_tmp) {
- if ((isflowid && (val == 0 || ((m->m_flags & M_PKTHDR) &&
- m->m_pkthdr.pkt_flowid == val))) ||
- (!isflowid &&
- MBUF_SCIDX(mbuf_get_service_class(m)) < val)) {
- /* remove it from the class queue */
- MBUFQ_REMOVE(&q->mbufq, m);
- MBUFQ_NEXT(m) = NULL;
- break;
+ void *pkt = NULL;
+ uint32_t pkt_len;
+
+ switch (qptype(q)) {
+ case QP_MBUF: {
+ struct mbuf *m, *m_tmp;
+
+ MBUFQ_FOREACH_SAFE(m, &qmbufq(q), m_tmp) {
+ if ((isflowid && (val == 0 ||
+ ((m->m_flags & M_PKTHDR) &&
+ m->m_pkthdr.pkt_flowid == val))) ||
+ (!isflowid &&
+ MBUF_SCIDX(mbuf_get_service_class(m)) < val)) {
+ /* remove it from the class queue */
+ MBUFQ_REMOVE(&qmbufq(q), m);
+ MBUFQ_NEXT(m) = NULL;
+ break;
+ }
+ }
+ if (m != NULL) {
+ pkt = m;
+ pkt_len = m_length(m);
}
+ break;
}
- if (m != NULL) {
- u_int32_t l = m_length(m);
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
+ if (pkt != NULL) {
VERIFY(qlen(q) > 0);
qlen(q)--;
/* qsize is an approximation, so adjust if necessary */
- if (((int)qsize(q) - l) > 0)
- qsize(q) -= l;
+ if (((int)qsize(q) - pkt_len) > 0)
+ qsize(q) -= pkt_len;
else if (qsize(q) != 0)
qsize(q) = 0;
}
- return (m);
-
+ return (pkt);
}
/* get a packet of a specific flow beginning from the head of the queue */
-struct mbuf *
+void *
_getq_flow(class_queue_t *q, u_int32_t flow)
{
return (_getq_flow_or_scidx(q, flow, TRUE));
}
/* Get a packet whose MBUF_SCIDX() < scidx from head of queue */
-struct mbuf *
+void *
_getq_scidx_lt(class_queue_t *q, u_int32_t scidx)
{
return (_getq_flow_or_scidx(q, scidx, FALSE));
}
-/* get all packets starting from the head of the queue */
-struct mbuf *
-_getq_all(class_queue_t *q, struct mbuf **last, u_int32_t *qlenp,
+/* get all packets (chained) starting from the head of the queue */
+void *
+_getq_all(class_queue_t *q, void **last, u_int32_t *qlenp,
u_int64_t *qsizep)
{
- struct mbuf *m;
+ void *pkt = NULL;
+
+ switch (qptype(q)) {
+ case QP_MBUF:
+ pkt = MBUFQ_FIRST(&qmbufq(q));
+ if (last != NULL)
+ *last = MBUFQ_LAST(&qmbufq(q));
+ MBUFQ_INIT(&qmbufq(q));
+ break;
- m = MBUFQ_FIRST(&q->mbufq);
- if (last != NULL)
- *last = MBUFQ_LAST(&q->mbufq);
- MBUFQ_INIT(&q->mbufq);
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
if (qlenp != NULL)
*qlenp = qlen(q);
qlen(q) = 0;
qsize(q) = 0;
- return (m);
+ return (pkt);
}
-/* drop a packet at the tail of the queue */
-struct mbuf *
-_getq_tail(class_queue_t *q)
+static inline struct mbuf *
+_getq_tail_mbuf(class_queue_t *q)
{
- struct mq_head *head = &q->mbufq;
+ struct mq_head *head = &qmbufq(q);
struct mbuf *m = MBUFQ_LAST(head);
if (m != NULL) {
return (m);
}
-/* randomly select a packet in the queue */
-struct mbuf *
-_getq_random(class_queue_t *q)
+/* drop a packet at the tail of the queue */
+void *
+_getq_tail(class_queue_t *q)
+{
+ void *t = NULL;
+
+ switch (qptype(q)) {
+ case QP_MBUF:
+ t = _getq_tail_mbuf(q);
+ break;
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
+ return (t);
+}
+
+static inline struct mbuf *
+_getq_random_mbuf(class_queue_t *q)
{
- struct mq_head *head = &q->mbufq;
+ struct mq_head *head = &qmbufq(q);
struct mbuf *m = NULL;
unsigned int n;
u_int32_t rnd;
+ /* XXX: Add support for Kernel packet when needed */
+ VERIFY((qptype(q) == QP_MBUF));
+
n = qlen(q);
if (n == 0) {
VERIFY(MBUFQ_EMPTY(head));
}
m = MBUFQ_FIRST(head);
- read_random(&rnd, sizeof (rnd));
+ read_frandom(&rnd, sizeof (rnd));
n = (rnd % n) + 1;
if (n == 1) {
return (m);
}
-/* remove a packet from the queue */
-void
-_removeq(class_queue_t *q, struct mbuf *m)
+/* randomly select a packet in the queue */
+void *
+_getq_random(class_queue_t *q)
+{
+ void *r = NULL;
+
+ switch (qptype(q)) {
+ case QP_MBUF:
+ r = _getq_random_mbuf(q);
+ break;
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+
+ return (r);
+}
+
+static inline void
+_removeq_mbuf(class_queue_t *q, struct mbuf *m)
{
- struct mq_head *head = &q->mbufq;
+ struct mq_head *head = &qmbufq(q);
struct mbuf *m0, **mtail;
m0 = MBUFQ_FIRST(head);
MBUFQ_NEXT(m) = NULL;
}
+/* remove a packet from the queue */
+void
+_removeq(class_queue_t *q, void *pkt)
+{
+ switch (qptype(q)) {
+ case QP_MBUF:
+ _removeq_mbuf(q, pkt);
+ break;
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+}
+
void
_flushq(class_queue_t *q)
{
(void) _flushq_flow(q, 0, NULL, NULL);
}
-void
-_flushq_flow(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, u_int32_t *len)
+static inline void
+_flushq_flow_mbuf(class_queue_t *q, u_int32_t flow, u_int32_t *cnt,
+ u_int32_t *len)
{
MBUFQ_HEAD(mq_freeq) freeq;
struct mbuf *m, *m_tmp;
MBUFQ_INIT(&freeq);
- MBUFQ_FOREACH_SAFE(m, &q->mbufq, m_tmp) {
+ MBUFQ_FOREACH_SAFE(m, &qmbufq(q), m_tmp) {
if (flow == 0 || ((m->m_flags & M_PKTHDR) &&
m->m_pkthdr.pkt_flowid == flow)) {
/* remove it from the class queue */
- MBUFQ_REMOVE(&q->mbufq, m);
+ MBUFQ_REMOVE(&qmbufq(q), m);
MBUFQ_NEXT(m) = NULL;
/* and add it to the free queue */
if (len != NULL)
*len = l;
}
+
+void
+_flushq_flow(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, u_int32_t *len)
+{
+ switch (qptype(q)) {
+ case QP_MBUF:
+ _flushq_flow_mbuf(q, flow, cnt, len);
+ break;
+
+ default:
+ VERIFY(0);
+ /* NOTREACHED */
+ }
+}