4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/types.h>
31 #include <sys/atomic.h>
32 #include <sys/systm.h>
33 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <sys/modctl.h>
37 #include <sys/sunddi.h>
39 #include <ipp/ipp_config.h>
40 #include <inet/common.h>
41 #include <ipp/flowacct/flowacct_impl.h>
44 #define D_SM_COMMENT "IPP Flow Accounting Module"
46 /* DDI file for flowacct ipp module */
48 static int flowacct_create_action(ipp_action_id_t
, nvlist_t
**, ipp_flags_t
);
49 static int flowacct_modify_action(ipp_action_id_t
, nvlist_t
**, ipp_flags_t
);
50 static int flowacct_destroy_action(ipp_action_id_t
, ipp_flags_t
);
51 static int flowacct_info(ipp_action_id_t
, int (*)(nvlist_t
*, void *), void *,
53 static int flowacct_invoke_action(ipp_action_id_t
, ipp_packet_t
*);
55 static int update_flowacct_kstats(ipp_stat_t
*, void *, int);
57 ipp_ops_t flowacct_ops
= {
59 flowacct_create_action
, /* ippo_action_create */
60 flowacct_modify_action
, /* ippo_action_modify */
61 flowacct_destroy_action
, /* ippo_action_destroy */
62 flowacct_info
, /* ippo_action_info */
63 flowacct_invoke_action
/* ippo_action_invoke */
66 extern struct mod_ops mod_ippops
;
69 * Module linkage information for the kernel.
71 static struct modlipp modlipp
= {
77 static struct modlinkage modlinkage
= {
86 return (mod_install(&modlinkage
));
92 return (mod_remove(&modlinkage
));
96 _info(struct modinfo
*modinfop
)
98 return (mod_info(&modlinkage
, modinfop
));
101 /* Update global stats */
103 update_flowacct_kstats(ipp_stat_t
*sp
, void *arg
, int rw
)
105 flowacct_data_t
*flowacct_data
= (flowacct_data_t
*)arg
;
106 flowacct_stat_t
*fl_stat
= (flowacct_stat_t
*)sp
->ipps_data
;
107 ASSERT((fl_stat
!= NULL
) && (flowacct_data
!= 0));
109 (void) ipp_stat_named_op(&fl_stat
->nbytes
, &flowacct_data
->nbytes
, rw
);
110 (void) ipp_stat_named_op(&fl_stat
->tbytes
, &flowacct_data
->tbytes
, rw
);
111 (void) ipp_stat_named_op(&fl_stat
->nflows
, &flowacct_data
->nflows
, rw
);
112 (void) ipp_stat_named_op(&fl_stat
->usedmem
, &flowacct_data
->usedmem
,
114 (void) ipp_stat_named_op(&fl_stat
->npackets
, &flowacct_data
->npackets
,
116 (void) ipp_stat_named_op(&fl_stat
->epackets
, &flowacct_data
->epackets
,
121 /* Initialize global stats */
123 global_statinit(ipp_action_id_t aid
, flowacct_data_t
*flowacct_data
)
125 flowacct_stat_t
*flacct_stat
;
128 if ((err
= ipp_stat_create(aid
, FLOWACCT_STATS_STRING
,
129 FLOWACCT_STATS_COUNT
, update_flowacct_kstats
, flowacct_data
,
130 &flowacct_data
->stats
)) != 0) {
131 flowacct0dbg(("global_statinit: error creating flowacct "\
135 flacct_stat
= (flowacct_stat_t
*)(flowacct_data
->stats
)->ipps_data
;
136 ASSERT(flacct_stat
!= NULL
);
138 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "bytes_in_tbl",
139 IPP_STAT_UINT64
, &flacct_stat
->tbytes
)) != 0) {
140 flowacct0dbg(("global_statinit: ipp_stat_named_init returned "\
141 "with error %d\n", err
));
144 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "nbytes",
145 IPP_STAT_UINT64
, &flacct_stat
->nbytes
)) != 0) {
146 flowacct0dbg(("global_statinit: ipp_stat_named_init returned "\
147 "with error %d\n", err
));
150 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "npackets",
151 IPP_STAT_UINT64
, &flacct_stat
->npackets
)) != 0) {
152 flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
153 "with error %d\n", err
));
156 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "usedmem",
157 IPP_STAT_UINT64
, &flacct_stat
->usedmem
)) != 0) {
158 flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
159 "with error %d\n", err
));
162 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "flows_in_tbl",
163 IPP_STAT_UINT32
, &flacct_stat
->nflows
)) != 0) {
164 flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
165 "with error %d\n", err
));
168 if ((err
= ipp_stat_named_init(flowacct_data
->stats
, "epackets",
169 IPP_STAT_UINT64
, &flacct_stat
->epackets
)) != 0) {
170 flowacct0dbg(("global_statinit:ipp_stat_named_init returned "\
171 "with error %d\n", err
));
174 ipp_stat_install(flowacct_data
->stats
);
180 flowacct_create_action(ipp_action_id_t aid
, nvlist_t
**nvlpp
, ipp_flags_t flags
)
183 flowacct_data_t
*flowacct_data
;
188 uint32_t timeout
= FLOWACCT_DEF_TIMEOUT
;
189 uint32_t timer
= FLOWACCT_DEF_TIMER
;
192 *nvlpp
= NULL
; /* nvlist should be NULL on return */
194 if ((flowacct_data
= kmem_zalloc(FLOWACCT_DATA_SZ
, KM_NOSLEEP
))
200 /* parse next action name */
201 if ((rc
= nvlist_lookup_string(nvlp
, FLOWACCT_NEXT_ACTION_NAME
,
202 &next_action
)) != 0) {
204 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
205 flowacct0dbg(("flowacct_create_action: invalid config, "\
206 "next_action missing\n"));
209 if ((flowacct_data
->next_action
= ipp_action_lookup(next_action
))
210 == IPP_ACTION_INVAL
) {
212 flowacct0dbg(("flowacct_create_action: invalid next_action\n"));
213 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
217 if ((rc
= ipp_action_name(aid
, &flowacct_data
->act_name
)) != 0) {
219 flowacct0dbg(("flowacct_create_action: invalid next aid\n"));
220 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
224 /* parse flow timeout - in millisec, if present */
225 (void) nvlist_lookup_uint32(nvlp
, FLOWACCT_TIMEOUT
, &timeout
);
227 /* Convert to FLOWACCT_MSEC_TO_NSEC */
228 flowacct_data
->timeout
= (uint64_t)timeout
* FLOWACCT_MSEC_TO_NSEC
;
230 /* parse flow timer - in millisec, if present */
231 (void) nvlist_lookup_uint32(nvlp
, FLOWACCT_TIMER
, &timer
);
233 /* Convert to FLOWACCT_MSEC_TO_USEC */
234 flowacct_data
->timer
= (uint64_t)timer
* FLOWACCT_MSEC_TO_USEC
;
236 if ((rc
= nvlist_lookup_uint32(nvlp
, FLOWACCT_MAX_LIMIT
,
237 &flowacct_data
->max_limit
)) != 0) {
239 flowacct0dbg(("flowacct_create_action: invalid config, "\
240 "max_limit missing\n"));
241 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
245 if ((rc
= nvlist_lookup_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
,
247 flowacct_data
->global_stats
= B_FALSE
;
249 flowacct_data
->global_stats
= (boolean_t
)bstats
;
250 if (flowacct_data
->global_stats
) {
251 if ((rc
= global_statinit(aid
, flowacct_data
)) != 0) {
252 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
260 /* set action chain reference */
261 if ((rc
= ipp_action_ref(aid
, flowacct_data
->next_action
,
263 flowacct0dbg(("flowacct_create_action: ipp_action_ref " \
264 "returned with error %d\n", rc
));
265 if (flowacct_data
->stats
!= NULL
) {
266 ipp_stat_destroy(flowacct_data
->stats
);
268 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
272 /* Initialize locks */
273 for (flow_count
= 0, head
= flowacct_data
->flows_tbl
;
274 flow_count
< (FLOW_TBL_COUNT
+ 1); flow_count
++, head
++) {
275 mutex_init(&head
->lock
, NULL
, MUTEX_DEFAULT
, 0);
278 ipp_action_set_ptr(aid
, (void *)flowacct_data
);
283 flowacct_modify_action(ipp_action_id_t aid
, nvlist_t
**nvlpp
, ipp_flags_t flags
)
288 char *next_action_name
, *act_name
;
289 ipp_action_id_t next_action
;
290 uint32_t timeout
, timer
, bstats
, max_limit
;
291 flowacct_data_t
*flowacct_data
;
294 *nvlpp
= NULL
; /* nvlist should be NULL when this returns */
296 if ((rc
= nvlist_lookup_byte(nvlp
, IPP_CONFIG_TYPE
, &config_type
))
299 flowacct0dbg(("flowacct_modify_action: invalid configuration "\
304 if (config_type
!= IPP_SET
) {
306 flowacct0dbg(("flowacct_modify_action: invalid configuration "\
307 "type %d\n", config_type
));
311 flowacct_data
= (flowacct_data_t
*)ipp_action_get_ptr(aid
);
313 /* parse next action name, if present */
314 if ((rc
= nvlist_lookup_string(nvlp
, FLOWACCT_NEXT_ACTION_NAME
,
315 &next_action_name
)) == 0) {
316 /* lookup action name to get action id */
317 if ((next_action
= ipp_action_lookup(next_action_name
))
318 == IPP_ACTION_INVAL
) {
320 flowacct0dbg(("flowacct_modify_action: next_action "\
324 /* reference new action */
325 if ((rc
= ipp_action_ref(aid
, next_action
, flags
)) != 0) {
327 flowacct0dbg(("flowacct_modify_action: "\
328 "ipp_action_ref returned with error %d\n", rc
));
332 if ((rc
= ipp_action_name(aid
, &act_name
)) != 0) {
334 flowacct0dbg(("flowacct_modify_action: invalid next "\
339 /* unref old action */
340 rc
= ipp_action_unref(aid
, flowacct_data
->next_action
, flags
);
342 flowacct_data
->next_action
= next_action
;
343 kmem_free(flowacct_data
->act_name
,
344 (strlen(flowacct_data
->act_name
) + 1));
345 flowacct_data
->act_name
= act_name
;
348 /* parse timeout, if present */
349 if ((rc
= nvlist_lookup_uint32(nvlp
, FLOWACCT_TIMEOUT
, &timeout
))
351 flowacct_data
->timeout
= (uint64_t)timeout
*
352 FLOWACCT_MSEC_TO_NSEC
;
355 /* parse timer, if present */
356 if ((rc
= nvlist_lookup_uint32(nvlp
, FLOWACCT_TIMER
, &timer
)) == 0) {
357 flowacct_data
->timer
= (uint64_t)timer
* FLOWACCT_MSEC_TO_USEC
;
360 /* parse max_flow, if present */
361 if ((rc
= nvlist_lookup_uint32(nvlp
, FLOWACCT_MAX_LIMIT
, &max_limit
))
363 flowacct_data
->max_limit
= max_limit
;
366 /* parse gather_stats boolean, if present */
367 if ((rc
= nvlist_lookup_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
, &bstats
))
369 boolean_t new_val
= (boolean_t
)bstats
;
371 /* Turning global stats on */
372 if (new_val
&& !flowacct_data
->global_stats
) {
373 rc
= global_statinit(aid
, flowacct_data
);
375 flowacct_data
->global_stats
= new_val
;
377 flowacct0dbg(("flowacct_modify_action: error "\
378 "enabling stats\n"));
380 } else if (!new_val
&& flowacct_data
->global_stats
) {
381 flowacct_data
->global_stats
= new_val
;
382 ipp_stat_destroy(flowacct_data
->stats
);
389 flowacct_destroy_action(ipp_action_id_t aid
, ipp_flags_t flags
)
391 flowacct_data_t
*flowacct_data
;
395 flowacct_data
= (flowacct_data_t
*)ipp_action_get_ptr(aid
);
396 ASSERT(flowacct_data
!= NULL
);
398 while (flowacct_data
->flow_tid
!= 0) {
399 timeout_id_t tid
= flowacct_data
->flow_tid
;
400 flowacct_data
->flow_tid
= 0;
401 (void) untimeout(tid
);
404 if (flowacct_data
->stats
!= NULL
) {
405 ipp_stat_destroy(flowacct_data
->stats
);
408 /* Dump all the flows to the file */
409 flowacct_timer(FLOWACCT_PURGE_FLOW
, flowacct_data
);
411 kmem_free(flowacct_data
->act_name
, (strlen(flowacct_data
->act_name
)
414 /* Destroy the locks */
415 for (flow_count
= 0, head
= flowacct_data
->flows_tbl
;
416 flow_count
< FLOW_TBL_COUNT
; flow_count
++, head
++) {
417 mutex_destroy(&head
->lock
);
419 /* unreference the action */
420 rc
= ipp_action_unref(aid
, flowacct_data
->next_action
, flags
);
424 kmem_free(flowacct_data
, FLOWACCT_DATA_SZ
);
429 flowacct_invoke_action(ipp_action_id_t aid
, ipp_packet_t
*packet
)
431 flowacct_data_t
*flowacct_data
;
435 /* get mblk from ipp_packet structure */
436 mp
= ipp_packet_get_data(packet
);
437 flowacct_data
= (flowacct_data_t
*)ipp_action_get_ptr(aid
);
438 ASSERT(flowacct_data
!= NULL
);
440 /* flowacct packet as configured */
441 if ((rc
= flowacct_process(&mp
, flowacct_data
)) != 0) {
444 /* return packet with next action set */
445 return (ipp_packet_next(packet
, flowacct_data
->next_action
));
451 flowacct_info(ipp_action_id_t aid
, int (*fn
)(nvlist_t
*, void *), void *arg
,
455 flowacct_data_t
*flowacct_data
;
460 flowacct_data
= (flowacct_data_t
*)ipp_action_get_ptr(aid
);
461 ASSERT(flowacct_data
!= NULL
);
464 /* allocate nvlist to be passed back */
465 if ((rc
= nvlist_alloc(&nvlp
, NV_UNIQUE_NAME
, KM_NOSLEEP
)) != 0) {
466 flowacct0dbg(("flowacct_info: memory allocation failure\n"));
470 /* look up next action with the next action id */
471 if ((rc
= ipp_action_name(flowacct_data
->next_action
,
472 &next_action
)) != 0) {
473 flowacct0dbg(("flowacct_info: next action not available\n"));
478 /* add next action name */
479 if ((rc
= nvlist_add_string(nvlp
, FLOWACCT_NEXT_ACTION_NAME
,
480 next_action
)) != 0) {
481 flowacct0dbg(("flowacct_info: error adding next action\n"));
483 kmem_free(next_action
, (strlen(next_action
) + 1));
487 /* free action name */
488 kmem_free(next_action
, (strlen(next_action
) + 1));
490 /* add config type */
491 if ((rc
= nvlist_add_byte(nvlp
, IPP_CONFIG_TYPE
, IPP_SET
)) != 0) {
492 flowacct0dbg(("flowacct_info: error adding config type\n"));
498 param
= flowacct_data
->timer
/ FLOWACCT_MSEC_TO_USEC
;
499 if ((rc
= nvlist_add_uint32(nvlp
, FLOWACCT_TIMER
, param
)) != 0) {
500 flowacct0dbg(("flowacct_info: error adding timer info.\n"));
506 if ((rc
= nvlist_add_uint32(nvlp
, FLOWACCT_MAX_LIMIT
,
507 flowacct_data
->max_limit
)) != 0) {
508 flowacct0dbg(("flowacct_info: error adding max_flow info.\n"));
514 param
= flowacct_data
->timeout
/ FLOWACCT_MSEC_TO_NSEC
;
516 if ((rc
= nvlist_add_uint32(nvlp
, FLOWACCT_TIMEOUT
, param
)) != 0) {
517 flowacct0dbg(("flowacct_info: error adding timeout info.\n"));
522 /* add global stats boolean */
523 if ((rc
= nvlist_add_uint32(nvlp
, IPP_ACTION_STATS_ENABLE
,
524 (uint32_t)flowacct_data
->global_stats
)) != 0) {
525 flowacct0dbg(("flowacct_info: error adding global stats "\
531 /* call back with nvlist */