From 597482dad495d5f087b7c78264b95adb2968cc88 Mon Sep 17 00:00:00 2001 From: Jerome Stanislaus Date: Fri, 4 Mar 2016 14:08:46 -0700 Subject: datatop: add support to capture ip table stats With the new -r option, datatop will now capture IP table stats every 5sec on a separate thread without affecting the normal datatop polling. CRs-fixed: 979414 Change-Id: Ia90b565f370a0c4983381e7c2ab84315d53728db --- datatop/src/Android.mk | 1 + datatop/src/Makefile.am | 1 + datatop/src/datatop.c | 19 +- datatop/src/datatop_fileops.c | 37 +++- datatop/src/datatop_fileops.h | 4 +- datatop/src/datatop_ip_table_poll.c | 346 ++++++++++++++++++++++++++++++++++++ datatop/src/datatop_opt.c | 35 +++- datatop/src/datatop_opt.h | 5 +- datatop/src/datatop_polling.h | 4 +- 9 files changed, 445 insertions(+), 7 deletions(-) create mode 100644 datatop/src/datatop_ip_table_poll.c diff --git a/datatop/src/Android.mk b/datatop/src/Android.mk index 6b93c9f..9270110 100644 --- a/datatop/src/Android.mk +++ b/datatop/src/Android.mk @@ -17,6 +17,7 @@ LOCAL_SRC_FILES += datatop_stat_poll.c LOCAL_SRC_FILES += datatop_str.c LOCAL_SRC_FILES += datatop_sys_snap.c LOCAL_SRC_FILES += datatop_value_only_poll.c +LOCAL_SRC_FILES += datatop_ip_table_poll.c LOCAL_CFLAGS := -Wall -Wextra -Werror -pedantic -std=c99 LOCAL_CFLAGS += -DVERSION="\"1.0.4"\" diff --git a/datatop/src/Makefile.am b/datatop/src/Makefile.am index 5dd0469..8ac8014 100644 --- a/datatop/src/Makefile.am +++ b/datatop/src/Makefile.am @@ -20,3 +20,4 @@ datatop_SOURCES += datatop_linked_list.c datatop_SOURCES += datatop_opt.c datatop_SOURCES += datatop_gen_poll.c datatop_SOURCES += datatop_sys_snap.c +datatop_SOURCES += datatop_ip_table_poll.c diff --git a/datatop/src/datatop.c b/datatop/src/datatop.c index 82022a3..da8e74d 100644 --- a/datatop/src/datatop.c +++ b/datatop/src/datatop.c @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -46,6 +46,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "datatop_interface.h" #include "datatop_linked_list.h" #include "datatop_opt.h" @@ -175,6 +176,7 @@ static void dtop_set_niceness(int niceness) int main(int argc, char **argv) { int parse_status; + pthread_t tid; printf("DataTop - Version %s\n", VERSION); printf("(c)2014-2015 Linux Foundation\n"); @@ -197,6 +199,13 @@ int main(int argc, char **argv) break; } + if (usr_cl_opts.iptables_rules_routes == OPT_CHOSE) { + if (!usr_cl_opts.out_dir) { + printf("Please provide an out directory.\n"); + exit(EXIT_FAILURE); + } + } + dtop_dual_line_init("/proc/net/netstat"); dtop_dual_line_init("/proc/net/snmp"); dtop_single_line_init("/proc/net/snmp6"); @@ -213,6 +222,14 @@ int main(int argc, char **argv) dtop_gen_init("/sys/kernel/debug/clk/snoc_clk/"); dtop_gen_init("/sys/kernel/debug/clk/pnoc_clk/"); + if (usr_cl_opts.iptables_rules_routes == OPT_CHOSE) { + printf("Datatop IP Tables, rules, routes\n"); + dtop_ip_table_init(usr_cl_opts.out_dir); + if(0 != pthread_create(&tid, NULL, &dtop_ip_table_start_poll, NULL)) { + printf("Unable to create capture_ip_tables_rules_routes thread\n"); + } + } + if (usr_cl_opts.print_cl == OPT_CHOSE) { dtop_poll(first_dpg_list); dtop_print_terminal(first_dpg_list); diff --git a/datatop/src/datatop_fileops.c b/datatop/src/datatop_fileops.c index b4c866c..9ff06b5 100644 --- a/datatop/src/datatop_fileops.c +++ b/datatop/src/datatop_fileops.c @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -40,6 +40,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "datatop_interface.h" #include "datatop_linked_list.h" #include "datatop_opt.h" @@ -113,6 +114,40 @@ int dtop_check_writefile_access(char *fw) return VALID; } +/** + * @brief Checks for the presence of a dir. + * + * @param fw Dir to check the presence + * @return INVALID - Out dir doesn't exist. + * @return VALID - Out dir exist and can be written to. + */ +int dtop_check_out_dir_presence(char *fw) +{ + if (access(fw, F_OK)) { + printf("Out dir not present\n"); + return INVALID; + } + + return VALID; +} + +/** + * @brief Creates a directory + * + * @param New directory full path. + * @return INVALID - Out dir doesn't exist or write access denied. + * @return VALID - Out dir exist and can be written to. + */ +int dtop_create_dir(char *full_path) +{ + if (!mkdir(full_path, 0755)) { + printf("Unable to create dir: %s, errno: %d\n", full_path, errno); + return INVALID; + } + + return VALID; +} + /** * @brief Opens file and handles possible errors. * diff --git a/datatop/src/datatop_fileops.h b/datatop/src/datatop_fileops.h index 0078e06..9d60a41 100644 --- a/datatop/src/datatop_fileops.h +++ b/datatop/src/datatop_fileops.h @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -42,6 +42,8 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. int dt_read_file(const char *file, char **buffer, int len); void dt_free(char **buffer); int dtop_check_writefile_access(char *fw); +int dtop_check_out_dir_presence(char *fw); +int dtop_create_dir(char *full_path); int dtop_open_writing_file(char *fw, FILE **to_file); void dtop_close_file(FILE *fw); int dtop_get_file_line_amount(char *file); diff --git a/datatop/src/datatop_ip_table_poll.c b/datatop/src/datatop_ip_table_poll.c new file mode 100644 index 0000000..980eb4c --- /dev/null +++ b/datatop/src/datatop_ip_table_poll.c @@ -0,0 +1,346 @@ +/************************************************************************ +Copyright (c) 2016, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +************************************************************************/ + +/** + * @file datatop_ip_table_poll.c + * @brief Adds ability for TP Tables, Rules and Routes data collection + Unlike other polls, this is intended for running as a separate + thread as it can cause delays of > 3sec per poll + * + */ + +#include +#include +#include +#include +#include +#include +#include "datatop_interface.h" +#include "datatop_fileops.h" +#include "datatop_str.h" +#include "datatop_polling.h" + +#define DTOP_IPTRR_POLL_PERIOD 5.00 + +/** +* @struct dtop_ip_table_vars +* @brief Struct used to hold necessary variables for /proc/stat dpg +* +* @var dtop_ip_table_vars::line +* Array of strings where necessary dp names and values are held. +* @var dtop_ip_table_vars::line_count +* Number of lines the file is that the dpg represents. +*/ +struct dtop_ip_table_vars { + char *out_dir; +}dtop_ip_table_storage; + +struct dtop_linked_list *ip_dpg_list = NULL; + +pthread_mutex_t dtop_ip_table_lock; + +/** + * @brief Perform IP table command and store it in a file + * + * @param dpg Struct that polled data is added to. + * @return DTOP_POLL_IO_ERR - Poll of dpg unsuccessful. + * @return DTOP_POLL_OK - Poll of dpg successful. + */ +int dtop_ip_table_poll(struct dtop_data_point_gatherer *dpg) +{ + FILE *fd; + FILE *fo = (FILE *)dpg->file; + char buf[1001]; + + time_t rawtime; + struct tm * timeinfo; + + if(fo == NULL) + { + fprintf(stderr, "Could not fopen: %s\n", dpg->file); + return DTOP_POLL_IO_ERR; + } + + time ( &rawtime ); + timeinfo = gmtime ( &rawtime ); + + fprintf ( fo, "============\nStart: %s==========\n", asctime (timeinfo) ); + fflush(fo); + + /* redirect stderr to output file */ + dup2(fileno(fo), 2); + + fd = popen((char *)dpg->priv, "r"); + if(fd == NULL) + { + fprintf(stderr, "Could not popen: %s\n", (char *)dpg->priv); + return DTOP_POLL_IO_ERR; + } + + while(fgets(buf, 1000, fd) != NULL) + { + fputs(buf, fo); + } + + fprintf ( fo, "============\nEnd: %s==========\n\n", asctime (timeinfo) ); + fflush(fo); + pclose(fd); + return DTOP_POLL_OK; +} + +/** + * @brief Frees dynamically allocated IP table dpg. + * + * Frees the memory of the dpg along with it's data_points + * and other malloc'd memory no longer needed. + * + * @param dpg Dpg to deconstruct and deallocate memory for. + */ +static void dtop_ip_table_dpg_deconstructor + (struct dtop_data_point_gatherer *dpset) +{ + int i; + free(dpset->prefix); + if(dpset->file) + { + fclose((FILE *)dpset->file); + } + + free(dpset); +} + +/** + * @brief Registers a new IP table dpg to the list. + * + * @param dpg Dpg to construct and allocate memory for. + */ +void dtop_ip_table_register(struct dtop_data_point_gatherer *dpg) +{ + if (dpg) + ip_dpg_list = dtop_add_linked_list(dpg, ip_dpg_list); +} + +/** + * @brief Open the files for writing the output for each dpg. + * + * @param None + */ +int dtop_ip_table_init_files() +{ + struct dtop_data_point_gatherer *dpset; + struct dtop_linked_list *curr_ptr = ip_dpg_list; + FILE *fd; + + while(curr_ptr) + { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + fd = fopen(dpset->prefix, "a+"); + if(!fd) + { + fprintf(stderr, "Could not fopen: %s\n", dpset->prefix); + return DTOP_POLL_IO_ERR; + } + dpset->file = (char *)fd; + curr_ptr = curr_ptr->next_ptr; + } + return DTOP_POLL_OK; +} + +/** + * @brief Perform cleanup of IP table dgp list at exit. + * + * @param None + */ +void dtop_ip_table_poll_cleanup() +{ + struct dtop_data_point_gatherer *dpset; + struct dtop_linked_list *curr_ptr = ip_dpg_list; + + pthread_mutex_lock(&dtop_ip_table_lock); + deconstruct_dpgs(ip_dpg_list); + dtop_rem_linked_list(ip_dpg_list); + pthread_mutex_unlock(&dtop_ip_table_lock); + +} + +/** + * @brief The thread to poll for IP table data. + * + * @param arg ptr + */ +void *dtop_ip_table_start_poll(void *arg) +{ + time_t start_t, curr_t; + double diff_t = 9999999.00; /* some high # > DTOP_IPTRR_POLL_PERIOD */ + int ret = DTOP_POLL_OK; + + if (pthread_mutex_init(&dtop_ip_table_lock, NULL) != 0) + { + printf("\n mutex init failed\n"); + return NULL; + } + + atexit(dtop_ip_table_poll_cleanup); + + if(DTOP_POLL_OK != ( ret = dtop_ip_table_init_files())) + { + return NULL; + } + + while(1) + { + struct dtop_linked_list *curr_ptr = ip_dpg_list; + struct dtop_data_point_gatherer *dpset; + + pthread_mutex_lock(&dtop_ip_table_lock); + + if (diff_t >= DTOP_IPTRR_POLL_PERIOD) + { + printf("Poll for IP Tables, Rules & Routes\n"); + time(&start_t); + while (curr_ptr) + { + dpset = (struct dtop_data_point_gatherer *) curr_ptr->data; + dpset->poll(dpset); + curr_ptr = curr_ptr->next_ptr; + } + } + pthread_mutex_unlock(&dtop_ip_table_lock); + + /* sleep for 500 milliseconds */ + usleep(500 * 1000); + time(&curr_t); + diff_t = difftime(curr_t, start_t); + } + return NULL; +} + +/** + * @brief Creates a dpg for ip table command + * + * Dynamically allocates memory for dpg which is then added to a linked list + * via the dtop_register(dpg) function call. + * + * @param data_points dtop_data_point struct that dpg points to. + * @param storage dtop_ip_table_vars struct that holds relevant dpg variables. + */ +/*static void construct_ip_table_dpg(struct dtop_data_point + *data_points, struct dtop_ip_table_vars *command, int dp_count) +*/ +static void construct_ip_table_dpg(char *command) +{ + struct dtop_data_point_gatherer *dpg = malloc + (sizeof(struct dtop_data_point_gatherer)); + char *file_name = (char *)malloc(strlen(command)+ 1 + 1 + strlen(dtop_ip_table_storage.out_dir) + 4); + int i, fname_start_ind; + + strcpy(file_name, dtop_ip_table_storage.out_dir); + strcat(file_name, "/"); + + fname_start_ind = strlen(file_name); + strcat(file_name, command); + strcat(file_name, ".txt"); + + for(i=fname_start_ind; file_name[i]; i++) + { + if(file_name[i] == ' ') + file_name[i] = '_'; + if(file_name[i] == '/') + file_name[i] = '-'; + } + + dpg->prefix = file_name; + dpg->poll = dtop_ip_table_poll; + dpg->priv = (char *)command; + dpg->file = NULL; + dpg->deconstruct = dtop_ip_table_dpg_deconstructor; + + dtop_ip_table_register(dpg); +} + +/* + * @brief Scans "/proc/stat" in order to autodetect dps. + * + * Searches through "/proc/stat" file for all available data + * points to create as dp structs. + * + * @param storage dtop_ip_table_vars struct where relevant variables are stored. + */ + +/** + * @brief Calls dtop_search for "/proc/stat" file. + */ +void dtop_ip_table_init(char *out_dir) +{ + dtop_ip_table_storage.out_dir = out_dir; + construct_ip_table_dpg("ip xfrm state show"); + construct_ip_table_dpg("ip xfrm policy show"); + construct_ip_table_dpg("ip addr"); + construct_ip_table_dpg("iptables -t raw -L -n -v"); + construct_ip_table_dpg("iptables -t mangle -L -n -v"); + construct_ip_table_dpg("iptables -L -n -v"); + construct_ip_table_dpg("iptables -t nat -L -n -v"); + construct_ip_table_dpg("ip6tables -t raw -L -n -v"); + construct_ip_table_dpg("ip6tables -t mangle -L -n -v"); + construct_ip_table_dpg("ip6tables -L -n -v"); + construct_ip_table_dpg("ip6tables -t nat -L -n -v"); + construct_ip_table_dpg("ip rule show"); + construct_ip_table_dpg("ip -6 rule show"); + construct_ip_table_dpg("ip route show table all"); + construct_ip_table_dpg("ip -6 route show table all"); + construct_ip_table_dpg("ip route show table rmnet_data0"); + construct_ip_table_dpg("ip route show table rmnet_data1"); + construct_ip_table_dpg("ip route show table rmnet_data2"); + construct_ip_table_dpg("ip route show table rmnet_data6"); + construct_ip_table_dpg("ip route show table rmnet_data7"); + construct_ip_table_dpg("ip route show table r_rmnet_data0"); + construct_ip_table_dpg("ip route show table r_rmnet_data1"); + construct_ip_table_dpg("ip route show table r_rmnet_data2"); + construct_ip_table_dpg("ip route show table r_rmnet_data6"); + construct_ip_table_dpg("ip route show table r_rmnet_data7"); + construct_ip_table_dpg("ip -6 route show table rmnet_data0"); + construct_ip_table_dpg("ip -6 route show table rmnet_data1"); + construct_ip_table_dpg("ip -6 route show table rmnet_data2"); + construct_ip_table_dpg("ip -6 route show table rmnet_data6"); + construct_ip_table_dpg("ip -6 route show table rmnet_data7"); + construct_ip_table_dpg("ip -6 route show table r_rmnet_data0"); + construct_ip_table_dpg("ip -6 route show table r_rmnet_data1"); + construct_ip_table_dpg("ip -6 route show table r_rmnet_data2"); + construct_ip_table_dpg("ip -6 route show table r_rmnet_data6"); + construct_ip_table_dpg("ip -6 route show table r_rmnet_data7"); + construct_ip_table_dpg("ip route show table wlan0"); + construct_ip_table_dpg("ip -6 route show table wlan0"); + construct_ip_table_dpg("ip route show table dummy0"); + construct_ip_table_dpg("ip -6 route show table dummy0"); + construct_ip_table_dpg("cat /proc/net/xfrm_stat"); + construct_ip_table_dpg("cat /proc/sys/net/ipv4/ip_forward"); + construct_ip_table_dpg("cat /proc/sys/net/ipv6/conf/all/forwarding"); + + printf("Poll for IP Tables, Rules & Routes every 5 seconds\n"); +} diff --git a/datatop/src/datatop_opt.c b/datatop/src/datatop_opt.c index c2bb366..b10f593 100644 --- a/datatop/src/datatop_opt.c +++ b/datatop/src/datatop_opt.c @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -42,6 +42,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "datatop_opt.h" #include "datatop_interface.h" #include "datatop_linked_list.h" @@ -72,13 +73,20 @@ void dtop_load_default_options(struct cli_opts *clopts) int dtop_parse_cli_opts(struct cli_opts *clopts, int argc, char **argv) { int option; + time_t rawtime; + struct tm * timeinfo; + char timestamp[100]; + + time ( &rawtime ); + timeinfo = gmtime ( &rawtime ); + strftime (timestamp, 100,"%F_%H-%M-%S",timeinfo); if (!clopts || !*argv) { printf("Internal Error: Null Pointer\n"); goto error; } - while ((option = getopt(argc, argv, "phi:t:w:s:n:")) != -1) { + while ((option = getopt(argc, argv, "phri:t:w:o:s:n:")) != -1) { switch (option) { case 'p': clopts->print_cl = OPT_CHOSE; @@ -126,6 +134,23 @@ int dtop_parse_cli_opts(struct cli_opts *clopts, int argc, char **argv) } break; + case 'o': + if (dtop_check_out_dir_presence(optarg) != VALID) { + goto error; + } + + if(strlen(optarg) + strlen(timestamp) > OUT_DIR_LEN_MAX) { + printf("Out dir too long!"); + goto error; + } + strcpy(clopts->out_dir, optarg); + strcat(clopts->out_dir, "/"); + strcat(clopts->out_dir, timestamp); + if(dtop_create_dir(clopts->out_dir) != INVALID) { + goto error; + } + break; + case 's': if (dtop_check_writefile_access(optarg) == VALID) clopts->snapshot_file = optarg; @@ -133,6 +158,10 @@ int dtop_parse_cli_opts(struct cli_opts *clopts, int argc, char **argv) goto error; break; + case 'r': + clopts->iptables_rules_routes = OPT_CHOSE; + break; + case '?': default: goto error; @@ -167,6 +196,8 @@ void dtop_print_help_opts(void) printf("\t-w , file name (.csv)\tWrite output to a file\n"); printf("\t-s , file name\t\tPrint system snapshot to a file\n"); printf("\t-n , nice value\t\tSet niceness (default 19)\n"); + printf("\t-r , \t\t\tCapture IPTables, Rules and Routes\n"); + printf("\t-o , out directory for -w options\t\tOut dir where the set of files are saved\n"); printf("\t-h\t\t\tGet help\n"); } diff --git a/datatop/src/datatop_opt.h b/datatop/src/datatop_opt.h index 8f2d855..a1ad288 100644 --- a/datatop/src/datatop_opt.h +++ b/datatop/src/datatop_opt.h @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -49,6 +49,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define VALID 0 #define INVALID -1 #define DEFAULT_NICE 19 /* Lowest priority */ +#define OUT_DIR_LEN_MAX 150 /** * @struct cli_opts @@ -74,6 +75,8 @@ struct cli_opts { int cli_help; /* -h option */ char *file_name; /* -w option */ char *snapshot_file; /* -s option */ + int iptables_rules_routes; /* -r option */ + char out_dir[OUT_DIR_LEN_MAX]; /* -o option */ int print_csv; int poll_time_selected; int priority; /* -n option (niceness) */ diff --git a/datatop/src/datatop_polling.h b/datatop/src/datatop_polling.h index d917474..53d2c1b 100644 --- a/datatop/src/datatop_polling.h +++ b/datatop/src/datatop_polling.h @@ -1,5 +1,5 @@ /************************************************************************ -Copyright (c) 2015, The Linux Foundation. All rights reserved. +Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are @@ -41,6 +41,8 @@ void dtop_value_only_init(char *name); void dtop_meminfo_init(void); void dtop_dev_init(void); void dtop_stat_init(void); +void dtop_ip_table_init(char *out_dir); +void *dtop_ip_table_start_poll(void * arg); void dtop_cpu_stats_init(void); int dtop_value_only_poll(struct dtop_data_point_gatherer *dpg); void dtop_value_only_dpg_deconstructor -- cgit v1.2.3