xref: /onnv-gate/usr/src/uts/common/ipp/flowacct/flowacctddi.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 2002 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/conf.h>
31*0Sstevel@tonic-gate #include <sys/atomic.h>
32*0Sstevel@tonic-gate #include <sys/systm.h>
33*0Sstevel@tonic-gate #include <sys/socket.h>
34*0Sstevel@tonic-gate #include <sys/spl.h>
35*0Sstevel@tonic-gate #include <netinet/in.h>
36*0Sstevel@tonic-gate #include <sys/modctl.h>
37*0Sstevel@tonic-gate #include <sys/sunddi.h>
38*0Sstevel@tonic-gate #include <ipp/ipp.h>
39*0Sstevel@tonic-gate #include <ipp/ipp_config.h>
40*0Sstevel@tonic-gate #include <inet/common.h>
41*0Sstevel@tonic-gate #include <ipp/flowacct/flowacct_impl.h>
42*0Sstevel@tonic-gate #include <sys/ddi.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define	D_SM_COMMENT	"IPP Flow Accounting Module"
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /* DDI file for flowacct ipp module */
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate static int flowacct_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
49*0Sstevel@tonic-gate static int flowacct_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
50*0Sstevel@tonic-gate static int flowacct_destroy_action(ipp_action_id_t, ipp_flags_t);
51*0Sstevel@tonic-gate static int flowacct_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
52*0Sstevel@tonic-gate     ipp_flags_t);
53*0Sstevel@tonic-gate static int flowacct_invoke_action(ipp_action_id_t, ipp_packet_t *);
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate static int update_flowacct_kstats(ipp_stat_t *, void *, int);
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate ipp_ops_t flowacct_ops = {
58*0Sstevel@tonic-gate 	IPPO_REV,
59*0Sstevel@tonic-gate 	flowacct_create_action,		/* ippo_action_create */
60*0Sstevel@tonic-gate 	flowacct_modify_action,		/* ippo_action_modify */
61*0Sstevel@tonic-gate 	flowacct_destroy_action,	/* ippo_action_destroy */
62*0Sstevel@tonic-gate 	flowacct_info,			/* ippo_action_info */
63*0Sstevel@tonic-gate 	flowacct_invoke_action		/* ippo_action_invoke */
64*0Sstevel@tonic-gate };
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate extern struct mod_ops mod_ippops;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * Module linkage information for the kernel.
70*0Sstevel@tonic-gate  */
71*0Sstevel@tonic-gate static struct modlipp modlipp = {
72*0Sstevel@tonic-gate 	&mod_ippops,
73*0Sstevel@tonic-gate 	D_SM_COMMENT " 1.12",
74*0Sstevel@tonic-gate 	&flowacct_ops
75*0Sstevel@tonic-gate };
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
78*0Sstevel@tonic-gate 	MODREV_1,
79*0Sstevel@tonic-gate 	(void *)&modlipp,
80*0Sstevel@tonic-gate 	NULL
81*0Sstevel@tonic-gate };
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate int
_init(void)84*0Sstevel@tonic-gate _init(void)
85*0Sstevel@tonic-gate {
86*0Sstevel@tonic-gate 	return (mod_install(&modlinkage));
87*0Sstevel@tonic-gate }
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate int
_fini(void)90*0Sstevel@tonic-gate _fini(void)
91*0Sstevel@tonic-gate {
92*0Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
93*0Sstevel@tonic-gate }
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate int
_info(struct modinfo * modinfop)96*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
99*0Sstevel@tonic-gate }
100*0Sstevel@tonic-gate 
101*0Sstevel@tonic-gate /* Update global stats */
102*0Sstevel@tonic-gate static int
update_flowacct_kstats(ipp_stat_t * sp,void * arg,int rw)103*0Sstevel@tonic-gate update_flowacct_kstats(ipp_stat_t *sp, void *arg, int rw)
104*0Sstevel@tonic-gate {
105*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data = (flowacct_data_t *)arg;
106*0Sstevel@tonic-gate 	flowacct_stat_t *fl_stat  = (flowacct_stat_t *)sp->ipps_data;
107*0Sstevel@tonic-gate 	ASSERT((fl_stat != NULL) && (flowacct_data != 0));
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->nbytes, &flowacct_data->nbytes, rw);
110*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->tbytes, &flowacct_data->tbytes, rw);
111*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->nflows, &flowacct_data->nflows, rw);
112*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->usedmem, &flowacct_data->usedmem,
113*0Sstevel@tonic-gate 	    rw);
114*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->npackets, &flowacct_data->npackets,
115*0Sstevel@tonic-gate 	    rw);
116*0Sstevel@tonic-gate 	(void) ipp_stat_named_op(&fl_stat->epackets, &flowacct_data->epackets,
117*0Sstevel@tonic-gate 	    rw);
118*0Sstevel@tonic-gate 	return (0);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate /* Initialize global stats */
122*0Sstevel@tonic-gate static int
global_statinit(ipp_action_id_t aid,flowacct_data_t * flowacct_data)123*0Sstevel@tonic-gate global_statinit(ipp_action_id_t aid, flowacct_data_t *flowacct_data)
124*0Sstevel@tonic-gate {
125*0Sstevel@tonic-gate 	flowacct_stat_t *flacct_stat;
126*0Sstevel@tonic-gate 	int err = 0;
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	if ((err = ipp_stat_create(aid, FLOWACCT_STATS_STRING,
129*0Sstevel@tonic-gate 	    FLOWACCT_STATS_COUNT, update_flowacct_kstats, flowacct_data,
130*0Sstevel@tonic-gate 	    &flowacct_data->stats)) != 0) {
131*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit: error creating flowacct "\
132*0Sstevel@tonic-gate 		    "stats\n"));
133*0Sstevel@tonic-gate 		return (err);
134*0Sstevel@tonic-gate 	}
135*0Sstevel@tonic-gate 	flacct_stat = (flowacct_stat_t *)(flowacct_data->stats)->ipps_data;
136*0Sstevel@tonic-gate 	ASSERT(flacct_stat != NULL);
137*0Sstevel@tonic-gate 
138*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "bytes_in_tbl",
139*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &flacct_stat->tbytes)) != 0) {
140*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit: ipp_stat_named_init returned "\
141*0Sstevel@tonic-gate 		    "with error %d\n", err));
142*0Sstevel@tonic-gate 		return (err);
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "nbytes",
145*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &flacct_stat->nbytes)) != 0) {
146*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit: ipp_stat_named_init returned "\
147*0Sstevel@tonic-gate 		    "with error %d\n", err));
148*0Sstevel@tonic-gate 		return (err);
149*0Sstevel@tonic-gate 	}
150*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "npackets",
151*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &flacct_stat->npackets)) != 0) {
152*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
153*0Sstevel@tonic-gate 		    "with error %d\n", err));
154*0Sstevel@tonic-gate 		return (err);
155*0Sstevel@tonic-gate 	}
156*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "usedmem",
157*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &flacct_stat->usedmem)) != 0) {
158*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
159*0Sstevel@tonic-gate 		    "with error %d\n", err));
160*0Sstevel@tonic-gate 		return (err);
161*0Sstevel@tonic-gate 	}
162*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "flows_in_tbl",
163*0Sstevel@tonic-gate 	    IPP_STAT_UINT32, &flacct_stat->nflows)) != 0) {
164*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
165*0Sstevel@tonic-gate 		    "with error %d\n", err));
166*0Sstevel@tonic-gate 		return (err);
167*0Sstevel@tonic-gate 	}
168*0Sstevel@tonic-gate 	if ((err = ipp_stat_named_init(flowacct_data->stats, "epackets",
169*0Sstevel@tonic-gate 	    IPP_STAT_UINT64, &flacct_stat->epackets)) != 0) {
170*0Sstevel@tonic-gate 		flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
171*0Sstevel@tonic-gate 		    "with error %d\n", err));
172*0Sstevel@tonic-gate 		return (err);
173*0Sstevel@tonic-gate 	}
174*0Sstevel@tonic-gate 	ipp_stat_install(flowacct_data->stats);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	return (err);
177*0Sstevel@tonic-gate }
178*0Sstevel@tonic-gate 
179*0Sstevel@tonic-gate static int
flowacct_create_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)180*0Sstevel@tonic-gate flowacct_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
181*0Sstevel@tonic-gate {
182*0Sstevel@tonic-gate 	nvlist_t *nvlp;
183*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data;
184*0Sstevel@tonic-gate 	char *next_action;
185*0Sstevel@tonic-gate 	int rc, flow_count;
186*0Sstevel@tonic-gate 	list_head_t *head;
187*0Sstevel@tonic-gate 	uint32_t bstats;
188*0Sstevel@tonic-gate 	uint32_t timeout = FLOWACCT_DEF_TIMEOUT;
189*0Sstevel@tonic-gate 	uint32_t timer = FLOWACCT_DEF_TIMER;
190*0Sstevel@tonic-gate 
191*0Sstevel@tonic-gate 	nvlp = *nvlpp;
192*0Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL on return */
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	if ((flowacct_data = kmem_zalloc(FLOWACCT_DATA_SZ, KM_NOSLEEP))
195*0Sstevel@tonic-gate 	    == NULL) {
196*0Sstevel@tonic-gate 		nvlist_free(nvlp);
197*0Sstevel@tonic-gate 		return (ENOMEM);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate 
200*0Sstevel@tonic-gate 	/* parse next action name */
201*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, FLOWACCT_NEXT_ACTION_NAME,
202*0Sstevel@tonic-gate 	    &next_action)) != 0) {
203*0Sstevel@tonic-gate 		nvlist_free(nvlp);
204*0Sstevel@tonic-gate 		kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
205*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_create_action: invalid config, "\
206*0Sstevel@tonic-gate 		    "next_action missing\n"));
207*0Sstevel@tonic-gate 		return (rc);
208*0Sstevel@tonic-gate 	}
209*0Sstevel@tonic-gate 	if ((flowacct_data->next_action = ipp_action_lookup(next_action))
210*0Sstevel@tonic-gate 	    == IPP_ACTION_INVAL) {
211*0Sstevel@tonic-gate 		nvlist_free(nvlp);
212*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_create_action: invalid next_action\n"));
213*0Sstevel@tonic-gate 		kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
214*0Sstevel@tonic-gate 		return (EINVAL);
215*0Sstevel@tonic-gate 	}
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 	if ((rc = ipp_action_name(aid, &flowacct_data->act_name)) != 0) {
218*0Sstevel@tonic-gate 		nvlist_free(nvlp);
219*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_create_action: invalid next aid\n"));
220*0Sstevel@tonic-gate 		kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
221*0Sstevel@tonic-gate 		return (EINVAL);
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	/* parse flow timeout - in millisec, if present */
225*0Sstevel@tonic-gate 	(void) nvlist_lookup_uint32(nvlp, FLOWACCT_TIMEOUT, &timeout);
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate 	/* Convert to FLOWACCT_MSEC_TO_NSEC */
228*0Sstevel@tonic-gate 	flowacct_data->timeout = (uint64_t)timeout * FLOWACCT_MSEC_TO_NSEC;
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate 	/* parse flow timer - in millisec, if present  */
231*0Sstevel@tonic-gate 	(void) nvlist_lookup_uint32(nvlp, FLOWACCT_TIMER, &timer);
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	/* Convert to FLOWACCT_MSEC_TO_USEC */
234*0Sstevel@tonic-gate 	flowacct_data->timer = (uint64_t)timer * FLOWACCT_MSEC_TO_USEC;
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, FLOWACCT_MAX_LIMIT,
237*0Sstevel@tonic-gate 	    &flowacct_data->max_limit)) != 0) {
238*0Sstevel@tonic-gate 		nvlist_free(nvlp);
239*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_create_action: invalid config, "\
240*0Sstevel@tonic-gate 		    "max_limit missing\n"));
241*0Sstevel@tonic-gate 		kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
242*0Sstevel@tonic-gate 		return (rc);
243*0Sstevel@tonic-gate 	}
244*0Sstevel@tonic-gate 
245*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
246*0Sstevel@tonic-gate 	    &bstats)) != 0) {
247*0Sstevel@tonic-gate 		flowacct_data->global_stats = B_FALSE;
248*0Sstevel@tonic-gate 	} else {
249*0Sstevel@tonic-gate 		flowacct_data->global_stats = (boolean_t)bstats;
250*0Sstevel@tonic-gate 		if (flowacct_data->global_stats) {
251*0Sstevel@tonic-gate 			if ((rc = global_statinit(aid, flowacct_data)) != 0) {
252*0Sstevel@tonic-gate 				kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
253*0Sstevel@tonic-gate 				return (rc);
254*0Sstevel@tonic-gate 			}
255*0Sstevel@tonic-gate 		}
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	nvlist_free(nvlp);
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	/* set action chain reference */
261*0Sstevel@tonic-gate 	if ((rc = ipp_action_ref(aid, flowacct_data->next_action,
262*0Sstevel@tonic-gate 	    flags)) != 0) {
263*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_create_action: ipp_action_ref " \
264*0Sstevel@tonic-gate 		    "returned with error %d\n", rc));
265*0Sstevel@tonic-gate 		if (flowacct_data->stats != NULL) {
266*0Sstevel@tonic-gate 			ipp_stat_destroy(flowacct_data->stats);
267*0Sstevel@tonic-gate 		}
268*0Sstevel@tonic-gate 		kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
269*0Sstevel@tonic-gate 		return (rc);
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/* Initialize locks */
273*0Sstevel@tonic-gate 	for (flow_count = 0, head = flowacct_data->flows_tbl;
274*0Sstevel@tonic-gate 	    flow_count < (FLOW_TBL_COUNT + 1); flow_count++, head++) {
275*0Sstevel@tonic-gate 		mutex_init(&head->lock, NULL, MUTEX_DEFAULT, 0);
276*0Sstevel@tonic-gate 	}
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 	ipp_action_set_ptr(aid, (void *)flowacct_data);
279*0Sstevel@tonic-gate 	return (0);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate static int
flowacct_modify_action(ipp_action_id_t aid,nvlist_t ** nvlpp,ipp_flags_t flags)283*0Sstevel@tonic-gate flowacct_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	nvlist_t *nvlp;
286*0Sstevel@tonic-gate 	int rc = 0;
287*0Sstevel@tonic-gate 	uint8_t config_type;
288*0Sstevel@tonic-gate 	char *next_action_name, *act_name;
289*0Sstevel@tonic-gate 	ipp_action_id_t next_action;
290*0Sstevel@tonic-gate 	uint32_t timeout, timer, bstats, max_limit;
291*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data;
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate 	nvlp = *nvlpp;
294*0Sstevel@tonic-gate 	*nvlpp = NULL;		/* nvlist should be NULL when this returns */
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
297*0Sstevel@tonic-gate 	    != 0) {
298*0Sstevel@tonic-gate 		nvlist_free(nvlp);
299*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_modify_action: invalid configuration "\
300*0Sstevel@tonic-gate 		    "type\n"));
301*0Sstevel@tonic-gate 		return (rc);
302*0Sstevel@tonic-gate 	}
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 	if (config_type != IPP_SET) {
305*0Sstevel@tonic-gate 		nvlist_free(nvlp);
306*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_modify_action: invalid configuration "\
307*0Sstevel@tonic-gate 		    "type %d\n", config_type));
308*0Sstevel@tonic-gate 		return (EINVAL);
309*0Sstevel@tonic-gate 	}
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 	flowacct_data = (flowacct_data_t *)ipp_action_get_ptr(aid);
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	/* parse next action name, if present */
314*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_string(nvlp, FLOWACCT_NEXT_ACTION_NAME,
315*0Sstevel@tonic-gate 	    &next_action_name)) == 0) {
316*0Sstevel@tonic-gate 		/* lookup action name to get action id */
317*0Sstevel@tonic-gate 		if ((next_action = ipp_action_lookup(next_action_name))
318*0Sstevel@tonic-gate 		    == IPP_ACTION_INVAL) {
319*0Sstevel@tonic-gate 			nvlist_free(nvlp);
320*0Sstevel@tonic-gate 			flowacct0dbg(("flowacct_modify_action: next_action "\
321*0Sstevel@tonic-gate 			    "invalid\n"));
322*0Sstevel@tonic-gate 			return (EINVAL);
323*0Sstevel@tonic-gate 		}
324*0Sstevel@tonic-gate 		/* reference new action */
325*0Sstevel@tonic-gate 		if ((rc = ipp_action_ref(aid, next_action, flags)) != 0) {
326*0Sstevel@tonic-gate 			nvlist_free(nvlp);
327*0Sstevel@tonic-gate 			flowacct0dbg(("flowacct_modify_action: "\
328*0Sstevel@tonic-gate 			    "ipp_action_ref returned with error %d\n", rc));
329*0Sstevel@tonic-gate 			return (rc);
330*0Sstevel@tonic-gate 		}
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 		if ((rc = ipp_action_name(aid, &act_name)) != 0) {
333*0Sstevel@tonic-gate 			nvlist_free(nvlp);
334*0Sstevel@tonic-gate 			flowacct0dbg(("flowacct_modify_action: invalid next "\
335*0Sstevel@tonic-gate 			    "aid\n"));
336*0Sstevel@tonic-gate 			return (EINVAL);
337*0Sstevel@tonic-gate 		}
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 		/* unref old action */
340*0Sstevel@tonic-gate 		rc = ipp_action_unref(aid, flowacct_data->next_action, flags);
341*0Sstevel@tonic-gate 		ASSERT(rc == 0);
342*0Sstevel@tonic-gate 		flowacct_data->next_action = next_action;
343*0Sstevel@tonic-gate 		kmem_free(flowacct_data->act_name,
344*0Sstevel@tonic-gate 		    (strlen(flowacct_data->act_name) + 1));
345*0Sstevel@tonic-gate 		flowacct_data->act_name = act_name;
346*0Sstevel@tonic-gate 	}
347*0Sstevel@tonic-gate 
348*0Sstevel@tonic-gate 	/* parse timeout, if present */
349*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, FLOWACCT_TIMEOUT, &timeout))
350*0Sstevel@tonic-gate 	    == 0) {
351*0Sstevel@tonic-gate 		flowacct_data->timeout = (uint64_t)timeout *
352*0Sstevel@tonic-gate 		    FLOWACCT_MSEC_TO_NSEC;
353*0Sstevel@tonic-gate 	}
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	/* parse timer, if present */
356*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, FLOWACCT_TIMER, &timer)) == 0) {
357*0Sstevel@tonic-gate 		flowacct_data->timer = (uint64_t)timer * FLOWACCT_MSEC_TO_USEC;
358*0Sstevel@tonic-gate 	}
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* parse max_flow, if present */
361*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, FLOWACCT_MAX_LIMIT, &max_limit))
362*0Sstevel@tonic-gate 	    == 0) {
363*0Sstevel@tonic-gate 		flowacct_data->max_limit = max_limit;
364*0Sstevel@tonic-gate 	}
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	/* parse gather_stats boolean, if present */
367*0Sstevel@tonic-gate 	if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
368*0Sstevel@tonic-gate 	    == 0) {
369*0Sstevel@tonic-gate 		boolean_t new_val = (boolean_t)bstats;
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 		/* Turning global stats on */
372*0Sstevel@tonic-gate 		if (new_val && !flowacct_data->global_stats) {
373*0Sstevel@tonic-gate 			rc = global_statinit(aid, flowacct_data);
374*0Sstevel@tonic-gate 			if (rc == 0) {
375*0Sstevel@tonic-gate 				flowacct_data->global_stats = new_val;
376*0Sstevel@tonic-gate 			} else {
377*0Sstevel@tonic-gate 				flowacct0dbg(("flowacct_modify_action: error "\
378*0Sstevel@tonic-gate 				    "enabling stats\n"));
379*0Sstevel@tonic-gate 			}
380*0Sstevel@tonic-gate 		} else if (!new_val && flowacct_data->global_stats) {
381*0Sstevel@tonic-gate 			flowacct_data->global_stats = new_val;
382*0Sstevel@tonic-gate 			ipp_stat_destroy(flowacct_data->stats);
383*0Sstevel@tonic-gate 		}
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 	return (0);
386*0Sstevel@tonic-gate }
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate static int
flowacct_destroy_action(ipp_action_id_t aid,ipp_flags_t flags)389*0Sstevel@tonic-gate flowacct_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
390*0Sstevel@tonic-gate {
391*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data;
392*0Sstevel@tonic-gate 	int rc, flow_count;
393*0Sstevel@tonic-gate 	list_head_t *head;
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate 	flowacct_data = (flowacct_data_t *)ipp_action_get_ptr(aid);
396*0Sstevel@tonic-gate 	ASSERT(flowacct_data != NULL);
397*0Sstevel@tonic-gate 
398*0Sstevel@tonic-gate 	while (flowacct_data->flow_tid != 0) {
399*0Sstevel@tonic-gate 		timeout_id_t tid = flowacct_data->flow_tid;
400*0Sstevel@tonic-gate 		flowacct_data->flow_tid = 0;
401*0Sstevel@tonic-gate 		(void) untimeout(tid);
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 
404*0Sstevel@tonic-gate 	if (flowacct_data->stats != NULL) {
405*0Sstevel@tonic-gate 		ipp_stat_destroy(flowacct_data->stats);
406*0Sstevel@tonic-gate 	}
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	/* Dump all the flows to the file */
409*0Sstevel@tonic-gate 	flowacct_timer(FLOWACCT_PURGE_FLOW, flowacct_data);
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 	kmem_free(flowacct_data->act_name, (strlen(flowacct_data->act_name)
412*0Sstevel@tonic-gate 	    + 1));
413*0Sstevel@tonic-gate 
414*0Sstevel@tonic-gate 	/* Destroy the locks */
415*0Sstevel@tonic-gate 	for (flow_count = 0, head = flowacct_data->flows_tbl;
416*0Sstevel@tonic-gate 	    flow_count < FLOW_TBL_COUNT; flow_count++, head++) {
417*0Sstevel@tonic-gate 		mutex_destroy(&head->lock);
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 	/* unreference the action */
420*0Sstevel@tonic-gate 	rc = ipp_action_unref(aid, flowacct_data->next_action, flags);
421*0Sstevel@tonic-gate 	ASSERT(rc == 0);
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 
424*0Sstevel@tonic-gate 	kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
425*0Sstevel@tonic-gate 	return (0);
426*0Sstevel@tonic-gate }
427*0Sstevel@tonic-gate 
428*0Sstevel@tonic-gate static int
flowacct_invoke_action(ipp_action_id_t aid,ipp_packet_t * packet)429*0Sstevel@tonic-gate flowacct_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
430*0Sstevel@tonic-gate {
431*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data;
432*0Sstevel@tonic-gate 	mblk_t *mp = NULL;
433*0Sstevel@tonic-gate 	int rc;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	/* get mblk from ipp_packet structure */
436*0Sstevel@tonic-gate 	mp = ipp_packet_get_data(packet);
437*0Sstevel@tonic-gate 	flowacct_data = (flowacct_data_t *)ipp_action_get_ptr(aid);
438*0Sstevel@tonic-gate 	ASSERT(flowacct_data != NULL);
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate 	/* flowacct packet as configured */
441*0Sstevel@tonic-gate 	if ((rc = flowacct_process(&mp, flowacct_data)) != 0) {
442*0Sstevel@tonic-gate 		return (rc);
443*0Sstevel@tonic-gate 	} else {
444*0Sstevel@tonic-gate 		/* return packet with next action set */
445*0Sstevel@tonic-gate 		return (ipp_packet_next(packet, flowacct_data->next_action));
446*0Sstevel@tonic-gate 	}
447*0Sstevel@tonic-gate }
448*0Sstevel@tonic-gate 
449*0Sstevel@tonic-gate /* ARGSUSED */
450*0Sstevel@tonic-gate static int
flowacct_info(ipp_action_id_t aid,int (* fn)(nvlist_t *,void *),void * arg,ipp_flags_t flags)451*0Sstevel@tonic-gate flowacct_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
452*0Sstevel@tonic-gate     ipp_flags_t flags)
453*0Sstevel@tonic-gate {
454*0Sstevel@tonic-gate 	nvlist_t *nvlp;
455*0Sstevel@tonic-gate 	flowacct_data_t *flowacct_data;
456*0Sstevel@tonic-gate 	char *next_action;
457*0Sstevel@tonic-gate 	uint32_t param;
458*0Sstevel@tonic-gate 	int rc;
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	flowacct_data = (flowacct_data_t *)ipp_action_get_ptr(aid);
461*0Sstevel@tonic-gate 	ASSERT(flowacct_data != NULL);
462*0Sstevel@tonic-gate 	ASSERT(fn != NULL);
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	/* allocate nvlist to be passed back */
465*0Sstevel@tonic-gate 	if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
466*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: memory allocation failure\n"));
467*0Sstevel@tonic-gate 		return (rc);
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 	/* look up next action with the next action id */
471*0Sstevel@tonic-gate 	if ((rc = ipp_action_name(flowacct_data->next_action,
472*0Sstevel@tonic-gate 	    &next_action)) != 0) {
473*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: next action not available\n"));
474*0Sstevel@tonic-gate 		nvlist_free(nvlp);
475*0Sstevel@tonic-gate 		return (rc);
476*0Sstevel@tonic-gate 	}
477*0Sstevel@tonic-gate 
478*0Sstevel@tonic-gate 	/* add next action name */
479*0Sstevel@tonic-gate 	if ((rc = nvlist_add_string(nvlp, FLOWACCT_NEXT_ACTION_NAME,
480*0Sstevel@tonic-gate 	    next_action)) != 0) {
481*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding next action\n"));
482*0Sstevel@tonic-gate 		nvlist_free(nvlp);
483*0Sstevel@tonic-gate 		kmem_free(next_action, (strlen(next_action) + 1));
484*0Sstevel@tonic-gate 		return (rc);
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	/* free action name */
488*0Sstevel@tonic-gate 	kmem_free(next_action, (strlen(next_action) + 1));
489*0Sstevel@tonic-gate 
490*0Sstevel@tonic-gate 	/* add config type */
491*0Sstevel@tonic-gate 	if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
492*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding config type\n"));
493*0Sstevel@tonic-gate 		nvlist_free(nvlp);
494*0Sstevel@tonic-gate 		return (rc);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	/* add timer */
498*0Sstevel@tonic-gate 	param = flowacct_data->timer / FLOWACCT_MSEC_TO_USEC;
499*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, FLOWACCT_TIMER, param)) != 0) {
500*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding timer info.\n"));
501*0Sstevel@tonic-gate 		nvlist_free(nvlp);
502*0Sstevel@tonic-gate 		return (rc);
503*0Sstevel@tonic-gate 	}
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	/* add max_limit */
506*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, FLOWACCT_MAX_LIMIT,
507*0Sstevel@tonic-gate 	    flowacct_data->max_limit)) != 0) {
508*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding max_flow info.\n"));
509*0Sstevel@tonic-gate 		nvlist_free(nvlp);
510*0Sstevel@tonic-gate 		return (rc);
511*0Sstevel@tonic-gate 	}
512*0Sstevel@tonic-gate 
513*0Sstevel@tonic-gate 
514*0Sstevel@tonic-gate 	param = flowacct_data->timeout / FLOWACCT_MSEC_TO_NSEC;
515*0Sstevel@tonic-gate 	/* add timeout */
516*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, FLOWACCT_TIMEOUT, param)) != 0) {
517*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding timeout info.\n"));
518*0Sstevel@tonic-gate 		nvlist_free(nvlp);
519*0Sstevel@tonic-gate 		return (rc);
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 	/* add global stats boolean */
523*0Sstevel@tonic-gate 	if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
524*0Sstevel@tonic-gate 	    (uint32_t)flowacct_data->global_stats)) != 0) {
525*0Sstevel@tonic-gate 		flowacct0dbg(("flowacct_info: error adding global stats "\
526*0Sstevel@tonic-gate 		    "info.\n"));
527*0Sstevel@tonic-gate 		nvlist_free(nvlp);
528*0Sstevel@tonic-gate 		return (rc);
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	/* call back with nvlist */
532*0Sstevel@tonic-gate 	rc = fn(nvlp, arg);
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 	nvlist_free(nvlp);
535*0Sstevel@tonic-gate 	return (rc);
536*0Sstevel@tonic-gate }
537