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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <sys/types.h>
27 #include <sys/atomic.h>
28 #include <sys/systm.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <sys/modctl.h>
32 #include <sys/sunddi.h>
33 #include <ipp/ipp.h>
34 #include <ipp/ipp_config.h>
35 #include <inet/common.h>
36 #include <ipp/meters/meter_impl.h>
37
38 #define D_SM_COMMENT "IPP Single-Two Rate Token Meter"
39
40 /* DDI file for tokenmt ipp module */
41
42 /* Default DSCP to colour mapping for colour-aware meter */
43 enum meter_colour default_dscp_to_colour[64] = {
44 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
45 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
46 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
47 TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
48 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
49 TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
50 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
51 TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
52 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
53 TOKENMT_YELLOW, TOKENMT_GREEN, TOKENMT_RED, TOKENMT_GREEN,
54 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
55 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
56 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
57 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
58 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN,
59 TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN, TOKENMT_GREEN
60 };
61
62 static int tokenmt_create_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
63 static int tokenmt_modify_action(ipp_action_id_t, nvlist_t **, ipp_flags_t);
64 static int tokenmt_destroy_action(ipp_action_id_t, ipp_flags_t);
65 static int tokenmt_info(ipp_action_id_t, int (*)(nvlist_t *, void *), void *,
66 ipp_flags_t);
67 static int tokenmt_invoke_action(ipp_action_id_t, ipp_packet_t *);
68
69 /* Initialize stats */
70 static int tokenmt_statinit(ipp_action_id_t, tokenmt_data_t *);
71
72 /* Stats callback function */
73 static int tokenmt_update_stats(ipp_stat_t *, void *, int);
74
75 ipp_ops_t tokenmt_ops = {
76 IPPO_REV,
77 tokenmt_create_action, /* ippo_action_create */
78 tokenmt_modify_action, /* ippo_action_modify */
79 tokenmt_destroy_action, /* ippo_action_destroy */
80 tokenmt_info, /* ippo_action_info */
81 tokenmt_invoke_action /* ippo_action_invoke */
82 };
83
84 extern struct mod_ops mod_ippops;
85
86 /*
87 * Module linkage information for the kernel.
88 */
89 static struct modlipp modlipp = {
90 &mod_ippops,
91 D_SM_COMMENT,
92 &tokenmt_ops
93 };
94
95 static struct modlinkage modlinkage = {
96 MODREV_1,
97 { (void *)&modlipp, NULL }
98 };
99
100
101 int
102 _init(void)
103 {
104 return (mod_install(&modlinkage));
105 }
106
107 int
108 _fini(void)
109 {
110 return (mod_remove(&modlinkage));
111 }
112
113 int
114 _info(struct modinfo *modinfop)
115 {
116 return (mod_info(&modlinkage, modinfop));
117 }
118
119 /* ARGSUSED */
120 static int
121 tokenmt_create_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
122 {
123 nvlist_t *nvlp;
124 tokenmt_data_t *tokenmt_data;
125 char *next_action;
126 tokenmt_cfg_t *cfg_parms;
127 uint32_t mode;
128 uint32_t bstats;
129 int rc, rc2;
130 int32_t *colour_tbl;
131 uint_t nelem = 64;
132
133 nvlp = *nvlpp;
134 *nvlpp = NULL; /* nvlist should be NULL on return */
135
136 if ((cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP)) == NULL) {
137 nvlist_free(nvlp);
138 return (ENOMEM);
139 }
140
141 /* parse red next action name */
142 if ((rc = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME,
143 &next_action)) != 0) {
144 nvlist_free(nvlp);
145 tokenmt0dbg(("tokenmt_create_action:invalid config, red "\
146 "action name missing\n"));
147 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
148 return (rc);
149 }
150 if ((cfg_parms->red_action = ipp_action_lookup(next_action))
151 == IPP_ACTION_INVAL) {
152 nvlist_free(nvlp);
153 tokenmt0dbg(("tokenmt_create_action: red action invalid\n"));
154 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
155 return (EINVAL);
156 }
157
158 /* parse yellow next action name, if present this is Two Rate meter */
159 if ((rc = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
160 &next_action)) == 0) {
161 if ((cfg_parms->yellow_action = ipp_action_lookup(next_action))
162 == IPP_ACTION_INVAL) {
163 nvlist_free(nvlp);
164 tokenmt0dbg(("tokenmt_create_action: yellow action "\
165 "invalid\n"));
166 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
167 return (EINVAL);
168 }
169 } else {
170 cfg_parms->yellow_action = TOKENMT_NO_ACTION;
171 }
172
173 /* parse green next action name */
174 if ((rc = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
175 &next_action)) != 0) {
176 nvlist_free(nvlp);
177 tokenmt0dbg(("tokenmt_create_action:invalid config, green " \
178 "action name missing\n"));
179 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
180 return (rc);
181 }
182 if ((cfg_parms->green_action = ipp_action_lookup(next_action))
183 == IPP_ACTION_INVAL) {
184 nvlist_free(nvlp);
185 tokenmt0dbg(("tokenmt_create_action: green action invalid\n"));
186 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
187 return (EINVAL);
188 }
189
190 /* parse committed rate - in kilo bits / sec */
191 if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE,
192 &cfg_parms->committed_rate)) != 0) {
193 nvlist_free(nvlp);
194 tokenmt0dbg(("tokenmt_create_action: invalid config, "\
195 " committed rate missing\n"));
196 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
197 return (rc);
198 }
199 if (cfg_parms->committed_rate == 0) {
200 nvlist_free(nvlp);
201 tokenmt0dbg(("tokenmt_create_action: invalid committed rate, "\
202 "%u\n", cfg_parms->committed_rate));
203 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
204 return (EINVAL);
205 }
206
207 /* parse committed burst in bits */
208 if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST,
209 &cfg_parms->committed_burst)) != 0) {
210 nvlist_free(nvlp);
211 tokenmt0dbg(("tokenmt_create_action: invalid config, "\
212 " committed burst missing\n"));
213 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
214 return (rc);
215 }
216
217
218 /*
219 * If the peak burst size is specified, make sure we have the
220 * yellow action.
221 */
222 if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST,
223 &cfg_parms->peak_burst)) == 0) {
224 if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
225 nvlist_free(nvlp);
226 tokenmt0dbg(("tokenmt_create_action: peak burst "\
227 "specified without yellow action\n"));
228 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
229 return (EINVAL);
230 }
231 } else if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
232 nvlist_free(nvlp);
233 tokenmt0dbg(("tokenmt_create_action: peak burst must be "\
234 "provided with yellow action\n"));
235 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
236 return (EINVAL);
237 }
238
239 /* Check if we have a peak_rate */
240 if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE,
241 &cfg_parms->peak_rate)) == 0) {
242 if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
243 nvlist_free(nvlp);
244 tokenmt0dbg(("tokenmt_create_action: peak rate "\
245 "specified without yellow action\n"));
246 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
247 return (EINVAL);
248 } else if ((cfg_parms->peak_rate == 0) ||
249 (cfg_parms->peak_rate < cfg_parms->committed_rate)) {
250 nvlist_free(nvlp);
251 tokenmt0dbg(("tokenmt_create_action: invalid "\
252 "peak rate, %u\n", cfg_parms->peak_rate));
253 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
254 return (EINVAL);
255 }
256 cfg_parms->tokenmt_type = TRTCL_TOKENMT;
257 } else {
258 cfg_parms->tokenmt_type = SRTCL_TOKENMT;
259 }
260
261 /* Validate the committed and peak burst size */
262 if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) {
263 if ((cfg_parms->committed_burst == 0) &&
264 (cfg_parms->peak_burst == 0)) {
265 nvlist_free(nvlp);
266 tokenmt0dbg(("tokenmt_create_action: at least one "\
267 "burst size must be non-zero\n"));
268 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
269 return (EINVAL);
270 }
271 } else { /* TRTCL_TOKENMT */
272 if ((cfg_parms->committed_burst == 0) ||
273 (cfg_parms->peak_burst == 0)) {
274 nvlist_free(nvlp);
275 tokenmt0dbg(("tokenmt_create_action: both the "\
276 "burst sizes must be non-zero\n"));
277 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
278 return (EINVAL);
279 }
280 }
281
282 /* just copy default colour mapping */
283 bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour,
284 sizeof (default_dscp_to_colour));
285
286 /* parse mode, if present */
287 if ((rc = nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE,
288 &mode)) != 0) {
289 cfg_parms->colour_aware = B_FALSE;
290 } else {
291 cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE;
292 }
293
294 /* Get the dscp to colour mapping array */
295 if (cfg_parms->colour_aware) {
296 if ((rc = nvlist_lookup_int32_array(nvlp,
297 TOKENMT_COLOUR_MAP, &colour_tbl, &nelem)) == 0) {
298 int count;
299 for (count = 0; count < 64; count++) {
300 if (colour_tbl[count] == -1)
301 continue;
302 cfg_parms->dscp_to_colour[count] =
303 colour_tbl[count];
304 }
305 }
306 }
307
308 /* parse stats */
309 if ((rc = nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats))
310 != 0) {
311 cfg_parms->stats = B_FALSE;
312 } else {
313 cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE;
314 }
315
316 nvlist_free(nvlp);
317
318 /* Initialize other stuff */
319 tokenmt_data = kmem_zalloc(TOKENMT_DATA_SZ, KM_NOSLEEP);
320 if (tokenmt_data == NULL) {
321 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
322 return (ENOMEM);
323 }
324
325 /* Initialize stats, if required */
326 if (cfg_parms->stats) {
327 if ((rc = tokenmt_statinit(aid, tokenmt_data)) != 0) {
328 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
329 kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
330 return (rc);
331 }
332 }
333
334 /* set action chain reference */
335 if ((rc = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
336 tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \
337 "returned with error %d", rc));
338 goto cleanup;
339 }
340 if ((rc = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
341 tokenmt0dbg(("tokenmt_create_action: ipp_action_ref " \
342 "returned with error %d", rc));
343 rc2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
344 ASSERT(rc2 == 0);
345 goto cleanup;
346 }
347
348 if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
349 if ((rc = ipp_action_ref(aid, cfg_parms->yellow_action,
350 flags)) != 0) {
351 tokenmt0dbg(("tokenmt_create_action: ipp_action_ref "\
352 "returned with error %d", rc));
353 rc2 = ipp_action_unref(aid, cfg_parms->red_action,
354 flags);
355 ASSERT(rc2 == 0);
356 rc2 = ipp_action_unref(aid, cfg_parms->green_action,
357 flags);
358 ASSERT(rc2 == 0);
359 goto cleanup;
360 }
361 }
362
363
364 tokenmt_data->cfg_parms = cfg_parms;
365
366 tokenmt_data->committed_tokens = cfg_parms->committed_burst;
367 tokenmt_data->peak_tokens = cfg_parms->peak_burst;
368 tokenmt_data->last_seen = gethrtime();
369
370 mutex_init(&tokenmt_data->tokenmt_lock, NULL, MUTEX_DEFAULT, 0);
371 ipp_action_set_ptr(aid, (void *)tokenmt_data);
372 return (0);
373
374 cleanup:
375 if (cfg_parms->stats) {
376 ipp_stat_destroy(tokenmt_data->stats);
377 }
378 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
379 kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
380 return (rc);
381 }
382
383 static int
384 tokenmt_modify_action(ipp_action_id_t aid, nvlist_t **nvlpp, ipp_flags_t flags)
385 {
386 nvlist_t *nvlp;
387 int err = 0, err2;
388 uint8_t config_type;
389 char *next_action_name;
390 ipp_action_id_t next_action;
391 uint32_t rate, cbs, pbs;
392 tokenmt_cfg_t *cfg_parms, *old_cfg;
393 tokenmt_data_t *tokenmt_data;
394 uint32_t bstats, mode;
395 int32_t *colour_tbl;
396 uint_t nelem = 64;
397
398 nvlp = *nvlpp;
399 *nvlpp = NULL; /* nvlist should be NULL when this returns */
400
401 if ((err = nvlist_lookup_byte(nvlp, IPP_CONFIG_TYPE, &config_type))
402 != 0) {
403 nvlist_free(nvlp);
404 tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\
405 "type"));
406 return (err);
407 }
408
409 if (config_type != IPP_SET) {
410 nvlist_free(nvlp);
411 tokenmt0dbg(("tokenmt_modify_action: invalid configuration "\
412 "type %d", config_type));
413 return (EINVAL);
414 }
415
416 tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
417 old_cfg = tokenmt_data->cfg_parms;
418
419 cfg_parms = kmem_zalloc(TOKENMT_CFG_SZ, KM_NOSLEEP);
420 if (cfg_parms == NULL) {
421 nvlist_free(nvlp);
422 tokenmt0dbg(("tokenmt_modify_action: memory allocation "\
423 "failure\n"));
424 return (ENOMEM);
425 }
426
427 /* Just copy all and change as needed */
428 bcopy(old_cfg, cfg_parms, TOKENMT_CFG_SZ);
429
430 /* parse red action name, if present */
431 if ((err = nvlist_lookup_string(nvlp, TOKENMT_RED_ACTION_NAME,
432 &next_action_name)) == 0) {
433 /* Get action id */
434 if ((next_action = ipp_action_lookup(next_action_name))
435 == IPP_ACTION_INVAL) {
436 nvlist_free(nvlp);
437 tokenmt0dbg(("tokenmt_modify_action: next_action "\
438 "invalid"));
439 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
440 return (EINVAL);
441 }
442 cfg_parms->red_action = next_action;
443 }
444
445 /* parse yellow action name, if present */
446 if ((err = nvlist_lookup_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
447 &next_action_name)) == 0) {
448 /* Get action id */
449 if ((next_action = ipp_action_lookup(next_action_name))
450 == IPP_ACTION_INVAL) {
451 nvlist_free(nvlp);
452 tokenmt0dbg(("tokenmt_modify_action: next_action "\
453 "invalid"));
454 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
455 return (EINVAL);
456 }
457 cfg_parms->yellow_action = next_action;
458 } else {
459 cfg_parms->yellow_action = TOKENMT_NO_ACTION;
460 }
461
462 /* parse green action name, if present */
463 if ((err = nvlist_lookup_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
464 &next_action_name)) == 0) {
465 /* Get action id */
466 if ((next_action = ipp_action_lookup(next_action_name))
467 == IPP_ACTION_INVAL) {
468 nvlist_free(nvlp);
469 tokenmt0dbg(("tokenmt_modify_action: next_action "\
470 "invalid"));
471 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
472 return (EINVAL);
473 }
474 cfg_parms->green_action = next_action;
475 }
476
477 /* parse committed rate, if present */
478 if ((err = nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_RATE, &rate))
479 == 0) {
480 if (rate == 0) {
481 nvlist_free(nvlp);
482 tokenmt0dbg(("tokenmt_modify_action: invalid "\
483 "committed rate %u\n", cfg_parms->committed_rate));
484 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
485 return (EINVAL);
486 }
487 cfg_parms->committed_rate = rate;
488 }
489
490 /* parse committed burst, if present */
491 if (nvlist_lookup_uint32(nvlp, TOKENMT_COMMITTED_BURST, &cbs) == 0) {
492 cfg_parms->committed_burst = cbs;
493 }
494
495
496 if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_BURST, &pbs) == 0) {
497 cfg_parms->peak_burst = pbs;
498 } else {
499 cfg_parms->peak_burst = 0;
500 }
501
502 /* If the peak rate is not specified, then it means single rate meter */
503 if (nvlist_lookup_uint32(nvlp, TOKENMT_PEAK_RATE, &rate) == 0) {
504 cfg_parms->peak_rate = rate;
505 if ((rate == 0) || (rate < cfg_parms->committed_rate)) {
506 nvlist_free(nvlp);
507 tokenmt0dbg(("tokenmt_modify_action: invalid "\
508 "committed rate %u\n", cfg_parms->committed_rate));
509 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
510 return (EINVAL);
511 }
512 cfg_parms->tokenmt_type = TRTCL_TOKENMT;
513 } else {
514 cfg_parms->peak_rate = 0;
515 cfg_parms->tokenmt_type = SRTCL_TOKENMT;
516 }
517
518 if (cfg_parms->yellow_action == TOKENMT_NO_ACTION) {
519 if ((cfg_parms->peak_burst != 0) ||
520 (cfg_parms->tokenmt_type == TRTCL_TOKENMT)) {
521 nvlist_free(nvlp);
522 tokenmt0dbg(("tokenmt_modify_action: yellow action "\
523 "missing\n"));
524 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
525 return (EINVAL);
526 }
527 } else {
528 if ((cfg_parms->tokenmt_type != TRTCL_TOKENMT) &&
529 (cfg_parms->peak_burst == 0)) {
530 nvlist_free(nvlp);
531 tokenmt0dbg(("tokenmt_modify_action: peak "\
532 "burst/rate missing\n"));
533 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
534 return (EINVAL);
535 }
536 }
537
538 /* Validate the committed and peak burst size */
539 if (cfg_parms->tokenmt_type == SRTCL_TOKENMT) {
540 if ((cfg_parms->committed_burst == 0) &&
541 (cfg_parms->peak_burst == 0)) {
542 nvlist_free(nvlp);
543 tokenmt0dbg(("tokenmt_modify_action: at least one "\
544 "burst size must be non-zero\n"));
545 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
546 return (EINVAL);
547 }
548 } else { /* TRTCL_TOKENMT */
549 if ((cfg_parms->committed_burst == 0) ||
550 (cfg_parms->peak_burst == 0)) {
551 nvlist_free(nvlp);
552 tokenmt0dbg(("tokenmt_modify_action: both the "\
553 "burst sizes must be non-zero\n"));
554 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
555 return (EINVAL);
556 }
557 }
558
559 /* parse mode */
560 if (nvlist_lookup_uint32(nvlp, TOKENMT_COLOUR_AWARE, &mode) == 0) {
561 cfg_parms->colour_aware = (mode == 0) ? B_FALSE : B_TRUE;
562 } else {
563 cfg_parms->colour_aware = B_FALSE;
564 }
565
566 if (cfg_parms->colour_aware) {
567 if (nvlist_lookup_int32_array(nvlp, TOKENMT_COLOUR_MAP,
568 &colour_tbl, &nelem) == 0) {
569 int count;
570 for (count = 0; count < 64; count++) {
571 if (colour_tbl[count] == -1)
572 continue;
573 cfg_parms->dscp_to_colour[count] =
574 colour_tbl[count];
575 }
576 } else {
577 bcopy(default_dscp_to_colour, cfg_parms->dscp_to_colour,
578 sizeof (default_dscp_to_colour));
579 }
580 }
581
582 /* parse stats, if present */
583 if (nvlist_lookup_uint32(nvlp, IPP_ACTION_STATS_ENABLE, &bstats) == 0) {
584 cfg_parms->stats = (bstats == 0) ? B_FALSE : B_TRUE;
585 if (cfg_parms->stats && !old_cfg->stats) {
586 if ((err = tokenmt_statinit(aid, tokenmt_data)) != 0) {
587 nvlist_free(nvlp);
588 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
589 return (err);
590 }
591 } else if (!cfg_parms->stats && old_cfg->stats) {
592 ipp_stat_destroy(tokenmt_data->stats);
593 }
594 }
595
596 /* Can we ref all the new actions? */
597 if ((err = ipp_action_ref(aid, cfg_parms->red_action, flags)) != 0) {
598 tokenmt0dbg(("tokenmt_modify_data: can't ref. red action\n"));
599 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
600 return (err);
601 }
602 if ((err = ipp_action_ref(aid, cfg_parms->green_action, flags)) != 0) {
603 tokenmt0dbg(("tokenmt_modify_data:can't ref. green action\n"));
604 err2 = ipp_action_unref(aid, cfg_parms->red_action, flags);
605 ASSERT(err2 == 0);
606 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
607 return (err);
608 }
609
610 if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
611 if ((err = ipp_action_ref(aid, cfg_parms->yellow_action,
612 flags)) != 0) {
613 tokenmt0dbg(("tokenmt_modify_data:can't ref. yellow "\
614 "action\n"));
615 err2 = ipp_action_unref(aid, cfg_parms->red_action,
616 flags);
617 ASSERT(err2 == 0);
618 err2 = ipp_action_unref(aid, cfg_parms->green_action,
619 flags);
620 ASSERT(err2 == 0);
621 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
622 return (err);
623 }
624 }
625
626
627 /* Actually modify the configuration */
628 mutex_enter(&tokenmt_data->tokenmt_lock);
629 tokenmt_data->cfg_parms = cfg_parms;
630 mutex_exit(&tokenmt_data->tokenmt_lock);
631
632 /* Un-ref the old actions */
633 err = ipp_action_unref(aid, old_cfg->red_action, flags);
634 ASSERT(err == 0);
635 if (old_cfg->yellow_action != TOKENMT_NO_ACTION) {
636 err = ipp_action_unref(aid, old_cfg->yellow_action, flags);
637 ASSERT(err == 0);
638 }
639 err = ipp_action_unref(aid, old_cfg->green_action, flags);
640 ASSERT(err == 0);
641
642 /* Free the old configuration */
643 kmem_free(old_cfg, TOKENMT_CFG_SZ);
644 return (0);
645 }
646
647 static int
648 tokenmt_destroy_action(ipp_action_id_t aid, ipp_flags_t flags)
649 {
650 tokenmt_data_t *tokenmt_data;
651 tokenmt_cfg_t *cfg_parms;
652 int rc;
653
654 tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
655 ASSERT(tokenmt_data != NULL);
656
657 cfg_parms = tokenmt_data->cfg_parms;
658
659 if (cfg_parms->stats) {
660 ipp_stat_destroy(tokenmt_data->stats);
661 }
662
663 /* unreference the action */
664 rc = ipp_action_unref(aid, cfg_parms->red_action, flags);
665 ASSERT(rc == 0);
666 if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
667 rc = ipp_action_unref(aid, cfg_parms->yellow_action, flags);
668 ASSERT(rc == 0);
669 }
670 rc = ipp_action_unref(aid, cfg_parms->green_action, flags);
671 ASSERT(rc == 0);
672
673 mutex_destroy(&tokenmt_data->tokenmt_lock);
674 kmem_free(cfg_parms, TOKENMT_CFG_SZ);
675 kmem_free(tokenmt_data, TOKENMT_DATA_SZ);
676 return (0);
677 }
678
679 static int
680 tokenmt_invoke_action(ipp_action_id_t aid, ipp_packet_t *packet)
681 {
682 tokenmt_data_t *tokenmt_data;
683 ipp_action_id_t next_action;
684 mblk_t *mp = NULL;
685 int rc;
686
687 /* get mblk from ipp_packet structure */
688 mp = ipp_packet_get_data(packet);
689 tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
690 ASSERT(tokenmt_data != NULL);
691
692 /* meter packet as configured */
693 if ((rc = tokenmt_process(&mp, tokenmt_data, &next_action)) != 0) {
694 return (rc);
695 } else {
696 return (ipp_packet_next(packet, next_action));
697 }
698 }
699
700 static int
701 tokenmt_statinit(ipp_action_id_t aid, tokenmt_data_t *tokenmt_data) {
702
703 int rc = 0;
704 meter_stat_t *statsp;
705
706 /* install stats entry */
707 if ((rc = ipp_stat_create(aid, TOKENMT_STATS_STRING, METER_STATS_COUNT,
708 tokenmt_update_stats, tokenmt_data, &tokenmt_data->stats)) != 0) {
709 tokenmt0dbg(("tokenmt_statinit: ipp_stat_create failed "\
710 " with %d\n", rc));
711 return (rc);
712 }
713
714 statsp = (meter_stat_t *)(tokenmt_data->stats)->ipps_data;
715 ASSERT(statsp != NULL);
716
717 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "red_packets",
718 IPP_STAT_UINT64, &statsp->red_packets)) != 0) {
719 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
720 " with %d\n", rc));
721 return (rc);
722 }
723 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "yellow_packets",
724 IPP_STAT_UINT64, &statsp->yellow_packets)) != 0) {
725 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
726 " with %d\n", rc));
727 return (rc);
728 }
729 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "green_packets",
730 IPP_STAT_UINT64, &statsp->green_packets)) != 0) {
731 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
732 " with %d\n", rc));
733 return (rc);
734 }
735 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "red_bits",
736 IPP_STAT_UINT64, &statsp->red_bits)) != 0) {
737 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
738 " with %d\n", rc));
739 return (rc);
740 }
741 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "yellow_bits",
742 IPP_STAT_UINT64, &statsp->yellow_bits)) != 0) {
743 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
744 " with %d\n", rc));
745 return (rc);
746 }
747 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "green_bits",
748 IPP_STAT_UINT64, &statsp->green_bits)) != 0) {
749 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
750 " with %d\n", rc));
751 return (rc);
752 }
753 if ((rc = ipp_stat_named_init(tokenmt_data->stats, "epackets",
754 IPP_STAT_UINT64, &statsp->epackets)) != 0) {
755 tokenmt0dbg(("tokenmt_statinit:ipp_stat_named_init failed "\
756 " with %d\n", rc));
757 return (rc);
758 }
759
760 ipp_stat_install(tokenmt_data->stats);
761
762 return (rc);
763 }
764
765 static int
766 tokenmt_update_stats(ipp_stat_t *sp, void *args, int rw)
767 {
768 tokenmt_data_t *tokenmt_data = (tokenmt_data_t *)args;
769 meter_stat_t *stats = (meter_stat_t *)sp->ipps_data;
770
771 ASSERT((tokenmt_data != NULL) && (stats != NULL));
772
773 (void) ipp_stat_named_op(&stats->red_packets,
774 &tokenmt_data->red_packets, rw);
775 (void) ipp_stat_named_op(&stats->yellow_packets,
776 &tokenmt_data->yellow_packets, rw);
777 (void) ipp_stat_named_op(&stats->green_packets,
778 &tokenmt_data->green_packets, rw);
779 (void) ipp_stat_named_op(&stats->red_bits,
780 &tokenmt_data->red_bits, rw);
781 (void) ipp_stat_named_op(&stats->yellow_bits,
782 &tokenmt_data->yellow_bits, rw);
783 (void) ipp_stat_named_op(&stats->green_bits,
784 &tokenmt_data->green_bits, rw);
785 (void) ipp_stat_named_op(&stats->epackets, &tokenmt_data->epackets,
786 rw);
787
788 return (0);
789 }
790
791 /* ARGSUSED */
792 static int
793 tokenmt_info(ipp_action_id_t aid, int (*fn)(nvlist_t *, void *), void *arg,
794 ipp_flags_t flags)
795 {
796 nvlist_t *nvlp;
797 tokenmt_data_t *tokenmt_data;
798 tokenmt_cfg_t *cfg_parms;
799 char *next_action;
800 int32_t dscp_to_colour[64];
801 int rc;
802
803 tokenmt_data = (tokenmt_data_t *)ipp_action_get_ptr(aid);
804 ASSERT(tokenmt_data != NULL);
805
806 cfg_parms = tokenmt_data->cfg_parms;
807
808 /* allocate nvlist to be passed back */
809 if ((rc = nvlist_alloc(&nvlp, NV_UNIQUE_NAME, KM_NOSLEEP)) != 0) {
810 tokenmt0dbg(("tokenmt_info: memory allocation failure\n"));
811 return (rc);
812 }
813
814 /* look up red next action with the next action id */
815 if ((rc = ipp_action_name(cfg_parms->red_action, &next_action)) != 0) {
816 tokenmt0dbg(("tokenmt_info: red_action not available\n"));
817 nvlist_free(nvlp);
818 return (rc);
819 }
820
821 /* add next action name */
822 if ((rc = nvlist_add_string(nvlp, TOKENMT_RED_ACTION_NAME,
823 next_action)) != 0) {
824 nvlist_free(nvlp);
825 tokenmt0dbg(("tokenmt_info: error adding red_action\n"));
826 kmem_free(next_action, (strlen(next_action) + 1));
827 return (rc);
828 }
829
830 /* free action name */
831 kmem_free(next_action, (strlen(next_action) + 1));
832
833
834 /* look up yellow next action with the next action id */
835 if (cfg_parms->yellow_action != TOKENMT_NO_ACTION) {
836 if ((rc = ipp_action_name(cfg_parms->yellow_action,
837 &next_action)) != 0) {
838 tokenmt0dbg(("tokenmt_info: yellow_action not "\
839 "available\n"));
840 nvlist_free(nvlp);
841 return (rc);
842 }
843 /* add next action name */
844 if ((rc = nvlist_add_string(nvlp, TOKENMT_YELLOW_ACTION_NAME,
845 next_action)) != 0) {
846 nvlist_free(nvlp);
847 tokenmt0dbg(("tokenmt_info: error adding "\
848 "yellow_action\n"));
849 kmem_free(next_action, (strlen(next_action) + 1));
850 return (rc);
851 }
852 /* free action name */
853 kmem_free(next_action, (strlen(next_action) + 1));
854 }
855
856 /* look up green next action with the next action id */
857 if ((rc = ipp_action_name(cfg_parms->green_action,
858 &next_action)) != 0) {
859 tokenmt0dbg(("tokenmt_info: green_action not available\n"));
860 nvlist_free(nvlp);
861 return (rc);
862 }
863
864 /* add next action name */
865 if ((rc = nvlist_add_string(nvlp, TOKENMT_GREEN_ACTION_NAME,
866 next_action)) != 0) {
867 nvlist_free(nvlp);
868 tokenmt0dbg(("tokenmt_info: error adding green_action\n"));
869 kmem_free(next_action, (strlen(next_action) + 1));
870 return (rc);
871 }
872
873 /* free action name */
874 kmem_free(next_action, (strlen(next_action) + 1));
875
876 /* add config type */
877 if ((rc = nvlist_add_byte(nvlp, IPP_CONFIG_TYPE, IPP_SET)) != 0) {
878 tokenmt0dbg(("tokenmt_info: error adding config_type\n"));
879 nvlist_free(nvlp);
880 return (rc);
881 }
882
883 /* add committed_rate */
884 if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COMMITTED_RATE,
885 cfg_parms->committed_rate)) != 0) {
886 tokenmt0dbg(("tokenmt_info: error adding committed_rate\n"));
887 nvlist_free(nvlp);
888 return (rc);
889 }
890
891 if (cfg_parms->tokenmt_type == TRTCL_TOKENMT) {
892 /* add peak rate */
893 if ((rc = nvlist_add_uint32(nvlp, TOKENMT_PEAK_RATE,
894 cfg_parms->peak_rate)) != 0) {
895 tokenmt0dbg(("tokenmt_info: error adding peak_rate\n"));
896 nvlist_free(nvlp);
897 return (rc);
898 }
899 }
900
901 /* add committed_burst */
902 if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COMMITTED_BURST,
903 cfg_parms->committed_burst)) != 0) {
904 tokenmt0dbg(("tokenmt_info: error adding committed_burst\n"));
905 nvlist_free(nvlp);
906 return (rc);
907 }
908
909 /* add peak_burst */
910 if (cfg_parms->peak_burst != 0) {
911 if ((rc = nvlist_add_uint32(nvlp, TOKENMT_PEAK_BURST,
912 cfg_parms->peak_burst)) != 0) {
913 tokenmt0dbg(("tokenmt_info: error adding peak "\
914 "burst\n"));
915 nvlist_free(nvlp);
916 return (rc);
917 }
918 }
919
920 /* add colour aware */
921 if ((rc = nvlist_add_uint32(nvlp, TOKENMT_COLOUR_AWARE,
922 cfg_parms->colour_aware)) != 0) {
923 tokenmt0dbg(("tokenmt_info: error adding mode\n"));
924 nvlist_free(nvlp);
925 return (rc);
926 }
927
928 if (cfg_parms->colour_aware) {
929 bcopy(cfg_parms->dscp_to_colour, dscp_to_colour,
930 sizeof (cfg_parms->dscp_to_colour));
931 if ((rc = nvlist_add_int32_array(nvlp, TOKENMT_COLOUR_MAP,
932 dscp_to_colour, 64)) != 0) {
933 tokenmt0dbg(("tokenmt_info: error adding colour "\
934 "array\n"));
935 nvlist_free(nvlp);
936 return (rc);
937 }
938 }
939
940 if ((rc = nvlist_add_uint32(nvlp, IPP_ACTION_STATS_ENABLE,
941 (uint32_t)cfg_parms->stats)) != 0) {
942 tokenmt0dbg(("tokenmt_info: error adding stats status\n"));
943 nvlist_free(nvlp);
944 return (rc);
945 }
946
947 /* call back with nvlist */
948 rc = fn(nvlp, arg);
949
950 nvlist_free(nvlp);
951 return (rc);
952 }