Compare commits
	
		
			93 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| c8ca7394f5 | |||
| 969cebd4ae | |||
| 5677863e61 | |||
| ed8528cf9c | |||
| 737c642819 | |||
| b44d0152c4 | |||
| fdd139ada2 | |||
| 49ce252ec5 | |||
| 14db0bff4c | |||
| 3413751795 | |||
| 1b3f11bde3 | |||
| af8923b779 | |||
| 3e4970485d | |||
| f312679738 | |||
| 2efc2f4a60 | |||
| a3d894000b | |||
| 8b2638c349 | |||
| a5301347f6 | |||
| 29fb4317d7 | |||
| 32d8c76b18 | |||
| 577112870d | |||
| 5b938e05c7 | |||
| 5cd24ffd6a | |||
| 702df3c0a1 | |||
| 7317715e15 | |||
| 86f6da0703 | |||
| 723f6a5b47 | |||
| ddcd5e7d24 | |||
| df271c43a4 | |||
| 8f39217bd7 | |||
| e47a376f70 | |||
| 828b5b5368 | |||
| 1c25eacc95 | |||
| f177718f24 | |||
| cc22e4e35d | |||
| 19c35e4990 | |||
| 70e6f97b65 | |||
| a6c635dc96 | |||
| f78c0e5b98 | |||
| 0e08ec1b79 | |||
| 74770b8806 | |||
| fa6abf3a80 | |||
| 0103671f1f | |||
| 4efaa8ce9e | |||
| 1f79ea4396 | |||
| 67b6ee3bd6 | |||
| cbcdab6669 | |||
| 8dcd666db6 | |||
| a0eea59519 | |||
| f9c714fa15 | |||
| 892bdac762 | |||
| 4488cd03f9 | |||
| 753a9e09dd | |||
| 0641291ad5 | |||
| f666ffd0b7 | |||
| 559e31e62f | |||
| 9a69cb6d59 | |||
| 665c63d4e7 | |||
| 964f48465a | |||
| e31a860af6 | |||
| 2027a634a7 | |||
| 30946f2d78 | |||
| 47547eb29f | |||
| 21ec49ed67 | |||
| 29172c819c | |||
| 2ccea2c56e | |||
| 51a24c315b | |||
| 5cecc86856 | |||
| 5e61c5c0e4 | |||
| 4645116a57 | |||
| c80554be16 | |||
| 2a410be36f | |||
| c1ae292c95 | |||
| 234efb85f6 | |||
| 229d58c975 | |||
| 8fc5a55da4 | |||
| 3ecdad6f56 | |||
| 511e0196e1 | |||
| 0100916a95 | |||
| ea065c5619 | |||
| baabc8b729 | |||
| 88548ccf96 | |||
| c4ed01f272 | |||
| c1d0bb41c7 | |||
| 7f8d60f40f | |||
| 6920af805c | |||
| 8b4ce86cc9 | |||
| 17a4adb0f2 | |||
| 4492ab547c | |||
| a36136ec4d | |||
| e3d208905d | |||
| 68bd14ffd1 | |||
| e2df502abc | 
							
								
								
									
										42
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								.travis.yml
									
									
									
									
									
								
							| @ -1,10 +1,40 @@ | ||||
| language: c | ||||
|  | ||||
| os: | ||||
|   - linux | ||||
|   - osx | ||||
|  | ||||
| env: | ||||
|   global: | ||||
|     - secure: "C87Pgf5AVDoyQfm9MIv81g" | ||||
|  | ||||
| compiler: | ||||
|   - gcc | ||||
|   - clang | ||||
| before_install: | ||||
|   - sudo apt-get install libconfuse-dev | ||||
|   - sudo apt-get install libnl-3-dev libnl-route-3-dev | ||||
|   - sudo apt-get install libncurses-dev | ||||
| # Change this to your needs | ||||
| script: ./autogen.sh && ./configure && make | ||||
|  | ||||
| # container-based builds | ||||
| sudo: false | ||||
| addons: | ||||
|   apt: | ||||
|     packages: | ||||
|     # packages list: https://github.com/travis-ci/apt-package-whitelist/blob/master/ubuntu-precise | ||||
|     - libconfuse-dev | ||||
|     - libncurses5-dev | ||||
|     - libnl-3-dev | ||||
|     - libnl-route-3-dev | ||||
|   coverity_scan: | ||||
|     project: | ||||
|       name: "tgraf/bmon" | ||||
|       description: "bandwidth monitor" | ||||
|     notification_email: tgraf@suug.ch | ||||
|     build_command_prepend: "./autogen.sh && ./configure" | ||||
|     build_command: "make -j2" | ||||
|     branch_pattern: coverity_scan | ||||
|  | ||||
|  | ||||
| install: | ||||
|   - if [ "$TRAVIS_BRANCH" = "coverity_scan" ] && ! [ "$TRAVIS_OS_NAME" = "linux" -a "$CC" = "gcc" ]; then exit ; fi | ||||
|   - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update > /dev/null && brew install confuse ; fi | ||||
|  | ||||
| script: | ||||
|   - ./.travis/run.sh | ||||
|  | ||||
							
								
								
									
										9
									
								
								.travis/run.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								.travis/run.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,9 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| FLAGS="-Werror" | ||||
|  | ||||
| if [ $CC = "clang" ]; then | ||||
| 	FLAGS="$FLAGS -Wno-error=unused-command-line-argument" | ||||
| fi | ||||
|  | ||||
| ./autogen.sh && ./configure && make CFLAGS="$FLAGS" && make distcheck | ||||
| @ -4,4 +4,4 @@ ACLOCAL_AMFLAGS = -I m4 | ||||
|  | ||||
| SUBDIRS = src man include examples | ||||
|  | ||||
| EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.adoc | ||||
| EXTRA_DIST = ChangeLog LICENSE.BSD LICENSE.MIT NEWS README.md | ||||
|  | ||||
							
								
								
									
										38
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								NEWS
									
									
									
									
									
								
							| @ -1,12 +1,46 @@ | ||||
| HEAD | ||||
|  | ||||
| v4.0 - Dec 13, 2016 | ||||
|  * Use monotonic clock instead of realtime clock | ||||
|  * Pick default selected interface based on policy | ||||
|  * Collect RX NoHandler statistics if available (Linux) | ||||
|  * CentOS installation instructions | ||||
|  * Proper stdout flush in ASCII mode | ||||
|  * Bugfixes | ||||
|  | ||||
| v3.9 - Jul 19, 2016 | ||||
|  * Color support | ||||
|  * Add ability to reset statistics from curses UI | ||||
|  * NetBSD compile fix | ||||
|  * Option to enable info display by default | ||||
|  * Additional IPv6 statistics | ||||
|  * Various fixes | ||||
|  | ||||
| v3.8 - July 25, 2015 | ||||
|  * Don't disable Netlink if TC stats are unavailable | ||||
|  | ||||
| v3.7 - November 22, 2014 | ||||
|  * Bugfixes | ||||
|  * Documentation updates | ||||
|  * Provide minimal interface information on BSD | ||||
|   | ||||
| v3.6 - November 22, 2014 | ||||
|  * Build fix for uclinux | ||||
|  * Fix LICENSE links | ||||
|  | ||||
| v3.5 - August 30, 2014 | ||||
|  * Fixes for all defects identified by coverity | ||||
|  * Fix accuracy issue on total rate calculation | ||||
|  * Travis-CI support | ||||
|  * Various other small bugfixes | ||||
|  | ||||
| v3.4 - August 24, 2014 | ||||
| ---------------------- | ||||
|  * Bugfixes | ||||
|    * blank screen with config file | ||||
|    * quick-help toggle with '?' in curses | ||||
|  * Better bmon.conf example | ||||
|  | ||||
| v3.3 - July 6, 2014 | ||||
| ------------------- | ||||
|  * MacOS X port | ||||
|  * Only initialize curses module if actually used | ||||
|  * Assorted bug and spelling fixes | ||||
|  | ||||
							
								
								
									
										92
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								README.md
									
									
									
									
									
								
							| @ -8,20 +8,74 @@ statistics and prepare them visually in a human friendly way. It | ||||
| features various output methods including an interactive curses user | ||||
| interface and a programmable text output for scripting. | ||||
|  | ||||
| ## Changes | ||||
| ## Download | ||||
|  | ||||
| ### New in 3.4 | ||||
|  * [Latest Release](https://github.com/tgraf/bmon/releases/latest) | ||||
|  * [Older Releases](https://github.com/tgraf/bmon/releases) | ||||
|  | ||||
| ## Debian/Ubuntu Installation | ||||
|  | ||||
| ``` | ||||
| git clone https://github.com/tgraf/bmon.git | ||||
| cd bmon | ||||
| apt-get install build-essential make libconfuse-dev libnl-3-dev libnl-route-3-dev libncurses-dev pkg-config dh-autoreconf | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| make install | ||||
| bmon | ||||
| ``` | ||||
| ## CentOS (6) Installation | ||||
|  | ||||
| ``` | ||||
| git clone https://github.com/tgraf/bmon.git | ||||
| cd bmon | ||||
| yum install make libconfuse-devel libnl3-devel libnl-route3-devel ncurses-devel | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| make install | ||||
| bmon | ||||
| ``` | ||||
|  | ||||
| ## OSX Installation | ||||
|  | ||||
| ### Brew | ||||
| ``` | ||||
| brew install bmon | ||||
| ``` | ||||
|  | ||||
| ### Compile yourself | ||||
| Install libconfuse | ||||
| ``` | ||||
| wget https://github.com/martinh/libconfuse/releases/download/v2.8/confuse-2.8.zip | ||||
| unzip confuse-2.8.zip && cd confuse-2.8 | ||||
| PATH=/usr/local/opt/gettext/bin:$PATH ./configure | ||||
| make | ||||
| make install | ||||
| ``` | ||||
|  | ||||
| Install bmon | ||||
| ``` | ||||
| git clone https://github.com/tgraf/bmon.git | ||||
| cd bmon | ||||
| ./autogen.sh | ||||
| ./configure | ||||
| make | ||||
| make install | ||||
| bmon | ||||
| ``` | ||||
|  | ||||
| ------------- | ||||
| ## New in 4.0 | ||||
|  * Use monotonic clock instead of realtime clock | ||||
|  * Pick default selected interface based on policy | ||||
|  * Collect RX NoHandler statistics if available (Linux) | ||||
|  * CentOS installation instructions | ||||
|  * Proper stdout flush in ASCII mode | ||||
|  * Bugfixes | ||||
|    * blank screen with config file | ||||
|    * quick-help toggle with '?' in curses | ||||
|  * Better bmon.conf example | ||||
|  | ||||
| ## New in 3.3 | ||||
|  * MacOS X port | ||||
|  * Only initialize curses module if actually used | ||||
|  * Assorted bug and spelling fixes | ||||
|  * Various build fixes | ||||
|  | ||||
| ------------- | ||||
| ### Usage | ||||
|  | ||||
| To run bmon in the default curses mode: | ||||
| @ -35,14 +89,18 @@ provided via: | ||||
|  | ||||
| ## Screenshots | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| ## Copyright | ||||
|  | ||||
| > *Copyright (c) 2001-2014 Thomas Graf <tgraf@suug.ch> | ||||
| > Copyright (c) 2013 Red Hat, Inc.* | ||||
| Various authors, see git commit log. | ||||
|  | ||||
| Please see the [LICENSE](https://github.com/tgraf/bmon/blob/master/LICENSE) | ||||
| file for additional details. | ||||
| > *Copyright (c) 2001-2016 Thomas Graf <tgraf@suug.ch>* | ||||
| > *Copyright (c) 2013 Red Hat, Inc.* | ||||
|  | ||||
| Please see the [LICENSE.BSD](https://github.com/tgraf/bmon/blob/master/LICENSE.BSD) | ||||
| and [LICENSE.MIT](https://github.com/tgraf/bmon/blob/master/LICENSE.MIT) files for | ||||
| additional details. | ||||
|  | ||||
|  | ||||
							
								
								
									
										21
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								configure.ac
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| # | ||||
| # configure.in      Configure Script | ||||
| # | ||||
| # Copyright (c) 2001-2013 Thomas Graf <tgraf@suug.ch> | ||||
| # Copyright (c) 2001-2016 Thomas Graf <tgraf@suug.ch> | ||||
| # | ||||
| # Permission is hereby granted, free of charge, to any person obtaining a | ||||
| # copy of this software and associated documentation files (the "Software"), | ||||
| @ -21,7 +21,7 @@ | ||||
| # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
| # DEALINGS IN THE SOFTWARE. | ||||
|  | ||||
| AC_INIT(bmon, 3.4, [], [], [http://www.infradead.org/~tgr/bmon/]) | ||||
| AC_INIT(bmon, 4.0, [], [], [https://github.com/tgraf/bmon]) | ||||
| AC_CONFIG_HEADERS(include/bmon/defs.h) | ||||
| AC_CONFIG_AUX_DIR([build-aux]) | ||||
| AC_CONFIG_MACRO_DIR([m4]) | ||||
| @ -58,10 +58,18 @@ AC_CHECK_HEADERS(sys/param.h sys/socket.h) | ||||
|  | ||||
| AC_CHECK_TYPES(suseconds_t) | ||||
|  | ||||
| AC_CHECK_FUNCS(atexit gettimeofday memset pow socket strcasecmp) | ||||
| AC_CHECK_FUNCS(atexit clock_gettime memset pow socket strcasecmp) | ||||
| AC_CHECK_FUNCS(strchr strdup strerror strncasecmp strstr strtol) | ||||
| AC_CHECK_FUNCS(uname getdate) | ||||
|  | ||||
| AC_PATH_PROG([PKG_CONFIG], [pkg-config], [no]) | ||||
| AS_IF([test "x$PKG_CONFIG" = "xno"],[ | ||||
|    AC_MSG_ERROR([ | ||||
|       *** The pkg-config script could not be found. Make sure it is | ||||
|       *** in your path, or set the PKG_CONFIG environment variable | ||||
|       *** to the full path to pkg-config.]) | ||||
|    ]) | ||||
|  | ||||
| AX_WITH_CURSES | ||||
| if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then | ||||
|         AC_MSG_ERROR([requires an X/Open-compatible Curses library with color]) | ||||
| @ -70,7 +78,7 @@ fi | ||||
| PKG_CHECK_MODULES([CONFUSE], [libconfuse], [], AC_MSG_ERROR([requires libconfuse])) | ||||
|  | ||||
| case ${target_os} in | ||||
|     linux*) | ||||
|     linux*|uclinux*) | ||||
|         PKG_CHECK_MODULES([LIBNL], [libnl-3.0], [], AC_MSG_ERROR([requires libnl3-dev])) | ||||
|         PKG_CHECK_MODULES([LIBNL_ROUTE], [libnl-route-3.0], [], AC_MSG_ERROR([requires libnl3-route])) | ||||
|     ;; | ||||
| @ -78,6 +86,9 @@ esac | ||||
|  | ||||
| AC_CHECK_LIB(m, pow, [], AC_MSG_ERROR([requires libm])) | ||||
|  | ||||
| # Don't fail if not found (for instance, OS X does not have clock_gettime) | ||||
| AC_CHECK_LIB(rt, clock_gettime, [], []) | ||||
|  | ||||
| BMON_LIB="" | ||||
|  | ||||
| ##################################################################### | ||||
| @ -164,7 +175,7 @@ case ${target_os} in | ||||
| 	AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system]) | ||||
|     ;; | ||||
|  | ||||
|     *bsd*) | ||||
|     *bsd*|dragonfly*) | ||||
| 	AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) | ||||
|     ;; | ||||
|  | ||||
|  | ||||
| @ -11,10 +11,10 @@ | ||||
|  | ||||
| /*  | ||||
|  * element eth0 { | ||||
|  * 	description	= { "My description" } | ||||
|  * 	rxmax		= { 10000 } | ||||
|  * 	txmax		= { 10000 } | ||||
|  * 	max		= { 12500000 } | ||||
|  * 	description	= "My description" | ||||
|  * 	rxmax		= 10000 | ||||
|  * 	txmax		= 10000 | ||||
|  * 	max		= 12500000 | ||||
|  * } | ||||
|  */ | ||||
|  | ||||
| @ -86,3 +86,27 @@ history day { | ||||
| 	interval	= 86400. | ||||
| 	size		= 60 | ||||
| } | ||||
|  | ||||
| layout colors { | ||||
|     color default { | ||||
|        color_pair  = {"white", "black"} | ||||
|     } | ||||
|     color statusbar { | ||||
|         color_pair = {"blue", "white", "reverse"} | ||||
|     } | ||||
|     color header { | ||||
|         color_pair = {"yellow", "black"} | ||||
|     } | ||||
|     color list { | ||||
|         color_pair = {"white", "black"} | ||||
|     } | ||||
|     color selected { | ||||
|         color_pair = {"white", "black", "reverse"} | ||||
|     } | ||||
|     color RX_graph { | ||||
|         color_pair = {"green", "black"} | ||||
|     } | ||||
|     color TX_graph { | ||||
|         color_pair = {"red", "black"} | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -16,4 +16,5 @@ noinst_HEADERS = \ | ||||
| 	bmon/module.h \ | ||||
| 	bmon/output.h \ | ||||
| 	bmon/unit.h \ | ||||
| 	bmon/layout.h \ | ||||
| 	bmon/utils.h | ||||
|  | ||||
| @ -42,6 +42,9 @@ struct rate | ||||
| 	/* Value of r_current at last read */ | ||||
| 	uint64_t		r_prev; | ||||
|  | ||||
| 	/* Reset value to substract to emulate statistics reset */ | ||||
| 	uint64_t		r_reset; | ||||
|  | ||||
| 	/* Rate per second calculated every `rate_interval' */ | ||||
| 	float			r_rate; | ||||
|  | ||||
| @ -49,6 +52,8 @@ struct rate | ||||
| 	timestamp_t		r_last_calc; | ||||
| }; | ||||
|  | ||||
| extern uint64_t			rate_get_total(struct rate *); | ||||
|  | ||||
| enum { | ||||
| 	ATTR_TYPE_UNSPEC, | ||||
| 	ATTR_TYPE_COUNTER, | ||||
| @ -134,5 +139,6 @@ extern struct attr *		attr_select_prev(void); | ||||
| extern struct attr *		attr_current(void); | ||||
|  | ||||
| extern void			attr_start_collecting_history(struct attr *); | ||||
| extern void			attr_reset_counter(struct attr *a); | ||||
|  | ||||
| #endif | ||||
|  | ||||
| @ -60,9 +60,11 @@ enum { | ||||
| #if defined __GNUC__ | ||||
| #define __init __attribute__ ((constructor)) | ||||
| #define __exit __attribute__ ((destructor)) | ||||
| #define __unused__ __attribute__ ((unused)) | ||||
| #else | ||||
| #define __init | ||||
| #define __exit | ||||
| #define __unused__ | ||||
| #endif | ||||
|  | ||||
| #ifdef DEBUG | ||||
|  | ||||
| @ -74,6 +74,8 @@ enum { | ||||
| 	LAYOUT_HEADER, | ||||
| 	LAYOUT_LIST, | ||||
| 	LAYOUT_SELECTED, | ||||
|     LAYOUT_RX_GRAPH, | ||||
|     LAYOUT_TX_GRAPH, | ||||
| 	__LAYOUT_MAX | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -48,7 +48,7 @@ | ||||
| #include <dirent.h> | ||||
| #ifdef SYS_BSD | ||||
| # include <float.h> | ||||
| #else | ||||
| #elif !defined(__ANDROID__) | ||||
| # include <values.h> | ||||
| #endif | ||||
|  | ||||
|  | ||||
| @ -9,6 +9,9 @@ | ||||
| /* Define to 1 if you have the `atexit' function. */ | ||||
| #undef HAVE_ATEXIT | ||||
|  | ||||
| /* Define to 1 if you have the `clock_gettime' function. */ | ||||
| #undef HAVE_CLOCK_GETTIME | ||||
|  | ||||
| /* have curses */ | ||||
| #undef HAVE_CURSES | ||||
|  | ||||
| @ -39,15 +42,15 @@ | ||||
| /* Define to 1 if you have the <getopt.h> header file. */ | ||||
| #undef HAVE_GETOPT_H | ||||
|  | ||||
| /* Define to 1 if you have the `gettimeofday' function. */ | ||||
| #undef HAVE_GETTIMEOFDAY | ||||
|  | ||||
| /* Define to 1 if you have the <inttypes.h> header file. */ | ||||
| #undef HAVE_INTTYPES_H | ||||
|  | ||||
| /* Define to 1 if you have the `m' library (-lm). */ | ||||
| #undef HAVE_LIBM | ||||
|  | ||||
| /* Define to 1 if you have the `rt' library (-lrt). */ | ||||
| #undef HAVE_LIBRT | ||||
|  | ||||
| /* Define to 1 if you have the <memory.h> header file. */ | ||||
| #undef HAVE_MEMORY_H | ||||
|  | ||||
|  | ||||
							
								
								
									
										130
									
								
								include/bmon/layout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								include/bmon/layout.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,130 @@ | ||||
|  | ||||
| #ifndef __BMON_LAYOUT_H_ | ||||
| #define __BMON_LAYOUT_H_ | ||||
|  | ||||
| #include <bmon/bmon.h> | ||||
| #include <bmon/conf.h> | ||||
| #include <bmon/unit.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
|  | ||||
| static int parse_color(const char* color) | ||||
| { | ||||
|     int color_code = -1; | ||||
|  | ||||
|     if ((strcasestr(color, "red") != NULL)) | ||||
|         color_code = COLOR_RED; | ||||
|     else if ((strcasestr(color, "green") != NULL)) | ||||
|         color_code = COLOR_GREEN; | ||||
|     else if ((strcasestr(color, "white") != NULL)) | ||||
|         color_code = COLOR_WHITE; | ||||
|     else if ((strcasestr(color, "black") != NULL)) | ||||
|         color_code = COLOR_BLACK; | ||||
|     else if ((strcasestr(color, "blue") != NULL)) | ||||
|         color_code = COLOR_BLUE; | ||||
|     else if ((strcasestr(color, "yellow") != NULL)) | ||||
|         color_code = COLOR_YELLOW; | ||||
|     else if ((strcasestr(color, "magenta") != NULL)) | ||||
|         color_code = COLOR_MAGENTA; | ||||
|     else if ((strcasestr(color, "cyan") != NULL)) | ||||
|         color_code = COLOR_CYAN; | ||||
|     else if ((atoi(color) >= 0)) | ||||
|         color_code = atoi(color); | ||||
|  | ||||
|     return color_code; | ||||
| } | ||||
|  | ||||
| /* | ||||
|     A_NORMAL        Normal display (no highlight) | ||||
|     A_STANDOUT      Best highlighting mode of the terminal. | ||||
|     A_UNDERLINE     Underlining | ||||
|     A_REVERSE       Reverse video | ||||
|     A_BLINK         Blinking | ||||
|     A_DIM           Half bright | ||||
|     A_BOLD          Extra bright or bold | ||||
|     A_PROTECT       Protected mode | ||||
|     A_INVIS         Invisible or blank mode | ||||
|     A_ALTCHARSET    Alternate character set | ||||
|     A_CHARTEXT      Bit-mask to extract a character | ||||
| */ | ||||
|  | ||||
| static int parse_attribute(const char* attr) | ||||
| { | ||||
|     /* no attribute is valid, so we have nothing to do */ | ||||
|     if (attr == NULL) | ||||
|         return 0; | ||||
|  | ||||
|     if ((strcasestr(attr, "normal") != NULL)) | ||||
|         return A_NORMAL; | ||||
|     else if ((strcasestr(attr, "standout") != NULL)) | ||||
|         return A_STANDOUT; | ||||
|     else if ((strcasestr(attr, "underline") != NULL)) | ||||
|         return A_UNDERLINE; | ||||
|     else if ((strcasestr(attr, "reverse") != NULL)) | ||||
|         return A_REVERSE; | ||||
|     else if ((strcasestr(attr, "blink") != NULL)) | ||||
|         return A_BLINK; | ||||
|     else if ((strcasestr(attr, "dim") != NULL)) | ||||
|         return A_DIM; | ||||
|     else if ((strcasestr(attr, "bold") != NULL)) | ||||
|         return A_BOLD; | ||||
|     else if ((strcasestr(attr, "protect") != NULL)) | ||||
|         return A_PROTECT; | ||||
|     else if ((strcasestr(attr, "invis") != NULL)) | ||||
|         return A_INVIS; | ||||
|     else if ((strcasestr(attr, "altcharset") != NULL)) | ||||
|         return A_ALTCHARSET; | ||||
|     else if ((strcasestr(attr, "chartext") != NULL)) | ||||
|         return A_CHARTEXT; | ||||
|  | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void add_layout(const char *layout_name, cfg_t *color_cfg) | ||||
| { | ||||
|     const char *fg, *bg, *attr_str = NULL; | ||||
|     int size = -1, fg_code, bg_code, attr_mask, layout_idx = 0; | ||||
|  | ||||
|     size = cfg_size(color_cfg, "color_pair"); | ||||
|     fg = cfg_getnstr(color_cfg, "color_pair", 0); | ||||
|     bg = cfg_getnstr(color_cfg, "color_pair", 1); | ||||
|     if (size > 2) | ||||
|         attr_str = cfg_getnstr(color_cfg, "color_pair", 2); | ||||
|  | ||||
|     fg_code = parse_color(fg); | ||||
|     bg_code = parse_color(bg); | ||||
|     if (fg_code == -1 || bg_code == -1) { | ||||
|         quit("Unknown color [%s]: %s\n", (fg_code == -1) ? "fg" : "bg", | ||||
|                 (fg_code == -1) ? fg : bg); | ||||
|     } | ||||
|     attr_mask = parse_attribute(attr_str); | ||||
|     if (attr_mask == -1) { | ||||
|         quit("Unknown attribute: '%s'\n", attr_str); | ||||
|     } | ||||
|  | ||||
|     DBG("%s:\tfg: %s bg: %s attr: %s\n", layout_name, fg, bg, attr_str); | ||||
|  | ||||
|     if ((strcasecmp(layout_name, "default") == 0)) | ||||
|         layout_idx = LAYOUT_DEFAULT; | ||||
|     else if ((strcasecmp(layout_name, "statusbar") == 0)) | ||||
|         layout_idx = LAYOUT_STATUSBAR; | ||||
|     else if ((strcasecmp(layout_name, "header") == 0)) | ||||
|         layout_idx = LAYOUT_HEADER; | ||||
|     else if ((strcasecmp(layout_name, "list") == 0)) | ||||
|         layout_idx = LAYOUT_LIST; | ||||
|     else if ((strcasecmp(layout_name, "selected") == 0)) | ||||
|         layout_idx = LAYOUT_SELECTED; | ||||
|     else if ((strcasecmp(layout_name, "rx_graph") == 0)) | ||||
|         layout_idx = LAYOUT_RX_GRAPH; | ||||
|     else if ((strcasecmp(layout_name, "tx_graph") == 0)) | ||||
|         layout_idx = LAYOUT_TX_GRAPH; | ||||
|     else { | ||||
|         quit("Unknown layout name: '%s'\n", layout_name); | ||||
|     } | ||||
|  | ||||
|     struct layout l = { fg_code, bg_code, attr_mask}; | ||||
|     cfg_layout[layout_idx] = l; | ||||
| } | ||||
|  | ||||
| #endif /* __BMON_LAYOUT_H_ */ | ||||
							
								
								
									
										21
									
								
								man/bmon.8
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								man/bmon.8
									
									
									
									
									
								
							| @ -34,7 +34,7 @@ in parallel. bmon automatically loads a useful and working input module | ||||
| by default. See INPUT MODULES for more details. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-o\fR, \fB\-\-ouptut\fRMODULE[:OPTIONS][,MODULE...] | ||||
| \fB \-o\fR, \fB\-\-output=\fRMODULE[:OPTIONS][,MODULE...] | ||||
| .RS 4 | ||||
| Set list of output modules to load and use. Multiple modules can be used | ||||
| in parallel. By default, bmon will use the curses output mode, if that is | ||||
| @ -44,7 +44,7 @@ text mode. See OUTPUT MODULES for more details. | ||||
| .PP | ||||
| \fB \-U\fR, \fB\-\-use\-si\fR | ||||
| .RS 4 | ||||
| Use SI unit system instead of 1KB = 1'024 bytes. | ||||
| Use SI unit system (1KB = 1'000 bytes) instead of 1KB = 1'024 bytes. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-f\fR, \fB\-\-configfile=\fRFILE | ||||
| @ -58,7 +58,7 @@ Set policy defining which network interfaces to display. See | ||||
| INTERFACE SELECTION for more details. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-a\fR, \fB\-\-show\-all=\fR | ||||
| \fB \-a\fR, \fB\-\-show\-all\fR | ||||
| .RS 4 | ||||
| Display all interfaces, even interface that are administratively down. | ||||
| .RE | ||||
| @ -75,6 +75,11 @@ Set interval in seconds in which the rate per counter is calculated. | ||||
| The default is 1.0 seconds. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-b\fR, \fB\-\-use\-bit\fR | ||||
| .RS 4 | ||||
| Show rates in bits per second instead of bytes per second. | ||||
| .RE | ||||
| .PP | ||||
| \fB \-L\fR, \fB\-\-lifetime=\fRFLOAT | ||||
| .RS 4 | ||||
| Set lifetime of an element in seconds before it is no longer displayed | ||||
| @ -132,7 +137,7 @@ The following output modules exist: | ||||
| .TP | ||||
| \fBcurses\fR | ||||
| Interactive curses based text user interface providing real time rate | ||||
| estimations and a graphical representatio nof each attribute. Press '?' | ||||
| estimations and a graphical representation of each attribute. Press '?' | ||||
| to display the quick reference guide. This is the default output mode. | ||||
|  | ||||
| .TP | ||||
| @ -215,6 +220,14 @@ and eth1: | ||||
| .RS 4 | ||||
| \fBbmon \-p eth0,eth1 \-o curses\fP | ||||
| .RE | ||||
| .PP | ||||
| To run bmon in format mode, monitoring any eth* interfaces, with a specified | ||||
| format string: | ||||
| .PP | ||||
| .RS 4 | ||||
| \fBbmon \-p \(aqeth*\(aq \-o format:fmt=\(aq$(element:name) $(attr:rxrate:packets)\en\(aq\fP | ||||
| .RE | ||||
| .PP | ||||
|  | ||||
| .SH "FILES" | ||||
| /etc/bmon.conf | ||||
|  | ||||
| @ -7,6 +7,7 @@ bmon_CFLAGS = \ | ||||
| 	-I${top_builddir}/include \ | ||||
| 	-DSYSCONFDIR=\"$(sysconfdir)\" \ | ||||
| 	-D_GNU_SOURCE \ | ||||
| 	-Wall \ | ||||
| 	$(CURSES_CFLAGS) \ | ||||
| 	$(CONFUSE_CFLAGS) \ | ||||
| 	$(LIBNL_CFLAGS) \ | ||||
| @ -40,4 +41,5 @@ bmon_SOURCES = \ | ||||
| 	out_null.c \ | ||||
| 	out_format.c \ | ||||
| 	out_ascii.c \ | ||||
| 	out_curses.c | ||||
| 	out_curses.c \ | ||||
| 	out_trigger.c | ||||
|  | ||||
							
								
								
									
										15
									
								
								src/attr.c
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/attr.c
									
									
									
									
									
								
							| @ -111,7 +111,7 @@ int attr_def_add(const char *name, const char *desc, struct unit *unit, | ||||
| 	return def->ad_id; | ||||
| } | ||||
|  | ||||
| void attr_def_free(struct attr_def *def) | ||||
| static void attr_def_free(struct attr_def *def) | ||||
| { | ||||
| 	if (!def) | ||||
| 		return; | ||||
| @ -524,6 +524,11 @@ static float __calc_usage(double rate, uint64_t max) | ||||
| 	return 100.0f / ((double) max / (rate * cfg_rate_interval)); | ||||
| } | ||||
|  | ||||
| uint64_t rate_get_total(struct rate *r) | ||||
| { | ||||
| 	return r->r_total - r->r_reset; | ||||
| } | ||||
|  | ||||
| void attr_calc_usage(struct attr *a, float *rx, float *tx, | ||||
| 		     uint64_t rxmax, uint64_t txmax) | ||||
| { | ||||
| @ -626,6 +631,14 @@ void attr_notify_update(struct attr *a, timestamp_t *ts) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void attr_reset_counter(struct attr *a) | ||||
| { | ||||
| 	if (a->a_def->ad_type == ATTR_TYPE_COUNTER) { | ||||
| 		a->a_rx_rate.r_reset = a->a_rx_rate.r_total; | ||||
| 		a->a_tx_rate.r_reset = a->a_tx_rate.r_total; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void __exit attr_exit(void) | ||||
| { | ||||
| 	struct attr_def *ad, *n; | ||||
|  | ||||
							
								
								
									
										55
									
								
								src/bmon.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								src/bmon.c
									
									
									
									
									
								
							| @ -33,8 +33,6 @@ | ||||
| #include <bmon/group.h> | ||||
|  | ||||
| int start_time; | ||||
| int do_quit = 0; | ||||
| int is_daemon = 0; | ||||
|  | ||||
| struct reader_timing rtiming; | ||||
|  | ||||
| @ -69,14 +67,14 @@ static char *usage_text = | ||||
| "   Examples:\n" \ | ||||
| "       -o curses:ngraph=2\n" \ | ||||
| "       -o list            # Shows a list of available modules\n" \ | ||||
| "       -o curses:help     # Shows a help text for html module\n" \ | ||||
| "       -o curses:help     # Shows a help text for curses module\n" \ | ||||
| "\n" \ | ||||
| "Interface selection:\n" \ | ||||
| "   policy  := [!]simple_regexp,[!]simple_regexp,...\n" \ | ||||
| "\n" \ | ||||
| "   Example: -p 'eth*,lo*,!eth1'\n" \ | ||||
| "\n" \ | ||||
| "Please see the bmon(1) man pages for full documentation.\n"; | ||||
| "Please see the bmon(8) man pages for full documentation.\n"; | ||||
|  | ||||
| static void do_shutdown(void) | ||||
| { | ||||
| @ -88,14 +86,7 @@ static void do_shutdown(void) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| RETSIGTYPE sig_int(int unused) | ||||
| { | ||||
| 	if (do_quit) | ||||
| 		exit(-1); | ||||
| 	do_quit = 1; | ||||
| } | ||||
|  | ||||
| void sig_exit(void) | ||||
| static void sig_exit(void) | ||||
| { | ||||
| 	do_shutdown(); | ||||
| } | ||||
| @ -120,7 +111,7 @@ void quit(const char *fmt, ...) | ||||
| static inline void print_version(void) | ||||
| { | ||||
| 	printf("bmon %s\n", PACKAGE_VERSION); | ||||
| 	printf("Copyright (C) 2001-2013 by Thomas Graf <tgraf@suug.ch>\n"); | ||||
| 	printf("Copyright (C) 2001-2015 by Thomas Graf <tgraf@suug.ch>\n"); | ||||
| 	printf("Copyright (C) 2013 Red Hat, Inc.\n"); | ||||
| 	printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \ | ||||
| 	       "software, and you\nare welcome to redistribute it under " \ | ||||
| @ -136,10 +127,10 @@ static void parse_args_pre(int argc, char *argv[]) | ||||
| 		char *gostr = "+:hvVf:"; | ||||
|  | ||||
| 		struct option long_opts[] = { | ||||
| 			{"help", 0, 0, 'h'}, | ||||
| 			{"version", 0, 0, 'v'}, | ||||
| 			{"configfile", 1, 0, 'f'}, | ||||
| 			{0, 0, 0, 0}, | ||||
| 			{"help", 0, NULL, 'h'}, | ||||
| 			{"version", 0, NULL, 'v'}, | ||||
| 			{"configfile", 1, NULL, 'f'}, | ||||
| 			{NULL, 0, NULL, 0}, | ||||
| 		}; | ||||
| 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | ||||
| 		if (c == -1) | ||||
| @ -175,17 +166,17 @@ static int parse_args_post(int argc, char *argv[]) | ||||
| 			      "L:hvVf:"; | ||||
|  | ||||
| 		struct option long_opts[] = { | ||||
| 			{"input", 1, 0, 'i'}, | ||||
| 			{"output", 1, 0, 'o'}, | ||||
| 			{"policy", 1, 0, 'p'}, | ||||
| 			{"read-interval", 1, 0, 'r'}, | ||||
| 			{"rate-interval", 1, 0, 'R'}, | ||||
| 			{"sleep-interval", 1, 0, 's'}, | ||||
| 			{"show-all", 0, 0, 'a'}, | ||||
| 			{"use-si", 0, 0, 'U'}, | ||||
| 			{"use-bit", 0, 0, 'b'}, | ||||
| 			{"lifetime", 1, 0, 'L'}, | ||||
| 			{0, 0, 0, 0}, | ||||
| 			{"input", 1, NULL, 'i'}, | ||||
| 			{"output", 1, NULL, 'o'}, | ||||
| 			{"policy", 1, NULL, 'p'}, | ||||
| 			{"read-interval", 1, NULL, 'r'}, | ||||
| 			{"rate-interval", 1, NULL, 'R'}, | ||||
| 			{"sleep-interval", 1, NULL, 's'}, | ||||
| 			{"show-all", 0, NULL, 'a'}, | ||||
| 			{"use-si", 0, NULL, 'U'}, | ||||
| 			{"use-bit", 0, NULL, 'b'}, | ||||
| 			{"lifetime", 1, NULL, 'L'}, | ||||
| 			{NULL, 0, NULL, 0}, | ||||
| 		}; | ||||
| 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | ||||
| 		if (c == -1) | ||||
| @ -220,7 +211,7 @@ static int parse_args_post(int argc, char *argv[]) | ||||
| 				break; | ||||
|  | ||||
| 			case 'a': | ||||
| 				cfg_setint(cfg, "show_all", 1); | ||||
| 				cfg_setbool(cfg, "show_all", cfg_true); | ||||
| 				break; | ||||
|  | ||||
| 			case 'U': | ||||
| @ -270,7 +261,7 @@ int main(int argc, char *argv[]) | ||||
| 	unsigned long sleep_time; | ||||
| 	double read_interval; | ||||
| 	 | ||||
| 	start_time = time(0); | ||||
| 	start_time = time(NULL); | ||||
| 	memset(&rtiming, 0, sizeof(rtiming)); | ||||
| 	rtiming.rt_variance.v_min = FLT_MAX; | ||||
|  | ||||
| @ -361,9 +352,6 @@ int main(int argc, char *argv[]) | ||||
| 				output_post(); | ||||
| 			} | ||||
|  | ||||
| 			if (do_quit) | ||||
| 				exit(0); | ||||
|  | ||||
| 			/* | ||||
| 			 * ST := Configured ST | ||||
| 			 */ | ||||
| @ -399,5 +387,4 @@ int main(int argc, char *argv[]) | ||||
| static void __init bmon_init(void) | ||||
| { | ||||
| 	atexit(&sig_exit); | ||||
| 	//signal(SIGINT, &sig_int); | ||||
| } | ||||
|  | ||||
							
								
								
									
										88
									
								
								src/conf.c
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								src/conf.c
									
									
									
									
									
								
							| @ -30,6 +30,7 @@ | ||||
| #include <bmon/element.h> | ||||
| #include <bmon/element_cfg.h> | ||||
| #include <bmon/history.h> | ||||
| #include <bmon/layout.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
| cfg_t *cfg; | ||||
| @ -69,6 +70,16 @@ static cfg_opt_t unit_opts[] = { | ||||
| 	CFG_END() | ||||
| }; | ||||
|  | ||||
| static cfg_opt_t color_opts[] = { | ||||
|     CFG_STR_LIST("color_pair", "", CFGF_NONE), | ||||
|     CFG_END() | ||||
| }; | ||||
|  | ||||
| static cfg_opt_t layout_opts[] = { | ||||
|     CFG_SEC("color", color_opts, CFGF_MULTI | CFGF_TITLE), | ||||
|     CFG_END() | ||||
| }; | ||||
|  | ||||
| static cfg_opt_t global_opts[] = { | ||||
| 	CFG_FLOAT("read_interval", 1.0f, CFGF_NONE), | ||||
| 	CFG_FLOAT("rate_interval", 1.0f, CFGF_NONE), | ||||
| @ -87,6 +98,7 @@ static cfg_opt_t global_opts[] = { | ||||
| 	CFG_SEC("attr", attr_opts, CFGF_MULTI | CFGF_TITLE), | ||||
| 	CFG_SEC("history", history_opts, CFGF_MULTI | CFGF_TITLE), | ||||
| 	CFG_SEC("element", element_opts, CFGF_MULTI | CFGF_TITLE), | ||||
|     CFG_SEC("layout", layout_opts, CFGF_MULTI | CFGF_TITLE), | ||||
| 	CFG_END() | ||||
| }; | ||||
|  | ||||
| @ -109,16 +121,20 @@ struct layout cfg_layout[] = | ||||
|     {-1, -1, 0},            /* header */ | ||||
|     {-1, -1, 0},            /* list */ | ||||
|     {-1, -1, A_REVERSE},    /* selected */ | ||||
|     {-1, -1, 0},            /* RX graph */ | ||||
|     {-1, -1, 0},            /* TX graph */ | ||||
| }; | ||||
| #else | ||||
| struct layout cfg_layout[] = | ||||
| { | ||||
| 	{0, 0, 0},                               /* dummy, not used */ | ||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* default */ | ||||
| 	{COLOR_BLACK, COLOR_WHITE, A_REVERSE},  /* statusbar */ | ||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* header */ | ||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* list */ | ||||
| 	{COLOR_BLACK, COLOR_WHITE, A_REVERSE},  /* selected */ | ||||
| 	{COLOR_WHITE, COLOR_BLACK, 0},           /* default */ | ||||
| 	{COLOR_BLUE,   COLOR_GREEN, A_REVERSE},  /* statusbar */ | ||||
| 	{COLOR_GREEN,  COLOR_BLACK, 0},          /* header */ | ||||
| 	{COLOR_WHITE,  COLOR_BLACK, 0},          /* list */ | ||||
| 	{COLOR_YELLOW, COLOR_BLACK, A_REVERSE},  /* selected */ | ||||
|     {COLOR_GREEN,  COLOR_BLACK, 0},          /* RX graph */ | ||||
|     {COLOR_RED,    COLOR_BLACK, 0},          /* TX graph */ | ||||
| }; | ||||
| #endif | ||||
| #endif | ||||
| @ -371,7 +387,7 @@ static void configfile_read_units(void) | ||||
|  | ||||
| static void configfile_read_attrs(void) | ||||
| { | ||||
| 	int i, nattrs, t; | ||||
| 	int i, nattrs, t = 0; | ||||
|  | ||||
| 	nattrs = cfg_size(cfg, "attr"); | ||||
|  | ||||
| @ -423,6 +439,41 @@ static void configfile_read_attrs(void) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void configfile_read_layout_cfg(void) | ||||
| { | ||||
|     int i, nlayouts; | ||||
|     cfg_t *lout; | ||||
|     nlayouts = cfg_size(cfg, "layout"); | ||||
|     for (i = 0; i < nlayouts; i++) | ||||
|     { | ||||
|         int c, ncolors; | ||||
|         const char *name; | ||||
|         if (!(lout = cfg_getnsec(cfg, "layout", i))) | ||||
|             BUG(); | ||||
|  | ||||
|         if (!(name = cfg_title(lout))) | ||||
|             BUG(); | ||||
|  | ||||
|         ncolors = cfg_size(lout, "color"); | ||||
|         if (ncolors > LAYOUT_MAX) { | ||||
|             fprintf(stderr, "Warning excceeded maximum number of layouts\n"); | ||||
|             ncolors = LAYOUT_MAX; | ||||
|         } | ||||
|  | ||||
|         for (c = 0; c < ncolors; c++) { | ||||
|             cfg_t *color_pair; | ||||
|  | ||||
|             if (!(color_pair = cfg_getnsec(lout, "color", c))) | ||||
|                 BUG(); | ||||
|  | ||||
|             if (!(name = cfg_title(color_pair))) | ||||
|                 BUG(); | ||||
|  | ||||
|             add_layout(name, color_pair); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void conf_read(const char *path, int must) | ||||
| { | ||||
| 	int err; | ||||
| @ -450,6 +501,7 @@ static void conf_read(const char *path, int must) | ||||
| 	configfile_read_history(); | ||||
| 	configfile_read_attrs(); | ||||
| 	configfile_read_element_cfg(); | ||||
|     configfile_read_layout_cfg(); | ||||
| } | ||||
|  | ||||
| static const char default_config[] = \ | ||||
| @ -508,6 +560,29 @@ static const char default_config[] = \ | ||||
| "history day {" \ | ||||
| "	interval	= 86400.0" \ | ||||
| "	size		= 60" \ | ||||
| "}" | ||||
| "layout colors {" \ | ||||
| "   color default {" \ | ||||
| "       color_pair = { \"white\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color statusbar{" \ | ||||
| "       color_pair = { \"blue\", \"white\", \"reverse\" }" \ | ||||
| "   }" \ | ||||
| "   color header {" \ | ||||
| "       color_pair = { \"yellow\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color list {" \ | ||||
| "       color_pair = { \"white\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color selected {" \ | ||||
| "       color_pair = { \"yellow\", \"black\", \"reverse\" }" \ | ||||
| "   }" \ | ||||
| "   color rx_graph {" \ | ||||
| "       color_pair = { \"green\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "   color tx_graph {" \ | ||||
| "       color_pair = { \"red\", \"black\" }" \ | ||||
| "   }" \ | ||||
| "}"; | ||||
|  | ||||
| static void conf_read_default(void) | ||||
| @ -524,6 +599,7 @@ static void conf_read_default(void) | ||||
| 	configfile_read_history(); | ||||
| 	configfile_read_attrs(); | ||||
| 	configfile_read_element_cfg(); | ||||
|     configfile_read_layout_cfg(); | ||||
| } | ||||
|  | ||||
| void configfile_read(void) | ||||
|  | ||||
| @ -113,8 +113,9 @@ void element_parse_policy(const char *policy) | ||||
| 	xfree(copy); | ||||
| } | ||||
|  | ||||
| struct element *__lookup_element(struct element_group *group, const char *name, | ||||
| 				 uint32_t id, struct element *parent) | ||||
| static struct element *__lookup_element(struct element_group *group, | ||||
| 					const char *name, uint32_t id, | ||||
| 					struct element *parent) | ||||
| { | ||||
| 	struct list_head *list; | ||||
| 	struct element *e; | ||||
| @ -200,12 +201,6 @@ void element_free(struct element *e) | ||||
| 	struct attr *a, *an; | ||||
| 	int i; | ||||
|  | ||||
| 	if (e->e_group->g_current == e) { | ||||
| 		element_select_prev(); | ||||
| 		if (e->e_group->g_current == e) | ||||
| 			e->e_group->g_current = NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_for_each_entry_safe(c, cnext, &e->e_childs, e_list) | ||||
| 		element_free(c); | ||||
|  | ||||
| @ -220,6 +215,12 @@ void element_free(struct element *e) | ||||
| 		list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list) | ||||
| 			attr_free(a); | ||||
|  | ||||
| 	if (e->e_group->g_current == e) { | ||||
| 		element_select_prev(); | ||||
| 		if (e->e_group->g_current == e) | ||||
| 			e->e_group->g_current = NULL; | ||||
| 	} | ||||
|  | ||||
| 	list_del(&e->e_list); | ||||
| 	e->e_group->g_nelements--; | ||||
|  | ||||
| @ -357,6 +358,26 @@ int element_set_usage_attr(struct element *e, const char *usage) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void element_pick_from_policy(struct element_group *g) | ||||
| { | ||||
| 	if (!list_empty(&allowed)) { | ||||
| 		struct policy *p; | ||||
|  | ||||
| 		list_for_each_entry(p, &allowed, p_list) { | ||||
| 			struct element *e; | ||||
|  | ||||
| 			list_for_each_entry(e, &g->g_elements, e_list) { | ||||
| 				if (match_mask(p, e->e_name)) { | ||||
| 					g->g_current = e; | ||||
| 					return; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	element_select_first(); | ||||
| } | ||||
|  | ||||
| struct element *element_current(void) | ||||
| { | ||||
| 	struct element_group *g; | ||||
| @ -364,8 +385,12 @@ struct element *element_current(void) | ||||
| 	if (!(g = group_current())) | ||||
| 		return NULL; | ||||
|  | ||||
| 	/* | ||||
| 	 * If no element is picked yet, pick a default interface according to | ||||
| 	 * the selection policy. | ||||
| 	 */ | ||||
| 	if (!g->g_current) | ||||
| 		element_select_first(); | ||||
| 		element_pick_from_policy(g); | ||||
|  | ||||
| 	return g->g_current; | ||||
| } | ||||
|  | ||||
							
								
								
									
										20
									
								
								src/graph.c
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								src/graph.c
									
									
									
									
									
								
							| @ -58,26 +58,6 @@ static inline char *tbl_pos(struct graph_cfg *cfg, char *tbl, int nrow, int ncol | ||||
| 	return at_col(at_row(cfg, tbl, nrow), ncol); | ||||
| } | ||||
|  | ||||
| static void write_column(struct graph_cfg *cfg, struct graph_table *tbl, int ncol, | ||||
| 			 uint64_t value, double *scale, double half_step) | ||||
| { | ||||
| 	char *col = at_col(tbl->gt_table, ncol); | ||||
| 	int i; | ||||
|  | ||||
| #if 0 | ||||
| 	if (value == UNK_DATA) { | ||||
| 		for (i = 0; i < height; i++) | ||||
| 			*(at_row(g, col, i)) = unk_char; | ||||
| #endif | ||||
| 	if (value) { | ||||
| 		*(at_row(cfg, col, 0)) = ':'; | ||||
|  | ||||
| 		for (i = 0; i < cfg->gc_height; i++) | ||||
| 			if (value >= (scale[i] - half_step)) | ||||
| 				*(at_row(cfg, col, i)) = cfg->gc_foreground; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void fill_table(struct graph *g, struct graph_table *tbl, | ||||
| 		       struct history *h, struct history_store *data) | ||||
| { | ||||
|  | ||||
| @ -261,7 +261,7 @@ static void __init group_init(void) | ||||
| { | ||||
| 	DBG("init"); | ||||
|  | ||||
| 	group_new_hdr("intf", "Interfaces", | ||||
| 	group_new_hdr(DEFAULT_GROUP, "Interfaces", | ||||
| 		      "RX bps", "pps", "TX bps", "pps"); | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -89,7 +89,11 @@ static void dummy_read(void) | ||||
| 		char gname[32]; | ||||
| 		struct element_group *group; | ||||
|  | ||||
| 		if (gidx == 0) | ||||
| 			snprintf(gname, sizeof(gname), "%s", DEFAULT_GROUP); | ||||
| 		else | ||||
| 			snprintf(gname, sizeof(gname), "group%02d", gidx); | ||||
|  | ||||
| 		group = group_lookup(gname, GROUP_CREATE); | ||||
|  | ||||
| 		for (n = 0; n < c_numdev; n++) { | ||||
| @ -185,7 +189,7 @@ static void dummy_parse_opt(const char *type, const char *value) | ||||
| 		c_numdev = strtol(value, NULL, 0); | ||||
| 	else if (!strcasecmp(type, "randomize")) { | ||||
| 		c_randomize = 1; | ||||
| 		srand(time(0)); | ||||
| 		srand(time(NULL)); | ||||
| 	} else if (!strcasecmp(type, "seed") && value) | ||||
| 		srand(strtol(value, NULL, 0)); | ||||
| 	else if (!strcasecmp(type, "mtu") && value) | ||||
|  | ||||
							
								
								
									
										129
									
								
								src/in_netlink.c
									
									
									
									
									
								
							
							
						
						
									
										129
									
								
								src/in_netlink.c
									
									
									
									
									
								
							| @ -37,6 +37,8 @@ static int c_notc = 0; | ||||
| static struct element_group *grp; | ||||
| static struct bmon_module netlink_ops; | ||||
|  | ||||
| #include <linux/if.h> | ||||
|  | ||||
| #include <netlink/netlink.h> | ||||
| #include <netlink/cache.h> | ||||
| #include <netlink/utils.h> | ||||
| @ -47,6 +49,22 @@ static struct bmon_module netlink_ops; | ||||
| #include <netlink/route/classifier.h> | ||||
| #include <netlink/route/qdisc/htb.h> | ||||
|  | ||||
| /* These counters are not available prior to libnl 3.2.25. Set them to -1 so | ||||
|  * rtnl_link_get_stat() won't be called for them. */ | ||||
| #if LIBNL_CURRENT < 220 | ||||
| # define RTNL_LINK_ICMP6_CSUMERRORS	-1 | ||||
| # define RTNL_LINK_IP6_CSUMERRORS	-1 | ||||
| # define RTNL_LINK_IP6_NOECTPKTS	-1 | ||||
| # define RTNL_LINK_IP6_ECT1PKTS		-1 | ||||
| # define RTNL_LINK_IP6_ECT0PKTS		-1 | ||||
| # define RTNL_LINK_IP6_CEPKTS		-1 | ||||
| #endif | ||||
|  | ||||
| /* Not available prior to libnl 3.2.29 */ | ||||
| #if LIBNL_CURRENT < 224 | ||||
| # define RTNL_LINK_RX_NOHANDLER		-1 | ||||
| #endif | ||||
|  | ||||
| static struct attr_map link_attrs[] = { | ||||
| { | ||||
| 	.name		= "bytes", | ||||
| @ -88,6 +106,14 @@ static struct attr_map link_attrs[] = { | ||||
| 	.rxid		= RTNL_LINK_RX_COMPRESSED, | ||||
| 	.txid		= RTNL_LINK_TX_COMPRESSED, | ||||
| }, | ||||
| { | ||||
| 	.name		= "nohandler", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "No Handler", | ||||
| 	.rxid		= RTNL_LINK_RX_NOHANDLER, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "fifoerr", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| @ -280,6 +306,14 @@ static struct attr_map link_attrs[] = { | ||||
| 	.rxid		= RTNL_LINK_ICMP6_INERRORS, | ||||
| 	.txid		= RTNL_LINK_ICMP6_OUTERRORS, | ||||
| }, | ||||
| { | ||||
| 	.name		= "icmp6csumerr", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "ICMPv6 Checksum Errors", | ||||
| 	.rxid		= RTNL_LINK_ICMP6_CSUMERRORS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6inhdrerr", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| @ -320,6 +354,14 @@ static struct attr_map link_attrs[] = { | ||||
| 	.rxid		= RTNL_LINK_IP6_INADDRERRORS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6csumerr", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "Ip6 Checksum Error", | ||||
| 	.rxid		= RTNL_LINK_IP6_CSUMERRORS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6reasmtimeo", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| @ -351,6 +393,38 @@ static struct attr_map link_attrs[] = { | ||||
| 	.description	= "Ip6 Reasm/Frag Requests", | ||||
| 	.rxid		= RTNL_LINK_IP6_REASMREQDS, | ||||
| 	.txid		= RTNL_LINK_IP6_FRAGCREATES, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6noectpkts", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "Ip6 Non-ECT Packets", | ||||
| 	.rxid		= RTNL_LINK_IP6_NOECTPKTS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6ect1pkts", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "Ip6 ECT(1) Packets", | ||||
| 	.rxid		= RTNL_LINK_IP6_ECT1PKTS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6ect0pkts", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "Ip6 ECT(0) Packets", | ||||
| 	.rxid		= RTNL_LINK_IP6_ECT0PKTS, | ||||
| 	.txid		= -1, | ||||
| }, | ||||
| { | ||||
| 	.name		= "ip6cepkts", | ||||
| 	.type		= ATTR_TYPE_COUNTER, | ||||
| 	.unit		= UNIT_NUMBER, | ||||
| 	.description	= "Ip6 CE Packets", | ||||
| 	.rxid		= RTNL_LINK_IP6_CEPKTS, | ||||
| 	.txid		= -1, | ||||
| } | ||||
| }; | ||||
|  | ||||
| @ -430,12 +504,13 @@ static struct attr_map tc_attrs[] = { | ||||
| }; | ||||
|  | ||||
| struct rdata { | ||||
| 	struct nl_cache *	class_cache; | ||||
| 	struct element *	parent; | ||||
| 	int 			level; | ||||
| }; | ||||
|  | ||||
| static struct nl_sock *sock; | ||||
| static struct nl_cache *link_cache, *qdisc_cache, *class_cache; | ||||
| static struct nl_cache *link_cache, *qdisc_cache; | ||||
|  | ||||
| static void update_tc_attrs(struct element *e, struct rtnl_tc *tc) | ||||
| { | ||||
| @ -470,10 +545,10 @@ static void update_tc_infos(struct element *e, struct rtnl_tc *tc) | ||||
|  | ||||
| static void handle_qdisc(struct nl_object *obj, void *); | ||||
| static void find_classes(uint32_t, struct rdata *); | ||||
| static void find_qdiscs(uint32_t, struct rdata *); | ||||
| static void find_qdiscs(int, uint32_t, struct rdata *); | ||||
|  | ||||
| static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix, | ||||
| 				     struct rdata *rdata) | ||||
| 				     const struct rdata *rdata) | ||||
| { | ||||
| 	char buf[IFNAME_MAX], name[IFNAME_MAX]; | ||||
| 	uint32_t id = rtnl_tc_get_handle(tc); | ||||
| @ -483,11 +558,14 @@ static struct element *handle_tc_obj(struct rtnl_tc *tc, const char *prefix, | ||||
| 	snprintf(name, sizeof(name), "%s %s (%s)", | ||||
| 		 prefix, buf, rtnl_tc_get_kind(tc)); | ||||
|  | ||||
| 	if (!(e = element_lookup(grp, name, id, rdata ? rdata->parent : NULL, ELEMENT_CREAT))) | ||||
| 	if (!rdata || !rdata->parent) | ||||
| 		BUG(); | ||||
|  | ||||
| 	if (!(e = element_lookup(grp, name, id, rdata->parent, ELEMENT_CREAT))) | ||||
| 		return NULL; | ||||
|  | ||||
| 	if (e->e_flags & ELEMENT_FLAG_CREATED) { | ||||
| 		e->e_level = rdata ? rdata->level : 0; | ||||
| 		e->e_level = rdata->level; | ||||
|  | ||||
| 		if (element_set_key_attr(e, "tc_bytes", "tc_packets") || | ||||
| 		    element_set_usage_attr(e, "tc_bytes")) | ||||
| @ -518,8 +596,9 @@ static void handle_class(struct nl_object *obj, void *arg) | ||||
| { | ||||
| 	struct rtnl_tc *tc = (struct rtnl_tc *) obj; | ||||
| 	struct element *e; | ||||
| 	struct rdata *rdata = arg; | ||||
| 	const struct rdata *rdata = arg; | ||||
| 	struct rdata ndata = { | ||||
| 		.class_cache = rdata->class_cache, | ||||
| 		.level = rdata->level + 1, | ||||
| 	}; | ||||
|  | ||||
| @ -532,10 +611,10 @@ static void handle_class(struct nl_object *obj, void *arg) | ||||
| 		element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc)); | ||||
|  | ||||
| 	find_classes(rtnl_tc_get_handle(tc), &ndata); | ||||
| 	find_qdiscs(rtnl_tc_get_handle(tc), &ndata); | ||||
| 	find_qdiscs(rtnl_tc_get_ifindex(tc), rtnl_tc_get_handle(tc), &ndata); | ||||
| } | ||||
|  | ||||
| static void find_qdiscs(uint32_t parent, struct rdata *rdata) | ||||
| static void find_qdiscs(int ifindex, uint32_t parent, struct rdata *rdata) | ||||
| { | ||||
| 	struct rtnl_qdisc *filter; | ||||
|  | ||||
| @ -543,6 +622,7 @@ static void find_qdiscs(uint32_t parent, struct rdata *rdata) | ||||
| 		return; | ||||
|  | ||||
| 	rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); | ||||
| 	rtnl_tc_set_ifindex((struct rtnl_tc *) filter, ifindex); | ||||
|  | ||||
| 	nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), | ||||
| 				handle_qdisc, rdata); | ||||
| @ -571,7 +651,7 @@ static void find_classes(uint32_t parent, struct rdata *rdata) | ||||
|  | ||||
| 	rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); | ||||
|  | ||||
| 	nl_cache_foreach_filter(class_cache, OBJ_CAST(filter), | ||||
| 	nl_cache_foreach_filter(rdata->class_cache, OBJ_CAST(filter), | ||||
| 				handle_class, rdata); | ||||
|  | ||||
| 	rtnl_class_put(filter); | ||||
| @ -581,8 +661,9 @@ static void handle_qdisc(struct nl_object *obj, void *arg) | ||||
| { | ||||
| 	struct rtnl_tc *tc = (struct rtnl_tc *) obj; | ||||
| 	struct element *e; | ||||
| 	struct rdata *rdata = arg; | ||||
| 	const struct rdata *rdata = arg; | ||||
| 	struct rdata ndata = { | ||||
| 		.class_cache = rdata->class_cache, | ||||
| 		.level = rdata->level + 1, | ||||
| 	}; | ||||
|  | ||||
| @ -604,6 +685,7 @@ static void handle_qdisc(struct nl_object *obj, void *arg) | ||||
| static void handle_tc(struct element *e, struct rtnl_link *link) | ||||
| { | ||||
| 	struct rtnl_qdisc *qdisc; | ||||
| 	struct nl_cache *class_cache; | ||||
| 	int ifindex = rtnl_link_get_ifindex(link); | ||||
| 	struct rdata rdata = { | ||||
| 		.level = 1, | ||||
| @ -613,6 +695,8 @@ static void handle_tc(struct element *e, struct rtnl_link *link) | ||||
| 	if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0) | ||||
| 		return; | ||||
|  | ||||
| 	rdata.class_cache = class_cache; | ||||
|  | ||||
| 	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); | ||||
| 	if (qdisc) { | ||||
| 		handle_qdisc(OBJ_CAST(qdisc), &rdata); | ||||
| @ -736,7 +820,7 @@ static void do_link(struct nl_object *obj, void *arg) | ||||
| 		attr_update(e, m->attrid, c_rx, c_tx, flags); | ||||
| 	} | ||||
|  | ||||
| 	if (!c_notc) | ||||
| 	if (!c_notc && qdisc_cache) | ||||
| 		handle_tc(e, link); | ||||
|  | ||||
| 	element_notify_update(e, NULL); | ||||
| @ -752,7 +836,8 @@ static void netlink_read(void) | ||||
| 		goto disable; | ||||
| 	} | ||||
|  | ||||
| 	if ((err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) { | ||||
| 	if (qdisc_cache && | ||||
| 	    (err = nl_cache_resync(sock, qdisc_cache, NULL, NULL)) < 0) { | ||||
| 		fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err)); | ||||
| 		goto disable; | ||||
| 	} | ||||
| @ -772,9 +857,20 @@ static void netlink_shutdown(void) | ||||
| 	nl_socket_free(sock); | ||||
| } | ||||
|  | ||||
| static void netlink_use_bit(struct attr_map *map, const int size) | ||||
| { | ||||
| 	if(cfg_getbool(cfg, "use_bit")) { | ||||
| 		for(int i = 0; i < size; ++i) { | ||||
| 			if(!strcmp(map[i].description, "Bytes")) { | ||||
| 				map[i].description = "Bits"; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int netlink_do_init(void) | ||||
| { | ||||
| 	int err, i; | ||||
| 	int err; | ||||
|  | ||||
| 	if (!(sock = nl_socket_alloc())) { | ||||
| 		fprintf(stderr, "Unable to allocate netlink socket\n"); | ||||
| @ -792,10 +888,13 @@ static int netlink_do_init(void) | ||||
| 	} | ||||
|  | ||||
| 	if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) { | ||||
| 		fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err)); | ||||
| 		goto disable; | ||||
| 		fprintf(stderr, "Warning: Unable to allocate qdisc cache: %s\n", nl_geterror(err)); | ||||
| 		fprintf(stderr, "Disabling QoS statistics.\n"); | ||||
| 		qdisc_cache = NULL; | ||||
| 	} | ||||
|  | ||||
| 	netlink_use_bit(link_attrs, ARRAY_SIZE(link_attrs)); | ||||
| 	netlink_use_bit(tc_attrs, ARRAY_SIZE(tc_attrs)); | ||||
| 	if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) || | ||||
| 	    attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs))) | ||||
| 		BUG(); | ||||
|  | ||||
| @ -101,7 +101,7 @@ static void proc_read(void) | ||||
| { | ||||
| 	struct element *e; | ||||
| 	FILE *fd; | ||||
| 	char buf[512], *p, *s, *unused; | ||||
| 	char buf[512], *p, *s, *unused __unused__; | ||||
| 	int w; | ||||
| 	 | ||||
| 	if (!(fd = fopen(c_path, "r"))) | ||||
|  | ||||
| @ -163,6 +163,7 @@ sysctl_read(void) | ||||
| 		struct element *e, *e_parent = NULL; | ||||
| 		struct if_msghdr *ifm, *nextifm; | ||||
| 		struct sockaddr_dl *sdl; | ||||
| 		char info_buf[64]; | ||||
|  | ||||
| 		ifm = (struct if_msghdr *) next; | ||||
| 		if (ifm->ifm_type != RTM_IFINFO) | ||||
| @ -225,6 +226,20 @@ sysctl_read(void) | ||||
| 			attr_update(e, m->attrid, rx, tx, flags); | ||||
| 		} | ||||
|  | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%ju", (uintmax_t)ifm->ifm_data.ifi_mtu); | ||||
| 		element_update_info(e, "MTU", info_buf); | ||||
|  | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%ju", (uintmax_t)ifm->ifm_data.ifi_metric); | ||||
| 		element_update_info(e, "Metric", info_buf); | ||||
|  | ||||
| #if !(defined(__NetBSD__) || defined(__FreeBSD__)) | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_recvquota); | ||||
| 		element_update_info(e, "RX-Quota", info_buf); | ||||
|  | ||||
| 		snprintf(info_buf, sizeof(info_buf), "%u", ifm->ifm_data.ifi_xmitquota); | ||||
| 		element_update_info(e, "TX-Quota", info_buf); | ||||
| #endif | ||||
|  | ||||
| 		element_notify_update(e, NULL); | ||||
| 		element_lifesign(e, 1); | ||||
| 	} | ||||
|  | ||||
| @ -130,7 +130,6 @@ static void __auto_load(struct bmon_module *m) | ||||
| int module_set(struct bmon_subsys *ss, const char *name) | ||||
| { | ||||
| 	struct bmon_module *mod; | ||||
| 	struct list_head *list; | ||||
| 	LIST_HEAD(tmp_list); | ||||
| 	module_conf_t *m; | ||||
|  | ||||
|  | ||||
| @ -101,10 +101,10 @@ static void print_attr_detail(struct element *e, struct attr *a, void *arg) | ||||
| 	char *rx_u, *tx_u; | ||||
| 	int rxprec, txprec; | ||||
|  | ||||
| 	double rx = unit_value2str(a->a_rx_rate.r_total, | ||||
| 	double rx = unit_value2str(rate_get_total(&a->a_rx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &rx_u, &rxprec); | ||||
| 	double tx = unit_value2str(a->a_tx_rate.r_total, | ||||
| 	double tx = unit_value2str(rate_get_total(&a->a_tx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &tx_u, &txprec); | ||||
|  | ||||
| @ -212,6 +212,7 @@ static void ascii_draw_group(struct element_group *g, void *arg) | ||||
| static void ascii_draw(void) | ||||
| { | ||||
| 	group_foreach(ascii_draw_group, NULL); | ||||
| 	fflush(stdout); | ||||
|  | ||||
| 	if (c_quit_after > 0) | ||||
| 		if (--c_quit_after == 0) | ||||
|  | ||||
| @ -45,6 +45,8 @@ enum { | ||||
| 	KEY_TOGGLE_DETAILS	= 'd', | ||||
| 	KEY_TOGGLE_INFO		= 'i', | ||||
| 	KEY_COLLECT_HISTORY	= 'h', | ||||
| 	KEY_CTRL_N	= 14, | ||||
| 	KEY_CTRL_P	= 16, | ||||
| }; | ||||
|  | ||||
| #define DETAILS_COLS		40 | ||||
| @ -137,7 +139,7 @@ static void apply_layout(int layout) | ||||
| 		attrset(cfg_layout[layout].l_attr); | ||||
| } | ||||
|  | ||||
| char *float2str(double value, int width, int prec, char *buf, size_t len) | ||||
| static char *float2str(double value, int width, int prec, char *buf, size_t len) | ||||
| { | ||||
| 	snprintf(buf, len, "%'*.*f", width, value == 0.0f ? 0 : prec, value); | ||||
|  | ||||
| @ -147,22 +149,24 @@ char *float2str(double value, int width, int prec, char *buf, size_t len) | ||||
| static void put_line(const char *fmt, ...) | ||||
| { | ||||
| 	va_list args; | ||||
| 	char buf[2048]; | ||||
| 	int x, y; | ||||
| 	char *buf; | ||||
| 	int len; | ||||
| 	int x, y __unused__; | ||||
|  | ||||
| 	memset(buf, 0, sizeof(buf)); | ||||
| 	getyx(stdscr, y, x); | ||||
|  | ||||
| 	len = cols - x; | ||||
| 	buf = xcalloc(len+1, 1); | ||||
|  | ||||
| 	va_start(args, fmt); | ||||
| 	vsnprintf(buf, sizeof(buf), fmt, args); | ||||
| 	vsnprintf(buf, len+1, fmt, args); | ||||
| 	va_end(args); | ||||
|  | ||||
| 	if (strlen(buf) > cols-x) | ||||
| 		buf[cols - x] = '\0'; | ||||
| 	else | ||||
| 		memset(&buf[strlen(buf)], ' ', cols - strlen(buf)-x); | ||||
| 	if (strlen(buf) < len) | ||||
| 		memset(&buf[strlen(buf)], ' ', len - strlen(buf)); | ||||
|  | ||||
| 	addstr(buf); | ||||
| 	xfree(buf); | ||||
| } | ||||
|  | ||||
| static void center_text(const char *fmt, ...) | ||||
| @ -241,10 +245,10 @@ static void draw_attr_detail(struct element *e, struct attr *a, void *arg) | ||||
| 	int rxprec, txprec, ncol; | ||||
| 	struct detail_arg *da = arg; | ||||
|  | ||||
| 	double rx = unit_value2str(a->a_rx_rate.r_total, | ||||
| 	double rx = unit_value2str(rate_get_total(&a->a_rx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &rx_u, &rxprec); | ||||
| 	double tx = unit_value2str(a->a_tx_rate.r_total, | ||||
| 	double tx = unit_value2str(rate_get_total(&a->a_tx_rate), | ||||
| 				   a->a_def->ad_unit, | ||||
| 				   &tx_u, &txprec); | ||||
|  | ||||
| @ -258,7 +262,7 @@ static void draw_attr_detail(struct element *e, struct attr *a, void *arg) | ||||
| 	if (ncol > 0) | ||||
| 		addch(ACS_VLINE); | ||||
|  | ||||
| 	put_line(" %-14.14s %8s%-3s %8s%-3s\n", | ||||
| 	put_line(" %-14.14s %8s%-3s %8s%-3s", | ||||
| 		 a->a_def->ad_description, | ||||
| 		 (a->a_flags & ATTR_RX_ENABLED) ? | ||||
| 		 float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u, | ||||
| @ -392,6 +396,7 @@ static void draw_help(void) | ||||
| 	mvaddnstr(y+15, x+3, "H             Start recording history data", -1); | ||||
| 	mvaddnstr(y+16, x+3, "TAB           Switch time unit of graph", -1); | ||||
| 	mvaddnstr(y+17, x+3, "<, >          Change number of graphs", -1); | ||||
| 	mvaddnstr(y+18, x+3, "r             Reset counter of element", -1); | ||||
|  | ||||
| 	attroff(A_STANDOUT); | ||||
|  | ||||
| @ -419,6 +424,7 @@ static void draw_header(void) | ||||
| 	move(row, COLS - strlen(PACKAGE_STRING) - 1); | ||||
| 	put_line("%s", PACKAGE_STRING); | ||||
| 	move(row, 0); | ||||
| 	apply_layout(LAYOUT_LIST); | ||||
| } | ||||
|  | ||||
| static int lines_required_for_statusbar(void) | ||||
| @ -430,7 +436,7 @@ static void draw_statusbar(void) | ||||
| { | ||||
| 	static const char *help_text = "Press ? for help"; | ||||
| 	char s[27]; | ||||
| 	time_t t = time(0); | ||||
| 	time_t t = time(NULL); | ||||
|  | ||||
| 	apply_layout(LAYOUT_STATUSBAR); | ||||
|  | ||||
| @ -631,6 +637,7 @@ static void draw_element(struct element_group *g, struct element *e, | ||||
|  | ||||
| static void draw_group(struct element_group *g, void *arg) | ||||
| { | ||||
| 	apply_layout(LAYOUT_HEADER); | ||||
| 	int *line = arg; | ||||
|  | ||||
| 	if (line_visible(*line)) { | ||||
| @ -683,7 +690,7 @@ static void draw_graph_centered(struct graph *g, int row, int ncol, | ||||
|  | ||||
| static void draw_table(struct graph *g, struct graph_table *tbl, | ||||
| 		       struct attr *a, struct history *h, | ||||
| 		       const char *hdr, int ncol) | ||||
| 		       const char *hdr, int ncol, int layout) | ||||
| { | ||||
| 	int i, save_row; | ||||
| 	char buf[32]; | ||||
| @ -708,11 +715,14 @@ static void draw_table(struct graph *g, struct graph_table *tbl, | ||||
| 	//move(row, ncol + g->g_cfg.gc_width - 3); | ||||
| 	//put_line("[err %.2f%%]", rtiming.rt_variance.v_error); | ||||
|  | ||||
|     memset(buf, 0, strlen(buf)); | ||||
| 	for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) { | ||||
| 		move(++row, ncol); | ||||
| 		put_line("%'8.2f %s", | ||||
| 			tbl->gt_scale[i], | ||||
| 			tbl->gt_table + (i * graph_row_size(&g->g_cfg))); | ||||
|         sprintf(buf, "%'8.2f ", tbl->gt_scale[i]); | ||||
|         addstr(buf); | ||||
|         apply_layout(layout); | ||||
|         put_line("%s", tbl->gt_table + (i * graph_row_size(&g->g_cfg))); | ||||
|         apply_layout(LAYOUT_LIST); | ||||
| 	} | ||||
|  | ||||
| 	move(++row, ncol); | ||||
| @ -746,14 +756,14 @@ static void draw_history_graph(struct attr *a, struct history *h) | ||||
| 	graph_refill(g, h); | ||||
|  | ||||
| 	save_row = row; | ||||
| 	draw_table(g, &g->g_rx, a, h, "RX", ncol); | ||||
| 	draw_table(g, &g->g_rx, a, h, "RX", ncol, LAYOUT_RX_GRAPH); | ||||
|  | ||||
| 	if (graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE) { | ||||
| 		ncol = cols / 2; | ||||
| 		row = save_row; | ||||
| 	} | ||||
|  | ||||
| 	draw_table(g, &g->g_tx, a, h, "TX", ncol); | ||||
| 	draw_table(g, &g->g_tx, a, h, "TX", ncol, LAYOUT_TX_GRAPH); | ||||
|  | ||||
| 	graph_free(g); | ||||
| } | ||||
| @ -973,8 +983,10 @@ draw: | ||||
| 	 */ | ||||
| 	NEXT_ROW(); | ||||
| 	hline(ACS_HLINE, cols); | ||||
| 	if (c_show_list) { | ||||
| 		mvaddch(row, LIST_COL_1, ACS_BTEE); | ||||
| 		mvaddch(row, LIST_COL_2, ACS_BTEE); | ||||
| 	} | ||||
|  | ||||
| 	if (!c_show_graph) | ||||
| 		center_text(" Press %c to enable graphical statistics ", | ||||
| @ -1016,6 +1028,12 @@ draw: | ||||
| 	NEXT_ROW(); | ||||
| 	hline(ACS_HLINE, cols); | ||||
|  | ||||
| 	if (c_show_details) { | ||||
| 		int i; | ||||
| 		for (i = 1; i < detail_cols; i++) | ||||
| 			mvaddch(row, (i * DETAILS_COLS) - 1, ACS_BTEE); | ||||
| 	} | ||||
|  | ||||
| 	if (!c_show_info) | ||||
| 		center_text(" Press %c to enable additional information ", | ||||
| 			    KEY_TOGGLE_INFO); | ||||
| @ -1079,6 +1097,16 @@ out: | ||||
| 	refresh(); | ||||
| } | ||||
|  | ||||
| static void __reset_attr_counter(struct element *e, struct attr *a, void *arg) | ||||
| { | ||||
| 	attr_reset_counter(a); | ||||
| } | ||||
|  | ||||
| static void reset_counters(void) | ||||
| { | ||||
| 	element_foreach_attr(current_element, __reset_attr_counter, NULL); | ||||
| } | ||||
|  | ||||
| static int handle_input(int ch) | ||||
| { | ||||
| 	switch (ch)  | ||||
| @ -1160,10 +1188,12 @@ static int handle_input(int ch) | ||||
| 			return 1; | ||||
|  | ||||
| 		case KEY_DOWN: | ||||
| 		case KEY_CTRL_N: | ||||
| 			element_select_next(); | ||||
| 			return 1; | ||||
|  | ||||
| 		case KEY_UP: | ||||
| 		case KEY_CTRL_P: | ||||
| 			element_select_prev(); | ||||
| 			return 1; | ||||
|  | ||||
| @ -1198,6 +1228,10 @@ static int handle_input(int ch) | ||||
| 		case '\t': | ||||
| 			history_select_next(); | ||||
| 			return 1; | ||||
|  | ||||
| 		case 'r': | ||||
| 			reset_counters(); | ||||
| 			return 1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| @ -1232,7 +1266,7 @@ static void print_module_help(void) | ||||
| 	"  Author: Thomas Graf <tgraf@suug.ch>\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Options:\n" \ | ||||
| 	"    fgchar=CHAR    Foreground character (default: '*')\n" \ | ||||
| 	"    fgchar=CHAR    Foreground character (default: '|')\n" \ | ||||
| 	"    bgchar=CHAR    Background character (default: '.')\n" \ | ||||
| 	"    nchar=CHAR     Noise character (default: ':')\n" \ | ||||
| 	"    uchar=CHAR     Unknown character (default: '?')\n" \ | ||||
| @ -1242,6 +1276,7 @@ static void print_module_help(void) | ||||
| 	"    nocolors       Do not use colors\n" \ | ||||
| 	"    graph          Show graphical stats by default\n" \ | ||||
| 	"    details        Show detailed stats by default\n" \ | ||||
| 	"    info           Show additional info screen by default\n" \ | ||||
| 	"    minlist=INT    Minimum item list length\n"); | ||||
| } | ||||
|  | ||||
| @ -1264,6 +1299,8 @@ static void curses_parse_opt(const char *type, const char *value) | ||||
| 		c_show_graph = !!c_ngraph; | ||||
| 	} else if (!strcasecmp(type, "details")) | ||||
| 		c_show_details = 1; | ||||
| 	else if (!strcasecmp(type, "info")) | ||||
| 		c_show_info = 1; | ||||
| 	else if (!strcasecmp(type, "nocolors")) | ||||
| 		c_use_colors = 0; | ||||
| 	else if (!strcasecmp(type, "minlist") && value) | ||||
|  | ||||
| @ -119,25 +119,23 @@ static char *get_token(struct element_group *g, struct element *e, | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		if (!(a = attr_lookup(e, def->ad_id))) { | ||||
| 			fprintf(stderr, "Unable to find attribute %u (%s)\n", | ||||
| 				def->ad_id, name); | ||||
| 		if (!(a = attr_lookup(e, def->ad_id))) | ||||
| 			goto out; | ||||
| 		} | ||||
|  | ||||
| 		if (!strncasecmp(type, "rx:", 3)) { | ||||
| 			snprintf(buf, len, "%" PRIu64, a->a_rx_rate.r_total); | ||||
| 			snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_rx_rate)); | ||||
| 			return buf; | ||||
| 		} else if (!strncasecmp(type, "tx:", 3)) { | ||||
| 			snprintf(buf, len, "%" PRIu64, a->a_tx_rate.r_total); | ||||
| 			snprintf(buf, len, "%" PRIu64, rate_get_total(&a->a_tx_rate)); | ||||
| 			return buf; | ||||
| 		} else if (!strncasecmp(type, "rxrate:", 7)) { | ||||
| 			snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate); | ||||
| 			return buf; | ||||
| 		} else if (!strncasecmp(token+5, "txrate:", 7)) | ||||
| 		} else if (!strncasecmp(type, "txrate:", 7)) { | ||||
| 			snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate); | ||||
| 			return buf; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fprintf(stderr, "Unknown field \"%s\"\n", token); | ||||
| out: | ||||
| @ -168,6 +166,7 @@ static void draw_element(struct element_group *g, struct element *e, void *arg) | ||||
| static void format_draw(void) | ||||
| { | ||||
| 	group_foreach_recursive(draw_element, NULL); | ||||
| 	fflush(stdout); | ||||
|  | ||||
| 	if (c_quit_after > 0) | ||||
| 		if (--c_quit_after == 0) | ||||
| @ -322,15 +321,15 @@ static void print_help(void) | ||||
| 	"  Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Examples:\n" \ | ||||
| 	"    \"$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n\"\n" \ | ||||
| 	"    '$(element:name)\\t$(attr:rx:bytes)\\t$(attr:tx:bytes)\\n'\n" \ | ||||
| 	"    lo      12074   12074\n" \ | ||||
| 	"\n" \ | ||||
| 	"    \"$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n\"\n" \ | ||||
| 	"    '$(element:name) $(attr:rxrate:packets) $(attr:txrate:packets)\\n'\n" \ | ||||
| 	"    eth0 33 5\n" \ | ||||
| 	"\n" \ | ||||
| 	"    \"Element: $(element:name)\\nBytes Rate: \" \\\n" \ | ||||
| 	"        \"$(attr:rxrate:bytes)/$(attr:txrate:bytes)\\nPackets Rate: \" \\\n" \ | ||||
| 	"        \"$(attr:rxrate:packets)/$(attr:txrate:packets)\\n\"\n" \ | ||||
| 	"    'Item: $(element:name)\\nBytes Rate: $(attr:rxrate:bytes)/" \ | ||||
| 	"$(attr:txrate:bytes)\\nPackets Rate: $(attr:rxrate:packets)/" \ | ||||
| 	"$(attr:txrate:packets)\\n'\n" \ | ||||
| 	"    Item: eth0\n" \ | ||||
| 	"    Bytes Rate: 49130/2119\n" \ | ||||
| 	"    Packets Rate: 40/11\n" \ | ||||
|  | ||||
							
								
								
									
										197
									
								
								src/out_trigger.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								src/out_trigger.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,197 @@ | ||||
| /* | ||||
|  * out_trigger.c		Trigger based on traffic pattern | ||||
|  * | ||||
|  * Copyright (c) 2018 Babak Farrokhi <babak@farrokhi.net> | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a | ||||
|  * copy of this software and associated documentation files (the "Software"), | ||||
|  * to deal in the Software without restriction, including without limitation | ||||
|  * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||
|  * and/or sell copies of the Software, and to permit persons to whom the | ||||
|  * Software is furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included | ||||
|  * in all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | ||||
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||||
|  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||
|  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||
|  * DEALINGS IN THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| #include <bmon/bmon.h> | ||||
| #include <bmon/graph.h> | ||||
| #include <bmon/conf.h> | ||||
| #include <bmon/output.h> | ||||
| #include <bmon/group.h> | ||||
| #include <bmon/element.h> | ||||
| #include <bmon/input.h> | ||||
| #include <bmon/utils.h> | ||||
| #include <bmon/attr.h> | ||||
|  | ||||
| #define RECENT_SIZE 3 | ||||
|  | ||||
| static int c_quit_after_trigger = 0; | ||||
| static long c_threshold_high = -1; | ||||
| static long c_threshold_low = -1; | ||||
| static unsigned long recent_l[RECENT_SIZE]; | ||||
| static unsigned long recent_count = 0; | ||||
| static unsigned long recent_avg = 0; | ||||
| static unsigned long triggered = 0; | ||||
| static char *c_format; | ||||
| static FILE *c_fd; | ||||
|  | ||||
| static char *get_token(struct element_group *g, struct element *e, | ||||
| 		       const char *token, char *buf, size_t len) | ||||
| { | ||||
| 	char *name = strchr(token, ':'); | ||||
|  | ||||
| 	struct attr_def *def; | ||||
| 	struct attr *a; | ||||
|  | ||||
| 	if (!name) | ||||
| 		quit("Invalid attribute field \"%s\"\n", token); | ||||
|  | ||||
| 	name++; | ||||
|  | ||||
| 	def = attr_def_lookup(name); | ||||
| 	if (!def) | ||||
| 		quit("Undefined attribute \"%s\"\n", name); | ||||
|  | ||||
| 	if (!(a = attr_lookup(e, def->ad_id))) | ||||
| 		quit("Invalid attribute \"%s\"\n", name); | ||||
|  | ||||
| 	if (!strncasecmp(token, "rxrate:", 7)) { | ||||
| 		snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate); | ||||
| 		return buf; | ||||
| 	} else if (!strncasecmp(token, "txrate:", 7)) { | ||||
| 		snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate); | ||||
| 		return buf; | ||||
| 	} | ||||
|  | ||||
| 	quit("Unknown field \"%s\"\n", token); | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| static void run_trigger() | ||||
| { | ||||
| 	// TODO: Run the command | ||||
| 	if (++triggered >= c_quit_after_trigger) | ||||
| 		exit(0); | ||||
| } | ||||
|  | ||||
| static void trigger_check() | ||||
| { | ||||
| 	if (recent_count < RECENT_SIZE) | ||||
| 		return; | ||||
|  | ||||
| 	if (c_threshold_high > 0 && recent_avg > c_threshold_high) { | ||||
| 		fprintf(c_fd, "TRIGGER: Passed high threshold: %li > %li\n", recent_avg, c_threshold_high); | ||||
| 		run_trigger(); | ||||
| 		return; | ||||
| 	} | ||||
| 	if (c_threshold_low > 0 && recent_avg < c_threshold_low) { | ||||
| 		fprintf(c_fd, "TRIGGER: Droppped below threshold: %li < %li\n", recent_avg, c_threshold_low); | ||||
| 		run_trigger(); | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void trigger_process(struct element_group *g, struct element *e, void *arg) | ||||
| { | ||||
| 	char buf[128]; | ||||
| 	char *p; | ||||
|  | ||||
| 	p = get_token(g, e, c_format, buf, sizeof(buf)); | ||||
|  | ||||
| 	if (p) | ||||
| 	{ | ||||
| 		int i; | ||||
| 		unsigned long total = 0; | ||||
|  | ||||
| 		recent_l[recent_count % RECENT_SIZE] = strtol(p, NULL, 0); | ||||
| 		for (i=0; i < RECENT_SIZE; i++) | ||||
| 		{ | ||||
| 			fprintf(c_fd, "%li ", recent_l[i]); | ||||
| 			total += recent_l[i]; | ||||
| 		} | ||||
|  | ||||
| 		recent_avg = (unsigned long) total / RECENT_SIZE; | ||||
| 		fprintf(c_fd, " avg: %li\n", recent_avg); | ||||
| 		trigger_check(); | ||||
| 		recent_count++; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void trigger_do(void) | ||||
| { | ||||
| 	group_foreach_recursive(trigger_process, NULL); | ||||
| 	fflush(stdout); | ||||
| } | ||||
|  | ||||
| static void print_help(void) | ||||
| { | ||||
| 	printf( | ||||
| 	"trigger - Run actions based on traffic patterns\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Monitors a given probe and triggers an action if the criteria is met.\n" \ | ||||
| 	"  Criterias could be going above or dropping below a given threshold of traffic.\n" \ | ||||
| 	"  Probes could be Bytes/sec or Packets/sec on TX or RX\n" \ | ||||
| 	"\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Author: Babak Farrokhi <babak@farrokhi.net>\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Options:\n" \ | ||||
| 	"    probe=ELEMENT     Element to monitor for threshold\n" \ | ||||
| 	"    action=PROGRAM    Program or script to run when triggered\n" \ | ||||
| 	"    below=THRESHOLD   Minimum acceptable level for given element (average in past three seconds)\n" \ | ||||
| 	"    above=THRESHOLD   Maximum acceptable level for given element (average in past three seconds)\n" \ | ||||
| 	"    quittriggers=NUM  Quit after NUM triggers\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Probe Elements:\n" \ | ||||
| 	"    rxrate:packets    RX packet rate\n" \ | ||||
| 	"    txrate:packets    TX packet rate\n" \ | ||||
| 	"    rxrate:bytes      RX traffic rate (bytes)\n" \ | ||||
| 	"    txrate:bytes      TX traffic rate (bytes)\n" \ | ||||
| 	"\n" \ | ||||
| 	"  Examples:\n" \ | ||||
| 	"    bmon -p eth0 -o 'trigger:probe=rxrate:packets;below=5000;quittriggers=3;action=/opt/bin/alert'\n" \ | ||||
| 	"\n"); | ||||
| } | ||||
|  | ||||
| static void trigger_parse_opt(const char *type, const char *value) | ||||
| { | ||||
| 	if (!strcasecmp(type, "above") && value) | ||||
| 		c_threshold_high = strtol(value, NULL, 0); | ||||
| 	else if (!strcasecmp(type, "below") && value) | ||||
| 		c_threshold_low = strtol(value, NULL, 0); | ||||
| 	else if (!strcasecmp(type, "quittriggers") && value) | ||||
| 		c_quit_after_trigger = strtol(value, NULL, 0); | ||||
| 	else if (!strcasecmp(type, "probe")) { | ||||
| 		if (c_format) | ||||
| 			free(c_format); | ||||
| 		c_format = strdup(value); | ||||
| 	} | ||||
| 	else if (!strcasecmp(type, "help")) { | ||||
| 		print_help(); | ||||
| 		exit(0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static struct bmon_module trigger_ops = { | ||||
| 	.m_name		= "trigger", | ||||
| 	.m_do		= trigger_do, | ||||
| 	.m_parse_opt	= trigger_parse_opt, | ||||
| }; | ||||
|  | ||||
| static void __init ascii_init(void) | ||||
| { | ||||
| 	c_fd = stdout; | ||||
| 	c_format = strdup("$(rxrate:packets)\\n"); | ||||
|  | ||||
| 	output_register(&trigger_ops); | ||||
| } | ||||
| @ -28,7 +28,7 @@ | ||||
| #include <bmon/utils.h> | ||||
| #include <bmon/unit.h> | ||||
|  | ||||
| static struct unit *byte_unit, *bit_unit, *number_unit; | ||||
| static struct unit *byte_unit, *bit_unit; | ||||
|  | ||||
| static LIST_HEAD(units); | ||||
|  | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							| @ -27,6 +27,11 @@ | ||||
| #include <bmon/conf.h> | ||||
| #include <bmon/utils.h> | ||||
|  | ||||
| #ifdef __MACH__ | ||||
| #include <mach/clock.h> | ||||
| #include <mach/mach.h> | ||||
| #endif | ||||
|  | ||||
| void *xcalloc(size_t n, size_t s) | ||||
| { | ||||
| 	void *d = calloc(n, s); | ||||
| @ -112,12 +117,21 @@ int timestamp_is_negative(timestamp_t *ts) | ||||
|  | ||||
| void update_timestamp(timestamp_t *dst) | ||||
| { | ||||
| 	struct timeval tv; | ||||
| #ifdef __MACH__ | ||||
| 	clock_serv_t cclock; | ||||
| 	mach_timespec_t tp; | ||||
|  | ||||
| 	gettimeofday(&tv, NULL); | ||||
| 	host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); | ||||
| 	clock_get_time(cclock, &tp); | ||||
| 	mach_port_deallocate(mach_task_self(), cclock); | ||||
| #else | ||||
| 	struct timespec tp; | ||||
|  | ||||
| 	dst->tv_sec = tv.tv_sec; | ||||
| 	dst->tv_usec = tv.tv_usec; | ||||
| 	clock_gettime(CLOCK_MONOTONIC, &tp); | ||||
| #endif | ||||
|  | ||||
| 	dst->tv_sec = tp.tv_sec; | ||||
| 	dst->tv_usec = tp.tv_nsec / 1000; | ||||
| } | ||||
|  | ||||
| void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	