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 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 31 * 32 * This code is derived from software contributed to The DragonFly Project 33 * by Matthew Dillon <dillon@backplane.com> 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in 43 * the documentation and/or other materials provided with the 44 * distribution. 45 * 3. Neither the name of The DragonFly Project nor the names of its 46 * contributors may be used to endorse or promote products derived 47 * from this software without specific, prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 52 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 53 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 54 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 55 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 56 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 57 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 58 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 59 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 60 * SUCH DAMAGE. 61 * 62 * $DragonFly: src/sys/net/altq/altq_fairq.c,v 1.2 2008/05/14 11:59:23 sephe Exp $ 63 */ 64/* 65 * Matt: I gutted altq_priq.c and used it as a skeleton on which to build 66 * fairq. The fairq algorithm is completely different then priq, of course, 67 * but because I used priq's skeleton I believe I should include priq's 68 * copyright. 69 * 70 * Copyright (C) 2000-2003 71 * Sony Computer Science Laboratories Inc. All rights reserved. 72 * 73 * Redistribution and use in source and binary forms, with or without 74 * modification, are permitted provided that the following conditions 75 * are met: 76 * 1. Redistributions of source code must retain the above copyright 77 * notice, this list of conditions and the following disclaimer. 78 * 2. Redistributions in binary form must reproduce the above copyright 79 * notice, this list of conditions and the following disclaimer in the 80 * documentation and/or other materials provided with the distribution. 81 * 82 * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 83 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 84 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 85 * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 86 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 87 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 88 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 89 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 90 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 91 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 92 * SUCH DAMAGE. 93 */ 94 95#if PF_ALTQ && PKTSCHED_FAIRQ 96 97#include <sys/cdefs.h> 98#include <sys/param.h> 99#include <sys/malloc.h> 100#include <sys/mbuf.h> 101#include <sys/systm.h> 102#include <sys/errno.h> 103#include <sys/kernel.h> 104 105#include <net/if.h> 106#include <net/pfvar.h> 107#include <net/net_osdep.h> 108#include <net/altq/altq.h> 109#include <net/altq/altq_fairq.h> 110#include <netinet/in.h> 111 112/* 113 * function prototypes 114 */ 115static int altq_fairq_enqueue(struct ifaltq *, struct mbuf *); 116static struct mbuf *altq_fairq_dequeue(struct ifaltq *, enum altdq_op); 117static int altq_fairq_request(struct ifaltq *, enum altrq, void *); 118 119int 120altq_fairq_pfattach(struct pf_altq *a) 121{ 122 struct ifnet *ifp; 123 int error; 124 125 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 126 127 if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) 128 return (EINVAL); 129 130 IFCQ_LOCK(&ifp->if_snd); 131 error = altq_attach(IFCQ_ALTQ(&ifp->if_snd), ALTQT_FAIRQ, a->altq_disc, 132 altq_fairq_enqueue, altq_fairq_dequeue, NULL, altq_fairq_request); 133 IFCQ_UNLOCK(&ifp->if_snd); 134 135 return (error); 136} 137 138int 139altq_fairq_add(struct pf_altq *a) 140{ 141 struct fairq_if *fif; 142 struct ifnet *ifp; 143 144 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 145 146 if ((ifp = ifunit(a->ifname)) == NULL) 147 return (EINVAL); 148 if (!ALTQ_IS_READY(IFCQ_ALTQ(&ifp->if_snd))) 149 return (ENODEV); 150 151 fif = fairq_alloc(ifp, M_WAITOK, TRUE); 152 if (fif == NULL) 153 return (ENOMEM); 154 155 /* keep the state in pf_altq */ 156 a->altq_disc = fif; 157 158 return (0); 159} 160 161int 162altq_fairq_remove(struct pf_altq *a) 163{ 164 struct fairq_if *fif; 165 166 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 167 168 if ((fif = a->altq_disc) == NULL) 169 return (EINVAL); 170 a->altq_disc = NULL; 171 172 return (fairq_destroy(fif)); 173} 174 175int 176altq_fairq_add_queue(struct pf_altq *a) 177{ 178 struct fairq_if *fif; 179 struct fairq_opts *opts = &a->pq_u.fairq_opts; 180 int err; 181 182 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 183 184 if ((fif = a->altq_disc) == NULL) 185 return (EINVAL); 186 187 IFCQ_LOCK(fif->fif_ifq); 188 err = fairq_add_queue(fif, a->priority, a->qlimit, a->bandwidth, 189 opts->nbuckets, opts->flags, opts->hogs_m1, opts->lssc_m1, 190 opts->lssc_d, opts->lssc_m2, a->qid, NULL); 191 IFCQ_UNLOCK(fif->fif_ifq); 192 193 return (err); 194} 195 196int 197altq_fairq_remove_queue(struct pf_altq *a) 198{ 199 struct fairq_if *fif; 200 int err; 201 202 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 203 204 if ((fif = a->altq_disc) == NULL) 205 return (EINVAL); 206 207 IFCQ_LOCK(fif->fif_ifq); 208 err = fairq_remove_queue(fif, a->qid); 209 IFCQ_UNLOCK(fif->fif_ifq); 210 211 return (err); 212} 213 214int 215altq_fairq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 216{ 217 struct ifclassq *ifq = NULL; 218 struct fairq_if *fif; 219 struct fairq_classstats stats; 220 int error = 0; 221 222 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 223 224 if ((unsigned)*nbytes < sizeof (stats)) 225 return (EINVAL); 226 227 if ((fif = altq_lookup(a->ifname, ALTQT_FAIRQ)) == NULL) 228 return (EBADF); 229 230 ifq = fif->fif_ifq; 231 IFCQ_LOCK_ASSERT_HELD(ifq); /* lock held by altq_lookup */ 232 error = fairq_get_class_stats(fif, a->qid, &stats); 233 IFCQ_UNLOCK(ifq); 234 if (error != 0) 235 return (error); 236 237 if ((error = copyout((caddr_t)&stats, (user_addr_t)(uintptr_t)ubuf, 238 sizeof (stats))) != 0) 239 return (error); 240 241 *nbytes = sizeof (stats); 242 243 return (0); 244} 245 246static int 247altq_fairq_request(struct ifaltq *altq, enum altrq req, void *arg) 248{ 249 struct fairq_if *fif = (struct fairq_if *)altq->altq_disc; 250 251 switch (req) { 252 case ALTRQ_PURGE: 253 fairq_purge(fif); 254 break; 255 256 case ALTRQ_PURGE_SC: 257 /* not supported for ALTQ instance */ 258 break; 259 260 case ALTRQ_EVENT: 261 fairq_event(fif, (cqev_t)arg); 262 break; 263 } 264 return (0); 265} 266 267/* 268 * altq_fairq_enqueue is an enqueue function to be registered to 269 * (*altq_enqueue) in struct ifaltq. 270 */ 271static int 272altq_fairq_enqueue(struct ifaltq *altq, struct mbuf *m) 273{ 274 /* grab class set by classifier */ 275 if (!(m->m_flags & M_PKTHDR)) { 276 /* should not happen */ 277 printf("%s: packet for %s does not have pkthdr\n", __func__, 278 if_name(altq->altq_ifcq->ifcq_ifp)); 279 m_freem(m); 280 return (ENOBUFS); 281 } 282 283 return (fairq_enqueue(altq->altq_disc, NULL, m, m_pftag(m))); 284} 285 286/* 287 * altq_fairq_dequeue is a dequeue function to be registered to 288 * (*altq_dequeue) in struct ifaltq. 289 * 290 * note: ALTDQ_POLL returns the next packet without removing the packet 291 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 292 * ALTDQ_REMOVE must return the same packet if called immediately 293 * after ALTDQ_POLL. 294 */ 295static struct mbuf * 296altq_fairq_dequeue(struct ifaltq *altq, enum altdq_op op) 297{ 298 return (fairq_dequeue(altq->altq_disc, (cqdq_op_t)op)); 299} 300#endif /* PF_ALTQ && PKTSCHED_FAIRQ */ 301