From 8b3c3abb6326dd0bcde8c77d913dfa586ddf3c47 Mon Sep 17 00:00:00 2001 From: "osdl.net!shemminger" Date: Tue, 19 Oct 2004 20:21:14 +0000 Subject: [PATCH] Initial revision --- README.lnstat | 0 misc/README.lnstat | 81 ----------- misc/lnstat.c | 336 --------------------------------------------- misc/lnstat.h | 43 ------ misc/lnstat_util.c | 323 ------------------------------------------- 5 files changed, 783 deletions(-) create mode 100644 README.lnstat diff --git a/README.lnstat b/README.lnstat new file mode 100644 index 00000000..e69de29b diff --git a/misc/README.lnstat b/misc/README.lnstat index 057925f6..e69de29b 100644 --- a/misc/README.lnstat +++ b/misc/README.lnstat @@ -1,81 +0,0 @@ -lnstat - linux networking statistics -(C) 2004 Harald Welte - * - * Development of this code was funded by Astaro AG, http://www.astaro.com/ - * - * Based on original concept and ideas from predecessor rtstat.c: - * - * Copyright 2001 by Robert Olsson - * Uppsala University, Sweden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -/* Maximum number of fields that can be displayed */ -#define MAX_FIELDS 64 - -/* Maximum number of header lines */ -#define HDR_LINES 10 - -/* default field width if none specified */ -#define FIELD_WIDTH_DEFAULT 8 -#define FIELD_WIDTH_MAX 20 - -#define DEFAULT_INTERVAL 2 - -#define HDR_LINE_LENGTH (MAX_FIELDS*FIELD_WIDTH_MAX) - -#include -#include -#include -#include -#include - -#include "lnstat.h" - -static struct option opts[] = { - { "version", 0, NULL, 'V' }, - { "count", 1, NULL, 'c' }, - { "dump", 1, NULL, 'd' }, - { "file", 1, NULL, 'f' }, - { "help", 0, NULL, 'h' }, - { "interval", 1, NULL, 'i' }, - { "key", 1, NULL, 'k' }, - { "subject", 1, NULL, 's' }, - { "width", 1, NULL, 'w' }, -}; - -static int usage(char *name, int exit_code) -{ - fprintf(stderr, "%s Version %s\n", name, LNSTAT_VERSION); - fprintf(stderr, "Copyright (C) 2004 by Harald Welte " - "\n"); - fprintf(stderr, "This program is free software licensed under GNU GPLv2" - "\nwith ABSOLUTELY NO WARRANTY.\n\n"); - fprintf(stderr, "Parameters:\n"); - fprintf(stderr, "\t-V --version\t\tPrint Version of Program\n"); - fprintf(stderr, "\t-c --count \t" - "Print number of intervals\n"); - fprintf(stderr, "\t-d --dumpt\t\t" - "Dump list of available files/keys\n"); - fprintf(stderr, "\t-f --file \tStatistics file to use\n"); - fprintf(stderr, "\t-h --help\t\tThis help message\n"); - fprintf(stderr, "\t-i --interval \t" - "Set interval to 'intv' seconds\n"); - fprintf(stderr, "\t-k --keys k,k,k,...\tDisplay only keys specified\n"); - fprintf(stderr, "\t-s --subject [0-2]\t?\n"); - fprintf(stderr, "\t-w --width n,n,n,...\tWidth for each field\n"); - fprintf(stderr, "\n"); - - exit(exit_code); -} - -struct field_param { - char *name; - struct lnstat_field *lf; - struct { - unsigned int width; - } print; -}; - -struct field_params { - unsigned int num; - struct field_param params[MAX_FIELDS]; -}; - -static void print_line(FILE *of, struct lnstat_file *lnstat_files, - struct field_params *fp) -{ - int i; - - for (i = 0; i < fp->num; i++) { - struct lnstat_field *lf = fp->params[i].lf; - char formatbuf[255]; - - snprintf(formatbuf, sizeof(formatbuf)-1, "%%%ulu|", - fp->params[i].print.width); - fprintf(of, formatbuf, lf->result); - } - fputc('\n', of); -} - -/* find lnstat_field according to user specification */ -static int map_field_params(struct lnstat_file *lnstat_files, - struct field_params *fps, int interval) -{ - int i, j = 0; - struct lnstat_file *lf; - - /* no field specification on commandline, need to build default */ - if (!fps->num) { - for (lf = lnstat_files; lf; lf = lf->next) { - for (i = 0; i < lf->num_fields; i++) { - fps->params[j].lf = &lf->fields[i]; - fps->params[j].lf->file->interval.tv_sec = - interval; - if (!fps->params[j].print.width) - fps->params[j].print.width = - FIELD_WIDTH_DEFAULT; - j++; - } - } - fps->num = j; - return 1; - } - - for (i = 0; i < fps->num; i++) { - fps->params[i].lf = lnstat_find_field(lnstat_files, - fps->params[i].name); - if (!fps->params[i].lf) { - fprintf(stderr, "Field `%s' unknown\n", - fps->params[i].name); - return 0; - } - fps->params[i].lf->file->interval.tv_sec = interval; - if (!fps->params[i].print.width) - fps->params[i].print.width = FIELD_WIDTH_DEFAULT; - } - return 1; -} - -struct table_hdr { - int num_lines; - char *hdr[HDR_LINES]; -}; - -static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files, - struct field_params *fps, - int linewidth) -{ - int h,i; - static struct table_hdr th; - int ofs = 0; - - for (i = 0; i < HDR_LINES; i++) { - th.hdr[i] = malloc(HDR_LINE_LENGTH); - memset(th.hdr[i], 0, sizeof(th.hdr[i])); - } - - for (i = 0; i < fps->num; i++) { - char *cname, *fname = fps->params[i].lf->name; - char fmt[12]; - unsigned int width = fps->params[i].print.width; - - snprintf(fmt, sizeof(fmt)-1, "%%%u.%us|", width, width); - - snprintf(th.hdr[0]+ofs, width+2, fmt, - fps->params[i].lf->file->basename); - - cname = fname; - for (h = 1; h < HDR_LINES; h++) { - if (cname - fname >= strlen(fname)) - snprintf(th.hdr[h]+ofs, width+2, fmt, ""); - else { - th.num_lines = h+1; - snprintf(th.hdr[h]+ofs, width+2, fmt, cname); - } - cname += width; - } - ofs += width+1; - } - /* fill in spaces */ - for (h = 1; h <= th.num_lines; h++) { - for (i = 0; i < ofs; i++) { - if (th.hdr[h][i] == '\0') - th.hdr[h][i] = ' '; - } - } - - return &th; -} - -static int print_hdr(FILE *of, struct table_hdr *th) -{ - int i; - - for (i = 0; i < th->num_lines; i++) { - fputs(th->hdr[i], of); - fputc('\n', of); - } - return 0; -} - - -int main(int argc, char **argv) -{ - struct lnstat_file *lnstat_files; - char *basename; - int c; - - int interval = DEFAULT_INTERVAL; - int hdr = 2; - - enum { - MODE_DUMP, - MODE_NORMAL, - } mode; - unsigned long count = 0; - struct field_params fp; - int num_req_files = 0; - char *req_files[LNSTAT_MAX_FILES]; - - memset(&fp, 0, sizeof(fp)); - - mode = MODE_NORMAL; - - /* backwards compatibility mode for old tools */ - basename = strrchr(argv[0], '/') + 1; - if (!strcmp(basename, "rtstat")) { - /* rtstat compatibility mode */ - req_files[0] = "rt_cache"; - num_req_files = 1; - } else if (!strcmp(basename, "ctstat")) { - /* ctstat compatibility mode */ - req_files[0] = "ip_conntrack"; - num_req_files = 1; - } - - while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:", - opts, NULL)) != -1) { - switch (c) { - int i, len; - char *tmp, *tok; - case 'c': - count = strtoul(optarg, NULL, 0); - break; - case 'd': - mode = MODE_DUMP; - break; - case 'f': - req_files[num_req_files++] = strdup(optarg); - break; - case '?': - case 'h': - usage(argv[0], 0); - break; - case 'i': - sscanf(optarg, "%u", &interval); - break; - case 'k': - tmp = strdup(optarg); - if (!tmp) - break; - for (tok = strtok(tmp, ","); - tok; - tok = strtok(NULL, ",")) { - if (fp.num >= MAX_FIELDS) - break; - fp.params[fp.num++].name = tok; - } - break; - case 's': - sscanf(optarg, "%u", &hdr); - break; - case 'w': - tmp = strdup(optarg); - if (!tmp) - break; - i = 0; - for (tok = strtok(tmp, ","); - tok; - tok = strtok(NULL, ",")) { - len = strtoul(tok, NULL, 0); - if (len > FIELD_WIDTH_MAX) - len = FIELD_WIDTH_MAX; - fp.params[i].print.width = len; - i++; - } - if (i == 1) { - for (i = 0; i < MAX_FIELDS; i++) - fp.params[i].print.width = len; - } - break; - default: - usage(argv[0], 1); - break; - } - } - - lnstat_files = lnstat_scan_dir(PROC_NET_STAT, num_req_files, - (const char **) req_files); - - switch (mode) { - int i; - struct table_hdr *header; - case MODE_DUMP: - lnstat_dump(stderr, lnstat_files); - break; - case MODE_NORMAL: - - if (!map_field_params(lnstat_files, &fp, interval)) - exit(1); - - header = build_hdr_string(lnstat_files, &fp, 80); - if (!header) - exit(1); - - if (interval < 1 ) - interval=1; - - for (i = 0; i < count; i++) { - if ((hdr > 1 && (! (i % 20))) || (hdr == 1 && i == 0)) - print_hdr(stdout, header); - lnstat_update(lnstat_files); - print_line(stdout, lnstat_files, &fp); - sleep(interval); - } - } - - return 1; -} - diff --git a/misc/lnstat.h b/misc/lnstat.h index 8bd7ede9..e69de29b 100644 --- a/misc/lnstat.h +++ b/misc/lnstat.h @@ -1,43 +0,0 @@ -#ifndef _LNSTAT_H -#define _LNSTAT_H - -#include - -#define LNSTAT_VERSION "0.02 041002" - -#define PROC_NET_STAT "/proc/net/stat" - -#define LNSTAT_MAX_FILES 32 -#define LNSTAT_MAX_FIELDS_PER_LINE 32 -#define LNSTAT_MAX_FIELD_NAME_LEN 32 - -struct lnstat_file; - -struct lnstat_field { - struct lnstat_file *file; - unsigned int num; /* field number in line */ - char name[LNSTAT_MAX_FIELD_NAME_LEN+1]; - unsigned long values[2]; /* two buffers for values */ - unsigned long result; -}; - -struct lnstat_file { - struct lnstat_file *next; - char path[PATH_MAX+1]; - char basename[NAME_MAX+1]; - struct timeval last_read; /* last time of read */ - struct timeval interval; /* interval */ - int compat; /* 1 == backwards compat mode */ - FILE *fp; - unsigned int num_fields; /* number of fields */ - struct lnstat_field fields[LNSTAT_MAX_FIELDS_PER_LINE]; -}; - - -struct lnstat_file *lnstat_scan_dir(const char *path, const int num_req_files, - const char **req_files); -int lnstat_update(struct lnstat_file *lnstat_files); -int lnstat_dump(FILE *outfd, struct lnstat_file *lnstat_files); -struct lnstat_field *lnstat_find_field(struct lnstat_file *lnstat_files, - char *name); -#endif /* _LNSTAT_H */ diff --git a/misc/lnstat_util.c b/misc/lnstat_util.c index c694b289..e69de29b 100644 --- a/misc/lnstat_util.c +++ b/misc/lnstat_util.c @@ -1,323 +0,0 @@ -/* lnstat.c: Unified linux network statistics - * - * Copyright (C) 2004 by Harald Welte - * - * Development of this code was funded by Astaro AG, http://www.astaro.com/ - * - * Based on original concept and ideas from predecessor rtstat.c: - * - * Copyright 2001 by Robert Olsson - * Uppsala University, Sweden - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "lnstat.h" - -/* size of temp buffer used to read lines from procfiles */ -#define FGETS_BUF_SIZE 1024 - - -#define RTSTAT_COMPAT_LINE "entries in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n" - -/* Read (and summarize for SMP) the different stats vars. */ -static int scan_lines(struct lnstat_file *lf, int i) -{ - int j, num_lines = 0; - - for (j = 0; j < lf->num_fields; j++) - lf->fields[j].values[i] = 0; - - while(!feof(lf->fp)) { - char buf[FGETS_BUF_SIZE]; - char *ptr = buf; - - num_lines++; - - fgets(buf, sizeof(buf)-1, lf->fp); - gettimeofday(&lf->last_read, NULL); - - for (j = 0; j < lf->num_fields; j++) - lf->fields[j].values[i] = strtoul(ptr, &ptr, 16); - } - return num_lines; -} - -static int time_after(struct timeval *last, - struct timeval *tout, - struct timeval *now) -{ - if (now->tv_sec > last->tv_sec + tout->tv_sec) - return 1; - - if (now->tv_sec == last->tv_sec + tout->tv_sec) { - if (now->tv_usec > last->tv_usec + tout->tv_usec) - return 1; - } - - return 0; -} - -int lnstat_update(struct lnstat_file *lnstat_files) -{ - struct lnstat_file *lf; - char buf[FGETS_BUF_SIZE]; - struct timeval tv; - - gettimeofday(&tv, NULL); - - for (lf = lnstat_files; lf; lf = lf->next) { - if (time_after(&lf->last_read, &lf->interval, &tv)) { - int i; - struct lnstat_field *lfi; - - rewind(lf->fp); - if (!lf->compat) { - /* skip first line */ - fgets(buf, sizeof(buf)-1, lf->fp); - } - scan_lines(lf, 1); - - for (i = 0, lfi = &lf->fields[i]; - i < lf->num_fields; i++, lfi = &lf->fields[i]) { - if (i == 0) - lfi->result = lfi->values[1]; - else - lfi->result = (lfi->values[1]-lfi->values[0]) - / lf->interval.tv_sec; - } - - rewind(lf->fp); - fgets(buf, sizeof(buf)-1, lf->fp); - scan_lines(lf, 0); - } - } - - return 0; -} - -/* scan first template line and fill in per-field data structures */ -static int __lnstat_scan_fields(struct lnstat_file *lf, char *buf) -{ - char *tok; - int i; - - tok = strtok(buf, " \t\n"); - for (i = 0; i < LNSTAT_MAX_FIELDS_PER_LINE; i++) { - lf->fields[i].file = lf; - strncpy(lf->fields[i].name, tok, LNSTAT_MAX_FIELD_NAME_LEN); - /* has to be null-terminate since we initialize to zero - * and field size is NAME_LEN + 1 */ - tok = strtok(NULL, " \t\n"); - if (!tok) { - lf->num_fields = i+1; - return 0; - } - } - return 0; -} - -static int lnstat_scan_fields(struct lnstat_file *lf) -{ - char buf[FGETS_BUF_SIZE]; - - rewind(lf->fp); - fgets(buf, sizeof(buf)-1, lf->fp); - - return __lnstat_scan_fields(lf, buf); -} - -/* fake function emulating lnstat_scan_fields() for old kernels */ -static int lnstat_scan_compat_rtstat_fields(struct lnstat_file *lf) -{ - char buf[FGETS_BUF_SIZE]; - - strncpy(buf, RTSTAT_COMPAT_LINE, sizeof(buf)-1); - - return __lnstat_scan_fields(lf, buf); -} - -/* find out whether string 'name; is in given string array */ -static int name_in_array(const int num, const char **arr, const char *name) -{ - int i; - for (i = 0; i < num; i++) { - if (!strcmp(arr[i], name)) - return 1; - } - return 0; -} - -/* allocate lnstat_file and open given file */ -static struct lnstat_file *alloc_and_open(const char *path, const char *file) -{ - struct lnstat_file *lf; - - /* allocate */ - lf = malloc(sizeof(*lf)); - if (!lf) - return NULL; - - /* initialize */ - memset(lf, 0, sizeof(*lf)); - - /* de->d_name is guaranteed to be <= NAME_MAX */ - strcpy(lf->basename, file); - strcpy(lf->path, path); - strcat(lf->path, "/"); - strcat(lf->path, lf->basename); - - /* initialize to default */ - lf->interval.tv_sec = 1; - - /* open */ - lf->fp = fopen(lf->path, "r"); - if (!lf->fp) { - free(lf); - return NULL; - } - - return lf; -} - - -/* lnstat_scan_dir - find and parse all available statistics files/fields */ -struct lnstat_file *lnstat_scan_dir(const char *path, const int num_req_files, - const char **req_files) -{ - DIR *dir; - struct lnstat_file *lnstat_files = NULL; - struct dirent *de; - - if (!path) - path = PROC_NET_STAT; - - dir = opendir(path); - if (!dir) { - struct lnstat_file *lf; - /* Old kernel, before /proc/net/stat was introduced */ - fprintf(stderr, "Your kernel doesn't have lnstat support. "); - - /* we only support rtstat, not multiple files */ - if (num_req_files >= 2) { - fputc('\n', stderr); - return NULL; - } - - /* we really only accept rt_cache */ - if (num_req_files && !name_in_array(num_req_files, - req_files, "rt_cache")) { - fputc('\n', stderr); - return NULL; - } - - fprintf(stderr, "Fallback to old rtstat-only operation\n"); - - lf = alloc_and_open("/proc/net", "rt_cache_stat"); - if (!lf) - return NULL; - lf->compat = 1; - strncpy(lf->basename, "rt_cache", sizeof(lf->basename)); - - /* FIXME: support for old files */ - if (lnstat_scan_compat_rtstat_fields(lf) < 0) - return NULL; - - lf->next = lnstat_files; - lnstat_files = lf; - return lnstat_files; - } - - while ((de = readdir(dir))) { - struct lnstat_file *lf; - - if (de->d_type != DT_REG) - continue; - - if (num_req_files && !name_in_array(num_req_files, - req_files, de->d_name)) - continue; - - lf = alloc_and_open(path, de->d_name); - if (!lf) - return NULL; - - /* fill in field structure */ - if (lnstat_scan_fields(lf) < 0) - return NULL; - - /* prepend to global list */ - lf->next = lnstat_files; - lnstat_files = lf; - } - closedir(dir); - - return lnstat_files; -} - -int lnstat_dump(FILE *outfd, struct lnstat_file *lnstat_files) -{ - struct lnstat_file *lf; - - for (lf = lnstat_files; lf; lf = lf->next) { - int i; - - fprintf(outfd, "%s:\n", lf->path); - - for (i = 0; i < lf->num_fields; i++) - fprintf(outfd, "\t%2u: %s\n", i+1, lf->fields[i].name); - - } - return 0; -} - -struct lnstat_field *lnstat_find_field(struct lnstat_file *lnstat_files, - char *name) -{ - struct lnstat_file *lf; - struct lnstat_field *ret = NULL; - char *colon = strchr(name, ':'); - char *file, *field; - - if (colon) { - file = strndup(name, colon-name); - field = colon+1; - } else { - file = NULL; - field = name; - } - - for (lf = lnstat_files; lf; lf = lf->next) { - int i; - - if (file && strcmp(file, lf->basename)) - continue; - - for (i = 0; i < lf->num_fields; i++) { - if (!strcmp(field, lf->fields[i].name)) { - ret = &lf->fields[i]; - goto out; - } - } - } -out: - if (file) - free(file); - - return ret; -}