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