1130368Smlaier/* $FreeBSD$ */ 2130365Smlaier/* $KAME: altq_subr.c,v 1.21 2003/11/06 06:32:53 kjc Exp $ */ 3130365Smlaier 4130365Smlaier/* 5130365Smlaier * Copyright (C) 1997-2003 6130365Smlaier * Sony Computer Science Laboratories Inc. All rights reserved. 7130365Smlaier * 8130365Smlaier * Redistribution and use in source and binary forms, with or without 9130365Smlaier * modification, are permitted provided that the following conditions 10130365Smlaier * are met: 11130365Smlaier * 1. Redistributions of source code must retain the above copyright 12130365Smlaier * notice, this list of conditions and the following disclaimer. 13130365Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14130365Smlaier * notice, this list of conditions and the following disclaimer in the 15130365Smlaier * documentation and/or other materials provided with the distribution. 16130365Smlaier * 17130365Smlaier * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND 18130365Smlaier * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19130365Smlaier * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20130365Smlaier * ARE DISCLAIMED. IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE 21130365Smlaier * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22130365Smlaier * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23130365Smlaier * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24130365Smlaier * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25130365Smlaier * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26130365Smlaier * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27130365Smlaier * SUCH DAMAGE. 28130365Smlaier */ 29130365Smlaier 30130365Smlaier#if defined(__FreeBSD__) || defined(__NetBSD__) 31130365Smlaier#include "opt_altq.h" 32130365Smlaier#include "opt_inet.h" 33130365Smlaier#ifdef __FreeBSD__ 34130365Smlaier#include "opt_inet6.h" 35130365Smlaier#endif 36130365Smlaier#endif /* __FreeBSD__ || __NetBSD__ */ 37130365Smlaier 38130365Smlaier#include <sys/param.h> 39130365Smlaier#include <sys/malloc.h> 40130365Smlaier#include <sys/mbuf.h> 41130365Smlaier#include <sys/systm.h> 42130365Smlaier#include <sys/proc.h> 43130365Smlaier#include <sys/socket.h> 44130365Smlaier#include <sys/socketvar.h> 45130365Smlaier#include <sys/kernel.h> 46130365Smlaier#include <sys/errno.h> 47130365Smlaier#include <sys/syslog.h> 48130365Smlaier#include <sys/sysctl.h> 49130365Smlaier#include <sys/queue.h> 50130365Smlaier 51130365Smlaier#include <net/if.h> 52130365Smlaier#include <net/if_dl.h> 53130365Smlaier#include <net/if_types.h> 54189106Sbz#ifdef __FreeBSD__ 55185571Sbz#include <net/vnet.h> 56189106Sbz#endif 57130365Smlaier 58130365Smlaier#include <netinet/in.h> 59130365Smlaier#include <netinet/in_systm.h> 60130365Smlaier#include <netinet/ip.h> 61130365Smlaier#ifdef INET6 62130365Smlaier#include <netinet/ip6.h> 63130365Smlaier#endif 64130365Smlaier#include <netinet/tcp.h> 65130365Smlaier#include <netinet/udp.h> 66130365Smlaier 67130365Smlaier#include <net/pfvar.h> 68130365Smlaier#include <altq/altq.h> 69130365Smlaier#ifdef ALTQ3_COMPAT 70130365Smlaier#include <altq/altq_conf.h> 71130365Smlaier#endif 72130365Smlaier 73130365Smlaier/* machine dependent clock related includes */ 74130365Smlaier#ifdef __FreeBSD__ 75167905Snjl#include <sys/bus.h> 76167905Snjl#include <sys/cpu.h> 77167905Snjl#include <sys/eventhandler.h> 78130365Smlaier#include <machine/clock.h> 79130365Smlaier#endif 80219458Sjkim#if defined(__amd64__) || defined(__i386__) 81130365Smlaier#include <machine/cpufunc.h> /* for pentium tsc */ 82130365Smlaier#include <machine/specialreg.h> /* for CPUID_TSC */ 83219673Sjkim#ifdef __FreeBSD__ 84219673Sjkim#include <machine/md_var.h> /* for cpu_feature */ 85219673Sjkim#elif defined(__NetBSD__) || defined(__OpenBSD__) 86219673Sjkim#include <machine/cpu.h> /* for cpu_feature */ 87130365Smlaier#endif 88219458Sjkim#endif /* __amd64 || __i386__ */ 89130365Smlaier 90130365Smlaier/* 91130365Smlaier * internal function prototypes 92130365Smlaier */ 93130365Smlaierstatic void tbr_timeout(void *); 94130365Smlaierint (*altq_input)(struct mbuf *, int) = NULL; 95130508Smlaierstatic struct mbuf *tbr_dequeue(struct ifaltq *, int); 96130365Smlaierstatic int tbr_timer = 0; /* token bucket regulator timer */ 97142178Smlaier#if !defined(__FreeBSD__) || (__FreeBSD_version < 600000) 98130365Smlaierstatic struct callout tbr_callout = CALLOUT_INITIALIZER; 99142178Smlaier#else 100142178Smlaierstatic struct callout tbr_callout; 101142178Smlaier#endif 102130365Smlaier 103130365Smlaier#ifdef ALTQ3_CLFIER_COMPAT 104130365Smlaierstatic int extract_ports4(struct mbuf *, struct ip *, struct flowinfo_in *); 105130365Smlaier#ifdef INET6 106130365Smlaierstatic int extract_ports6(struct mbuf *, struct ip6_hdr *, 107130365Smlaier struct flowinfo_in6 *); 108130365Smlaier#endif 109130365Smlaierstatic int apply_filter4(u_int32_t, struct flow_filter *, 110130365Smlaier struct flowinfo_in *); 111130365Smlaierstatic int apply_ppfilter4(u_int32_t, struct flow_filter *, 112130365Smlaier struct flowinfo_in *); 113130365Smlaier#ifdef INET6 114130365Smlaierstatic int apply_filter6(u_int32_t, struct flow_filter6 *, 115130365Smlaier struct flowinfo_in6 *); 116130365Smlaier#endif 117130365Smlaierstatic int apply_tosfilter4(u_int32_t, struct flow_filter *, 118130365Smlaier struct flowinfo_in *); 119130365Smlaierstatic u_long get_filt_handle(struct acc_classifier *, int); 120130365Smlaierstatic struct acc_filter *filth_to_filtp(struct acc_classifier *, u_long); 121130365Smlaierstatic u_int32_t filt2fibmask(struct flow_filter *); 122130365Smlaier 123130365Smlaierstatic void ip4f_cache(struct ip *, struct flowinfo_in *); 124130365Smlaierstatic int ip4f_lookup(struct ip *, struct flowinfo_in *); 125130365Smlaierstatic int ip4f_init(void); 126130365Smlaierstatic struct ip4_frag *ip4f_alloc(void); 127130365Smlaierstatic void ip4f_free(struct ip4_frag *); 128130365Smlaier#endif /* ALTQ3_CLFIER_COMPAT */ 129130365Smlaier 130130365Smlaier/* 131130365Smlaier * alternate queueing support routines 132130365Smlaier */ 133130365Smlaier 134130365Smlaier/* look up the queue state by the interface name and the queueing type. */ 135130365Smlaiervoid * 136130365Smlaieraltq_lookup(name, type) 137130365Smlaier char *name; 138130365Smlaier int type; 139130365Smlaier{ 140130365Smlaier struct ifnet *ifp; 141130365Smlaier 142130365Smlaier if ((ifp = ifunit(name)) != NULL) { 143130368Smlaier /* read if_snd unlocked */ 144130365Smlaier if (type != ALTQT_NONE && ifp->if_snd.altq_type == type) 145130365Smlaier return (ifp->if_snd.altq_disc); 146130365Smlaier } 147130365Smlaier 148130365Smlaier return NULL; 149130365Smlaier} 150130365Smlaier 151130365Smlaierint 152130365Smlaieraltq_attach(ifq, type, discipline, enqueue, dequeue, request, clfier, classify) 153130365Smlaier struct ifaltq *ifq; 154130365Smlaier int type; 155130365Smlaier void *discipline; 156130365Smlaier int (*enqueue)(struct ifaltq *, struct mbuf *, struct altq_pktattr *); 157130365Smlaier struct mbuf *(*dequeue)(struct ifaltq *, int); 158130365Smlaier int (*request)(struct ifaltq *, int, void *); 159130365Smlaier void *clfier; 160130365Smlaier void *(*classify)(void *, struct mbuf *, int); 161130365Smlaier{ 162130368Smlaier IFQ_LOCK(ifq); 163130368Smlaier if (!ALTQ_IS_READY(ifq)) { 164130368Smlaier IFQ_UNLOCK(ifq); 165130365Smlaier return ENXIO; 166130368Smlaier } 167130365Smlaier 168130365Smlaier#ifdef ALTQ3_COMPAT 169130365Smlaier /* 170130365Smlaier * pfaltq can override the existing discipline, but altq3 cannot. 171130365Smlaier * check these if clfier is not NULL (which implies altq3). 172130365Smlaier */ 173130365Smlaier if (clfier != NULL) { 174130368Smlaier if (ALTQ_IS_ENABLED(ifq)) { 175130368Smlaier IFQ_UNLOCK(ifq); 176130365Smlaier return EBUSY; 177130368Smlaier } 178130368Smlaier if (ALTQ_IS_ATTACHED(ifq)) { 179130368Smlaier IFQ_UNLOCK(ifq); 180130365Smlaier return EEXIST; 181130368Smlaier } 182130365Smlaier } 183130365Smlaier#endif 184130365Smlaier ifq->altq_type = type; 185130365Smlaier ifq->altq_disc = discipline; 186130365Smlaier ifq->altq_enqueue = enqueue; 187130365Smlaier ifq->altq_dequeue = dequeue; 188130365Smlaier ifq->altq_request = request; 189130365Smlaier ifq->altq_clfier = clfier; 190130365Smlaier ifq->altq_classify = classify; 191130365Smlaier ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED); 192130365Smlaier#ifdef ALTQ3_COMPAT 193130365Smlaier#ifdef ALTQ_KLD 194130365Smlaier altq_module_incref(type); 195130365Smlaier#endif 196130365Smlaier#endif 197130368Smlaier IFQ_UNLOCK(ifq); 198130365Smlaier return 0; 199130365Smlaier} 200130365Smlaier 201130365Smlaierint 202130365Smlaieraltq_detach(ifq) 203130365Smlaier struct ifaltq *ifq; 204130365Smlaier{ 205130368Smlaier IFQ_LOCK(ifq); 206130368Smlaier 207130368Smlaier if (!ALTQ_IS_READY(ifq)) { 208130368Smlaier IFQ_UNLOCK(ifq); 209130365Smlaier return ENXIO; 210130368Smlaier } 211130368Smlaier if (ALTQ_IS_ENABLED(ifq)) { 212130368Smlaier IFQ_UNLOCK(ifq); 213130365Smlaier return EBUSY; 214130368Smlaier } 215130368Smlaier if (!ALTQ_IS_ATTACHED(ifq)) { 216130368Smlaier IFQ_UNLOCK(ifq); 217130365Smlaier return (0); 218130368Smlaier } 219130365Smlaier#ifdef ALTQ3_COMPAT 220130365Smlaier#ifdef ALTQ_KLD 221130365Smlaier altq_module_declref(ifq->altq_type); 222130365Smlaier#endif 223130365Smlaier#endif 224130365Smlaier 225130365Smlaier ifq->altq_type = ALTQT_NONE; 226130365Smlaier ifq->altq_disc = NULL; 227130365Smlaier ifq->altq_enqueue = NULL; 228130365Smlaier ifq->altq_dequeue = NULL; 229130365Smlaier ifq->altq_request = NULL; 230130365Smlaier ifq->altq_clfier = NULL; 231130365Smlaier ifq->altq_classify = NULL; 232130365Smlaier ifq->altq_flags &= ALTQF_CANTCHANGE; 233130368Smlaier 234130368Smlaier IFQ_UNLOCK(ifq); 235130365Smlaier return 0; 236130365Smlaier} 237130365Smlaier 238130365Smlaierint 239130365Smlaieraltq_enable(ifq) 240130365Smlaier struct ifaltq *ifq; 241130365Smlaier{ 242130365Smlaier int s; 243130365Smlaier 244130368Smlaier IFQ_LOCK(ifq); 245130368Smlaier 246130368Smlaier if (!ALTQ_IS_READY(ifq)) { 247130368Smlaier IFQ_UNLOCK(ifq); 248130365Smlaier return ENXIO; 249130368Smlaier } 250130368Smlaier if (ALTQ_IS_ENABLED(ifq)) { 251130368Smlaier IFQ_UNLOCK(ifq); 252130365Smlaier return 0; 253130368Smlaier } 254130365Smlaier 255130365Smlaier#ifdef __NetBSD__ 256130365Smlaier s = splnet(); 257130365Smlaier#else 258130365Smlaier s = splimp(); 259130365Smlaier#endif 260130368Smlaier IFQ_PURGE_NOLOCK(ifq); 261130365Smlaier ASSERT(ifq->ifq_len == 0); 262130550Smlaier ifq->ifq_drv_maxlen = 0; /* disable bulk dequeue */ 263130365Smlaier ifq->altq_flags |= ALTQF_ENABLED; 264130365Smlaier if (ifq->altq_clfier != NULL) 265130365Smlaier ifq->altq_flags |= ALTQF_CLASSIFY; 266130365Smlaier splx(s); 267130365Smlaier 268130368Smlaier IFQ_UNLOCK(ifq); 269130365Smlaier return 0; 270130365Smlaier} 271130365Smlaier 272130365Smlaierint 273130365Smlaieraltq_disable(ifq) 274130365Smlaier struct ifaltq *ifq; 275130365Smlaier{ 276130365Smlaier int s; 277130365Smlaier 278130368Smlaier IFQ_LOCK(ifq); 279130368Smlaier if (!ALTQ_IS_ENABLED(ifq)) { 280130368Smlaier IFQ_UNLOCK(ifq); 281130365Smlaier return 0; 282130368Smlaier } 283130365Smlaier 284130365Smlaier#ifdef __NetBSD__ 285130365Smlaier s = splnet(); 286130365Smlaier#else 287130365Smlaier s = splimp(); 288130365Smlaier#endif 289130368Smlaier IFQ_PURGE_NOLOCK(ifq); 290130365Smlaier ASSERT(ifq->ifq_len == 0); 291130365Smlaier ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY); 292130365Smlaier splx(s); 293130368Smlaier 294130368Smlaier IFQ_UNLOCK(ifq); 295130365Smlaier return 0; 296130365Smlaier} 297130365Smlaier 298130365Smlaier#ifdef ALTQ_DEBUG 299130365Smlaiervoid 300130365Smlaieraltq_assert(file, line, failedexpr) 301130365Smlaier const char *file, *failedexpr; 302130365Smlaier int line; 303130365Smlaier{ 304130365Smlaier (void)printf("altq assertion \"%s\" failed: file \"%s\", line %d\n", 305130365Smlaier failedexpr, file, line); 306130365Smlaier panic("altq assertion"); 307130365Smlaier /* NOTREACHED */ 308130365Smlaier} 309130365Smlaier#endif 310130365Smlaier 311130365Smlaier/* 312130365Smlaier * internal representation of token bucket parameters 313130365Smlaier * rate: byte_per_unittime << 32 314130365Smlaier * (((bits_per_sec) / 8) << 32) / machclk_freq 315130365Smlaier * depth: byte << 32 316130365Smlaier * 317130365Smlaier */ 318130365Smlaier#define TBR_SHIFT 32 319130365Smlaier#define TBR_SCALE(x) ((int64_t)(x) << TBR_SHIFT) 320130365Smlaier#define TBR_UNSCALE(x) ((x) >> TBR_SHIFT) 321130365Smlaier 322130508Smlaierstatic struct mbuf * 323130365Smlaiertbr_dequeue(ifq, op) 324130365Smlaier struct ifaltq *ifq; 325130365Smlaier int op; 326130365Smlaier{ 327130365Smlaier struct tb_regulator *tbr; 328130365Smlaier struct mbuf *m; 329130365Smlaier int64_t interval; 330130365Smlaier u_int64_t now; 331130365Smlaier 332130368Smlaier IFQ_LOCK_ASSERT(ifq); 333130365Smlaier tbr = ifq->altq_tbr; 334130365Smlaier if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) { 335130365Smlaier /* if this is a remove after poll, bypass tbr check */ 336130365Smlaier } else { 337130365Smlaier /* update token only when it is negative */ 338130365Smlaier if (tbr->tbr_token <= 0) { 339130365Smlaier now = read_machclk(); 340130365Smlaier interval = now - tbr->tbr_last; 341130365Smlaier if (interval >= tbr->tbr_filluptime) 342130365Smlaier tbr->tbr_token = tbr->tbr_depth; 343130365Smlaier else { 344130365Smlaier tbr->tbr_token += interval * tbr->tbr_rate; 345130365Smlaier if (tbr->tbr_token > tbr->tbr_depth) 346130365Smlaier tbr->tbr_token = tbr->tbr_depth; 347130365Smlaier } 348130365Smlaier tbr->tbr_last = now; 349130365Smlaier } 350130365Smlaier /* if token is still negative, don't allow dequeue */ 351130365Smlaier if (tbr->tbr_token <= 0) 352130365Smlaier return (NULL); 353130365Smlaier } 354130365Smlaier 355130365Smlaier if (ALTQ_IS_ENABLED(ifq)) 356130365Smlaier m = (*ifq->altq_dequeue)(ifq, op); 357130365Smlaier else { 358130365Smlaier if (op == ALTDQ_POLL) 359130368Smlaier _IF_POLL(ifq, m); 360130365Smlaier else 361130368Smlaier _IF_DEQUEUE(ifq, m); 362130365Smlaier } 363130365Smlaier 364130365Smlaier if (m != NULL && op == ALTDQ_REMOVE) 365130365Smlaier tbr->tbr_token -= TBR_SCALE(m_pktlen(m)); 366130365Smlaier tbr->tbr_lastop = op; 367130365Smlaier return (m); 368130365Smlaier} 369130365Smlaier 370130365Smlaier/* 371130365Smlaier * set a token bucket regulator. 372130365Smlaier * if the specified rate is zero, the token bucket regulator is deleted. 373130365Smlaier */ 374130365Smlaierint 375130365Smlaiertbr_set(ifq, profile) 376130365Smlaier struct ifaltq *ifq; 377130365Smlaier struct tb_profile *profile; 378130365Smlaier{ 379130365Smlaier struct tb_regulator *tbr, *otbr; 380130508Smlaier 381130508Smlaier if (tbr_dequeue_ptr == NULL) 382130508Smlaier tbr_dequeue_ptr = tbr_dequeue; 383130365Smlaier 384130365Smlaier if (machclk_freq == 0) 385130365Smlaier init_machclk(); 386130365Smlaier if (machclk_freq == 0) { 387130365Smlaier printf("tbr_set: no cpu clock available!\n"); 388130365Smlaier return (ENXIO); 389130365Smlaier } 390130365Smlaier 391130368Smlaier IFQ_LOCK(ifq); 392130365Smlaier if (profile->rate == 0) { 393130365Smlaier /* delete this tbr */ 394130368Smlaier if ((tbr = ifq->altq_tbr) == NULL) { 395130368Smlaier IFQ_UNLOCK(ifq); 396130365Smlaier return (ENOENT); 397130368Smlaier } 398130365Smlaier ifq->altq_tbr = NULL; 399184205Sdes free(tbr, M_DEVBUF); 400130368Smlaier IFQ_UNLOCK(ifq); 401130365Smlaier return (0); 402130365Smlaier } 403130365Smlaier 404240233Sglebius tbr = malloc(sizeof(struct tb_regulator), M_DEVBUF, M_NOWAIT | M_ZERO); 405240233Sglebius if (tbr == NULL) { 406130368Smlaier IFQ_UNLOCK(ifq); 407130365Smlaier return (ENOMEM); 408130368Smlaier } 409130365Smlaier 410130365Smlaier tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq; 411130365Smlaier tbr->tbr_depth = TBR_SCALE(profile->depth); 412130365Smlaier if (tbr->tbr_rate > 0) 413130365Smlaier tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate; 414130365Smlaier else 415130365Smlaier tbr->tbr_filluptime = 0xffffffffffffffffLL; 416130365Smlaier tbr->tbr_token = tbr->tbr_depth; 417130365Smlaier tbr->tbr_last = read_machclk(); 418130365Smlaier tbr->tbr_lastop = ALTDQ_REMOVE; 419130365Smlaier 420130365Smlaier otbr = ifq->altq_tbr; 421130365Smlaier ifq->altq_tbr = tbr; /* set the new tbr */ 422130365Smlaier 423130365Smlaier if (otbr != NULL) 424184205Sdes free(otbr, M_DEVBUF); 425130365Smlaier else { 426130365Smlaier if (tbr_timer == 0) { 427130365Smlaier CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0); 428130365Smlaier tbr_timer = 1; 429130365Smlaier } 430130365Smlaier } 431130368Smlaier IFQ_UNLOCK(ifq); 432130365Smlaier return (0); 433130365Smlaier} 434130365Smlaier 435130365Smlaier/* 436130365Smlaier * tbr_timeout goes through the interface list, and kicks the drivers 437130365Smlaier * if necessary. 438130368Smlaier * 439130368Smlaier * MPSAFE 440130365Smlaier */ 441130365Smlaierstatic void 442130365Smlaiertbr_timeout(arg) 443130365Smlaier void *arg; 444130365Smlaier{ 445219457Sjkim#ifdef __FreeBSD__ 446192278Sbz VNET_ITERATOR_DECL(vnet_iter); 447192278Sbz#endif 448130365Smlaier struct ifnet *ifp; 449130365Smlaier int active, s; 450130365Smlaier 451130365Smlaier active = 0; 452130365Smlaier#ifdef __NetBSD__ 453130365Smlaier s = splnet(); 454130365Smlaier#else 455130365Smlaier s = splimp(); 456130365Smlaier#endif 457219457Sjkim#ifdef __FreeBSD__ 458196481Srwatson IFNET_RLOCK_NOSLEEP(); 459196481Srwatson VNET_LIST_RLOCK_NOSLEEP(); 460192278Sbz VNET_FOREACH(vnet_iter) { 461192278Sbz CURVNET_SET(vnet_iter); 462130368Smlaier#endif 463192278Sbz for (ifp = TAILQ_FIRST(&V_ifnet); ifp; 464192278Sbz ifp = TAILQ_NEXT(ifp, if_list)) { 465192278Sbz /* read from if_snd unlocked */ 466192278Sbz if (!TBR_IS_ENABLED(&ifp->if_snd)) 467192278Sbz continue; 468192278Sbz active++; 469192278Sbz if (!IFQ_IS_EMPTY(&ifp->if_snd) && 470192278Sbz ifp->if_start != NULL) 471192278Sbz (*ifp->if_start)(ifp); 472192278Sbz } 473219457Sjkim#ifdef __FreeBSD__ 474192278Sbz CURVNET_RESTORE(); 475130365Smlaier } 476196481Srwatson VNET_LIST_RUNLOCK_NOSLEEP(); 477196481Srwatson IFNET_RUNLOCK_NOSLEEP(); 478130368Smlaier#endif 479130365Smlaier splx(s); 480130365Smlaier if (active > 0) 481130365Smlaier CALLOUT_RESET(&tbr_callout, 1, tbr_timeout, (void *)0); 482130365Smlaier else 483130365Smlaier tbr_timer = 0; /* don't need tbr_timer anymore */ 484130365Smlaier} 485130365Smlaier 486130365Smlaier/* 487130365Smlaier * get token bucket regulator profile 488130365Smlaier */ 489130365Smlaierint 490130365Smlaiertbr_get(ifq, profile) 491130365Smlaier struct ifaltq *ifq; 492130365Smlaier struct tb_profile *profile; 493130365Smlaier{ 494130365Smlaier struct tb_regulator *tbr; 495130365Smlaier 496130368Smlaier IFQ_LOCK(ifq); 497130365Smlaier if ((tbr = ifq->altq_tbr) == NULL) { 498130365Smlaier profile->rate = 0; 499130365Smlaier profile->depth = 0; 500130365Smlaier } else { 501130365Smlaier profile->rate = 502130365Smlaier (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq); 503130365Smlaier profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth); 504130365Smlaier } 505130368Smlaier IFQ_UNLOCK(ifq); 506130365Smlaier return (0); 507130365Smlaier} 508130365Smlaier 509130365Smlaier/* 510130365Smlaier * attach a discipline to the interface. if one already exists, it is 511130365Smlaier * overridden. 512130368Smlaier * Locking is done in the discipline specific attach functions. Basically 513130368Smlaier * they call back to altq_attach which takes care of the attach and locking. 514130365Smlaier */ 515130365Smlaierint 516130365Smlaieraltq_pfattach(struct pf_altq *a) 517130365Smlaier{ 518130365Smlaier int error = 0; 519130365Smlaier 520130365Smlaier switch (a->scheduler) { 521130365Smlaier case ALTQT_NONE: 522130365Smlaier break; 523130365Smlaier#ifdef ALTQ_CBQ 524130365Smlaier case ALTQT_CBQ: 525130365Smlaier error = cbq_pfattach(a); 526130365Smlaier break; 527130365Smlaier#endif 528130365Smlaier#ifdef ALTQ_PRIQ 529130365Smlaier case ALTQT_PRIQ: 530130365Smlaier error = priq_pfattach(a); 531130365Smlaier break; 532130365Smlaier#endif 533130365Smlaier#ifdef ALTQ_HFSC 534130365Smlaier case ALTQT_HFSC: 535130365Smlaier error = hfsc_pfattach(a); 536130365Smlaier break; 537130365Smlaier#endif 538130365Smlaier default: 539130365Smlaier error = ENXIO; 540130365Smlaier } 541130365Smlaier 542130365Smlaier return (error); 543130365Smlaier} 544130365Smlaier 545130365Smlaier/* 546130365Smlaier * detach a discipline from the interface. 547130365Smlaier * it is possible that the discipline was already overridden by another 548130365Smlaier * discipline. 549130365Smlaier */ 550130365Smlaierint 551130365Smlaieraltq_pfdetach(struct pf_altq *a) 552130365Smlaier{ 553130365Smlaier struct ifnet *ifp; 554130365Smlaier int s, error = 0; 555130365Smlaier 556130365Smlaier if ((ifp = ifunit(a->ifname)) == NULL) 557130365Smlaier return (EINVAL); 558130365Smlaier 559130365Smlaier /* if this discipline is no longer referenced, just return */ 560130368Smlaier /* read unlocked from if_snd */ 561130365Smlaier if (a->altq_disc == NULL || a->altq_disc != ifp->if_snd.altq_disc) 562130365Smlaier return (0); 563130365Smlaier 564130365Smlaier#ifdef __NetBSD__ 565130365Smlaier s = splnet(); 566130365Smlaier#else 567130365Smlaier s = splimp(); 568130365Smlaier#endif 569130368Smlaier /* read unlocked from if_snd, _disable and _detach take care */ 570130365Smlaier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 571130365Smlaier error = altq_disable(&ifp->if_snd); 572130365Smlaier if (error == 0) 573130365Smlaier error = altq_detach(&ifp->if_snd); 574130365Smlaier splx(s); 575130365Smlaier 576130365Smlaier return (error); 577130365Smlaier} 578130365Smlaier 579130365Smlaier/* 580130365Smlaier * add a discipline or a queue 581130368Smlaier * Locking is done in the discipline specific functions with regards to 582130368Smlaier * malloc with WAITOK, also it is not yet clear which lock to use. 583130365Smlaier */ 584130365Smlaierint 585130365Smlaieraltq_add(struct pf_altq *a) 586130365Smlaier{ 587130365Smlaier int error = 0; 588130365Smlaier 589130365Smlaier if (a->qname[0] != 0) 590130365Smlaier return (altq_add_queue(a)); 591130365Smlaier 592130365Smlaier if (machclk_freq == 0) 593130365Smlaier init_machclk(); 594130365Smlaier if (machclk_freq == 0) 595130365Smlaier panic("altq_add: no cpu clock"); 596130365Smlaier 597130365Smlaier switch (a->scheduler) { 598130365Smlaier#ifdef ALTQ_CBQ 599130365Smlaier case ALTQT_CBQ: 600130365Smlaier error = cbq_add_altq(a); 601130365Smlaier break; 602130365Smlaier#endif 603130365Smlaier#ifdef ALTQ_PRIQ 604130365Smlaier case ALTQT_PRIQ: 605130365Smlaier error = priq_add_altq(a); 606130365Smlaier break; 607130365Smlaier#endif 608130365Smlaier#ifdef ALTQ_HFSC 609130365Smlaier case ALTQT_HFSC: 610130365Smlaier error = hfsc_add_altq(a); 611130365Smlaier break; 612130365Smlaier#endif 613130365Smlaier default: 614130365Smlaier error = ENXIO; 615130365Smlaier } 616130365Smlaier 617130365Smlaier return (error); 618130365Smlaier} 619130365Smlaier 620130365Smlaier/* 621130365Smlaier * remove a discipline or a queue 622130368Smlaier * It is yet unclear what lock to use to protect this operation, the 623130368Smlaier * discipline specific functions will determine and grab it 624130365Smlaier */ 625130365Smlaierint 626130365Smlaieraltq_remove(struct pf_altq *a) 627130365Smlaier{ 628130365Smlaier int error = 0; 629130365Smlaier 630130365Smlaier if (a->qname[0] != 0) 631130365Smlaier return (altq_remove_queue(a)); 632130365Smlaier 633130365Smlaier switch (a->scheduler) { 634130365Smlaier#ifdef ALTQ_CBQ 635130365Smlaier case ALTQT_CBQ: 636130365Smlaier error = cbq_remove_altq(a); 637130365Smlaier break; 638130365Smlaier#endif 639130365Smlaier#ifdef ALTQ_PRIQ 640130365Smlaier case ALTQT_PRIQ: 641130365Smlaier error = priq_remove_altq(a); 642130365Smlaier break; 643130365Smlaier#endif 644130365Smlaier#ifdef ALTQ_HFSC 645130365Smlaier case ALTQT_HFSC: 646130365Smlaier error = hfsc_remove_altq(a); 647130365Smlaier break; 648130365Smlaier#endif 649130365Smlaier default: 650130365Smlaier error = ENXIO; 651130365Smlaier } 652130365Smlaier 653130365Smlaier return (error); 654130365Smlaier} 655130365Smlaier 656130365Smlaier/* 657130365Smlaier * add a queue to the discipline 658130368Smlaier * It is yet unclear what lock to use to protect this operation, the 659130368Smlaier * discipline specific functions will determine and grab it 660130365Smlaier */ 661130365Smlaierint 662130365Smlaieraltq_add_queue(struct pf_altq *a) 663130365Smlaier{ 664130365Smlaier int error = 0; 665130365Smlaier 666130365Smlaier switch (a->scheduler) { 667130365Smlaier#ifdef ALTQ_CBQ 668130365Smlaier case ALTQT_CBQ: 669130365Smlaier error = cbq_add_queue(a); 670130365Smlaier break; 671130365Smlaier#endif 672130365Smlaier#ifdef ALTQ_PRIQ 673130365Smlaier case ALTQT_PRIQ: 674130365Smlaier error = priq_add_queue(a); 675130365Smlaier break; 676130365Smlaier#endif 677130365Smlaier#ifdef ALTQ_HFSC 678130365Smlaier case ALTQT_HFSC: 679130365Smlaier error = hfsc_add_queue(a); 680130365Smlaier break; 681130365Smlaier#endif 682130365Smlaier default: 683130365Smlaier error = ENXIO; 684130365Smlaier } 685130365Smlaier 686130365Smlaier return (error); 687130365Smlaier} 688130365Smlaier 689130365Smlaier/* 690130365Smlaier * remove a queue from the discipline 691130368Smlaier * It is yet unclear what lock to use to protect this operation, the 692130368Smlaier * discipline specific functions will determine and grab it 693130365Smlaier */ 694130365Smlaierint 695130365Smlaieraltq_remove_queue(struct pf_altq *a) 696130365Smlaier{ 697130365Smlaier int error = 0; 698130365Smlaier 699130365Smlaier switch (a->scheduler) { 700130365Smlaier#ifdef ALTQ_CBQ 701130365Smlaier case ALTQT_CBQ: 702130365Smlaier error = cbq_remove_queue(a); 703130365Smlaier break; 704130365Smlaier#endif 705130365Smlaier#ifdef ALTQ_PRIQ 706130365Smlaier case ALTQT_PRIQ: 707130365Smlaier error = priq_remove_queue(a); 708130365Smlaier break; 709130365Smlaier#endif 710130365Smlaier#ifdef ALTQ_HFSC 711130365Smlaier case ALTQT_HFSC: 712130365Smlaier error = hfsc_remove_queue(a); 713130365Smlaier break; 714130365Smlaier#endif 715130365Smlaier default: 716130365Smlaier error = ENXIO; 717130365Smlaier } 718130365Smlaier 719130365Smlaier return (error); 720130365Smlaier} 721130365Smlaier 722130365Smlaier/* 723130365Smlaier * get queue statistics 724130368Smlaier * Locking is done in the discipline specific functions with regards to 725130368Smlaier * copyout operations, also it is not yet clear which lock to use. 726130365Smlaier */ 727130365Smlaierint 728130365Smlaieraltq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes) 729130365Smlaier{ 730130365Smlaier int error = 0; 731130365Smlaier 732130365Smlaier switch (a->scheduler) { 733130365Smlaier#ifdef ALTQ_CBQ 734130365Smlaier case ALTQT_CBQ: 735130365Smlaier error = cbq_getqstats(a, ubuf, nbytes); 736130365Smlaier break; 737130365Smlaier#endif 738130365Smlaier#ifdef ALTQ_PRIQ 739130365Smlaier case ALTQT_PRIQ: 740130365Smlaier error = priq_getqstats(a, ubuf, nbytes); 741130365Smlaier break; 742130365Smlaier#endif 743130365Smlaier#ifdef ALTQ_HFSC 744130365Smlaier case ALTQT_HFSC: 745130365Smlaier error = hfsc_getqstats(a, ubuf, nbytes); 746130365Smlaier break; 747130365Smlaier#endif 748130365Smlaier default: 749130365Smlaier error = ENXIO; 750130365Smlaier } 751130365Smlaier 752130365Smlaier return (error); 753130365Smlaier} 754130365Smlaier 755130365Smlaier/* 756130365Smlaier * read and write diffserv field in IPv4 or IPv6 header 757130365Smlaier */ 758130365Smlaieru_int8_t 759130365Smlaierread_dsfield(m, pktattr) 760130365Smlaier struct mbuf *m; 761130365Smlaier struct altq_pktattr *pktattr; 762130365Smlaier{ 763130365Smlaier struct mbuf *m0; 764130365Smlaier u_int8_t ds_field = 0; 765130365Smlaier 766130365Smlaier if (pktattr == NULL || 767130365Smlaier (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6)) 768130365Smlaier return ((u_int8_t)0); 769130365Smlaier 770130365Smlaier /* verify that pattr_hdr is within the mbuf data */ 771130365Smlaier for (m0 = m; m0 != NULL; m0 = m0->m_next) 772130365Smlaier if ((pktattr->pattr_hdr >= m0->m_data) && 773130365Smlaier (pktattr->pattr_hdr < m0->m_data + m0->m_len)) 774130365Smlaier break; 775130365Smlaier if (m0 == NULL) { 776130365Smlaier /* ick, pattr_hdr is stale */ 777130365Smlaier pktattr->pattr_af = AF_UNSPEC; 778130365Smlaier#ifdef ALTQ_DEBUG 779130365Smlaier printf("read_dsfield: can't locate header!\n"); 780130365Smlaier#endif 781130365Smlaier return ((u_int8_t)0); 782130365Smlaier } 783130365Smlaier 784130365Smlaier if (pktattr->pattr_af == AF_INET) { 785130365Smlaier struct ip *ip = (struct ip *)pktattr->pattr_hdr; 786130365Smlaier 787130365Smlaier if (ip->ip_v != 4) 788130365Smlaier return ((u_int8_t)0); /* version mismatch! */ 789130365Smlaier ds_field = ip->ip_tos; 790130365Smlaier } 791130365Smlaier#ifdef INET6 792130365Smlaier else if (pktattr->pattr_af == AF_INET6) { 793130365Smlaier struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr; 794130365Smlaier u_int32_t flowlabel; 795130365Smlaier 796130365Smlaier flowlabel = ntohl(ip6->ip6_flow); 797130365Smlaier if ((flowlabel >> 28) != 6) 798130365Smlaier return ((u_int8_t)0); /* version mismatch! */ 799130365Smlaier ds_field = (flowlabel >> 20) & 0xff; 800130365Smlaier } 801130365Smlaier#endif 802130365Smlaier return (ds_field); 803130365Smlaier} 804130365Smlaier 805130365Smlaiervoid 806189004Srdivackywrite_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, u_int8_t dsfield) 807130365Smlaier{ 808130365Smlaier struct mbuf *m0; 809130365Smlaier 810130365Smlaier if (pktattr == NULL || 811130365Smlaier (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6)) 812130365Smlaier return; 813130365Smlaier 814130365Smlaier /* verify that pattr_hdr is within the mbuf data */ 815130365Smlaier for (m0 = m; m0 != NULL; m0 = m0->m_next) 816130365Smlaier if ((pktattr->pattr_hdr >= m0->m_data) && 817130365Smlaier (pktattr->pattr_hdr < m0->m_data + m0->m_len)) 818130365Smlaier break; 819130365Smlaier if (m0 == NULL) { 820130365Smlaier /* ick, pattr_hdr is stale */ 821130365Smlaier pktattr->pattr_af = AF_UNSPEC; 822130365Smlaier#ifdef ALTQ_DEBUG 823130365Smlaier printf("write_dsfield: can't locate header!\n"); 824130365Smlaier#endif 825130365Smlaier return; 826130365Smlaier } 827130365Smlaier 828130365Smlaier if (pktattr->pattr_af == AF_INET) { 829130365Smlaier struct ip *ip = (struct ip *)pktattr->pattr_hdr; 830130365Smlaier u_int8_t old; 831130365Smlaier int32_t sum; 832130365Smlaier 833130365Smlaier if (ip->ip_v != 4) 834130365Smlaier return; /* version mismatch! */ 835130365Smlaier old = ip->ip_tos; 836130365Smlaier dsfield |= old & 3; /* leave CU bits */ 837130365Smlaier if (old == dsfield) 838130365Smlaier return; 839130365Smlaier ip->ip_tos = dsfield; 840130365Smlaier /* 841130365Smlaier * update checksum (from RFC1624) 842130365Smlaier * HC' = ~(~HC + ~m + m') 843130365Smlaier */ 844130365Smlaier sum = ~ntohs(ip->ip_sum) & 0xffff; 845130365Smlaier sum += 0xff00 + (~old & 0xff) + dsfield; 846130365Smlaier sum = (sum >> 16) + (sum & 0xffff); 847130365Smlaier sum += (sum >> 16); /* add carry */ 848130365Smlaier 849130365Smlaier ip->ip_sum = htons(~sum & 0xffff); 850130365Smlaier } 851130365Smlaier#ifdef INET6 852130365Smlaier else if (pktattr->pattr_af == AF_INET6) { 853130365Smlaier struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr; 854130365Smlaier u_int32_t flowlabel; 855130365Smlaier 856130365Smlaier flowlabel = ntohl(ip6->ip6_flow); 857130365Smlaier if ((flowlabel >> 28) != 6) 858130365Smlaier return; /* version mismatch! */ 859130365Smlaier flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20); 860130365Smlaier ip6->ip6_flow = htonl(flowlabel); 861130365Smlaier } 862130365Smlaier#endif 863130365Smlaier return; 864130365Smlaier} 865130365Smlaier 866130365Smlaier 867130365Smlaier/* 868130365Smlaier * high resolution clock support taking advantage of a machine dependent 869130365Smlaier * high resolution time counter (e.g., timestamp counter of intel pentium). 870130365Smlaier * we assume 871130365Smlaier * - 64-bit-long monotonically-increasing counter 872130365Smlaier * - frequency range is 100M-4GHz (CPU speed) 873130365Smlaier */ 874130365Smlaier/* if pcc is not available or disabled, emulate 256MHz using microtime() */ 875130365Smlaier#define MACHCLK_SHIFT 8 876130365Smlaier 877130365Smlaierint machclk_usepcc; 878171407Snjlu_int32_t machclk_freq; 879171407Snjlu_int32_t machclk_per_tick; 880130365Smlaier 881130365Smlaier#if defined(__i386__) && defined(__NetBSD__) 882130365Smlaierextern u_int64_t cpu_tsc_freq; 883219459Sjkim#endif 884130365Smlaier 885167905Snjl#if (__FreeBSD_version >= 700035) 886167905Snjl/* Update TSC freq with the value indicated by the caller. */ 887167905Snjlstatic void 888167905Snjltsc_freq_changed(void *arg, const struct cf_level *level, int status) 889167905Snjl{ 890167905Snjl /* If there was an error during the transition, don't do anything. */ 891167905Snjl if (status != 0) 892167905Snjl return; 893167905Snjl 894187566Sjkim#if (__FreeBSD_version >= 701102) && (defined(__amd64__) || defined(__i386__)) 895184102Sjkim /* If TSC is P-state invariant, don't do anything. */ 896184102Sjkim if (tsc_is_invariant) 897184102Sjkim return; 898184102Sjkim#endif 899184102Sjkim 900167905Snjl /* Total setting for this level gives the new frequency in MHz. */ 901171407Snjl init_machclk(); 902167905Snjl} 903167905SnjlEVENTHANDLER_DEFINE(cpufreq_post_change, tsc_freq_changed, NULL, 904171407Snjl EVENTHANDLER_PRI_LAST); 905167905Snjl#endif /* __FreeBSD_version >= 700035 */ 906167905Snjl 907171407Snjlstatic void 908171407Snjlinit_machclk_setup(void) 909130365Smlaier{ 910142201Sgreen#if (__FreeBSD_version >= 600000) 911142201Sgreen callout_init(&tbr_callout, 0); 912142201Sgreen#endif 913142201Sgreen 914130365Smlaier machclk_usepcc = 1; 915130365Smlaier 916219459Sjkim#if (!defined(__amd64__) && !defined(__i386__)) || defined(ALTQ_NOPCC) 917130365Smlaier machclk_usepcc = 0; 918130365Smlaier#endif 919130365Smlaier#if defined(__FreeBSD__) && defined(SMP) 920130365Smlaier machclk_usepcc = 0; 921130365Smlaier#endif 922130365Smlaier#if defined(__NetBSD__) && defined(MULTIPROCESSOR) 923130365Smlaier machclk_usepcc = 0; 924130365Smlaier#endif 925219458Sjkim#if defined(__amd64__) || defined(__i386__) 926130365Smlaier /* check if TSC is available */ 927219461Sjkim#ifdef __FreeBSD__ 928220433Sjkim if ((cpu_feature & CPUID_TSC) == 0 || 929220433Sjkim atomic_load_acq_64(&tsc_freq) == 0) 930219461Sjkim#else 931219461Sjkim if ((cpu_feature & CPUID_TSC) == 0) 932219461Sjkim#endif 933130365Smlaier machclk_usepcc = 0; 934130365Smlaier#endif 935171407Snjl} 936130365Smlaier 937171407Snjlvoid 938171407Snjlinit_machclk(void) 939171407Snjl{ 940171407Snjl static int called; 941171407Snjl 942171407Snjl /* Call one-time initialization function. */ 943171407Snjl if (!called) { 944171407Snjl init_machclk_setup(); 945171407Snjl called = 1; 946171407Snjl } 947171407Snjl 948130365Smlaier if (machclk_usepcc == 0) { 949130365Smlaier /* emulate 256MHz using microtime() */ 950130365Smlaier machclk_freq = 1000000 << MACHCLK_SHIFT; 951130365Smlaier machclk_per_tick = machclk_freq / hz; 952130365Smlaier#ifdef ALTQ_DEBUG 953130365Smlaier printf("altq: emulate %uHz cpu clock\n", machclk_freq); 954130365Smlaier#endif 955130365Smlaier return; 956130365Smlaier } 957130365Smlaier 958130365Smlaier /* 959130365Smlaier * if the clock frequency (of Pentium TSC or Alpha PCC) is 960130365Smlaier * accessible, just use it. 961130365Smlaier */ 962219458Sjkim#if defined(__amd64__) || defined(__i386__) 963130365Smlaier#ifdef __FreeBSD__ 964220433Sjkim machclk_freq = atomic_load_acq_64(&tsc_freq); 965130365Smlaier#elif defined(__NetBSD__) 966130365Smlaier machclk_freq = (u_int32_t)cpu_tsc_freq; 967130365Smlaier#elif defined(__OpenBSD__) && (defined(I586_CPU) || defined(I686_CPU)) 968130365Smlaier machclk_freq = pentium_mhz * 1000000; 969130365Smlaier#endif 970130365Smlaier#endif 971130365Smlaier 972130365Smlaier /* 973130365Smlaier * if we don't know the clock frequency, measure it. 974130365Smlaier */ 975130365Smlaier if (machclk_freq == 0) { 976130365Smlaier static int wait; 977130365Smlaier struct timeval tv_start, tv_end; 978130365Smlaier u_int64_t start, end, diff; 979130365Smlaier int timo; 980130365Smlaier 981130365Smlaier microtime(&tv_start); 982130365Smlaier start = read_machclk(); 983130365Smlaier timo = hz; /* 1 sec */ 984130365Smlaier (void)tsleep(&wait, PWAIT | PCATCH, "init_machclk", timo); 985130365Smlaier microtime(&tv_end); 986130365Smlaier end = read_machclk(); 987130365Smlaier diff = (u_int64_t)(tv_end.tv_sec - tv_start.tv_sec) * 1000000 988130365Smlaier + tv_end.tv_usec - tv_start.tv_usec; 989130365Smlaier if (diff != 0) 990130365Smlaier machclk_freq = (u_int)((end - start) * 1000000 / diff); 991130365Smlaier } 992130365Smlaier 993130365Smlaier machclk_per_tick = machclk_freq / hz; 994130365Smlaier 995130365Smlaier#ifdef ALTQ_DEBUG 996130365Smlaier printf("altq: CPU clock: %uHz\n", machclk_freq); 997130365Smlaier#endif 998130365Smlaier} 999130365Smlaier 1000130365Smlaier#if defined(__OpenBSD__) && defined(__i386__) 1001130365Smlaierstatic __inline u_int64_t 1002130365Smlaierrdtsc(void) 1003130365Smlaier{ 1004130365Smlaier u_int64_t rv; 1005130365Smlaier __asm __volatile(".byte 0x0f, 0x31" : "=A" (rv)); 1006130365Smlaier return (rv); 1007130365Smlaier} 1008130365Smlaier#endif /* __OpenBSD__ && __i386__ */ 1009130365Smlaier 1010130365Smlaieru_int64_t 1011130365Smlaierread_machclk(void) 1012130365Smlaier{ 1013130365Smlaier u_int64_t val; 1014130365Smlaier 1015130365Smlaier if (machclk_usepcc) { 1016219458Sjkim#if defined(__amd64__) || defined(__i386__) 1017130365Smlaier val = rdtsc(); 1018130365Smlaier#else 1019130365Smlaier panic("read_machclk"); 1020130365Smlaier#endif 1021130365Smlaier } else { 1022130365Smlaier struct timeval tv; 1023130365Smlaier 1024130365Smlaier microtime(&tv); 1025130365Smlaier val = (((u_int64_t)(tv.tv_sec - boottime.tv_sec) * 1000000 1026130365Smlaier + tv.tv_usec) << MACHCLK_SHIFT); 1027130365Smlaier } 1028130365Smlaier return (val); 1029130365Smlaier} 1030130365Smlaier 1031130365Smlaier#ifdef ALTQ3_CLFIER_COMPAT 1032130365Smlaier 1033130365Smlaier#ifndef IPPROTO_ESP 1034130365Smlaier#define IPPROTO_ESP 50 /* encapsulating security payload */ 1035130365Smlaier#endif 1036130365Smlaier#ifndef IPPROTO_AH 1037130365Smlaier#define IPPROTO_AH 51 /* authentication header */ 1038130365Smlaier#endif 1039130365Smlaier 1040130365Smlaier/* 1041130365Smlaier * extract flow information from a given packet. 1042130365Smlaier * filt_mask shows flowinfo fields required. 1043130365Smlaier * we assume the ip header is in one mbuf, and addresses and ports are 1044130365Smlaier * in network byte order. 1045130365Smlaier */ 1046130365Smlaierint 1047130365Smlaieraltq_extractflow(m, af, flow, filt_bmask) 1048130365Smlaier struct mbuf *m; 1049130365Smlaier int af; 1050130365Smlaier struct flowinfo *flow; 1051130365Smlaier u_int32_t filt_bmask; 1052130365Smlaier{ 1053130365Smlaier 1054130365Smlaier switch (af) { 1055130365Smlaier case PF_INET: { 1056130365Smlaier struct flowinfo_in *fin; 1057130365Smlaier struct ip *ip; 1058130365Smlaier 1059130365Smlaier ip = mtod(m, struct ip *); 1060130365Smlaier 1061130365Smlaier if (ip->ip_v != 4) 1062130365Smlaier break; 1063130365Smlaier 1064130365Smlaier fin = (struct flowinfo_in *)flow; 1065130365Smlaier fin->fi_len = sizeof(struct flowinfo_in); 1066130365Smlaier fin->fi_family = AF_INET; 1067130365Smlaier 1068130365Smlaier fin->fi_proto = ip->ip_p; 1069130365Smlaier fin->fi_tos = ip->ip_tos; 1070130365Smlaier 1071130365Smlaier fin->fi_src.s_addr = ip->ip_src.s_addr; 1072130365Smlaier fin->fi_dst.s_addr = ip->ip_dst.s_addr; 1073130365Smlaier 1074130365Smlaier if (filt_bmask & FIMB4_PORTS) 1075130365Smlaier /* if port info is required, extract port numbers */ 1076130365Smlaier extract_ports4(m, ip, fin); 1077130365Smlaier else { 1078130365Smlaier fin->fi_sport = 0; 1079130365Smlaier fin->fi_dport = 0; 1080130365Smlaier fin->fi_gpi = 0; 1081130365Smlaier } 1082130365Smlaier return (1); 1083130365Smlaier } 1084130365Smlaier 1085130365Smlaier#ifdef INET6 1086130365Smlaier case PF_INET6: { 1087130365Smlaier struct flowinfo_in6 *fin6; 1088130365Smlaier struct ip6_hdr *ip6; 1089130365Smlaier 1090130365Smlaier ip6 = mtod(m, struct ip6_hdr *); 1091130365Smlaier /* should we check the ip version? */ 1092130365Smlaier 1093130365Smlaier fin6 = (struct flowinfo_in6 *)flow; 1094130365Smlaier fin6->fi6_len = sizeof(struct flowinfo_in6); 1095130365Smlaier fin6->fi6_family = AF_INET6; 1096130365Smlaier 1097130365Smlaier fin6->fi6_proto = ip6->ip6_nxt; 1098130365Smlaier fin6->fi6_tclass = (ntohl(ip6->ip6_flow) >> 20) & 0xff; 1099130365Smlaier 1100130365Smlaier fin6->fi6_flowlabel = ip6->ip6_flow & htonl(0x000fffff); 1101130365Smlaier fin6->fi6_src = ip6->ip6_src; 1102130365Smlaier fin6->fi6_dst = ip6->ip6_dst; 1103130365Smlaier 1104130365Smlaier if ((filt_bmask & FIMB6_PORTS) || 1105130365Smlaier ((filt_bmask & FIMB6_PROTO) 1106130365Smlaier && ip6->ip6_nxt > IPPROTO_IPV6)) 1107130365Smlaier /* 1108130365Smlaier * if port info is required, or proto is required 1109130365Smlaier * but there are option headers, extract port 1110130365Smlaier * and protocol numbers. 1111130365Smlaier */ 1112130365Smlaier extract_ports6(m, ip6, fin6); 1113130365Smlaier else { 1114130365Smlaier fin6->fi6_sport = 0; 1115130365Smlaier fin6->fi6_dport = 0; 1116130365Smlaier fin6->fi6_gpi = 0; 1117130365Smlaier } 1118130365Smlaier return (1); 1119130365Smlaier } 1120130365Smlaier#endif /* INET6 */ 1121130365Smlaier 1122130365Smlaier default: 1123130365Smlaier break; 1124130365Smlaier } 1125130365Smlaier 1126130365Smlaier /* failed */ 1127130365Smlaier flow->fi_len = sizeof(struct flowinfo); 1128130365Smlaier flow->fi_family = AF_UNSPEC; 1129130365Smlaier return (0); 1130130365Smlaier} 1131130365Smlaier 1132130365Smlaier/* 1133130365Smlaier * helper routine to extract port numbers 1134130365Smlaier */ 1135130365Smlaier/* structure for ipsec and ipv6 option header template */ 1136130365Smlaierstruct _opt6 { 1137130365Smlaier u_int8_t opt6_nxt; /* next header */ 1138130365Smlaier u_int8_t opt6_hlen; /* header extension length */ 1139130365Smlaier u_int16_t _pad; 1140130365Smlaier u_int32_t ah_spi; /* security parameter index 1141130365Smlaier for authentication header */ 1142130365Smlaier}; 1143130365Smlaier 1144130365Smlaier/* 1145130365Smlaier * extract port numbers from a ipv4 packet. 1146130365Smlaier */ 1147130365Smlaierstatic int 1148130365Smlaierextract_ports4(m, ip, fin) 1149130365Smlaier struct mbuf *m; 1150130365Smlaier struct ip *ip; 1151130365Smlaier struct flowinfo_in *fin; 1152130365Smlaier{ 1153130365Smlaier struct mbuf *m0; 1154130365Smlaier u_short ip_off; 1155130365Smlaier u_int8_t proto; 1156130365Smlaier int off; 1157130365Smlaier 1158130365Smlaier fin->fi_sport = 0; 1159130365Smlaier fin->fi_dport = 0; 1160130365Smlaier fin->fi_gpi = 0; 1161130365Smlaier 1162130365Smlaier ip_off = ntohs(ip->ip_off); 1163130365Smlaier /* if it is a fragment, try cached fragment info */ 1164130365Smlaier if (ip_off & IP_OFFMASK) { 1165130365Smlaier ip4f_lookup(ip, fin); 1166130365Smlaier return (1); 1167130365Smlaier } 1168130365Smlaier 1169130365Smlaier /* locate the mbuf containing the protocol header */ 1170130365Smlaier for (m0 = m; m0 != NULL; m0 = m0->m_next) 1171130365Smlaier if (((caddr_t)ip >= m0->m_data) && 1172130365Smlaier ((caddr_t)ip < m0->m_data + m0->m_len)) 1173130365Smlaier break; 1174130365Smlaier if (m0 == NULL) { 1175130365Smlaier#ifdef ALTQ_DEBUG 1176130365Smlaier printf("extract_ports4: can't locate header! ip=%p\n", ip); 1177130365Smlaier#endif 1178130365Smlaier return (0); 1179130365Smlaier } 1180130365Smlaier off = ((caddr_t)ip - m0->m_data) + (ip->ip_hl << 2); 1181130365Smlaier proto = ip->ip_p; 1182130365Smlaier 1183130365Smlaier#ifdef ALTQ_IPSEC 1184130365Smlaier again: 1185130365Smlaier#endif 1186130365Smlaier while (off >= m0->m_len) { 1187130365Smlaier off -= m0->m_len; 1188130365Smlaier m0 = m0->m_next; 1189130365Smlaier if (m0 == NULL) 1190130365Smlaier return (0); /* bogus ip_hl! */ 1191130365Smlaier } 1192130365Smlaier if (m0->m_len < off + 4) 1193130365Smlaier return (0); 1194130365Smlaier 1195130365Smlaier switch (proto) { 1196130365Smlaier case IPPROTO_TCP: 1197130365Smlaier case IPPROTO_UDP: { 1198130365Smlaier struct udphdr *udp; 1199130365Smlaier 1200130365Smlaier udp = (struct udphdr *)(mtod(m0, caddr_t) + off); 1201130365Smlaier fin->fi_sport = udp->uh_sport; 1202130365Smlaier fin->fi_dport = udp->uh_dport; 1203130365Smlaier fin->fi_proto = proto; 1204130365Smlaier } 1205130365Smlaier break; 1206130365Smlaier 1207130365Smlaier#ifdef ALTQ_IPSEC 1208130365Smlaier case IPPROTO_ESP: 1209130365Smlaier if (fin->fi_gpi == 0){ 1210130365Smlaier u_int32_t *gpi; 1211130365Smlaier 1212130365Smlaier gpi = (u_int32_t *)(mtod(m0, caddr_t) + off); 1213130365Smlaier fin->fi_gpi = *gpi; 1214130365Smlaier } 1215130365Smlaier fin->fi_proto = proto; 1216130365Smlaier break; 1217130365Smlaier 1218130365Smlaier case IPPROTO_AH: { 1219130365Smlaier /* get next header and header length */ 1220130365Smlaier struct _opt6 *opt6; 1221130365Smlaier 1222130365Smlaier opt6 = (struct _opt6 *)(mtod(m0, caddr_t) + off); 1223130365Smlaier proto = opt6->opt6_nxt; 1224130365Smlaier off += 8 + (opt6->opt6_hlen * 4); 1225130365Smlaier if (fin->fi_gpi == 0 && m0->m_len >= off + 8) 1226130365Smlaier fin->fi_gpi = opt6->ah_spi; 1227130365Smlaier } 1228130365Smlaier /* goto the next header */ 1229130365Smlaier goto again; 1230130365Smlaier#endif /* ALTQ_IPSEC */ 1231130365Smlaier 1232130365Smlaier default: 1233130365Smlaier fin->fi_proto = proto; 1234130365Smlaier return (0); 1235130365Smlaier } 1236130365Smlaier 1237130365Smlaier /* if this is a first fragment, cache it. */ 1238130365Smlaier if (ip_off & IP_MF) 1239130365Smlaier ip4f_cache(ip, fin); 1240130365Smlaier 1241130365Smlaier return (1); 1242130365Smlaier} 1243130365Smlaier 1244130365Smlaier#ifdef INET6 1245130365Smlaierstatic int 1246130365Smlaierextract_ports6(m, ip6, fin6) 1247130365Smlaier struct mbuf *m; 1248130365Smlaier struct ip6_hdr *ip6; 1249130365Smlaier struct flowinfo_in6 *fin6; 1250130365Smlaier{ 1251130365Smlaier struct mbuf *m0; 1252130365Smlaier int off; 1253130365Smlaier u_int8_t proto; 1254130365Smlaier 1255130365Smlaier fin6->fi6_gpi = 0; 1256130365Smlaier fin6->fi6_sport = 0; 1257130365Smlaier fin6->fi6_dport = 0; 1258130365Smlaier 1259130365Smlaier /* locate the mbuf containing the protocol header */ 1260130365Smlaier for (m0 = m; m0 != NULL; m0 = m0->m_next) 1261130365Smlaier if (((caddr_t)ip6 >= m0->m_data) && 1262130365Smlaier ((caddr_t)ip6 < m0->m_data + m0->m_len)) 1263130365Smlaier break; 1264130365Smlaier if (m0 == NULL) { 1265130365Smlaier#ifdef ALTQ_DEBUG 1266130365Smlaier printf("extract_ports6: can't locate header! ip6=%p\n", ip6); 1267130365Smlaier#endif 1268130365Smlaier return (0); 1269130365Smlaier } 1270130365Smlaier off = ((caddr_t)ip6 - m0->m_data) + sizeof(struct ip6_hdr); 1271130365Smlaier 1272130365Smlaier proto = ip6->ip6_nxt; 1273130365Smlaier do { 1274130365Smlaier while (off >= m0->m_len) { 1275130365Smlaier off -= m0->m_len; 1276130365Smlaier m0 = m0->m_next; 1277130365Smlaier if (m0 == NULL) 1278130365Smlaier return (0); 1279130365Smlaier } 1280130365Smlaier if (m0->m_len < off + 4) 1281130365Smlaier return (0); 1282130365Smlaier 1283130365Smlaier switch (proto) { 1284130365Smlaier case IPPROTO_TCP: 1285130365Smlaier case IPPROTO_UDP: { 1286130365Smlaier struct udphdr *udp; 1287130365Smlaier 1288130365Smlaier udp = (struct udphdr *)(mtod(m0, caddr_t) + off); 1289130365Smlaier fin6->fi6_sport = udp->uh_sport; 1290130365Smlaier fin6->fi6_dport = udp->uh_dport; 1291130365Smlaier fin6->fi6_proto = proto; 1292130365Smlaier } 1293130365Smlaier return (1); 1294130365Smlaier 1295130365Smlaier case IPPROTO_ESP: 1296130365Smlaier if (fin6->fi6_gpi == 0) { 1297130365Smlaier u_int32_t *gpi; 1298130365Smlaier 1299130365Smlaier gpi = (u_int32_t *)(mtod(m0, caddr_t) + off); 1300130365Smlaier fin6->fi6_gpi = *gpi; 1301130365Smlaier } 1302130365Smlaier fin6->fi6_proto = proto; 1303130365Smlaier return (1); 1304130365Smlaier 1305130365Smlaier case IPPROTO_AH: { 1306130365Smlaier /* get next header and header length */ 1307130365Smlaier struct _opt6 *opt6; 1308130365Smlaier 1309130365Smlaier opt6 = (struct _opt6 *)(mtod(m0, caddr_t) + off); 1310130365Smlaier if (fin6->fi6_gpi == 0 && m0->m_len >= off + 8) 1311130365Smlaier fin6->fi6_gpi = opt6->ah_spi; 1312130365Smlaier proto = opt6->opt6_nxt; 1313130365Smlaier off += 8 + (opt6->opt6_hlen * 4); 1314130365Smlaier /* goto the next header */ 1315130365Smlaier break; 1316130365Smlaier } 1317130365Smlaier 1318130365Smlaier case IPPROTO_HOPOPTS: 1319130365Smlaier case IPPROTO_ROUTING: 1320130365Smlaier case IPPROTO_DSTOPTS: { 1321130365Smlaier /* get next header and header length */ 1322130365Smlaier struct _opt6 *opt6; 1323130365Smlaier 1324130365Smlaier opt6 = (struct _opt6 *)(mtod(m0, caddr_t) + off); 1325130365Smlaier proto = opt6->opt6_nxt; 1326130365Smlaier off += (opt6->opt6_hlen + 1) * 8; 1327130365Smlaier /* goto the next header */ 1328130365Smlaier break; 1329130365Smlaier } 1330130365Smlaier 1331130365Smlaier case IPPROTO_FRAGMENT: 1332130365Smlaier /* ipv6 fragmentations are not supported yet */ 1333130365Smlaier default: 1334130365Smlaier fin6->fi6_proto = proto; 1335130365Smlaier return (0); 1336130365Smlaier } 1337130365Smlaier } while (1); 1338130365Smlaier /*NOTREACHED*/ 1339130365Smlaier} 1340130365Smlaier#endif /* INET6 */ 1341130365Smlaier 1342130365Smlaier/* 1343130365Smlaier * altq common classifier 1344130365Smlaier */ 1345130365Smlaierint 1346130365Smlaieracc_add_filter(classifier, filter, class, phandle) 1347130365Smlaier struct acc_classifier *classifier; 1348130365Smlaier struct flow_filter *filter; 1349130365Smlaier void *class; 1350130365Smlaier u_long *phandle; 1351130365Smlaier{ 1352130365Smlaier struct acc_filter *afp, *prev, *tmp; 1353130365Smlaier int i, s; 1354130365Smlaier 1355130365Smlaier#ifdef INET6 1356130365Smlaier if (filter->ff_flow.fi_family != AF_INET && 1357130365Smlaier filter->ff_flow.fi_family != AF_INET6) 1358130365Smlaier return (EINVAL); 1359130365Smlaier#else 1360130365Smlaier if (filter->ff_flow.fi_family != AF_INET) 1361130365Smlaier return (EINVAL); 1362130365Smlaier#endif 1363130365Smlaier 1364184205Sdes afp = malloc(sizeof(struct acc_filter), 1365130365Smlaier M_DEVBUF, M_WAITOK); 1366130365Smlaier if (afp == NULL) 1367130365Smlaier return (ENOMEM); 1368130365Smlaier bzero(afp, sizeof(struct acc_filter)); 1369130365Smlaier 1370130365Smlaier afp->f_filter = *filter; 1371130365Smlaier afp->f_class = class; 1372130365Smlaier 1373130365Smlaier i = ACC_WILDCARD_INDEX; 1374130365Smlaier if (filter->ff_flow.fi_family == AF_INET) { 1375130365Smlaier struct flow_filter *filter4 = &afp->f_filter; 1376130365Smlaier 1377130365Smlaier /* 1378130365Smlaier * if address is 0, it's a wildcard. if address mask 1379130365Smlaier * isn't set, use full mask. 1380130365Smlaier */ 1381130365Smlaier if (filter4->ff_flow.fi_dst.s_addr == 0) 1382130365Smlaier filter4->ff_mask.mask_dst.s_addr = 0; 1383130365Smlaier else if (filter4->ff_mask.mask_dst.s_addr == 0) 1384130365Smlaier filter4->ff_mask.mask_dst.s_addr = 0xffffffff; 1385130365Smlaier if (filter4->ff_flow.fi_src.s_addr == 0) 1386130365Smlaier filter4->ff_mask.mask_src.s_addr = 0; 1387130365Smlaier else if (filter4->ff_mask.mask_src.s_addr == 0) 1388130365Smlaier filter4->ff_mask.mask_src.s_addr = 0xffffffff; 1389130365Smlaier 1390130365Smlaier /* clear extra bits in addresses */ 1391130365Smlaier filter4->ff_flow.fi_dst.s_addr &= 1392130365Smlaier filter4->ff_mask.mask_dst.s_addr; 1393130365Smlaier filter4->ff_flow.fi_src.s_addr &= 1394130365Smlaier filter4->ff_mask.mask_src.s_addr; 1395130365Smlaier 1396130365Smlaier /* 1397130365Smlaier * if dst address is a wildcard, use hash-entry 1398130365Smlaier * ACC_WILDCARD_INDEX. 1399130365Smlaier */ 1400130365Smlaier if (filter4->ff_mask.mask_dst.s_addr != 0xffffffff) 1401130365Smlaier i = ACC_WILDCARD_INDEX; 1402130365Smlaier else 1403130365Smlaier i = ACC_GET_HASH_INDEX(filter4->ff_flow.fi_dst.s_addr); 1404130365Smlaier } 1405130365Smlaier#ifdef INET6 1406130365Smlaier else if (filter->ff_flow.fi_family == AF_INET6) { 1407130365Smlaier struct flow_filter6 *filter6 = 1408130365Smlaier (struct flow_filter6 *)&afp->f_filter; 1409130365Smlaier#ifndef IN6MASK0 /* taken from kame ipv6 */ 1410130365Smlaier#define IN6MASK0 {{{ 0, 0, 0, 0 }}} 1411130365Smlaier#define IN6MASK128 {{{ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }}} 1412130365Smlaier const struct in6_addr in6mask0 = IN6MASK0; 1413130365Smlaier const struct in6_addr in6mask128 = IN6MASK128; 1414130365Smlaier#endif 1415130365Smlaier 1416130365Smlaier if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_dst)) 1417130365Smlaier filter6->ff_mask6.mask6_dst = in6mask0; 1418130365Smlaier else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_dst)) 1419130365Smlaier filter6->ff_mask6.mask6_dst = in6mask128; 1420130365Smlaier if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_flow6.fi6_src)) 1421130365Smlaier filter6->ff_mask6.mask6_src = in6mask0; 1422130365Smlaier else if (IN6_IS_ADDR_UNSPECIFIED(&filter6->ff_mask6.mask6_src)) 1423130365Smlaier filter6->ff_mask6.mask6_src = in6mask128; 1424130365Smlaier 1425130365Smlaier /* clear extra bits in addresses */ 1426130365Smlaier for (i = 0; i < 16; i++) 1427130365Smlaier filter6->ff_flow6.fi6_dst.s6_addr[i] &= 1428130365Smlaier filter6->ff_mask6.mask6_dst.s6_addr[i]; 1429130365Smlaier for (i = 0; i < 16; i++) 1430130365Smlaier filter6->ff_flow6.fi6_src.s6_addr[i] &= 1431130365Smlaier filter6->ff_mask6.mask6_src.s6_addr[i]; 1432130365Smlaier 1433130365Smlaier if (filter6->ff_flow6.fi6_flowlabel == 0) 1434130365Smlaier i = ACC_WILDCARD_INDEX; 1435130365Smlaier else 1436130365Smlaier i = ACC_GET_HASH_INDEX(filter6->ff_flow6.fi6_flowlabel); 1437130365Smlaier } 1438130365Smlaier#endif /* INET6 */ 1439130365Smlaier 1440130365Smlaier afp->f_handle = get_filt_handle(classifier, i); 1441130365Smlaier 1442130365Smlaier /* update filter bitmask */ 1443130365Smlaier afp->f_fbmask = filt2fibmask(filter); 1444130365Smlaier classifier->acc_fbmask |= afp->f_fbmask; 1445130365Smlaier 1446130365Smlaier /* 1447130365Smlaier * add this filter to the filter list. 1448130365Smlaier * filters are ordered from the highest rule number. 1449130365Smlaier */ 1450130365Smlaier#ifdef __NetBSD__ 1451130365Smlaier s = splnet(); 1452130365Smlaier#else 1453130365Smlaier s = splimp(); 1454130365Smlaier#endif 1455130365Smlaier prev = NULL; 1456130365Smlaier LIST_FOREACH(tmp, &classifier->acc_filters[i], f_chain) { 1457130365Smlaier if (tmp->f_filter.ff_ruleno > afp->f_filter.ff_ruleno) 1458130365Smlaier prev = tmp; 1459130365Smlaier else 1460130365Smlaier break; 1461130365Smlaier } 1462130365Smlaier if (prev == NULL) 1463130365Smlaier LIST_INSERT_HEAD(&classifier->acc_filters[i], afp, f_chain); 1464130365Smlaier else 1465130365Smlaier LIST_INSERT_AFTER(prev, afp, f_chain); 1466130365Smlaier splx(s); 1467130365Smlaier 1468130365Smlaier *phandle = afp->f_handle; 1469130365Smlaier return (0); 1470130365Smlaier} 1471130365Smlaier 1472130365Smlaierint 1473130365Smlaieracc_delete_filter(classifier, handle) 1474130365Smlaier struct acc_classifier *classifier; 1475130365Smlaier u_long handle; 1476130365Smlaier{ 1477130365Smlaier struct acc_filter *afp; 1478130365Smlaier int s; 1479130365Smlaier 1480130365Smlaier if ((afp = filth_to_filtp(classifier, handle)) == NULL) 1481130365Smlaier return (EINVAL); 1482130365Smlaier 1483130365Smlaier#ifdef __NetBSD__ 1484130365Smlaier s = splnet(); 1485130365Smlaier#else 1486130365Smlaier s = splimp(); 1487130365Smlaier#endif 1488130365Smlaier LIST_REMOVE(afp, f_chain); 1489130365Smlaier splx(s); 1490130365Smlaier 1491184205Sdes free(afp, M_DEVBUF); 1492130365Smlaier 1493130365Smlaier /* todo: update filt_bmask */ 1494130365Smlaier 1495130365Smlaier return (0); 1496130365Smlaier} 1497130365Smlaier 1498130365Smlaier/* 1499130365Smlaier * delete filters referencing to the specified class. 1500130365Smlaier * if the all flag is not 0, delete all the filters. 1501130365Smlaier */ 1502130365Smlaierint 1503130365Smlaieracc_discard_filters(classifier, class, all) 1504130365Smlaier struct acc_classifier *classifier; 1505130365Smlaier void *class; 1506130365Smlaier int all; 1507130365Smlaier{ 1508130365Smlaier struct acc_filter *afp; 1509130365Smlaier int i, s; 1510130365Smlaier 1511130365Smlaier#ifdef __NetBSD__ 1512130365Smlaier s = splnet(); 1513130365Smlaier#else 1514130365Smlaier s = splimp(); 1515130365Smlaier#endif 1516130365Smlaier for (i = 0; i < ACC_FILTER_TABLESIZE; i++) { 1517130365Smlaier do { 1518130365Smlaier LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain) 1519130365Smlaier if (all || afp->f_class == class) { 1520130365Smlaier LIST_REMOVE(afp, f_chain); 1521184205Sdes free(afp, M_DEVBUF); 1522130365Smlaier /* start again from the head */ 1523130365Smlaier break; 1524130365Smlaier } 1525130365Smlaier } while (afp != NULL); 1526130365Smlaier } 1527130365Smlaier splx(s); 1528130365Smlaier 1529130365Smlaier if (all) 1530130365Smlaier classifier->acc_fbmask = 0; 1531130365Smlaier 1532130365Smlaier return (0); 1533130365Smlaier} 1534130365Smlaier 1535130365Smlaiervoid * 1536130365Smlaieracc_classify(clfier, m, af) 1537130365Smlaier void *clfier; 1538130365Smlaier struct mbuf *m; 1539130365Smlaier int af; 1540130365Smlaier{ 1541130365Smlaier struct acc_classifier *classifier; 1542130365Smlaier struct flowinfo flow; 1543130365Smlaier struct acc_filter *afp; 1544130365Smlaier int i; 1545130365Smlaier 1546130365Smlaier classifier = (struct acc_classifier *)clfier; 1547130365Smlaier altq_extractflow(m, af, &flow, classifier->acc_fbmask); 1548130365Smlaier 1549130365Smlaier if (flow.fi_family == AF_INET) { 1550130365Smlaier struct flowinfo_in *fp = (struct flowinfo_in *)&flow; 1551130365Smlaier 1552130365Smlaier if ((classifier->acc_fbmask & FIMB4_ALL) == FIMB4_TOS) { 1553130365Smlaier /* only tos is used */ 1554130365Smlaier LIST_FOREACH(afp, 1555130365Smlaier &classifier->acc_filters[ACC_WILDCARD_INDEX], 1556130365Smlaier f_chain) 1557130365Smlaier if (apply_tosfilter4(afp->f_fbmask, 1558130365Smlaier &afp->f_filter, fp)) 1559130365Smlaier /* filter matched */ 1560130365Smlaier return (afp->f_class); 1561130365Smlaier } else if ((classifier->acc_fbmask & 1562130365Smlaier (~(FIMB4_PROTO|FIMB4_SPORT|FIMB4_DPORT) & FIMB4_ALL)) 1563130365Smlaier == 0) { 1564130365Smlaier /* only proto and ports are used */ 1565130365Smlaier LIST_FOREACH(afp, 1566130365Smlaier &classifier->acc_filters[ACC_WILDCARD_INDEX], 1567130365Smlaier f_chain) 1568130365Smlaier if (apply_ppfilter4(afp->f_fbmask, 1569130365Smlaier &afp->f_filter, fp)) 1570130365Smlaier /* filter matched */ 1571130365Smlaier return (afp->f_class); 1572130365Smlaier } else { 1573130365Smlaier /* get the filter hash entry from its dest address */ 1574130365Smlaier i = ACC_GET_HASH_INDEX(fp->fi_dst.s_addr); 1575130365Smlaier do { 1576130365Smlaier /* 1577130365Smlaier * go through this loop twice. first for dst 1578130365Smlaier * hash, second for wildcards. 1579130365Smlaier */ 1580130365Smlaier LIST_FOREACH(afp, &classifier->acc_filters[i], 1581130365Smlaier f_chain) 1582130365Smlaier if (apply_filter4(afp->f_fbmask, 1583130365Smlaier &afp->f_filter, fp)) 1584130365Smlaier /* filter matched */ 1585130365Smlaier return (afp->f_class); 1586130365Smlaier 1587130365Smlaier /* 1588130365Smlaier * check again for filters with a dst addr 1589130365Smlaier * wildcard. 1590130365Smlaier * (daddr == 0 || dmask != 0xffffffff). 1591130365Smlaier */ 1592130365Smlaier if (i != ACC_WILDCARD_INDEX) 1593130365Smlaier i = ACC_WILDCARD_INDEX; 1594130365Smlaier else 1595130365Smlaier break; 1596130365Smlaier } while (1); 1597130365Smlaier } 1598130365Smlaier } 1599130365Smlaier#ifdef INET6 1600130365Smlaier else if (flow.fi_family == AF_INET6) { 1601130365Smlaier struct flowinfo_in6 *fp6 = (struct flowinfo_in6 *)&flow; 1602130365Smlaier 1603130365Smlaier /* get the filter hash entry from its flow ID */ 1604130365Smlaier if (fp6->fi6_flowlabel != 0) 1605130365Smlaier i = ACC_GET_HASH_INDEX(fp6->fi6_flowlabel); 1606130365Smlaier else 1607130365Smlaier /* flowlable can be zero */ 1608130365Smlaier i = ACC_WILDCARD_INDEX; 1609130365Smlaier 1610130365Smlaier /* go through this loop twice. first for flow hash, second 1611130365Smlaier for wildcards. */ 1612130365Smlaier do { 1613130365Smlaier LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain) 1614130365Smlaier if (apply_filter6(afp->f_fbmask, 1615130365Smlaier (struct flow_filter6 *)&afp->f_filter, 1616130365Smlaier fp6)) 1617130365Smlaier /* filter matched */ 1618130365Smlaier return (afp->f_class); 1619130365Smlaier 1620130365Smlaier /* 1621130365Smlaier * check again for filters with a wildcard. 1622130365Smlaier */ 1623130365Smlaier if (i != ACC_WILDCARD_INDEX) 1624130365Smlaier i = ACC_WILDCARD_INDEX; 1625130365Smlaier else 1626130365Smlaier break; 1627130365Smlaier } while (1); 1628130365Smlaier } 1629130365Smlaier#endif /* INET6 */ 1630130365Smlaier 1631130365Smlaier /* no filter matched */ 1632130365Smlaier return (NULL); 1633130365Smlaier} 1634130365Smlaier 1635130365Smlaierstatic int 1636130365Smlaierapply_filter4(fbmask, filt, pkt) 1637130365Smlaier u_int32_t fbmask; 1638130365Smlaier struct flow_filter *filt; 1639130365Smlaier struct flowinfo_in *pkt; 1640130365Smlaier{ 1641130365Smlaier if (filt->ff_flow.fi_family != AF_INET) 1642130365Smlaier return (0); 1643130365Smlaier if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport) 1644130365Smlaier return (0); 1645130365Smlaier if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport) 1646130365Smlaier return (0); 1647130365Smlaier if ((fbmask & FIMB4_DADDR) && 1648130365Smlaier filt->ff_flow.fi_dst.s_addr != 1649130365Smlaier (pkt->fi_dst.s_addr & filt->ff_mask.mask_dst.s_addr)) 1650130365Smlaier return (0); 1651130365Smlaier if ((fbmask & FIMB4_SADDR) && 1652130365Smlaier filt->ff_flow.fi_src.s_addr != 1653130365Smlaier (pkt->fi_src.s_addr & filt->ff_mask.mask_src.s_addr)) 1654130365Smlaier return (0); 1655130365Smlaier if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto) 1656130365Smlaier return (0); 1657130365Smlaier if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos != 1658130365Smlaier (pkt->fi_tos & filt->ff_mask.mask_tos)) 1659130365Smlaier return (0); 1660130365Smlaier if ((fbmask & FIMB4_GPI) && filt->ff_flow.fi_gpi != (pkt->fi_gpi)) 1661130365Smlaier return (0); 1662130365Smlaier /* match */ 1663130365Smlaier return (1); 1664130365Smlaier} 1665130365Smlaier 1666130365Smlaier/* 1667130365Smlaier * filter matching function optimized for a common case that checks 1668130365Smlaier * only protocol and port numbers 1669130365Smlaier */ 1670130365Smlaierstatic int 1671130365Smlaierapply_ppfilter4(fbmask, filt, pkt) 1672130365Smlaier u_int32_t fbmask; 1673130365Smlaier struct flow_filter *filt; 1674130365Smlaier struct flowinfo_in *pkt; 1675130365Smlaier{ 1676130365Smlaier if (filt->ff_flow.fi_family != AF_INET) 1677130365Smlaier return (0); 1678130365Smlaier if ((fbmask & FIMB4_SPORT) && filt->ff_flow.fi_sport != pkt->fi_sport) 1679130365Smlaier return (0); 1680130365Smlaier if ((fbmask & FIMB4_DPORT) && filt->ff_flow.fi_dport != pkt->fi_dport) 1681130365Smlaier return (0); 1682130365Smlaier if ((fbmask & FIMB4_PROTO) && filt->ff_flow.fi_proto != pkt->fi_proto) 1683130365Smlaier return (0); 1684130365Smlaier /* match */ 1685130365Smlaier return (1); 1686130365Smlaier} 1687130365Smlaier 1688130365Smlaier/* 1689130365Smlaier * filter matching function only for tos field. 1690130365Smlaier */ 1691130365Smlaierstatic int 1692130365Smlaierapply_tosfilter4(fbmask, filt, pkt) 1693130365Smlaier u_int32_t fbmask; 1694130365Smlaier struct flow_filter *filt; 1695130365Smlaier struct flowinfo_in *pkt; 1696130365Smlaier{ 1697130365Smlaier if (filt->ff_flow.fi_family != AF_INET) 1698130365Smlaier return (0); 1699130365Smlaier if ((fbmask & FIMB4_TOS) && filt->ff_flow.fi_tos != 1700130365Smlaier (pkt->fi_tos & filt->ff_mask.mask_tos)) 1701130365Smlaier return (0); 1702130365Smlaier /* match */ 1703130365Smlaier return (1); 1704130365Smlaier} 1705130365Smlaier 1706130365Smlaier#ifdef INET6 1707130365Smlaierstatic int 1708130365Smlaierapply_filter6(fbmask, filt, pkt) 1709130365Smlaier u_int32_t fbmask; 1710130365Smlaier struct flow_filter6 *filt; 1711130365Smlaier struct flowinfo_in6 *pkt; 1712130365Smlaier{ 1713130365Smlaier int i; 1714130365Smlaier 1715130365Smlaier if (filt->ff_flow6.fi6_family != AF_INET6) 1716130365Smlaier return (0); 1717130365Smlaier if ((fbmask & FIMB6_FLABEL) && 1718130365Smlaier filt->ff_flow6.fi6_flowlabel != pkt->fi6_flowlabel) 1719130365Smlaier return (0); 1720130365Smlaier if ((fbmask & FIMB6_PROTO) && 1721130365Smlaier filt->ff_flow6.fi6_proto != pkt->fi6_proto) 1722130365Smlaier return (0); 1723130365Smlaier if ((fbmask & FIMB6_SPORT) && 1724130365Smlaier filt->ff_flow6.fi6_sport != pkt->fi6_sport) 1725130365Smlaier return (0); 1726130365Smlaier if ((fbmask & FIMB6_DPORT) && 1727130365Smlaier filt->ff_flow6.fi6_dport != pkt->fi6_dport) 1728130365Smlaier return (0); 1729130365Smlaier if (fbmask & FIMB6_SADDR) { 1730130365Smlaier for (i = 0; i < 4; i++) 1731130365Smlaier if (filt->ff_flow6.fi6_src.s6_addr32[i] != 1732130365Smlaier (pkt->fi6_src.s6_addr32[i] & 1733130365Smlaier filt->ff_mask6.mask6_src.s6_addr32[i])) 1734130365Smlaier return (0); 1735130365Smlaier } 1736130365Smlaier if (fbmask & FIMB6_DADDR) { 1737130365Smlaier for (i = 0; i < 4; i++) 1738130365Smlaier if (filt->ff_flow6.fi6_dst.s6_addr32[i] != 1739130365Smlaier (pkt->fi6_dst.s6_addr32[i] & 1740130365Smlaier filt->ff_mask6.mask6_dst.s6_addr32[i])) 1741130365Smlaier return (0); 1742130365Smlaier } 1743130365Smlaier if ((fbmask & FIMB6_TCLASS) && 1744130365Smlaier filt->ff_flow6.fi6_tclass != 1745130365Smlaier (pkt->fi6_tclass & filt->ff_mask6.mask6_tclass)) 1746130365Smlaier return (0); 1747130365Smlaier if ((fbmask & FIMB6_GPI) && 1748130365Smlaier filt->ff_flow6.fi6_gpi != pkt->fi6_gpi) 1749130365Smlaier return (0); 1750130365Smlaier /* match */ 1751130365Smlaier return (1); 1752130365Smlaier} 1753130365Smlaier#endif /* INET6 */ 1754130365Smlaier 1755130365Smlaier/* 1756130365Smlaier * filter handle: 1757130365Smlaier * bit 20-28: index to the filter hash table 1758130365Smlaier * bit 0-19: unique id in the hash bucket. 1759130365Smlaier */ 1760130365Smlaierstatic u_long 1761130365Smlaierget_filt_handle(classifier, i) 1762130365Smlaier struct acc_classifier *classifier; 1763130365Smlaier int i; 1764130365Smlaier{ 1765130365Smlaier static u_long handle_number = 1; 1766130365Smlaier u_long handle; 1767130365Smlaier struct acc_filter *afp; 1768130365Smlaier 1769130365Smlaier while (1) { 1770130365Smlaier handle = handle_number++ & 0x000fffff; 1771130365Smlaier 1772130365Smlaier if (LIST_EMPTY(&classifier->acc_filters[i])) 1773130365Smlaier break; 1774130365Smlaier 1775130365Smlaier LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain) 1776130365Smlaier if ((afp->f_handle & 0x000fffff) == handle) 1777130365Smlaier break; 1778130365Smlaier if (afp == NULL) 1779130365Smlaier break; 1780130365Smlaier /* this handle is already used, try again */ 1781130365Smlaier } 1782130365Smlaier 1783130365Smlaier return ((i << 20) | handle); 1784130365Smlaier} 1785130365Smlaier 1786130365Smlaier/* convert filter handle to filter pointer */ 1787130365Smlaierstatic struct acc_filter * 1788130365Smlaierfilth_to_filtp(classifier, handle) 1789130365Smlaier struct acc_classifier *classifier; 1790130365Smlaier u_long handle; 1791130365Smlaier{ 1792130365Smlaier struct acc_filter *afp; 1793130365Smlaier int i; 1794130365Smlaier 1795130365Smlaier i = ACC_GET_HINDEX(handle); 1796130365Smlaier 1797130365Smlaier LIST_FOREACH(afp, &classifier->acc_filters[i], f_chain) 1798130365Smlaier if (afp->f_handle == handle) 1799130365Smlaier return (afp); 1800130365Smlaier 1801130365Smlaier return (NULL); 1802130365Smlaier} 1803130365Smlaier 1804130365Smlaier/* create flowinfo bitmask */ 1805130365Smlaierstatic u_int32_t 1806130365Smlaierfilt2fibmask(filt) 1807130365Smlaier struct flow_filter *filt; 1808130365Smlaier{ 1809130365Smlaier u_int32_t mask = 0; 1810130365Smlaier#ifdef INET6 1811130365Smlaier struct flow_filter6 *filt6; 1812130365Smlaier#endif 1813130365Smlaier 1814130365Smlaier switch (filt->ff_flow.fi_family) { 1815130365Smlaier case AF_INET: 1816130365Smlaier if (filt->ff_flow.fi_proto != 0) 1817130365Smlaier mask |= FIMB4_PROTO; 1818130365Smlaier if (filt->ff_flow.fi_tos != 0) 1819130365Smlaier mask |= FIMB4_TOS; 1820130365Smlaier if (filt->ff_flow.fi_dst.s_addr != 0) 1821130365Smlaier mask |= FIMB4_DADDR; 1822130365Smlaier if (filt->ff_flow.fi_src.s_addr != 0) 1823130365Smlaier mask |= FIMB4_SADDR; 1824130365Smlaier if (filt->ff_flow.fi_sport != 0) 1825130365Smlaier mask |= FIMB4_SPORT; 1826130365Smlaier if (filt->ff_flow.fi_dport != 0) 1827130365Smlaier mask |= FIMB4_DPORT; 1828130365Smlaier if (filt->ff_flow.fi_gpi != 0) 1829130365Smlaier mask |= FIMB4_GPI; 1830130365Smlaier break; 1831130365Smlaier#ifdef INET6 1832130365Smlaier case AF_INET6: 1833130365Smlaier filt6 = (struct flow_filter6 *)filt; 1834130365Smlaier 1835130365Smlaier if (filt6->ff_flow6.fi6_proto != 0) 1836130365Smlaier mask |= FIMB6_PROTO; 1837130365Smlaier if (filt6->ff_flow6.fi6_tclass != 0) 1838130365Smlaier mask |= FIMB6_TCLASS; 1839130365Smlaier if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_dst)) 1840130365Smlaier mask |= FIMB6_DADDR; 1841130365Smlaier if (!IN6_IS_ADDR_UNSPECIFIED(&filt6->ff_flow6.fi6_src)) 1842130365Smlaier mask |= FIMB6_SADDR; 1843130365Smlaier if (filt6->ff_flow6.fi6_sport != 0) 1844130365Smlaier mask |= FIMB6_SPORT; 1845130365Smlaier if (filt6->ff_flow6.fi6_dport != 0) 1846130365Smlaier mask |= FIMB6_DPORT; 1847130365Smlaier if (filt6->ff_flow6.fi6_gpi != 0) 1848130365Smlaier mask |= FIMB6_GPI; 1849130365Smlaier if (filt6->ff_flow6.fi6_flowlabel != 0) 1850130365Smlaier mask |= FIMB6_FLABEL; 1851130365Smlaier break; 1852130365Smlaier#endif /* INET6 */ 1853130365Smlaier } 1854130365Smlaier return (mask); 1855130365Smlaier} 1856130365Smlaier 1857130365Smlaier 1858130365Smlaier/* 1859130365Smlaier * helper functions to handle IPv4 fragments. 1860130365Smlaier * currently only in-sequence fragments are handled. 1861130365Smlaier * - fragment info is cached in a LRU list. 1862130365Smlaier * - when a first fragment is found, cache its flow info. 1863130365Smlaier * - when a non-first fragment is found, lookup the cache. 1864130365Smlaier */ 1865130365Smlaier 1866130365Smlaierstruct ip4_frag { 1867130365Smlaier TAILQ_ENTRY(ip4_frag) ip4f_chain; 1868130365Smlaier char ip4f_valid; 1869130365Smlaier u_short ip4f_id; 1870130365Smlaier struct flowinfo_in ip4f_info; 1871130365Smlaier}; 1872130365Smlaier 1873130365Smlaierstatic TAILQ_HEAD(ip4f_list, ip4_frag) ip4f_list; /* IPv4 fragment cache */ 1874130365Smlaier 1875130365Smlaier#define IP4F_TABSIZE 16 /* IPv4 fragment cache size */ 1876130365Smlaier 1877130365Smlaier 1878130365Smlaierstatic void 1879130365Smlaierip4f_cache(ip, fin) 1880130365Smlaier struct ip *ip; 1881130365Smlaier struct flowinfo_in *fin; 1882130365Smlaier{ 1883130365Smlaier struct ip4_frag *fp; 1884130365Smlaier 1885130365Smlaier if (TAILQ_EMPTY(&ip4f_list)) { 1886130365Smlaier /* first time call, allocate fragment cache entries. */ 1887130365Smlaier if (ip4f_init() < 0) 1888130365Smlaier /* allocation failed! */ 1889130365Smlaier return; 1890130365Smlaier } 1891130365Smlaier 1892130365Smlaier fp = ip4f_alloc(); 1893130365Smlaier fp->ip4f_id = ip->ip_id; 1894130365Smlaier fp->ip4f_info.fi_proto = ip->ip_p; 1895130365Smlaier fp->ip4f_info.fi_src.s_addr = ip->ip_src.s_addr; 1896130365Smlaier fp->ip4f_info.fi_dst.s_addr = ip->ip_dst.s_addr; 1897130365Smlaier 1898130365Smlaier /* save port numbers */ 1899130365Smlaier fp->ip4f_info.fi_sport = fin->fi_sport; 1900130365Smlaier fp->ip4f_info.fi_dport = fin->fi_dport; 1901130365Smlaier fp->ip4f_info.fi_gpi = fin->fi_gpi; 1902130365Smlaier} 1903130365Smlaier 1904130365Smlaierstatic int 1905130365Smlaierip4f_lookup(ip, fin) 1906130365Smlaier struct ip *ip; 1907130365Smlaier struct flowinfo_in *fin; 1908130365Smlaier{ 1909130365Smlaier struct ip4_frag *fp; 1910130365Smlaier 1911130365Smlaier for (fp = TAILQ_FIRST(&ip4f_list); fp != NULL && fp->ip4f_valid; 1912130365Smlaier fp = TAILQ_NEXT(fp, ip4f_chain)) 1913130365Smlaier if (ip->ip_id == fp->ip4f_id && 1914130365Smlaier ip->ip_src.s_addr == fp->ip4f_info.fi_src.s_addr && 1915130365Smlaier ip->ip_dst.s_addr == fp->ip4f_info.fi_dst.s_addr && 1916130365Smlaier ip->ip_p == fp->ip4f_info.fi_proto) { 1917130365Smlaier 1918130365Smlaier /* found the matching entry */ 1919130365Smlaier fin->fi_sport = fp->ip4f_info.fi_sport; 1920130365Smlaier fin->fi_dport = fp->ip4f_info.fi_dport; 1921130365Smlaier fin->fi_gpi = fp->ip4f_info.fi_gpi; 1922130365Smlaier 1923130365Smlaier if ((ntohs(ip->ip_off) & IP_MF) == 0) 1924130365Smlaier /* this is the last fragment, 1925130365Smlaier release the entry. */ 1926130365Smlaier ip4f_free(fp); 1927130365Smlaier 1928130365Smlaier return (1); 1929130365Smlaier } 1930130365Smlaier 1931130365Smlaier /* no matching entry found */ 1932130365Smlaier return (0); 1933130365Smlaier} 1934130365Smlaier 1935130365Smlaierstatic int 1936130365Smlaierip4f_init(void) 1937130365Smlaier{ 1938130365Smlaier struct ip4_frag *fp; 1939130365Smlaier int i; 1940130365Smlaier 1941130365Smlaier TAILQ_INIT(&ip4f_list); 1942130365Smlaier for (i=0; i<IP4F_TABSIZE; i++) { 1943184205Sdes fp = malloc(sizeof(struct ip4_frag), 1944130365Smlaier M_DEVBUF, M_NOWAIT); 1945130365Smlaier if (fp == NULL) { 1946130365Smlaier printf("ip4f_init: can't alloc %dth entry!\n", i); 1947130365Smlaier if (i == 0) 1948130365Smlaier return (-1); 1949130365Smlaier return (0); 1950130365Smlaier } 1951130365Smlaier fp->ip4f_valid = 0; 1952130365Smlaier TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain); 1953130365Smlaier } 1954130365Smlaier return (0); 1955130365Smlaier} 1956130365Smlaier 1957130365Smlaierstatic struct ip4_frag * 1958130365Smlaierip4f_alloc(void) 1959130365Smlaier{ 1960130365Smlaier struct ip4_frag *fp; 1961130365Smlaier 1962130365Smlaier /* reclaim an entry at the tail, put it at the head */ 1963130365Smlaier fp = TAILQ_LAST(&ip4f_list, ip4f_list); 1964130365Smlaier TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain); 1965130365Smlaier fp->ip4f_valid = 1; 1966130365Smlaier TAILQ_INSERT_HEAD(&ip4f_list, fp, ip4f_chain); 1967130365Smlaier return (fp); 1968130365Smlaier} 1969130365Smlaier 1970130365Smlaierstatic void 1971130365Smlaierip4f_free(fp) 1972130365Smlaier struct ip4_frag *fp; 1973130365Smlaier{ 1974130365Smlaier TAILQ_REMOVE(&ip4f_list, fp, ip4f_chain); 1975130365Smlaier fp->ip4f_valid = 0; 1976130365Smlaier TAILQ_INSERT_TAIL(&ip4f_list, fp, ip4f_chain); 1977130365Smlaier} 1978130365Smlaier 1979130365Smlaier#endif /* ALTQ3_CLFIER_COMPAT */ 1980