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