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