altq_cdnr.c revision 184205
1130368Smlaier/*	$FreeBSD: head/sys/contrib/altq/altq/altq_cdnr.c 184205 2008-10-23 15:53:51Z des $	*/
2130365Smlaier/*	$KAME: altq_cdnr.c,v 1.14 2003/09/05 22:40:36 itojun Exp $	*/
3130365Smlaier
4130365Smlaier/*
5130365Smlaier * Copyright (C) 1999-2002
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#if (__FreeBSD__ != 2)
33130365Smlaier#include "opt_inet.h"
34130365Smlaier#ifdef __FreeBSD__
35130365Smlaier#include "opt_inet6.h"
36130365Smlaier#endif
37130365Smlaier#endif
38130365Smlaier#endif /* __FreeBSD__ || __NetBSD__ */
39130365Smlaier
40130365Smlaier#include <sys/param.h>
41130365Smlaier#include <sys/malloc.h>
42130365Smlaier#include <sys/mbuf.h>
43130365Smlaier#include <sys/socket.h>
44130365Smlaier#include <sys/sockio.h>
45130365Smlaier#include <sys/systm.h>
46130365Smlaier#include <sys/proc.h>
47130365Smlaier#include <sys/errno.h>
48130365Smlaier#include <sys/kernel.h>
49130365Smlaier#include <sys/queue.h>
50130365Smlaier
51130365Smlaier#include <net/if.h>
52130365Smlaier#include <net/if_types.h>
53130365Smlaier#include <netinet/in.h>
54130365Smlaier#include <netinet/in_systm.h>
55130365Smlaier#include <netinet/ip.h>
56130365Smlaier#ifdef INET6
57130365Smlaier#include <netinet/ip6.h>
58130365Smlaier#endif
59130365Smlaier
60130365Smlaier#include <altq/altq.h>
61130368Smlaier#ifdef ALTQ3_COMPAT
62130365Smlaier#include <altq/altq_conf.h>
63130368Smlaier#endif
64130365Smlaier#include <altq/altq_cdnr.h>
65130365Smlaier
66130365Smlaier#ifdef ALTQ3_COMPAT
67130365Smlaier/*
68130365Smlaier * diffserv traffic conditioning module
69130365Smlaier */
70130365Smlaier
71130365Smlaierint altq_cdnr_enabled = 0;
72130365Smlaier
73130365Smlaier/* traffic conditioner is enabled by ALTQ_CDNR option in opt_altq.h */
74130365Smlaier#ifdef ALTQ_CDNR
75130365Smlaier
76130365Smlaier/* cdnr_list keeps all cdnr's allocated. */
77130365Smlaierstatic LIST_HEAD(, top_cdnr) tcb_list;
78130365Smlaier
79130365Smlaierstatic int altq_cdnr_input(struct mbuf *, int);
80130365Smlaierstatic struct top_cdnr *tcb_lookup(char *ifname);
81130365Smlaierstatic struct cdnr_block *cdnr_handle2cb(u_long);
82130365Smlaierstatic u_long cdnr_cb2handle(struct cdnr_block *);
83130365Smlaierstatic void *cdnr_cballoc(struct top_cdnr *, int,
84130365Smlaier       struct tc_action *(*)(struct cdnr_block *, struct cdnr_pktinfo *));
85130365Smlaierstatic void cdnr_cbdestroy(void *);
86130365Smlaierstatic int tca_verify_action(struct tc_action *);
87130365Smlaierstatic void tca_import_action(struct tc_action *, struct tc_action *);
88130365Smlaierstatic void tca_invalidate_action(struct tc_action *);
89130365Smlaier
90130365Smlaierstatic int generic_element_destroy(struct cdnr_block *);
91130365Smlaierstatic struct top_cdnr *top_create(struct ifaltq *);
92130365Smlaierstatic int top_destroy(struct top_cdnr *);
93130365Smlaierstatic struct cdnr_block *element_create(struct top_cdnr *, struct tc_action *);
94130365Smlaierstatic int element_destroy(struct cdnr_block *);
95130365Smlaierstatic void tb_import_profile(struct tbe *, struct tb_profile *);
96130365Smlaierstatic struct tbmeter *tbm_create(struct top_cdnr *, struct tb_profile *,
97130365Smlaier				  struct tc_action *, struct tc_action *);
98130365Smlaierstatic int tbm_destroy(struct tbmeter *);
99130365Smlaierstatic struct tc_action *tbm_input(struct cdnr_block *, struct cdnr_pktinfo *);
100130365Smlaierstatic struct trtcm *trtcm_create(struct top_cdnr *,
101130365Smlaier		  struct tb_profile *, struct tb_profile *,
102130365Smlaier		  struct tc_action *, struct tc_action *, struct tc_action *,
103130365Smlaier		  int);
104130365Smlaierstatic int trtcm_destroy(struct trtcm *);
105130365Smlaierstatic struct tc_action *trtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
106130365Smlaierstatic struct tswtcm *tswtcm_create(struct top_cdnr *,
107130365Smlaier		  u_int32_t, u_int32_t, u_int32_t,
108130365Smlaier		  struct tc_action *, struct tc_action *, struct tc_action *);
109130365Smlaierstatic int tswtcm_destroy(struct tswtcm *);
110130365Smlaierstatic struct tc_action *tswtcm_input(struct cdnr_block *, struct cdnr_pktinfo *);
111130365Smlaier
112130365Smlaierstatic int cdnrcmd_if_attach(char *);
113130365Smlaierstatic int cdnrcmd_if_detach(char *);
114130365Smlaierstatic int cdnrcmd_add_element(struct cdnr_add_element *);
115130365Smlaierstatic int cdnrcmd_delete_element(struct cdnr_delete_element *);
116130365Smlaierstatic int cdnrcmd_add_filter(struct cdnr_add_filter *);
117130365Smlaierstatic int cdnrcmd_delete_filter(struct cdnr_delete_filter *);
118130365Smlaierstatic int cdnrcmd_add_tbm(struct cdnr_add_tbmeter *);
119130365Smlaierstatic int cdnrcmd_modify_tbm(struct cdnr_modify_tbmeter *);
120130365Smlaierstatic int cdnrcmd_tbm_stats(struct cdnr_tbmeter_stats *);
121130365Smlaierstatic int cdnrcmd_add_trtcm(struct cdnr_add_trtcm *);
122130365Smlaierstatic int cdnrcmd_modify_trtcm(struct cdnr_modify_trtcm *);
123130365Smlaierstatic int cdnrcmd_tcm_stats(struct cdnr_tcm_stats *);
124130365Smlaierstatic int cdnrcmd_add_tswtcm(struct cdnr_add_tswtcm *);
125130365Smlaierstatic int cdnrcmd_modify_tswtcm(struct cdnr_modify_tswtcm *);
126130365Smlaierstatic int cdnrcmd_get_stats(struct cdnr_get_stats *);
127130365Smlaier
128130365Smlaieraltqdev_decl(cdnr);
129130365Smlaier
130130365Smlaier/*
131130365Smlaier * top level input function called from ip_input.
132130365Smlaier * should be called before converting header fields to host-byte-order.
133130365Smlaier */
134130365Smlaierint
135130365Smlaieraltq_cdnr_input(m, af)
136130365Smlaier	struct mbuf	*m;
137130365Smlaier	int		af;	/* address family */
138130365Smlaier{
139130365Smlaier	struct ifnet		*ifp;
140130365Smlaier	struct ip		*ip;
141130365Smlaier	struct top_cdnr		*top;
142130365Smlaier	struct tc_action	*tca;
143130365Smlaier	struct cdnr_block	*cb;
144130365Smlaier	struct cdnr_pktinfo	pktinfo;
145130365Smlaier
146130365Smlaier	ifp = m->m_pkthdr.rcvif;
147130365Smlaier	if (!ALTQ_IS_CNDTNING(&ifp->if_snd))
148130365Smlaier		/* traffic conditioner is not enabled on this interface */
149130365Smlaier		return (1);
150130365Smlaier
151130365Smlaier	top = ifp->if_snd.altq_cdnr;
152130365Smlaier
153130365Smlaier	ip = mtod(m, struct ip *);
154130365Smlaier#ifdef INET6
155130365Smlaier	if (af == AF_INET6) {
156130365Smlaier		u_int32_t flowlabel;
157130365Smlaier
158130365Smlaier		flowlabel = ((struct ip6_hdr *)ip)->ip6_flow;
159130365Smlaier		pktinfo.pkt_dscp = (ntohl(flowlabel) >> 20) & DSCP_MASK;
160130365Smlaier	} else
161130365Smlaier#endif
162130365Smlaier		pktinfo.pkt_dscp = ip->ip_tos & DSCP_MASK;
163130365Smlaier	pktinfo.pkt_len = m_pktlen(m);
164130365Smlaier
165130365Smlaier	tca = NULL;
166130365Smlaier
167130365Smlaier	cb = acc_classify(&top->tc_classifier, m, af);
168130365Smlaier	if (cb != NULL)
169130365Smlaier		tca = &cb->cb_action;
170130365Smlaier
171130365Smlaier	if (tca == NULL)
172130365Smlaier		tca = &top->tc_block.cb_action;
173130365Smlaier
174130365Smlaier	while (1) {
175130365Smlaier		PKTCNTR_ADD(&top->tc_cnts[tca->tca_code], pktinfo.pkt_len);
176130365Smlaier
177130365Smlaier		switch (tca->tca_code) {
178130365Smlaier		case TCACODE_PASS:
179130365Smlaier			return (1);
180130365Smlaier		case TCACODE_DROP:
181130365Smlaier			m_freem(m);
182130365Smlaier			return (0);
183130365Smlaier		case TCACODE_RETURN:
184130365Smlaier			return (0);
185130365Smlaier		case TCACODE_MARK:
186130365Smlaier#ifdef INET6
187130365Smlaier			if (af == AF_INET6) {
188130365Smlaier				struct ip6_hdr *ip6 = (struct ip6_hdr *)ip;
189130365Smlaier				u_int32_t flowlabel;
190130365Smlaier
191130365Smlaier				flowlabel = ntohl(ip6->ip6_flow);
192130365Smlaier				flowlabel = (tca->tca_dscp << 20) |
193130365Smlaier					(flowlabel & ~(DSCP_MASK << 20));
194130365Smlaier				ip6->ip6_flow = htonl(flowlabel);
195130365Smlaier			} else
196130365Smlaier#endif
197130365Smlaier				ip->ip_tos = tca->tca_dscp |
198130365Smlaier					(ip->ip_tos & DSCP_CUMASK);
199130365Smlaier			return (1);
200130365Smlaier		case TCACODE_NEXT:
201130365Smlaier			cb = tca->tca_next;
202130365Smlaier			tca = (*cb->cb_input)(cb, &pktinfo);
203130365Smlaier			break;
204130365Smlaier		case TCACODE_NONE:
205130365Smlaier		default:
206130365Smlaier			return (1);
207130365Smlaier		}
208130365Smlaier	}
209130365Smlaier}
210130365Smlaier
211130365Smlaierstatic struct top_cdnr *
212130365Smlaiertcb_lookup(ifname)
213130365Smlaier	char *ifname;
214130365Smlaier{
215130365Smlaier	struct top_cdnr *top;
216130365Smlaier	struct ifnet *ifp;
217130365Smlaier
218130365Smlaier	if ((ifp = ifunit(ifname)) != NULL)
219130365Smlaier		LIST_FOREACH(top, &tcb_list, tc_next)
220130365Smlaier			if (top->tc_ifq->altq_ifp == ifp)
221130365Smlaier				return (top);
222130365Smlaier	return (NULL);
223130365Smlaier}
224130365Smlaier
225130365Smlaierstatic struct cdnr_block *
226130365Smlaiercdnr_handle2cb(handle)
227130365Smlaier	u_long handle;
228130365Smlaier{
229130365Smlaier	struct cdnr_block *cb;
230130365Smlaier
231130365Smlaier	cb = (struct cdnr_block *)handle;
232130365Smlaier	if (handle != ALIGN(cb))
233130365Smlaier		return (NULL);
234130365Smlaier
235130365Smlaier	if (cb == NULL || cb->cb_handle != handle)
236130365Smlaier		return (NULL);
237130365Smlaier	return (cb);
238130365Smlaier}
239130365Smlaier
240130365Smlaierstatic u_long
241130365Smlaiercdnr_cb2handle(cb)
242130365Smlaier	struct cdnr_block *cb;
243130365Smlaier{
244130365Smlaier	return (cb->cb_handle);
245130365Smlaier}
246130365Smlaier
247130365Smlaierstatic void *
248130365Smlaiercdnr_cballoc(top, type, input_func)
249130365Smlaier	struct top_cdnr *top;
250130365Smlaier	int type;
251130365Smlaier	struct tc_action *(*input_func)(struct cdnr_block *,
252130365Smlaier					struct cdnr_pktinfo *);
253130365Smlaier{
254130365Smlaier	struct cdnr_block *cb;
255130365Smlaier	int size;
256130365Smlaier
257130365Smlaier	switch (type) {
258130365Smlaier	case TCETYPE_TOP:
259130365Smlaier		size = sizeof(struct top_cdnr);
260130365Smlaier		break;
261130365Smlaier	case TCETYPE_ELEMENT:
262130365Smlaier		size = sizeof(struct cdnr_block);
263130365Smlaier		break;
264130365Smlaier	case TCETYPE_TBMETER:
265130365Smlaier		size = sizeof(struct tbmeter);
266130365Smlaier		break;
267130365Smlaier	case TCETYPE_TRTCM:
268130365Smlaier		size = sizeof(struct trtcm);
269130365Smlaier		break;
270130365Smlaier	case TCETYPE_TSWTCM:
271130365Smlaier		size = sizeof(struct tswtcm);
272130365Smlaier		break;
273130365Smlaier	default:
274130365Smlaier		return (NULL);
275130365Smlaier	}
276130365Smlaier
277184205Sdes	cb = malloc(size, M_DEVBUF, M_WAITOK);
278130365Smlaier	if (cb == NULL)
279130365Smlaier		return (NULL);
280130365Smlaier	bzero(cb, size);
281130365Smlaier
282130365Smlaier	cb->cb_len = size;
283130365Smlaier	cb->cb_type = type;
284130365Smlaier	cb->cb_ref = 0;
285130365Smlaier	cb->cb_handle = (u_long)cb;
286130365Smlaier	if (top == NULL)
287130365Smlaier		cb->cb_top = (struct top_cdnr *)cb;
288130365Smlaier	else
289130365Smlaier		cb->cb_top = top;
290130365Smlaier
291130365Smlaier	if (input_func != NULL) {
292130365Smlaier		/*
293130365Smlaier		 * if this cdnr has an action function,
294130365Smlaier		 * make tc_action to call itself.
295130365Smlaier		 */
296130365Smlaier		cb->cb_action.tca_code = TCACODE_NEXT;
297130365Smlaier		cb->cb_action.tca_next = cb;
298130365Smlaier		cb->cb_input = input_func;
299130365Smlaier	} else
300130365Smlaier		cb->cb_action.tca_code = TCACODE_NONE;
301130365Smlaier
302130365Smlaier	/* if this isn't top, register the element to the top level cdnr */
303130365Smlaier	if (top != NULL)
304130365Smlaier		LIST_INSERT_HEAD(&top->tc_elements, cb, cb_next);
305130365Smlaier
306130365Smlaier	return ((void *)cb);
307130365Smlaier}
308130365Smlaier
309130365Smlaierstatic void
310130365Smlaiercdnr_cbdestroy(cblock)
311130365Smlaier	void *cblock;
312130365Smlaier{
313130365Smlaier	struct cdnr_block *cb = cblock;
314130365Smlaier
315130365Smlaier	/* delete filters belonging to this cdnr */
316130365Smlaier	acc_discard_filters(&cb->cb_top->tc_classifier, cb, 0);
317130365Smlaier
318130365Smlaier	/* remove from the top level cdnr */
319130365Smlaier	if (cb->cb_top != cblock)
320130365Smlaier		LIST_REMOVE(cb, cb_next);
321130365Smlaier
322184205Sdes	free(cb, M_DEVBUF);
323130365Smlaier}
324130365Smlaier
325130365Smlaier/*
326130365Smlaier * conditioner common destroy routine
327130365Smlaier */
328130365Smlaierstatic int
329130365Smlaiergeneric_element_destroy(cb)
330130365Smlaier	struct cdnr_block *cb;
331130365Smlaier{
332130365Smlaier	int error = 0;
333130365Smlaier
334130365Smlaier	switch (cb->cb_type) {
335130365Smlaier	case TCETYPE_TOP:
336130365Smlaier		error = top_destroy((struct top_cdnr *)cb);
337130365Smlaier		break;
338130365Smlaier	case TCETYPE_ELEMENT:
339130365Smlaier		error = element_destroy(cb);
340130365Smlaier		break;
341130365Smlaier	case TCETYPE_TBMETER:
342130365Smlaier		error = tbm_destroy((struct tbmeter *)cb);
343130365Smlaier		break;
344130365Smlaier	case TCETYPE_TRTCM:
345130365Smlaier		error = trtcm_destroy((struct trtcm *)cb);
346130365Smlaier		break;
347130365Smlaier	case TCETYPE_TSWTCM:
348130365Smlaier		error = tswtcm_destroy((struct tswtcm *)cb);
349130365Smlaier		break;
350130365Smlaier	default:
351130365Smlaier		error = EINVAL;
352130365Smlaier	}
353130365Smlaier	return (error);
354130365Smlaier}
355130365Smlaier
356130365Smlaierstatic int
357130365Smlaiertca_verify_action(utca)
358130365Smlaier	struct tc_action *utca;
359130365Smlaier{
360130365Smlaier	switch (utca->tca_code) {
361130365Smlaier	case TCACODE_PASS:
362130365Smlaier	case TCACODE_DROP:
363130365Smlaier	case TCACODE_MARK:
364130365Smlaier		/* these are ok */
365130365Smlaier		break;
366130365Smlaier
367130365Smlaier	case TCACODE_HANDLE:
368130365Smlaier		/* verify handle value */
369130365Smlaier		if (cdnr_handle2cb(utca->tca_handle) == NULL)
370130365Smlaier			return (-1);
371130365Smlaier		break;
372130365Smlaier
373130365Smlaier	case TCACODE_NONE:
374130365Smlaier	case TCACODE_RETURN:
375130365Smlaier	case TCACODE_NEXT:
376130365Smlaier	default:
377130365Smlaier		/* should not be passed from a user */
378130365Smlaier		return (-1);
379130365Smlaier	}
380130365Smlaier	return (0);
381130365Smlaier}
382130365Smlaier
383130365Smlaierstatic void
384130365Smlaiertca_import_action(ktca, utca)
385130365Smlaier	struct tc_action *ktca, *utca;
386130365Smlaier{
387130365Smlaier	struct cdnr_block *cb;
388130365Smlaier
389130365Smlaier	*ktca = *utca;
390130365Smlaier	if (ktca->tca_code == TCACODE_HANDLE) {
391130365Smlaier		cb = cdnr_handle2cb(ktca->tca_handle);
392130365Smlaier		if (cb == NULL) {
393130365Smlaier			ktca->tca_code = TCACODE_NONE;
394130365Smlaier			return;
395130365Smlaier		}
396130365Smlaier		ktca->tca_code = TCACODE_NEXT;
397130365Smlaier		ktca->tca_next = cb;
398130365Smlaier		cb->cb_ref++;
399130365Smlaier	} else if (ktca->tca_code == TCACODE_MARK) {
400130365Smlaier		ktca->tca_dscp &= DSCP_MASK;
401130365Smlaier	}
402130365Smlaier	return;
403130365Smlaier}
404130365Smlaier
405130365Smlaierstatic void
406130365Smlaiertca_invalidate_action(tca)
407130365Smlaier	struct tc_action *tca;
408130365Smlaier{
409130365Smlaier	struct cdnr_block *cb;
410130365Smlaier
411130365Smlaier	if (tca->tca_code == TCACODE_NEXT) {
412130365Smlaier		cb = tca->tca_next;
413130365Smlaier		if (cb == NULL)
414130365Smlaier			return;
415130365Smlaier		cb->cb_ref--;
416130365Smlaier	}
417130365Smlaier	tca->tca_code = TCACODE_NONE;
418130365Smlaier}
419130365Smlaier
420130365Smlaier/*
421130365Smlaier * top level traffic conditioner
422130365Smlaier */
423130365Smlaierstatic struct top_cdnr *
424130365Smlaiertop_create(ifq)
425130365Smlaier	struct ifaltq *ifq;
426130365Smlaier{
427130365Smlaier	struct top_cdnr *top;
428130365Smlaier
429130365Smlaier	if ((top = cdnr_cballoc(NULL, TCETYPE_TOP, NULL)) == NULL)
430130365Smlaier		return (NULL);
431130365Smlaier
432130365Smlaier	top->tc_ifq = ifq;
433130365Smlaier	/* set default action for the top level conditioner */
434130365Smlaier	top->tc_block.cb_action.tca_code = TCACODE_PASS;
435130365Smlaier
436130365Smlaier	LIST_INSERT_HEAD(&tcb_list, top, tc_next);
437130365Smlaier
438130365Smlaier	ifq->altq_cdnr = top;
439130365Smlaier
440130365Smlaier	return (top);
441130365Smlaier}
442130365Smlaier
443130365Smlaierstatic int
444130365Smlaiertop_destroy(top)
445130365Smlaier	struct top_cdnr *top;
446130365Smlaier{
447130365Smlaier	struct cdnr_block *cb;
448130365Smlaier
449130365Smlaier	if (ALTQ_IS_CNDTNING(top->tc_ifq))
450130365Smlaier		ALTQ_CLEAR_CNDTNING(top->tc_ifq);
451130365Smlaier	top->tc_ifq->altq_cdnr = NULL;
452130365Smlaier
453130365Smlaier	/*
454130365Smlaier	 * destroy all the conditioner elements belonging to this interface
455130365Smlaier	 */
456130365Smlaier	while ((cb = LIST_FIRST(&top->tc_elements)) != NULL) {
457130365Smlaier		while (cb != NULL && cb->cb_ref > 0)
458130365Smlaier			cb = LIST_NEXT(cb, cb_next);
459130365Smlaier		if (cb != NULL)
460130365Smlaier			generic_element_destroy(cb);
461130365Smlaier	}
462130365Smlaier
463130365Smlaier	LIST_REMOVE(top, tc_next);
464130365Smlaier
465130365Smlaier	cdnr_cbdestroy(top);
466130365Smlaier
467130365Smlaier	/* if there is no active conditioner, remove the input hook */
468130365Smlaier	if (altq_input != NULL) {
469130365Smlaier		LIST_FOREACH(top, &tcb_list, tc_next)
470130365Smlaier			if (ALTQ_IS_CNDTNING(top->tc_ifq))
471130365Smlaier				break;
472130365Smlaier		if (top == NULL)
473130365Smlaier			altq_input = NULL;
474130365Smlaier	}
475130365Smlaier
476130365Smlaier	return (0);
477130365Smlaier}
478130365Smlaier
479130365Smlaier/*
480130365Smlaier * simple tc elements without input function (e.g., dropper and makers).
481130365Smlaier */
482130365Smlaierstatic struct cdnr_block *
483130365Smlaierelement_create(top, action)
484130365Smlaier	struct top_cdnr *top;
485130365Smlaier	struct tc_action *action;
486130365Smlaier{
487130365Smlaier	struct cdnr_block *cb;
488130365Smlaier
489130365Smlaier	if (tca_verify_action(action) < 0)
490130365Smlaier		return (NULL);
491130365Smlaier
492130365Smlaier	if ((cb = cdnr_cballoc(top, TCETYPE_ELEMENT, NULL)) == NULL)
493130365Smlaier		return (NULL);
494130365Smlaier
495130365Smlaier	tca_import_action(&cb->cb_action, action);
496130365Smlaier
497130365Smlaier	return (cb);
498130365Smlaier}
499130365Smlaier
500130365Smlaierstatic int
501130365Smlaierelement_destroy(cb)
502130365Smlaier	struct cdnr_block *cb;
503130365Smlaier{
504130365Smlaier	if (cb->cb_ref > 0)
505130365Smlaier		return (EBUSY);
506130365Smlaier
507130365Smlaier	tca_invalidate_action(&cb->cb_action);
508130365Smlaier
509130365Smlaier	cdnr_cbdestroy(cb);
510130365Smlaier	return (0);
511130365Smlaier}
512130365Smlaier
513130365Smlaier/*
514130365Smlaier * internal representation of token bucket parameters
515130365Smlaier *	rate: 	byte_per_unittime << 32
516130365Smlaier *		(((bits_per_sec) / 8) << 32) / machclk_freq
517130365Smlaier *	depth:	byte << 32
518130365Smlaier *
519130365Smlaier */
520130365Smlaier#define	TB_SHIFT	32
521130365Smlaier#define	TB_SCALE(x)	((u_int64_t)(x) << TB_SHIFT)
522130365Smlaier#define	TB_UNSCALE(x)	((x) >> TB_SHIFT)
523130365Smlaier
524130365Smlaierstatic void
525130365Smlaiertb_import_profile(tb, profile)
526130365Smlaier	struct tbe *tb;
527130365Smlaier	struct tb_profile *profile;
528130365Smlaier{
529130365Smlaier	tb->rate = TB_SCALE(profile->rate / 8) / machclk_freq;
530130365Smlaier	tb->depth = TB_SCALE(profile->depth);
531130365Smlaier	if (tb->rate > 0)
532130365Smlaier		tb->filluptime = tb->depth / tb->rate;
533130365Smlaier	else
534130365Smlaier		tb->filluptime = 0xffffffffffffffffLL;
535130365Smlaier	tb->token = tb->depth;
536130365Smlaier	tb->last = read_machclk();
537130365Smlaier}
538130365Smlaier
539130365Smlaier/*
540130365Smlaier * simple token bucket meter
541130365Smlaier */
542130365Smlaierstatic struct tbmeter *
543130365Smlaiertbm_create(top, profile, in_action, out_action)
544130365Smlaier	struct top_cdnr *top;
545130365Smlaier	struct tb_profile *profile;
546130365Smlaier	struct tc_action *in_action, *out_action;
547130365Smlaier{
548130365Smlaier	struct tbmeter *tbm = NULL;
549130365Smlaier
550130365Smlaier	if (tca_verify_action(in_action) < 0
551130365Smlaier	    || tca_verify_action(out_action) < 0)
552130365Smlaier		return (NULL);
553130365Smlaier
554130365Smlaier	if ((tbm = cdnr_cballoc(top, TCETYPE_TBMETER,
555130365Smlaier				tbm_input)) == NULL)
556130365Smlaier		return (NULL);
557130365Smlaier
558130365Smlaier	tb_import_profile(&tbm->tb, profile);
559130365Smlaier
560130365Smlaier	tca_import_action(&tbm->in_action, in_action);
561130365Smlaier	tca_import_action(&tbm->out_action, out_action);
562130365Smlaier
563130365Smlaier	return (tbm);
564130365Smlaier}
565130365Smlaier
566130365Smlaierstatic int
567130365Smlaiertbm_destroy(tbm)
568130365Smlaier	struct tbmeter *tbm;
569130365Smlaier{
570130365Smlaier	if (tbm->cdnrblk.cb_ref > 0)
571130365Smlaier		return (EBUSY);
572130365Smlaier
573130365Smlaier	tca_invalidate_action(&tbm->in_action);
574130365Smlaier	tca_invalidate_action(&tbm->out_action);
575130365Smlaier
576130365Smlaier	cdnr_cbdestroy(tbm);
577130365Smlaier	return (0);
578130365Smlaier}
579130365Smlaier
580130365Smlaierstatic struct tc_action *
581130365Smlaiertbm_input(cb, pktinfo)
582130365Smlaier	struct cdnr_block *cb;
583130365Smlaier	struct cdnr_pktinfo *pktinfo;
584130365Smlaier{
585130365Smlaier	struct tbmeter *tbm = (struct tbmeter *)cb;
586130365Smlaier	u_int64_t	len;
587130365Smlaier	u_int64_t	interval, now;
588130365Smlaier
589130365Smlaier	len = TB_SCALE(pktinfo->pkt_len);
590130365Smlaier
591130365Smlaier	if (tbm->tb.token < len) {
592130365Smlaier		now = read_machclk();
593130365Smlaier		interval = now - tbm->tb.last;
594130365Smlaier		if (interval >= tbm->tb.filluptime)
595130365Smlaier			tbm->tb.token = tbm->tb.depth;
596130365Smlaier		else {
597130365Smlaier			tbm->tb.token += interval * tbm->tb.rate;
598130365Smlaier			if (tbm->tb.token > tbm->tb.depth)
599130365Smlaier				tbm->tb.token = tbm->tb.depth;
600130365Smlaier		}
601130365Smlaier		tbm->tb.last = now;
602130365Smlaier	}
603130365Smlaier
604130365Smlaier	if (tbm->tb.token < len) {
605130365Smlaier		PKTCNTR_ADD(&tbm->out_cnt, pktinfo->pkt_len);
606130365Smlaier		return (&tbm->out_action);
607130365Smlaier	}
608130365Smlaier
609130365Smlaier	tbm->tb.token -= len;
610130365Smlaier	PKTCNTR_ADD(&tbm->in_cnt, pktinfo->pkt_len);
611130365Smlaier	return (&tbm->in_action);
612130365Smlaier}
613130365Smlaier
614130365Smlaier/*
615130365Smlaier * two rate three color marker
616130365Smlaier * as described in draft-heinanen-diffserv-trtcm-01.txt
617130365Smlaier */
618130365Smlaierstatic struct trtcm *
619130365Smlaiertrtcm_create(top, cmtd_profile, peak_profile,
620130365Smlaier	     green_action, yellow_action, red_action, coloraware)
621130365Smlaier	struct top_cdnr *top;
622130365Smlaier	struct tb_profile *cmtd_profile, *peak_profile;
623130365Smlaier	struct tc_action *green_action, *yellow_action, *red_action;
624130365Smlaier	int	coloraware;
625130365Smlaier{
626130365Smlaier	struct trtcm *tcm = NULL;
627130365Smlaier
628130365Smlaier	if (tca_verify_action(green_action) < 0
629130365Smlaier	    || tca_verify_action(yellow_action) < 0
630130365Smlaier	    || tca_verify_action(red_action) < 0)
631130365Smlaier		return (NULL);
632130365Smlaier
633130365Smlaier	if ((tcm = cdnr_cballoc(top, TCETYPE_TRTCM,
634130365Smlaier				trtcm_input)) == NULL)
635130365Smlaier		return (NULL);
636130365Smlaier
637130365Smlaier	tb_import_profile(&tcm->cmtd_tb, cmtd_profile);
638130365Smlaier	tb_import_profile(&tcm->peak_tb, peak_profile);
639130365Smlaier
640130365Smlaier	tca_import_action(&tcm->green_action, green_action);
641130365Smlaier	tca_import_action(&tcm->yellow_action, yellow_action);
642130365Smlaier	tca_import_action(&tcm->red_action, red_action);
643130365Smlaier
644130365Smlaier	/* set dscps to use */
645130365Smlaier	if (tcm->green_action.tca_code == TCACODE_MARK)
646130365Smlaier		tcm->green_dscp = tcm->green_action.tca_dscp & DSCP_MASK;
647130365Smlaier	else
648130365Smlaier		tcm->green_dscp = DSCP_AF11;
649130365Smlaier	if (tcm->yellow_action.tca_code == TCACODE_MARK)
650130365Smlaier		tcm->yellow_dscp = tcm->yellow_action.tca_dscp & DSCP_MASK;
651130365Smlaier	else
652130365Smlaier		tcm->yellow_dscp = DSCP_AF12;
653130365Smlaier	if (tcm->red_action.tca_code == TCACODE_MARK)
654130365Smlaier		tcm->red_dscp = tcm->red_action.tca_dscp & DSCP_MASK;
655130365Smlaier	else
656130365Smlaier		tcm->red_dscp = DSCP_AF13;
657130365Smlaier
658130365Smlaier	tcm->coloraware = coloraware;
659130365Smlaier
660130365Smlaier	return (tcm);
661130365Smlaier}
662130365Smlaier
663130365Smlaierstatic int
664130365Smlaiertrtcm_destroy(tcm)
665130365Smlaier	struct trtcm *tcm;
666130365Smlaier{
667130365Smlaier	if (tcm->cdnrblk.cb_ref > 0)
668130365Smlaier		return (EBUSY);
669130365Smlaier
670130365Smlaier	tca_invalidate_action(&tcm->green_action);
671130365Smlaier	tca_invalidate_action(&tcm->yellow_action);
672130365Smlaier	tca_invalidate_action(&tcm->red_action);
673130365Smlaier
674130365Smlaier	cdnr_cbdestroy(tcm);
675130365Smlaier	return (0);
676130365Smlaier}
677130365Smlaier
678130365Smlaierstatic struct tc_action *
679130365Smlaiertrtcm_input(cb, pktinfo)
680130365Smlaier	struct cdnr_block *cb;
681130365Smlaier	struct cdnr_pktinfo *pktinfo;
682130365Smlaier{
683130365Smlaier	struct trtcm *tcm = (struct trtcm *)cb;
684130365Smlaier	u_int64_t	len;
685130365Smlaier	u_int64_t	interval, now;
686130365Smlaier	u_int8_t	color;
687130365Smlaier
688130365Smlaier	len = TB_SCALE(pktinfo->pkt_len);
689130365Smlaier	if (tcm->coloraware) {
690130365Smlaier		color = pktinfo->pkt_dscp;
691130365Smlaier		if (color != tcm->yellow_dscp && color != tcm->red_dscp)
692130365Smlaier			color = tcm->green_dscp;
693130365Smlaier	} else {
694130365Smlaier		/* if color-blind, precolor it as green */
695130365Smlaier		color = tcm->green_dscp;
696130365Smlaier	}
697130365Smlaier
698130365Smlaier	now = read_machclk();
699130365Smlaier	if (tcm->cmtd_tb.token < len) {
700130365Smlaier		interval = now - tcm->cmtd_tb.last;
701130365Smlaier		if (interval >= tcm->cmtd_tb.filluptime)
702130365Smlaier			tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
703130365Smlaier		else {
704130365Smlaier			tcm->cmtd_tb.token += interval * tcm->cmtd_tb.rate;
705130365Smlaier			if (tcm->cmtd_tb.token > tcm->cmtd_tb.depth)
706130365Smlaier				tcm->cmtd_tb.token = tcm->cmtd_tb.depth;
707130365Smlaier		}
708130365Smlaier		tcm->cmtd_tb.last = now;
709130365Smlaier	}
710130365Smlaier	if (tcm->peak_tb.token < len) {
711130365Smlaier		interval = now - tcm->peak_tb.last;
712130365Smlaier		if (interval >= tcm->peak_tb.filluptime)
713130365Smlaier			tcm->peak_tb.token = tcm->peak_tb.depth;
714130365Smlaier		else {
715130365Smlaier			tcm->peak_tb.token += interval * tcm->peak_tb.rate;
716130365Smlaier			if (tcm->peak_tb.token > tcm->peak_tb.depth)
717130365Smlaier				tcm->peak_tb.token = tcm->peak_tb.depth;
718130365Smlaier		}
719130365Smlaier		tcm->peak_tb.last = now;
720130365Smlaier	}
721130365Smlaier
722130365Smlaier	if (color == tcm->red_dscp || tcm->peak_tb.token < len) {
723130365Smlaier		pktinfo->pkt_dscp = tcm->red_dscp;
724130365Smlaier		PKTCNTR_ADD(&tcm->red_cnt, pktinfo->pkt_len);
725130365Smlaier		return (&tcm->red_action);
726130365Smlaier	}
727130365Smlaier
728130365Smlaier	if (color == tcm->yellow_dscp || tcm->cmtd_tb.token < len) {
729130365Smlaier		pktinfo->pkt_dscp = tcm->yellow_dscp;
730130365Smlaier		tcm->peak_tb.token -= len;
731130365Smlaier		PKTCNTR_ADD(&tcm->yellow_cnt, pktinfo->pkt_len);
732130365Smlaier		return (&tcm->yellow_action);
733130365Smlaier	}
734130365Smlaier
735130365Smlaier	pktinfo->pkt_dscp = tcm->green_dscp;
736130365Smlaier	tcm->cmtd_tb.token -= len;
737130365Smlaier	tcm->peak_tb.token -= len;
738130365Smlaier	PKTCNTR_ADD(&tcm->green_cnt, pktinfo->pkt_len);
739130365Smlaier	return (&tcm->green_action);
740130365Smlaier}
741130365Smlaier
742130365Smlaier/*
743130365Smlaier * time sliding window three color marker
744130365Smlaier * as described in draft-fang-diffserv-tc-tswtcm-00.txt
745130365Smlaier */
746130365Smlaierstatic struct tswtcm *
747130365Smlaiertswtcm_create(top, cmtd_rate, peak_rate, avg_interval,
748130365Smlaier	      green_action, yellow_action, red_action)
749130365Smlaier	struct top_cdnr *top;
750130365Smlaier	u_int32_t	cmtd_rate, peak_rate, avg_interval;
751130365Smlaier	struct tc_action *green_action, *yellow_action, *red_action;
752130365Smlaier{
753130365Smlaier	struct tswtcm *tsw;
754130365Smlaier
755130365Smlaier	if (tca_verify_action(green_action) < 0
756130365Smlaier	    || tca_verify_action(yellow_action) < 0
757130365Smlaier	    || tca_verify_action(red_action) < 0)
758130365Smlaier		return (NULL);
759130365Smlaier
760130365Smlaier	if ((tsw = cdnr_cballoc(top, TCETYPE_TSWTCM,
761130365Smlaier				tswtcm_input)) == NULL)
762130365Smlaier		return (NULL);
763130365Smlaier
764130365Smlaier	tca_import_action(&tsw->green_action, green_action);
765130365Smlaier	tca_import_action(&tsw->yellow_action, yellow_action);
766130365Smlaier	tca_import_action(&tsw->red_action, red_action);
767130365Smlaier
768130365Smlaier	/* set dscps to use */
769130365Smlaier	if (tsw->green_action.tca_code == TCACODE_MARK)
770130365Smlaier		tsw->green_dscp = tsw->green_action.tca_dscp & DSCP_MASK;
771130365Smlaier	else
772130365Smlaier		tsw->green_dscp = DSCP_AF11;
773130365Smlaier	if (tsw->yellow_action.tca_code == TCACODE_MARK)
774130365Smlaier		tsw->yellow_dscp = tsw->yellow_action.tca_dscp & DSCP_MASK;
775130365Smlaier	else
776130365Smlaier		tsw->yellow_dscp = DSCP_AF12;
777130365Smlaier	if (tsw->red_action.tca_code == TCACODE_MARK)
778130365Smlaier		tsw->red_dscp = tsw->red_action.tca_dscp & DSCP_MASK;
779130365Smlaier	else
780130365Smlaier		tsw->red_dscp = DSCP_AF13;
781130365Smlaier
782130365Smlaier	/* convert rates from bits/sec to bytes/sec */
783130365Smlaier	tsw->cmtd_rate = cmtd_rate / 8;
784130365Smlaier	tsw->peak_rate = peak_rate / 8;
785130365Smlaier	tsw->avg_rate = 0;
786130365Smlaier
787130365Smlaier	/* timewin is converted from msec to machine clock unit */
788130365Smlaier	tsw->timewin = (u_int64_t)machclk_freq * avg_interval / 1000;
789130365Smlaier
790130365Smlaier	return (tsw);
791130365Smlaier}
792130365Smlaier
793130365Smlaierstatic int
794130365Smlaiertswtcm_destroy(tsw)
795130365Smlaier	struct tswtcm *tsw;
796130365Smlaier{
797130365Smlaier	if (tsw->cdnrblk.cb_ref > 0)
798130365Smlaier		return (EBUSY);
799130365Smlaier
800130365Smlaier	tca_invalidate_action(&tsw->green_action);
801130365Smlaier	tca_invalidate_action(&tsw->yellow_action);
802130365Smlaier	tca_invalidate_action(&tsw->red_action);
803130365Smlaier
804130365Smlaier	cdnr_cbdestroy(tsw);
805130365Smlaier	return (0);
806130365Smlaier}
807130365Smlaier
808130365Smlaierstatic struct tc_action *
809130365Smlaiertswtcm_input(cb, pktinfo)
810130365Smlaier	struct cdnr_block *cb;
811130365Smlaier	struct cdnr_pktinfo *pktinfo;
812130365Smlaier{
813130365Smlaier	struct tswtcm	*tsw = (struct tswtcm *)cb;
814130365Smlaier	int		len;
815130365Smlaier	u_int32_t	avg_rate;
816130365Smlaier	u_int64_t	interval, now, tmp;
817130365Smlaier
818130365Smlaier	/*
819130365Smlaier	 * rate estimator
820130365Smlaier	 */
821130365Smlaier	len = pktinfo->pkt_len;
822130365Smlaier	now = read_machclk();
823130365Smlaier
824130365Smlaier	interval = now - tsw->t_front;
825130365Smlaier	/*
826130365Smlaier	 * calculate average rate:
827130365Smlaier	 *	avg = (avg * timewin + pkt_len)/(timewin + interval)
828130365Smlaier	 * pkt_len needs to be multiplied by machclk_freq in order to
829130365Smlaier	 * get (bytes/sec).
830130365Smlaier	 * note: when avg_rate (bytes/sec) and timewin (machclk unit) are
831130365Smlaier	 * less than 32 bits, the following 64-bit operation has enough
832130365Smlaier	 * precision.
833130365Smlaier	 */
834130365Smlaier	tmp = ((u_int64_t)tsw->avg_rate * tsw->timewin
835130365Smlaier	       + (u_int64_t)len * machclk_freq) / (tsw->timewin + interval);
836130365Smlaier	tsw->avg_rate = avg_rate = (u_int32_t)tmp;
837130365Smlaier	tsw->t_front = now;
838130365Smlaier
839130365Smlaier	/*
840130365Smlaier	 * marker
841130365Smlaier	 */
842130365Smlaier	if (avg_rate > tsw->cmtd_rate) {
843130365Smlaier		u_int32_t randval = arc4random() % avg_rate;
844130365Smlaier
845130365Smlaier		if (avg_rate > tsw->peak_rate) {
846130365Smlaier			if (randval < avg_rate - tsw->peak_rate) {
847130365Smlaier				/* mark red */
848130365Smlaier				pktinfo->pkt_dscp = tsw->red_dscp;
849130365Smlaier				PKTCNTR_ADD(&tsw->red_cnt, len);
850130365Smlaier				return (&tsw->red_action);
851130365Smlaier			} else if (randval < avg_rate - tsw->cmtd_rate)
852130365Smlaier				goto mark_yellow;
853130365Smlaier		} else {
854130365Smlaier			/* peak_rate >= avg_rate > cmtd_rate */
855130365Smlaier			if (randval < avg_rate - tsw->cmtd_rate) {
856130365Smlaier			mark_yellow:
857130365Smlaier				pktinfo->pkt_dscp = tsw->yellow_dscp;
858130365Smlaier				PKTCNTR_ADD(&tsw->yellow_cnt, len);
859130365Smlaier				return (&tsw->yellow_action);
860130365Smlaier			}
861130365Smlaier		}
862130365Smlaier	}
863130365Smlaier
864130365Smlaier	/* mark green */
865130365Smlaier	pktinfo->pkt_dscp = tsw->green_dscp;
866130365Smlaier	PKTCNTR_ADD(&tsw->green_cnt, len);
867130365Smlaier	return (&tsw->green_action);
868130365Smlaier}
869130365Smlaier
870130365Smlaier/*
871130365Smlaier * ioctl requests
872130365Smlaier */
873130365Smlaierstatic int
874130365Smlaiercdnrcmd_if_attach(ifname)
875130365Smlaier	char *ifname;
876130365Smlaier{
877130365Smlaier	struct ifnet *ifp;
878130365Smlaier	struct top_cdnr *top;
879130365Smlaier
880130365Smlaier	if ((ifp = ifunit(ifname)) == NULL)
881130365Smlaier		return (EBADF);
882130365Smlaier
883130365Smlaier	if (ifp->if_snd.altq_cdnr != NULL)
884130365Smlaier		return (EBUSY);
885130365Smlaier
886130365Smlaier	if ((top = top_create(&ifp->if_snd)) == NULL)
887130365Smlaier		return (ENOMEM);
888130365Smlaier	return (0);
889130365Smlaier}
890130365Smlaier
891130365Smlaierstatic int
892130365Smlaiercdnrcmd_if_detach(ifname)
893130365Smlaier	char *ifname;
894130365Smlaier{
895130365Smlaier	struct top_cdnr *top;
896130365Smlaier
897130365Smlaier	if ((top = tcb_lookup(ifname)) == NULL)
898130365Smlaier		return (EBADF);
899130365Smlaier
900130365Smlaier	return top_destroy(top);
901130365Smlaier}
902130365Smlaier
903130365Smlaierstatic int
904130365Smlaiercdnrcmd_add_element(ap)
905130365Smlaier	struct cdnr_add_element *ap;
906130365Smlaier{
907130365Smlaier	struct top_cdnr *top;
908130365Smlaier	struct cdnr_block *cb;
909130365Smlaier
910130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
911130365Smlaier		return (EBADF);
912130365Smlaier
913130365Smlaier	cb = element_create(top, &ap->action);
914130365Smlaier	if (cb == NULL)
915130365Smlaier		return (EINVAL);
916130365Smlaier	/* return a class handle to the user */
917130365Smlaier	ap->cdnr_handle = cdnr_cb2handle(cb);
918130365Smlaier	return (0);
919130365Smlaier}
920130365Smlaier
921130365Smlaierstatic int
922130365Smlaiercdnrcmd_delete_element(ap)
923130365Smlaier	struct cdnr_delete_element *ap;
924130365Smlaier{
925130365Smlaier	struct top_cdnr *top;
926130365Smlaier	struct cdnr_block *cb;
927130365Smlaier
928130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
929130365Smlaier		return (EBADF);
930130365Smlaier
931130365Smlaier	if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
932130365Smlaier		return (EINVAL);
933130365Smlaier
934130365Smlaier	if (cb->cb_type != TCETYPE_ELEMENT)
935130365Smlaier		return generic_element_destroy(cb);
936130365Smlaier
937130365Smlaier	return element_destroy(cb);
938130365Smlaier}
939130365Smlaier
940130365Smlaierstatic int
941130365Smlaiercdnrcmd_add_filter(ap)
942130365Smlaier	struct cdnr_add_filter *ap;
943130365Smlaier{
944130365Smlaier	struct top_cdnr *top;
945130365Smlaier	struct cdnr_block *cb;
946130365Smlaier
947130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
948130365Smlaier		return (EBADF);
949130365Smlaier
950130365Smlaier	if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
951130365Smlaier		return (EINVAL);
952130365Smlaier
953130365Smlaier	return acc_add_filter(&top->tc_classifier, &ap->filter,
954130365Smlaier			      cb, &ap->filter_handle);
955130365Smlaier}
956130365Smlaier
957130365Smlaierstatic int
958130365Smlaiercdnrcmd_delete_filter(ap)
959130365Smlaier	struct cdnr_delete_filter *ap;
960130365Smlaier{
961130365Smlaier	struct top_cdnr *top;
962130365Smlaier
963130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
964130365Smlaier		return (EBADF);
965130365Smlaier
966130365Smlaier	return acc_delete_filter(&top->tc_classifier, ap->filter_handle);
967130365Smlaier}
968130365Smlaier
969130365Smlaierstatic int
970130365Smlaiercdnrcmd_add_tbm(ap)
971130365Smlaier	struct cdnr_add_tbmeter *ap;
972130365Smlaier{
973130365Smlaier	struct top_cdnr *top;
974130365Smlaier	struct tbmeter *tbm;
975130365Smlaier
976130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
977130365Smlaier		return (EBADF);
978130365Smlaier
979130365Smlaier	tbm = tbm_create(top, &ap->profile, &ap->in_action, &ap->out_action);
980130365Smlaier	if (tbm == NULL)
981130365Smlaier		return (EINVAL);
982130365Smlaier	/* return a class handle to the user */
983130365Smlaier	ap->cdnr_handle = cdnr_cb2handle(&tbm->cdnrblk);
984130365Smlaier	return (0);
985130365Smlaier}
986130365Smlaier
987130365Smlaierstatic int
988130365Smlaiercdnrcmd_modify_tbm(ap)
989130365Smlaier	struct cdnr_modify_tbmeter *ap;
990130365Smlaier{
991130365Smlaier	struct tbmeter *tbm;
992130365Smlaier
993130365Smlaier	if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
994130365Smlaier		return (EINVAL);
995130365Smlaier
996130365Smlaier	tb_import_profile(&tbm->tb, &ap->profile);
997130365Smlaier
998130365Smlaier	return (0);
999130365Smlaier}
1000130365Smlaier
1001130365Smlaierstatic int
1002130365Smlaiercdnrcmd_tbm_stats(ap)
1003130365Smlaier	struct cdnr_tbmeter_stats *ap;
1004130365Smlaier{
1005130365Smlaier	struct tbmeter *tbm;
1006130365Smlaier
1007130365Smlaier	if ((tbm = (struct tbmeter *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1008130365Smlaier		return (EINVAL);
1009130365Smlaier
1010130365Smlaier	ap->in_cnt = tbm->in_cnt;
1011130365Smlaier	ap->out_cnt = tbm->out_cnt;
1012130365Smlaier
1013130365Smlaier	return (0);
1014130365Smlaier}
1015130365Smlaier
1016130365Smlaierstatic int
1017130365Smlaiercdnrcmd_add_trtcm(ap)
1018130365Smlaier	struct cdnr_add_trtcm *ap;
1019130365Smlaier{
1020130365Smlaier	struct top_cdnr *top;
1021130365Smlaier	struct trtcm *tcm;
1022130365Smlaier
1023130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1024130365Smlaier		return (EBADF);
1025130365Smlaier
1026130365Smlaier	tcm = trtcm_create(top, &ap->cmtd_profile, &ap->peak_profile,
1027130365Smlaier			   &ap->green_action, &ap->yellow_action,
1028130365Smlaier			   &ap->red_action, ap->coloraware);
1029130365Smlaier	if (tcm == NULL)
1030130365Smlaier		return (EINVAL);
1031130365Smlaier
1032130365Smlaier	/* return a class handle to the user */
1033130365Smlaier	ap->cdnr_handle = cdnr_cb2handle(&tcm->cdnrblk);
1034130365Smlaier	return (0);
1035130365Smlaier}
1036130365Smlaier
1037130365Smlaierstatic int
1038130365Smlaiercdnrcmd_modify_trtcm(ap)
1039130365Smlaier	struct cdnr_modify_trtcm *ap;
1040130365Smlaier{
1041130365Smlaier	struct trtcm *tcm;
1042130365Smlaier
1043130365Smlaier	if ((tcm = (struct trtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1044130365Smlaier		return (EINVAL);
1045130365Smlaier
1046130365Smlaier	tb_import_profile(&tcm->cmtd_tb, &ap->cmtd_profile);
1047130365Smlaier	tb_import_profile(&tcm->peak_tb, &ap->peak_profile);
1048130365Smlaier
1049130365Smlaier	return (0);
1050130365Smlaier}
1051130365Smlaier
1052130365Smlaierstatic int
1053130365Smlaiercdnrcmd_tcm_stats(ap)
1054130365Smlaier	struct cdnr_tcm_stats *ap;
1055130365Smlaier{
1056130365Smlaier	struct cdnr_block *cb;
1057130365Smlaier
1058130365Smlaier	if ((cb = cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1059130365Smlaier		return (EINVAL);
1060130365Smlaier
1061130365Smlaier	if (cb->cb_type == TCETYPE_TRTCM) {
1062130365Smlaier	    struct trtcm *tcm = (struct trtcm *)cb;
1063130365Smlaier
1064130365Smlaier	    ap->green_cnt = tcm->green_cnt;
1065130365Smlaier	    ap->yellow_cnt = tcm->yellow_cnt;
1066130365Smlaier	    ap->red_cnt = tcm->red_cnt;
1067130365Smlaier	} else if (cb->cb_type == TCETYPE_TSWTCM) {
1068130365Smlaier	    struct tswtcm *tsw = (struct tswtcm *)cb;
1069130365Smlaier
1070130365Smlaier	    ap->green_cnt = tsw->green_cnt;
1071130365Smlaier	    ap->yellow_cnt = tsw->yellow_cnt;
1072130365Smlaier	    ap->red_cnt = tsw->red_cnt;
1073130365Smlaier	} else
1074130365Smlaier	    return (EINVAL);
1075130365Smlaier
1076130365Smlaier	return (0);
1077130365Smlaier}
1078130365Smlaier
1079130365Smlaierstatic int
1080130365Smlaiercdnrcmd_add_tswtcm(ap)
1081130365Smlaier	struct cdnr_add_tswtcm *ap;
1082130365Smlaier{
1083130365Smlaier	struct top_cdnr *top;
1084130365Smlaier	struct tswtcm *tsw;
1085130365Smlaier
1086130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1087130365Smlaier		return (EBADF);
1088130365Smlaier
1089130365Smlaier	if (ap->cmtd_rate > ap->peak_rate)
1090130365Smlaier		return (EINVAL);
1091130365Smlaier
1092130365Smlaier	tsw = tswtcm_create(top, ap->cmtd_rate, ap->peak_rate,
1093130365Smlaier			    ap->avg_interval, &ap->green_action,
1094130365Smlaier			    &ap->yellow_action, &ap->red_action);
1095130365Smlaier	if (tsw == NULL)
1096130365Smlaier	    return (EINVAL);
1097130365Smlaier
1098130365Smlaier	/* return a class handle to the user */
1099130365Smlaier	ap->cdnr_handle = cdnr_cb2handle(&tsw->cdnrblk);
1100130365Smlaier	return (0);
1101130365Smlaier}
1102130365Smlaier
1103130365Smlaierstatic int
1104130365Smlaiercdnrcmd_modify_tswtcm(ap)
1105130365Smlaier	struct cdnr_modify_tswtcm *ap;
1106130365Smlaier{
1107130365Smlaier	struct tswtcm *tsw;
1108130365Smlaier
1109130365Smlaier	if ((tsw = (struct tswtcm *)cdnr_handle2cb(ap->cdnr_handle)) == NULL)
1110130365Smlaier		return (EINVAL);
1111130365Smlaier
1112130365Smlaier	if (ap->cmtd_rate > ap->peak_rate)
1113130365Smlaier		return (EINVAL);
1114130365Smlaier
1115130365Smlaier	/* convert rates from bits/sec to bytes/sec */
1116130365Smlaier	tsw->cmtd_rate = ap->cmtd_rate / 8;
1117130365Smlaier	tsw->peak_rate = ap->peak_rate / 8;
1118130365Smlaier	tsw->avg_rate = 0;
1119130365Smlaier
1120130365Smlaier	/* timewin is converted from msec to machine clock unit */
1121130365Smlaier	tsw->timewin = (u_int64_t)machclk_freq * ap->avg_interval / 1000;
1122130365Smlaier
1123130365Smlaier	return (0);
1124130365Smlaier}
1125130365Smlaier
1126130365Smlaierstatic int
1127130365Smlaiercdnrcmd_get_stats(ap)
1128130365Smlaier	struct cdnr_get_stats *ap;
1129130365Smlaier{
1130130365Smlaier	struct top_cdnr *top;
1131130365Smlaier	struct cdnr_block *cb;
1132130365Smlaier	struct tbmeter *tbm;
1133130365Smlaier	struct trtcm *tcm;
1134130365Smlaier	struct tswtcm *tsw;
1135130365Smlaier	struct tce_stats tce, *usp;
1136130365Smlaier	int error, n, nskip, nelements;
1137130365Smlaier
1138130365Smlaier	if ((top = tcb_lookup(ap->iface.cdnr_ifname)) == NULL)
1139130365Smlaier		return (EBADF);
1140130365Smlaier
1141130365Smlaier	/* copy action stats */
1142130365Smlaier	bcopy(top->tc_cnts, ap->cnts, sizeof(ap->cnts));
1143130365Smlaier
1144130365Smlaier	/* stats for each element */
1145130365Smlaier	nelements = ap->nelements;
1146130365Smlaier	usp = ap->tce_stats;
1147130365Smlaier	if (nelements <= 0 || usp == NULL)
1148130365Smlaier		return (0);
1149130365Smlaier
1150130365Smlaier	nskip = ap->nskip;
1151130365Smlaier	n = 0;
1152130365Smlaier	LIST_FOREACH(cb, &top->tc_elements, cb_next) {
1153130365Smlaier		if (nskip > 0) {
1154130365Smlaier			nskip--;
1155130365Smlaier			continue;
1156130365Smlaier		}
1157130365Smlaier
1158130365Smlaier		bzero(&tce, sizeof(tce));
1159130365Smlaier		tce.tce_handle = cb->cb_handle;
1160130365Smlaier		tce.tce_type = cb->cb_type;
1161130365Smlaier		switch (cb->cb_type) {
1162130365Smlaier		case TCETYPE_TBMETER:
1163130365Smlaier			tbm = (struct tbmeter *)cb;
1164130365Smlaier			tce.tce_cnts[0] = tbm->in_cnt;
1165130365Smlaier			tce.tce_cnts[1] = tbm->out_cnt;
1166130365Smlaier			break;
1167130365Smlaier		case TCETYPE_TRTCM:
1168130365Smlaier			tcm = (struct trtcm *)cb;
1169130365Smlaier			tce.tce_cnts[0] = tcm->green_cnt;
1170130365Smlaier			tce.tce_cnts[1] = tcm->yellow_cnt;
1171130365Smlaier			tce.tce_cnts[2] = tcm->red_cnt;
1172130365Smlaier			break;
1173130365Smlaier		case TCETYPE_TSWTCM:
1174130365Smlaier			tsw = (struct tswtcm *)cb;
1175130365Smlaier			tce.tce_cnts[0] = tsw->green_cnt;
1176130365Smlaier			tce.tce_cnts[1] = tsw->yellow_cnt;
1177130365Smlaier			tce.tce_cnts[2] = tsw->red_cnt;
1178130365Smlaier			break;
1179130365Smlaier		default:
1180130365Smlaier			continue;
1181130365Smlaier		}
1182130365Smlaier
1183130365Smlaier		if ((error = copyout((caddr_t)&tce, (caddr_t)usp++,
1184130365Smlaier				     sizeof(tce))) != 0)
1185130365Smlaier			return (error);
1186130365Smlaier
1187130365Smlaier		if (++n == nelements)
1188130365Smlaier			break;
1189130365Smlaier	}
1190130365Smlaier	ap->nelements = n;
1191130365Smlaier
1192130365Smlaier	return (0);
1193130365Smlaier}
1194130365Smlaier
1195130365Smlaier/*
1196130365Smlaier * conditioner device interface
1197130365Smlaier */
1198130365Smlaierint
1199130365Smlaiercdnropen(dev, flag, fmt, p)
1200130365Smlaier	dev_t dev;
1201130365Smlaier	int flag, fmt;
1202130365Smlaier#if (__FreeBSD_version > 500000)
1203130365Smlaier	struct thread *p;
1204130365Smlaier#else
1205130365Smlaier	struct proc *p;
1206130365Smlaier#endif
1207130365Smlaier{
1208130365Smlaier	if (machclk_freq == 0)
1209130365Smlaier		init_machclk();
1210130365Smlaier
1211130365Smlaier	if (machclk_freq == 0) {
1212130365Smlaier		printf("cdnr: no cpu clock available!\n");
1213130365Smlaier		return (ENXIO);
1214130365Smlaier	}
1215130365Smlaier
1216130365Smlaier	/* everything will be done when the queueing scheme is attached. */
1217130365Smlaier	return 0;
1218130365Smlaier}
1219130365Smlaier
1220130365Smlaierint
1221130365Smlaiercdnrclose(dev, flag, fmt, p)
1222130365Smlaier	dev_t dev;
1223130365Smlaier	int flag, fmt;
1224130365Smlaier#if (__FreeBSD_version > 500000)
1225130365Smlaier	struct thread *p;
1226130365Smlaier#else
1227130365Smlaier	struct proc *p;
1228130365Smlaier#endif
1229130365Smlaier{
1230130365Smlaier	struct top_cdnr *top;
1231130365Smlaier	int err, error = 0;
1232130365Smlaier
1233130365Smlaier	while ((top = LIST_FIRST(&tcb_list)) != NULL) {
1234130365Smlaier		/* destroy all */
1235130365Smlaier		err = top_destroy(top);
1236130365Smlaier		if (err != 0 && error == 0)
1237130365Smlaier			error = err;
1238130365Smlaier	}
1239130365Smlaier	altq_input = NULL;
1240130365Smlaier
1241130365Smlaier	return (error);
1242130365Smlaier}
1243130365Smlaier
1244130365Smlaierint
1245130365Smlaiercdnrioctl(dev, cmd, addr, flag, p)
1246130365Smlaier	dev_t dev;
1247130365Smlaier	ioctlcmd_t cmd;
1248130365Smlaier	caddr_t addr;
1249130365Smlaier	int flag;
1250130365Smlaier#if (__FreeBSD_version > 500000)
1251130365Smlaier	struct thread *p;
1252130365Smlaier#else
1253130365Smlaier	struct proc *p;
1254130365Smlaier#endif
1255130365Smlaier{
1256130365Smlaier	struct top_cdnr *top;
1257130365Smlaier	struct cdnr_interface *ifacep;
1258130365Smlaier	int	s, error = 0;
1259130365Smlaier
1260130365Smlaier	/* check super-user privilege */
1261130365Smlaier	switch (cmd) {
1262130365Smlaier	case CDNR_GETSTATS:
1263130365Smlaier		break;
1264130365Smlaier	default:
1265164033Srwatson#if (__FreeBSD_version > 700000)
1266164033Srwatson		if ((error = priv_check(p, PRIV_ALTQ_MANAGE)) != 0)
1267164033Srwatson#elsif (__FreeBSD_version > 400000)
1268130365Smlaier		if ((error = suser(p)) != 0)
1269130365Smlaier#else
1270130365Smlaier		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
1271130365Smlaier#endif
1272130365Smlaier			return (error);
1273130365Smlaier		break;
1274130365Smlaier	}
1275130365Smlaier
1276130365Smlaier#ifdef __NetBSD__
1277130365Smlaier	s = splnet();
1278130365Smlaier#else
1279130365Smlaier	s = splimp();
1280130365Smlaier#endif
1281130365Smlaier	switch (cmd) {
1282130365Smlaier
1283130365Smlaier	case CDNR_IF_ATTACH:
1284130365Smlaier		ifacep = (struct cdnr_interface *)addr;
1285130365Smlaier		error = cdnrcmd_if_attach(ifacep->cdnr_ifname);
1286130365Smlaier		break;
1287130365Smlaier
1288130365Smlaier	case CDNR_IF_DETACH:
1289130365Smlaier		ifacep = (struct cdnr_interface *)addr;
1290130365Smlaier		error = cdnrcmd_if_detach(ifacep->cdnr_ifname);
1291130365Smlaier		break;
1292130365Smlaier
1293130365Smlaier	case CDNR_ENABLE:
1294130365Smlaier	case CDNR_DISABLE:
1295130365Smlaier		ifacep = (struct cdnr_interface *)addr;
1296130365Smlaier		if ((top = tcb_lookup(ifacep->cdnr_ifname)) == NULL) {
1297130365Smlaier			error = EBADF;
1298130365Smlaier			break;
1299130365Smlaier		}
1300130365Smlaier
1301130365Smlaier		switch (cmd) {
1302130365Smlaier
1303130365Smlaier		case CDNR_ENABLE:
1304130365Smlaier			ALTQ_SET_CNDTNING(top->tc_ifq);
1305130365Smlaier			if (altq_input == NULL)
1306130365Smlaier				altq_input = altq_cdnr_input;
1307130365Smlaier			break;
1308130365Smlaier
1309130365Smlaier		case CDNR_DISABLE:
1310130365Smlaier			ALTQ_CLEAR_CNDTNING(top->tc_ifq);
1311130365Smlaier			LIST_FOREACH(top, &tcb_list, tc_next)
1312130365Smlaier				if (ALTQ_IS_CNDTNING(top->tc_ifq))
1313130365Smlaier					break;
1314130365Smlaier			if (top == NULL)
1315130365Smlaier				altq_input = NULL;
1316130365Smlaier			break;
1317130365Smlaier		}
1318130365Smlaier		break;
1319130365Smlaier
1320130365Smlaier	case CDNR_ADD_ELEM:
1321130365Smlaier		error = cdnrcmd_add_element((struct cdnr_add_element *)addr);
1322130365Smlaier		break;
1323130365Smlaier
1324130365Smlaier	case CDNR_DEL_ELEM:
1325130365Smlaier		error = cdnrcmd_delete_element((struct cdnr_delete_element *)addr);
1326130365Smlaier		break;
1327130365Smlaier
1328130365Smlaier	case CDNR_ADD_TBM:
1329130365Smlaier		error = cdnrcmd_add_tbm((struct cdnr_add_tbmeter *)addr);
1330130365Smlaier		break;
1331130365Smlaier
1332130365Smlaier	case CDNR_MOD_TBM:
1333130365Smlaier		error = cdnrcmd_modify_tbm((struct cdnr_modify_tbmeter *)addr);
1334130365Smlaier		break;
1335130365Smlaier
1336130365Smlaier	case CDNR_TBM_STATS:
1337130365Smlaier		error = cdnrcmd_tbm_stats((struct cdnr_tbmeter_stats *)addr);
1338130365Smlaier		break;
1339130365Smlaier
1340130365Smlaier	case CDNR_ADD_TCM:
1341130365Smlaier		error = cdnrcmd_add_trtcm((struct cdnr_add_trtcm *)addr);
1342130365Smlaier		break;
1343130365Smlaier
1344130365Smlaier	case CDNR_MOD_TCM:
1345130365Smlaier		error = cdnrcmd_modify_trtcm((struct cdnr_modify_trtcm *)addr);
1346130365Smlaier		break;
1347130365Smlaier
1348130365Smlaier	case CDNR_TCM_STATS:
1349130365Smlaier		error = cdnrcmd_tcm_stats((struct cdnr_tcm_stats *)addr);
1350130365Smlaier		break;
1351130365Smlaier
1352130365Smlaier	case CDNR_ADD_FILTER:
1353130365Smlaier		error = cdnrcmd_add_filter((struct cdnr_add_filter *)addr);
1354130365Smlaier		break;
1355130365Smlaier
1356130365Smlaier	case CDNR_DEL_FILTER:
1357130365Smlaier		error = cdnrcmd_delete_filter((struct cdnr_delete_filter *)addr);
1358130365Smlaier		break;
1359130365Smlaier
1360130365Smlaier	case CDNR_GETSTATS:
1361130365Smlaier		error = cdnrcmd_get_stats((struct cdnr_get_stats *)addr);
1362130365Smlaier		break;
1363130365Smlaier
1364130365Smlaier	case CDNR_ADD_TSW:
1365130365Smlaier		error = cdnrcmd_add_tswtcm((struct cdnr_add_tswtcm *)addr);
1366130365Smlaier		break;
1367130365Smlaier
1368130365Smlaier	case CDNR_MOD_TSW:
1369130365Smlaier		error = cdnrcmd_modify_tswtcm((struct cdnr_modify_tswtcm *)addr);
1370130365Smlaier		break;
1371130365Smlaier
1372130365Smlaier	default:
1373130365Smlaier		error = EINVAL;
1374130365Smlaier		break;
1375130365Smlaier	}
1376130365Smlaier	splx(s);
1377130365Smlaier
1378130365Smlaier	return error;
1379130365Smlaier}
1380130365Smlaier
1381130365Smlaier#ifdef KLD_MODULE
1382130365Smlaier
1383130365Smlaierstatic struct altqsw cdnr_sw =
1384130365Smlaier	{"cdnr", cdnropen, cdnrclose, cdnrioctl};
1385130365Smlaier
1386130365SmlaierALTQ_MODULE(altq_cdnr, ALTQT_CDNR, &cdnr_sw);
1387130365Smlaier
1388130365Smlaier#endif /* KLD_MODULE */
1389130365Smlaier
1390130365Smlaier#endif /* ALTQ3_COMPAT */
1391130365Smlaier#endif /* ALTQ_CDNR */
1392