1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <sys/types.h>
28 #include <sys/atomic.h>
29 #include <sys/systm.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <sys/modctl.h>
33 #include <sys/sunddi.h>
34 #include <ipp/ipp.h>
35 #include <ipp/ipp_config.h>
36 #include <inet/common.h>
37 #include <ipp/meters/meter_impl.h>
38
39 #define D_SM_COMMENT "IPP Sliding Window Meter"
40
41 /* DDI file for tswtcl ipp module */
42
43 static int tswtcl_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
44 static int tswtcl_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
45 static int tswtcl_destroy_action(ipp_action_id_t, ipp_flags_t);
46 static int tswtcl_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
47 ipp_flags_t);
48 static int tswtcl_invoke_action(ipp_action_id_t, ipp_packet_t *);
49
50 /* Stats init function */
51 static int tswtcl_statinit(ipp_action_id_t, tswtcl_data_t *);
52
53 /* Stats callback function */
54 static int tswtcl_update_stats(ipp_stat_t *, void *, int);
55
56 ipp_ops_t tswtcl_ops = {
57 IPPO_REV,
58 tswtcl_create_action, /* ippo_action_create */
59 tswtcl_modify_action, /* ippo_action_modify */
60 tswtcl_destroy_action, /* ippo_action_destroy */
61 tswtcl_info, /* ippo_action_info */
62 tswtcl_invoke_action /* ippo_action_invoke */
63 };
64
65 extern struct mod_ops mod_ippops;
66
67 /*
68 * Module linkage information for the kernel.
69 */
70 static struct modlipp modlipp = {
71 &mod_ippops,
72 D_SM_COMMENT,
73 &tswtcl_ops
74 };
75
76 static struct modlinkage modlinkage = {
77 MODREV_1,
78 { (void *)&modlipp, NULL }
79 };
80
81
82 int
83 _init(void)
84 {
85 return (mod_install(&modlinkage));
86 }
87
88 int
89 _fini(void)
90 {
91 return (mod_remove(&modlinkage));
92 }
93
94 int
95 _info(struct modinfo *modinfop)
96 {
97 return (mod_info(&modlinkage, modinfop));
98 }
99
100 /* ARGSUSED */
101 static int
102 tswtcl_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
103 {
104 nvlist_t *nvlp;
105 tswtcl_data_t *tswtcl_data;
106 tswtcl_cfg_t *cfg_parms;
107 char *next_action;
108 uint32_t bstats;
109 int rc, rc2;
110
111 nvlp = *nvlpp;
112 *nvlpp = NULL; /* nvlist should be NULL on return */
113
114
115 if ((cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP)) == NULL) {
116 nvlist_free(nvlp);
117 return (ENOMEM);
118 }
119
120 /* parse red next action name */
121 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
122 &next_action)) != 0) {
123 nvlist_free(nvlp);
124 tswtcl0dbg(("tswtcl_create_action:invalid config, red action" \
125 " name missing\n"));
126 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
127 return (rc);
128 }
129 if ((cfg_parms->red_action = ipp_action_lookup(next_action))
130 == IPP_ACTION_INVAL) {
131 nvlist_free(nvlp);
132 tswtcl0dbg(("tswtcl_create_action: red action invalid\n"));
133 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
134 return (EINVAL);
135 }
136
137 /* parse yellow next action name */
138 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
139 &next_action)) != 0) {
140 nvlist_free(nvlp);
141 tswtcl0dbg(("tswtcl_create_action:invalid config, yellow " \
142 "action name missing\n"));
143 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
144 return (rc);
145 }
146 if ((cfg_parms->yellow_action = ipp_action_lookup(next_action))
147 == IPP_ACTION_INVAL) {
148 nvlist_free(nvlp);
149 tswtcl0dbg(("tswtcl_create_action: yellow action invalid\n"));
150 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
151 return (EINVAL);
152 }
153
154 /* parse green next action name */
155 if ((rc = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
156 &next_action)) != 0) {
157 nvlist_free(nvlp);
158 tswtcl0dbg(("tswtcl_create_action:invalid config, green " \
159 "action name missing\n"));
160 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
161 return (rc);
162 }
163 if ((cfg_parms->green_action = ipp_action_lookup(next_action))
164 == IPP_ACTION_INVAL) {
165 nvlist_free(nvlp);
166 tswtcl0dbg(("tswtcl_create_action: green action invalid\n"));
167 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
168 return (EINVAL);
169 }
170
171 /* parse committed rate - in bits / sec */
172 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE,
173 &cfg_parms->committed_rate)) != 0) {
174 nvlist_free(nvlp);
175 tswtcl0dbg(("tswtcl_create_action: invalid config, "\
176 " committed rate missing\n"));
177 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
178 return (rc);
179 }
180
181 /* parse peak rate - in bits / sec */
182 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE,
183 &cfg_parms->peak_rate)) != 0) {
184 nvlist_free(nvlp);
185 tswtcl0dbg(("tswtcl_create_action: invalid config, "\
186 " peak rate missing\n"));
187 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
188 return (rc);
189 }
190
191 if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
192 nvlist_free(nvlp);
193 tswtcl0dbg(("tswtcl_create_action: invalid config, "\
194 " peak rate < committed rate\n"));
195 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
196 return (EINVAL);
197 }
198
199 /* parse window - in msec */
200 if ((rc = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
201 &cfg_parms->window)) != 0) {
202 nvlist_free(nvlp);
203 tswtcl0dbg(("tswtcl_create_action: invalid config, "\
204 " window missing\n"));
205 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
206 return (rc);
207 }
208 /* convert to nsec */
209 cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
210 METER_MSEC_TO_NSEC;
211
212 /* parse stats */
213 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
214 != 0) {
215 cfg_parms->stats = B_FALSE;
216 } else {
217 cfg_parms->stats = (boolean_t)bstats;
218 }
219
220 nvlist_free(nvlp);
221
222 /* Initialize other stuff */
223 tswtcl_data = kmem_zalloc(TSWTCL_DATA_SZ, KM_NOSLEEP);
224 if (tswtcl_data == NULL) {
225 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
226 return (ENOMEM);
227 }
228
229 if (cfg_parms->stats) {
230 if ((rc = tswtcl_statinit(aid, tswtcl_data)) != 0) {
231 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
232 kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
233 return (rc);
234 }
235 }
236
237 /* set action chain reference */
238 if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
239 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
240 "returned with error %d", rc));
241 goto cleanup;
242 }
243 if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
244 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
245 "returned with error %d", rc));
246 rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
247 ASSERT(rc2 == 0);
248 goto cleanup;
249 }
250 if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
251 tswtcl0dbg(("tswtcl_create_action: ipp_action_ref " \
252 "returned with error %d", rc));
253 rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
254 ASSERT(rc2 == 0);
255 rc2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
256 ASSERT(rc2 == 0);
257 goto cleanup;
258 }
259
260 /* Initializations */
261 cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
262 tswtcl_data->cfg_parms = cfg_parms;
263 tswtcl_data->avg_rate = cfg_parms->committed_rate;
264 mutex_init(&tswtcl_data->tswtcl_lock, NULL, MUTEX_DEFAULT, 0);
265 tswtcl_data->win_front = gethrtime();
266 ipp_action_set_ptr(aid, (void *)tswtcl_data);
267
268 return (0);
269
270 cleanup:
271 if (cfg_parms->stats) {
272 ipp_stat_destroy(tswtcl_data->stats);
273 }
274 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
275 kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
276 return (rc);
277
278 }
279
280 static int
281 tswtcl_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
282 {
283
284 nvlist_t *nvlp;
285 int err = 0, err2;
286 uint8_t config_type;
287 char *next_action_name;
288 ipp_action_id_t next_action;
289 uint32_t rate;
290 tswtcl_cfg_t *cfg_parms, *old_cfg;
291 tswtcl_data_t *tswtcl_data;
292 uint32_t bstats;
293
294 nvlp = *nvlpp;
295 *nvlpp = NULL; /* nvlist should be NULL when this returns */
296
297 if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
298 != 0) {
299 nvlist_free(nvlp);
300 tswtcl0dbg(("tswtcl_modify_action:invalid configuration type"));
301 return (err);
302 }
303
304 if (config_type != IPP_SET) {
305 nvlist_free(nvlp);
306 tswtcl0dbg(("tswtcl_modify_action:invalid configuration type " \
307 "%d", config_type));
308 return (EINVAL);
309 }
310
311 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
312 old_cfg = tswtcl_data->cfg_parms;
313
314 cfg_parms = kmem_alloc(TSWTCL_CFG_SZ, KM_NOSLEEP);
315 if (cfg_parms == NULL) {
316 nvlist_free(nvlp);
317 tswtcl0dbg(("tswtcl_modify_action:mem. allocation failure\n"));
318 return (ENOMEM);
319 }
320
321 /* Just copy all and change as needed */
322 bcopy(old_cfg, cfg_parms, TSWTCL_CFG_SZ);
323
324 /* parse red action name, if present */
325 if ((err = nvlist_lookup_string(nvlp, TSWTCL_RED_ACTION_NAME,
326 &next_action_name)) == 0) {
327 /* Get action id */
328 if ((next_action = ipp_action_lookup(next_action_name))
329 == IPP_ACTION_INVAL) {
330 nvlist_free(nvlp);
331 tswtcl0dbg(("tswtcl_modify_action: red next_action"\
332 " invalid\n"));
333 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
334 return (EINVAL);
335 }
336 cfg_parms->red_action = next_action;
337 }
338
339 /* parse yellow action name, if present */
340 if ((err = nvlist_lookup_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
341 &next_action_name)) == 0) {
342 /* Get action id */
343 if ((next_action = ipp_action_lookup(next_action_name))
344 == IPP_ACTION_INVAL) {
345 nvlist_free(nvlp);
346 tswtcl0dbg(("tswtcl_modify_action: yellow next_action"\
347 " invalid\n"));
348 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
349 return (EINVAL);
350 }
351 cfg_parms->yellow_action = next_action;
352 }
353
354 /* parse green action name, if present */
355 if ((err = nvlist_lookup_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
356 &next_action_name)) == 0) {
357 /* Get action id */
358 if ((next_action = ipp_action_lookup(next_action_name))
359 == IPP_ACTION_INVAL) {
360 nvlist_free(nvlp);
361 tswtcl0dbg(("tswtcl_modify_action: green next_action"\
362 " invalid\n"));
363 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
364 return (EINVAL);
365 }
366 cfg_parms->green_action = next_action;
367 }
368
369 /* parse committed rate, if present */
370 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_COMMITTED_RATE, &rate))
371 == 0) {
372 cfg_parms->committed_rate = rate;
373 }
374
375 /* parse peak rate, if present */
376 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_PEAK_RATE, &rate))
377 == 0) {
378 cfg_parms->peak_rate = rate;
379 }
380
381 if (cfg_parms->peak_rate < cfg_parms->committed_rate) {
382 nvlist_free(nvlp);
383 tswtcl0dbg(("tswtcl_create_action: invalid config, "\
384 " peak rate < committed rate\n"));
385 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
386 return (EINVAL);
387 }
388
389 /* parse window - in msec */
390 if ((err = nvlist_lookup_uint32(nvlp, TSWTCL_WINDOW,
391 &cfg_parms->window)) != 0) {
392 cfg_parms->nsecwindow = (uint64_t)cfg_parms->window *
393 METER_MSEC_TO_NSEC;
394 }
395
396 /* parse stats, if present */
397 if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) {
398 cfg_parms->stats = (boolean_t)bstats;
399 if (cfg_parms->stats && !old_cfg->stats) {
400 if ((err = tswtcl_statinit(aid, tswtcl_data)) != 0) {
401 nvlist_free(nvlp);
402 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
403 return (err);
404 }
405 } else if (!cfg_parms->stats && old_cfg->stats) {
406 ipp_stat_destroy(tswtcl_data->stats);
407 }
408 }
409
410 /* Can we ref all the new actions? */
411 if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
412 tswtcl0dbg(("tswtcl_modify_data: can't ref. red action\n"));
413 nvlist_free(nvlp);
414 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
415 return (err);
416 }
417
418 if ((err = ipp_action_ref(aid, cfg_parms->yellow_action, flags)) != 0) {
419 tswtcl0dbg(("tswtcl_modify_data:can't ref. yellow action\n"));
420 nvlist_free(nvlp);
421 err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
422 ASSERT(err2 == 0);
423 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
424 return (err);
425 }
426
427 if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
428 tswtcl0dbg(("tswtcl_modify_data:can't ref. green action\n"));
429 nvlist_free(nvlp);
430 err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
431 ASSERT(err2 == 0);
432 err2 = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
433 ASSERT(err2 == 0);
434 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
435 return (err);
436 }
437
438 /* Re-compute pminusc */
439 cfg_parms->pminusc = cfg_parms->peak_rate - cfg_parms->committed_rate;
440
441 /* Actually modify the configuration */
442 mutex_enter(&tswtcl_data->tswtcl_lock);
443 tswtcl_data->cfg_parms = cfg_parms;
444 mutex_exit(&tswtcl_data->tswtcl_lock);
445
446 /* Un-ref the old actions */
447 err = ipp_action_unref(aid, old_cfg->red_action, flags);
448 ASSERT(err == 0);
449 err = ipp_action_unref(aid, old_cfg->yellow_action, flags);
450 ASSERT(err == 0);
451 err = ipp_action_unref(aid, old_cfg->green_action, flags);
452 ASSERT(err == 0);
453
454 /* Free the old configuration */
455 kmem_free(old_cfg, TSWTCL_CFG_SZ);
456
457 nvlist_free(nvlp);
458
459 return (0);
460 }
461
462 static int
463 tswtcl_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
464 {
465 tswtcl_data_t *tswtcl_data;
466 tswtcl_cfg_t *cfg_parms;
467 int rc;
468
469 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
470 ASSERT(tswtcl_data != NULL);
471
472 cfg_parms = tswtcl_data->cfg_parms;
473
474 if (cfg_parms->stats) {
475 ipp_stat_destroy(tswtcl_data->stats);
476 }
477
478 /* unreference the action */
479 rc = ipp_action_unref(aid, cfg_parms->red_action, flags);
480 ASSERT(rc == 0);
481 rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
482 ASSERT(rc == 0);
483 rc = ipp_action_unref(aid, cfg_parms->green_action, flags);
484 ASSERT(rc == 0);
485
486 mutex_destroy(&tswtcl_data->tswtcl_lock);
487 kmem_free(cfg_parms, TSWTCL_CFG_SZ);
488 kmem_free(tswtcl_data, TSWTCL_DATA_SZ);
489 return (0);
490 }
491
492 static int
493 tswtcl_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
494 {
495 tswtcl_data_t *tswtcl_data;
496 ipp_action_id_t next_action;
497 mblk_t *mp = NULL;
498 int rc;
499
500 /* get mblk from ipp_packet structure */
501 mp = ipp_packet_get_data(packet);
502 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
503 ASSERT(tswtcl_data != NULL);
504
505 /* tswtcl packet as configured */
506 if ((rc = tswtcl_process(&mp, tswtcl_data, &next_action)) != 0) {
507 return (rc);
508 } else {
509 return (ipp_packet_next(packet, next_action));
510 }
511 }
512
513 static int
514 tswtcl_statinit(ipp_action_id_t aid, tswtcl_data_t *tswtcl_data)
515 {
516 int rc = 0;
517 meter_stat_t *statsp;
518
519 /* install stats entry */
520 if ((rc = ipp_stat_create(aid, TSWTCL_STATS_STRING, METER_STATS_COUNT,
521 tswtcl_update_stats, tswtcl_data, &tswtcl_data->stats)) != 0) {
522 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
523 " with %d\n", rc));
524 return (rc);
525 }
526
527 statsp = (meter_stat_t *)(tswtcl_data->stats)->ipps_data;
528 ASSERT(statsp != NULL);
529
530 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_packets",
531 IPP_STAT_UINT64, &statsp->red_packets)) != 0) {
532 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
533 " with %d\n", rc));
534 return (rc);
535 }
536 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "red_bits",
537 IPP_STAT_UINT64, &statsp->red_bits)) != 0) {
538 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
539 " with %d\n", rc));
540 return (rc);
541 }
542 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_packets",
543 IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) {
544 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
545 " with %d\n", rc));
546 return (rc);
547 }
548 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "yellow_bits",
549 IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) {
550 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
551 " with %d\n", rc));
552 return (rc);
553 }
554 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_packets",
555 IPP_STAT_UINT64, &statsp->green_packets)) != 0) {
556 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
557 " with %d\n", rc));
558 return (rc);
559 }
560 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "green_bits",
561 IPP_STAT_UINT64, &statsp->green_bits)) != 0) {
562 tswtcl0dbg(("tswtcl_statinit:ipp_stat_create failed "\
563 " with %d\n", rc));
564 return (rc);
565 }
566 if ((rc = ipp_stat_named_init(tswtcl_data->stats, "epackets",
567 IPP_STAT_UINT64, &statsp->epackets)) != 0) {
568 tswtcl0dbg(("tswtcl_statinit:ipp_stat_named_init failed "\
569 " with %d\n", rc));
570 return (rc);
571 }
572 ipp_stat_install(tswtcl_data->stats);
573
574 return (rc);
575
576 }
577
578 static int
579 tswtcl_update_stats(ipp_stat_t *sp, void *args, int rw)
580 {
581 tswtcl_data_t *tswtcl_data = (tswtcl_data_t *)args;
582 meter_stat_t *stats = (meter_stat_t *)sp->ipps_data;
583
584 ASSERT((tswtcl_data != NULL) && (stats != NULL));
585
586 (void) ipp_stat_named_op(&stats->red_packets, &tswtcl_data->red_packets,
587 rw);
588 (void) ipp_stat_named_op(&stats->yellow_packets,
589 &tswtcl_data->yellow_packets, rw);
590 (void) ipp_stat_named_op(&stats->green_packets,
591 &tswtcl_data->green_packets, rw);
592
593 (void) ipp_stat_named_op(&stats->red_bits, &tswtcl_data->red_bits, rw);
594 (void) ipp_stat_named_op(&stats->yellow_bits,
595 &tswtcl_data->yellow_bits, rw);
596 (void) ipp_stat_named_op(&stats->green_bits,
597 &tswtcl_data->green_bits, rw);
598
599 (void) ipp_stat_named_op(&stats->epackets, &tswtcl_data->epackets,
600 rw);
601
602 return (0);
603 }
604
605 /* ARGSUSED */
606 static int
607 tswtcl_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
608 ipp_flags_t flags)
609 {
610 nvlist_t *nvlp;
611 tswtcl_data_t *tswtcl_data;
612 tswtcl_cfg_t *cfg_parms;
613 char *next_action;
614 int rc;
615
616 tswtcl_data = (tswtcl_data_t *)ipp_action_get_ptr(aid);
617 ASSERT(tswtcl_data != NULL);
618
619 cfg_parms = tswtcl_data->cfg_parms;
620
621 /* allocate nvlist to be passed back */
622 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
623 tswtcl0dbg(("tswtcl_info: memory allocation failure\n"));
624 return (rc);
625 }
626
627 /* look up red next action with the next action id */
628 if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) {
629 tswtcl0dbg(("tswtcl_info: red action not available\n"));
630 nvlist_free(nvlp);
631 return (rc);
632 }
633
634 /* add next action name */
635 if ((rc = nvlist_add_string(nvlp, TSWTCL_RED_ACTION_NAME,
636 next_action)) != 0) {
637 tswtcl0dbg(("tswtcl_info: error adding\n"));
638 nvlist_free(nvlp);
639 kmem_free(next_action, (strlen(next_action) + 1));
640 return (rc);
641 }
642
643 /* free action name */
644 kmem_free(next_action, (strlen(next_action) + 1));
645
646 /* look up yellow next action with the next action id */
647 if ((rc = ipp_action_name(cfg_parms->yellow_action,
648 &next_action)) != 0) {
649 tswtcl0dbg(("tswtcl_info: yellow action not available\n"));
650 nvlist_free(nvlp);
651 return (rc);
652 }
653
654 /* add next action name */
655 if ((rc = nvlist_add_string(nvlp, TSWTCL_YELLOW_ACTION_NAME,
656 next_action)) != 0) {
657 tswtcl0dbg(("tswtcl_info: error adding yellow action\n"));
658 nvlist_free(nvlp);
659 kmem_free(next_action, (strlen(next_action) + 1));
660 return (rc);
661 }
662 /* free action name */
663 kmem_free(next_action, (strlen(next_action) + 1));
664
665 /* look up green next action with the next action id */
666 if ((rc = ipp_action_name(cfg_parms->green_action,
667 &next_action)) != 0) {
668 tswtcl0dbg(("tswtcl_info: green action not available\n"));
669 nvlist_free(nvlp);
670 return (rc);
671 }
672
673 /* add next action name */
674 if ((rc = nvlist_add_string(nvlp, TSWTCL_GREEN_ACTION_NAME,
675 next_action)) != 0) {
676 tswtcl0dbg(("tswtcl_info: error adding green action\n"));
677 nvlist_free(nvlp);
678 kmem_free(next_action, (strlen(next_action) + 1));
679 return (rc);
680 }
681
682 /* free action name */
683 kmem_free(next_action, (strlen(next_action) + 1));
684
685 /* add config type */
686 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
687 tswtcl0dbg(("tswtcl_info: error adding config_type\n"));
688 nvlist_free(nvlp);
689 return (rc);
690 }
691
692 /* add committed_rate */
693 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_COMMITTED_RATE,
694 cfg_parms->committed_rate)) != 0) {
695 tswtcl0dbg(("tswtcl_info: error adding committed_rate\n"));
696 nvlist_free(nvlp);
697 return (rc);
698 }
699
700 /* add peak_rate */
701 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_PEAK_RATE,
702 cfg_parms->peak_rate)) != 0) {
703 tswtcl0dbg(("tswtcl_info: error adding peak_rate\n"));
704 nvlist_free(nvlp);
705 return (rc);
706 }
707
708 /* add window */
709 if ((rc = nvlist_add_uint32(nvlp, TSWTCL_WINDOW,
710 cfg_parms->window)) != 0) {
711 tswtcl0dbg(("tswtcl_info: error adding window\n"));
712 nvlist_free(nvlp);
713 return (rc);
714 }
715
716 if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
717 (uint32_t)(uintptr_t)tswtcl_data->stats)) != 0) {
718 tswtcl0dbg(("tswtcl_info: error adding stats status\n"));
719 nvlist_free(nvlp);
720 return (rc);
721 }
722
723 /* call back with nvlist */
724 rc = fn(nvlp, arg);
725
726 nvlist_free(nvlp);
727 return (rc);
728 }