xref: /dragonfly/sys/net/altq/altq_subr.c (revision adceedaf)
14d723e5aSJoerg Sonnenberger /*	$KAME: altq_subr.c,v 1.23 2004/04/20 16:10:06 itojun Exp $	*/
24d723e5aSJoerg Sonnenberger 
34d723e5aSJoerg Sonnenberger /*
44d723e5aSJoerg Sonnenberger  * Copyright (C) 1997-2003
54d723e5aSJoerg Sonnenberger  *	Sony Computer Science Laboratories Inc.  All rights reserved.
64d723e5aSJoerg Sonnenberger  *
74d723e5aSJoerg Sonnenberger  * Redistribution and use in source and binary forms, with or without
84d723e5aSJoerg Sonnenberger  * modification, are permitted provided that the following conditions
94d723e5aSJoerg Sonnenberger  * are met:
104d723e5aSJoerg Sonnenberger  * 1. Redistributions of source code must retain the above copyright
114d723e5aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer.
124d723e5aSJoerg Sonnenberger  * 2. Redistributions in binary form must reproduce the above copyright
134d723e5aSJoerg Sonnenberger  *    notice, this list of conditions and the following disclaimer in the
144d723e5aSJoerg Sonnenberger  *    documentation and/or other materials provided with the distribution.
154d723e5aSJoerg Sonnenberger  *
164d723e5aSJoerg Sonnenberger  * THIS SOFTWARE IS PROVIDED BY SONY CSL AND CONTRIBUTORS ``AS IS'' AND
174d723e5aSJoerg Sonnenberger  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
184d723e5aSJoerg Sonnenberger  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
194d723e5aSJoerg Sonnenberger  * ARE DISCLAIMED.  IN NO EVENT SHALL SONY CSL OR CONTRIBUTORS BE LIABLE
204d723e5aSJoerg Sonnenberger  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
214d723e5aSJoerg Sonnenberger  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
224d723e5aSJoerg Sonnenberger  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
234d723e5aSJoerg Sonnenberger  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
244d723e5aSJoerg Sonnenberger  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
254d723e5aSJoerg Sonnenberger  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
264d723e5aSJoerg Sonnenberger  * SUCH DAMAGE.
274d723e5aSJoerg Sonnenberger  */
284d723e5aSJoerg Sonnenberger 
294d723e5aSJoerg Sonnenberger #include "opt_altq.h"
304d723e5aSJoerg Sonnenberger #include "opt_inet.h"
314d723e5aSJoerg Sonnenberger #include "opt_inet6.h"
324d723e5aSJoerg Sonnenberger 
334d723e5aSJoerg Sonnenberger #include <sys/param.h>
344d723e5aSJoerg Sonnenberger #include <sys/malloc.h>
354d723e5aSJoerg Sonnenberger #include <sys/mbuf.h>
364d723e5aSJoerg Sonnenberger #include <sys/systm.h>
374d723e5aSJoerg Sonnenberger #include <sys/proc.h>
384d723e5aSJoerg Sonnenberger #include <sys/socket.h>
394d723e5aSJoerg Sonnenberger #include <sys/socketvar.h>
404d723e5aSJoerg Sonnenberger #include <sys/kernel.h>
414d723e5aSJoerg Sonnenberger #include <sys/callout.h>
424d723e5aSJoerg Sonnenberger #include <sys/errno.h>
434d723e5aSJoerg Sonnenberger #include <sys/syslog.h>
444d723e5aSJoerg Sonnenberger #include <sys/sysctl.h>
454d723e5aSJoerg Sonnenberger #include <sys/queue.h>
460b31d406SSascha Wildner #include <sys/thread2.h>
474d723e5aSJoerg Sonnenberger 
484d723e5aSJoerg Sonnenberger #include <net/if.h>
494d723e5aSJoerg Sonnenberger #include <net/if_dl.h>
504d723e5aSJoerg Sonnenberger #include <net/if_types.h>
514d723e5aSJoerg Sonnenberger #include <net/ifq_var.h>
52948a738eSSepherosa Ziehau #include <net/netmsg2.h>
53948a738eSSepherosa Ziehau #include <net/netisr2.h>
544d723e5aSJoerg Sonnenberger 
554d723e5aSJoerg Sonnenberger #include <netinet/in.h>
564d723e5aSJoerg Sonnenberger #include <netinet/in_systm.h>
574d723e5aSJoerg Sonnenberger #include <netinet/ip.h>
584d723e5aSJoerg Sonnenberger #ifdef INET6
594d723e5aSJoerg Sonnenberger #include <netinet/ip6.h>
604d723e5aSJoerg Sonnenberger #endif
614d723e5aSJoerg Sonnenberger #include <netinet/tcp.h>
624d723e5aSJoerg Sonnenberger #include <netinet/udp.h>
634d723e5aSJoerg Sonnenberger 
644d723e5aSJoerg Sonnenberger #include <net/pf/pfvar.h>
654d723e5aSJoerg Sonnenberger #include <net/altq/altq.h>
664d723e5aSJoerg Sonnenberger 
674d723e5aSJoerg Sonnenberger /* machine dependent clock related includes */
68870b0161SMatthew Dillon #include <machine/clock.h>		/* for tsc_frequency */
694d723e5aSJoerg Sonnenberger #include <machine/md_var.h>		/* for cpu_feature */
704d723e5aSJoerg Sonnenberger #include <machine/specialreg.h>		/* for CPUID_TSC */
714d723e5aSJoerg Sonnenberger 
724d723e5aSJoerg Sonnenberger /*
734d723e5aSJoerg Sonnenberger  * internal function prototypes
744d723e5aSJoerg Sonnenberger  */
754d723e5aSJoerg Sonnenberger static void	tbr_timeout(void *);
76948a738eSSepherosa Ziehau static void	tbr_timeout_dispatch(netmsg_t);
779db4b353SSepherosa Ziehau static int	altq_enable_locked(struct ifaltq *);
789db4b353SSepherosa Ziehau static int	altq_disable_locked(struct ifaltq *);
799db4b353SSepherosa Ziehau static int	altq_detach_locked(struct ifaltq *);
809db4b353SSepherosa Ziehau static int	tbr_set_locked(struct ifaltq *, struct tb_profile *);
819db4b353SSepherosa Ziehau 
824d723e5aSJoerg Sonnenberger int (*altq_input)(struct mbuf *, int) = NULL;
834d723e5aSJoerg Sonnenberger static int tbr_timer = 0;	/* token bucket regulator timer */
844d723e5aSJoerg Sonnenberger static struct callout tbr_callout;
85948a738eSSepherosa Ziehau static struct netmsg_base tbr_timeout_netmsg;
864d723e5aSJoerg Sonnenberger 
874d723e5aSJoerg Sonnenberger int pfaltq_running;	/* keep track of running state */
884d723e5aSJoerg Sonnenberger 
894d723e5aSJoerg Sonnenberger MALLOC_DEFINE(M_ALTQ, "altq", "ALTQ structures");
904d723e5aSJoerg Sonnenberger 
914d723e5aSJoerg Sonnenberger /*
924d723e5aSJoerg Sonnenberger  * alternate queueing support routines
934d723e5aSJoerg Sonnenberger  */
944d723e5aSJoerg Sonnenberger 
954d723e5aSJoerg Sonnenberger /* look up the queue state by the interface name and the queueing type. */
964d723e5aSJoerg Sonnenberger void *
altq_lookup(const char * name,int type)974d723e5aSJoerg Sonnenberger altq_lookup(const char *name, int type)
984d723e5aSJoerg Sonnenberger {
994d723e5aSJoerg Sonnenberger 	struct ifnet *ifp;
1004d723e5aSJoerg Sonnenberger 
1014d723e5aSJoerg Sonnenberger 	if ((ifp = ifunit(name)) != NULL) {
1024d723e5aSJoerg Sonnenberger 		if (type != ALTQT_NONE && ifp->if_snd.altq_type == type)
1034d723e5aSJoerg Sonnenberger 			return (ifp->if_snd.altq_disc);
1044d723e5aSJoerg Sonnenberger 	}
1054d723e5aSJoerg Sonnenberger 
1064d723e5aSJoerg Sonnenberger 	return (NULL);
1074d723e5aSJoerg Sonnenberger }
1084d723e5aSJoerg Sonnenberger 
1094d723e5aSJoerg Sonnenberger int
altq_attach(struct ifaltq * ifq,int type,void * discipline,altq_mapsubq_t mapsubq,ifsq_enqueue_t enqueue,ifsq_dequeue_t dequeue,ifsq_request_t request,void * clfier,void * (* classify)(struct ifaltq *,struct mbuf *,struct altq_pktattr *))1104d723e5aSJoerg Sonnenberger altq_attach(struct ifaltq *ifq, int type, void *discipline,
1112cc2f639SSepherosa Ziehau     altq_mapsubq_t mapsubq,
112f0a26983SSepherosa Ziehau     ifsq_enqueue_t enqueue, ifsq_dequeue_t dequeue, ifsq_request_t request,
1134d723e5aSJoerg Sonnenberger     void *clfier,
114f0a26983SSepherosa Ziehau     void *(*classify)(struct ifaltq *, struct mbuf *, struct altq_pktattr *))
1154d723e5aSJoerg Sonnenberger {
1164d723e5aSJoerg Sonnenberger 	if (!ifq_is_ready(ifq))
1174d723e5aSJoerg Sonnenberger 		return ENXIO;
1184d723e5aSJoerg Sonnenberger 
1194d723e5aSJoerg Sonnenberger 	ifq->altq_type     = type;
1204d723e5aSJoerg Sonnenberger 	ifq->altq_disc     = discipline;
1214d723e5aSJoerg Sonnenberger 	ifq->altq_clfier   = clfier;
1224d723e5aSJoerg Sonnenberger 	ifq->altq_classify = classify;
1234d723e5aSJoerg Sonnenberger 	ifq->altq_flags &= (ALTQF_CANTCHANGE|ALTQF_ENABLED);
1242cc2f639SSepherosa Ziehau 	ifq_set_methods(ifq, mapsubq, enqueue, dequeue, request);
1254d723e5aSJoerg Sonnenberger 	return 0;
1264d723e5aSJoerg Sonnenberger }
1274d723e5aSJoerg Sonnenberger 
1289db4b353SSepherosa Ziehau static int
altq_detach_locked(struct ifaltq * ifq)1299db4b353SSepherosa Ziehau altq_detach_locked(struct ifaltq *ifq)
1304d723e5aSJoerg Sonnenberger {
1314d723e5aSJoerg Sonnenberger 	if (!ifq_is_ready(ifq))
1324d723e5aSJoerg Sonnenberger 		return ENXIO;
1334d723e5aSJoerg Sonnenberger 	if (ifq_is_enabled(ifq))
1344d723e5aSJoerg Sonnenberger 		return EBUSY;
1354d723e5aSJoerg Sonnenberger 	if (!ifq_is_attached(ifq))
1364d723e5aSJoerg Sonnenberger 		return (0);
1374d723e5aSJoerg Sonnenberger 
138b2f93efeSJoerg Sonnenberger 	ifq_set_classic(ifq);
1394d723e5aSJoerg Sonnenberger 	ifq->altq_type     = ALTQT_NONE;
1404d723e5aSJoerg Sonnenberger 	ifq->altq_disc     = NULL;
1414d723e5aSJoerg Sonnenberger 	ifq->altq_clfier   = NULL;
1424d723e5aSJoerg Sonnenberger 	ifq->altq_classify = NULL;
1434d723e5aSJoerg Sonnenberger 	ifq->altq_flags &= ALTQF_CANTCHANGE;
1444d723e5aSJoerg Sonnenberger 	return 0;
1454d723e5aSJoerg Sonnenberger }
1464d723e5aSJoerg Sonnenberger 
1474d723e5aSJoerg Sonnenberger int
altq_detach(struct ifaltq * ifq)1489db4b353SSepherosa Ziehau altq_detach(struct ifaltq *ifq)
1499db4b353SSepherosa Ziehau {
1509db4b353SSepherosa Ziehau 	int error;
1519db4b353SSepherosa Ziehau 
152f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
1539db4b353SSepherosa Ziehau 	error = altq_detach_locked(ifq);
154f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
1559db4b353SSepherosa Ziehau 	return error;
1569db4b353SSepherosa Ziehau }
1579db4b353SSepherosa Ziehau 
1589db4b353SSepherosa Ziehau static int
altq_enable_locked(struct ifaltq * ifq)1599db4b353SSepherosa Ziehau altq_enable_locked(struct ifaltq *ifq)
1604d723e5aSJoerg Sonnenberger {
1614d723e5aSJoerg Sonnenberger 	if (!ifq_is_ready(ifq))
1624d723e5aSJoerg Sonnenberger 		return ENXIO;
1634d723e5aSJoerg Sonnenberger 	if (ifq_is_enabled(ifq))
1644d723e5aSJoerg Sonnenberger 		return 0;
1654d723e5aSJoerg Sonnenberger 
1669275f515SSepherosa Ziehau 	ifq_purge_all_locked(ifq);
1679db4b353SSepherosa Ziehau 
1684d723e5aSJoerg Sonnenberger 	ifq->altq_flags |= ALTQF_ENABLED;
1694d723e5aSJoerg Sonnenberger 	if (ifq->altq_clfier != NULL)
1704d723e5aSJoerg Sonnenberger 		ifq->altq_flags |= ALTQF_CLASSIFY;
1719db4b353SSepherosa Ziehau 	return 0;
1729db4b353SSepherosa Ziehau }
1734d723e5aSJoerg Sonnenberger 
1749db4b353SSepherosa Ziehau int
altq_enable(struct ifaltq * ifq)1759db4b353SSepherosa Ziehau altq_enable(struct ifaltq *ifq)
1769db4b353SSepherosa Ziehau {
1779db4b353SSepherosa Ziehau 	int error;
1789db4b353SSepherosa Ziehau 
179f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
1809db4b353SSepherosa Ziehau 	error = altq_enable_locked(ifq);
181f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
1829db4b353SSepherosa Ziehau 	return error;
1839db4b353SSepherosa Ziehau }
1849db4b353SSepherosa Ziehau 
1859db4b353SSepherosa Ziehau static int
altq_disable_locked(struct ifaltq * ifq)1869db4b353SSepherosa Ziehau altq_disable_locked(struct ifaltq *ifq)
1879db4b353SSepherosa Ziehau {
1889db4b353SSepherosa Ziehau 	if (!ifq_is_enabled(ifq))
1899db4b353SSepherosa Ziehau 		return 0;
1909db4b353SSepherosa Ziehau 
1919275f515SSepherosa Ziehau 	ifq_purge_all_locked(ifq);
1929db4b353SSepherosa Ziehau 	ifq->altq_flags &= ~(ALTQF_ENABLED|ALTQF_CLASSIFY);
1934d723e5aSJoerg Sonnenberger 	return 0;
1944d723e5aSJoerg Sonnenberger }
1954d723e5aSJoerg Sonnenberger 
1964d723e5aSJoerg Sonnenberger int
altq_disable(struct ifaltq * ifq)1974d723e5aSJoerg Sonnenberger altq_disable(struct ifaltq *ifq)
1984d723e5aSJoerg Sonnenberger {
1999db4b353SSepherosa Ziehau 	int error;
2004d723e5aSJoerg Sonnenberger 
201f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
2029db4b353SSepherosa Ziehau 	error = altq_disable_locked(ifq);
203f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
2049db4b353SSepherosa Ziehau 	return error;
2054d723e5aSJoerg Sonnenberger }
2064d723e5aSJoerg Sonnenberger 
2074d723e5aSJoerg Sonnenberger /*
2084d723e5aSJoerg Sonnenberger  * internal representation of token bucket parameters
2094d723e5aSJoerg Sonnenberger  *	rate:	byte_per_unittime << 32
2104d723e5aSJoerg Sonnenberger  *		(((bits_per_sec) / 8) << 32) / machclk_freq
2114d723e5aSJoerg Sonnenberger  *	depth:	byte << 32
2124d723e5aSJoerg Sonnenberger  *
2134d723e5aSJoerg Sonnenberger  */
2144d723e5aSJoerg Sonnenberger #define	TBR_SHIFT	32
2154d723e5aSJoerg Sonnenberger #define	TBR_SCALE(x)	((int64_t)(x) << TBR_SHIFT)
2164d723e5aSJoerg Sonnenberger #define	TBR_UNSCALE(x)	((x) >> TBR_SHIFT)
2174d723e5aSJoerg Sonnenberger 
2184d723e5aSJoerg Sonnenberger struct mbuf *
tbr_dequeue(struct ifaltq_subque * ifsq,int op)219ac9843a1SSepherosa Ziehau tbr_dequeue(struct ifaltq_subque *ifsq, int op)
2204d723e5aSJoerg Sonnenberger {
221f0a26983SSepherosa Ziehau 	struct ifaltq *ifq = ifsq->ifsq_altq;
2224d723e5aSJoerg Sonnenberger 	struct tb_regulator *tbr;
2234d723e5aSJoerg Sonnenberger 	struct mbuf *m;
2244d723e5aSJoerg Sonnenberger 	int64_t interval;
2254d723e5aSJoerg Sonnenberger 	uint64_t now;
2264d723e5aSJoerg Sonnenberger 
227f0a26983SSepherosa Ziehau 	if (ifsq_get_index(ifsq) != ALTQ_SUBQ_INDEX_DEFAULT) {
228f0a26983SSepherosa Ziehau 		/*
229f0a26983SSepherosa Ziehau 		 * Race happened, the unrelated subqueue was
230f0a26983SSepherosa Ziehau 		 * picked during the packet scheduler transition.
231f0a26983SSepherosa Ziehau 		 */
232f0a26983SSepherosa Ziehau 		ifsq_classic_request(ifsq, ALTRQ_PURGE, NULL);
233f0a26983SSepherosa Ziehau 		return NULL;
234f0a26983SSepherosa Ziehau 	}
235f0a26983SSepherosa Ziehau 
2360b31d406SSascha Wildner 	crit_enter();
2374d723e5aSJoerg Sonnenberger 	tbr = ifq->altq_tbr;
2384d723e5aSJoerg Sonnenberger 	if (op == ALTDQ_REMOVE && tbr->tbr_lastop == ALTDQ_POLL) {
2394d723e5aSJoerg Sonnenberger 		/* if this is a remove after poll, bypass tbr check */
2404d723e5aSJoerg Sonnenberger 	} else {
2414d723e5aSJoerg Sonnenberger 		/* update token only when it is negative */
2424d723e5aSJoerg Sonnenberger 		if (tbr->tbr_token <= 0) {
2434d723e5aSJoerg Sonnenberger 			now = read_machclk();
2444d723e5aSJoerg Sonnenberger 			interval = now - tbr->tbr_last;
2454d723e5aSJoerg Sonnenberger 			if (interval >= tbr->tbr_filluptime)
2464d723e5aSJoerg Sonnenberger 				tbr->tbr_token = tbr->tbr_depth;
2474d723e5aSJoerg Sonnenberger 			else {
2484d723e5aSJoerg Sonnenberger 				tbr->tbr_token += interval * tbr->tbr_rate;
2494d723e5aSJoerg Sonnenberger 				if (tbr->tbr_token > tbr->tbr_depth)
2504d723e5aSJoerg Sonnenberger 					tbr->tbr_token = tbr->tbr_depth;
2514d723e5aSJoerg Sonnenberger 			}
2524d723e5aSJoerg Sonnenberger 			tbr->tbr_last = now;
2534d723e5aSJoerg Sonnenberger 		}
2544d723e5aSJoerg Sonnenberger 		/* if token is still negative, don't allow dequeue */
255e9cb6d99SMatthew Dillon 		if (tbr->tbr_token <= 0) {
2560b31d406SSascha Wildner 			crit_exit();
2574d723e5aSJoerg Sonnenberger 			return (NULL);
2584d723e5aSJoerg Sonnenberger 		}
259e9cb6d99SMatthew Dillon 	}
2604d723e5aSJoerg Sonnenberger 
261ac9843a1SSepherosa Ziehau 	if (ifq_is_enabled(ifq))
2626dadc833SSepherosa Ziehau 		m = (*ifsq->ifsq_dequeue)(ifsq, op);
263ac9843a1SSepherosa Ziehau 	else
264b21c2105SSepherosa Ziehau 		m = ifsq_classic_dequeue(ifsq, op);
2654d723e5aSJoerg Sonnenberger 
2664d723e5aSJoerg Sonnenberger 	if (m != NULL && op == ALTDQ_REMOVE)
2674d723e5aSJoerg Sonnenberger 		tbr->tbr_token -= TBR_SCALE(m_pktlen(m));
2684d723e5aSJoerg Sonnenberger 	tbr->tbr_lastop = op;
2690b31d406SSascha Wildner 	crit_exit();
2704d723e5aSJoerg Sonnenberger 	return (m);
2714d723e5aSJoerg Sonnenberger }
2724d723e5aSJoerg Sonnenberger 
2734d723e5aSJoerg Sonnenberger /*
2744d723e5aSJoerg Sonnenberger  * set a token bucket regulator.
2754d723e5aSJoerg Sonnenberger  * if the specified rate is zero, the token bucket regulator is deleted.
2764d723e5aSJoerg Sonnenberger  */
2779db4b353SSepherosa Ziehau static int
tbr_set_locked(struct ifaltq * ifq,struct tb_profile * profile)2789db4b353SSepherosa Ziehau tbr_set_locked(struct ifaltq *ifq, struct tb_profile *profile)
2794d723e5aSJoerg Sonnenberger {
2804d723e5aSJoerg Sonnenberger 	struct tb_regulator *tbr, *otbr;
2814d723e5aSJoerg Sonnenberger 
2824d723e5aSJoerg Sonnenberger 	if (machclk_freq == 0)
2834d723e5aSJoerg Sonnenberger 		init_machclk();
2844d723e5aSJoerg Sonnenberger 	if (machclk_freq == 0) {
2859db4b353SSepherosa Ziehau 		kprintf("%s: no cpu clock available!\n", __func__);
2864d723e5aSJoerg Sonnenberger 		return (ENXIO);
2874d723e5aSJoerg Sonnenberger 	}
2884d723e5aSJoerg Sonnenberger 
2894d723e5aSJoerg Sonnenberger 	if (profile->rate == 0) {
2904d723e5aSJoerg Sonnenberger 		/* delete this tbr */
2914d723e5aSJoerg Sonnenberger 		if ((tbr = ifq->altq_tbr) == NULL)
2924d723e5aSJoerg Sonnenberger 			return (ENOENT);
2934d723e5aSJoerg Sonnenberger 		ifq->altq_tbr = NULL;
294efda3bd0SMatthew Dillon 		kfree(tbr, M_ALTQ);
2954d723e5aSJoerg Sonnenberger 		return (0);
2964d723e5aSJoerg Sonnenberger 	}
2974d723e5aSJoerg Sonnenberger 
298efda3bd0SMatthew Dillon 	tbr = kmalloc(sizeof(*tbr), M_ALTQ, M_WAITOK | M_ZERO);
2994d723e5aSJoerg Sonnenberger 	tbr->tbr_rate = TBR_SCALE(profile->rate / 8) / machclk_freq;
3004d723e5aSJoerg Sonnenberger 	tbr->tbr_depth = TBR_SCALE(profile->depth);
3014d723e5aSJoerg Sonnenberger 	if (tbr->tbr_rate > 0)
3024d723e5aSJoerg Sonnenberger 		tbr->tbr_filluptime = tbr->tbr_depth / tbr->tbr_rate;
3034d723e5aSJoerg Sonnenberger 	else
3044d723e5aSJoerg Sonnenberger 		tbr->tbr_filluptime = 0xffffffffffffffffLL;
3054d723e5aSJoerg Sonnenberger 	tbr->tbr_token = tbr->tbr_depth;
3064d723e5aSJoerg Sonnenberger 	tbr->tbr_last = read_machclk();
3074d723e5aSJoerg Sonnenberger 	tbr->tbr_lastop = ALTDQ_REMOVE;
3084d723e5aSJoerg Sonnenberger 
3094d723e5aSJoerg Sonnenberger 	otbr = ifq->altq_tbr;
3104d723e5aSJoerg Sonnenberger 	ifq->altq_tbr = tbr;	/* set the new tbr */
3114d723e5aSJoerg Sonnenberger 
3124d723e5aSJoerg Sonnenberger 	if (otbr != NULL)
313efda3bd0SMatthew Dillon 		kfree(otbr, M_ALTQ);
3144d723e5aSJoerg Sonnenberger 	else if (tbr_timer == 0) {
315948a738eSSepherosa Ziehau 		callout_reset_bycpu(&tbr_callout, 1, tbr_timeout, NULL, 0);
3164d723e5aSJoerg Sonnenberger 		tbr_timer = 1;
3174d723e5aSJoerg Sonnenberger 	}
3184d723e5aSJoerg Sonnenberger 	return (0);
3194d723e5aSJoerg Sonnenberger }
3204d723e5aSJoerg Sonnenberger 
3219db4b353SSepherosa Ziehau int
tbr_set(struct ifaltq * ifq,struct tb_profile * profile)3229db4b353SSepherosa Ziehau tbr_set(struct ifaltq *ifq, struct tb_profile *profile)
3239db4b353SSepherosa Ziehau {
3249db4b353SSepherosa Ziehau 	int error;
3259db4b353SSepherosa Ziehau 
326f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
3279db4b353SSepherosa Ziehau 	error = tbr_set_locked(ifq, profile);
328f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
3299db4b353SSepherosa Ziehau 	return error;
3309db4b353SSepherosa Ziehau }
3319db4b353SSepherosa Ziehau 
332948a738eSSepherosa Ziehau static void
tbr_timeout(void * arg __unused)333948a738eSSepherosa Ziehau tbr_timeout(void *arg __unused)
334948a738eSSepherosa Ziehau {
335948a738eSSepherosa Ziehau 	struct lwkt_msg *lmsg = &tbr_timeout_netmsg.lmsg;
336948a738eSSepherosa Ziehau 
337948a738eSSepherosa Ziehau 	KASSERT(mycpuid == 0, ("not on cpu0"));
338948a738eSSepherosa Ziehau 	crit_enter();
339948a738eSSepherosa Ziehau 	if (lmsg->ms_flags & MSGF_DONE)
340948a738eSSepherosa Ziehau 		lwkt_sendmsg_oncpu(netisr_cpuport(0), lmsg);
341948a738eSSepherosa Ziehau 	crit_exit();
342948a738eSSepherosa Ziehau }
343948a738eSSepherosa Ziehau 
3444d723e5aSJoerg Sonnenberger /*
3454d723e5aSJoerg Sonnenberger  * tbr_timeout goes through the interface list, and kicks the drivers
3464d723e5aSJoerg Sonnenberger  * if necessary.
3474d723e5aSJoerg Sonnenberger  */
3484d723e5aSJoerg Sonnenberger static void
tbr_timeout_dispatch(netmsg_t nmsg)349948a738eSSepherosa Ziehau tbr_timeout_dispatch(netmsg_t nmsg)
3504d723e5aSJoerg Sonnenberger {
351b4051e25SSepherosa Ziehau 	const struct ifnet_array *arr;
352b4051e25SSepherosa Ziehau 	int active, i;
3534d723e5aSJoerg Sonnenberger 
3545204e13cSSepherosa Ziehau 	ASSERT_NETISR0;
355948a738eSSepherosa Ziehau 
3560b31d406SSascha Wildner 	crit_enter();
357948a738eSSepherosa Ziehau 	lwkt_replymsg(&nmsg->lmsg, 0);	/* reply ASAP */
358948a738eSSepherosa Ziehau 	crit_exit();
359948a738eSSepherosa Ziehau 
360948a738eSSepherosa Ziehau 	active = 0;
361b4051e25SSepherosa Ziehau 	arr = ifnet_array_get();
362b4051e25SSepherosa Ziehau 	for (i = 0; i < arr->ifnet_count; ++i) {
363b4051e25SSepherosa Ziehau 		struct ifnet *ifp = arr->ifnet_arr[i];
3643c4cd924SSepherosa Ziehau 		struct ifaltq_subque *ifsq;
365f0a26983SSepherosa Ziehau 
3664d723e5aSJoerg Sonnenberger 		if (ifp->if_snd.altq_tbr == NULL)
3674d723e5aSJoerg Sonnenberger 			continue;
3683c4cd924SSepherosa Ziehau 
3693c4cd924SSepherosa Ziehau 		ifsq = &ifp->if_snd.altq_subq[ALTQ_SUBQ_INDEX_DEFAULT];
3704d723e5aSJoerg Sonnenberger 		active++;
371f0a26983SSepherosa Ziehau 		if (!ifsq_is_empty(ifsq) && ifp->if_start != NULL) {
372bfefe4a6SSepherosa Ziehau 			ifsq_serialize_hw(ifsq);
373f0a26983SSepherosa Ziehau 			(*ifp->if_start)(ifp, ifsq);
374bfefe4a6SSepherosa Ziehau 			ifsq_deserialize_hw(ifsq);
37578195a76SMatthew Dillon 		}
3764d723e5aSJoerg Sonnenberger 	}
3774d723e5aSJoerg Sonnenberger 	if (active > 0)
3784d723e5aSJoerg Sonnenberger 		callout_reset(&tbr_callout, 1, tbr_timeout, NULL);
3794d723e5aSJoerg Sonnenberger 	else
3804d723e5aSJoerg Sonnenberger 		tbr_timer = 0;	/* don't need tbr_timer anymore */
3814d723e5aSJoerg Sonnenberger }
3824d723e5aSJoerg Sonnenberger 
3834d723e5aSJoerg Sonnenberger /*
3844d723e5aSJoerg Sonnenberger  * get token bucket regulator profile
3854d723e5aSJoerg Sonnenberger  */
3864d723e5aSJoerg Sonnenberger int
tbr_get(struct ifaltq * ifq,struct tb_profile * profile)3874d723e5aSJoerg Sonnenberger tbr_get(struct ifaltq *ifq, struct tb_profile *profile)
3884d723e5aSJoerg Sonnenberger {
3894d723e5aSJoerg Sonnenberger 	struct tb_regulator *tbr;
3904d723e5aSJoerg Sonnenberger 
3914d723e5aSJoerg Sonnenberger 	if ((tbr = ifq->altq_tbr) == NULL) {
3924d723e5aSJoerg Sonnenberger 		profile->rate = 0;
3934d723e5aSJoerg Sonnenberger 		profile->depth = 0;
3944d723e5aSJoerg Sonnenberger 	} else {
3954d723e5aSJoerg Sonnenberger 		profile->rate =
3964d723e5aSJoerg Sonnenberger 		    (u_int)TBR_UNSCALE(tbr->tbr_rate * 8 * machclk_freq);
3974d723e5aSJoerg Sonnenberger 		profile->depth = (u_int)TBR_UNSCALE(tbr->tbr_depth);
3984d723e5aSJoerg Sonnenberger 	}
3994d723e5aSJoerg Sonnenberger 	return (0);
4004d723e5aSJoerg Sonnenberger }
4014d723e5aSJoerg Sonnenberger 
4024d723e5aSJoerg Sonnenberger /*
4034d723e5aSJoerg Sonnenberger  * attach a discipline to the interface.  if one already exists, it is
4044d723e5aSJoerg Sonnenberger  * overridden.
4054d723e5aSJoerg Sonnenberger  */
4064d723e5aSJoerg Sonnenberger int
altq_pfattach(struct pf_altq * a)4074d723e5aSJoerg Sonnenberger altq_pfattach(struct pf_altq *a)
4084d723e5aSJoerg Sonnenberger {
4099db4b353SSepherosa Ziehau 	struct ifaltq *ifq;
4104d723e5aSJoerg Sonnenberger 	struct ifnet *ifp;
4119db4b353SSepherosa Ziehau 	int error;
4129db4b353SSepherosa Ziehau 
4139db4b353SSepherosa Ziehau 	if (a->scheduler == ALTQT_NONE)
4149db4b353SSepherosa Ziehau 		return 0;
4159db4b353SSepherosa Ziehau 
4169db4b353SSepherosa Ziehau 	if (a->altq_disc == NULL)
4179db4b353SSepherosa Ziehau 		return EINVAL;
4189db4b353SSepherosa Ziehau 
419b4051e25SSepherosa Ziehau 	ifnet_lock();
420b4051e25SSepherosa Ziehau 
4219db4b353SSepherosa Ziehau 	ifp = ifunit(a->ifname);
422b4051e25SSepherosa Ziehau 	if (ifp == NULL) {
423b4051e25SSepherosa Ziehau 		ifnet_unlock();
4249db4b353SSepherosa Ziehau 		return EINVAL;
425b4051e25SSepherosa Ziehau 	}
4269db4b353SSepherosa Ziehau 	ifq = &ifp->if_snd;
4279db4b353SSepherosa Ziehau 
428f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
4294d723e5aSJoerg Sonnenberger 
4304d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
4314d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
4324d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
4339db4b353SSepherosa Ziehau 		error = cbq_pfattach(a, ifq);
4344d723e5aSJoerg Sonnenberger 		break;
4354d723e5aSJoerg Sonnenberger #endif
4364d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
4374d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
4389db4b353SSepherosa Ziehau 		error = priq_pfattach(a, ifq);
4394d723e5aSJoerg Sonnenberger 		break;
4404d723e5aSJoerg Sonnenberger #endif
4414d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
4424d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
4439db4b353SSepherosa Ziehau 		error = hfsc_pfattach(a, ifq);
4444d723e5aSJoerg Sonnenberger 		break;
4454d723e5aSJoerg Sonnenberger #endif
4465950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
4475950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
4489db4b353SSepherosa Ziehau 		error = fairq_pfattach(a, ifq);
4495950bf01SMatthew Dillon 		break;
4505950bf01SMatthew Dillon #endif
4514d723e5aSJoerg Sonnenberger 	default:
4524d723e5aSJoerg Sonnenberger 		error = ENXIO;
4539db4b353SSepherosa Ziehau 		goto back;
4544d723e5aSJoerg Sonnenberger 	}
4554d723e5aSJoerg Sonnenberger 
4564d723e5aSJoerg Sonnenberger 	/* if the state is running, enable altq */
4579db4b353SSepherosa Ziehau 	if (error == 0 && pfaltq_running && ifq->altq_type != ALTQT_NONE &&
4589db4b353SSepherosa Ziehau 	    !ifq_is_enabled(ifq))
4599db4b353SSepherosa Ziehau 		error = altq_enable_locked(ifq);
4604d723e5aSJoerg Sonnenberger 
4614d723e5aSJoerg Sonnenberger 	/* if altq is already enabled, reset set tokenbucket regulator */
4629db4b353SSepherosa Ziehau 	if (error == 0 && ifq_is_enabled(ifq)) {
4639db4b353SSepherosa Ziehau 		struct tb_profile tb;
4649db4b353SSepherosa Ziehau 
4654d723e5aSJoerg Sonnenberger 		tb.rate = a->ifbandwidth;
4664d723e5aSJoerg Sonnenberger 		tb.depth = a->tbrsize;
4679db4b353SSepherosa Ziehau 		error = tbr_set_locked(ifq, &tb);
4684d723e5aSJoerg Sonnenberger 	}
4699db4b353SSepherosa Ziehau back:
470f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
471b4051e25SSepherosa Ziehau 	ifnet_unlock();
4724d723e5aSJoerg Sonnenberger 	return (error);
4734d723e5aSJoerg Sonnenberger }
4744d723e5aSJoerg Sonnenberger 
4754d723e5aSJoerg Sonnenberger /*
4764d723e5aSJoerg Sonnenberger  * detach a discipline from the interface.
4774d723e5aSJoerg Sonnenberger  * it is possible that the discipline was already overridden by another
4784d723e5aSJoerg Sonnenberger  * discipline.
4794d723e5aSJoerg Sonnenberger  */
4804d723e5aSJoerg Sonnenberger int
altq_pfdetach(struct pf_altq * a)4814d723e5aSJoerg Sonnenberger altq_pfdetach(struct pf_altq *a)
4824d723e5aSJoerg Sonnenberger {
4834d723e5aSJoerg Sonnenberger 	struct ifnet *ifp;
4849db4b353SSepherosa Ziehau 	struct ifaltq *ifq;
4850b31d406SSascha Wildner 	int error = 0;
4864d723e5aSJoerg Sonnenberger 
487b4051e25SSepherosa Ziehau 	ifnet_lock();
488b4051e25SSepherosa Ziehau 
4899db4b353SSepherosa Ziehau 	ifp = ifunit(a->ifname);
490b4051e25SSepherosa Ziehau 	if (ifp == NULL) {
491b4051e25SSepherosa Ziehau 		ifnet_unlock();
4924d723e5aSJoerg Sonnenberger 		return (EINVAL);
493b4051e25SSepherosa Ziehau 	}
4949db4b353SSepherosa Ziehau 	ifq = &ifp->if_snd;
4954d723e5aSJoerg Sonnenberger 
4964d723e5aSJoerg Sonnenberger 	/* if this discipline is no longer referenced, just return */
497b4051e25SSepherosa Ziehau 	if (a->altq_disc == NULL) {
498b4051e25SSepherosa Ziehau 		ifnet_unlock();
4994d723e5aSJoerg Sonnenberger 		return (0);
500b4051e25SSepherosa Ziehau 	}
5014d723e5aSJoerg Sonnenberger 
502f0a26983SSepherosa Ziehau 	ifq_lock_all(ifq);
5034d723e5aSJoerg Sonnenberger 
5049db4b353SSepherosa Ziehau 	if (a->altq_disc != ifq->altq_disc)
5059db4b353SSepherosa Ziehau 		goto back;
5069db4b353SSepherosa Ziehau 
5079db4b353SSepherosa Ziehau 	if (ifq_is_enabled(ifq))
5089db4b353SSepherosa Ziehau 		error = altq_disable_locked(ifq);
5099db4b353SSepherosa Ziehau 	if (error == 0)
5109db4b353SSepherosa Ziehau 		error = altq_detach_locked(ifq);
5119db4b353SSepherosa Ziehau 
5129db4b353SSepherosa Ziehau back:
513f0a26983SSepherosa Ziehau 	ifq_unlock_all(ifq);
514b4051e25SSepherosa Ziehau 	ifnet_unlock();
5154d723e5aSJoerg Sonnenberger 	return (error);
5164d723e5aSJoerg Sonnenberger }
5174d723e5aSJoerg Sonnenberger 
5184d723e5aSJoerg Sonnenberger /*
5194d723e5aSJoerg Sonnenberger  * add a discipline or a queue
5204d723e5aSJoerg Sonnenberger  */
5214d723e5aSJoerg Sonnenberger int
altq_add(struct pf_altq * a)5224d723e5aSJoerg Sonnenberger altq_add(struct pf_altq *a)
5234d723e5aSJoerg Sonnenberger {
5244d723e5aSJoerg Sonnenberger 	int error = 0;
5254d723e5aSJoerg Sonnenberger 
5264d723e5aSJoerg Sonnenberger 	if (a->qname[0] != 0)
5274d723e5aSJoerg Sonnenberger 		return (altq_add_queue(a));
5284d723e5aSJoerg Sonnenberger 
5294d723e5aSJoerg Sonnenberger 	if (machclk_freq == 0)
5304d723e5aSJoerg Sonnenberger 		init_machclk();
5314d723e5aSJoerg Sonnenberger 	if (machclk_freq == 0)
5324d723e5aSJoerg Sonnenberger 		panic("altq_add: no cpu clock");
5334d723e5aSJoerg Sonnenberger 
5344d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
5354d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
5364d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
5374d723e5aSJoerg Sonnenberger 		error = cbq_add_altq(a);
5384d723e5aSJoerg Sonnenberger 		break;
5394d723e5aSJoerg Sonnenberger #endif
5404d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
5414d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
5424d723e5aSJoerg Sonnenberger 		error = priq_add_altq(a);
5434d723e5aSJoerg Sonnenberger 		break;
5444d723e5aSJoerg Sonnenberger #endif
5454d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
5464d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
5474d723e5aSJoerg Sonnenberger 		error = hfsc_add_altq(a);
5484d723e5aSJoerg Sonnenberger 		break;
5494d723e5aSJoerg Sonnenberger #endif
5505950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
5515950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
5525950bf01SMatthew Dillon 		error = fairq_add_altq(a);
5535950bf01SMatthew Dillon 		break;
5545950bf01SMatthew Dillon #endif
5554d723e5aSJoerg Sonnenberger 	default:
5564d723e5aSJoerg Sonnenberger 		error = ENXIO;
5574d723e5aSJoerg Sonnenberger 	}
5584d723e5aSJoerg Sonnenberger 
5594d723e5aSJoerg Sonnenberger 	return (error);
5604d723e5aSJoerg Sonnenberger }
5614d723e5aSJoerg Sonnenberger 
5624d723e5aSJoerg Sonnenberger /*
5634d723e5aSJoerg Sonnenberger  * remove a discipline or a queue
5644d723e5aSJoerg Sonnenberger  */
5654d723e5aSJoerg Sonnenberger int
altq_remove(struct pf_altq * a)5664d723e5aSJoerg Sonnenberger altq_remove(struct pf_altq *a)
5674d723e5aSJoerg Sonnenberger {
5684d723e5aSJoerg Sonnenberger 	int error = 0;
5694d723e5aSJoerg Sonnenberger 
5704d723e5aSJoerg Sonnenberger 	if (a->qname[0] != 0)
5714d723e5aSJoerg Sonnenberger 		return (altq_remove_queue(a));
5724d723e5aSJoerg Sonnenberger 
5734d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
5744d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
5754d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
5764d723e5aSJoerg Sonnenberger 		error = cbq_remove_altq(a);
5774d723e5aSJoerg Sonnenberger 		break;
5784d723e5aSJoerg Sonnenberger #endif
5794d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
5804d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
5814d723e5aSJoerg Sonnenberger 		error = priq_remove_altq(a);
5824d723e5aSJoerg Sonnenberger 		break;
5834d723e5aSJoerg Sonnenberger #endif
5844d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
5854d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
5864d723e5aSJoerg Sonnenberger 		error = hfsc_remove_altq(a);
5874d723e5aSJoerg Sonnenberger 		break;
5884d723e5aSJoerg Sonnenberger #endif
5895950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
5905950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
5915950bf01SMatthew Dillon 		error = fairq_remove_altq(a);
5925950bf01SMatthew Dillon 		break;
5935950bf01SMatthew Dillon #endif
5944d723e5aSJoerg Sonnenberger 	default:
5954d723e5aSJoerg Sonnenberger 		error = ENXIO;
5964d723e5aSJoerg Sonnenberger 	}
5974d723e5aSJoerg Sonnenberger 
5984d723e5aSJoerg Sonnenberger 	return (error);
5994d723e5aSJoerg Sonnenberger }
6004d723e5aSJoerg Sonnenberger 
6014d723e5aSJoerg Sonnenberger /*
6024d723e5aSJoerg Sonnenberger  * add a queue to the discipline
6034d723e5aSJoerg Sonnenberger  */
6044d723e5aSJoerg Sonnenberger int
altq_add_queue(struct pf_altq * a)6054d723e5aSJoerg Sonnenberger altq_add_queue(struct pf_altq *a)
6064d723e5aSJoerg Sonnenberger {
6074d723e5aSJoerg Sonnenberger 	int error = 0;
6084d723e5aSJoerg Sonnenberger 
6094d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
6104d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
6114d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
6124d723e5aSJoerg Sonnenberger 		error = cbq_add_queue(a);
6134d723e5aSJoerg Sonnenberger 		break;
6144d723e5aSJoerg Sonnenberger #endif
6154d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
6164d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
6174d723e5aSJoerg Sonnenberger 		error = priq_add_queue(a);
6184d723e5aSJoerg Sonnenberger 		break;
6194d723e5aSJoerg Sonnenberger #endif
6204d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
6214d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
6224d723e5aSJoerg Sonnenberger 		error = hfsc_add_queue(a);
6234d723e5aSJoerg Sonnenberger 		break;
6244d723e5aSJoerg Sonnenberger #endif
6255950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
6265950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
6275950bf01SMatthew Dillon 		error = fairq_add_queue(a);
6285950bf01SMatthew Dillon 		break;
6295950bf01SMatthew Dillon #endif
6304d723e5aSJoerg Sonnenberger 	default:
6314d723e5aSJoerg Sonnenberger 		error = ENXIO;
6324d723e5aSJoerg Sonnenberger 	}
6334d723e5aSJoerg Sonnenberger 
6344d723e5aSJoerg Sonnenberger 	return (error);
6354d723e5aSJoerg Sonnenberger }
6364d723e5aSJoerg Sonnenberger 
6374d723e5aSJoerg Sonnenberger /*
6384d723e5aSJoerg Sonnenberger  * remove a queue from the discipline
6394d723e5aSJoerg Sonnenberger  */
6404d723e5aSJoerg Sonnenberger int
altq_remove_queue(struct pf_altq * a)6414d723e5aSJoerg Sonnenberger altq_remove_queue(struct pf_altq *a)
6424d723e5aSJoerg Sonnenberger {
6434d723e5aSJoerg Sonnenberger 	int error = 0;
6444d723e5aSJoerg Sonnenberger 
6454d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
6464d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
6474d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
6484d723e5aSJoerg Sonnenberger 		error = cbq_remove_queue(a);
6494d723e5aSJoerg Sonnenberger 		break;
6504d723e5aSJoerg Sonnenberger #endif
6514d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
6524d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
6534d723e5aSJoerg Sonnenberger 		error = priq_remove_queue(a);
6544d723e5aSJoerg Sonnenberger 		break;
6554d723e5aSJoerg Sonnenberger #endif
6564d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
6574d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
6584d723e5aSJoerg Sonnenberger 		error = hfsc_remove_queue(a);
6594d723e5aSJoerg Sonnenberger 		break;
6604d723e5aSJoerg Sonnenberger #endif
6615950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
6625950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
6635950bf01SMatthew Dillon 		error = fairq_remove_queue(a);
6645950bf01SMatthew Dillon 		break;
6655950bf01SMatthew Dillon #endif
6664d723e5aSJoerg Sonnenberger 	default:
6674d723e5aSJoerg Sonnenberger 		error = ENXIO;
6684d723e5aSJoerg Sonnenberger 	}
6694d723e5aSJoerg Sonnenberger 
6704d723e5aSJoerg Sonnenberger 	return (error);
6714d723e5aSJoerg Sonnenberger }
6724d723e5aSJoerg Sonnenberger 
6734d723e5aSJoerg Sonnenberger /*
6744d723e5aSJoerg Sonnenberger  * get queue statistics
6754d723e5aSJoerg Sonnenberger  */
6764d723e5aSJoerg Sonnenberger int
altq_getqstats(struct pf_altq * a,void * ubuf,int * nbytes)6774d723e5aSJoerg Sonnenberger altq_getqstats(struct pf_altq *a, void *ubuf, int *nbytes)
6784d723e5aSJoerg Sonnenberger {
6794d723e5aSJoerg Sonnenberger 	int error = 0;
6804d723e5aSJoerg Sonnenberger 
6814d723e5aSJoerg Sonnenberger 	switch (a->scheduler) {
6824d723e5aSJoerg Sonnenberger #ifdef ALTQ_CBQ
6834d723e5aSJoerg Sonnenberger 	case ALTQT_CBQ:
6844d723e5aSJoerg Sonnenberger 		error = cbq_getqstats(a, ubuf, nbytes);
6854d723e5aSJoerg Sonnenberger 		break;
6864d723e5aSJoerg Sonnenberger #endif
6874d723e5aSJoerg Sonnenberger #ifdef ALTQ_PRIQ
6884d723e5aSJoerg Sonnenberger 	case ALTQT_PRIQ:
6894d723e5aSJoerg Sonnenberger 		error = priq_getqstats(a, ubuf, nbytes);
6904d723e5aSJoerg Sonnenberger 		break;
6914d723e5aSJoerg Sonnenberger #endif
6924d723e5aSJoerg Sonnenberger #ifdef ALTQ_HFSC
6934d723e5aSJoerg Sonnenberger 	case ALTQT_HFSC:
6944d723e5aSJoerg Sonnenberger 		error = hfsc_getqstats(a, ubuf, nbytes);
6954d723e5aSJoerg Sonnenberger 		break;
6964d723e5aSJoerg Sonnenberger #endif
6975950bf01SMatthew Dillon #ifdef ALTQ_FAIRQ
6985950bf01SMatthew Dillon 	case ALTQT_FAIRQ:
6995950bf01SMatthew Dillon 		error = fairq_getqstats(a, ubuf, nbytes);
7005950bf01SMatthew Dillon 		break;
7015950bf01SMatthew Dillon #endif
7024d723e5aSJoerg Sonnenberger 	default:
7034d723e5aSJoerg Sonnenberger 		error = ENXIO;
7044d723e5aSJoerg Sonnenberger 	}
7054d723e5aSJoerg Sonnenberger 
7064d723e5aSJoerg Sonnenberger 	return (error);
7074d723e5aSJoerg Sonnenberger }
7084d723e5aSJoerg Sonnenberger 
7094d723e5aSJoerg Sonnenberger /*
7104d723e5aSJoerg Sonnenberger  * read and write diffserv field in IPv4 or IPv6 header
7114d723e5aSJoerg Sonnenberger  */
7124d723e5aSJoerg Sonnenberger uint8_t
read_dsfield(struct mbuf * m,struct altq_pktattr * pktattr)7134d723e5aSJoerg Sonnenberger read_dsfield(struct mbuf *m, struct altq_pktattr *pktattr)
7144d723e5aSJoerg Sonnenberger {
7154d723e5aSJoerg Sonnenberger 	struct mbuf *m0;
7164d723e5aSJoerg Sonnenberger 	uint8_t ds_field = 0;
7174d723e5aSJoerg Sonnenberger 
7184d723e5aSJoerg Sonnenberger 	if (pktattr == NULL ||
7194d723e5aSJoerg Sonnenberger 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
7204d723e5aSJoerg Sonnenberger 		return ((uint8_t)0);
7214d723e5aSJoerg Sonnenberger 
7224d723e5aSJoerg Sonnenberger 	/* verify that pattr_hdr is within the mbuf data */
7234d723e5aSJoerg Sonnenberger 	for (m0 = m; m0 != NULL; m0 = m0->m_next) {
7244d723e5aSJoerg Sonnenberger 		if ((pktattr->pattr_hdr >= m0->m_data) &&
7254d723e5aSJoerg Sonnenberger 		    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
7264d723e5aSJoerg Sonnenberger 			break;
7274d723e5aSJoerg Sonnenberger 	}
7284d723e5aSJoerg Sonnenberger 	if (m0 == NULL) {
7294d723e5aSJoerg Sonnenberger 		/* ick, pattr_hdr is stale */
7304d723e5aSJoerg Sonnenberger 		pktattr->pattr_af = AF_UNSPEC;
7314d723e5aSJoerg Sonnenberger #ifdef ALTQ_DEBUG
7324b1cf444SSascha Wildner 		kprintf("read_dsfield: can't locate header!\n");
7334d723e5aSJoerg Sonnenberger #endif
7344d723e5aSJoerg Sonnenberger 		return ((uint8_t)0);
7354d723e5aSJoerg Sonnenberger 	}
7364d723e5aSJoerg Sonnenberger 
7374d723e5aSJoerg Sonnenberger 	if (pktattr->pattr_af == AF_INET) {
7384d723e5aSJoerg Sonnenberger 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
7394d723e5aSJoerg Sonnenberger 
7404d723e5aSJoerg Sonnenberger 		if (ip->ip_v != 4)
7414d723e5aSJoerg Sonnenberger 			return ((uint8_t)0);	/* version mismatch! */
7424d723e5aSJoerg Sonnenberger 		ds_field = ip->ip_tos;
7434d723e5aSJoerg Sonnenberger 	}
7444d723e5aSJoerg Sonnenberger #ifdef INET6
7454d723e5aSJoerg Sonnenberger 	else if (pktattr->pattr_af == AF_INET6) {
7464d723e5aSJoerg Sonnenberger 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
7474d723e5aSJoerg Sonnenberger 		uint32_t flowlabel;
7484d723e5aSJoerg Sonnenberger 
7494d723e5aSJoerg Sonnenberger 		flowlabel = ntohl(ip6->ip6_flow);
7504d723e5aSJoerg Sonnenberger 		if ((flowlabel >> 28) != 6)
7514d723e5aSJoerg Sonnenberger 			return ((uint8_t)0);	/* version mismatch! */
7524d723e5aSJoerg Sonnenberger 		ds_field = (flowlabel >> 20) & 0xff;
7534d723e5aSJoerg Sonnenberger 	}
7544d723e5aSJoerg Sonnenberger #endif
7554d723e5aSJoerg Sonnenberger 	return (ds_field);
7564d723e5aSJoerg Sonnenberger }
7574d723e5aSJoerg Sonnenberger 
7584d723e5aSJoerg Sonnenberger void
write_dsfield(struct mbuf * m,struct altq_pktattr * pktattr,uint8_t dsfield)7594d723e5aSJoerg Sonnenberger write_dsfield(struct mbuf *m, struct altq_pktattr *pktattr, uint8_t dsfield)
7604d723e5aSJoerg Sonnenberger {
7614d723e5aSJoerg Sonnenberger 	struct mbuf *m0;
7624d723e5aSJoerg Sonnenberger 
7634d723e5aSJoerg Sonnenberger 	if (pktattr == NULL ||
7644d723e5aSJoerg Sonnenberger 	    (pktattr->pattr_af != AF_INET && pktattr->pattr_af != AF_INET6))
7654d723e5aSJoerg Sonnenberger 		return;
7664d723e5aSJoerg Sonnenberger 
7674d723e5aSJoerg Sonnenberger 	/* verify that pattr_hdr is within the mbuf data */
7684d723e5aSJoerg Sonnenberger 	for (m0 = m; m0 != NULL; m0 = m0->m_next) {
7694d723e5aSJoerg Sonnenberger 		if ((pktattr->pattr_hdr >= m0->m_data) &&
7704d723e5aSJoerg Sonnenberger 		    (pktattr->pattr_hdr < m0->m_data + m0->m_len))
7714d723e5aSJoerg Sonnenberger 			break;
7724d723e5aSJoerg Sonnenberger 	}
7734d723e5aSJoerg Sonnenberger 	if (m0 == NULL) {
7744d723e5aSJoerg Sonnenberger 		/* ick, pattr_hdr is stale */
7754d723e5aSJoerg Sonnenberger 		pktattr->pattr_af = AF_UNSPEC;
7764d723e5aSJoerg Sonnenberger #ifdef ALTQ_DEBUG
7774b1cf444SSascha Wildner 		kprintf("write_dsfield: can't locate header!\n");
7784d723e5aSJoerg Sonnenberger #endif
7794d723e5aSJoerg Sonnenberger 		return;
7804d723e5aSJoerg Sonnenberger 	}
7814d723e5aSJoerg Sonnenberger 
7824d723e5aSJoerg Sonnenberger 	if (pktattr->pattr_af == AF_INET) {
7834d723e5aSJoerg Sonnenberger 		struct ip *ip = (struct ip *)pktattr->pattr_hdr;
7844d723e5aSJoerg Sonnenberger 		uint8_t old;
7854d723e5aSJoerg Sonnenberger 		int32_t sum;
7864d723e5aSJoerg Sonnenberger 
7874d723e5aSJoerg Sonnenberger 		if (ip->ip_v != 4)
7884d723e5aSJoerg Sonnenberger 			return;		/* version mismatch! */
7894d723e5aSJoerg Sonnenberger 		old = ip->ip_tos;
7904d723e5aSJoerg Sonnenberger 		dsfield |= old & 3;	/* leave CU bits */
7914d723e5aSJoerg Sonnenberger 		if (old == dsfield)
7924d723e5aSJoerg Sonnenberger 			return;
7934d723e5aSJoerg Sonnenberger 		ip->ip_tos = dsfield;
7944d723e5aSJoerg Sonnenberger 		/*
7954d723e5aSJoerg Sonnenberger 		 * update checksum (from RFC1624)
7964d723e5aSJoerg Sonnenberger 		 *	   HC' = ~(~HC + ~m + m')
7974d723e5aSJoerg Sonnenberger 		 */
7984d723e5aSJoerg Sonnenberger 		sum = ~ntohs(ip->ip_sum) & 0xffff;
7994d723e5aSJoerg Sonnenberger 		sum += 0xff00 + (~old & 0xff) + dsfield;
8004d723e5aSJoerg Sonnenberger 		sum = (sum >> 16) + (sum & 0xffff);
8014d723e5aSJoerg Sonnenberger 		sum += (sum >> 16);  /* add carry */
8024d723e5aSJoerg Sonnenberger 
8034d723e5aSJoerg Sonnenberger 		ip->ip_sum = htons(~sum & 0xffff);
8044d723e5aSJoerg Sonnenberger 	}
8054d723e5aSJoerg Sonnenberger #ifdef INET6
8064d723e5aSJoerg Sonnenberger 	else if (pktattr->pattr_af == AF_INET6) {
8074d723e5aSJoerg Sonnenberger 		struct ip6_hdr *ip6 = (struct ip6_hdr *)pktattr->pattr_hdr;
8084d723e5aSJoerg Sonnenberger 		uint32_t flowlabel;
8094d723e5aSJoerg Sonnenberger 
8104d723e5aSJoerg Sonnenberger 		flowlabel = ntohl(ip6->ip6_flow);
8114d723e5aSJoerg Sonnenberger 		if ((flowlabel >> 28) != 6)
8124d723e5aSJoerg Sonnenberger 			return;		/* version mismatch! */
8134d723e5aSJoerg Sonnenberger 		flowlabel = (flowlabel & 0xf03fffff) | (dsfield << 20);
8144d723e5aSJoerg Sonnenberger 		ip6->ip6_flow = htonl(flowlabel);
8154d723e5aSJoerg Sonnenberger 	}
8164d723e5aSJoerg Sonnenberger #endif
8174d723e5aSJoerg Sonnenberger }
8184d723e5aSJoerg Sonnenberger 
8194d723e5aSJoerg Sonnenberger /*
8204d723e5aSJoerg Sonnenberger  * high resolution clock support taking advantage of a machine dependent
8214d723e5aSJoerg Sonnenberger  * high resolution time counter (e.g., timestamp counter of intel pentium).
8224d723e5aSJoerg Sonnenberger  * we assume
8234d723e5aSJoerg Sonnenberger  *  - 64-bit-long monotonically-increasing counter
8244d723e5aSJoerg Sonnenberger  *  - frequency range is 100M-4GHz (CPU speed)
8254d723e5aSJoerg Sonnenberger  */
8264d723e5aSJoerg Sonnenberger /* if pcc is not available or disabled, emulate 256MHz using microtime() */
8274d723e5aSJoerg Sonnenberger #define	MACHCLK_SHIFT	8
8284d723e5aSJoerg Sonnenberger 
8294a47584bSSepherosa Ziehau static int machclk_usepcc;
830870b0161SMatthew Dillon uint64_t machclk_freq = 0;
8314d723e5aSJoerg Sonnenberger uint32_t machclk_per_tick = 0;
8324d723e5aSJoerg Sonnenberger 
8334d723e5aSJoerg Sonnenberger void
init_machclk(void)8344d723e5aSJoerg Sonnenberger init_machclk(void)
8354d723e5aSJoerg Sonnenberger {
836948a738eSSepherosa Ziehau 	callout_init_mp(&tbr_callout);
837948a738eSSepherosa Ziehau 	netmsg_init(&tbr_timeout_netmsg, NULL, &netisr_adone_rport,
838948a738eSSepherosa Ziehau 	    MSGF_PRIORITY, tbr_timeout_dispatch);
8394d723e5aSJoerg Sonnenberger 
8404a47584bSSepherosa Ziehau #ifdef ALTQ_NOPCC
8414a47584bSSepherosa Ziehau 	machclk_usepcc = 0;
8424a47584bSSepherosa Ziehau #else
8434d723e5aSJoerg Sonnenberger 	machclk_usepcc = 1;
8444a47584bSSepherosa Ziehau #endif
8454d723e5aSJoerg Sonnenberger 
846ac8ea0adSSascha Wildner #if defined(__x86_64__)
847*adceedafSImre Vadász 	if (tsc_mpsync && tsc_present)
848*adceedafSImre Vadász 		machclk_freq = tsc_frequency;
849*adceedafSImre Vadász 	else
8504a47584bSSepherosa Ziehau 		machclk_usepcc = 0;
8514a47584bSSepherosa Ziehau #else
8524d723e5aSJoerg Sonnenberger 	machclk_usepcc = 0;
8534d723e5aSJoerg Sonnenberger #endif
8544d723e5aSJoerg Sonnenberger 
855*adceedafSImre Vadász 	if (machclk_usepcc) {
856*adceedafSImre Vadász #ifdef ALTQ_DEBUG
857*adceedafSImre Vadász 		kprintf("altq: CPU clock: %juHz\n", (uintmax_t)machclk_freq);
858*adceedafSImre Vadász #endif
859*adceedafSImre Vadász 	} else {
860699a76d9SSepherosa Ziehau 		/* emulate 256MHz using microuptime() */
861870b0161SMatthew Dillon 		machclk_freq = 1000000LLU << MACHCLK_SHIFT;
8624d723e5aSJoerg Sonnenberger #ifdef ALTQ_DEBUG
8634a47584bSSepherosa Ziehau 		kprintf("altq: emulate %juHz cpu clock\n",
8644a47584bSSepherosa Ziehau 		    (uintmax_t)machclk_freq);
8654d723e5aSJoerg Sonnenberger #endif
8664d723e5aSJoerg Sonnenberger 	}
8674d723e5aSJoerg Sonnenberger 	machclk_per_tick = machclk_freq / hz;
8684d723e5aSJoerg Sonnenberger }
8694d723e5aSJoerg Sonnenberger 
8704d723e5aSJoerg Sonnenberger uint64_t
read_machclk(void)8714d723e5aSJoerg Sonnenberger read_machclk(void)
8724d723e5aSJoerg Sonnenberger {
8734d723e5aSJoerg Sonnenberger 	uint64_t val;
8744d723e5aSJoerg Sonnenberger 
8754d723e5aSJoerg Sonnenberger 	if (machclk_usepcc) {
876870b0161SMatthew Dillon #ifdef _RDTSC_SUPPORTED_
8774d723e5aSJoerg Sonnenberger 		val = rdtsc();
8784d723e5aSJoerg Sonnenberger #else
8794d723e5aSJoerg Sonnenberger 		panic("read_machclk");
8804d723e5aSJoerg Sonnenberger #endif
8814d723e5aSJoerg Sonnenberger 	} else {
8824d723e5aSJoerg Sonnenberger 		struct timeval tv;
8834d723e5aSJoerg Sonnenberger 
884699a76d9SSepherosa Ziehau 		microuptime(&tv);
885699a76d9SSepherosa Ziehau 		val = (((uint64_t)tv.tv_sec * 1000000 + tv.tv_usec) <<
886699a76d9SSepherosa Ziehau 		    MACHCLK_SHIFT);
8874d723e5aSJoerg Sonnenberger 	}
8884d723e5aSJoerg Sonnenberger 	return (val);
8894d723e5aSJoerg Sonnenberger }
890