Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / ipp / flowacct / flowacctddi.c
blobbd348ad4c49329e8eef332c5968480eb2235aeb6
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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>
30 #include <sys/conf.h>
31 #include <sys/atomic.h>
32 #include <sys/systm.h>
33 #include <sys/socket.h>
34 #include <sys/spl.h>
35 #include <netinet/in.h>
36 #include <sys/modctl.h>
37 #include <sys/sunddi.h>
38 #include <ipp/ipp.h>
39 #include <ipp/ipp_config.h>
40 #include <inet/common.h>
41 #include <ipp/flowacct/flowacct_impl.h>
42 #include <sys/ddi.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 *,
52 ipp_flags_t);
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 = {
58 IPPO_REV,
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 = {
72 &mod_ippops,
73 D_SM_COMMENT " 1.12",
74 &flowacct_ops
77 static struct modlinkage modlinkage = {
78 MODREV_1,
79 (void *)&modlipp,
80 NULL
83 int
84 _init(void)
86 return (mod_install(&modlinkage));
89 int
90 _fini(void)
92 return (mod_remove(&modlinkage));
95 int
96 _info(struct modinfo *modinfop)
98 return (mod_info(&modlinkage, modinfop));
101 /* Update global stats */
102 static int
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,
113 rw);
114 (void) ipp_stat_named_op(&fl_stat->npackets, &flowacct_data->npackets,
115 rw);
116 (void) ipp_stat_named_op(&fl_stat->epackets, &flowacct_data->epackets,
117 rw);
118 return (0);
121 /* Initialize global stats */
122 static int
123 global_statinit(ipp_action_id_t aid, flowacct_data_t *flowacct_data)
125 flowacct_stat_t *flacct_stat;
126 int err = 0;
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 "\
132 "stats\n"));
133 return (err);
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));
142 return (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));
148 return (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));
154 return (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));
160 return (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));
166 return (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));
172 return (err);
174 ipp_stat_install(flowacct_data->stats);
176 return (err);
179 static int
180 flowacct_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
182 nvlist_t *nvlp;
183 flowacct_data_t *flowacct_data;
184 char *next_action;
185 int rc, flow_count;
186 list_head_t *head;
187 uint32_t bstats;
188 uint32_t timeout = FLOWACCT_DEF_TIMEOUT;
189 uint32_t timer = FLOWACCT_DEF_TIMER;
191 nvlp = *nvlpp;
192 *nvlpp = NULL; /* nvlist should be NULL on return */
194 if ((flowacct_data = kmem_zalloc(FLOWACCT_DATA_SZ, KM_NOSLEEP))
195 == NULL) {
196 nvlist_free(nvlp);
197 return (ENOMEM);
200 /* parse next action name */
201 if ((rc = nvlist_lookup_string(nvlp, FLOWACCT_NEXT_ACTION_NAME,
202 &next_action)) != 0) {
203 nvlist_free(nvlp);
204 kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
205 flowacct0dbg(("flowacct_create_action: invalid config, "\
206 "next_action missing\n"));
207 return (rc);
209 if ((flowacct_data->next_action = ipp_action_lookup(next_action))
210 == IPP_ACTION_INVAL) {
211 nvlist_free(nvlp);
212 flowacct0dbg(("flowacct_create_action: invalid next_action\n"));
213 kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
214 return (EINVAL);
217 if ((rc = ipp_action_name(aid, &flowacct_data->act_name)) != 0) {
218 nvlist_free(nvlp);
219 flowacct0dbg(("flowacct_create_action: invalid next aid\n"));
220 kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
221 return (EINVAL);
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) {
238 nvlist_free(nvlp);
239 flowacct0dbg(("flowacct_create_action: invalid config, "\
240 "max_limit missing\n"));
241 kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
242 return (rc);
245 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
246 &bstats)) != 0) {
247 flowacct_data->global_stats = B_FALSE;
248 } else {
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);
253 return (rc);
258 nvlist_free(nvlp);
260 /* set action chain reference */
261 if ((rc = ipp_action_ref(aid, flowacct_data->next_action,
262 flags)) != 0) {
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);
269 return (rc);
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);
279 return (0);
282 static int
283 flowacct_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
285 nvlist_t *nvlp;
286 int rc = 0;
287 uint8_t config_type;
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;
293 nvlp = *nvlpp;
294 *nvlpp = NULL; /* nvlist should be NULL when this returns */
296 if ((rc = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
297 != 0) {
298 nvlist_free(nvlp);
299 flowacct0dbg(("flowacct_modify_action: invalid configuration "\
300 "type\n"));
301 return (rc);
304 if (config_type != IPP_SET) {
305 nvlist_free(nvlp);
306 flowacct0dbg(("flowacct_modify_action: invalid configuration "\
307 "type %d\n", config_type));
308 return (EINVAL);
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) {
319 nvlist_free(nvlp);
320 flowacct0dbg(("flowacct_modify_action: next_action "\
321 "invalid\n"));
322 return (EINVAL);
324 /* reference new action */
325 if ((rc = ipp_action_ref(aid, next_action, flags)) != 0) {
326 nvlist_free(nvlp);
327 flowacct0dbg(("flowacct_modify_action: "\
328 "ipp_action_ref returned with error %d\n", rc));
329 return (rc);
332 if ((rc = ipp_action_name(aid, &act_name)) != 0) {
333 nvlist_free(nvlp);
334 flowacct0dbg(("flowacct_modify_action: invalid next "\
335 "aid\n"));
336 return (EINVAL);
339 /* unref old action */
340 rc = ipp_action_unref(aid, flowacct_data->next_action, flags);
341 ASSERT(rc == 0);
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))
350 == 0) {
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))
362 == 0) {
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))
368 == 0) {
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);
374 if (rc == 0) {
375 flowacct_data->global_stats = new_val;
376 } else {
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);
385 return (0);
388 static int
389 flowacct_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
391 flowacct_data_t *flowacct_data;
392 int rc, flow_count;
393 list_head_t *head;
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)
412 + 1));
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);
421 ASSERT(rc == 0);
424 kmem_free(flowacct_data, FLOWACCT_DATA_SZ);
425 return (0);
428 static int
429 flowacct_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
431 flowacct_data_t *flowacct_data;
432 mblk_t *mp = NULL;
433 int rc;
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) {
442 return (rc);
443 } else {
444 /* return packet with next action set */
445 return (ipp_packet_next(packet, flowacct_data->next_action));
449 /* ARGSUSED */
450 static int
451 flowacct_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
452 ipp_flags_t flags)
454 nvlist_t *nvlp;
455 flowacct_data_t *flowacct_data;
456 char *next_action;
457 uint32_t param;
458 int rc;
460 flowacct_data = (flowacct_data_t *)ipp_action_get_ptr(aid);
461 ASSERT(flowacct_data != NULL);
462 ASSERT(fn != 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"));
467 return (rc);
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"));
474 nvlist_free(nvlp);
475 return (rc);
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"));
482 nvlist_free(nvlp);
483 kmem_free(next_action, (strlen(next_action) + 1));
484 return (rc);
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"));
493 nvlist_free(nvlp);
494 return (rc);
497 /* add timer */
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"));
501 nvlist_free(nvlp);
502 return (rc);
505 /* add max_limit */
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"));
509 nvlist_free(nvlp);
510 return (rc);
514 param = flowacct_data->timeout / FLOWACCT_MSEC_TO_NSEC;
515 /* add timeout */
516 if ((rc = nvlist_add_uint32(nvlp, FLOWACCT_TIMEOUT, param)) != 0) {
517 flowacct0dbg(("flowacct_info: error adding timeout info.\n"));
518 nvlist_free(nvlp);
519 return (rc);
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 "\
526 "info.\n"));
527 nvlist_free(nvlp);
528 return (rc);
531 /* call back with nvlist */
532 rc = fn(nvlp, arg);
534 nvlist_free(nvlp);
535 return (rc);