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