xref: /mOS-networking-stack/core/src/config.c (revision 76404edc)
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