1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <ctype.h> 38 #include <rte_string_fns.h> 39 #include <rte_sched.h> 40 41 #include "cfg_file.h" 42 #include "main.h" 43 44 45 /** when we resize a file structure, how many extra entries 46 * for new sections do we add in */ 47 #define CFG_ALLOC_SECTION_BATCH 8 48 /** when we resize a section structure, how many extra entries 49 * for new entries do we add in */ 50 #define CFG_ALLOC_ENTRY_BATCH 16 51 52 static unsigned 53 _strip(char *str, unsigned len) 54 { 55 int newlen = len; 56 if (len == 0) 57 return 0; 58 59 if (isspace(str[len-1])) { 60 /* strip trailing whitespace */ 61 while (newlen > 0 && isspace(str[newlen - 1])) 62 str[--newlen] = '\0'; 63 } 64 65 if (isspace(str[0])) { 66 /* strip leading whitespace */ 67 int i,start = 1; 68 while (isspace(str[start]) && start < newlen) 69 start++ 70 ; /* do nothing */ 71 newlen -= start; 72 for (i = 0; i < newlen; i++) 73 str[i] = str[i+start]; 74 str[i] = '\0'; 75 } 76 return newlen; 77 } 78 79 struct cfg_file * 80 cfg_load(const char *filename, int flags) 81 { 82 int allocated_sections = CFG_ALLOC_SECTION_BATCH; 83 int allocated_entries = 0; 84 int curr_section = -1; 85 int curr_entry = -1; 86 char buffer[256]; 87 int lineno = 0; 88 struct cfg_file *cfg = NULL; 89 90 FILE *f = fopen(filename, "r"); 91 if (f == NULL) 92 return NULL; 93 94 cfg = malloc(sizeof(*cfg) + sizeof(cfg->sections[0]) * allocated_sections); 95 if (cfg == NULL) 96 goto error2; 97 98 memset(cfg->sections, 0, sizeof(cfg->sections[0]) * allocated_sections); 99 100 while (fgets(buffer, sizeof(buffer), f) != NULL) { 101 char *pos = NULL; 102 size_t len = strnlen(buffer, sizeof(buffer)); 103 lineno++; 104 if (len >=sizeof(buffer) - 1 && buffer[len-1] != '\n'){ 105 printf("Error line %d - no \\n found on string. " 106 "Check if line too long\n", lineno); 107 goto error1; 108 } 109 if ((pos = memchr(buffer, ';', sizeof(buffer))) != NULL) { 110 *pos = '\0'; 111 len = pos - buffer; 112 } 113 114 len = _strip(buffer, len); 115 if (buffer[0] != '[' && memchr(buffer, '=', len) == NULL) 116 continue; 117 118 if (buffer[0] == '[') { 119 /* section heading line */ 120 char *end = memchr(buffer, ']', len); 121 if (end == NULL) { 122 printf("Error line %d - no terminating '[' found\n", lineno); 123 goto error1; 124 } 125 *end = '\0'; 126 _strip(&buffer[1], end - &buffer[1]); 127 128 /* close off old section and add start new one */ 129 if (curr_section >= 0) 130 cfg->sections[curr_section]->num_entries = curr_entry + 1; 131 curr_section++; 132 133 /* resize overall struct if we don't have room for more sections */ 134 if (curr_section == allocated_sections) { 135 allocated_sections += CFG_ALLOC_SECTION_BATCH; 136 struct cfg_file *n_cfg = realloc(cfg, sizeof(*cfg) + 137 sizeof(cfg->sections[0]) * allocated_sections); 138 if (n_cfg == NULL) { 139 printf("Error - no more memory\n"); 140 goto error1; 141 } 142 cfg = n_cfg; 143 } 144 145 /* allocate space for new section */ 146 allocated_entries = CFG_ALLOC_ENTRY_BATCH; 147 curr_entry = -1; 148 cfg->sections[curr_section] = malloc(sizeof(*cfg->sections[0]) + 149 sizeof(cfg->sections[0]->entries[0]) * allocated_entries); 150 if (cfg->sections[curr_section] == NULL) { 151 printf("Error - no more memory\n"); 152 goto error1; 153 } 154 155 rte_snprintf(cfg->sections[curr_section]->name, 156 sizeof(cfg->sections[0]->name), 157 "%s", &buffer[1]); 158 } 159 else { 160 /* value line */ 161 if (curr_section < 0) { 162 printf("Error line %d - value outside of section\n", lineno); 163 goto error1; 164 } 165 166 struct cfg_section *sect = cfg->sections[curr_section]; 167 char *split[2]; 168 if (rte_strsplit(buffer, sizeof(buffer), split, 2, '=') != 2) { 169 printf("Error at line %d - cannot split string\n", lineno); 170 goto error1; 171 } 172 173 curr_entry++; 174 if (curr_entry == allocated_entries) { 175 allocated_entries += CFG_ALLOC_ENTRY_BATCH; 176 struct cfg_section *n_sect = realloc(sect, sizeof(*sect) + 177 sizeof(sect->entries[0]) * allocated_entries); 178 if (n_sect == NULL) { 179 printf("Error - no more memory\n"); 180 goto error1; 181 } 182 sect = cfg->sections[curr_section] = n_sect; 183 } 184 185 sect->entries[curr_entry] = malloc(sizeof(*sect->entries[0])); 186 if (sect->entries[curr_entry] == NULL) { 187 printf("Error - no more memory\n"); 188 goto error1; 189 } 190 191 struct cfg_entry *entry = sect->entries[curr_entry]; 192 rte_snprintf(entry->name, sizeof(entry->name), "%s", split[0]); 193 rte_snprintf(entry->value, sizeof(entry->value), "%s", split[1]); 194 _strip(entry->name, strnlen(entry->name, sizeof(entry->name))); 195 _strip(entry->value, strnlen(entry->value, sizeof(entry->value))); 196 } 197 } 198 fclose(f); 199 cfg->flags = flags; 200 cfg->sections[curr_section]->num_entries = curr_entry + 1; 201 cfg->num_sections = curr_section + 1; 202 return cfg; 203 204 error1: 205 cfg_close(cfg); 206 error2: 207 fclose(f); 208 return NULL; 209 } 210 211 212 int cfg_close(struct cfg_file *cfg) 213 { 214 int i, j; 215 216 if (cfg == NULL) 217 return -1; 218 219 for(i = 0; i < cfg->num_sections; i++) { 220 if (cfg->sections[i] != NULL) { 221 if (cfg->sections[i]->num_entries) { 222 for(j = 0; j < cfg->sections[i]->num_entries; j++) { 223 if (cfg->sections[i]->entries[j] != NULL) 224 free(cfg->sections[i]->entries[j]); 225 } 226 } 227 free(cfg->sections[i]); 228 } 229 } 230 free(cfg); 231 232 return 0; 233 } 234 235 int 236 cfg_num_sections(struct cfg_file *cfg, const char *sectionname, size_t length) 237 { 238 int i; 239 int num_sections = 0; 240 for (i = 0; i < cfg->num_sections; i++) { 241 if (strncmp(cfg->sections[i]->name, sectionname, length) == 0) 242 num_sections++; 243 } 244 return num_sections; 245 } 246 247 int 248 cfg_sections(struct cfg_file *cfg, char *sections[], int max_sections) 249 { 250 int i; 251 for (i = 0; i < cfg->num_sections && i < max_sections; i++) { 252 rte_snprintf(sections[i], CFG_NAME_LEN, "%s", cfg->sections[i]->name); 253 } 254 return i; 255 } 256 257 static const struct cfg_section * 258 _get_section(struct cfg_file *cfg, const char *sectionname) 259 { 260 int i; 261 for (i = 0; i < cfg->num_sections; i++) { 262 if (strncmp(cfg->sections[i]->name, sectionname, 263 sizeof(cfg->sections[0]->name)) == 0) 264 return cfg->sections[i]; 265 } 266 return NULL; 267 } 268 269 int 270 cfg_has_section(struct cfg_file *cfg, const char *sectionname) 271 { 272 return (_get_section(cfg, sectionname) != NULL); 273 } 274 275 int 276 cfg_section_num_entries(struct cfg_file *cfg, const char *sectionname) 277 { 278 const struct cfg_section *s = _get_section(cfg, sectionname); 279 if (s == NULL) 280 return -1; 281 return s->num_entries; 282 } 283 284 285 int 286 cfg_section_entries(struct cfg_file *cfg, const char *sectionname, 287 struct cfg_entry *entries, int max_entries) 288 { 289 int i; 290 const struct cfg_section *sect = _get_section(cfg, sectionname); 291 if (sect == NULL) 292 return -1; 293 for (i = 0; i < max_entries && i < sect->num_entries; i++) 294 entries[i] = *sect->entries[i]; 295 return i; 296 } 297 298 const char * 299 cfg_get_entry(struct cfg_file *cfg, const char *sectionname, 300 const char *entryname) 301 { 302 int i; 303 const struct cfg_section *sect = _get_section(cfg, sectionname); 304 if (sect == NULL) 305 return NULL; 306 for (i = 0; i < sect->num_entries; i++) 307 if (strncmp(sect->entries[i]->name, entryname, CFG_NAME_LEN) == 0) 308 return sect->entries[i]->value; 309 return NULL; 310 } 311 312 int 313 cfg_has_entry(struct cfg_file *cfg, const char *sectionname, 314 const char *entryname) 315 { 316 return (cfg_get_entry(cfg, sectionname, entryname) != NULL); 317 } 318 319 320 int 321 cfg_load_port(struct cfg_file *cfg, struct rte_sched_port_params *port_params) 322 { 323 const char *entry; 324 int j; 325 326 if (!cfg || !port_params) 327 return -1; 328 329 entry = cfg_get_entry(cfg, "port", "frame overhead"); 330 if (entry) 331 port_params->frame_overhead = (uint32_t)atoi(entry); 332 333 entry = cfg_get_entry(cfg, "port", "number of subports per port"); 334 if (entry) 335 port_params->n_subports_per_port = (uint32_t)atoi(entry); 336 337 entry = cfg_get_entry(cfg, "port", "number of pipes per subport"); 338 if (entry) 339 port_params->n_pipes_per_subport = (uint32_t)atoi(entry); 340 341 entry = cfg_get_entry(cfg, "port", "queue sizes"); 342 if (entry) { 343 char *next; 344 345 for(j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { 346 port_params->qsize[j] = (uint16_t)strtol(entry, &next, 10); 347 if (next == NULL) 348 break; 349 entry = next; 350 } 351 } 352 353 #ifdef RTE_SCHED_RED 354 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { 355 char str[32]; 356 357 /* Parse WRED min thresholds */ 358 rte_snprintf(str, sizeof(str), "tc %d wred min", j); 359 entry = cfg_get_entry(cfg, "red", str); 360 if (entry) { 361 char *next; 362 int k; 363 /* for each packet colour (green, yellow, red) */ 364 for (k = 0; k < e_RTE_METER_COLORS; k++) { 365 port_params->red_params[j][k].min_th 366 = (uint16_t)strtol(entry, &next, 10); 367 if (next == NULL) 368 break; 369 entry = next; 370 } 371 } 372 373 /* Parse WRED max thresholds */ 374 rte_snprintf(str, sizeof(str), "tc %d wred max", j); 375 entry = cfg_get_entry(cfg, "red", str); 376 if (entry) { 377 char *next; 378 int k; 379 /* for each packet colour (green, yellow, red) */ 380 for (k = 0; k < e_RTE_METER_COLORS; k++) { 381 port_params->red_params[j][k].max_th 382 = (uint16_t)strtol(entry, &next, 10); 383 if (next == NULL) 384 break; 385 entry = next; 386 } 387 } 388 389 /* Parse WRED inverse mark probabilities */ 390 rte_snprintf(str, sizeof(str), "tc %d wred inv prob", j); 391 entry = cfg_get_entry(cfg, "red", str); 392 if (entry) { 393 char *next; 394 int k; 395 /* for each packet colour (green, yellow, red) */ 396 for (k = 0; k < e_RTE_METER_COLORS; k++) { 397 port_params->red_params[j][k].maxp_inv 398 = (uint8_t)strtol(entry, &next, 10); 399 400 if (next == NULL) 401 break; 402 entry = next; 403 } 404 } 405 406 /* Parse WRED EWMA filter weights */ 407 rte_snprintf(str, sizeof(str), "tc %d wred weight", j); 408 entry = cfg_get_entry(cfg, "red", str); 409 if (entry) { 410 char *next; 411 int k; 412 /* for each packet colour (green, yellow, red) */ 413 for (k = 0; k < e_RTE_METER_COLORS; k++) { 414 port_params->red_params[j][k].wq_log2 415 = (uint8_t)strtol(entry, &next, 10); 416 if (next == NULL) 417 break; 418 entry = next; 419 } 420 } 421 } 422 #endif /* RTE_SCHED_RED */ 423 424 return 0; 425 } 426 427 int 428 cfg_load_pipe(struct cfg_file *cfg, struct rte_sched_pipe_params *pipe_params) 429 { 430 int i, j; 431 char *next; 432 const char *entry; 433 int profiles; 434 435 if (!cfg || !pipe_params) 436 return -1; 437 438 profiles = cfg_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1); 439 port_params.n_pipe_profiles = profiles; 440 441 for (j = 0; j < profiles; j++) { 442 char pipe_name[32]; 443 rte_snprintf(pipe_name, sizeof(pipe_name), "pipe profile %d", j); 444 445 entry = cfg_get_entry(cfg, pipe_name, "tb rate"); 446 if (entry) 447 pipe_params[j].tb_rate = (uint32_t)atoi(entry); 448 449 entry = cfg_get_entry(cfg, pipe_name, "tb size"); 450 if (entry) 451 pipe_params[j].tb_size = (uint32_t)atoi(entry); 452 453 entry = cfg_get_entry(cfg, pipe_name, "tc period"); 454 if (entry) 455 pipe_params[j].tc_period = (uint32_t)atoi(entry); 456 457 entry = cfg_get_entry(cfg, pipe_name, "tc 0 rate"); 458 if (entry) 459 pipe_params[j].tc_rate[0] = (uint32_t)atoi(entry); 460 461 entry = cfg_get_entry(cfg, pipe_name, "tc 1 rate"); 462 if (entry) 463 pipe_params[j].tc_rate[1] = (uint32_t)atoi(entry); 464 465 entry = cfg_get_entry(cfg, pipe_name, "tc 2 rate"); 466 if (entry) 467 pipe_params[j].tc_rate[2] = (uint32_t)atoi(entry); 468 469 entry = cfg_get_entry(cfg, pipe_name, "tc 3 rate"); 470 if (entry) 471 pipe_params[j].tc_rate[3] = (uint32_t)atoi(entry); 472 473 #ifdef RTE_SCHED_SUBPORT_TC_OV 474 entry = cfg_get_entry(cfg, pipe_name, "tc 3 oversubscription weight"); 475 if (entry) 476 pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry); 477 #endif 478 479 entry = cfg_get_entry(cfg, pipe_name, "tc 0 wrr weights"); 480 if (entry) { 481 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 482 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] = 483 (uint8_t)strtol(entry, &next, 10); 484 if (next == NULL) 485 break; 486 entry = next; 487 } 488 } 489 entry = cfg_get_entry(cfg, pipe_name, "tc 1 wrr weights"); 490 if (entry) { 491 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 492 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] = 493 (uint8_t)strtol(entry, &next, 10); 494 if (next == NULL) 495 break; 496 entry = next; 497 } 498 } 499 entry = cfg_get_entry(cfg, pipe_name, "tc 2 wrr weights"); 500 if (entry) { 501 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 502 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] = 503 (uint8_t)strtol(entry, &next, 10); 504 if (next == NULL) 505 break; 506 entry = next; 507 } 508 } 509 entry = cfg_get_entry(cfg, pipe_name, "tc 3 wrr weights"); 510 if (entry) { 511 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 512 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] = 513 (uint8_t)strtol(entry, &next, 10); 514 if (next == NULL) 515 break; 516 entry = next; 517 } 518 } 519 } 520 return 0; 521 } 522 523 int 524 cfg_load_subport(struct cfg_file *cfg, struct rte_sched_subport_params *subport_params) 525 { 526 const char *entry; 527 int i, j, k; 528 529 if (!cfg || !subport_params) 530 return -1; 531 532 memset(app_pipe_to_profile, -1, sizeof(app_pipe_to_profile)); 533 534 for (i = 0; i < MAX_SCHED_SUBPORTS; i++) { 535 char sec_name[CFG_NAME_LEN]; 536 rte_snprintf(sec_name, sizeof(sec_name), "subport %d", i); 537 538 if (cfg_has_section(cfg, sec_name)) { 539 entry = cfg_get_entry(cfg, sec_name, "tb rate"); 540 if (entry) 541 subport_params[i].tb_rate = (uint32_t)atoi(entry); 542 543 entry = cfg_get_entry(cfg, sec_name, "tb size"); 544 if (entry) 545 subport_params[i].tb_size = (uint32_t)atoi(entry); 546 547 entry = cfg_get_entry(cfg, sec_name, "tc period"); 548 if (entry) 549 subport_params[i].tc_period = (uint32_t)atoi(entry); 550 551 entry = cfg_get_entry(cfg, sec_name, "tc 0 rate"); 552 if (entry) 553 subport_params[i].tc_rate[0] = (uint32_t)atoi(entry); 554 555 entry = cfg_get_entry(cfg, sec_name, "tc 1 rate"); 556 if (entry) 557 subport_params[i].tc_rate[1] = (uint32_t)atoi(entry); 558 559 entry = cfg_get_entry(cfg, sec_name, "tc 2 rate"); 560 if (entry) 561 subport_params[i].tc_rate[2] = (uint32_t)atoi(entry); 562 563 entry = cfg_get_entry(cfg, sec_name, "tc 3 rate"); 564 if (entry) 565 subport_params[i].tc_rate[3] = (uint32_t)atoi(entry); 566 567 int n_entries = cfg_section_num_entries(cfg, sec_name); 568 struct cfg_entry entries[n_entries]; 569 570 cfg_section_entries(cfg, sec_name, entries, n_entries); 571 572 for (j = 0; j < n_entries; j++) { 573 if (strncmp("pipe", entries[j].name, sizeof("pipe") - 1) == 0) { 574 int profile; 575 char *tokens[2] = {NULL, NULL}; 576 int n_tokens; 577 int begin, end; 578 579 profile = atoi(entries[j].value); 580 n_tokens = rte_strsplit(&entries[j].name[sizeof("pipe")], 581 strnlen(entries[j].name, CFG_NAME_LEN), tokens, 2, '-'); 582 583 begin = atoi(tokens[0]); 584 if (n_tokens == 2) 585 end = atoi(tokens[1]); 586 else 587 end = begin; 588 589 if (end >= MAX_SCHED_PIPES || begin > end) 590 return -1; 591 592 for (k = begin; k <= end; k++) { 593 char profile_name[CFG_NAME_LEN]; 594 595 rte_snprintf(profile_name, sizeof(profile_name), 596 "pipe profile %d", profile); 597 if (cfg_has_section(cfg, profile_name)) 598 app_pipe_to_profile[i][k] = profile; 599 else 600 rte_exit(EXIT_FAILURE, "Wrong pipe profile %s\n", 601 entries[j].value); 602 603 } 604 } 605 } 606 } 607 } 608 609 return 0; 610 } 611 612 613