1/* 2 * Copyright (c) 2007-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/* $OpenBSD: altq_hfsc.c,v 1.25 2007/09/13 20:40:02 chl Exp $ */ 30/* $KAME: altq_hfsc.c,v 1.17 2002/11/29 07:48:33 kjc Exp $ */ 31 32/* 33 * Copyright (c) 1997-1999 Carnegie Mellon University. All Rights Reserved. 34 * 35 * Permission to use, copy, modify, and distribute this software and 36 * its documentation is hereby granted (including for commercial or 37 * for-profit use), provided that both the copyright notice and this 38 * permission notice appear in all copies of the software, derivative 39 * works, or modified versions, and any portions thereof. 40 * 41 * THIS SOFTWARE IS EXPERIMENTAL AND IS KNOWN TO HAVE BUGS, SOME OF 42 * WHICH MAY HAVE SERIOUS CONSEQUENCES. CARNEGIE MELLON PROVIDES THIS 43 * SOFTWARE IN ITS ``AS IS'' CONDITION, AND ANY EXPRESS OR IMPLIED 44 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 45 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 46 * DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE 47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 48 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 49 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 50 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 51 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 53 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 54 * DAMAGE. 55 * 56 * Carnegie Mellon encourages (but does not require) users of this 57 * software to return any improvements or extensions that they make, 58 * and to grant Carnegie Mellon the rights to redistribute these 59 * changes without encumbrance. 60 */ 61 62#include <sys/cdefs.h> 63 64#if PF_ALTQ && PKTSCHED_HFSC 65 66#include <sys/cdefs.h> 67#include <sys/param.h> 68#include <sys/malloc.h> 69#include <sys/mbuf.h> 70#include <sys/systm.h> 71#include <sys/errno.h> 72#include <sys/kernel.h> 73 74#include <net/if.h> 75#include <net/pfvar.h> 76#include <net/net_osdep.h> 77#include <net/altq/altq.h> 78#include <net/altq/altq_hfsc.h> 79#include <netinet/in.h> 80 81/* 82 * function prototypes 83 */ 84static int altq_hfsc_request(struct ifaltq *, enum altrq, void *); 85static int altq_hfsc_enqueue(struct ifaltq *, struct mbuf *); 86static struct mbuf *altq_hfsc_dequeue(struct ifaltq *, enum altdq_op); 87 88int 89altq_hfsc_pfattach(struct pf_altq *a) 90{ 91 struct ifnet *ifp; 92 int error; 93 94 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 95 96 if ((ifp = ifunit(a->ifname)) == NULL || a->altq_disc == NULL) 97 return (EINVAL); 98 99 IFCQ_LOCK(&ifp->if_snd); 100 error = altq_attach(IFCQ_ALTQ(&ifp->if_snd), ALTQT_HFSC, a->altq_disc, 101 altq_hfsc_enqueue, altq_hfsc_dequeue, NULL, altq_hfsc_request); 102 IFCQ_UNLOCK(&ifp->if_snd); 103 104 return (error); 105} 106 107int 108altq_hfsc_add(struct pf_altq *a) 109{ 110 struct hfsc_if *hif; 111 struct ifnet *ifp; 112 113 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 114 115 if ((ifp = ifunit(a->ifname)) == NULL) 116 return (EINVAL); 117 if (!ALTQ_IS_READY(IFCQ_ALTQ(&ifp->if_snd))) 118 return (ENODEV); 119 120 hif = hfsc_alloc(ifp, M_WAITOK, TRUE); 121 if (hif == NULL) 122 return (ENOMEM); 123 124 /* keep the state in pf_altq */ 125 a->altq_disc = hif; 126 127 return (0); 128} 129 130int 131altq_hfsc_remove(struct pf_altq *a) 132{ 133 struct hfsc_if *hif; 134 135 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 136 137 if ((hif = a->altq_disc) == NULL) 138 return (EINVAL); 139 a->altq_disc = NULL; 140 141 return (hfsc_destroy(hif)); 142} 143 144int 145altq_hfsc_add_queue(struct pf_altq *a) 146{ 147 struct hfsc_if *hif; 148 struct hfsc_opts *opts = &a->pq_u.hfsc_opts; 149 struct service_curve rtsc, lssc, ulsc; 150 int err; 151 152 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 153 154 if ((hif = a->altq_disc) == NULL) 155 return (EINVAL); 156 157 bzero(&rtsc, sizeof (rtsc)); 158 bzero(&lssc, sizeof (lssc)); 159 bzero(&ulsc, sizeof (ulsc)); 160 161 rtsc.m1 = opts->rtsc_m1; 162 rtsc.d = opts->rtsc_d; 163 rtsc.m2 = opts->rtsc_m2; 164 rtsc.fl = opts->rtsc_fl; 165 lssc.m1 = opts->lssc_m1; 166 lssc.d = opts->lssc_d; 167 lssc.m2 = opts->lssc_m2; 168 lssc.fl = opts->lssc_fl; 169 ulsc.m1 = opts->ulsc_m1; 170 ulsc.d = opts->ulsc_d; 171 ulsc.m2 = opts->ulsc_m2; 172 ulsc.fl = opts->ulsc_fl; 173 174 IFCQ_LOCK(hif->hif_ifq); 175 err = hfsc_add_queue(hif, &rtsc, &lssc, &ulsc, a->qlimit, 176 opts->flags, a->parent_qid, a->qid, NULL); 177 IFCQ_UNLOCK(hif->hif_ifq); 178 179 return (err); 180} 181 182int 183altq_hfsc_remove_queue(struct pf_altq *a) 184{ 185 struct hfsc_if *hif; 186 int err; 187 188 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 189 190 if ((hif = a->altq_disc) == NULL) 191 return (EINVAL); 192 193 IFCQ_LOCK(hif->hif_ifq); 194 err = hfsc_remove_queue(hif, a->qid); 195 IFCQ_UNLOCK(hif->hif_ifq); 196 197 return (err); 198} 199 200int 201altq_hfsc_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 202{ 203 struct ifclassq *ifq = NULL; 204 struct hfsc_if *hif; 205 struct hfsc_classstats stats; 206 int error = 0; 207 208 lck_mtx_assert(pf_lock, LCK_MTX_ASSERT_OWNED); 209 210 if ((unsigned)*nbytes < sizeof (stats)) 211 return (EINVAL); 212 213 if ((hif = altq_lookup(a->ifname, ALTQT_HFSC)) == NULL) 214 return (EBADF); 215 216 ifq = hif->hif_ifq; 217 IFCQ_LOCK_ASSERT_HELD(ifq); /* lock held by altq_lookup */ 218 error = hfsc_get_class_stats(hif, a->qid, &stats); 219 IFCQ_UNLOCK(ifq); 220 if (error != 0) 221 return (error); 222 223 if ((error = copyout((caddr_t)&stats, (user_addr_t)(uintptr_t)ubuf, 224 sizeof (stats))) != 0) 225 return (error); 226 227 *nbytes = sizeof (stats); 228 229 return (0); 230} 231 232static int 233altq_hfsc_request(struct ifaltq *altq, enum altrq req, void *arg) 234{ 235 struct hfsc_if *hif = (struct hfsc_if *)altq->altq_disc; 236 237 switch (req) { 238 case ALTRQ_PURGE: 239 hfsc_purge(hif); 240 break; 241 242 case ALTRQ_PURGE_SC: 243 /* not supported for ALTQ instance */ 244 break; 245 246 case ALTRQ_EVENT: 247 hfsc_event(hif, (cqev_t)arg); 248 break; 249 } 250 return (0); 251} 252 253/* 254 * altq_hfsc_enqueue is an enqueue function to be registered to 255 * (*altq_enqueue) in struct ifaltq. 256 */ 257static int 258altq_hfsc_enqueue(struct ifaltq *altq, struct mbuf *m) 259{ 260 /* grab class set by classifier */ 261 if (!(m->m_flags & M_PKTHDR)) { 262 /* should not happen */ 263 printf("%s: packet for %s does not have pkthdr\n", __func__, 264 if_name(altq->altq_ifcq->ifcq_ifp)); 265 m_freem(m); 266 return (ENOBUFS); 267 } 268 269 return (hfsc_enqueue(altq->altq_disc, NULL, m, m_pftag(m))); 270} 271 272/* 273 * altq_hfsc_dequeue is a dequeue function to be registered to 274 * (*altq_dequeue) in struct ifaltq. 275 * 276 * note: ALTDQ_POLL returns the next packet without removing the packet 277 * from the queue. ALTDQ_REMOVE is a normal dequeue operation. 278 * ALTDQ_REMOVE must return the same packet if called immediately 279 * after ALTDQ_POLL. 280 */ 281static struct mbuf * 282altq_hfsc_dequeue(struct ifaltq *altq, enum altdq_op op) 283{ 284 return (hfsc_dequeue(altq->altq_disc, (cqdq_op_t)op)); 285} 286#endif /* PF_ALTQ && PKTSCHED_HFSC */ 287