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