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 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 snprintf(entry->name, sizeof(entry->name), "%s", split[0]); 193 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_load_port(struct rte_cfgfile *cfg, struct rte_sched_port_params *port_params) 237 { 238 const char *entry; 239 int j; 240 241 if (!cfg || !port_params) 242 return -1; 243 244 entry = rte_cfgfile_get_entry(cfg, "port", "frame overhead"); 245 if (entry) 246 port_params->frame_overhead = (uint32_t)atoi(entry); 247 248 entry = rte_cfgfile_get_entry(cfg, "port", "number of subports per port"); 249 if (entry) 250 port_params->n_subports_per_port = (uint32_t)atoi(entry); 251 252 entry = rte_cfgfile_get_entry(cfg, "port", "number of pipes per subport"); 253 if (entry) 254 port_params->n_pipes_per_subport = (uint32_t)atoi(entry); 255 256 entry = rte_cfgfile_get_entry(cfg, "port", "queue sizes"); 257 if (entry) { 258 char *next; 259 260 for(j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { 261 port_params->qsize[j] = (uint16_t)strtol(entry, &next, 10); 262 if (next == NULL) 263 break; 264 entry = next; 265 } 266 } 267 268 #ifdef RTE_SCHED_RED 269 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) { 270 char str[32]; 271 272 /* Parse WRED min thresholds */ 273 snprintf(str, sizeof(str), "tc %d wred min", j); 274 entry = rte_cfgfile_get_entry(cfg, "red", str); 275 if (entry) { 276 char *next; 277 int k; 278 /* for each packet colour (green, yellow, red) */ 279 for (k = 0; k < e_RTE_METER_COLORS; k++) { 280 port_params->red_params[j][k].min_th 281 = (uint16_t)strtol(entry, &next, 10); 282 if (next == NULL) 283 break; 284 entry = next; 285 } 286 } 287 288 /* Parse WRED max thresholds */ 289 snprintf(str, sizeof(str), "tc %d wred max", j); 290 entry = rte_cfgfile_get_entry(cfg, "red", str); 291 if (entry) { 292 char *next; 293 int k; 294 /* for each packet colour (green, yellow, red) */ 295 for (k = 0; k < e_RTE_METER_COLORS; k++) { 296 port_params->red_params[j][k].max_th 297 = (uint16_t)strtol(entry, &next, 10); 298 if (next == NULL) 299 break; 300 entry = next; 301 } 302 } 303 304 /* Parse WRED inverse mark probabilities */ 305 snprintf(str, sizeof(str), "tc %d wred inv prob", j); 306 entry = rte_cfgfile_get_entry(cfg, "red", str); 307 if (entry) { 308 char *next; 309 int k; 310 /* for each packet colour (green, yellow, red) */ 311 for (k = 0; k < e_RTE_METER_COLORS; k++) { 312 port_params->red_params[j][k].maxp_inv 313 = (uint8_t)strtol(entry, &next, 10); 314 315 if (next == NULL) 316 break; 317 entry = next; 318 } 319 } 320 321 /* Parse WRED EWMA filter weights */ 322 snprintf(str, sizeof(str), "tc %d wred weight", j); 323 entry = rte_cfgfile_get_entry(cfg, "red", str); 324 if (entry) { 325 char *next; 326 int k; 327 /* for each packet colour (green, yellow, red) */ 328 for (k = 0; k < e_RTE_METER_COLORS; k++) { 329 port_params->red_params[j][k].wq_log2 330 = (uint8_t)strtol(entry, &next, 10); 331 if (next == NULL) 332 break; 333 entry = next; 334 } 335 } 336 } 337 #endif /* RTE_SCHED_RED */ 338 339 return 0; 340 } 341 342 int 343 cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params) 344 { 345 int i, j; 346 char *next; 347 const char *entry; 348 int profiles; 349 350 if (!cfg || !pipe_params) 351 return -1; 352 353 profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1); 354 port_params.n_pipe_profiles = profiles; 355 356 for (j = 0; j < profiles; j++) { 357 char pipe_name[32]; 358 snprintf(pipe_name, sizeof(pipe_name), "pipe profile %d", j); 359 360 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tb rate"); 361 if (entry) 362 pipe_params[j].tb_rate = (uint32_t)atoi(entry); 363 364 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tb size"); 365 if (entry) 366 pipe_params[j].tb_size = (uint32_t)atoi(entry); 367 368 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc period"); 369 if (entry) 370 pipe_params[j].tc_period = (uint32_t)atoi(entry); 371 372 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 0 rate"); 373 if (entry) 374 pipe_params[j].tc_rate[0] = (uint32_t)atoi(entry); 375 376 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 1 rate"); 377 if (entry) 378 pipe_params[j].tc_rate[1] = (uint32_t)atoi(entry); 379 380 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 2 rate"); 381 if (entry) 382 pipe_params[j].tc_rate[2] = (uint32_t)atoi(entry); 383 384 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 3 rate"); 385 if (entry) 386 pipe_params[j].tc_rate[3] = (uint32_t)atoi(entry); 387 388 #ifdef RTE_SCHED_SUBPORT_TC_OV 389 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 3 oversubscription weight"); 390 if (entry) 391 pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry); 392 #endif 393 394 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 0 wrr weights"); 395 if (entry) { 396 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 397 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] = 398 (uint8_t)strtol(entry, &next, 10); 399 if (next == NULL) 400 break; 401 entry = next; 402 } 403 } 404 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 1 wrr weights"); 405 if (entry) { 406 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 407 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] = 408 (uint8_t)strtol(entry, &next, 10); 409 if (next == NULL) 410 break; 411 entry = next; 412 } 413 } 414 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 2 wrr weights"); 415 if (entry) { 416 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 417 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] = 418 (uint8_t)strtol(entry, &next, 10); 419 if (next == NULL) 420 break; 421 entry = next; 422 } 423 } 424 entry = rte_cfgfile_get_entry(cfg, pipe_name, "tc 3 wrr weights"); 425 if (entry) { 426 for(i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) { 427 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] = 428 (uint8_t)strtol(entry, &next, 10); 429 if (next == NULL) 430 break; 431 entry = next; 432 } 433 } 434 } 435 return 0; 436 } 437 438 int 439 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params) 440 { 441 const char *entry; 442 int i, j, k; 443 444 if (!cfg || !subport_params) 445 return -1; 446 447 memset(app_pipe_to_profile, -1, sizeof(app_pipe_to_profile)); 448 449 for (i = 0; i < MAX_SCHED_SUBPORTS; i++) { 450 char sec_name[CFG_NAME_LEN]; 451 snprintf(sec_name, sizeof(sec_name), "subport %d", i); 452 453 if (rte_cfgfile_has_section(cfg, sec_name)) { 454 entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate"); 455 if (entry) 456 subport_params[i].tb_rate = (uint32_t)atoi(entry); 457 458 entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size"); 459 if (entry) 460 subport_params[i].tb_size = (uint32_t)atoi(entry); 461 462 entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period"); 463 if (entry) 464 subport_params[i].tc_period = (uint32_t)atoi(entry); 465 466 entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate"); 467 if (entry) 468 subport_params[i].tc_rate[0] = (uint32_t)atoi(entry); 469 470 entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate"); 471 if (entry) 472 subport_params[i].tc_rate[1] = (uint32_t)atoi(entry); 473 474 entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate"); 475 if (entry) 476 subport_params[i].tc_rate[2] = (uint32_t)atoi(entry); 477 478 entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate"); 479 if (entry) 480 subport_params[i].tc_rate[3] = (uint32_t)atoi(entry); 481 482 int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name); 483 struct rte_cfgfile_entry entries[n_entries]; 484 485 rte_cfgfile_section_entries(cfg, sec_name, entries, n_entries); 486 487 for (j = 0; j < n_entries; j++) { 488 if (strncmp("pipe", entries[j].name, sizeof("pipe") - 1) == 0) { 489 int profile; 490 char *tokens[2] = {NULL, NULL}; 491 int n_tokens; 492 int begin, end; 493 494 profile = atoi(entries[j].value); 495 n_tokens = rte_strsplit(&entries[j].name[sizeof("pipe")], 496 strnlen(entries[j].name, CFG_NAME_LEN), tokens, 2, '-'); 497 498 begin = atoi(tokens[0]); 499 if (n_tokens == 2) 500 end = atoi(tokens[1]); 501 else 502 end = begin; 503 504 if (end >= MAX_SCHED_PIPES || begin > end) 505 return -1; 506 507 for (k = begin; k <= end; k++) { 508 char profile_name[CFG_NAME_LEN]; 509 510 snprintf(profile_name, sizeof(profile_name), 511 "pipe profile %d", profile); 512 if (rte_cfgfile_has_section(cfg, profile_name)) 513 app_pipe_to_profile[i][k] = profile; 514 else 515 rte_exit(EXIT_FAILURE, "Wrong pipe profile %s\n", 516 entries[j].value); 517 518 } 519 } 520 } 521 } 522 } 523 524 return 0; 525 } 526