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 103 _init(void) 104 { 105 return (mod_install(&modlinkage)); 106 } 107 108 int 109 _fini(void) 110 { 111 return (mod_remove(&modlinkage)); 112 } 113 114 int 115 _info(struct modinfo *modinfop) 116 { 117 return (mod_info(&modlinkage, modinfop)); 118 } 119 120 /* ARGSUSED */ 121 static int 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 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 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 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 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 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 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