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