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