1 #include <stdlib.h> 2 #include <assert.h> 3 #include <sys/socket.h> 4 #include <sys/ioctl.h> 5 #include <sys/stat.h> 6 #include <net/if.h> 7 #include <arpa/inet.h> 8 #include <netinet/in.h> 9 #include <netdb.h> 10 #include <stdio.h> 11 #include <unistd.h> 12 #include <ctype.h> 13 #include <string.h> 14 15 #include "mtcp.h" 16 #include "config.h" 17 #include "tcp_in.h" 18 #include "arp.h" 19 #include "debug.h" 20 #include "mtcp_util.h" 21 /* for setting up io modules */ 22 #include "io_module.h" 23 /* for if_nametoindex */ 24 #include <net/if.h> 25 26 #define MAX_PROCLINE_LEN 1024 27 28 #ifdef DARWIN 29 #pragma GCC diagnostic ignored "-Wformat" 30 #pragma GCC diagnostic ignored "-Wempty-body" 31 #endif 32 33 /*----------------------------------------------------------------------------*/ 34 int8_t end_app_exists = 0; 35 int8_t mon_app_exists = 0; 36 addr_pool_t ap[ETH_NUM] = {NULL}; 37 char *file = NULL; 38 /*----------------------------------------------------------------------------*/ 39 /* return 0 on failure */ 40 #define MATCH_ITEM(name, item) \ 41 ((strncmp(#name, item, strlen(#name)) == 0) \ 42 && (!isalnum(item[strlen(#name)]))) 43 44 #define TRY_ASSIGN_NUM(name, base, item, value) \ 45 ((strncmp(#name, item, strlen(#name)) == 0) \ 46 && (!isalnum(item[strlen(#name)])) \ 47 && (sscanf(value, \ 48 (sizeof((base)->name) == sizeof(char)) ? "%hhi" : \ 49 (sizeof((base)->name) == sizeof(short)) ? "%hi" : \ 50 (sizeof((base)->name) == sizeof(int)) ? "%i" : \ 51 (sizeof((base)->name) == sizeof(long)) ? "%li" : \ 52 (sizeof((base)->name) == sizeof(long long)) ? "%lli" : "ERROR", \ 53 &(base)->name) > 0)) 54 55 #define TRY_ASSIGN_STR(name, base, item, value) \ 56 (((strncmp(#name, item, strlen(#name)) == 0) \ 57 && (!isalnum(item[strlen(#name)])) \ 58 && (strlen(value) < sizeof((base)->name))) ? \ 59 (strcpy((base)->name, value), 1) : 0) 60 61 #define LINE_FOREACH(line, llen, buf, blen) \ 62 for(line = buf, \ 63 llen = ((strchr(line, '\n') == NULL) ? (buf + blen - line) \ 64 : strchr(line, '\n') - line); \ 65 line + llen < buf + blen; \ 66 line += llen + 1, \ 67 llen = ((strchr(line, '\n') == NULL) ? (buf + blen - line) \ 68 : strchr(line, '\n') - line)) \ 69 /*----------------------------------------------------------------------------*/ 70 static int 71 SetMultiProcessSupport(char *multiprocess_details) 72 { 73 char *token = " ="; 74 char *sample; 75 char *saveptr; 76 77 TRACE_CONFIG("Loading multi-process configuration\n"); 78 79 sample = strtok_r(multiprocess_details, token, &saveptr); 80 if (sample == NULL) { 81 TRACE_CONFIG("No option for multi-process support given!\n"); 82 return -1; 83 } 84 g_config.mos->multiprocess_curr_core = mystrtol(sample, 10); 85 86 sample = strtok_r(NULL, token, &saveptr); 87 if (sample != NULL && !strcmp(sample, "master")) 88 g_config.mos->multiprocess_is_master = 1; 89 90 return 0; 91 } 92 /*----------------------------------------------------------------------------*/ 93 static int 94 DetectWord(char *buf, int len, char **word, int *wlen) 95 { 96 int i; 97 for (i = 0; i < len; i++) { 98 if (isspace(buf[i])) 99 continue; 100 101 if (isalpha(buf[i])) { 102 *word = &buf[i]; 103 break; 104 } else 105 /* not word */ 106 return -1; 107 } 108 109 if (i == len) 110 return -1; 111 112 for (*wlen = 0; *wlen < len; (*wlen)++) { 113 if (isalnum((*word)[*wlen]) || (*word)[*wlen] == '_') 114 continue; 115 116 assert(*wlen != 0); 117 break; 118 } 119 120 assert(*word >= buf && *word + *wlen <= buf + len); 121 122 return 0; 123 } 124 /*----------------------------------------------------------------------------*/ 125 static int 126 ReadItemValue(char *line, int llen, char *item, int ilen, char *value, int vlen) 127 { 128 const char *end = &line[llen]; 129 char *word = NULL; 130 int wlen = 0; 131 132 if (DetectWord(line, llen, &word, &wlen) < 0 || wlen > ilen) 133 return -1; 134 135 line = word + wlen; 136 137 /* skip space */ 138 while (line < end && isspace(*line)) 139 line++; 140 141 if (*(line++) != '=') 142 return -1; 143 144 while (line < end && isspace(*line)) 145 line++; 146 147 if (end - line > vlen) 148 return -1; 149 150 while (isspace(*(end - 1))) 151 end--; 152 153 if (end <= line) 154 return -1; 155 156 strncpy(item, word, wlen); 157 158 strncpy(value, line, (size_t)(end - line)); 159 160 return 0; 161 } 162 /*----------------------------------------------------------------------------*/ 163 static void 164 FeedAppConfLine(struct conf_block *blk, char *line, int len) 165 { 166 struct app_conf * const conf = (struct app_conf *)blk->conf; 167 168 char item[WORD_LEN + 1] = {0}; 169 char value[STR_LEN + 1] = {0}; 170 171 if (ReadItemValue(line, len, item, WORD_LEN, value, STR_LEN) < 0) 172 return; 173 174 if (TRY_ASSIGN_STR(type, conf, item, value)); 175 else if (TRY_ASSIGN_STR(run, conf, item, value)) { 176 StrToArgs(conf->run, &conf->app_argc, conf->app_argv, MOS_APP_ARGC); 177 #if 0 178 conf->app_argv[conf->app_argc++] = strtok(conf->run, " \t\n\r"); 179 while (conf->app_argc < MOS_APP_ARGC && 180 (conf->app_argv[conf->app_argc] = strtok(NULL, " \t\n\r"))) 181 conf->app_argc++; 182 #endif 183 } else if (TRY_ASSIGN_NUM(cpu_mask, conf, item, value)); 184 else if (TRY_ASSIGN_NUM(ip_forward, conf, item, value)); 185 } 186 /*----------------------------------------------------------------------------*/ 187 static void 188 FeedMosConfLine(struct conf_block *blk, char *line, int len) 189 { 190 struct mos_conf * const conf = (struct mos_conf *)blk->conf; 191 192 char item[WORD_LEN + 1] = {0}; 193 char value[STR_LEN + 1] = {0}; 194 195 if (ReadItemValue(line, len, item, WORD_LEN, value, STR_LEN) < 0) 196 return; 197 198 if (TRY_ASSIGN_NUM(nb_mem_channels, conf, item, value)); 199 else if (TRY_ASSIGN_NUM(forward, conf, item, value)); 200 else if (TRY_ASSIGN_NUM(max_concurrency, conf, item, value)); 201 else if (TRY_ASSIGN_NUM(rmem_size, conf, item, value)); 202 else if (TRY_ASSIGN_NUM(wmem_size, conf, item, value)); 203 else if (TRY_ASSIGN_NUM(tcp_tw_interval, conf, item, value)) 204 g_config.mos->tcp_tw_interval = 205 SEC_TO_USEC(g_config.mos->tcp_tw_interval) / TIME_TICK; 206 else if (TRY_ASSIGN_NUM(tcp_timeout, conf, item, value)) 207 g_config.mos->tcp_timeout = 208 SEC_TO_USEC(g_config.mos->tcp_timeout) / TIME_TICK; 209 else if (TRY_ASSIGN_NUM(no_ring_buffers, conf, item, value)); 210 else if (TRY_ASSIGN_STR(mos_log, conf, item, value)); 211 else if (TRY_ASSIGN_STR(stat_print, conf, item, value)); 212 else if (TRY_ASSIGN_STR(port, conf, item, value)); 213 else if (strcmp(item, "multiprocess") == 0) { 214 conf->multiprocess = 1; 215 SetMultiProcessSupport(value); 216 } 217 } 218 /*----------------------------------------------------------------------------*/ 219 static void 220 FeedNetdevConfLine(struct conf_block *blk, char *line, int len) 221 { 222 struct netdev_conf * const conf = (struct netdev_conf *)blk->conf; 223 224 #ifndef DARWIN 225 int i; 226 #endif 227 uint64_t cpu_mask; 228 char *word = NULL; 229 int wlen; 230 231 if (DetectWord(line, len, &word, &wlen) < 0 || wlen > WORD_LEN || wlen <= 0) 232 return; 233 234 line = word + wlen; 235 236 if (sscanf(line, "%li", &cpu_mask) <= 0) 237 return; 238 239 struct netdev_entry *ent = calloc(1, sizeof(struct netdev_entry)); 240 if (!ent) { 241 TRACE_ERROR("Could not allocate memory for netdev_entry!\n"); 242 exit(EXIT_FAILURE); 243 } 244 245 strncpy(ent->dev_name, word, wlen); 246 ent->cpu_mask = cpu_mask; 247 g_config.mos->cpu_mask |= cpu_mask; 248 249 strncpy(ent->ifr.ifr_name, ent->dev_name, IFNAMSIZ-1); 250 ent->ifr.ifr_name[IFNAMSIZ-1] = '\0'; 251 252 /* Create socket */ 253 int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); 254 if (sock == -1) { 255 perror("socket"); 256 exit(EXIT_FAILURE); 257 } 258 259 /* getting address */ 260 if (ioctl(sock, SIOCGIFADDR, &ent->ifr) == 0 ) { 261 struct in_addr sin = ((struct sockaddr_in *)&ent->ifr.ifr_addr)->sin_addr; 262 ent->ip_addr = *(uint32_t *)&sin; 263 } 264 265 /* Net MASK */ 266 if (ioctl(sock, SIOCGIFNETMASK, &ent->ifr) == 0) { 267 struct in_addr sin = ((struct sockaddr_in *)&ent->ifr.ifr_addr)->sin_addr; 268 ent->netmask = *(uint32_t *)&sin; 269 } 270 271 #ifdef DARWIN 272 /* FIXME: How can I retrieve a mac address in MAC OS? */ 273 #else 274 if (ioctl(sock, SIOCGIFHWADDR, &ent->ifr) == 0 ) { 275 for (i = 0; i < 6; i ++) { 276 ent->haddr[i] = ent->ifr.ifr_addr.sa_data[i]; 277 } 278 } 279 #endif 280 281 close(sock); 282 283 ent->ifindex = -1; 284 285 TAILQ_INSERT_TAIL(&conf->list, ent, link); 286 conf->ent[conf->num] = ent; 287 conf->num++; 288 } 289 /*----------------------------------------------------------------------------*/ 290 static void 291 FeedArpConfLine(struct conf_block *blk, char *line, int len) 292 { 293 struct arp_conf * const conf = (struct arp_conf *)blk->conf; 294 295 char address[WORD_LEN]; 296 int prefix; 297 uint8_t haddr[ETH_ALEN] = {0}; 298 299 /* skip first space */ 300 while (isspace(*line)) 301 line++, len--; 302 303 if (sscanf(line, "%[0-9.]/%d %hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 304 address, &prefix, &haddr[0], &haddr[1], &haddr[2], 305 &haddr[3], &haddr[4], &haddr[5]) != 8) 306 return; 307 308 struct _arp_entry *ent = calloc(1, sizeof(struct _arp_entry)); 309 if (!ent) { 310 TRACE_ERROR("Could not allocate memory for arp_entry!\n"); 311 exit(EXIT_FAILURE); 312 } 313 314 ent->ip = inet_addr(address); 315 ent->prefix = prefix; 316 ent->mask = htonl((prefix == 0) ? 0 : ((-1) << (32 - prefix))); 317 ent->masked_ip = ent->mask & ent->ip; 318 memcpy(ent->haddr, haddr, ETH_ALEN); 319 TAILQ_INSERT_TAIL(&conf->list, ent, link); 320 conf->ent[conf->num] = ent; 321 conf->num++; 322 } 323 /*----------------------------------------------------------------------------*/ 324 static void 325 FeedRouteConfLine(struct conf_block *blk, char *line, int len) 326 { 327 struct route_conf * const conf = (struct route_conf *)blk->conf; 328 329 char address[WORD_LEN], dev_name[WORD_LEN]; 330 int prefix; 331 332 /* skip first space */ 333 while (isspace(*line)) 334 line++, len--; 335 336 if (sscanf(line, "%[0-9.]/%d %[^ ^\n^\t]", address, &prefix, dev_name) != 3) 337 return; 338 339 struct route_entry *ent = calloc(1, sizeof(struct route_entry)); 340 if (!ent) { 341 TRACE_ERROR("Could not allocate memory for route_entry!\n"); 342 exit(EXIT_FAILURE); 343 } 344 345 ent->ip = inet_addr(address); 346 ent->mask = htonl((prefix == 0) ? 0 : ((-1) << (32 - prefix))); 347 ent->masked_ip = ent->mask & ent->ip; 348 ent->prefix = prefix; 349 ent->nif = -1; 350 strcpy(ent->dev_name, dev_name); 351 352 TAILQ_INSERT_TAIL(&conf->list, ent, link); 353 conf->ent[conf->num] = ent; 354 conf->num++; 355 } 356 /*----------------------------------------------------------------------------*/ 357 static void 358 FeedNICFwdConfLine(struct conf_block *blk, char *line, int len) 359 { 360 struct nic_forward_conf * const conf = (struct nic_forward_conf *)blk->conf; 361 char dev_name_in[WORD_LEN]; 362 char dev_name_out[WORD_LEN]; 363 364 /* skip first space */ 365 while (isspace(*line)) 366 line++, len--; 367 368 if (sscanf(line, "%[^ ^\n^\t] %[^ ^\n^\t]", dev_name_in, dev_name_out) != 2) 369 return; 370 371 struct nic_forward_entry *ent = calloc(1, sizeof(struct nic_forward_entry)); 372 if (!ent) { 373 TRACE_ERROR("Could not allocate memory for nic forward entry!\n"); 374 exit(EXIT_FAILURE); 375 } 376 377 strcpy(ent->nif_in, dev_name_in); 378 strcpy(ent->nif_out, dev_name_out); 379 TAILQ_INSERT_TAIL(&conf->list, ent, link); 380 conf->ent[conf->num] = ent; 381 conf->num++; 382 } 383 /*----------------------------------------------------------------------------*/ 384 static void 385 MosConfAddChild(struct conf_block *blk, struct conf_block *child) 386 { 387 struct mos_conf * const conf = (struct mos_conf *)blk->conf; 388 389 if (strcmp(child->name, NETDEV_BLOCK_NAME) == 0) { 390 conf->netdev = child; 391 conf->netdev_table = (struct netdev_conf *)child->conf; 392 } else if (strcmp(child->name, ARP_BLOCK_NAME) == 0) { 393 conf->arp = child; 394 conf->arp_table = (struct arp_conf *)child->conf; 395 } else if (strcmp(child->name, ROUTE_BLOCK_NAME) == 0) { 396 conf->route = child; 397 conf->route_table = (struct route_conf *)child->conf; 398 } else if (strcmp(child->name, FORWARD_BLOCK_NAME) == 0) { 399 conf->nic_forward = child; 400 conf->nic_forward_table = (struct nic_forward_conf *)child->conf; 401 } else 402 return; 403 } 404 /*----------------------------------------------------------------------------*/ 405 static int 406 AppConfIsValid(struct conf_block *blk) 407 { 408 struct app_conf * const conf = (struct app_conf *)blk->conf; 409 410 if (conf->app_argc <= 0) 411 return 0; 412 413 return 1; 414 } 415 /*----------------------------------------------------------------------------*/ 416 static int 417 MosConfIsValid(struct conf_block *blk) 418 { 419 return 1; 420 } 421 /*----------------------------------------------------------------------------*/ 422 static int 423 NetdevConfIsValid(struct conf_block *blk) 424 { 425 return 1; 426 } 427 /*----------------------------------------------------------------------------*/ 428 static int 429 ArpConfIsValid(struct conf_block *blk) 430 { 431 return 1; 432 } 433 /*----------------------------------------------------------------------------*/ 434 static int 435 RouteConfIsValid(struct conf_block *blk) 436 { 437 return 1; 438 } 439 /*----------------------------------------------------------------------------*/ 440 static int 441 NICFwdConfIsValid(struct conf_block *blk) 442 { 443 return 1; 444 } 445 /*----------------------------------------------------------------------------*/ 446 static void 447 NetdevConfPrint(struct conf_block *blk) 448 { 449 struct netdev_conf * const conf = (struct netdev_conf *)blk->conf; 450 451 printf(" +===== Netdev configuration (%d entries) =====\n", 452 conf->num); 453 454 struct netdev_entry *walk; 455 TAILQ_FOREACH(walk, &conf->list, link) { 456 printf(" | %s(idx: %d, HADDR: %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX) maps to CPU 0x%016lX\n", 457 walk->dev_name, walk->ifindex, 458 walk->haddr[0], walk->haddr[1], walk->haddr[2], 459 walk->haddr[3], walk->haddr[4], walk->haddr[5], 460 walk->cpu_mask); 461 } 462 printf(" |\n"); 463 } 464 /*----------------------------------------------------------------------------*/ 465 static void 466 ArpConfPrint(struct conf_block *blk) 467 { 468 struct arp_conf * const conf = (struct arp_conf *)blk->conf; 469 470 printf(" +===== Static ARP table configuration (%d entries) =====\n", 471 conf->num); 472 473 struct _arp_entry *walk; 474 TAILQ_FOREACH(walk, &conf->list, link) { 475 printf(" | IP: 0x%08X, NETMASK: 0x%08X, " 476 "HADDR: %02hhX:%02hhX:%02hhX:%02hhX:%02hhX:%02hhX\n", 477 ntohl(walk->ip), ntohl(walk->mask), 478 walk->haddr[0], walk->haddr[1], walk->haddr[2], 479 walk->haddr[3], walk->haddr[4], walk->haddr[5]); 480 } 481 printf(" |\n"); 482 } 483 /*----------------------------------------------------------------------------*/ 484 static void 485 RouteConfPrint(struct conf_block *blk) 486 { 487 struct route_conf * const conf = (struct route_conf *)blk->conf; 488 489 printf(" +===== Routing table configuration (%d entries) =====\n", 490 conf->num); 491 492 struct route_entry *walk; 493 TAILQ_FOREACH(walk, &conf->list, link) { 494 printf(" | IP: 0x%08X, NETMASK: 0x%08X, INTERFACE: %s(idx: %d)\n", 495 ntohl(walk->ip), ntohl(walk->mask), walk->dev_name, walk->nif); 496 } 497 printf(" |\n"); 498 } 499 /*----------------------------------------------------------------------------*/ 500 static void 501 NICFwdConfPrint(struct conf_block *blk) 502 { 503 int i; 504 struct nic_forward_conf * const conf = (struct nic_forward_conf *)blk->conf; 505 506 printf(" +===== NIC Forwarding table configuration (%d entries) =====\n", 507 conf->num); 508 509 struct nic_forward_entry *walk; 510 TAILQ_FOREACH(walk, &conf->list, link) { 511 printf(" | NIC Forwarding Entry: %s <---> %s", 512 walk->nif_in, walk->nif_out); 513 } 514 printf(" |\n"); 515 516 printf(" | NIC Forwarding Index Table: |\n"); 517 518 for (i = 0; i < MAX_FORWARD_ENTRY; i++) 519 printf( " | %d --> %d | \n", i, conf->nic_fwd_table[i]); 520 } 521 /*----------------------------------------------------------------------------*/ 522 static void 523 AppConfPrint(struct conf_block *blk) 524 { 525 struct app_conf * const conf = (struct app_conf *)blk->conf; 526 527 printf("===== Application configuration =====\n"); 528 printf("| type: %s\n", conf->type); 529 printf("| run: %s\n", conf->run); 530 printf("| cpu_mask: 0x%016lX\n", conf->cpu_mask); 531 printf("| ip_forward: %s\n", conf->ip_forward ? "forward" : "drop"); 532 printf("\n"); 533 } 534 /*----------------------------------------------------------------------------*/ 535 static void 536 MosConfPrint(struct conf_block *blk) 537 { 538 struct mos_conf * const conf = (struct mos_conf *)blk->conf; 539 540 printf("===== MOS configuration =====\n"); 541 printf("| num_cores: %d\n", conf->num_cores); 542 printf("| nb_mem_channels: %d\n", conf->nb_mem_channels); 543 printf("| max_concurrency: %d\n", conf->max_concurrency); 544 printf("| rmem_size: %d\n", conf->rmem_size); 545 printf("| wmem_size: %d\n", conf->wmem_size); 546 printf("| tcp_tw_interval: %d\n", conf->tcp_tw_interval); 547 printf("| tcp_timeout: %d\n", conf->tcp_timeout); 548 printf("| multiprocess: %s\n", conf->multiprocess ? "true" : "false"); 549 printf("| mos_log: %s\n", conf->mos_log); 550 printf("| stat_print: %s\n", conf->stat_print); 551 printf("| forward: %s\n", conf->forward ? "forward" : "drop"); 552 printf("|\n"); 553 if (conf->netdev) 554 conf->netdev->print(conf->netdev); 555 if (conf->arp) 556 conf->arp->print(conf->arp); 557 if (conf->route) 558 conf->route->print(conf->route); 559 if (conf->nic_forward) 560 conf->nic_forward->print(conf->nic_forward); 561 printf("\n"); 562 } 563 /*----------------------------------------------------------------------------*/ 564 static void 565 InitAppBlock(struct config *config, struct conf_block *blk) 566 { 567 assert(blk); 568 569 blk->name = APP_BLOCK_NAME; 570 571 blk->feed = FeedAppConfLine; 572 blk->addchild = NULL; 573 blk->isvalid = AppConfIsValid; 574 blk->print = AppConfPrint; 575 576 struct app_conf *conf = calloc(1, sizeof(struct app_conf)); 577 if (conf == NULL) { 578 TRACE_ERROR("Could not allocate memory for app_conf!\n"); 579 exit(EXIT_FAILURE); 580 } 581 /* set default values */ 582 conf->cpu_mask = -1; 583 conf->ip_forward = 1; 584 conf->app_argc = 0; 585 blk->conf = conf; 586 587 blk->list = (typeof(blk->list))&config->app_blkh; 588 } 589 /*----------------------------------------------------------------------------*/ 590 static void 591 InitMosBlock(struct config *config, struct conf_block *blk) 592 { 593 assert(blk); 594 595 blk->name = MOS_BLOCK_NAME; 596 597 blk->feed = FeedMosConfLine; 598 blk->addchild = MosConfAddChild; 599 blk->isvalid = MosConfIsValid; 600 blk->print = MosConfPrint; 601 602 struct mos_conf *conf = calloc(1, sizeof(struct mos_conf)); 603 if (conf == NULL) { 604 TRACE_ERROR("Could not allocate memory for mos_conf!\n"); 605 exit(EXIT_FAILURE); 606 } 607 /* set default values */ 608 conf->forward = 1; 609 conf->nb_mem_channels = 0; 610 conf->max_concurrency = 100000; 611 conf->no_ring_buffers = 0; 612 conf->rmem_size = 8192; 613 conf->wmem_size = 8192; 614 conf->tcp_tw_interval = SEC_TO_USEC(TCP_TIMEWAIT) / TIME_TICK; 615 conf->tcp_timeout = SEC_TO_USEC(TCP_TIMEOUT) / TIME_TICK; 616 conf->cpu_mask = 0; 617 blk->conf = conf; 618 619 blk->list = (typeof(blk->list))&config->mos_blkh; 620 config->mos = conf; 621 } 622 /*----------------------------------------------------------------------------*/ 623 static void 624 InitNetdevBlock(struct config *config, struct conf_block *blk) 625 { 626 assert(blk); 627 628 blk->name = NETDEV_BLOCK_NAME; 629 630 blk->feed = FeedNetdevConfLine; 631 blk->addchild = NULL; 632 blk->isvalid = NetdevConfIsValid; 633 blk->print = NetdevConfPrint; 634 635 struct netdev_conf *conf = calloc(1, sizeof(struct netdev_conf)); 636 if (conf == NULL) { 637 TRACE_ERROR("Could not allocate memory for netdev_conf!\n"); 638 exit(EXIT_FAILURE); 639 } 640 TAILQ_INIT(&conf->list); 641 blk->conf = conf; 642 643 blk->list = NULL; 644 } 645 /*----------------------------------------------------------------------------*/ 646 static void 647 FetchARPKernelEntries(struct arp_conf * const config) 648 { 649 #define _PATH_PROCNET_ARP "/proc/net/arp" 650 #define DPDK_PREFIX "dpdk" 651 #define DPDK_PREFIX_LEN 4 652 #define LINE_LEN 200 653 #define ENTRY_LEN 25 654 655 FILE *fp; 656 char ip[ENTRY_LEN]; 657 char hwa[ENTRY_LEN]; 658 char mask[ENTRY_LEN]; 659 char dev[WORD_LEN]; 660 char line[LINE_LEN]; 661 int type, flags, num; 662 663 if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) { 664 perror(_PATH_PROCNET_ARP); 665 exit(EXIT_FAILURE); 666 } 667 668 /* Bypass header -- read until newline */ 669 if (fgets(line, sizeof(line), fp) != (char *) NULL) { 670 strcpy(mask, "-"); 671 strcpy(dev, "-"); 672 /* Read the ARP cache entries. */ 673 for (; fgets(line, sizeof(line), fp);) { 674 675 num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n", 676 ip, &type, &flags, hwa, mask, dev); 677 if (num < 6) 678 break; 679 680 /* if the user specified device differs, skip it */ 681 if (strncmp(dev, DPDK_PREFIX, DPDK_PREFIX_LEN)) 682 continue; 683 684 /* if the entry has not expired/tagged for removal then... */ 685 if (flags != 0x00) { 686 /* add the new arp entry in MOS database */ 687 struct _arp_entry *ent = calloc(1, sizeof(struct _arp_entry)); 688 if (!ent) { 689 TRACE_ERROR("Can't allocate memory for arp_entry\n"); 690 exit(EXIT_FAILURE); 691 } 692 uint8_t haddr[ETH_ALEN] = {0}; 693 if (sscanf(hwa, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", 694 &haddr[0], &haddr[1], &haddr[2], 695 &haddr[3], &haddr[4], &haddr[5]) != 6) { 696 TRACE_ERROR("Error reading the ARP entry\n"); 697 exit(EXIT_FAILURE); 698 } 699 ent->ip = inet_addr(ip); 700 ent->prefix = 32; 701 ent->mask = htonl((ent->prefix == 0) ? 0 : ((-1) << (32 - ent->prefix))); 702 ent->masked_ip = ent->mask & ent->ip; 703 memcpy(ent->haddr, haddr, ETH_ALEN); 704 TAILQ_INSERT_TAIL(&config->list, ent, link); 705 config->ent[config->num] = ent; 706 config->num++; 707 } 708 } 709 } 710 711 fclose(fp); 712 } 713 /*----------------------------------------------------------------------------*/ 714 static void 715 FetchRouteKernelEntries(struct route_conf * const config) 716 { 717 #define _PATH_PROCNET_ROUTE "/proc/net/route" 718 #define DPDK_PREFIX "dpdk" 719 #define DPDK_PREFIX_LEN 4 720 721 FILE *fp; 722 uint32_t gate; 723 uint32_t dest; 724 uint32_t mask; 725 char dev[WORD_LEN]; 726 char line[LINE_LEN]; 727 char mtu[ENTRY_LEN]; 728 char win[ENTRY_LEN]; 729 char irtt[ENTRY_LEN]; 730 int flags, num, cnt, use, metric; 731 732 if ((fp = fopen(_PATH_PROCNET_ROUTE, "r")) == NULL) { 733 perror(_PATH_PROCNET_ARP); 734 exit(EXIT_FAILURE); 735 } 736 737 /* Bypass header -- read until newline */ 738 if (fgets(line, sizeof(line), fp) != (char *) NULL) { 739 /* Read the route table entries. */ 740 for (; fgets(line, sizeof(line), fp);) { 741 742 num = sscanf(line, "%s %08X %08X %d %d %d %d %08X %s %s %s\n", 743 dev, 744 &dest, 745 &gate, 746 &flags, &cnt, &use, &metric, 747 &mask, 748 mtu, win, irtt); 749 750 if (num < 11) 751 break; 752 #if 0 753 /* if the user specified device differs, skip it */ 754 if (strncmp(dev, DPDK_PREFIX, DPDK_PREFIX_LEN)) 755 continue; 756 #endif 757 struct route_entry *ent = calloc(1, sizeof(struct route_entry)); 758 if (!ent) { 759 TRACE_ERROR("Could not allocate memory for route_entry!\n"); 760 exit(EXIT_FAILURE); 761 } 762 763 ent->ip = dest; 764 765 /* __builtin_clz() returns undefined output with zero */ 766 if (mask == 0) 767 ent->prefix = 0; 768 else 769 ent->prefix = 32 - __builtin_clz(mask); 770 ent->mask = mask; 771 ent->masked_ip = ent->mask & ent->ip; 772 strcpy(ent->dev_name, dev); 773 TAILQ_INSERT_TAIL(&config->list, ent, link); 774 config->ent[config->num] = ent; 775 config->num++; 776 } 777 } 778 779 fclose(fp); 780 } 781 /*----------------------------------------------------------------------------*/ 782 static void 783 InitArpBlock(struct config *config, struct conf_block *blk) 784 { 785 assert(blk); 786 787 blk->name = ARP_BLOCK_NAME; 788 789 blk->feed = FeedArpConfLine; 790 blk->addchild = NULL; 791 blk->isvalid = ArpConfIsValid; 792 blk->print = ArpConfPrint; 793 794 struct arp_conf *conf = calloc(1, sizeof(struct arp_conf)); 795 if (conf == NULL) { 796 TRACE_ERROR("Could not allocate memory for arp_conf!\n"); 797 exit(EXIT_FAILURE); 798 } 799 TAILQ_INIT(&conf->list); 800 blk->conf = conf; 801 802 blk->list = NULL; 803 config->mos->arp = blk; 804 805 /* fetch relevant ARP entries for dpdk? from kernel tables */ 806 FetchARPKernelEntries(conf); 807 } 808 /*----------------------------------------------------------------------------*/ 809 static void 810 InitRouteBlock(struct config *config, struct conf_block *blk) 811 { 812 assert(blk); 813 814 blk->name = ROUTE_BLOCK_NAME; 815 816 blk->feed = FeedRouteConfLine; 817 blk->addchild = NULL; 818 blk->isvalid = RouteConfIsValid; 819 blk->print = RouteConfPrint; 820 821 struct route_conf *conf = calloc(1, sizeof(struct route_conf)); 822 if (conf == NULL) { 823 TRACE_ERROR("Could not allocate memory for route_conf!\n"); 824 exit(EXIT_FAILURE); 825 } 826 TAILQ_INIT(&conf->list); 827 blk->conf = conf; 828 829 blk->list = NULL; 830 config->mos->route = blk; 831 832 /* fetch relevant route entries for dpdk? from kernel tables */ 833 FetchRouteKernelEntries(conf); 834 } 835 /*----------------------------------------------------------------------------*/ 836 static void 837 InitNICForwardBlock(struct config *config, struct conf_block *blk) 838 { 839 int i; 840 assert(blk); 841 blk->name = FORWARD_BLOCK_NAME; 842 843 blk->feed = FeedNICFwdConfLine; 844 blk->addchild = NULL; 845 blk->isvalid = NICFwdConfIsValid; 846 blk->print = NICFwdConfPrint; 847 848 struct nic_forward_conf *conf = calloc(1, sizeof(struct nic_forward_conf)); 849 if (conf == NULL) { 850 TRACE_ERROR("Could not allocate memory for nic_forward_conf!\n"); 851 exit(EXIT_FAILURE); 852 } 853 for (i = 0; i < MAX_FORWARD_ENTRY; i++) 854 conf->nic_fwd_table[i] = -1; 855 856 TAILQ_INIT(&conf->list); 857 blk->conf = conf; 858 859 blk->list = NULL; 860 config->mos->nic_forward = blk; 861 } 862 /*----------------------------------------------------------------------------*/ 863 void 864 PrintConf(struct config *conf) 865 { 866 struct conf_block *walk; 867 TAILQ_FOREACH(walk, &conf->app_blkh, link) { 868 if (walk->print) 869 walk->print(walk); 870 } 871 872 TAILQ_FOREACH(walk, &conf->mos_blkh, link) { 873 if (walk->print) 874 walk->print(walk); 875 } 876 } 877 /*----------------------------------------------------------------------------*/ 878 static void 879 CheckConfValidity(struct config *conf) 880 { 881 struct conf_block *walk; 882 TAILQ_FOREACH(walk, &conf->app_blkh, link) { 883 if (!walk->isvalid || !walk->isvalid(walk)) 884 goto __error; 885 } 886 887 TAILQ_FOREACH(walk, &conf->mos_blkh, link) { 888 struct conf_block *child; 889 890 if (!walk->isvalid || !walk->isvalid(walk)) 891 goto __error; 892 893 child = ((struct mos_conf *)walk->conf)->netdev; 894 if (!child->isvalid || !child->isvalid(child)) 895 goto __error; 896 897 child = ((struct mos_conf *)walk->conf)->arp; 898 if (!child->isvalid || !child->isvalid(child)) 899 goto __error; 900 901 child = ((struct mos_conf *)walk->conf)->route; 902 if (!child->isvalid || !child->isvalid(child)) 903 goto __error; 904 } 905 906 return; 907 908 __error: 909 printf("!!!!! Configuration validity check failure !!!!!\n"); 910 if (walk && walk->print) 911 walk->print(walk); 912 exit(0); 913 } 914 /*----------------------------------------------------------------------------*/ 915 static char * 916 ReadConf(const char *fname) 917 { 918 ssize_t hav_read = 0, rc; 919 FILE *fp = fopen(fname, "r"); 920 if (fp == NULL) { 921 TRACE_ERROR("Cannot open the config file %s\n", fname); 922 exit(-1); 923 } 924 925 /* find out the size of file */ 926 fseek(fp, 0L, SEEK_END); 927 int size = ftell(fp); 928 fseek(fp, 0L, SEEK_SET); 929 930 file = calloc(1, size + 1); 931 if (file == NULL) { 932 TRACE_ERROR("Can't allocate memory for file!\n"); 933 exit(EXIT_FAILURE); 934 } 935 936 file[size] = '\0'; 937 938 while (hav_read < size) { 939 rc = fread(file, 1, size, fp); 940 /* sanity check */ 941 if (rc <= 0) break; 942 hav_read += rc; 943 } 944 945 fclose(fp); 946 947 return file; 948 } 949 /*----------------------------------------------------------------------------*/ 950 static char * 951 PreprocessConf(char *raw) 952 { 953 char *line; 954 int llen; 955 956 int len = strlen(raw); 957 958 LINE_FOREACH(line, llen, raw, len) { 959 int i, iscomment = 0; 960 for (i = 0; i < llen; i++) { 961 if (!iscomment && line[i] == '#') 962 iscomment = 1; 963 if (iscomment) 964 line[i] = ' '; 965 } 966 } 967 return raw; 968 } 969 /*----------------------------------------------------------------------------*/ 970 static void 971 InitConfig(struct config *config) 972 { 973 int i; 974 struct conf_block *blk; 975 976 TAILQ_INIT(&g_free_blkh); 977 TAILQ_INIT(&config->app_blkh); 978 TAILQ_INIT(&config->mos_blkh); 979 980 for (i = 0; i < MAX_APP_BLOCK; i++) { 981 /* Allocate app conf_block */ 982 blk = calloc(1, sizeof(struct conf_block)); 983 if (blk == NULL) goto init_config_err; 984 InitAppBlock(config, blk); 985 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 986 987 /* Allocate netdev conf_block */ 988 blk = calloc(1, sizeof(struct conf_block)); 989 if (blk == NULL) goto init_config_err; 990 InitNetdevBlock(config, blk); 991 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 992 } 993 994 for (i = 0; i < MAX_MOS_BLOCK; i++) { 995 /* Allocate mos conf_block */ 996 blk = calloc(1, sizeof(struct conf_block)); 997 if (blk == NULL) goto init_config_err; 998 InitMosBlock(config, blk); 999 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 1000 1001 /* Allocate arp conf_block */ 1002 blk = calloc(1, sizeof(struct conf_block)); 1003 if (blk == NULL) goto init_config_err; 1004 InitArpBlock(config, blk); 1005 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 1006 1007 /* Allocate route conf_block */ 1008 blk = calloc(1, sizeof(struct conf_block)); 1009 if (blk == NULL) goto init_config_err; 1010 InitRouteBlock(config, blk); 1011 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 1012 1013 /* Allocate nic_forward conf_block */ 1014 blk = calloc (1, sizeof(struct conf_block)); 1015 if (blk == NULL) goto init_config_err; 1016 InitNICForwardBlock(config, blk); 1017 TAILQ_INSERT_TAIL(&g_free_blkh, blk, link); 1018 } 1019 return; 1020 init_config_err: 1021 TRACE_ERROR("Can't allocate memory for blk_entry!\n"); 1022 exit(EXIT_FAILURE); 1023 } 1024 /*----------------------------------------------------------------------------*/ 1025 static struct conf_block * 1026 AllocateBlock(char *name, int len) 1027 { 1028 struct conf_block *walk, *tmp; 1029 1030 for (walk = TAILQ_FIRST(&g_free_blkh); walk != NULL; walk = tmp) { 1031 tmp = TAILQ_NEXT(walk, link); 1032 if (len == strlen(walk->name) && strncmp(walk->name, name, len) == 0) { 1033 TAILQ_REMOVE(&g_free_blkh, walk, link); 1034 if (walk->list) 1035 TAILQ_INSERT_TAIL(walk->list, walk, link); 1036 return walk; 1037 } 1038 } 1039 1040 return NULL; 1041 } 1042 /*----------------------------------------------------------------------------*/ 1043 struct conf_block * 1044 DetectBlock(struct conf_block *blk, char *buf, int len) 1045 { 1046 int depth = 0; 1047 char *blkname = NULL, *end = &buf[len]; 1048 int blknamelen; 1049 struct conf_block *nblk; 1050 1051 /* skip first space */ 1052 while (buf < end && isspace(*buf)) 1053 buf++; 1054 1055 if (DetectWord(buf, len, &blkname, &blknamelen) < 0 1056 || blkname != buf) 1057 /* Failed to detect conf_block name */ 1058 return NULL; 1059 1060 /* fast forward buffer */ 1061 buf += blknamelen; 1062 1063 /* skip space */ 1064 while (buf < end && isspace(*buf)) 1065 buf++; 1066 1067 /* buf must be '{' */ 1068 if (buf >= end || *buf != '{') 1069 return NULL; 1070 1071 buf++; /* skip '{' */ 1072 while (buf < end && isspace(*buf)) 1073 buf++; /* skip space */ 1074 depth++; /* Now in first parenthesis */ 1075 1076 /* Now, the `buf` points the first byte inside conf_block */ 1077 1078 for (len = 0; &buf[len] < end; len++) { 1079 if (buf[len] == '{') 1080 depth++; 1081 else if (buf[len] == '}' && --depth == 0) 1082 break; 1083 } 1084 1085 if (depth != 0) 1086 /* Failed to find the end of parenthesis */ 1087 return NULL; 1088 1089 if (!(nblk = AllocateBlock(blkname, blknamelen))) 1090 return NULL; 1091 1092 if (blk) { 1093 assert(blk->addchild); 1094 blk->addchild(blk, nblk); 1095 } 1096 1097 nblk->buf = buf; 1098 nblk->len = len; 1099 1100 return nblk; 1101 } 1102 /*----------------------------------------------------------------------------*/ 1103 static void 1104 ParseBlock(struct conf_block *blk) 1105 { 1106 char *line; 1107 int llen; 1108 1109 LINE_FOREACH(line, llen, blk->buf, blk->len) { 1110 struct conf_block *nblk; 1111 1112 if ((nblk = DetectBlock(blk, line, blk->len - (line - blk->buf)))) { 1113 ParseBlock(nblk); 1114 /* skip nested conf_block by fast forwarding line */ 1115 line = &nblk->buf[nblk->len] + 1; 1116 llen = 0; 1117 } else 1118 blk->feed(blk, line, llen); 1119 } 1120 } 1121 /*----------------------------------------------------------------------------*/ 1122 void 1123 PatchCONFIG(struct config *config) 1124 { 1125 int i, count; 1126 char *word, *str, *end; 1127 int wlen; 1128 uint64_t value; 1129 1130 value = g_config.mos->cpu_mask; 1131 for (count = 0; value != 0; count++, value &= value-1); 1132 if (count > num_cpus) { 1133 TRACE_ERROR("CPU mask (%016lX) exceeds the number of CPU cores (%d)\n", 1134 g_config.mos->cpu_mask, num_cpus); 1135 exit(-1); 1136 } 1137 if (count > MAX_CPUS) { 1138 TRACE_ERROR("mOS does not support more than %d CPU cores for now\n", 1139 MAX_CPUS); 1140 exit(-1); 1141 } 1142 g_config.mos->num_cores = count; 1143 1144 word = NULL; 1145 1146 i = 0; 1147 struct conf_block *bwalk; 1148 TAILQ_FOREACH(bwalk, &g_config.app_blkh, link) { 1149 struct app_conf *app_conf = (struct app_conf *)bwalk->conf; 1150 g_config.mos->forward = g_config.mos->forward && app_conf->ip_forward; 1151 if (end_app_exists == 0 && !strcmp(app_conf->type, "end")) 1152 end_app_exists = 1; 1153 if (mon_app_exists == 0 && !strcmp(app_conf->type, "monitor")) 1154 mon_app_exists = 1; 1155 i++; 1156 } 1157 /* turn on monitor mode if end app is not set */ 1158 if (!end_app_exists && !mon_app_exists) mon_app_exists = 1; 1159 1160 /* stat print */ 1161 str = g_config.mos->stat_print; 1162 end = str + strlen(str); 1163 while (DetectWord(str, end - str, &word, &wlen) == 0) { 1164 for (i = 0; i < g_config.mos->netdev_table->num; i++) { 1165 if (strncmp(g_config.mos->netdev_table->ent[i]->dev_name, word, wlen) == 0) { 1166 g_config.mos->netdev_table->ent[i]->stat_print = TRUE; 1167 } 1168 } 1169 str = word + wlen; 1170 } 1171 1172 } 1173 /*----------------------------------------------------------------------------*/ 1174 int 1175 LoadConfigurationUpperHalf(const char *fname) 1176 { 1177 char *line; 1178 int llen; 1179 1180 char *raw = ReadConf(fname); 1181 char *preprocessed = PreprocessConf(raw); 1182 int len = strlen(preprocessed); 1183 1184 InitConfig(&g_config); 1185 1186 LINE_FOREACH(line, llen, preprocessed, len) { 1187 struct conf_block *nblk; 1188 1189 if ((nblk = DetectBlock(NULL, line, len - (line - preprocessed)))) { 1190 ParseBlock(nblk); 1191 /* skip parsed conf_block by fast forwarding line */ 1192 line = &nblk->buf[nblk->len] + 1; 1193 llen = 0; 1194 } 1195 } 1196 1197 CheckConfValidity(&g_config); 1198 1199 PatchCONFIG(&g_config); 1200 1201 //PrintConf(&g_config); 1202 1203 return 0; 1204 } 1205 /*----------------------------------------------------------------------------*/ 1206 void 1207 LoadConfigurationLowerHalf(void) 1208 { 1209 struct route_conf *route_conf = g_config.mos->route_table; 1210 struct netdev_conf *netdev_conf = g_config.mos->netdev_table; 1211 struct nic_forward_conf *nicfwd_conf = g_config.mos->nic_forward_table; 1212 struct route_entry *rwalk; 1213 struct netdev_entry *nwalk; 1214 struct nic_forward_entry *fwalk; 1215 int nif_in = -1; 1216 int nif_out = -1; 1217 1218 TAILQ_FOREACH(rwalk, &route_conf->list, link) { 1219 TAILQ_FOREACH(nwalk, &netdev_conf->list, link) { 1220 if (!strcmp(nwalk->dev_name, rwalk->dev_name)) 1221 break; 1222 } 1223 if (!nwalk) 1224 continue; 1225 if (nwalk->ifindex < 0 && 1226 (nwalk->ifindex = current_iomodule_func->get_nif(&nwalk->ifr)) < 0) { 1227 TRACE_ERROR("Interface '%s' not found\n", nwalk->dev_name); 1228 exit(EXIT_FAILURE); 1229 } 1230 1231 rwalk->nif = nwalk->ifindex; 1232 } 1233 1234 if (nicfwd_conf != NULL) { 1235 TAILQ_FOREACH(fwalk, &nicfwd_conf->list, link) { 1236 TAILQ_FOREACH(nwalk, &netdev_conf->list, link) { 1237 if (!strcmp(nwalk->dev_name, fwalk->nif_in)) 1238 nif_in = nwalk->ifindex = current_iomodule_func->get_nif(&nwalk->ifr); 1239 if (!strcmp(nwalk->dev_name, fwalk->nif_out)) 1240 nif_out = nwalk->ifindex = current_iomodule_func->get_nif(&nwalk->ifr); 1241 } 1242 1243 if (nif_in != -1) 1244 nicfwd_conf->nic_fwd_table[nif_in] = nif_out; 1245 if (nif_out != -1) 1246 nicfwd_conf->nic_fwd_table[nif_out] = nif_in; 1247 nif_in = nif_out = -1; 1248 } 1249 } 1250 } 1251 /*----------------------------------------------------------------------------*/ 1252 void 1253 FreeConfigResources() 1254 { 1255 if (file) { 1256 free(file); 1257 file = NULL; 1258 } 1259 } 1260 /*----------------------------------------------------------------------------*/ 1261 int 1262 FetchEndianType() 1263 { 1264 #ifdef ENABLE_DPDK 1265 char *argv; 1266 char **argp = &argv; 1267 1268 if (current_iomodule_func == &dpdk_module_func) { 1269 /* dpdk_module_func logic down below */ 1270 dpdk_module_func.dev_ioctl(NULL, 0, DRV_NAME, (void *)argp); 1271 if (!strcmp(*argp, "net_i40e")) 1272 return 1; 1273 1274 return 0; 1275 } 1276 #endif 1277 return 1; 1278 } 1279 /*----------------------------------------------------------------------------*/ 1280