]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/classq/classq.c
xnu-4570.1.46.tar.gz
[apple/xnu.git] / bsd / net / classq / classq.c
index 67c1f44ead1d8668a9e46e88835aa4447b94a83d..35d86188fd8907c40335ecfee1d60687b4910218 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2017 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -73,6 +73,7 @@
 
 #include <libkern/libkern.h>
 
 
 #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");
 u_int32_t classq_verbose = 0;  /* more noise if greater than 1 */
 
 SYSCTL_NODE(_net, OID_AUTO, classq, CTLFLAG_RW|CTLFLAG_LOCKED, 0, "classq");
@@ -81,44 +82,100 @@ SYSCTL_UINT(_net_classq, OID_AUTO, verbose, CTLFLAG_RW|CTLFLAG_LOCKED,
        &classq_verbose, 0, "Class queue verbosity level");
 
 void
        &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;
        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
        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);
        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
 }
 
 /* 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)
 {
     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 */
        qlen(q) += cnt;
        qsize(q) += size;
 }
 
 /* get a packet at the head of the queue */
-struct mbuf *
+void *
 _getq(class_queue_t *q)
 {
 _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;
                VERIFY(qlen(q) == 0);
                if (qsize(q) > 0)
                        qsize(q) = 0;
@@ -128,73 +185,97 @@ _getq(class_queue_t *q)
        qlen(q)--;
 
        /* qsize is an approximation, so adjust if necessary */
        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;
 
        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)
 {
 _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 */
                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;
        }
 
                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 */
 }
 
 /* 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 */
 _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));
 }
 
 _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)
 {
     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);
 
        if (qlenp != NULL)
                *qlenp = qlen(q);
@@ -204,14 +285,13 @@ _getq_all(class_queue_t *q, struct mbuf **last, u_int32_t *qlenp,
        qlen(q) = 0;
        qsize(q) = 0;
 
        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) {
        struct mbuf *m = MBUFQ_LAST(head);
 
        if (m != NULL) {
@@ -247,15 +327,36 @@ _getq_tail(class_queue_t *q)
        return (m);
 }
 
        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;
 
        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));
        n = qlen(q);
        if (n == 0) {
                VERIFY(MBUFQ_EMPTY(head));
@@ -265,7 +366,7 @@ _getq_random(class_queue_t *q)
        }
 
        m = MBUFQ_FIRST(head);
        }
 
        m = MBUFQ_FIRST(head);
-       read_random(&rnd, sizeof (rnd));
+       read_frandom(&rnd, sizeof (rnd));
        n = (rnd % n) + 1;
 
        if (n == 1) {
        n = (rnd % n) + 1;
 
        if (n == 1) {
@@ -301,11 +402,29 @@ _getq_random(class_queue_t *q)
        return (m);
 }
 
        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);
        struct mbuf *m0, **mtail;
 
        m0 = MBUFQ_FIRST(head);
@@ -339,14 +458,30 @@ _removeq(class_queue_t *q, struct mbuf *m)
        MBUFQ_NEXT(m) = NULL;
 }
 
        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(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_HEAD(mq_freeq) freeq;
        struct mbuf *m, *m_tmp;
@@ -354,11 +489,11 @@ _flushq_flow(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, u_int32_t *len)
 
        MBUFQ_INIT(&freeq);
 
 
        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 */
                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 */
                        MBUFQ_NEXT(m) = NULL;
 
                        /* and add it to the free queue */
@@ -389,3 +524,17 @@ _flushq_flow(class_queue_t *q, u_int32_t flow, u_int32_t *cnt, u_int32_t *len)
        if (len != NULL)
                *len = l;
 }
        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 */
+       }
+}