xref: /mOS-networking-stack/samples/nat/nat.c (revision 602e2e46)
176404edcSAsim Jamshed 
276404edcSAsim Jamshed #define _LARGEFILE64_SOURCE
376404edcSAsim Jamshed #include <stdio.h>
476404edcSAsim Jamshed #include <stdlib.h>
576404edcSAsim Jamshed #include <unistd.h>
676404edcSAsim Jamshed #include <stdint.h>
776404edcSAsim Jamshed #include <sys/types.h>
876404edcSAsim Jamshed #include <sys/stat.h>
976404edcSAsim Jamshed #include <sys/socket.h>
1076404edcSAsim Jamshed #include <netinet/in.h>
1176404edcSAsim Jamshed #include <arpa/inet.h>
1276404edcSAsim Jamshed #include <fcntl.h>
1376404edcSAsim Jamshed #include <dirent.h>
1476404edcSAsim Jamshed #include <string.h>
1576404edcSAsim Jamshed #include <time.h>
1676404edcSAsim Jamshed #include <pthread.h>
1776404edcSAsim Jamshed #include <signal.h>
1876404edcSAsim Jamshed #include <linux/if_ether.h>
1976404edcSAsim Jamshed #include <linux/tcp.h>
2076404edcSAsim Jamshed 
2176404edcSAsim Jamshed #include <sys/queue.h>
2276404edcSAsim Jamshed 
2376404edcSAsim Jamshed #include <mos_api.h>
2476404edcSAsim Jamshed #include <mtcp_util.h>
2576404edcSAsim Jamshed 
2676404edcSAsim Jamshed #include "cpu.h"
2776404edcSAsim Jamshed #include "http_parsing.h"
2876404edcSAsim Jamshed #include "debug.h"
2976404edcSAsim Jamshed #include "applib.h"
3076404edcSAsim Jamshed 
3176404edcSAsim Jamshed /* update_curpacket()'s byte offsets */
3276404edcSAsim Jamshed #define OFFSET_DST_IP		16
3376404edcSAsim Jamshed #define OFFSET_SRC_IP		12
3476404edcSAsim Jamshed #define OFFSET_DST_PORT		 2
3576404edcSAsim Jamshed #define OFFSET_SRC_PORT		 0
3676404edcSAsim Jamshed 
3776404edcSAsim Jamshed /* default configure file path */
3876404edcSAsim Jamshed #define MOS_CONFIG_FILE		"config/mos.conf"
3976404edcSAsim Jamshed 
4076404edcSAsim Jamshed #define MAX_CORES 16
4176404edcSAsim Jamshed 
4276404edcSAsim Jamshed enum {
4376404edcSAsim Jamshed 	SRC,
4476404edcSAsim Jamshed 	DST,
4576404edcSAsim Jamshed };
4676404edcSAsim Jamshed 
4776404edcSAsim Jamshed struct port {
4876404edcSAsim Jamshed 	uint16_t port;
4976404edcSAsim Jamshed 	TAILQ_ENTRY(port) link;
5076404edcSAsim Jamshed };
5176404edcSAsim Jamshed 
5276404edcSAsim Jamshed static int g_core_limit  = 1;   /* number of CPU cores used, WHY GLOBAL? */
5376404edcSAsim Jamshed static in_addr_t g_NATIP = 0;   /* NAT IP address */
5476404edcSAsim Jamshed static TAILQ_HEAD(, port) g_free_addrs;
5576404edcSAsim Jamshed static pthread_mutex_t g_addrlock;
5676404edcSAsim Jamshed 
578c9e1184SAsim Jamshed /*----------------------------------------------------------------------------*/
5876404edcSAsim Jamshed static void
assign_port(mctx_t mctx,int sock)5976404edcSAsim Jamshed assign_port(mctx_t mctx, int sock)
6076404edcSAsim Jamshed {
6176404edcSAsim Jamshed 	struct port *w;
6276404edcSAsim Jamshed 	struct sockaddr_in addr[2];
6335f6bf22STom Barbette 	socklen_t len = sizeof(struct sockaddr_in) * 2;
6476404edcSAsim Jamshed 
6576404edcSAsim Jamshed 	/* remove a NAT mapping for this connection */
6676404edcSAsim Jamshed 	if (mtcp_getpeername(mctx, sock, (struct sockaddr *)&addr, &len,
6705e3289cSYoungGyoun 						 MOS_SIDE_BOTH) < 0) {
6876404edcSAsim Jamshed 		TRACE_ERROR("mtcp_getpeer() failed for sock=%d\n", sock);
6976404edcSAsim Jamshed 		return;
7076404edcSAsim Jamshed 	}
7176404edcSAsim Jamshed 	/* assign a port number */
7276404edcSAsim Jamshed 	pthread_mutex_lock(&g_addrlock);
73602e2e46STom Barbette 	TAILQ_FOREACH(w, &g_free_addrs, link) {
74602e2e46STom Barbette 		/* Don't compute RSS CPU mapping value if # cpus = 1 */
75602e2e46STom Barbette 		if (g_core_limit == 1 || GetRSSCPUCore(g_NATIP, addr[MOS_SIDE_SVR].sin_addr.s_addr,
768c9e1184SAsim Jamshed 				  w->port, addr[MOS_SIDE_SVR].sin_port, g_core_limit)
7776404edcSAsim Jamshed 			 == mctx->cpu)
7876404edcSAsim Jamshed 			break;
79602e2e46STom Barbette 	}
8076404edcSAsim Jamshed 	if (w) {
8176404edcSAsim Jamshed 		TAILQ_REMOVE(&g_free_addrs, w, link);
8276404edcSAsim Jamshed 		mtcp_set_uctx(mctx, sock, w);
8376404edcSAsim Jamshed 	} else {
8476404edcSAsim Jamshed 		/* we're running out of available ports */
8576404edcSAsim Jamshed 		/* FIXME: Handle this */
8676404edcSAsim Jamshed 		TRACE_ERROR("No suitable port found! (CPU %d)\n", mctx->cpu);
8776404edcSAsim Jamshed 	}
8876404edcSAsim Jamshed 	pthread_mutex_unlock(&g_addrlock);
8976404edcSAsim Jamshed }
908c9e1184SAsim Jamshed /*----------------------------------------------------------------------------*/
9176404edcSAsim Jamshed static int
set_addr(mctx_t mctx,int sock,uint32_t ip,uint16_t port,int part)9276404edcSAsim Jamshed set_addr(mctx_t mctx, int sock, uint32_t ip, uint16_t port, int part)
9376404edcSAsim Jamshed {
9476404edcSAsim Jamshed 	int off_ip, off_port;
9576404edcSAsim Jamshed 
9676404edcSAsim Jamshed 	if (part == SRC) {
9776404edcSAsim Jamshed 		off_ip = OFFSET_SRC_IP;
9876404edcSAsim Jamshed 		off_port = OFFSET_SRC_PORT;
9976404edcSAsim Jamshed 	} else /* if (part == DST) */ {
10076404edcSAsim Jamshed 		off_ip = OFFSET_DST_IP;
10176404edcSAsim Jamshed 		off_port = OFFSET_DST_PORT;
10276404edcSAsim Jamshed 	}
10376404edcSAsim Jamshed 
10476404edcSAsim Jamshed 	if (mtcp_setlastpkt(mctx, sock, 0, off_ip,
10576404edcSAsim Jamshed 				  (uint8_t *)&ip, sizeof(in_addr_t),
10676404edcSAsim Jamshed 				  MOS_IP_HDR | MOS_OVERWRITE) < 0) {
10776404edcSAsim Jamshed 		TRACE_ERROR("mtcp_setlastpkt() failed\n");
10876404edcSAsim Jamshed 		return -1;
10976404edcSAsim Jamshed 	}
11076404edcSAsim Jamshed 	if (mtcp_setlastpkt(mctx, sock, 0, off_port,
11176404edcSAsim Jamshed 				  (uint8_t *)&port, sizeof(in_port_t),
11276404edcSAsim Jamshed 				  MOS_TCP_HDR | MOS_OVERWRITE
11376404edcSAsim Jamshed 				  | MOS_UPDATE_IP_CHKSUM | MOS_UPDATE_TCP_CHKSUM) < 0) {
11476404edcSAsim Jamshed 		TRACE_ERROR("mtcp_setlastpkt() failed\n");
11576404edcSAsim Jamshed 		return -1;
11676404edcSAsim Jamshed 	}
11776404edcSAsim Jamshed 
11876404edcSAsim Jamshed 	return 0;
11976404edcSAsim Jamshed }
1208c9e1184SAsim Jamshed /*----------------------------------------------------------------------------*/
12176404edcSAsim Jamshed static void
translate_addr(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)12276404edcSAsim Jamshed translate_addr(mctx_t mctx, int sock, int side, uint64_t events,
12376404edcSAsim Jamshed 		filter_arg_t *arg)
12476404edcSAsim Jamshed {
12576404edcSAsim Jamshed 	struct port *w;
12676404edcSAsim Jamshed 
12776404edcSAsim Jamshed 	if (!(w = mtcp_get_uctx(mctx, sock)))
12876404edcSAsim Jamshed 		assign_port(mctx, sock);
12976404edcSAsim Jamshed 
13076404edcSAsim Jamshed 	/* Translate the addresses */
13176404edcSAsim Jamshed 	if (side == MOS_SIDE_CLI) {
13276404edcSAsim Jamshed 		/* CLI (LAN) ==> SVR (WAN) : SNAT */
13376404edcSAsim Jamshed 		if (!(w = mtcp_get_uctx(mctx, sock)))
13476404edcSAsim Jamshed 			return;
13576404edcSAsim Jamshed 
13676404edcSAsim Jamshed 		if (set_addr(mctx, sock, g_NATIP, w->port, SRC) < 0 &&
13776404edcSAsim Jamshed 			mtcp_setlastpkt(mctx, sock, side, 0, NULL, 0, MOS_DROP) < 0)
13876404edcSAsim Jamshed 			exit(EXIT_FAILURE);
13976404edcSAsim Jamshed 	} else /* if (side == MOS_SIDE_SVR) */ {
14076404edcSAsim Jamshed 		/* SVR (WAN) ==> CLI (LAN) : DNAT */
14176404edcSAsim Jamshed 		struct sockaddr_in addr[2];
14235f6bf22STom Barbette 		socklen_t len = sizeof(struct sockaddr_in) * 2;
14376404edcSAsim Jamshed 
14476404edcSAsim Jamshed 		if (mtcp_getpeername(mctx, sock, (struct sockaddr *)&addr, &len,
14505e3289cSYoungGyoun 					MOS_SIDE_BOTH) < 0) {
14676404edcSAsim Jamshed 			TRACE_ERROR("mtcp_getpeer() failed sock=%d side=%d\n", sock, side);
14776404edcSAsim Jamshed 			return;
14876404edcSAsim Jamshed 		}
14976404edcSAsim Jamshed 
15076404edcSAsim Jamshed 		if (set_addr(mctx, sock, addr[MOS_SIDE_CLI].sin_addr.s_addr,
15176404edcSAsim Jamshed 					 addr[MOS_SIDE_CLI].sin_port, DST) < 0 &&
15276404edcSAsim Jamshed 			mtcp_setlastpkt(mctx, sock, side, 0, NULL, 0, MOS_DROP) < 0)
15376404edcSAsim Jamshed 			exit(EXIT_FAILURE);
15476404edcSAsim Jamshed 	}
15576404edcSAsim Jamshed }
1568c9e1184SAsim Jamshed /*----------------------------------------------------------------------------*/
15776404edcSAsim Jamshed static void
release_port(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)15876404edcSAsim Jamshed release_port(mctx_t mctx, int sock, int side, uint64_t events,
15976404edcSAsim Jamshed 		filter_arg_t *arg)
16076404edcSAsim Jamshed {
16176404edcSAsim Jamshed 	/* release the port number */
16276404edcSAsim Jamshed 	struct port *w;
16376404edcSAsim Jamshed 
16476404edcSAsim Jamshed 	if (!(w = mtcp_get_uctx(mctx, sock)))
16576404edcSAsim Jamshed 		return;
16676404edcSAsim Jamshed 
16776404edcSAsim Jamshed 	/* assign a port number */
16876404edcSAsim Jamshed 	pthread_mutex_lock(&g_addrlock);
16976404edcSAsim Jamshed 	TAILQ_INSERT_TAIL(&g_free_addrs, w, link);
17076404edcSAsim Jamshed 	mtcp_set_uctx(mctx, sock, NULL);
17176404edcSAsim Jamshed 	pthread_mutex_unlock(&g_addrlock);
17276404edcSAsim Jamshed }
17376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
17476404edcSAsim Jamshed static void
init_monitor(mctx_t mctx)17576404edcSAsim Jamshed init_monitor(mctx_t mctx)
17676404edcSAsim Jamshed {
17776404edcSAsim Jamshed 	int lsock = mtcp_socket(mctx, AF_INET, MOS_SOCK_MONITOR_STREAM, 0);
17876404edcSAsim Jamshed 	if (lsock < 0) {
17976404edcSAsim Jamshed 		TRACE_ERROR("Failed to create monitor raw socket!\n");
18076404edcSAsim Jamshed 		return;
18176404edcSAsim Jamshed 	}
18276404edcSAsim Jamshed 
18376404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, lsock, MOS_ON_PKT_IN, MOS_HK_SND,
18476404edcSAsim Jamshed 							   translate_addr))
18576404edcSAsim Jamshed 		exit(EXIT_FAILURE);
18676404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, lsock, MOS_ON_CONN_END, MOS_HK_SND,
18776404edcSAsim Jamshed 							   release_port))
18876404edcSAsim Jamshed 		exit(EXIT_FAILURE);
18976404edcSAsim Jamshed }
19076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
19176404edcSAsim Jamshed int
main(int argc,char ** argv)19276404edcSAsim Jamshed main(int argc, char **argv)
19376404edcSAsim Jamshed {
19476404edcSAsim Jamshed 	int i, opt;
19576404edcSAsim Jamshed 	char *fname = MOS_CONFIG_FILE;  /* path to the default mos config file */
19676404edcSAsim Jamshed 	struct mtcp_conf mcfg;          /* mOS configuration */
19776404edcSAsim Jamshed 	mctx_t mctx_list[MAX_CORES];                     /* mOS context */
19876404edcSAsim Jamshed 
19976404edcSAsim Jamshed 	/* get the total # of cpu cores */
20076404edcSAsim Jamshed 	g_core_limit = GetNumCPUs();
20176404edcSAsim Jamshed 
20276404edcSAsim Jamshed 	/* Parse command line arguments */
20376404edcSAsim Jamshed 	while ((opt = getopt(argc, argv, "c:f:i:")) != -1) {
20476404edcSAsim Jamshed 		switch (opt) {
20576404edcSAsim Jamshed 		case 'f':
20676404edcSAsim Jamshed 			fname = optarg;
20776404edcSAsim Jamshed 			break;
20876404edcSAsim Jamshed 		case 'c':
20976404edcSAsim Jamshed 			if (atoi(optarg) > g_core_limit) {
21076404edcSAsim Jamshed 				printf("Available number of CPU cores is %d\n", g_core_limit);
21176404edcSAsim Jamshed 				return -1;
21276404edcSAsim Jamshed 			}
21376404edcSAsim Jamshed 			g_core_limit = atoi(optarg);
21476404edcSAsim Jamshed 			break;
21576404edcSAsim Jamshed 		case 'i':
21676404edcSAsim Jamshed 			g_NATIP = inet_addr(optarg);
21776404edcSAsim Jamshed 			break;
21876404edcSAsim Jamshed 		default:
21976404edcSAsim Jamshed 			printf("Usage: %s [-f mos_config_file] [-c #_of_cpu] [-i ip_address]\n", argv[0]);
22076404edcSAsim Jamshed 			return 0;
22176404edcSAsim Jamshed 		}
22276404edcSAsim Jamshed 	}
22376404edcSAsim Jamshed 
22476404edcSAsim Jamshed 	/* NAT IP address checking */
22576404edcSAsim Jamshed 	if (!g_NATIP) {
22676404edcSAsim Jamshed 		fprintf(stderr, "You have to specify IP address of NAT with '-i' option\n");
22776404edcSAsim Jamshed 		exit(EXIT_FAILURE);
22876404edcSAsim Jamshed 	}
22976404edcSAsim Jamshed 
23076404edcSAsim Jamshed 	/* parse mos configuration file */
23176404edcSAsim Jamshed 	if (mtcp_init(fname)) {
23276404edcSAsim Jamshed 		fprintf(stderr, "Failed to initialize mtcp.\n");
23376404edcSAsim Jamshed 		exit(EXIT_FAILURE);
23476404edcSAsim Jamshed 	}
23576404edcSAsim Jamshed 
23676404edcSAsim Jamshed 	/* set the core limit */
23776404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
23876404edcSAsim Jamshed 	mcfg.num_cores = g_core_limit;
23976404edcSAsim Jamshed 	mtcp_setconf(&mcfg);
24076404edcSAsim Jamshed 
24176404edcSAsim Jamshed 	/* Initialize global data structure */
24276404edcSAsim Jamshed 	pthread_mutex_init(&g_addrlock, NULL);
24376404edcSAsim Jamshed 	TAILQ_INIT(&g_free_addrs);
24476404edcSAsim Jamshed 	for (i = 1025; i < 65535; i++) {
24576404edcSAsim Jamshed 		struct port *p = malloc(sizeof(struct port));
24676404edcSAsim Jamshed 		if (!p)
24776404edcSAsim Jamshed 			exit(EXIT_FAILURE);
24876404edcSAsim Jamshed 		p->port = htons(i);
24976404edcSAsim Jamshed 		TAILQ_INSERT_TAIL(&g_free_addrs, p, link);
25076404edcSAsim Jamshed 	}
25176404edcSAsim Jamshed 
25276404edcSAsim Jamshed 	for (i = 0; i < g_core_limit; i++) {
25376404edcSAsim Jamshed 		/* Run mOS for each CPU core */
25476404edcSAsim Jamshed 		if (!(mctx_list[i] = mtcp_create_context(i))) {
25576404edcSAsim Jamshed 			fprintf(stderr, "Failed to craete mtcp context.\n");
25676404edcSAsim Jamshed 			return -1;
25776404edcSAsim Jamshed 		}
25876404edcSAsim Jamshed 
25976404edcSAsim Jamshed 		/* init monitor */
26076404edcSAsim Jamshed 		init_monitor(mctx_list[i]);
26176404edcSAsim Jamshed 	}
26276404edcSAsim Jamshed 
26376404edcSAsim Jamshed 	/* wait until mOS finishes */
26476404edcSAsim Jamshed 	for (i = 0; i < g_core_limit; i++)
26576404edcSAsim Jamshed 		mtcp_app_join(mctx_list[i]);
26676404edcSAsim Jamshed 
26776404edcSAsim Jamshed 	mtcp_destroy();
26876404edcSAsim Jamshed 	return 0;
26976404edcSAsim Jamshed }
27076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
271