17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56d730a61Svi  * Common Development and Distribution License (the "License").
66d730a61Svi  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
216d730a61Svi 
227c478bd9Sstevel@tonic-gate /*
23*39b361b2SRichard Bean  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/socket.h>
317c478bd9Sstevel@tonic-gate #include <netinet/in.h>
327c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
337c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
347c478bd9Sstevel@tonic-gate #include <ipp/ipp.h>
357c478bd9Sstevel@tonic-gate #include <ipp/ipp_config.h>
367c478bd9Sstevel@tonic-gate #include <inet/common.h>
377c478bd9Sstevel@tonic-gate #include <ipp/meters/meter_impl.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #define	D_SM_COMMENT	"IPP Sliding Window Meter"
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate /* DDI file for tswtcl ipp module */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static int tswtcl_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
447c478bd9Sstevel@tonic-gate static int tswtcl_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
457c478bd9Sstevel@tonic-gate static int tswtcl_destroy_action(ipp_action_id_t, ipp_flags_t);
467c478bd9Sstevel@tonic-gate static int tswtcl_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
477c478bd9Sstevel@tonic-gate     ipp_flags_t);
487c478bd9Sstevel@tonic-gate static int tswtcl_invoke_action(ipp_action_id_t, ipp_packet_t *);
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* Stats init function */
517c478bd9Sstevel@tonic-gate static int tswtcl_statinit(ipp_action_id_t, tswtcl_data_t *);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* Stats callback function */
547c478bd9Sstevel@tonic-gate static int tswtcl_update_stats(ipp_stat_t *, void *, int);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate ipp_ops_t tswtcl_ops = {
577c478bd9Sstevel@tonic-gate 	IPPO_REV,
587c478bd9Sstevel@tonic-gate 	tswtcl_create_action,	/* ippo_action_create */
597c478bd9Sstevel@tonic-gate 	tswtcl_modify_action,	/* ippo_action_modify */
607c478bd9Sstevel@tonic-gate 	tswtcl_destroy_action,	/* ippo_action_destroy */
617c478bd9Sstevel@tonic-gate 	tswtcl_info,		/* ippo_action_info */
627c478bd9Sstevel@tonic-gate 	tswtcl_invoke_action	/* ippo_action_invoke */
637c478bd9Sstevel@tonic-gate };
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate extern struct mod_ops mod_ippops;
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
697c478bd9Sstevel@tonic-gate  */
707c478bd9Sstevel@tonic-gate static struct modlipp modlipp = {
717c478bd9Sstevel@tonic-gate 	&mod_ippops,
72*39b361b2SRichard Bean 	D_SM_COMMENT,
737c478bd9Sstevel@tonic-gate 	&tswtcl_ops
747c478bd9Sstevel@tonic-gate };
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
777c478bd9Sstevel@tonic-gate 	MODREV_1,
787c478bd9Sstevel@tonic-gate 	(void *)&modlipp,
797c478bd9Sstevel@tonic-gate 	NULL
807c478bd9Sstevel@tonic-gate };
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate int
_init(void)847c478bd9Sstevel@tonic-gate _init(void)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate int
_fini(void)907c478bd9Sstevel@tonic-gate _fini(void)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)967c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* ARGSUSED */
1027c478bd9Sstevel@tonic-gate static int
tswtcl_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)1037c478bd9Sstevel@tonic-gate tswtcl_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
1067c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
1077c478bd9Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
1087c478bd9Sstevel@tonic-gate 	char *next_action;
1097c478bd9Sstevel@tonic-gate 	uint32_t bstats;
1107c478bd9Sstevel@tonic-gate 	int rc, rc2;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	nvlp = *nvlpp;
1137c478bd9Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL on return */
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	if ((cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP)) == NULL) {
1177c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1187c478bd9Sstevel@tonic-gate 		return (ENOMEM);
1197c478bd9Sstevel@tonic-gate 	}
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	/* parse red next action name */
1227c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
1237c478bd9Sstevel@tonic-gate 	    &next_action)) != 0) {
1247c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1257c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, red action" \
1267c478bd9Sstevel@tonic-gate 		    " name missing\n"));
1277c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1287c478bd9Sstevel@tonic-gate 		return (rc);
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 	if ((cfg_parms->red_action = ipp_action_lookup(next_action))
1317c478bd9Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1327c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1337c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: red action invalid\n"));
1347c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1357c478bd9Sstevel@tonic-gate 		return (EINVAL);
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	/* parse yellow next action name */
1397c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
1407c478bd9Sstevel@tonic-gate 	    &next_action)) != 0) {
1417c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1427c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, yellow " \
1437c478bd9Sstevel@tonic-gate 		    "action name missing\n"));
1447c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1457c478bd9Sstevel@tonic-gate 		return (rc);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 	if ((cfg_parms->yellow_action = ipp_action_lookup(next_action))
1487c478bd9Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1497c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1507c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: yellow action invalid\n"));
1517c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1527c478bd9Sstevel@tonic-gate 		return (EINVAL);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* parse green next action name */
1567c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
1577c478bd9Sstevel@tonic-gate 	    &next_action)) != 0) {
1587c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1597c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action:invalid config, green " \
1607c478bd9Sstevel@tonic-gate 		    "action name missing\n"));
1617c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1627c478bd9Sstevel@tonic-gate 		return (rc);
1637c478bd9Sstevel@tonic-gate 	}
1647c478bd9Sstevel@tonic-gate 	if ((cfg_parms->green_action = ipp_action_lookup(next_action))
1657c478bd9Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
1667c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1677c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: green action invalid\n"));
1687c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1697c478bd9Sstevel@tonic-gate 		return (EINVAL);
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	/* parse committed rate  - in bits / sec */
1737c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE,
1747c478bd9Sstevel@tonic-gate 	    &cfg_parms->committed_rate)) != 0) {
1757c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1767c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1777c478bd9Sstevel@tonic-gate 		    " committed rate missing\n"));
1787c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1797c478bd9Sstevel@tonic-gate 		return (rc);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* parse peak rate  - in bits / sec */
1837c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE,
1847c478bd9Sstevel@tonic-gate 	    &cfg_parms->peak_rate)) != 0) {
1857c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1867c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1877c478bd9Sstevel@tonic-gate 		    " peak rate missing\n"));
1887c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1897c478bd9Sstevel@tonic-gate 		return (rc);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
1937c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
1947c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
1957c478bd9Sstevel@tonic-gate 		    " peak rate < committed rate\n"));
1967c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
1977c478bd9Sstevel@tonic-gate 		return (EINVAL);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	/* parse window - in msec */
2017c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
2027c478bd9Sstevel@tonic-gate 	    &cfg_parms->window)) != 0) {
2037c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
2047c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
2057c478bd9Sstevel@tonic-gate 		    " window missing\n"));
2067c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2077c478bd9Sstevel@tonic-gate 		return (rc);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	/* convert to nsec */
2107c478bd9Sstevel@tonic-gate 	cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
2117c478bd9Sstevel@tonic-gate 	    METER_MSEC_TO_NSEC;
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	/* parse stats */
2147c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
2157c478bd9Sstevel@tonic-gate 	    != 0) {
2167c478bd9Sstevel@tonic-gate 		cfg_parms->stats = B_FALSE;
2177c478bd9Sstevel@tonic-gate 	} else {
2187c478bd9Sstevel@tonic-gate 		cfg_parms->stats = (boolean_t)bstats;
2197c478bd9Sstevel@tonic-gate 	}
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	nvlist_free(nvlp);
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	/* Initialize other stuff */
2247c478bd9Sstevel@tonic-gate 	tswtcl_data = kmem_zalloc(TSWTCL_DATA_SZ, KM_NOSLEEP);
2257c478bd9Sstevel@tonic-gate 	if (tswtcl_data == NULL) {
2267c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2277c478bd9Sstevel@tonic-gate 		return (ENOMEM);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if (cfg_parms->stats) {
2317c478bd9Sstevel@tonic-gate 		if ((rc = tswtcl_statinit(aid, tswtcl_data)) != 0) {
2327c478bd9Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2336d730a61Svi 			kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
2347c478bd9Sstevel@tonic-gate 			return (rc);
2357c478bd9Sstevel@tonic-gate 		}
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/* set action chain reference */
2397c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
2407c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2417c478bd9Sstevel@tonic-gate 		    "returned with error %d", rc));
2427c478bd9Sstevel@tonic-gate 		goto cleanup;
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
2457c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2467c478bd9Sstevel@tonic-gate 		    "returned with error %d", rc));
2477c478bd9Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
2487c478bd9Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2497c478bd9Sstevel@tonic-gate 		goto cleanup;
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
2527c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
2537c478bd9Sstevel@tonic-gate 		    "returned with error %d", rc));
2547c478bd9Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
2557c478bd9Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2567c478bd9Sstevel@tonic-gate 		rc2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
2577c478bd9Sstevel@tonic-gate 		ASSERT(rc2 == 0);
2587c478bd9Sstevel@tonic-gate 		goto cleanup;
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	/* Initializations */
2627c478bd9Sstevel@tonic-gate 	cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
2637c478bd9Sstevel@tonic-gate 	tswtcl_data->cfg_parms = cfg_parms;
2647c478bd9Sstevel@tonic-gate 	tswtcl_data->avg_rate = cfg_parms->committed_rate;
2657c478bd9Sstevel@tonic-gate 	mutex_init(&tswtcl_data->tswtcl_lock, NULL, MUTEX_DEFAULT, 0);
2667c478bd9Sstevel@tonic-gate 	tswtcl_data->win_front = gethrtime();
2677c478bd9Sstevel@tonic-gate 	ipp_action_set_ptr(aid, (void *)tswtcl_data);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	return (0);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate cleanup:
2727c478bd9Sstevel@tonic-gate 	if (cfg_parms->stats) {
2737c478bd9Sstevel@tonic-gate 		ipp_stat_destroy(tswtcl_data->stats);
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 	kmem_free(cfg_parms, TSWTCL_CFG_SZ);
2767c478bd9Sstevel@tonic-gate 	kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
2777c478bd9Sstevel@tonic-gate 	return (rc);
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate static int
tswtcl_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)2827c478bd9Sstevel@tonic-gate tswtcl_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
2837c478bd9Sstevel@tonic-gate {
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
2867c478bd9Sstevel@tonic-gate 	int err = 0, err2;
2877c478bd9Sstevel@tonic-gate 	uint8_t config_type;
2887c478bd9Sstevel@tonic-gate 	char *next_action_name;
2897c478bd9Sstevel@tonic-gate 	ipp_action_id_t next_action;
2907c478bd9Sstevel@tonic-gate 	uint32_t rate;
2917c478bd9Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms, *old_cfg;
2927c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
2937c478bd9Sstevel@tonic-gate 	uint32_t bstats;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	nvlp = *nvlpp;
2967c478bd9Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
2997c478bd9Sstevel@tonic-gate 	    != 0) {
3007c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
3017c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:invalid configuration type"));
3027c478bd9Sstevel@tonic-gate 		return (err);
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate 	if (config_type != IPP_SET) {
3067c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
3077c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:invalid configuration type " \
3087c478bd9Sstevel@tonic-gate 		    "%d", config_type));
3097c478bd9Sstevel@tonic-gate 		return (EINVAL);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
3137c478bd9Sstevel@tonic-gate 	old_cfg = tswtcl_data->cfg_parms;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP);
3167c478bd9Sstevel@tonic-gate 	if (cfg_parms == NULL) {
3177c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
3187c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_action:mem. allocation failure\n"));
3197c478bd9Sstevel@tonic-gate 		return (ENOMEM);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/* Just copy all and change as needed */
3237c478bd9Sstevel@tonic-gate 	bcopy(old_cfg, cfg_parms, TSWTCL_CFG_SZ);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	/* parse red action name, if present */
3267c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
3277c478bd9Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3287c478bd9Sstevel@tonic-gate 		/* Get action id */
3297c478bd9Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3307c478bd9Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3317c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
3327c478bd9Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: red next_action"\
3337c478bd9Sstevel@tonic-gate 			    " invalid\n"));
3347c478bd9Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3357c478bd9Sstevel@tonic-gate 			return (EINVAL);
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate 		cfg_parms->red_action = next_action;
3387c478bd9Sstevel@tonic-gate 	}
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	/* parse yellow action name, if present */
3417c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
3427c478bd9Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3437c478bd9Sstevel@tonic-gate 		/* Get action id */
3447c478bd9Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3457c478bd9Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3467c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
3477c478bd9Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: yellow next_action"\
3487c478bd9Sstevel@tonic-gate 			    "  invalid\n"));
3497c478bd9Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3507c478bd9Sstevel@tonic-gate 			return (EINVAL);
3517c478bd9Sstevel@tonic-gate 		}
3527c478bd9Sstevel@tonic-gate 		cfg_parms->yellow_action = next_action;
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* parse green action name, if present */
3567c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
3577c478bd9Sstevel@tonic-gate 	    &next_action_name)) == 0) {
3587c478bd9Sstevel@tonic-gate 		/* Get action id */
3597c478bd9Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
3607c478bd9Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
3617c478bd9Sstevel@tonic-gate 			nvlist_free(nvlp);
3627c478bd9Sstevel@tonic-gate 			tswtcl0dbg(("tswtcl_modify_action: green next_action"\
3637c478bd9Sstevel@tonic-gate 			    " invalid\n"));
3647c478bd9Sstevel@tonic-gate 			kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3657c478bd9Sstevel@tonic-gate 			return (EINVAL);
3667c478bd9Sstevel@tonic-gate 		}
3677c478bd9Sstevel@tonic-gate 		cfg_parms->green_action = next_action;
3687c478bd9Sstevel@tonic-gate 	}
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate 	/* parse committed rate, if present */
3717c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE, &rate))
3727c478bd9Sstevel@tonic-gate 	    == 0) {
3737c478bd9Sstevel@tonic-gate 		cfg_parms->committed_rate = rate;
3747c478bd9Sstevel@tonic-gate 	}
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	/* parse peak rate, if present */
3777c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE, &rate))
3787c478bd9Sstevel@tonic-gate 	    == 0) {
3797c478bd9Sstevel@tonic-gate 		cfg_parms->peak_rate = rate;
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
3837c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
3847c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_create_action: invalid config, "\
3857c478bd9Sstevel@tonic-gate 		    " peak rate < committed rate\n"));
3867c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
3877c478bd9Sstevel@tonic-gate 		return (EINVAL);
3887c478bd9Sstevel@tonic-gate 	}
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/* parse window - in msec */
3917c478bd9Sstevel@tonic-gate 	if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
3927c478bd9Sstevel@tonic-gate 	    &cfg_parms->window)) != 0) {
3937c478bd9Sstevel@tonic-gate 		cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
3947c478bd9Sstevel@tonic-gate 		    METER_MSEC_TO_NSEC;
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* parse stats, if present */
3987c478bd9Sstevel@tonic-gate 	if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) {
3997c478bd9Sstevel@tonic-gate 		cfg_parms->stats = (boolean_t)bstats;
4007c478bd9Sstevel@tonic-gate 		if (cfg_parms->stats && !old_cfg->stats) {
4017c478bd9Sstevel@tonic-gate 			if ((err = tswtcl_statinit(aid, tswtcl_data)) != 0) {
4027c478bd9Sstevel@tonic-gate 				nvlist_free(nvlp);
4037c478bd9Sstevel@tonic-gate 				kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4047c478bd9Sstevel@tonic-gate 				return (err);
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 		} else if (!cfg_parms->stats && old_cfg->stats) {
4077c478bd9Sstevel@tonic-gate 			ipp_stat_destroy(tswtcl_data->stats);
4087c478bd9Sstevel@tonic-gate 		}
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* Can we ref all the new actions? */
4127c478bd9Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
4137c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data: can't ref. red action\n"));
4147c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
4157c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4167c478bd9Sstevel@tonic-gate 		return (err);
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
4207c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data:can't ref. yellow action\n"));
4217c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
4227c478bd9Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
4237c478bd9Sstevel@tonic-gate 		ASSERT(err2 == 0);
4247c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4257c478bd9Sstevel@tonic-gate 		return (err);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
4297c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_modify_data:can't ref. green action\n"));
4307c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
4317c478bd9Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
4327c478bd9Sstevel@tonic-gate 		ASSERT(err2 == 0);
4337c478bd9Sstevel@tonic-gate 		err2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
4347c478bd9Sstevel@tonic-gate 		ASSERT(err2 == 0);
4357c478bd9Sstevel@tonic-gate 		kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4367c478bd9Sstevel@tonic-gate 		return (err);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* Re-compute pminusc */
4407c478bd9Sstevel@tonic-gate 	cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	/* Actually modify the configuration */
4437c478bd9Sstevel@tonic-gate 	mutex_enter(&tswtcl_data->tswtcl_lock);
4447c478bd9Sstevel@tonic-gate 	tswtcl_data->cfg_parms = cfg_parms;
4457c478bd9Sstevel@tonic-gate 	mutex_exit(&tswtcl_data->tswtcl_lock);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/* Un-ref the old actions */
4487c478bd9Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->red_action, flags);
4497c478bd9Sstevel@tonic-gate 	ASSERT(err == 0);
4507c478bd9Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->yellow_action, flags);
4517c478bd9Sstevel@tonic-gate 	ASSERT(err == 0);
4527c478bd9Sstevel@tonic-gate 	err = ipp_action_unref(aid, old_cfg->green_action, flags);
4537c478bd9Sstevel@tonic-gate 	ASSERT(err == 0);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	/* Free the old configuration */
4567c478bd9Sstevel@tonic-gate 	kmem_free(old_cfg, TSWTCL_CFG_SZ);
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	nvlist_free(nvlp);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	return (0);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate static int
tswtcl_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)4647c478bd9Sstevel@tonic-gate tswtcl_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
4657c478bd9Sstevel@tonic-gate {
4667c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
4677c478bd9Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
4687c478bd9Sstevel@tonic-gate 	int rc;
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
4717c478bd9Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	cfg_parms = tswtcl_data->cfg_parms;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	if (cfg_parms->stats) {
4767c478bd9Sstevel@tonic-gate 		ipp_stat_destroy(tswtcl_data->stats);
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	/* unreference the action */
4807c478bd9Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->red_action, flags);
4817c478bd9Sstevel@tonic-gate 	ASSERT(rc == 0);
4827c478bd9Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
4837c478bd9Sstevel@tonic-gate 	ASSERT(rc == 0);
4847c478bd9Sstevel@tonic-gate 	rc = ipp_action_unref(aid, cfg_parms->green_action, flags);
4857c478bd9Sstevel@tonic-gate 	ASSERT(rc == 0);
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	mutex_destroy(&tswtcl_data->tswtcl_lock);
4887c478bd9Sstevel@tonic-gate 	kmem_free(cfg_parms, TSWTCL_CFG_SZ);
4897c478bd9Sstevel@tonic-gate 	kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
4907c478bd9Sstevel@tonic-gate 	return (0);
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate static int
tswtcl_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)4947c478bd9Sstevel@tonic-gate tswtcl_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
4977c478bd9Sstevel@tonic-gate 	ipp_action_id_t next_action;
4987c478bd9Sstevel@tonic-gate 	mblk_t *mp = NULL;
4997c478bd9Sstevel@tonic-gate 	int rc;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/* get mblk from ipp_packet structure */
5027c478bd9Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
5037c478bd9Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
5047c478bd9Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	/* tswtcl packet as configured */
5077c478bd9Sstevel@tonic-gate 	if ((rc = tswtcl_process(&mp, tswtcl_data, &next_action)) != 0) {
5087c478bd9Sstevel@tonic-gate 		return (rc);
5097c478bd9Sstevel@tonic-gate 	} else {
5107c478bd9Sstevel@tonic-gate 		return (ipp_packet_next(packet, next_action));
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate static int
tswtcl_statinit(ipp_action_id_t aid,tswtcl_data_t * tswtcl_data)5157c478bd9Sstevel@tonic-gate tswtcl_statinit(ipp_action_id_t aid, tswtcl_data_t *tswtcl_data)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	int rc = 0;
5187c478bd9Sstevel@tonic-gate 	meter_stat_t *statsp;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/* install stats entry */
5217c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_create(aid, TSWTCL_STATS_STRING, METER_STATS_COUNT,
5227c478bd9Sstevel@tonic-gate 	    tswtcl_update_stats, tswtcl_data, &tswtcl_data->stats)) != 0) {
5237c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5247c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5257c478bd9Sstevel@tonic-gate 		return (rc);
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	statsp = (meter_stat_t *)(tswtcl_data->stats)->ipps_data;
5297c478bd9Sstevel@tonic-gate 	ASSERT(statsp != NULL);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_packets",
5327c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_packets)) != 0) {
5337c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5347c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5357c478bd9Sstevel@tonic-gate 		return (rc);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_bits",
5387c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->red_bits)) != 0) {
5397c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5407c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5417c478bd9Sstevel@tonic-gate 		return (rc);
5427c478bd9Sstevel@tonic-gate 	}
5437c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_packets",
5447c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) {
5457c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5467c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5477c478bd9Sstevel@tonic-gate 		return (rc);
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_bits",
5507c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) {
5517c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5527c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5537c478bd9Sstevel@tonic-gate 		return (rc);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_packets",
5567c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_packets)) != 0) {
5577c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5587c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5597c478bd9Sstevel@tonic-gate 		return (rc);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_bits",
5627c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->green_bits)) != 0) {
5637c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
5647c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5657c478bd9Sstevel@tonic-gate 		return (rc);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 	if ((rc = ipp_stat_named_init(tswtcl_data->stats, "epackets",
5687c478bd9Sstevel@tonic-gate 	    IPP_STAT_UINT64, &statsp->epackets)) != 0) {
5697c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
5707c478bd9Sstevel@tonic-gate 		    " with %d\n", rc));
5717c478bd9Sstevel@tonic-gate 		return (rc);
5727c478bd9Sstevel@tonic-gate 	}
5737c478bd9Sstevel@tonic-gate 	ipp_stat_install(tswtcl_data->stats);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	return (rc);
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate static int
tswtcl_update_stats(ipp_stat_t * sp,void * args,int rw)5807c478bd9Sstevel@tonic-gate tswtcl_update_stats(ipp_stat_t *sp, void *args, int rw)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data = (tswtcl_data_t *)args;
5837c478bd9Sstevel@tonic-gate 	meter_stat_t *stats = (meter_stat_t *)sp->ipps_data;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate 	ASSERT((tswtcl_data != NULL) && (stats != NULL));
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_packets, &tswtcl_data->red_packets,
5887c478bd9Sstevel@tonic-gate 	    rw);
5897c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_packets,
5907c478bd9Sstevel@tonic-gate 	    &tswtcl_data->yellow_packets, rw);
5917c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_packets,
5927c478bd9Sstevel@tonic-gate 	    &tswtcl_data->green_packets, rw);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->red_bits, &tswtcl_data->red_bits, rw);
5957c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->yellow_bits,
5967c478bd9Sstevel@tonic-gate 	    &tswtcl_data->yellow_bits, rw);
5977c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->green_bits,
5987c478bd9Sstevel@tonic-gate 	    &tswtcl_data->green_bits, rw);
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	(void) ipp_stat_named_op(&stats->epackets, &tswtcl_data->epackets,
6017c478bd9Sstevel@tonic-gate 	    rw);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	return (0);
6047c478bd9Sstevel@tonic-gate }
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate /* ARGSUSED */
6077c478bd9Sstevel@tonic-gate static int
tswtcl_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)6087c478bd9Sstevel@tonic-gate tswtcl_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
6097c478bd9Sstevel@tonic-gate     ipp_flags_t flags)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate 	nvlist_t *nvlp;
6127c478bd9Sstevel@tonic-gate 	tswtcl_data_t *tswtcl_data;
6137c478bd9Sstevel@tonic-gate 	tswtcl_cfg_t *cfg_parms;
6147c478bd9Sstevel@tonic-gate 	char *next_action;
6157c478bd9Sstevel@tonic-gate 	int rc;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
6187c478bd9Sstevel@tonic-gate 	ASSERT(tswtcl_data != NULL);
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	cfg_parms = tswtcl_data->cfg_parms;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	/* allocate nvlist to be passed back */
6237c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
6247c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: memory allocation failure\n"));
6257c478bd9Sstevel@tonic-gate 		return (rc);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/* look up red next action with the next action id */
6297c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) {
6307c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: red action not available\n"));
6317c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6327c478bd9Sstevel@tonic-gate 		return (rc);
6337c478bd9Sstevel@tonic-gate 	}
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	/* add next action name */
6367c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_RED_ACTION_NAME,
6377c478bd9Sstevel@tonic-gate 	    next_action)) != 0) {
6387c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding\n"));
6397c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6407c478bd9Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6417c478bd9Sstevel@tonic-gate 		return (rc);
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	/* free action name */
6457c478bd9Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/* look up yellow next action with the next action id */
6487c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->yellow_action,
6497c478bd9Sstevel@tonic-gate 	    &next_action)) != 0) {
6507c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: yellow action not available\n"));
6517c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6527c478bd9Sstevel@tonic-gate 		return (rc);
6537c478bd9Sstevel@tonic-gate 	}
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/* add next action name */
6567c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
6577c478bd9Sstevel@tonic-gate 	    next_action)) != 0) {
6587c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding yellow action\n"));
6597c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6607c478bd9Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6617c478bd9Sstevel@tonic-gate 		return (rc);
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 	/* free action name */
6647c478bd9Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	/* look up green next action with the next action id */
6677c478bd9Sstevel@tonic-gate 	if ((rc = ipp_action_name(cfg_parms->green_action,
6687c478bd9Sstevel@tonic-gate 	    &next_action)) != 0) {
6697c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: green action not available\n"));
6707c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6717c478bd9Sstevel@tonic-gate 		return (rc);
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	/* add next action name */
6757c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
6767c478bd9Sstevel@tonic-gate 	    next_action)) != 0) {
6777c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding green action\n"));
6787c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6797c478bd9Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
6807c478bd9Sstevel@tonic-gate 		return (rc);
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/* free action name */
6847c478bd9Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	/* add config type */
6877c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
6887c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding config_type\n"));
6897c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6907c478bd9Sstevel@tonic-gate 		return (rc);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	/* add committed_rate  */
6947c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_COMMITTED_RATE,
6957c478bd9Sstevel@tonic-gate 	    cfg_parms->committed_rate)) != 0) {
6967c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding committed_rate\n"));
6977c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
6987c478bd9Sstevel@tonic-gate 		return (rc);
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/* add peak_rate  */
7027c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_PEAK_RATE,
7037c478bd9Sstevel@tonic-gate 	    cfg_parms->peak_rate)) != 0) {
7047c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding peak_rate\n"));
7057c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
7067c478bd9Sstevel@tonic-gate 		return (rc);
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/* add window  */
7107c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, TSWTCL_WINDOW,
7117c478bd9Sstevel@tonic-gate 	    cfg_parms->window)) != 0) {
7127c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding window\n"));
7137c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
7147c478bd9Sstevel@tonic-gate 		return (rc);
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
7187c478bd9Sstevel@tonic-gate 	    (uint32_t)(uintptr_t)tswtcl_data->stats)) != 0) {
7197c478bd9Sstevel@tonic-gate 		tswtcl0dbg(("tswtcl_info: error adding stats status\n"));
7207c478bd9Sstevel@tonic-gate 		nvlist_free(nvlp);
7217c478bd9Sstevel@tonic-gate 		return (rc);
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/* call back with nvlist */
7257c478bd9Sstevel@tonic-gate 	rc = fn(nvlp, arg);
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	nvlist_free(nvlp);
7287c478bd9Sstevel@tonic-gate 	return (rc);
7297c478bd9Sstevel@tonic-gate }
730