1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 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 * quick fair queueing 31 */ 32 33#if PF_ALTQ 34 35#include <sys/cdefs.h> 36#include <sys/param.h> 37#include <sys/malloc.h> 38#include <sys/mbuf.h> 39#include <sys/systm.h> 40#include <sys/errno.h> 41#include <sys/kernel.h> 42 43#include <net/if.h> 44#include <net/pfvar.h> 45#include <net/net_osdep.h> 46#include <net/altq/altq.h> 47#include <net/altq/altq_qfq.h> 48#include <netinet/in.h> 49 50/* 51 * function prototypes 52 */ 53static int altq_qfq_enqueue(struct ifaltq *, struct mbuf *); 54static struct mbuf *altq_qfq_dequeue(struct ifaltq *, enum altdq_op); 55static int altq_qfq_request(struct ifaltq *, enum altrq, void *); 56 57int 58altq_qfq_pfattach(struct pf_altq *a) 59{ 60 struct ifnet *ifp; 61 int error; 62 63 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 64 65 if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) 66 return (EINVAL); 67 68 IFCQ_LOCK(&ifp->if_snd); 69 error = altq_attach(IFCQ_ALTQ(&ifp->if_snd), ALTQT_QFQ, a->altq_disc, 70 altq_qfq_enqueue, altq_qfq_dequeue, NULL, altq_qfq_request); 71 IFCQ_UNLOCK(&ifp->if_snd); 72 73 return (error); 74} 75 76int 77altq_qfq_add(struct pf_altq *a) 78{ 79 struct qfq_if *qif; 80 struct ifnet *ifp; 81 82 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 83 84 if ((ifp = ifunit(a->ifname)) == NULL) 85 return (EINVAL); 86 if (!ALTQ_IS_READY(IFCQ_ALTQ(&ifp->if_snd))) 87 return (ENODEV); 88 89 qif = qfq_alloc(ifp, M_WAITOK, TRUE); 90 if (qif == NULL) 91 return (ENOMEM); 92 93 /* keep the state in pf_altq */ 94 a->altq_disc = qif; 95 96 return (0); 97} 98 99int 100altq_qfq_remove(struct pf_altq *a) 101{ 102 struct qfq_if *qif; 103 104 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 105 106 if ((qif = a->altq_disc) == NULL) 107 return (EINVAL); 108 a->altq_disc = NULL; 109 110 return (qfq_destroy(qif)); 111} 112 113int 114altq_qfq_add_queue(struct pf_altq *a) 115{ 116 struct qfq_if *qif; 117 int err; 118 119 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 120 121 if ((qif = a->altq_disc) == NULL) 122 return (EINVAL); 123 124 IFCQ_LOCK(qif->qif_ifq); 125 err = qfq_add_queue(qif, a->qlimit, a->weight, a->pq_u.qfq_opts.lmax, 126 a->pq_u.qfq_opts.flags, a->qid, NULL); 127 IFCQ_UNLOCK(qif->qif_ifq); 128 129 return (err); 130} 131 132int 133altq_qfq_remove_queue(struct pf_altq *a) 134{ 135 struct qfq_if *qif; 136 int err; 137 138 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 139 140 if ((qif = a->altq_disc) == NULL) 141 return (EINVAL); 142 143 IFCQ_LOCK(qif->qif_ifq); 144 err = qfq_remove_queue(qif, a->qid); 145 IFCQ_UNLOCK(qif->qif_ifq); 146 147 return (err); 148} 149 150int 151altq_qfq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 152{ 153 struct ifclassq *ifq = NULL; 154 struct qfq_if *qif; 155 struct qfq_classstats stats; 156 int error = 0; 157 158 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 159 160 if ((unsigned)*nbytes < sizeof (stats)) 161 return (EINVAL); 162 163 if ((qif = altq_lookup(a->ifname, ALTQT_QFQ)) == NULL) 164 return (EBADF); 165 166 ifq = qif->qif_ifq; 167 IFCQ_LOCK_ASSERT_HELD(ifq); /* lock held by altq_lookup */ 168 error = qfq_get_class_stats(qif, a->qid, &stats); 169 IFCQ_UNLOCK(ifq); 170 if (error != 0) 171 return (error); 172 173 if ((error = copyout((caddr_t)&stats, (user_addr_t)(uintptr_t)ubuf, 174 sizeof (stats))) != 0) 175 return (error); 176 177 *nbytes = sizeof (stats); 178 179 return (0); 180} 181 182static int 183altq_qfq_request(struct ifaltq *altq, enum altrq req, void *arg) 184{ 185 struct qfq_if *qif = (struct qfq_if *)altq->altq_disc; 186 187 switch (req) { 188 case ALTRQ_PURGE: 189 qfq_purge(qif); 190 break; 191 192 case ALTRQ_PURGE_SC: 193 /* not supported for ALTQ instance */ 194 break; 195 196 case ALTRQ_EVENT: 197 qfq_event(qif, (cqev_t)arg); 198 break; 199 } 200 return (0); 201} 202 203/* 204 * altq_qfq_enqueue is an enqueue function to be registered to 205 * (*altq_enqueue) in struct ifaltq. 206 */ 207static int 208altq_qfq_enqueue(struct ifaltq *altq, struct mbuf *m) 209{ 210 /* grab class set by classifier */ 211 if (!(m->m_flags & M_PKTHDR)) { 212 /* should not happen */ 213 printf("%s: packet for %s does not have pkthdr\n", __func__, 214 if_name(altq->altq_ifcq->ifcq_ifp)); 215 m_freem(m); 216 return (ENOBUFS); 217 } 218 219 return (qfq_enqueue(altq->altq_disc, NULL, m, m_pftag(m))); 220} 221 222/* 223 * altq_qfq_dequeue is a dequeue function to be registered to 224 * (*altq_dequeue) in struct ifaltq. 225 * 226 * note: ALTDQ_POLL returns the next packet without removing the packet 227 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 228 * ALTDQ_REMOVE must return the same packet if called immediately 229 * after ALTDQ_POLL. 230 */ 231static struct mbuf * 232altq_qfq_dequeue(struct ifaltq *altq, enum altdq_op op) 233{ 234 return (qfq_dequeue(altq->altq_disc, (cqdq_op_t)op)); 235} 236#endif /* PF_ALTQ */ 237