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 }