176404edcSAsim Jamshed #define _LARGEFILE64_SOURCE
276404edcSAsim Jamshed #include <stdio.h>
376404edcSAsim Jamshed #include <stdlib.h>
476404edcSAsim Jamshed #include <unistd.h>
576404edcSAsim Jamshed #include <stdint.h>
676404edcSAsim Jamshed #include <sys/types.h>
776404edcSAsim Jamshed #include <sys/stat.h>
876404edcSAsim Jamshed #include <sys/socket.h>
976404edcSAsim Jamshed #include <netinet/in.h>
1076404edcSAsim Jamshed #include <arpa/inet.h>
1176404edcSAsim Jamshed #include <fcntl.h>
1276404edcSAsim Jamshed #include <string.h>
1376404edcSAsim Jamshed #include <time.h>
1476404edcSAsim Jamshed #include <sys/time.h>
1576404edcSAsim Jamshed #include <asm/byteorder.h>
1676404edcSAsim Jamshed #include <assert.h>
1776404edcSAsim Jamshed #include <signal.h>
1876404edcSAsim Jamshed #include <sys/queue.h>
1976404edcSAsim Jamshed #include <errno.h>
2076404edcSAsim Jamshed 
2176404edcSAsim Jamshed #include <mos_api.h>
2276404edcSAsim Jamshed #include "cpu.h"
2376404edcSAsim Jamshed 
2476404edcSAsim Jamshed /* Maximum CPU cores */
2576404edcSAsim Jamshed #define MAX_CORES 		16
2676404edcSAsim Jamshed /* Number of TCP flags to monitor */
2776404edcSAsim Jamshed #define NUM_FLAG 		6
2876404edcSAsim Jamshed /* Default path to mOS configuration file */
2976404edcSAsim Jamshed #define MOS_CONFIG_FILE		"config/mos.conf"
3076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
3176404edcSAsim Jamshed /* Global variables */
3276404edcSAsim Jamshed 
3376404edcSAsim Jamshed struct connection {
3476404edcSAsim Jamshed 	int sock;                      /* socket ID */
3576404edcSAsim Jamshed 	struct sockaddr_in addrs[2];   /* Address of a client and a serer */
3676404edcSAsim Jamshed 	int cli_state;                 /* TCP state of the client */
3776404edcSAsim Jamshed 	int svr_state;                 /* TCP state of the server */
3876404edcSAsim Jamshed 	TAILQ_ENTRY(connection) link;  /* link to next context in this core */
3976404edcSAsim Jamshed };
4076404edcSAsim Jamshed 
4176404edcSAsim Jamshed int g_max_cores;                              /* Number of CPU cores to be used */
4276404edcSAsim Jamshed mctx_t g_mctx[MAX_CORES];                     /* mOS context */
4376404edcSAsim Jamshed TAILQ_HEAD(, connection) g_sockq[MAX_CORES];  /* connection queue */
4476404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
4576404edcSAsim Jamshed /* Signal handler */
4676404edcSAsim Jamshed static void
sigint_handler(int signum)4776404edcSAsim Jamshed sigint_handler(int signum)
4876404edcSAsim Jamshed {
4976404edcSAsim Jamshed 	int i;
5076404edcSAsim Jamshed 
5176404edcSAsim Jamshed 	/* Terminate the program if any interrupt happens */
5276404edcSAsim Jamshed 	for (i = 0; i < g_max_cores; i++)
5376404edcSAsim Jamshed 		mtcp_destroy_context(g_mctx[i]);
5476404edcSAsim Jamshed }
5576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
5676404edcSAsim Jamshed /* Find connection structure by socket ID */
5776404edcSAsim Jamshed static inline struct connection *
find_connection(int cpu,int sock)5876404edcSAsim Jamshed find_connection(int cpu, int sock)
5976404edcSAsim Jamshed {
6076404edcSAsim Jamshed 	struct connection *c;
6176404edcSAsim Jamshed 
6276404edcSAsim Jamshed 	TAILQ_FOREACH(c, &g_sockq[cpu], link)
6376404edcSAsim Jamshed 		if (c->sock == sock)
6476404edcSAsim Jamshed 			return c;
6576404edcSAsim Jamshed 
6676404edcSAsim Jamshed 	return NULL;
6776404edcSAsim Jamshed }
6876404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
6976404edcSAsim Jamshed /* Create connection structure for new connection */
7076404edcSAsim Jamshed static void
cb_creation(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)7176404edcSAsim Jamshed cb_creation(mctx_t mctx, int sock, int side, uint64_t events, filter_arg_t *arg)
7276404edcSAsim Jamshed {
7376404edcSAsim Jamshed 	socklen_t addrslen = sizeof(struct sockaddr) * 2;
7476404edcSAsim Jamshed 	struct connection *c;
7576404edcSAsim Jamshed 
7676404edcSAsim Jamshed 	c = calloc(sizeof(struct connection), 1);
7776404edcSAsim Jamshed 	if (!c)
7876404edcSAsim Jamshed 		return;
7976404edcSAsim Jamshed 
8076404edcSAsim Jamshed 	/* Fill values of the connection structure */
8176404edcSAsim Jamshed 	c->sock = sock;
8276404edcSAsim Jamshed 	if (mtcp_getpeername(mctx, c->sock, (void *)c->addrs, &addrslen,
83*05e3289cSYoungGyoun 						 MOS_SIDE_BOTH) < 0) {
8476404edcSAsim Jamshed 		perror("mtcp_getpeername");
8576404edcSAsim Jamshed 		/* it's better to stop here and do debugging */
8676404edcSAsim Jamshed 		exit(EXIT_FAILURE);
8776404edcSAsim Jamshed 	}
8876404edcSAsim Jamshed 
8976404edcSAsim Jamshed 	/* Insert the structure to the queue */
9076404edcSAsim Jamshed 	TAILQ_INSERT_TAIL(&g_sockq[mctx->cpu], c, link);
9176404edcSAsim Jamshed }
9276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
9376404edcSAsim Jamshed /* Destroy connection structure */
9476404edcSAsim Jamshed static void
cb_destroy(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)9576404edcSAsim Jamshed cb_destroy(mctx_t mctx, int sock, int side, uint64_t events, filter_arg_t *arg)
9676404edcSAsim Jamshed {
9776404edcSAsim Jamshed 	struct connection *c;
9876404edcSAsim Jamshed 
9976404edcSAsim Jamshed 	if (!(c = find_connection(mctx->cpu, sock)))
10076404edcSAsim Jamshed 		return;
10176404edcSAsim Jamshed 
10276404edcSAsim Jamshed 	TAILQ_REMOVE(&g_sockq[mctx->cpu], c, link);
10376404edcSAsim Jamshed 	free(c);
10476404edcSAsim Jamshed }
10576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
10676404edcSAsim Jamshed /* Update connection's TCP state of each side */
10776404edcSAsim Jamshed static void
cb_st_chg(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)10876404edcSAsim Jamshed cb_st_chg(mctx_t mctx, int sock, int side, uint64_t events, filter_arg_t *arg)
10976404edcSAsim Jamshed {
11076404edcSAsim Jamshed 	struct connection *c;
11176404edcSAsim Jamshed 	socklen_t intlen = sizeof(int);
11276404edcSAsim Jamshed 
11376404edcSAsim Jamshed 	if (!(c = find_connection(mctx->cpu, sock)))
11476404edcSAsim Jamshed 		return;
11576404edcSAsim Jamshed 
11676404edcSAsim Jamshed 	if (side == MOS_SIDE_CLI) {
11776404edcSAsim Jamshed 		if (mtcp_getsockopt(mctx, c->sock, SOL_MONSOCKET, MOS_TCP_STATE_CLI,
11876404edcSAsim Jamshed 						(void *)&c->cli_state, &intlen) < 0) {
11976404edcSAsim Jamshed 			perror("mtcp_getsockopt");
12076404edcSAsim Jamshed 			exit(-1); /* it's better to stop here and do debugging */
12176404edcSAsim Jamshed 		}
12276404edcSAsim Jamshed 	} else {
12376404edcSAsim Jamshed 		if (mtcp_getsockopt(mctx, c->sock, SOL_MONSOCKET, MOS_TCP_STATE_SVR,
12476404edcSAsim Jamshed 						(void *)&c->svr_state, &intlen) < 0) {
12576404edcSAsim Jamshed 			perror("mtcp_getsockopt");
12676404edcSAsim Jamshed 			exit(-1); /* it's better to stop here and do debugging */
12776404edcSAsim Jamshed 		}
12876404edcSAsim Jamshed 	}
12976404edcSAsim Jamshed }
13076404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
13176404edcSAsim Jamshed /* Convert state value (integer) to string (char array) */
13276404edcSAsim Jamshed const char *
strstate(int state)13376404edcSAsim Jamshed strstate(int state)
13476404edcSAsim Jamshed {
13576404edcSAsim Jamshed 	switch (state) {
13676404edcSAsim Jamshed #define CASE(s) case TCP_##s: return #s
13776404edcSAsim Jamshed 		CASE(CLOSED);
13876404edcSAsim Jamshed 		CASE(LISTEN);
13976404edcSAsim Jamshed 		CASE(SYN_SENT);
14076404edcSAsim Jamshed 		CASE(SYN_RCVD);
14176404edcSAsim Jamshed 		CASE(ESTABLISHED);
14276404edcSAsim Jamshed 		CASE(FIN_WAIT_1);
14376404edcSAsim Jamshed 		CASE(FIN_WAIT_2);
14476404edcSAsim Jamshed 		CASE(CLOSE_WAIT);
14576404edcSAsim Jamshed 		CASE(CLOSING);
14676404edcSAsim Jamshed 		CASE(LAST_ACK);
14776404edcSAsim Jamshed 		CASE(TIME_WAIT);
14876404edcSAsim Jamshed 		default:
14976404edcSAsim Jamshed 		return "-";
15076404edcSAsim Jamshed 	}
15176404edcSAsim Jamshed }
15276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
15376404edcSAsim Jamshed /* Print ongoing connection information based on connection structure */
15476404edcSAsim Jamshed static void
cb_printstat(mctx_t mctx,int sock,int side,uint64_t events,filter_arg_t * arg)15576404edcSAsim Jamshed cb_printstat(mctx_t mctx, int sock, int side,
15676404edcSAsim Jamshed 				  uint64_t events, filter_arg_t *arg)
15776404edcSAsim Jamshed {
15876404edcSAsim Jamshed 	int i;
15976404edcSAsim Jamshed 	struct connection *c;
16076404edcSAsim Jamshed 	struct timeval tv_1sec = { /* 1 second */
16176404edcSAsim Jamshed 		.tv_sec = 1,
16276404edcSAsim Jamshed 		.tv_usec = 0
16376404edcSAsim Jamshed 	};
16476404edcSAsim Jamshed 
16576404edcSAsim Jamshed 	printf("Proto CPU "
16676404edcSAsim Jamshed 		   "Client Address        Client State "
16776404edcSAsim Jamshed 		   "Server Address        Server State\n");
16876404edcSAsim Jamshed 	for (i = 0; i < g_max_cores; i++)
16976404edcSAsim Jamshed 		TAILQ_FOREACH(c, &g_sockq[i], link) {
17076404edcSAsim Jamshed 			int space;
17176404edcSAsim Jamshed 
17276404edcSAsim Jamshed 			printf("%-5s %-3d ", "tcp", i);
17376404edcSAsim Jamshed 			space = printf("%s:", inet_ntoa(c->addrs[MOS_SIDE_CLI].sin_addr));
17476404edcSAsim Jamshed 			printf("%*d %-12s ",
17576404edcSAsim Jamshed 					space - 21,
17676404edcSAsim Jamshed 					ntohs(c->addrs[MOS_SIDE_CLI].sin_port),
17776404edcSAsim Jamshed 					strstate(c->cli_state));
17876404edcSAsim Jamshed 			space = printf("%s:", inet_ntoa(c->addrs[MOS_SIDE_SVR].sin_addr));
17976404edcSAsim Jamshed 			printf("%*d %-12s\n",
18076404edcSAsim Jamshed 					space - 21,
18176404edcSAsim Jamshed 					ntohs(c->addrs[MOS_SIDE_SVR].sin_port),
18276404edcSAsim Jamshed 					strstate(c->svr_state));
18376404edcSAsim Jamshed 		}
18476404edcSAsim Jamshed 
18576404edcSAsim Jamshed 	/* Set a timer for next printing */
18676404edcSAsim Jamshed 	if (mtcp_settimer(mctx, sock, &tv_1sec, cb_printstat)) {
18776404edcSAsim Jamshed 		fprintf(stderr, "Failed to register print timer\n");
18876404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if the timer is broken */
18976404edcSAsim Jamshed 	}
19076404edcSAsim Jamshed 
19176404edcSAsim Jamshed 	return;
19276404edcSAsim Jamshed }
19376404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
19476404edcSAsim Jamshed /* Register required callbacks */
19576404edcSAsim Jamshed static void
RegisterCallbacks(mctx_t mctx,int sock,event_t ev_new_syn)19676404edcSAsim Jamshed RegisterCallbacks(mctx_t mctx, int sock, event_t ev_new_syn)
19776404edcSAsim Jamshed {
19876404edcSAsim Jamshed 	struct timeval tv_1sec = { /* 1 second */
19976404edcSAsim Jamshed 		.tv_sec = 1,
20076404edcSAsim Jamshed 		.tv_usec = 0
20176404edcSAsim Jamshed 	};
20276404edcSAsim Jamshed 
20376404edcSAsim Jamshed 	/* Register callbacks */
20476404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, sock, MOS_ON_CONN_START,
20576404edcSAsim Jamshed 				   MOS_HK_SND, cb_creation)) {
20676404edcSAsim Jamshed 		fprintf(stderr, "Failed to register cb_creation()\n");
20776404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if callback registration fails */
20876404edcSAsim Jamshed 	}
20976404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, sock, MOS_ON_CONN_END,
21076404edcSAsim Jamshed 				   MOS_HK_SND, cb_destroy)) {
21176404edcSAsim Jamshed 		fprintf(stderr, "Failed to register cb_destroy()\n");
21276404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if callback registration fails */
21376404edcSAsim Jamshed 	}
21476404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, sock, MOS_ON_TCP_STATE_CHANGE,
21576404edcSAsim Jamshed 				   MOS_HK_SND, cb_st_chg)) {
21676404edcSAsim Jamshed 		fprintf(stderr, "Failed to register cb_st_chg()\n");
21776404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if callback registration fails */
21876404edcSAsim Jamshed 	}
21976404edcSAsim Jamshed 	if (mtcp_register_callback(mctx, sock, MOS_ON_TCP_STATE_CHANGE,
22076404edcSAsim Jamshed 				   MOS_HK_RCV, cb_st_chg)) {
22176404edcSAsim Jamshed 		fprintf(stderr, "Failed to register cb_st_chg()\n");
22276404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if callback registration fails */
22376404edcSAsim Jamshed 	}
22476404edcSAsim Jamshed 
22576404edcSAsim Jamshed 	/* CPU 0 is in charge of printing stats */
22676404edcSAsim Jamshed 	if (mctx->cpu == 0 &&
22776404edcSAsim Jamshed 		mtcp_settimer(mctx, sock, &tv_1sec, cb_printstat)) {
22876404edcSAsim Jamshed 		fprintf(stderr, "Failed to register print timer\n");
22976404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if the titmer is broken*/
23076404edcSAsim Jamshed 	}
23176404edcSAsim Jamshed }
23276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
23376404edcSAsim Jamshed /* Open monitoring socket and ready it for monitoring */
23476404edcSAsim Jamshed static void
InitMonitor(mctx_t mctx,event_t ev_new_syn)23576404edcSAsim Jamshed InitMonitor(mctx_t mctx, event_t ev_new_syn)
23676404edcSAsim Jamshed {
23776404edcSAsim Jamshed 	int sock;
23876404edcSAsim Jamshed 
23976404edcSAsim Jamshed 	/* Initialize internal memory structures */
24076404edcSAsim Jamshed 	TAILQ_INIT(&g_sockq[mctx->cpu]);
24176404edcSAsim Jamshed 
24276404edcSAsim Jamshed 	/* create socket and set it as nonblocking */
24376404edcSAsim Jamshed 	if ((sock = mtcp_socket(mctx, AF_INET,
24476404edcSAsim Jamshed 						 MOS_SOCK_MONITOR_STREAM, 0)) < 0) {
24576404edcSAsim Jamshed 		fprintf(stderr, "Failed to create monitor listening socket!\n");
24676404edcSAsim Jamshed 		exit(-1); /* no point in proceeding if we don't have a listening socket */
24776404edcSAsim Jamshed 	}
24876404edcSAsim Jamshed 
24976404edcSAsim Jamshed 	/* Disable socket buffer */
25076404edcSAsim Jamshed 	int optval = 0;
25176404edcSAsim Jamshed 	if (mtcp_setsockopt(mctx, sock, SOL_MONSOCKET, MOS_CLIBUF,
25276404edcSAsim Jamshed 							   &optval, sizeof(optval)) == -1) {
25376404edcSAsim Jamshed 		fprintf(stderr, "Could not disable CLIBUF!\n");
25476404edcSAsim Jamshed 	}
25576404edcSAsim Jamshed 	if (mtcp_setsockopt(mctx, sock, SOL_MONSOCKET, MOS_SVRBUF,
25676404edcSAsim Jamshed 							   &optval, sizeof(optval)) == -1) {
25776404edcSAsim Jamshed 		fprintf(stderr, "Could not disable SVRBUF!\n");
25876404edcSAsim Jamshed 	}
25976404edcSAsim Jamshed 
26076404edcSAsim Jamshed 	RegisterCallbacks(mctx, sock, ev_new_syn);
26176404edcSAsim Jamshed }
26276404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
26376404edcSAsim Jamshed int
main(int argc,char ** argv)26476404edcSAsim Jamshed main(int argc, char **argv)
26576404edcSAsim Jamshed {
26676404edcSAsim Jamshed 	int i, opt;
26776404edcSAsim Jamshed 	event_t ev_new_syn;             /* New SYN UDE */
26876404edcSAsim Jamshed 	char *fname = MOS_CONFIG_FILE;  /* path to the default mos config file */
26976404edcSAsim Jamshed 	struct mtcp_conf mcfg;          /* mOS configuration */
27076404edcSAsim Jamshed 
27176404edcSAsim Jamshed 	/* get the total # of cpu cores */
27276404edcSAsim Jamshed 	g_max_cores = GetNumCPUs();
27376404edcSAsim Jamshed 
27476404edcSAsim Jamshed 	/* Parse command line arguments */
27576404edcSAsim Jamshed 	while ((opt = getopt(argc, argv, "c:f:")) != -1) {
27676404edcSAsim Jamshed 		switch (opt) {
27776404edcSAsim Jamshed 		case 'f':
27876404edcSAsim Jamshed 			fname = optarg;
27976404edcSAsim Jamshed 			break;
28076404edcSAsim Jamshed 		case 'c':
28176404edcSAsim Jamshed 			if (atoi(optarg) > g_max_cores) {
28276404edcSAsim Jamshed 				printf("Available number of CPU cores is %d\n", g_max_cores);
28376404edcSAsim Jamshed 				return -1;
28476404edcSAsim Jamshed 			}
28576404edcSAsim Jamshed 			g_max_cores = atoi(optarg);
28676404edcSAsim Jamshed 			break;
28776404edcSAsim Jamshed 		default:
28876404edcSAsim Jamshed 			printf("Usage: %s [-f mos_config_file] [-c #_of_cpu]\n", argv[0]);
28976404edcSAsim Jamshed 			return 0;
29076404edcSAsim Jamshed 		}
29176404edcSAsim Jamshed 	}
29276404edcSAsim Jamshed 
29376404edcSAsim Jamshed 	/* parse mos configuration file */
29476404edcSAsim Jamshed 	if (mtcp_init(fname)) {
29576404edcSAsim Jamshed 		fprintf(stderr, "Failed to initialize mtcp.\n");
29676404edcSAsim Jamshed 		exit(EXIT_FAILURE);
29776404edcSAsim Jamshed 	}
29876404edcSAsim Jamshed 
29976404edcSAsim Jamshed 	/* set the core limit */
30076404edcSAsim Jamshed 	mtcp_getconf(&mcfg);
30176404edcSAsim Jamshed 	mcfg.num_cores = g_max_cores;
30276404edcSAsim Jamshed 	mtcp_setconf(&mcfg);
30376404edcSAsim Jamshed 
30476404edcSAsim Jamshed 	/* Register signal handler */
30576404edcSAsim Jamshed 	mtcp_register_signal(SIGINT, sigint_handler);
30676404edcSAsim Jamshed 
30776404edcSAsim Jamshed 	for (i = 0; i < g_max_cores; i++) {
30876404edcSAsim Jamshed 		/* Run mOS for each CPU core */
30976404edcSAsim Jamshed 		if (!(g_mctx[i] = mtcp_create_context(i))) {
31076404edcSAsim Jamshed 			fprintf(stderr, "Failed to craete mtcp context.\n");
31176404edcSAsim Jamshed 			return -1;
31276404edcSAsim Jamshed 		}
31376404edcSAsim Jamshed 
31476404edcSAsim Jamshed 		/* init monitor */
31576404edcSAsim Jamshed 		InitMonitor(g_mctx[i], ev_new_syn);
31676404edcSAsim Jamshed 	}
31776404edcSAsim Jamshed 
31876404edcSAsim Jamshed 	/* wait until mOS finishes */
31976404edcSAsim Jamshed 	for (i = 0; i < g_max_cores; i++)
32076404edcSAsim Jamshed 		mtcp_app_join(g_mctx[i]);
32176404edcSAsim Jamshed 
32276404edcSAsim Jamshed 	mtcp_destroy();
32376404edcSAsim Jamshed 	return 0;
32476404edcSAsim Jamshed }
32576404edcSAsim Jamshed /*----------------------------------------------------------------------------*/
326