xref: /onnv-gate/usr/src/uts/common/ipp/meters/tokenmtddi.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/atomic.h>
31*0Sstevel@tonic-gate #include <sys/systm.h>
32*0Sstevel@tonic-gate #include <sys/socket.h>
33*0Sstevel@tonic-gate #include <netinet/in.h>
34*0Sstevel@tonic-gate #include <sys/modctl.h>
35*0Sstevel@tonic-gate #include <sys/sunddi.h>
36*0Sstevel@tonic-gate #include <ipp/ipp.h>
37*0Sstevel@tonic-gate #include <ipp/ipp_config.h>
38*0Sstevel@tonic-gate #include <inet/common.h>
39*0Sstevel@tonic-gate #include <ipp/meters/meter_impl.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #define	D_SM_COMMENT	"IPP Single-Two Rate Token Meter"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate /* DDI file for tokenmt ipp module */
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate /* Default DSCP to colour mapping for colour-aware meter */
46*0Sstevel@tonic-gate enum meter_colour default_dscp_to_colour[64] = {
47*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
48*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
49*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
50*0Sstevel@tonic-gate 	TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
51*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
52*0Sstevel@tonic-gate 	TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
53*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
54*0Sstevel@tonic-gate 	TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
55*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
56*0Sstevel@tonic-gate 	TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
57*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
58*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
59*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
60*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
61*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
62*0Sstevel@tonic-gate 	TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN
63*0Sstevel@tonic-gate };
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate static int tokenmt_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
66*0Sstevel@tonic-gate static int tokenmt_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
67*0Sstevel@tonic-gate static int tokenmt_destroy_action(ipp_action_id_t, ipp_flags_t);
68*0Sstevel@tonic-gate static int tokenmt_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
69*0Sstevel@tonic-gate     ipp_flags_t);
70*0Sstevel@tonic-gate static int tokenmt_invoke_action(ipp_action_id_t, ipp_packet_t *);
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /* Initialize stats */
73*0Sstevel@tonic-gate static int tokenmt_statinit(ipp_action_id_t, tokenmt_data_t *);
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate /* Stats callback function */
76*0Sstevel@tonic-gate static int tokenmt_update_stats(ipp_stat_t *, void *, int);
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate ipp_ops_t tokenmt_ops = {
79*0Sstevel@tonic-gate 	IPPO_REV,
80*0Sstevel@tonic-gate 	tokenmt_create_action,	/* ippo_action_create */
81*0Sstevel@tonic-gate 	tokenmt_modify_action,	/* ippo_action_modify */
82*0Sstevel@tonic-gate 	tokenmt_destroy_action,	/* ippo_action_destroy */
83*0Sstevel@tonic-gate 	tokenmt_info,		/* ippo_action_info */
84*0Sstevel@tonic-gate 	tokenmt_invoke_action	/* ippo_action_invoke */
85*0Sstevel@tonic-gate };
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate extern struct mod_ops mod_ippops;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate /*
90*0Sstevel@tonic-gate  * Module linkage information for the kernel.
91*0Sstevel@tonic-gate  */
92*0Sstevel@tonic-gate static struct modlipp modlipp = {
93*0Sstevel@tonic-gate 	&mod_ippops,
94*0Sstevel@tonic-gate 	D_SM_COMMENT " %I%",
95*0Sstevel@tonic-gate 	&tokenmt_ops
96*0Sstevel@tonic-gate };
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
99*0Sstevel@tonic-gate 	MODREV_1,
100*0Sstevel@tonic-gate 	(void *)&modlipp,
101*0Sstevel@tonic-gate 	NULL
102*0Sstevel@tonic-gate };
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate int
106*0Sstevel@tonic-gate _init(void)
107*0Sstevel@tonic-gate {
108*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
109*0Sstevel@tonic-gate }
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate int
112*0Sstevel@tonic-gate _fini(void)
113*0Sstevel@tonic-gate {
114*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate int
118*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
119*0Sstevel@tonic-gate {
120*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
121*0Sstevel@tonic-gate }
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate /* ARGSUSED */
124*0Sstevel@tonic-gate static int
125*0Sstevel@tonic-gate tokenmt_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
126*0Sstevel@tonic-gate {
127*0Sstevel@tonic-gate 	nvlist_t *nvlp;
128*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data;
129*0Sstevel@tonic-gate 	char *next_action;
130*0Sstevel@tonic-gate 	tokenmt_cfg_t *cfg_parms;
131*0Sstevel@tonic-gate 	uint32_t mode;
132*0Sstevel@tonic-gate 	uint32_t bstats;
133*0Sstevel@tonic-gate 	int rc, rc2;
134*0Sstevel@tonic-gate 	int32_t *colour_tbl;
135*0Sstevel@tonic-gate 	uint_t nelem = 64;
136*0Sstevel@tonic-gate 
137*0Sstevel@tonic-gate 	nvlp = *nvlpp;
138*0Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL on return */
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate 	if ((cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP)) == NULL) {
141*0Sstevel@tonic-gate 		nvlist_free(nvlp);
142*0Sstevel@tonic-gate 		return (ENOMEM);
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	/* parse red next action name */
146*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME,
147*0Sstevel@tonic-gate 	    &next_action)) != 0) {
148*0Sstevel@tonic-gate 		nvlist_free(nvlp);
149*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action:invalid config, red "\
150*0Sstevel@tonic-gate 		    "action name missing\n"));
151*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
152*0Sstevel@tonic-gate 		return (rc);
153*0Sstevel@tonic-gate 	}
154*0Sstevel@tonic-gate 	if ((cfg_parms->red_action = ipp_action_lookup(next_action))
155*0Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
156*0Sstevel@tonic-gate 		nvlist_free(nvlp);
157*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: red action invalid\n"));
158*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
159*0Sstevel@tonic-gate 		return (EINVAL);
160*0Sstevel@tonic-gate 	}
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/* parse yellow next action name, if present  this is Two Rate meter */
163*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
164*0Sstevel@tonic-gate 	    &next_action)) == 0) {
165*0Sstevel@tonic-gate 		if ((cfg_parms->yellow_action = ipp_action_lookup(next_action))
166*0Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
167*0Sstevel@tonic-gate 			nvlist_free(nvlp);
168*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: yellow action "\
169*0Sstevel@tonic-gate 			    "invalid\n"));
170*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
171*0Sstevel@tonic-gate 			return (EINVAL);
172*0Sstevel@tonic-gate 		}
173*0Sstevel@tonic-gate 	} else {
174*0Sstevel@tonic-gate 		cfg_parms->yellow_action = TOKENMT_NO_ACTION;
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	/* parse green next action name */
178*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
179*0Sstevel@tonic-gate 	    &next_action)) != 0) {
180*0Sstevel@tonic-gate 		nvlist_free(nvlp);
181*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action:invalid config, green " \
182*0Sstevel@tonic-gate 		    "action name missing\n"));
183*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
184*0Sstevel@tonic-gate 		return (rc);
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 	if ((cfg_parms->green_action = ipp_action_lookup(next_action))
187*0Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
188*0Sstevel@tonic-gate 		nvlist_free(nvlp);
189*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: green action invalid\n"));
190*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
191*0Sstevel@tonic-gate 		return (EINVAL);
192*0Sstevel@tonic-gate 	}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	/* parse committed rate  - in kilo bits / sec */
195*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE,
196*0Sstevel@tonic-gate 	    &cfg_parms->committed_rate)) != 0) {
197*0Sstevel@tonic-gate 		nvlist_free(nvlp);
198*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: invalid config, "\
199*0Sstevel@tonic-gate 		    " committed rate missing\n"));
200*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
201*0Sstevel@tonic-gate 		return (rc);
202*0Sstevel@tonic-gate 	}
203*0Sstevel@tonic-gate 	if (cfg_parms->committed_rate == 0) {
204*0Sstevel@tonic-gate 		nvlist_free(nvlp);
205*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: invalid committed rate, "\
206*0Sstevel@tonic-gate 		    "%u\n", cfg_parms->committed_rate));
207*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
208*0Sstevel@tonic-gate 		return (EINVAL);
209*0Sstevel@tonic-gate 	}
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 	/* parse committed burst in bits */
212*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST,
213*0Sstevel@tonic-gate 	    &cfg_parms->committed_burst)) != 0) {
214*0Sstevel@tonic-gate 		nvlist_free(nvlp);
215*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: invalid config, "\
216*0Sstevel@tonic-gate 		    " committed burst missing\n"));
217*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
218*0Sstevel@tonic-gate 		return (rc);
219*0Sstevel@tonic-gate 	}
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate 
222*0Sstevel@tonic-gate 	/*
223*0Sstevel@tonic-gate 	 * If the peak burst size is specified, make sure we have the
224*0Sstevel@tonic-gate 	 * yellow action.
225*0Sstevel@tonic-gate 	 */
226*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST,
227*0Sstevel@tonic-gate 	    &cfg_parms->peak_burst)) == 0) {
228*0Sstevel@tonic-gate 		if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
229*0Sstevel@tonic-gate 			nvlist_free(nvlp);
230*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: peak burst "\
231*0Sstevel@tonic-gate 			    "specified without yellow action\n"));
232*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
233*0Sstevel@tonic-gate 			return (EINVAL);
234*0Sstevel@tonic-gate 		}
235*0Sstevel@tonic-gate 	} else if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
236*0Sstevel@tonic-gate 		nvlist_free(nvlp);
237*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: peak burst must be "\
238*0Sstevel@tonic-gate 		    "provided with yellow action\n"));
239*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
240*0Sstevel@tonic-gate 		return (EINVAL);
241*0Sstevel@tonic-gate 	}
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 	/* Check if we have a peak_rate */
244*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE,
245*0Sstevel@tonic-gate 	    &cfg_parms->peak_rate)) == 0) {
246*0Sstevel@tonic-gate 		if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
247*0Sstevel@tonic-gate 			nvlist_free(nvlp);
248*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: peak rate "\
249*0Sstevel@tonic-gate 			    "specified without yellow action\n"));
250*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
251*0Sstevel@tonic-gate 			return (EINVAL);
252*0Sstevel@tonic-gate 		} else if ((cfg_parms->peak_rate == 0) ||
253*0Sstevel@tonic-gate 		    (cfg_parms->peak_rate < cfg_parms->committed_rate)) {
254*0Sstevel@tonic-gate 			nvlist_free(nvlp);
255*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: invalid "\
256*0Sstevel@tonic-gate 			    "peak rate, %u\n", cfg_parms->peak_rate));
257*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
258*0Sstevel@tonic-gate 			return (EINVAL);
259*0Sstevel@tonic-gate 		}
260*0Sstevel@tonic-gate 		cfg_parms->tokenmt_type = TRTCL_TOKENMT;
261*0Sstevel@tonic-gate 	} else {
262*0Sstevel@tonic-gate 		cfg_parms->tokenmt_type = SRTCL_TOKENMT;
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	/* Validate the committed and peak burst size */
266*0Sstevel@tonic-gate 	if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) {
267*0Sstevel@tonic-gate 		if ((cfg_parms->committed_burst == 0) &&
268*0Sstevel@tonic-gate 		    (cfg_parms->peak_burst == 0)) {
269*0Sstevel@tonic-gate 			nvlist_free(nvlp);
270*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: at least one "\
271*0Sstevel@tonic-gate 			    "burst size must be non-zero\n"));
272*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
273*0Sstevel@tonic-gate 			return (EINVAL);
274*0Sstevel@tonic-gate 		}
275*0Sstevel@tonic-gate 	} else {	/* TRTCL_TOKENMT */
276*0Sstevel@tonic-gate 		if ((cfg_parms->committed_burst == 0) ||
277*0Sstevel@tonic-gate 		    (cfg_parms->peak_burst == 0)) {
278*0Sstevel@tonic-gate 			nvlist_free(nvlp);
279*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: both the "\
280*0Sstevel@tonic-gate 			    "burst sizes must be non-zero\n"));
281*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
282*0Sstevel@tonic-gate 			return (EINVAL);
283*0Sstevel@tonic-gate 		}
284*0Sstevel@tonic-gate 	}
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate 	/* just copy default colour mapping */
287*0Sstevel@tonic-gate 	bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour,
288*0Sstevel@tonic-gate 	    sizeof (default_dscp_to_colour));
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	/* parse mode, if present */
291*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE,
292*0Sstevel@tonic-gate 	    &mode)) != 0) {
293*0Sstevel@tonic-gate 		cfg_parms->colour_aware = B_FALSE;
294*0Sstevel@tonic-gate 	} else {
295*0Sstevel@tonic-gate 		cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE;
296*0Sstevel@tonic-gate 	}
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	/* Get the dscp to colour mapping array */
299*0Sstevel@tonic-gate 	if (cfg_parms->colour_aware) {
300*0Sstevel@tonic-gate 		if ((rc = nvlist_lookup_int32_array(nvlp,
301*0Sstevel@tonic-gate 		    TOKENMT_COLOUR_MAP, &colour_tbl, &nelem)) == 0) {
302*0Sstevel@tonic-gate 			int count;
303*0Sstevel@tonic-gate 			for (count = 0; count < 64; count++) {
304*0Sstevel@tonic-gate 				if (colour_tbl[count] == -1)
305*0Sstevel@tonic-gate 					continue;
306*0Sstevel@tonic-gate 				cfg_parms->dscp_to_colour[count] =
307*0Sstevel@tonic-gate 				    colour_tbl[count];
308*0Sstevel@tonic-gate 			}
309*0Sstevel@tonic-gate 		}
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	/* parse stats */
313*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
314*0Sstevel@tonic-gate 	    != 0) {
315*0Sstevel@tonic-gate 		cfg_parms->stats = B_FALSE;
316*0Sstevel@tonic-gate 	} else {
317*0Sstevel@tonic-gate 		cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE;
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	nvlist_free(nvlp);
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 	/* Initialize other stuff */
323*0Sstevel@tonic-gate 	tokenmt_data = kmem_zalloc(TOKENMT_DATA_SZ, KM_NOSLEEP);
324*0Sstevel@tonic-gate 	if (tokenmt_data == NULL) {
325*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
326*0Sstevel@tonic-gate 		return (ENOMEM);
327*0Sstevel@tonic-gate 	}
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	/* Initialize stats, if required */
330*0Sstevel@tonic-gate 	if (cfg_parms->stats) {
331*0Sstevel@tonic-gate 		if ((rc = tokenmt_statinit(aid, tokenmt_data)) != 0) {
332*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
333*0Sstevel@tonic-gate 			kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
334*0Sstevel@tonic-gate 			return (rc);
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	/* set action chain reference */
339*0Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
340*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \
341*0Sstevel@tonic-gate 		    "returned with error %d", rc));
342*0Sstevel@tonic-gate 		goto cleanup;
343*0Sstevel@tonic-gate 	}
344*0Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
345*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \
346*0Sstevel@tonic-gate 		    "returned with error %d", rc));
347*0Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
348*0Sstevel@tonic-gate 		ASSERT(rc2 == 0);
349*0Sstevel@tonic-gate 		goto cleanup;
350*0Sstevel@tonic-gate 	}
351*0Sstevel@tonic-gate 
352*0Sstevel@tonic-gate 	if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
353*0Sstevel@tonic-gate 		if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action,
354*0Sstevel@tonic-gate 		    flags)) != 0) {
355*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_create_action: ipp_action_ref "\
356*0Sstevel@tonic-gate 			    "returned with error %d", rc));
357*0Sstevel@tonic-gate 			rc2 = ipp_action_unref(aid, cfg_parms->red_action,
358*0Sstevel@tonic-gate 			    flags);
359*0Sstevel@tonic-gate 			ASSERT(rc2 == 0);
360*0Sstevel@tonic-gate 			rc2 = ipp_action_unref(aid, cfg_parms->green_action,
361*0Sstevel@tonic-gate 			    flags);
362*0Sstevel@tonic-gate 			ASSERT(rc2 == 0);
363*0Sstevel@tonic-gate 			goto cleanup;
364*0Sstevel@tonic-gate 		}
365*0Sstevel@tonic-gate 	}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 
368*0Sstevel@tonic-gate 	tokenmt_data->cfg_parms = cfg_parms;
369*0Sstevel@tonic-gate 
370*0Sstevel@tonic-gate 	tokenmt_data->committed_tokens = cfg_parms->committed_burst;
371*0Sstevel@tonic-gate 	tokenmt_data->peak_tokens = cfg_parms->peak_burst;
372*0Sstevel@tonic-gate 	tokenmt_data->last_seen = gethrtime();
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 	mutex_init(&tokenmt_data->tokenmt_lock, NULL, MUTEX_DEFAULT, 0);
375*0Sstevel@tonic-gate 	ipp_action_set_ptr(aid, (void *)tokenmt_data);
376*0Sstevel@tonic-gate 	return (0);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate cleanup:
379*0Sstevel@tonic-gate 	if (cfg_parms->stats) {
380*0Sstevel@tonic-gate 		ipp_stat_destroy(tokenmt_data->stats);
381*0Sstevel@tonic-gate 	}
382*0Sstevel@tonic-gate 	kmem_free(cfg_parms, TOKENMT_CFG_SZ);
383*0Sstevel@tonic-gate 	kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
384*0Sstevel@tonic-gate 	return (rc);
385*0Sstevel@tonic-gate }
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate static int
388*0Sstevel@tonic-gate tokenmt_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
389*0Sstevel@tonic-gate {
390*0Sstevel@tonic-gate 	nvlist_t *nvlp;
391*0Sstevel@tonic-gate 	int err = 0, err2;
392*0Sstevel@tonic-gate 	uint8_t config_type;
393*0Sstevel@tonic-gate 	char *next_action_name;
394*0Sstevel@tonic-gate 	ipp_action_id_t next_action;
395*0Sstevel@tonic-gate 	uint32_t rate, cbs, pbs;
396*0Sstevel@tonic-gate 	tokenmt_cfg_t *cfg_parms, *old_cfg;
397*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data;
398*0Sstevel@tonic-gate 	uint32_t bstats, mode;
399*0Sstevel@tonic-gate 	int32_t *colour_tbl;
400*0Sstevel@tonic-gate 	uint_t nelem = 64;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	nvlp = *nvlpp;
403*0Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
406*0Sstevel@tonic-gate 	    != 0) {
407*0Sstevel@tonic-gate 		nvlist_free(nvlp);
408*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\
409*0Sstevel@tonic-gate 		    "type"));
410*0Sstevel@tonic-gate 		return (err);
411*0Sstevel@tonic-gate 	}
412*0Sstevel@tonic-gate 
413*0Sstevel@tonic-gate 	if (config_type != IPP_SET) {
414*0Sstevel@tonic-gate 		nvlist_free(nvlp);
415*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\
416*0Sstevel@tonic-gate 		    "type %d", config_type));
417*0Sstevel@tonic-gate 		return (EINVAL);
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
421*0Sstevel@tonic-gate 	old_cfg = tokenmt_data->cfg_parms;
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP);
424*0Sstevel@tonic-gate 	if (cfg_parms == NULL) {
425*0Sstevel@tonic-gate 		nvlist_free(nvlp);
426*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_modify_action: memory allocation "\
427*0Sstevel@tonic-gate 		    "failure\n"));
428*0Sstevel@tonic-gate 		return (ENOMEM);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	/* Just copy all and change as needed */
432*0Sstevel@tonic-gate 	bcopy(old_cfg, cfg_parms, TOKENMT_CFG_SZ);
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate 	/* parse red action name, if present */
435*0Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME,
436*0Sstevel@tonic-gate 	    &next_action_name)) == 0) {
437*0Sstevel@tonic-gate 		/* Get action id */
438*0Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
439*0Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
440*0Sstevel@tonic-gate 			nvlist_free(nvlp);
441*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: next_action "\
442*0Sstevel@tonic-gate 			    "invalid"));
443*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
444*0Sstevel@tonic-gate 			return (EINVAL);
445*0Sstevel@tonic-gate 		}
446*0Sstevel@tonic-gate 		cfg_parms->red_action = next_action;
447*0Sstevel@tonic-gate 	}
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate 	/* parse yellow action name, if present */
450*0Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
451*0Sstevel@tonic-gate 	    &next_action_name)) == 0) {
452*0Sstevel@tonic-gate 		/* Get action id */
453*0Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
454*0Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
455*0Sstevel@tonic-gate 			nvlist_free(nvlp);
456*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: next_action "\
457*0Sstevel@tonic-gate 			    "invalid"));
458*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
459*0Sstevel@tonic-gate 			return (EINVAL);
460*0Sstevel@tonic-gate 		}
461*0Sstevel@tonic-gate 		cfg_parms->yellow_action = next_action;
462*0Sstevel@tonic-gate 	} else {
463*0Sstevel@tonic-gate 		cfg_parms->yellow_action = TOKENMT_NO_ACTION;
464*0Sstevel@tonic-gate 	}
465*0Sstevel@tonic-gate 
466*0Sstevel@tonic-gate 	/* parse green action name, if present */
467*0Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
468*0Sstevel@tonic-gate 	    &next_action_name)) == 0) {
469*0Sstevel@tonic-gate 		/* Get action id */
470*0Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
471*0Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
472*0Sstevel@tonic-gate 			nvlist_free(nvlp);
473*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: next_action "\
474*0Sstevel@tonic-gate 			    "invalid"));
475*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
476*0Sstevel@tonic-gate 			return (EINVAL);
477*0Sstevel@tonic-gate 		}
478*0Sstevel@tonic-gate 		cfg_parms->green_action = next_action;
479*0Sstevel@tonic-gate 	}
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate 	/* parse committed rate, if present */
482*0Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE, &rate))
483*0Sstevel@tonic-gate 	    == 0) {
484*0Sstevel@tonic-gate 		if (rate == 0) {
485*0Sstevel@tonic-gate 			nvlist_free(nvlp);
486*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: invalid "\
487*0Sstevel@tonic-gate 			    "committed rate %u\n", cfg_parms->committed_rate));
488*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
489*0Sstevel@tonic-gate 			return (EINVAL);
490*0Sstevel@tonic-gate 		}
491*0Sstevel@tonic-gate 		cfg_parms->committed_rate = rate;
492*0Sstevel@tonic-gate 	}
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 	/* parse committed burst, if present */
495*0Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST, &cbs) == 0) {
496*0Sstevel@tonic-gate 		cfg_parms->committed_burst = cbs;
497*0Sstevel@tonic-gate 	}
498*0Sstevel@tonic-gate 
499*0Sstevel@tonic-gate 
500*0Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST, &pbs) == 0) {
501*0Sstevel@tonic-gate 		cfg_parms->peak_burst = pbs;
502*0Sstevel@tonic-gate 	} else {
503*0Sstevel@tonic-gate 		cfg_parms->peak_burst = 0;
504*0Sstevel@tonic-gate 	}
505*0Sstevel@tonic-gate 
506*0Sstevel@tonic-gate 	/* If the peak rate is not specified, then it means single rate meter */
507*0Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE, &rate) == 0) {
508*0Sstevel@tonic-gate 		cfg_parms->peak_rate = rate;
509*0Sstevel@tonic-gate 		if ((rate == 0) || (rate < cfg_parms->committed_rate)) {
510*0Sstevel@tonic-gate 			nvlist_free(nvlp);
511*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: invalid "\
512*0Sstevel@tonic-gate 			    "committed rate %u\n", cfg_parms->committed_rate));
513*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
514*0Sstevel@tonic-gate 			return (EINVAL);
515*0Sstevel@tonic-gate 		}
516*0Sstevel@tonic-gate 		cfg_parms->tokenmt_type = TRTCL_TOKENMT;
517*0Sstevel@tonic-gate 	} else {
518*0Sstevel@tonic-gate 		cfg_parms->peak_rate = 0;
519*0Sstevel@tonic-gate 		cfg_parms->tokenmt_type = SRTCL_TOKENMT;
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
523*0Sstevel@tonic-gate 		if ((cfg_parms->peak_burst != 0) ||
524*0Sstevel@tonic-gate 		    (cfg_parms->tokenmt_type == TRTCL_TOKENMT)) {
525*0Sstevel@tonic-gate 			nvlist_free(nvlp);
526*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: yellow action "\
527*0Sstevel@tonic-gate 			    "missing\n"));
528*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
529*0Sstevel@tonic-gate 			return (EINVAL);
530*0Sstevel@tonic-gate 		}
531*0Sstevel@tonic-gate 	} else {
532*0Sstevel@tonic-gate 		if ((cfg_parms->tokenmt_type != TRTCL_TOKENMT) &&
533*0Sstevel@tonic-gate 		    (cfg_parms->peak_burst == 0)) {
534*0Sstevel@tonic-gate 			nvlist_free(nvlp);
535*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: peak "\
536*0Sstevel@tonic-gate 			    "burst/rate missing\n"));
537*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
538*0Sstevel@tonic-gate 			return (EINVAL);
539*0Sstevel@tonic-gate 		}
540*0Sstevel@tonic-gate 	}
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	/* Validate the committed and peak burst size */
543*0Sstevel@tonic-gate 	if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) {
544*0Sstevel@tonic-gate 		if ((cfg_parms->committed_burst == 0) &&
545*0Sstevel@tonic-gate 		    (cfg_parms->peak_burst == 0)) {
546*0Sstevel@tonic-gate 			nvlist_free(nvlp);
547*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: at least one "\
548*0Sstevel@tonic-gate 			    "burst size must be non-zero\n"));
549*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
550*0Sstevel@tonic-gate 			return (EINVAL);
551*0Sstevel@tonic-gate 		}
552*0Sstevel@tonic-gate 	} else {	/* TRTCL_TOKENMT */
553*0Sstevel@tonic-gate 		if ((cfg_parms->committed_burst == 0) ||
554*0Sstevel@tonic-gate 		    (cfg_parms->peak_burst == 0)) {
555*0Sstevel@tonic-gate 			nvlist_free(nvlp);
556*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_action: both the "\
557*0Sstevel@tonic-gate 			    "burst sizes must be non-zero\n"));
558*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
559*0Sstevel@tonic-gate 			return (EINVAL);
560*0Sstevel@tonic-gate 		}
561*0Sstevel@tonic-gate 	}
562*0Sstevel@tonic-gate 
563*0Sstevel@tonic-gate 	/* parse mode */
564*0Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE, &mode) == 0) {
565*0Sstevel@tonic-gate 		cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE;
566*0Sstevel@tonic-gate 	} else {
567*0Sstevel@tonic-gate 		cfg_parms->colour_aware = B_FALSE;
568*0Sstevel@tonic-gate 	}
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 	if (cfg_parms->colour_aware) {
571*0Sstevel@tonic-gate 		if (nvlist_lookup_int32_array(nvlp, TOKENMT_COLOUR_MAP,
572*0Sstevel@tonic-gate 		    &colour_tbl, &nelem) == 0) {
573*0Sstevel@tonic-gate 			int count;
574*0Sstevel@tonic-gate 			for (count = 0; count < 64; count++) {
575*0Sstevel@tonic-gate 				if (colour_tbl[count] == -1)
576*0Sstevel@tonic-gate 					continue;
577*0Sstevel@tonic-gate 				cfg_parms->dscp_to_colour[count] =
578*0Sstevel@tonic-gate 				    colour_tbl[count];
579*0Sstevel@tonic-gate 			}
580*0Sstevel@tonic-gate 		} else {
581*0Sstevel@tonic-gate 			bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour,
582*0Sstevel@tonic-gate 			    sizeof (default_dscp_to_colour));
583*0Sstevel@tonic-gate 		}
584*0Sstevel@tonic-gate 	}
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 	/* parse stats, if present */
587*0Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) {
588*0Sstevel@tonic-gate 		cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE;
589*0Sstevel@tonic-gate 		if (cfg_parms->stats && !old_cfg->stats) {
590*0Sstevel@tonic-gate 			if ((err = tokenmt_statinit(aid, tokenmt_data)) != 0) {
591*0Sstevel@tonic-gate 				nvlist_free(nvlp);
592*0Sstevel@tonic-gate 				kmem_free(cfg_parms, TOKENMT_CFG_SZ);
593*0Sstevel@tonic-gate 				return (err);
594*0Sstevel@tonic-gate 			}
595*0Sstevel@tonic-gate 		} else if (!cfg_parms->stats && old_cfg->stats) {
596*0Sstevel@tonic-gate 			ipp_stat_destroy(tokenmt_data->stats);
597*0Sstevel@tonic-gate 		}
598*0Sstevel@tonic-gate 	}
599*0Sstevel@tonic-gate 
600*0Sstevel@tonic-gate 	/* Can we ref all the new actions? */
601*0Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
602*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_modify_data: can't ref. red action\n"));
603*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
604*0Sstevel@tonic-gate 		return (err);
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
607*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_modify_data:can't ref. green action\n"));
608*0Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
609*0Sstevel@tonic-gate 		ASSERT(err2 == 0);
610*0Sstevel@tonic-gate 		kmem_free(cfg_parms, TOKENMT_CFG_SZ);
611*0Sstevel@tonic-gate 		return (err);
612*0Sstevel@tonic-gate 	}
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 	if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
615*0Sstevel@tonic-gate 		if ((err = ipp_action_ref(aid, cfg_parms->yellow_action,
616*0Sstevel@tonic-gate 		    flags)) != 0) {
617*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_modify_data:can't ref. yellow "\
618*0Sstevel@tonic-gate 			    "action\n"));
619*0Sstevel@tonic-gate 			err2 = ipp_action_unref(aid, cfg_parms->red_action,
620*0Sstevel@tonic-gate 			    flags);
621*0Sstevel@tonic-gate 			ASSERT(err2 == 0);
622*0Sstevel@tonic-gate 			err2 = ipp_action_unref(aid, cfg_parms->green_action,
623*0Sstevel@tonic-gate 			    flags);
624*0Sstevel@tonic-gate 			ASSERT(err2 == 0);
625*0Sstevel@tonic-gate 			kmem_free(cfg_parms, TOKENMT_CFG_SZ);
626*0Sstevel@tonic-gate 			return (err);
627*0Sstevel@tonic-gate 		}
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 
630*0Sstevel@tonic-gate 
631*0Sstevel@tonic-gate 	/* Actually modify the configuration */
632*0Sstevel@tonic-gate 	mutex_enter(&tokenmt_data->tokenmt_lock);
633*0Sstevel@tonic-gate 	tokenmt_data->cfg_parms = cfg_parms;
634*0Sstevel@tonic-gate 	mutex_exit(&tokenmt_data->tokenmt_lock);
635*0Sstevel@tonic-gate 
636*0Sstevel@tonic-gate 	/* Un-ref the old actions */
637*0Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->red_action, flags);
638*0Sstevel@tonic-gate 	ASSERT(err == 0);
639*0Sstevel@tonic-gate 	if (old_cfg->yellow_action != TOKENMT_NO_ACTION) {
640*0Sstevel@tonic-gate 		err = ipp_action_unref(aid, old_cfg->yellow_action, flags);
641*0Sstevel@tonic-gate 		ASSERT(err == 0);
642*0Sstevel@tonic-gate 	}
643*0Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->green_action, flags);
644*0Sstevel@tonic-gate 	ASSERT(err == 0);
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	/* Free the old configuration */
647*0Sstevel@tonic-gate 	kmem_free(old_cfg, TOKENMT_CFG_SZ);
648*0Sstevel@tonic-gate 	return (0);
649*0Sstevel@tonic-gate }
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate static int
652*0Sstevel@tonic-gate tokenmt_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
653*0Sstevel@tonic-gate {
654*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data;
655*0Sstevel@tonic-gate 	tokenmt_cfg_t *cfg_parms;
656*0Sstevel@tonic-gate 	int rc;
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate 	tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
659*0Sstevel@tonic-gate 	ASSERT(tokenmt_data != NULL);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 	cfg_parms = tokenmt_data->cfg_parms;
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	if (cfg_parms->stats) {
664*0Sstevel@tonic-gate 		ipp_stat_destroy(tokenmt_data->stats);
665*0Sstevel@tonic-gate 	}
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 	/* unreference the action */
668*0Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->red_action, flags);
669*0Sstevel@tonic-gate 	ASSERT(rc == 0);
670*0Sstevel@tonic-gate 	if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
671*0Sstevel@tonic-gate 		rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
672*0Sstevel@tonic-gate 		ASSERT(rc == 0);
673*0Sstevel@tonic-gate 	}
674*0Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->green_action, flags);
675*0Sstevel@tonic-gate 	ASSERT(rc == 0);
676*0Sstevel@tonic-gate 
677*0Sstevel@tonic-gate 	mutex_destroy(&tokenmt_data->tokenmt_lock);
678*0Sstevel@tonic-gate 	kmem_free(cfg_parms, TOKENMT_CFG_SZ);
679*0Sstevel@tonic-gate 	kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
680*0Sstevel@tonic-gate 	return (0);
681*0Sstevel@tonic-gate }
682*0Sstevel@tonic-gate 
683*0Sstevel@tonic-gate static int
684*0Sstevel@tonic-gate tokenmt_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
685*0Sstevel@tonic-gate {
686*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data;
687*0Sstevel@tonic-gate 	ipp_action_id_t next_action;
688*0Sstevel@tonic-gate 	mblk_t *mp = NULL;
689*0Sstevel@tonic-gate 	int rc;
690*0Sstevel@tonic-gate 
691*0Sstevel@tonic-gate 	/* get mblk from ipp_packet structure */
692*0Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
693*0Sstevel@tonic-gate 	tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
694*0Sstevel@tonic-gate 	ASSERT(tokenmt_data != NULL);
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 	/* meter packet as configured */
697*0Sstevel@tonic-gate 	if ((rc = tokenmt_process(&mp, tokenmt_data, &next_action)) != 0) {
698*0Sstevel@tonic-gate 		return (rc);
699*0Sstevel@tonic-gate 	} else {
700*0Sstevel@tonic-gate 		return (ipp_packet_next(packet, next_action));
701*0Sstevel@tonic-gate 	}
702*0Sstevel@tonic-gate }
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate static int
705*0Sstevel@tonic-gate tokenmt_statinit(ipp_action_id_t aid, tokenmt_data_t *tokenmt_data) {
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	int rc = 0;
708*0Sstevel@tonic-gate 	meter_stat_t *statsp;
709*0Sstevel@tonic-gate 
710*0Sstevel@tonic-gate 	/* install stats entry */
711*0Sstevel@tonic-gate 	if ((rc = ipp_stat_create(aid, TOKENMT_STATS_STRING, METER_STATS_COUNT,
712*0Sstevel@tonic-gate 	    tokenmt_update_stats, tokenmt_data, &tokenmt_data->stats)) != 0) {
713*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit: ipp_stat_create failed "\
714*0Sstevel@tonic-gate 		    " with %d\n", rc));
715*0Sstevel@tonic-gate 		return (rc);
716*0Sstevel@tonic-gate 	}
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	statsp = (meter_stat_t *)(tokenmt_data->stats)->ipps_data;
719*0Sstevel@tonic-gate 	ASSERT(statsp != NULL);
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "red_packets",
722*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_packets)) != 0) {
723*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
724*0Sstevel@tonic-gate 		    " with %d\n", rc));
725*0Sstevel@tonic-gate 		return (rc);
726*0Sstevel@tonic-gate 	}
727*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "yellow_packets",
728*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) {
729*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
730*0Sstevel@tonic-gate 		    " with %d\n", rc));
731*0Sstevel@tonic-gate 		return (rc);
732*0Sstevel@tonic-gate 	}
733*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "green_packets",
734*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_packets)) != 0) {
735*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
736*0Sstevel@tonic-gate 		    " with %d\n", rc));
737*0Sstevel@tonic-gate 		return (rc);
738*0Sstevel@tonic-gate 	}
739*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "red_bits",
740*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_bits)) != 0) {
741*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
742*0Sstevel@tonic-gate 		    " with %d\n", rc));
743*0Sstevel@tonic-gate 		return (rc);
744*0Sstevel@tonic-gate 	}
745*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "yellow_bits",
746*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) {
747*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
748*0Sstevel@tonic-gate 		    " with %d\n", rc));
749*0Sstevel@tonic-gate 		return (rc);
750*0Sstevel@tonic-gate 	}
751*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "green_bits",
752*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_bits)) != 0) {
753*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
754*0Sstevel@tonic-gate 		    " with %d\n", rc));
755*0Sstevel@tonic-gate 		return (rc);
756*0Sstevel@tonic-gate 	}
757*0Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tokenmt_data->stats, "epackets",
758*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->epackets)) != 0) {
759*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
760*0Sstevel@tonic-gate 		    " with %d\n", rc));
761*0Sstevel@tonic-gate 		return (rc);
762*0Sstevel@tonic-gate 	}
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 	ipp_stat_install(tokenmt_data->stats);
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 	return (rc);
767*0Sstevel@tonic-gate }
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate static int
770*0Sstevel@tonic-gate tokenmt_update_stats(ipp_stat_t *sp, void *args, int rw)
771*0Sstevel@tonic-gate {
772*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data = (tokenmt_data_t *)args;
773*0Sstevel@tonic-gate 	meter_stat_t *stats = (meter_stat_t *)sp->ipps_data;
774*0Sstevel@tonic-gate 
775*0Sstevel@tonic-gate 	ASSERT((tokenmt_data != NULL) && (stats != NULL));
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_packets,
778*0Sstevel@tonic-gate 	    &tokenmt_data->red_packets, rw);
779*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_packets,
780*0Sstevel@tonic-gate 	    &tokenmt_data->yellow_packets, rw);
781*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_packets,
782*0Sstevel@tonic-gate 	    &tokenmt_data->green_packets, rw);
783*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_bits,
784*0Sstevel@tonic-gate 	    &tokenmt_data->red_bits, rw);
785*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_bits,
786*0Sstevel@tonic-gate 	    &tokenmt_data->yellow_bits, rw);
787*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_bits,
788*0Sstevel@tonic-gate 	    &tokenmt_data->green_bits, rw);
789*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->epackets, &tokenmt_data->epackets,
790*0Sstevel@tonic-gate 	    rw);
791*0Sstevel@tonic-gate 
792*0Sstevel@tonic-gate 	return (0);
793*0Sstevel@tonic-gate }
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate /* ARGSUSED */
796*0Sstevel@tonic-gate static int
797*0Sstevel@tonic-gate tokenmt_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
798*0Sstevel@tonic-gate     ipp_flags_t flags)
799*0Sstevel@tonic-gate {
800*0Sstevel@tonic-gate 	nvlist_t *nvlp;
801*0Sstevel@tonic-gate 	tokenmt_data_t *tokenmt_data;
802*0Sstevel@tonic-gate 	tokenmt_cfg_t *cfg_parms;
803*0Sstevel@tonic-gate 	char *next_action;
804*0Sstevel@tonic-gate 	int32_t dscp_to_colour[64];
805*0Sstevel@tonic-gate 	int rc;
806*0Sstevel@tonic-gate 
807*0Sstevel@tonic-gate 	tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
808*0Sstevel@tonic-gate 	ASSERT(tokenmt_data != NULL);
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate 	cfg_parms = tokenmt_data->cfg_parms;
811*0Sstevel@tonic-gate 
812*0Sstevel@tonic-gate 	/* allocate nvlist to be passed back */
813*0Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
814*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: memory allocation failure\n"));
815*0Sstevel@tonic-gate 		return (rc);
816*0Sstevel@tonic-gate 	}
817*0Sstevel@tonic-gate 
818*0Sstevel@tonic-gate 	/* look up red next action with the next action id */
819*0Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) {
820*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: red_action not available\n"));
821*0Sstevel@tonic-gate 		nvlist_free(nvlp);
822*0Sstevel@tonic-gate 		return (rc);
823*0Sstevel@tonic-gate 	}
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	/* add next action name */
826*0Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TOKENMT_RED_ACTION_NAME,
827*0Sstevel@tonic-gate 	    next_action)) != 0) {
828*0Sstevel@tonic-gate 		nvlist_free(nvlp);
829*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding red_action\n"));
830*0Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
831*0Sstevel@tonic-gate 		return (rc);
832*0Sstevel@tonic-gate 	}
833*0Sstevel@tonic-gate 
834*0Sstevel@tonic-gate 	/* free action name */
835*0Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate 
838*0Sstevel@tonic-gate 	/* look up yellow next action with the next action id */
839*0Sstevel@tonic-gate 	if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
840*0Sstevel@tonic-gate 		if ((rc = ipp_action_name(cfg_parms->yellow_action,
841*0Sstevel@tonic-gate 		    &next_action)) != 0) {
842*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_info: yellow_action not "\
843*0Sstevel@tonic-gate 			    "available\n"));
844*0Sstevel@tonic-gate 			nvlist_free(nvlp);
845*0Sstevel@tonic-gate 			return (rc);
846*0Sstevel@tonic-gate 		}
847*0Sstevel@tonic-gate 		/* add next action name */
848*0Sstevel@tonic-gate 		if ((rc = nvlist_add_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
849*0Sstevel@tonic-gate 		    next_action)) != 0) {
850*0Sstevel@tonic-gate 			nvlist_free(nvlp);
851*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_info: error adding "\
852*0Sstevel@tonic-gate 			    "yellow_action\n"));
853*0Sstevel@tonic-gate 			kmem_free(next_action, (strlen(next_action) + 1));
854*0Sstevel@tonic-gate 			return (rc);
855*0Sstevel@tonic-gate 		}
856*0Sstevel@tonic-gate 		/* free action name */
857*0Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
858*0Sstevel@tonic-gate 	}
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	/* look up green next action with the next action id */
861*0Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->green_action,
862*0Sstevel@tonic-gate 	    &next_action)) != 0) {
863*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: green_action not available\n"));
864*0Sstevel@tonic-gate 		nvlist_free(nvlp);
865*0Sstevel@tonic-gate 		return (rc);
866*0Sstevel@tonic-gate 	}
867*0Sstevel@tonic-gate 
868*0Sstevel@tonic-gate 	/* add next action name */
869*0Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
870*0Sstevel@tonic-gate 	    next_action)) != 0) {
871*0Sstevel@tonic-gate 		nvlist_free(nvlp);
872*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding green_action\n"));
873*0Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
874*0Sstevel@tonic-gate 		return (rc);
875*0Sstevel@tonic-gate 	}
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate 	/* free action name */
878*0Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	/* add config type */
881*0Sstevel@tonic-gate 	if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
882*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding config_type\n"));
883*0Sstevel@tonic-gate 		nvlist_free(nvlp);
884*0Sstevel@tonic-gate 		return (rc);
885*0Sstevel@tonic-gate 	}
886*0Sstevel@tonic-gate 
887*0Sstevel@tonic-gate 	/* add committed_rate  */
888*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COMMITTED_RATE,
889*0Sstevel@tonic-gate 	    cfg_parms->committed_rate)) != 0) {
890*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding committed_rate\n"));
891*0Sstevel@tonic-gate 		nvlist_free(nvlp);
892*0Sstevel@tonic-gate 		return (rc);
893*0Sstevel@tonic-gate 	}
894*0Sstevel@tonic-gate 
895*0Sstevel@tonic-gate 	if (cfg_parms->tokenmt_type == TRTCL_TOKENMT) {
896*0Sstevel@tonic-gate 		/* add peak  rate */
897*0Sstevel@tonic-gate 		if ((rc = nvlist_add_uint32(nvlp, TOKENMT_PEAK_RATE,
898*0Sstevel@tonic-gate 		    cfg_parms->peak_rate)) != 0) {
899*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_info: error adding peak_rate\n"));
900*0Sstevel@tonic-gate 			nvlist_free(nvlp);
901*0Sstevel@tonic-gate 			return (rc);
902*0Sstevel@tonic-gate 		}
903*0Sstevel@tonic-gate 	}
904*0Sstevel@tonic-gate 
905*0Sstevel@tonic-gate 	/* add committed_burst  */
906*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COMMITTED_BURST,
907*0Sstevel@tonic-gate 	    cfg_parms->committed_burst)) != 0) {
908*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding committed_burst\n"));
909*0Sstevel@tonic-gate 		nvlist_free(nvlp);
910*0Sstevel@tonic-gate 		return (rc);
911*0Sstevel@tonic-gate 	}
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate 	/* add peak_burst  */
914*0Sstevel@tonic-gate 	if (cfg_parms->peak_burst != 0) {
915*0Sstevel@tonic-gate 		if ((rc = nvlist_add_uint32(nvlp, TOKENMT_PEAK_BURST,
916*0Sstevel@tonic-gate 		    cfg_parms->peak_burst)) != 0) {
917*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_info: error adding peak "\
918*0Sstevel@tonic-gate 			    "burst\n"));
919*0Sstevel@tonic-gate 			nvlist_free(nvlp);
920*0Sstevel@tonic-gate 			return (rc);
921*0Sstevel@tonic-gate 		}
922*0Sstevel@tonic-gate 	}
923*0Sstevel@tonic-gate 
924*0Sstevel@tonic-gate 	/* add colour aware  */
925*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COLOUR_AWARE,
926*0Sstevel@tonic-gate 	    cfg_parms->colour_aware)) != 0) {
927*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding mode\n"));
928*0Sstevel@tonic-gate 		nvlist_free(nvlp);
929*0Sstevel@tonic-gate 		return (rc);
930*0Sstevel@tonic-gate 	}
931*0Sstevel@tonic-gate 
932*0Sstevel@tonic-gate 	if (cfg_parms->colour_aware) {
933*0Sstevel@tonic-gate 		bcopy(cfg_parms->dscp_to_colour, dscp_to_colour,
934*0Sstevel@tonic-gate 		    sizeof (cfg_parms->dscp_to_colour));
935*0Sstevel@tonic-gate 		if ((rc = nvlist_add_int32_array(nvlp, TOKENMT_COLOUR_MAP,
936*0Sstevel@tonic-gate 		    dscp_to_colour, 64)) != 0) {
937*0Sstevel@tonic-gate 			tokenmt0dbg(("tokenmt_info: error adding colour "\
938*0Sstevel@tonic-gate 			    "array\n"));
939*0Sstevel@tonic-gate 			nvlist_free(nvlp);
940*0Sstevel@tonic-gate 			return (rc);
941*0Sstevel@tonic-gate 		}
942*0Sstevel@tonic-gate 	}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
945*0Sstevel@tonic-gate 	    (uint32_t)cfg_parms->stats)) != 0) {
946*0Sstevel@tonic-gate 		tokenmt0dbg(("tokenmt_info: error adding stats status\n"));
947*0Sstevel@tonic-gate 		nvlist_free(nvlp);
948*0Sstevel@tonic-gate 		return (rc);
949*0Sstevel@tonic-gate 	}
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 	/* call back with nvlist */
952*0Sstevel@tonic-gate 	rc = fn(nvlp, arg);
953*0Sstevel@tonic-gate 
954*0Sstevel@tonic-gate 	nvlist_free(nvlp);
955*0Sstevel@tonic-gate 	return (rc);
956*0Sstevel@tonic-gate }
957