xref: /onnv-gate/usr/src/uts/common/ipp/meters/tswtclddi.c (revision 7862:f8b6a07acfd6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53902Svi117747  * Common Development and Distribution License (the "License").
63902Svi117747  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213902Svi117747 
220Sstevel@tonic-gate /*
23*7862SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/atomic.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/socket.h>
310Sstevel@tonic-gate #include <netinet/in.h>
320Sstevel@tonic-gate #include <sys/modctl.h>
330Sstevel@tonic-gate #include <sys/sunddi.h>
340Sstevel@tonic-gate #include <ipp/ipp.h>
350Sstevel@tonic-gate #include <ipp/ipp_config.h>
360Sstevel@tonic-gate #include <inet/common.h>
370Sstevel@tonic-gate #include <ipp/meters/meter_impl.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #define	D_SM_COMMENT	"IPP Sliding Window Meter"
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /* DDI file for tswtcl ipp module */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static int tswtcl_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
440Sstevel@tonic-gate static int tswtcl_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
450Sstevel@tonic-gate static int tswtcl_destroy_action(ipp_action_id_t, ipp_flags_t);
460Sstevel@tonic-gate static int tswtcl_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
470Sstevel@tonic-gate     ipp_flags_t);
480Sstevel@tonic-gate static int tswtcl_invoke_action(ipp_action_id_t, ipp_packet_t *);
490Sstevel@tonic-gate 
500Sstevel@tonic-gate /* Stats init function */
510Sstevel@tonic-gate static int tswtcl_statinit(ipp_action_id_t, tswtcl_data_t *);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate /* Stats callback function */
540Sstevel@tonic-gate static int tswtcl_update_stats(ipp_stat_t *, void *, int);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate ipp_ops_t tswtcl_ops = {
570Sstevel@tonic-gate 	IPPO_REV,
580Sstevel@tonic-gate 	tswtcl_create_action,	/* ippo_action_create */
590Sstevel@tonic-gate 	tswtcl_modify_action,	/* ippo_action_modify */
600Sstevel@tonic-gate 	tswtcl_destroy_action,	/* ippo_action_destroy */
610Sstevel@tonic-gate 	tswtcl_info,		/* ippo_action_info */
620Sstevel@tonic-gate 	tswtcl_invoke_action	/* ippo_action_invoke */
630Sstevel@tonic-gate };
640Sstevel@tonic-gate 
650Sstevel@tonic-gate extern struct mod_ops mod_ippops;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Module linkage information for the kernel.
690Sstevel@tonic-gate  */
700Sstevel@tonic-gate static struct modlipp modlipp = {
710Sstevel@tonic-gate 	&mod_ippops,
72*7862SRichard.Bean@Sun.COM 	D_SM_COMMENT,
730Sstevel@tonic-gate 	&tswtcl_ops
740Sstevel@tonic-gate };
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static struct modlinkage modlinkage = {
770Sstevel@tonic-gate 	MODREV_1,
780Sstevel@tonic-gate 	(void *)&modlipp,
790Sstevel@tonic-gate 	NULL
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 
830Sstevel@tonic-gate int
_init(void)840Sstevel@tonic-gate _init(void)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	return (mod_install(&modlinkage));
870Sstevel@tonic-gate }
880Sstevel@tonic-gate 
890Sstevel@tonic-gate int
_fini(void)900Sstevel@tonic-gate _fini(void)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
930Sstevel@tonic-gate }
940Sstevel@tonic-gate 
950Sstevel@tonic-gate int
_info(struct modinfo * modinfop)960Sstevel@tonic-gate _info(struct modinfo *modinfop)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /* ARGSUSED */
1020Sstevel@tonic-gate static int
tswtcl_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)1030Sstevel@tonic-gate tswtcl_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	nvlist_t *nvlp;
1060Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
1070Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
1080Sstevel@tonic-gate 	char *next_action;
1090Sstevel@tonic-gate 	uint32_t bstats;
1100Sstevel@tonic-gate 	int rc, rc2;
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate 	nvlp = *nvlpp;
1130Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL on return */
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	if ((cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP)) == NULL) {
1170Sstevel@tonic-gate 		nvlist_free(nvlp);
1180Sstevel@tonic-gate 		return (ENOMEM);
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	/* parse red next action name */
1220Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
1230Sstevel@tonic-gate 	    &next_action)) != 0) {
1240Sstevel@tonic-gate 		nvlist_free(nvlp);
1250Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, red action" \
1260Sstevel@tonic-gate 		    " name missing\n"));
1270Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1280Sstevel@tonic-gate 		return (rc);
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 	if ((cfg_parms->red_action = ipp_action_lookup(next_action))
1310Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1320Sstevel@tonic-gate 		nvlist_free(nvlp);
1330Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: red action invalid\n"));
1340Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1350Sstevel@tonic-gate 		return (EINVAL);
1360Sstevel@tonic-gate 	}
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	/* parse yellow next action name */
1390Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
1400Sstevel@tonic-gate 	    &next_action)) != 0) {
1410Sstevel@tonic-gate 		nvlist_free(nvlp);
1420Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, yellow " \
1430Sstevel@tonic-gate 		    "action name missing\n"));
1440Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1450Sstevel@tonic-gate 		return (rc);
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 	if ((cfg_parms->yellow_action = ipp_action_lookup(next_action))
1480Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1490Sstevel@tonic-gate 		nvlist_free(nvlp);
1500Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: yellow action invalid\n"));
1510Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1520Sstevel@tonic-gate 		return (EINVAL);
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	/* parse green next action name */
1560Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
1570Sstevel@tonic-gate 	    &next_action)) != 0) {
1580Sstevel@tonic-gate 		nvlist_free(nvlp);
1590Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, green " \
1600Sstevel@tonic-gate 		    "action name missing\n"));
1610Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1620Sstevel@tonic-gate 		return (rc);
1630Sstevel@tonic-gate 	}
1640Sstevel@tonic-gate 	if ((cfg_parms->green_action = ipp_action_lookup(next_action))
1650Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1660Sstevel@tonic-gate 		nvlist_free(nvlp);
1670Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: green action invalid\n"));
1680Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1690Sstevel@tonic-gate 		return (EINVAL);
1700Sstevel@tonic-gate 	}
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/* parse committed rate  - in bits / sec */
1730Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE,
1740Sstevel@tonic-gate 	    &cfg_parms->committed_rate)) != 0) {
1750Sstevel@tonic-gate 		nvlist_free(nvlp);
1760Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1770Sstevel@tonic-gate 		    " committed rate missing\n"));
1780Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1790Sstevel@tonic-gate 		return (rc);
1800Sstevel@tonic-gate 	}
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* parse peak rate  - in bits / sec */
1830Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE,
1840Sstevel@tonic-gate 	    &cfg_parms->peak_rate)) != 0) {
1850Sstevel@tonic-gate 		nvlist_free(nvlp);
1860Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1870Sstevel@tonic-gate 		    " peak rate missing\n"));
1880Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1890Sstevel@tonic-gate 		return (rc);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
1930Sstevel@tonic-gate 		nvlist_free(nvlp);
1940Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1950Sstevel@tonic-gate 		    " peak rate < committed rate\n"));
1960Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1970Sstevel@tonic-gate 		return (EINVAL);
1980Sstevel@tonic-gate 	}
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/* parse window - in msec */
2010Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
2020Sstevel@tonic-gate 	    &cfg_parms->window)) != 0) {
2030Sstevel@tonic-gate 		nvlist_free(nvlp);
2040Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
2050Sstevel@tonic-gate 		    " window missing\n"));
2060Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2070Sstevel@tonic-gate 		return (rc);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 	/* convert to nsec */
2100Sstevel@tonic-gate 	cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
2110Sstevel@tonic-gate 	    METER_MSEC_TO_NSEC;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/* parse stats */
2140Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
2150Sstevel@tonic-gate 	    != 0) {
2160Sstevel@tonic-gate 		cfg_parms->stats = B_FALSE;
2170Sstevel@tonic-gate 	} else {
2180Sstevel@tonic-gate 		cfg_parms->stats = (boolean_t)bstats;
2190Sstevel@tonic-gate 	}
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	nvlist_free(nvlp);
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	/* Initialize other stuff */
2240Sstevel@tonic-gate 	tswtcl_data = kmem_zalloc(TSWTCL_DATA_SZ, KM_NOSLEEP);
2250Sstevel@tonic-gate 	if (tswtcl_data == NULL) {
2260Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2270Sstevel@tonic-gate 		return (ENOMEM);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	if (cfg_parms->stats) {
2310Sstevel@tonic-gate 		if ((rc = tswtcl_statinit(aid, tswtcl_data)) != 0) {
2320Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2333902Svi117747 			kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
2340Sstevel@tonic-gate 			return (rc);
2350Sstevel@tonic-gate 		}
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/* set action chain reference */
2390Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
2400Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2410Sstevel@tonic-gate 		    "returned with error %d", rc));
2420Sstevel@tonic-gate 		goto cleanup;
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
2450Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2460Sstevel@tonic-gate 		    "returned with error %d", rc));
2470Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
2480Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2490Sstevel@tonic-gate 		goto cleanup;
2500Sstevel@tonic-gate 	}
2510Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
2520Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2530Sstevel@tonic-gate 		    "returned with error %d", rc));
2540Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
2550Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2560Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
2570Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2580Sstevel@tonic-gate 		goto cleanup;
2590Sstevel@tonic-gate 	}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 	/* Initializations */
2620Sstevel@tonic-gate 	cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
2630Sstevel@tonic-gate 	tswtcl_data->cfg_parms = cfg_parms;
2640Sstevel@tonic-gate 	tswtcl_data->avg_rate = cfg_parms->committed_rate;
2650Sstevel@tonic-gate 	mutex_init(&tswtcl_data->tswtcl_lock, NULL, MUTEX_DEFAULT, 0);
2660Sstevel@tonic-gate 	tswtcl_data->win_front = gethrtime();
2670Sstevel@tonic-gate 	ipp_action_set_ptr(aid, (void *)tswtcl_data);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	return (0);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate cleanup:
2720Sstevel@tonic-gate 	if (cfg_parms->stats) {
2730Sstevel@tonic-gate 		ipp_stat_destroy(tswtcl_data->stats);
2740Sstevel@tonic-gate 	}
2750Sstevel@tonic-gate 	kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2760Sstevel@tonic-gate 	kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
2770Sstevel@tonic-gate 	return (rc);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate static int
tswtcl_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)2820Sstevel@tonic-gate tswtcl_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
2830Sstevel@tonic-gate {
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	nvlist_t *nvlp;
2860Sstevel@tonic-gate 	int err = 0, err2;
2870Sstevel@tonic-gate 	uint8_t config_type;
2880Sstevel@tonic-gate 	char *next_action_name;
2890Sstevel@tonic-gate 	ipp_action_id_t next_action;
2900Sstevel@tonic-gate 	uint32_t rate;
2910Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms, *old_cfg;
2920Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
2930Sstevel@tonic-gate 	uint32_t bstats;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	nvlp = *nvlpp;
2960Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
2990Sstevel@tonic-gate 	    != 0) {
3000Sstevel@tonic-gate 		nvlist_free(nvlp);
3010Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:invalid configuration type"));
3020Sstevel@tonic-gate 		return (err);
3030Sstevel@tonic-gate 	}
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	if (config_type != IPP_SET) {
3060Sstevel@tonic-gate 		nvlist_free(nvlp);
3070Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:invalid configuration type " \
3080Sstevel@tonic-gate 		    "%d", config_type));
3090Sstevel@tonic-gate 		return (EINVAL);
3100Sstevel@tonic-gate 	}
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
3130Sstevel@tonic-gate 	old_cfg = tswtcl_data->cfg_parms;
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 	cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP);
3160Sstevel@tonic-gate 	if (cfg_parms == NULL) {
3170Sstevel@tonic-gate 		nvlist_free(nvlp);
3180Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:mem. allocation failure\n"));
3190Sstevel@tonic-gate 		return (ENOMEM);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	/* Just copy all and change as needed */
3230Sstevel@tonic-gate 	bcopy(old_cfg, cfg_parms, TSWTCL_CFG_SZ);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/* parse red action name, if present */
3260Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
3270Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3280Sstevel@tonic-gate 		/* Get action id */
3290Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3300Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3310Sstevel@tonic-gate 			nvlist_free(nvlp);
3320Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: red next_action"\
3330Sstevel@tonic-gate 			    " invalid\n"));
3340Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3350Sstevel@tonic-gate 			return (EINVAL);
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 		cfg_parms->red_action = next_action;
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/* parse yellow action name, if present */
3410Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
3420Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3430Sstevel@tonic-gate 		/* Get action id */
3440Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3450Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3460Sstevel@tonic-gate 			nvlist_free(nvlp);
3470Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: yellow next_action"\
3480Sstevel@tonic-gate 			    "  invalid\n"));
3490Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3500Sstevel@tonic-gate 			return (EINVAL);
3510Sstevel@tonic-gate 		}
3520Sstevel@tonic-gate 		cfg_parms->yellow_action = next_action;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/* parse green action name, if present */
3560Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
3570Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3580Sstevel@tonic-gate 		/* Get action id */
3590Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3600Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3610Sstevel@tonic-gate 			nvlist_free(nvlp);
3620Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: green next_action"\
3630Sstevel@tonic-gate 			    " invalid\n"));
3640Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3650Sstevel@tonic-gate 			return (EINVAL);
3660Sstevel@tonic-gate 		}
3670Sstevel@tonic-gate 		cfg_parms->green_action = next_action;
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	/* parse committed rate, if present */
3710Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE, &rate))
3720Sstevel@tonic-gate 	    == 0) {
3730Sstevel@tonic-gate 		cfg_parms->committed_rate = rate;
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/* parse peak rate, if present */
3770Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE, &rate))
3780Sstevel@tonic-gate 	    == 0) {
3790Sstevel@tonic-gate 		cfg_parms->peak_rate = rate;
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
3830Sstevel@tonic-gate 		nvlist_free(nvlp);
3840Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
3850Sstevel@tonic-gate 		    " peak rate < committed rate\n"));
3860Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3870Sstevel@tonic-gate 		return (EINVAL);
3880Sstevel@tonic-gate 	}
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/* parse window - in msec */
3910Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
3920Sstevel@tonic-gate 	    &cfg_parms->window)) != 0) {
3930Sstevel@tonic-gate 		cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
3940Sstevel@tonic-gate 		    METER_MSEC_TO_NSEC;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	/* parse stats, if present */
3980Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) {
3990Sstevel@tonic-gate 		cfg_parms->stats = (boolean_t)bstats;
4000Sstevel@tonic-gate 		if (cfg_parms->stats && !old_cfg->stats) {
4010Sstevel@tonic-gate 			if ((err = tswtcl_statinit(aid, tswtcl_data)) != 0) {
4020Sstevel@tonic-gate 				nvlist_free(nvlp);
4030Sstevel@tonic-gate 				kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4040Sstevel@tonic-gate 				return (err);
4050Sstevel@tonic-gate 			}
4060Sstevel@tonic-gate 		} else if (!cfg_parms->stats && old_cfg->stats) {
4070Sstevel@tonic-gate 			ipp_stat_destroy(tswtcl_data->stats);
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/* Can we ref all the new actions? */
4120Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
4130Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data: can't ref. red action\n"));
4140Sstevel@tonic-gate 		nvlist_free(nvlp);
4150Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4160Sstevel@tonic-gate 		return (err);
4170Sstevel@tonic-gate 	}
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
4200Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data:can't ref. yellow action\n"));
4210Sstevel@tonic-gate 		nvlist_free(nvlp);
4220Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
4230Sstevel@tonic-gate 		ASSERT(err2 == 0);
4240Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4250Sstevel@tonic-gate 		return (err);
4260Sstevel@tonic-gate 	}
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
4290Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data:can't ref. green action\n"));
4300Sstevel@tonic-gate 		nvlist_free(nvlp);
4310Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
4320Sstevel@tonic-gate 		ASSERT(err2 == 0);
4330Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
4340Sstevel@tonic-gate 		ASSERT(err2 == 0);
4350Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4360Sstevel@tonic-gate 		return (err);
4370Sstevel@tonic-gate 	}
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	/* Re-compute pminusc */
4400Sstevel@tonic-gate 	cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate 	/* Actually modify the configuration */
4430Sstevel@tonic-gate 	mutex_enter(&tswtcl_data->tswtcl_lock);
4440Sstevel@tonic-gate 	tswtcl_data->cfg_parms = cfg_parms;
4450Sstevel@tonic-gate 	mutex_exit(&tswtcl_data->tswtcl_lock);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/* Un-ref the old actions */
4480Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->red_action, flags);
4490Sstevel@tonic-gate 	ASSERT(err == 0);
4500Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->yellow_action, flags);
4510Sstevel@tonic-gate 	ASSERT(err == 0);
4520Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->green_action, flags);
4530Sstevel@tonic-gate 	ASSERT(err == 0);
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/* Free the old configuration */
4560Sstevel@tonic-gate 	kmem_free(old_cfg, TSWTCL_CFG_SZ);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	nvlist_free(nvlp);
4590Sstevel@tonic-gate 
4600Sstevel@tonic-gate 	return (0);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate static int
tswtcl_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)4640Sstevel@tonic-gate tswtcl_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
4670Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
4680Sstevel@tonic-gate 	int rc;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
4710Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	cfg_parms = tswtcl_data->cfg_parms;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	if (cfg_parms->stats) {
4760Sstevel@tonic-gate 		ipp_stat_destroy(tswtcl_data->stats);
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	/* unreference the action */
4800Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->red_action, flags);
4810Sstevel@tonic-gate 	ASSERT(rc == 0);
4820Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
4830Sstevel@tonic-gate 	ASSERT(rc == 0);
4840Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->green_action, flags);
4850Sstevel@tonic-gate 	ASSERT(rc == 0);
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	mutex_destroy(&tswtcl_data->tswtcl_lock);
4880Sstevel@tonic-gate 	kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4890Sstevel@tonic-gate 	kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
4900Sstevel@tonic-gate 	return (0);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate static int
tswtcl_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)4940Sstevel@tonic-gate tswtcl_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
4950Sstevel@tonic-gate {
4960Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
4970Sstevel@tonic-gate 	ipp_action_id_t next_action;
4980Sstevel@tonic-gate 	mblk_t *mp = NULL;
4990Sstevel@tonic-gate 	int rc;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/* get mblk from ipp_packet structure */
5020Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
5030Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
5040Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/* tswtcl packet as configured */
5070Sstevel@tonic-gate 	if ((rc = tswtcl_process(&mp, tswtcl_data, &next_action)) != 0) {
5080Sstevel@tonic-gate 		return (rc);
5090Sstevel@tonic-gate 	} else {
5100Sstevel@tonic-gate 		return (ipp_packet_next(packet, next_action));
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate }
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate static int
tswtcl_statinit(ipp_action_id_t aid,tswtcl_data_t * tswtcl_data)5150Sstevel@tonic-gate tswtcl_statinit(ipp_action_id_t aid, tswtcl_data_t *tswtcl_data)
5160Sstevel@tonic-gate {
5170Sstevel@tonic-gate 	int rc = 0;
5180Sstevel@tonic-gate 	meter_stat_t *statsp;
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	/* install stats entry */
5210Sstevel@tonic-gate 	if ((rc = ipp_stat_create(aid, TSWTCL_STATS_STRING, METER_STATS_COUNT,
5220Sstevel@tonic-gate 	    tswtcl_update_stats, tswtcl_data, &tswtcl_data->stats)) != 0) {
5230Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5240Sstevel@tonic-gate 		    " with %d\n", rc));
5250Sstevel@tonic-gate 		return (rc);
5260Sstevel@tonic-gate 	}
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	statsp = (meter_stat_t *)(tswtcl_data->stats)->ipps_data;
5290Sstevel@tonic-gate 	ASSERT(statsp != NULL);
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_packets",
5320Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_packets)) != 0) {
5330Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5340Sstevel@tonic-gate 		    " with %d\n", rc));
5350Sstevel@tonic-gate 		return (rc);
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_bits",
5380Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_bits)) != 0) {
5390Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5400Sstevel@tonic-gate 		    " with %d\n", rc));
5410Sstevel@tonic-gate 		return (rc);
5420Sstevel@tonic-gate 	}
5430Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_packets",
5440Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) {
5450Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5460Sstevel@tonic-gate 		    " with %d\n", rc));
5470Sstevel@tonic-gate 		return (rc);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_bits",
5500Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) {
5510Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5520Sstevel@tonic-gate 		    " with %d\n", rc));
5530Sstevel@tonic-gate 		return (rc);
5540Sstevel@tonic-gate 	}
5550Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_packets",
5560Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_packets)) != 0) {
5570Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5580Sstevel@tonic-gate 		    " with %d\n", rc));
5590Sstevel@tonic-gate 		return (rc);
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_bits",
5620Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_bits)) != 0) {
5630Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5640Sstevel@tonic-gate 		    " with %d\n", rc));
5650Sstevel@tonic-gate 		return (rc);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "epackets",
5680Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->epackets)) != 0) {
5690Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5700Sstevel@tonic-gate 		    " with %d\n", rc));
5710Sstevel@tonic-gate 		return (rc);
5720Sstevel@tonic-gate 	}
5730Sstevel@tonic-gate 	ipp_stat_install(tswtcl_data->stats);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	return (rc);
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate }
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate static int
tswtcl_update_stats(ipp_stat_t * sp,void * args,int rw)5800Sstevel@tonic-gate tswtcl_update_stats(ipp_stat_t *sp, void *args, int rw)
5810Sstevel@tonic-gate {
5820Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data = (tswtcl_data_t *)args;
5830Sstevel@tonic-gate 	meter_stat_t *stats = (meter_stat_t *)sp->ipps_data;
5840Sstevel@tonic-gate 
5850Sstevel@tonic-gate 	ASSERT((tswtcl_data != NULL) && (stats != NULL));
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_packets, &tswtcl_data->red_packets,
5880Sstevel@tonic-gate 	    rw);
5890Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_packets,
5900Sstevel@tonic-gate 	    &tswtcl_data->yellow_packets, rw);
5910Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_packets,
5920Sstevel@tonic-gate 	    &tswtcl_data->green_packets, rw);
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_bits, &tswtcl_data->red_bits, rw);
5950Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_bits,
5960Sstevel@tonic-gate 	    &tswtcl_data->yellow_bits, rw);
5970Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_bits,
5980Sstevel@tonic-gate 	    &tswtcl_data->green_bits, rw);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->epackets, &tswtcl_data->epackets,
6010Sstevel@tonic-gate 	    rw);
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	return (0);
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate /* ARGSUSED */
6070Sstevel@tonic-gate static int
tswtcl_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)6080Sstevel@tonic-gate tswtcl_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
6090Sstevel@tonic-gate     ipp_flags_t flags)
6100Sstevel@tonic-gate {
6110Sstevel@tonic-gate 	nvlist_t *nvlp;
6120Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
6130Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
6140Sstevel@tonic-gate 	char *next_action;
6150Sstevel@tonic-gate 	int rc;
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
6180Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	cfg_parms = tswtcl_data->cfg_parms;
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	/* allocate nvlist to be passed back */
6230Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
6240Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: memory allocation failure\n"));
6250Sstevel@tonic-gate 		return (rc);
6260Sstevel@tonic-gate 	}
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/* look up red next action with the next action id */
6290Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) {
6300Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: red action not available\n"));
6310Sstevel@tonic-gate 		nvlist_free(nvlp);
6320Sstevel@tonic-gate 		return (rc);
6330Sstevel@tonic-gate 	}
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 	/* add next action name */
6360Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_RED_ACTION_NAME,
6370Sstevel@tonic-gate 	    next_action)) != 0) {
6380Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding\n"));
6390Sstevel@tonic-gate 		nvlist_free(nvlp);
6400Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6410Sstevel@tonic-gate 		return (rc);
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/* free action name */
6450Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	/* look up yellow next action with the next action id */
6480Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->yellow_action,
6490Sstevel@tonic-gate 	    &next_action)) != 0) {
6500Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: yellow action not available\n"));
6510Sstevel@tonic-gate 		nvlist_free(nvlp);
6520Sstevel@tonic-gate 		return (rc);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	/* add next action name */
6560Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
6570Sstevel@tonic-gate 	    next_action)) != 0) {
6580Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding yellow action\n"));
6590Sstevel@tonic-gate 		nvlist_free(nvlp);
6600Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6610Sstevel@tonic-gate 		return (rc);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 	/* free action name */
6640Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/* look up green next action with the next action id */
6670Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->green_action,
6680Sstevel@tonic-gate 	    &next_action)) != 0) {
6690Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: green action not available\n"));
6700Sstevel@tonic-gate 		nvlist_free(nvlp);
6710Sstevel@tonic-gate 		return (rc);
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate 	/* add next action name */
6750Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
6760Sstevel@tonic-gate 	    next_action)) != 0) {
6770Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding green action\n"));
6780Sstevel@tonic-gate 		nvlist_free(nvlp);
6790Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6800Sstevel@tonic-gate 		return (rc);
6810Sstevel@tonic-gate 	}
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	/* free action name */
6840Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6850Sstevel@tonic-gate 
6860Sstevel@tonic-gate 	/* add config type */
6870Sstevel@tonic-gate 	if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
6880Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding config_type\n"));
6890Sstevel@tonic-gate 		nvlist_free(nvlp);
6900Sstevel@tonic-gate 		return (rc);
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/* add committed_rate  */
6940Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_COMMITTED_RATE,
6950Sstevel@tonic-gate 	    cfg_parms->committed_rate)) != 0) {
6960Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding committed_rate\n"));
6970Sstevel@tonic-gate 		nvlist_free(nvlp);
6980Sstevel@tonic-gate 		return (rc);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/* add peak_rate  */
7020Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_PEAK_RATE,
7030Sstevel@tonic-gate 	    cfg_parms->peak_rate)) != 0) {
7040Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding peak_rate\n"));
7050Sstevel@tonic-gate 		nvlist_free(nvlp);
7060Sstevel@tonic-gate 		return (rc);
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/* add window  */
7100Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_WINDOW,
7110Sstevel@tonic-gate 	    cfg_parms->window)) != 0) {
7120Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding window\n"));
7130Sstevel@tonic-gate 		nvlist_free(nvlp);
7140Sstevel@tonic-gate 		return (rc);
7150Sstevel@tonic-gate 	}
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
7180Sstevel@tonic-gate 	    (uint32_t)(uintptr_t)tswtcl_data->stats)) != 0) {
7190Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding stats status\n"));
7200Sstevel@tonic-gate 		nvlist_free(nvlp);
7210Sstevel@tonic-gate 		return (rc);
7220Sstevel@tonic-gate 	}
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	/* call back with nvlist */
7250Sstevel@tonic-gate 	rc = fn(nvlp, arg);
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 	nvlist_free(nvlp);
7280Sstevel@tonic-gate 	return (rc);
7290Sstevel@tonic-gate }
730