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