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 | language: c | ||||||
|  |  | ||||||
|  | os: | ||||||
|  |   - linux | ||||||
|  |   - osx | ||||||
|  |  | ||||||
|  | env: | ||||||
|  |   global: | ||||||
|  |     - secure: "C87Pgf5AVDoyQfm9MIv81g" | ||||||
|  |  | ||||||
| compiler: | compiler: | ||||||
|   - gcc |   - gcc | ||||||
|   - clang |   - clang | ||||||
| before_install: |  | ||||||
|   - sudo apt-get install libconfuse-dev | # container-based builds | ||||||
|   - sudo apt-get install libnl-3-dev libnl-route-3-dev | sudo: false | ||||||
|   - sudo apt-get install libncurses-dev | addons: | ||||||
| # Change this to your needs |   apt: | ||||||
| script: ./autogen.sh && ./configure && make |     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 | 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 | v3.4 - August 24, 2014 | ||||||
| ---------------------- |  | ||||||
|  * Bugfixes |  * Bugfixes | ||||||
|    * blank screen with config file |    * blank screen with config file | ||||||
|    * quick-help toggle with '?' in curses |    * quick-help toggle with '?' in curses | ||||||
|  * Better bmon.conf example |  * Better bmon.conf example | ||||||
|  |  | ||||||
| v3.3 - July 6, 2014 | v3.3 - July 6, 2014 | ||||||
| ------------------- |  | ||||||
|  * MacOS X port |  * MacOS X port | ||||||
|  * Only initialize curses module if actually used |  * Only initialize curses module if actually used | ||||||
|  * Assorted bug and spelling fixes |  * 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 | features various output methods including an interactive curses user | ||||||
| interface and a programmable text output for scripting. | 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 |  * 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 | ### Usage | ||||||
|  |  | ||||||
| To run bmon in the default curses mode: | To run bmon in the default curses mode: | ||||||
| @ -35,14 +89,18 @@ provided via: | |||||||
|  |  | ||||||
| ## Screenshots | ## Screenshots | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| ## Copyright | ## Copyright | ||||||
|  |  | ||||||
| > *Copyright (c) 2001-2014 Thomas Graf <tgraf@suug.ch> | Various authors, see git commit log. | ||||||
| > Copyright (c) 2013 Red Hat, Inc.* |  | ||||||
|  |  | ||||||
| Please see the [LICENSE](https://github.com/tgraf/bmon/blob/master/LICENSE) | > *Copyright (c) 2001-2016 Thomas Graf <tgraf@suug.ch>* | ||||||
| file for additional details. | > *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 | # 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 | # Permission is hereby granted, free of charge, to any person obtaining a | ||||||
| # copy of this software and associated documentation files (the "Software"), | # 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 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
| # DEALINGS IN THE SOFTWARE. | # 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_HEADERS(include/bmon/defs.h) | ||||||
| AC_CONFIG_AUX_DIR([build-aux]) | AC_CONFIG_AUX_DIR([build-aux]) | ||||||
| AC_CONFIG_MACRO_DIR([m4]) | 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_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(strchr strdup strerror strncasecmp strstr strtol) | ||||||
| AC_CHECK_FUNCS(uname getdate) | 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 | AX_WITH_CURSES | ||||||
| if test "x$ax_cv_curses" != xyes || test "x$ax_cv_curses_color" != xyes; then | 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]) |         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])) | PKG_CHECK_MODULES([CONFUSE], [libconfuse], [], AC_MSG_ERROR([requires libconfuse])) | ||||||
|  |  | ||||||
| case ${target_os} in | case ${target_os} in | ||||||
|     linux*) |     linux*|uclinux*) | ||||||
|         PKG_CHECK_MODULES([LIBNL], [libnl-3.0], [], AC_MSG_ERROR([requires libnl3-dev])) |         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])) |         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])) | 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="" | BMON_LIB="" | ||||||
|  |  | ||||||
| ##################################################################### | ##################################################################### | ||||||
| @ -164,7 +175,7 @@ case ${target_os} in | |||||||
| 	AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system]) | 	AC_DEFINE_UNQUOTED(SYS_SUNOS, "1", [operating system]) | ||||||
|     ;; |     ;; | ||||||
|  |  | ||||||
|     *bsd*) |     *bsd*|dragonfly*) | ||||||
| 	AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) | 	AC_DEFINE_UNQUOTED(SYS_BSD, "1", [operating system]) | ||||||
|     ;; |     ;; | ||||||
|  |  | ||||||
|  | |||||||
| @ -11,10 +11,10 @@ | |||||||
|  |  | ||||||
| /*  | /*  | ||||||
|  * element eth0 { |  * element eth0 { | ||||||
|  * 	description	= { "My description" } |  * 	description	= "My description" | ||||||
|  * 	rxmax		= { 10000 } |  * 	rxmax		= 10000 | ||||||
|  * 	txmax		= { 10000 } |  * 	txmax		= 10000 | ||||||
|  * 	max		= { 12500000 } |  * 	max		= 12500000 | ||||||
|  * } |  * } | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| @ -86,3 +86,27 @@ history day { | |||||||
| 	interval	= 86400. | 	interval	= 86400. | ||||||
| 	size		= 60 | 	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/module.h \ | ||||||
| 	bmon/output.h \ | 	bmon/output.h \ | ||||||
| 	bmon/unit.h \ | 	bmon/unit.h \ | ||||||
|  | 	bmon/layout.h \ | ||||||
| 	bmon/utils.h | 	bmon/utils.h | ||||||
|  | |||||||
| @ -42,6 +42,9 @@ struct rate | |||||||
| 	/* Value of r_current at last read */ | 	/* Value of r_current at last read */ | ||||||
| 	uint64_t		r_prev; | 	uint64_t		r_prev; | ||||||
|  |  | ||||||
|  | 	/* Reset value to substract to emulate statistics reset */ | ||||||
|  | 	uint64_t		r_reset; | ||||||
|  |  | ||||||
| 	/* Rate per second calculated every `rate_interval' */ | 	/* Rate per second calculated every `rate_interval' */ | ||||||
| 	float			r_rate; | 	float			r_rate; | ||||||
|  |  | ||||||
| @ -49,6 +52,8 @@ struct rate | |||||||
| 	timestamp_t		r_last_calc; | 	timestamp_t		r_last_calc; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | extern uint64_t			rate_get_total(struct rate *); | ||||||
|  |  | ||||||
| enum { | enum { | ||||||
| 	ATTR_TYPE_UNSPEC, | 	ATTR_TYPE_UNSPEC, | ||||||
| 	ATTR_TYPE_COUNTER, | 	ATTR_TYPE_COUNTER, | ||||||
| @ -134,5 +139,6 @@ extern struct attr *		attr_select_prev(void); | |||||||
| extern struct attr *		attr_current(void); | extern struct attr *		attr_current(void); | ||||||
|  |  | ||||||
| extern void			attr_start_collecting_history(struct attr *); | extern void			attr_start_collecting_history(struct attr *); | ||||||
|  | extern void			attr_reset_counter(struct attr *a); | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -60,9 +60,11 @@ enum { | |||||||
| #if defined __GNUC__ | #if defined __GNUC__ | ||||||
| #define __init __attribute__ ((constructor)) | #define __init __attribute__ ((constructor)) | ||||||
| #define __exit __attribute__ ((destructor)) | #define __exit __attribute__ ((destructor)) | ||||||
|  | #define __unused__ __attribute__ ((unused)) | ||||||
| #else | #else | ||||||
| #define __init | #define __init | ||||||
| #define __exit | #define __exit | ||||||
|  | #define __unused__ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef DEBUG | #ifdef DEBUG | ||||||
|  | |||||||
| @ -74,6 +74,8 @@ enum { | |||||||
| 	LAYOUT_HEADER, | 	LAYOUT_HEADER, | ||||||
| 	LAYOUT_LIST, | 	LAYOUT_LIST, | ||||||
| 	LAYOUT_SELECTED, | 	LAYOUT_SELECTED, | ||||||
|  |     LAYOUT_RX_GRAPH, | ||||||
|  |     LAYOUT_TX_GRAPH, | ||||||
| 	__LAYOUT_MAX | 	__LAYOUT_MAX | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ | |||||||
| #include <dirent.h> | #include <dirent.h> | ||||||
| #ifdef SYS_BSD | #ifdef SYS_BSD | ||||||
| # include <float.h> | # include <float.h> | ||||||
| #else | #elif !defined(__ANDROID__) | ||||||
| # include <values.h> | # include <values.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | |||||||
| @ -9,6 +9,9 @@ | |||||||
| /* Define to 1 if you have the `atexit' function. */ | /* Define to 1 if you have the `atexit' function. */ | ||||||
| #undef HAVE_ATEXIT | #undef HAVE_ATEXIT | ||||||
|  |  | ||||||
|  | /* Define to 1 if you have the `clock_gettime' function. */ | ||||||
|  | #undef HAVE_CLOCK_GETTIME | ||||||
|  |  | ||||||
| /* have curses */ | /* have curses */ | ||||||
| #undef HAVE_CURSES | #undef HAVE_CURSES | ||||||
|  |  | ||||||
| @ -39,15 +42,15 @@ | |||||||
| /* Define to 1 if you have the <getopt.h> header file. */ | /* Define to 1 if you have the <getopt.h> header file. */ | ||||||
| #undef HAVE_GETOPT_H | #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. */ | /* Define to 1 if you have the <inttypes.h> header file. */ | ||||||
| #undef HAVE_INTTYPES_H | #undef HAVE_INTTYPES_H | ||||||
|  |  | ||||||
| /* Define to 1 if you have the `m' library (-lm). */ | /* Define to 1 if you have the `m' library (-lm). */ | ||||||
| #undef HAVE_LIBM | #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. */ | /* Define to 1 if you have the <memory.h> header file. */ | ||||||
| #undef HAVE_MEMORY_H | #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_ */ | ||||||
							
								
								
									
										19
									
								
								man/bmon.8
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								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. | by default. See INPUT MODULES for more details. | ||||||
| .RE | .RE | ||||||
| .PP | .PP | ||||||
| \fB \-o\fR, \fB\-\-ouptut\fRMODULE[:OPTIONS][,MODULE...] | \fB \-o\fR, \fB\-\-output=\fRMODULE[:OPTIONS][,MODULE...] | ||||||
| .RS 4 | .RS 4 | ||||||
| Set list of output modules to load and use. Multiple modules can be used | 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 | 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 | .PP | ||||||
| \fB \-U\fR, \fB\-\-use\-si\fR | \fB \-U\fR, \fB\-\-use\-si\fR | ||||||
| .RS 4 | .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 | .RE | ||||||
| .PP | .PP | ||||||
| \fB \-f\fR, \fB\-\-configfile=\fRFILE | \fB \-f\fR, \fB\-\-configfile=\fRFILE | ||||||
| @ -58,7 +58,7 @@ Set policy defining which network interfaces to display. See | |||||||
| INTERFACE SELECTION for more details. | INTERFACE SELECTION for more details. | ||||||
| .RE | .RE | ||||||
| .PP | .PP | ||||||
| \fB \-a\fR, \fB\-\-show\-all=\fR | \fB \-a\fR, \fB\-\-show\-all\fR | ||||||
| .RS 4 | .RS 4 | ||||||
| Display all interfaces, even interface that are administratively down. | Display all interfaces, even interface that are administratively down. | ||||||
| .RE | .RE | ||||||
| @ -75,6 +75,11 @@ Set interval in seconds in which the rate per counter is calculated. | |||||||
| The default is 1.0 seconds. | The default is 1.0 seconds. | ||||||
| .RE | .RE | ||||||
| .PP | .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 | \fB \-L\fR, \fB\-\-lifetime=\fRFLOAT | ||||||
| .RS 4 | .RS 4 | ||||||
| Set lifetime of an element in seconds before it is no longer displayed | Set lifetime of an element in seconds before it is no longer displayed | ||||||
| @ -215,6 +220,14 @@ and eth1: | |||||||
| .RS 4 | .RS 4 | ||||||
| \fBbmon \-p eth0,eth1 \-o curses\fP | \fBbmon \-p eth0,eth1 \-o curses\fP | ||||||
| .RE | .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" | .SH "FILES" | ||||||
| /etc/bmon.conf | /etc/bmon.conf | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ bmon_CFLAGS = \ | |||||||
| 	-I${top_builddir}/include \ | 	-I${top_builddir}/include \ | ||||||
| 	-DSYSCONFDIR=\"$(sysconfdir)\" \ | 	-DSYSCONFDIR=\"$(sysconfdir)\" \ | ||||||
| 	-D_GNU_SOURCE \ | 	-D_GNU_SOURCE \ | ||||||
|  | 	-Wall \ | ||||||
| 	$(CURSES_CFLAGS) \ | 	$(CURSES_CFLAGS) \ | ||||||
| 	$(CONFUSE_CFLAGS) \ | 	$(CONFUSE_CFLAGS) \ | ||||||
| 	$(LIBNL_CFLAGS) \ | 	$(LIBNL_CFLAGS) \ | ||||||
| @ -40,4 +41,5 @@ bmon_SOURCES = \ | |||||||
| 	out_null.c \ | 	out_null.c \ | ||||||
| 	out_format.c \ | 	out_format.c \ | ||||||
| 	out_ascii.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; | 	return def->ad_id; | ||||||
| } | } | ||||||
|  |  | ||||||
| void attr_def_free(struct attr_def *def) | static void attr_def_free(struct attr_def *def) | ||||||
| { | { | ||||||
| 	if (!def) | 	if (!def) | ||||||
| 		return; | 		return; | ||||||
| @ -524,6 +524,11 @@ static float __calc_usage(double rate, uint64_t max) | |||||||
| 	return 100.0f / ((double) max / (rate * cfg_rate_interval)); | 	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, | void attr_calc_usage(struct attr *a, float *rx, float *tx, | ||||||
| 		     uint64_t rxmax, uint64_t txmax) | 		     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) | static void __exit attr_exit(void) | ||||||
| { | { | ||||||
| 	struct attr_def *ad, *n; | 	struct attr_def *ad, *n; | ||||||
|  | |||||||
							
								
								
									
										55
									
								
								src/bmon.c
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								src/bmon.c
									
									
									
									
									
								
							| @ -33,8 +33,6 @@ | |||||||
| #include <bmon/group.h> | #include <bmon/group.h> | ||||||
|  |  | ||||||
| int start_time; | int start_time; | ||||||
| int do_quit = 0; |  | ||||||
| int is_daemon = 0; |  | ||||||
|  |  | ||||||
| struct reader_timing rtiming; | struct reader_timing rtiming; | ||||||
|  |  | ||||||
| @ -69,14 +67,14 @@ static char *usage_text = | |||||||
| "   Examples:\n" \ | "   Examples:\n" \ | ||||||
| "       -o curses:ngraph=2\n" \ | "       -o curses:ngraph=2\n" \ | ||||||
| "       -o list            # Shows a list of available modules\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" \ | "\n" \ | ||||||
| "Interface selection:\n" \ | "Interface selection:\n" \ | ||||||
| "   policy  := [!]simple_regexp,[!]simple_regexp,...\n" \ | "   policy  := [!]simple_regexp,[!]simple_regexp,...\n" \ | ||||||
| "\n" \ | "\n" \ | ||||||
| "   Example: -p 'eth*,lo*,!eth1'\n" \ | "   Example: -p 'eth*,lo*,!eth1'\n" \ | ||||||
| "\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) | static void do_shutdown(void) | ||||||
| { | { | ||||||
| @ -88,14 +86,7 @@ static void do_shutdown(void) | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| RETSIGTYPE sig_int(int unused) | static void sig_exit(void) | ||||||
| { |  | ||||||
| 	if (do_quit) |  | ||||||
| 		exit(-1); |  | ||||||
| 	do_quit = 1; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void sig_exit(void) |  | ||||||
| { | { | ||||||
| 	do_shutdown(); | 	do_shutdown(); | ||||||
| } | } | ||||||
| @ -120,7 +111,7 @@ void quit(const char *fmt, ...) | |||||||
| static inline void print_version(void) | static inline void print_version(void) | ||||||
| { | { | ||||||
| 	printf("bmon %s\n", PACKAGE_VERSION); | 	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("Copyright (C) 2013 Red Hat, Inc.\n"); | ||||||
| 	printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \ | 	printf("bmon comes with ABSOLUTELY NO WARRANTY. This is free " \ | ||||||
| 	       "software, and you\nare welcome to redistribute it under " \ | 	       "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:"; | 		char *gostr = "+:hvVf:"; | ||||||
|  |  | ||||||
| 		struct option long_opts[] = { | 		struct option long_opts[] = { | ||||||
| 			{"help", 0, 0, 'h'}, | 			{"help", 0, NULL, 'h'}, | ||||||
| 			{"version", 0, 0, 'v'}, | 			{"version", 0, NULL, 'v'}, | ||||||
| 			{"configfile", 1, 0, 'f'}, | 			{"configfile", 1, NULL, 'f'}, | ||||||
| 			{0, 0, 0, 0}, | 			{NULL, 0, NULL, 0}, | ||||||
| 		}; | 		}; | ||||||
| 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | ||||||
| 		if (c == -1) | 		if (c == -1) | ||||||
| @ -175,17 +166,17 @@ static int parse_args_post(int argc, char *argv[]) | |||||||
| 			      "L:hvVf:"; | 			      "L:hvVf:"; | ||||||
|  |  | ||||||
| 		struct option long_opts[] = { | 		struct option long_opts[] = { | ||||||
| 			{"input", 1, 0, 'i'}, | 			{"input", 1, NULL, 'i'}, | ||||||
| 			{"output", 1, 0, 'o'}, | 			{"output", 1, NULL, 'o'}, | ||||||
| 			{"policy", 1, 0, 'p'}, | 			{"policy", 1, NULL, 'p'}, | ||||||
| 			{"read-interval", 1, 0, 'r'}, | 			{"read-interval", 1, NULL, 'r'}, | ||||||
| 			{"rate-interval", 1, 0, 'R'}, | 			{"rate-interval", 1, NULL, 'R'}, | ||||||
| 			{"sleep-interval", 1, 0, 's'}, | 			{"sleep-interval", 1, NULL, 's'}, | ||||||
| 			{"show-all", 0, 0, 'a'}, | 			{"show-all", 0, NULL, 'a'}, | ||||||
| 			{"use-si", 0, 0, 'U'}, | 			{"use-si", 0, NULL, 'U'}, | ||||||
| 			{"use-bit", 0, 0, 'b'}, | 			{"use-bit", 0, NULL, 'b'}, | ||||||
| 			{"lifetime", 1, 0, 'L'}, | 			{"lifetime", 1, NULL, 'L'}, | ||||||
| 			{0, 0, 0, 0}, | 			{NULL, 0, NULL, 0}, | ||||||
| 		}; | 		}; | ||||||
| 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | 		int c = getopt_long(argc, argv, gostr, long_opts, NULL); | ||||||
| 		if (c == -1) | 		if (c == -1) | ||||||
| @ -220,7 +211,7 @@ static int parse_args_post(int argc, char *argv[]) | |||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case 'a': | 			case 'a': | ||||||
| 				cfg_setint(cfg, "show_all", 1); | 				cfg_setbool(cfg, "show_all", cfg_true); | ||||||
| 				break; | 				break; | ||||||
|  |  | ||||||
| 			case 'U': | 			case 'U': | ||||||
| @ -270,7 +261,7 @@ int main(int argc, char *argv[]) | |||||||
| 	unsigned long sleep_time; | 	unsigned long sleep_time; | ||||||
| 	double read_interval; | 	double read_interval; | ||||||
| 	 | 	 | ||||||
| 	start_time = time(0); | 	start_time = time(NULL); | ||||||
| 	memset(&rtiming, 0, sizeof(rtiming)); | 	memset(&rtiming, 0, sizeof(rtiming)); | ||||||
| 	rtiming.rt_variance.v_min = FLT_MAX; | 	rtiming.rt_variance.v_min = FLT_MAX; | ||||||
|  |  | ||||||
| @ -361,9 +352,6 @@ int main(int argc, char *argv[]) | |||||||
| 				output_post(); | 				output_post(); | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			if (do_quit) |  | ||||||
| 				exit(0); |  | ||||||
|  |  | ||||||
| 			/* | 			/* | ||||||
| 			 * ST := Configured ST | 			 * ST := Configured ST | ||||||
| 			 */ | 			 */ | ||||||
| @ -399,5 +387,4 @@ int main(int argc, char *argv[]) | |||||||
| static void __init bmon_init(void) | static void __init bmon_init(void) | ||||||
| { | { | ||||||
| 	atexit(&sig_exit); | 	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.h> | ||||||
| #include <bmon/element_cfg.h> | #include <bmon/element_cfg.h> | ||||||
| #include <bmon/history.h> | #include <bmon/history.h> | ||||||
|  | #include <bmon/layout.h> | ||||||
| #include <bmon/utils.h> | #include <bmon/utils.h> | ||||||
|  |  | ||||||
| cfg_t *cfg; | cfg_t *cfg; | ||||||
| @ -69,6 +70,16 @@ static cfg_opt_t unit_opts[] = { | |||||||
| 	CFG_END() | 	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[] = { | static cfg_opt_t global_opts[] = { | ||||||
| 	CFG_FLOAT("read_interval", 1.0f, CFGF_NONE), | 	CFG_FLOAT("read_interval", 1.0f, CFGF_NONE), | ||||||
| 	CFG_FLOAT("rate_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("attr", attr_opts, CFGF_MULTI | CFGF_TITLE), | ||||||
| 	CFG_SEC("history", history_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("element", element_opts, CFGF_MULTI | CFGF_TITLE), | ||||||
|  |     CFG_SEC("layout", layout_opts, CFGF_MULTI | CFGF_TITLE), | ||||||
| 	CFG_END() | 	CFG_END() | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @ -109,16 +121,20 @@ struct layout cfg_layout[] = | |||||||
|     {-1, -1, 0},            /* header */ |     {-1, -1, 0},            /* header */ | ||||||
|     {-1, -1, 0},            /* list */ |     {-1, -1, 0},            /* list */ | ||||||
|     {-1, -1, A_REVERSE},    /* selected */ |     {-1, -1, A_REVERSE},    /* selected */ | ||||||
|  |     {-1, -1, 0},            /* RX graph */ | ||||||
|  |     {-1, -1, 0},            /* TX graph */ | ||||||
| }; | }; | ||||||
| #else | #else | ||||||
| struct layout cfg_layout[] = | struct layout cfg_layout[] = | ||||||
| { | { | ||||||
| 	{0, 0, 0},                               /* dummy, not used */ | 	{0, 0, 0},                               /* dummy, not used */ | ||||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* default */ | 	{COLOR_WHITE, COLOR_BLACK, 0},           /* default */ | ||||||
| 	{COLOR_BLACK, COLOR_WHITE, A_REVERSE},  /* statusbar */ | 	{COLOR_BLUE,   COLOR_GREEN, A_REVERSE},  /* statusbar */ | ||||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* header */ | 	{COLOR_GREEN,  COLOR_BLACK, 0},          /* header */ | ||||||
| 	{COLOR_BLACK, COLOR_WHITE, 0},          /* list */ | 	{COLOR_WHITE,  COLOR_BLACK, 0},          /* list */ | ||||||
| 	{COLOR_BLACK, COLOR_WHITE, A_REVERSE},  /* selected */ | 	{COLOR_YELLOW, COLOR_BLACK, A_REVERSE},  /* selected */ | ||||||
|  |     {COLOR_GREEN,  COLOR_BLACK, 0},          /* RX graph */ | ||||||
|  |     {COLOR_RED,    COLOR_BLACK, 0},          /* TX graph */ | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
| @ -371,7 +387,7 @@ static void configfile_read_units(void) | |||||||
|  |  | ||||||
| static void configfile_read_attrs(void) | static void configfile_read_attrs(void) | ||||||
| { | { | ||||||
| 	int i, nattrs, t; | 	int i, nattrs, t = 0; | ||||||
|  |  | ||||||
| 	nattrs = cfg_size(cfg, "attr"); | 	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) | static void conf_read(const char *path, int must) | ||||||
| { | { | ||||||
| 	int err; | 	int err; | ||||||
| @ -450,6 +501,7 @@ static void conf_read(const char *path, int must) | |||||||
| 	configfile_read_history(); | 	configfile_read_history(); | ||||||
| 	configfile_read_attrs(); | 	configfile_read_attrs(); | ||||||
| 	configfile_read_element_cfg(); | 	configfile_read_element_cfg(); | ||||||
|  |     configfile_read_layout_cfg(); | ||||||
| } | } | ||||||
|  |  | ||||||
| static const char default_config[] = \ | static const char default_config[] = \ | ||||||
| @ -508,6 +560,29 @@ static const char default_config[] = \ | |||||||
| "history day {" \ | "history day {" \ | ||||||
| "	interval	= 86400.0" \ | "	interval	= 86400.0" \ | ||||||
| "	size		= 60" \ | "	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) | static void conf_read_default(void) | ||||||
| @ -524,6 +599,7 @@ static void conf_read_default(void) | |||||||
| 	configfile_read_history(); | 	configfile_read_history(); | ||||||
| 	configfile_read_attrs(); | 	configfile_read_attrs(); | ||||||
| 	configfile_read_element_cfg(); | 	configfile_read_element_cfg(); | ||||||
|  |     configfile_read_layout_cfg(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void configfile_read(void) | void configfile_read(void) | ||||||
|  | |||||||
| @ -113,8 +113,9 @@ void element_parse_policy(const char *policy) | |||||||
| 	xfree(copy); | 	xfree(copy); | ||||||
| } | } | ||||||
|  |  | ||||||
| struct element *__lookup_element(struct element_group *group, const char *name, | static struct element *__lookup_element(struct element_group *group, | ||||||
| 				 uint32_t id, struct element *parent) | 					const char *name, uint32_t id, | ||||||
|  | 					struct element *parent) | ||||||
| { | { | ||||||
| 	struct list_head *list; | 	struct list_head *list; | ||||||
| 	struct element *e; | 	struct element *e; | ||||||
| @ -200,12 +201,6 @@ void element_free(struct element *e) | |||||||
| 	struct attr *a, *an; | 	struct attr *a, *an; | ||||||
| 	int i; | 	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) | 	list_for_each_entry_safe(c, cnext, &e->e_childs, e_list) | ||||||
| 		element_free(c); | 		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) | 		list_for_each_entry_safe(a, an, &e->e_attrhash[i], a_list) | ||||||
| 			attr_free(a); | 			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); | 	list_del(&e->e_list); | ||||||
| 	e->e_group->g_nelements--; | 	e->e_group->g_nelements--; | ||||||
|  |  | ||||||
| @ -357,6 +358,26 @@ int element_set_usage_attr(struct element *e, const char *usage) | |||||||
| 	return 0; | 	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 *element_current(void) | ||||||
| { | { | ||||||
| 	struct element_group *g; | 	struct element_group *g; | ||||||
| @ -364,8 +385,12 @@ struct element *element_current(void) | |||||||
| 	if (!(g = group_current())) | 	if (!(g = group_current())) | ||||||
| 		return NULL; | 		return NULL; | ||||||
|  |  | ||||||
|  | 	/* | ||||||
|  | 	 * If no element is picked yet, pick a default interface according to | ||||||
|  | 	 * the selection policy. | ||||||
|  | 	 */ | ||||||
| 	if (!g->g_current) | 	if (!g->g_current) | ||||||
| 		element_select_first(); | 		element_pick_from_policy(g); | ||||||
|  |  | ||||||
| 	return g->g_current; | 	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); | 	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, | static void fill_table(struct graph *g, struct graph_table *tbl, | ||||||
| 		       struct history *h, struct history_store *data) | 		       struct history *h, struct history_store *data) | ||||||
| { | { | ||||||
|  | |||||||
| @ -261,7 +261,7 @@ static void __init group_init(void) | |||||||
| { | { | ||||||
| 	DBG("init"); | 	DBG("init"); | ||||||
|  |  | ||||||
| 	group_new_hdr("intf", "Interfaces", | 	group_new_hdr(DEFAULT_GROUP, "Interfaces", | ||||||
| 		      "RX bps", "pps", "TX bps", "pps"); | 		      "RX bps", "pps", "TX bps", "pps"); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -89,7 +89,11 @@ static void dummy_read(void) | |||||||
| 		char gname[32]; | 		char gname[32]; | ||||||
| 		struct element_group *group; | 		struct element_group *group; | ||||||
|  |  | ||||||
|  | 		if (gidx == 0) | ||||||
|  | 			snprintf(gname, sizeof(gname), "%s", DEFAULT_GROUP); | ||||||
|  | 		else | ||||||
| 			snprintf(gname, sizeof(gname), "group%02d", gidx); | 			snprintf(gname, sizeof(gname), "group%02d", gidx); | ||||||
|  |  | ||||||
| 		group = group_lookup(gname, GROUP_CREATE); | 		group = group_lookup(gname, GROUP_CREATE); | ||||||
|  |  | ||||||
| 		for (n = 0; n < c_numdev; n++) { | 		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); | 		c_numdev = strtol(value, NULL, 0); | ||||||
| 	else if (!strcasecmp(type, "randomize")) { | 	else if (!strcasecmp(type, "randomize")) { | ||||||
| 		c_randomize = 1; | 		c_randomize = 1; | ||||||
| 		srand(time(0)); | 		srand(time(NULL)); | ||||||
| 	} else if (!strcasecmp(type, "seed") && value) | 	} else if (!strcasecmp(type, "seed") && value) | ||||||
| 		srand(strtol(value, NULL, 0)); | 		srand(strtol(value, NULL, 0)); | ||||||
| 	else if (!strcasecmp(type, "mtu") && value) | 	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 element_group *grp; | ||||||
| static struct bmon_module netlink_ops; | static struct bmon_module netlink_ops; | ||||||
|  |  | ||||||
|  | #include <linux/if.h> | ||||||
|  |  | ||||||
| #include <netlink/netlink.h> | #include <netlink/netlink.h> | ||||||
| #include <netlink/cache.h> | #include <netlink/cache.h> | ||||||
| #include <netlink/utils.h> | #include <netlink/utils.h> | ||||||
| @ -47,6 +49,22 @@ static struct bmon_module netlink_ops; | |||||||
| #include <netlink/route/classifier.h> | #include <netlink/route/classifier.h> | ||||||
| #include <netlink/route/qdisc/htb.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[] = { | static struct attr_map link_attrs[] = { | ||||||
| { | { | ||||||
| 	.name		= "bytes", | 	.name		= "bytes", | ||||||
| @ -88,6 +106,14 @@ static struct attr_map link_attrs[] = { | |||||||
| 	.rxid		= RTNL_LINK_RX_COMPRESSED, | 	.rxid		= RTNL_LINK_RX_COMPRESSED, | ||||||
| 	.txid		= RTNL_LINK_TX_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", | 	.name		= "fifoerr", | ||||||
| 	.type		= ATTR_TYPE_COUNTER, | 	.type		= ATTR_TYPE_COUNTER, | ||||||
| @ -280,6 +306,14 @@ static struct attr_map link_attrs[] = { | |||||||
| 	.rxid		= RTNL_LINK_ICMP6_INERRORS, | 	.rxid		= RTNL_LINK_ICMP6_INERRORS, | ||||||
| 	.txid		= RTNL_LINK_ICMP6_OUTERRORS, | 	.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", | 	.name		= "ip6inhdrerr", | ||||||
| 	.type		= ATTR_TYPE_COUNTER, | 	.type		= ATTR_TYPE_COUNTER, | ||||||
| @ -320,6 +354,14 @@ static struct attr_map link_attrs[] = { | |||||||
| 	.rxid		= RTNL_LINK_IP6_INADDRERRORS, | 	.rxid		= RTNL_LINK_IP6_INADDRERRORS, | ||||||
| 	.txid		= -1, | 	.txid		= -1, | ||||||
| }, | }, | ||||||
|  | { | ||||||
|  | 	.name		= "ip6csumerr", | ||||||
|  | 	.type		= ATTR_TYPE_COUNTER, | ||||||
|  | 	.unit		= UNIT_NUMBER, | ||||||
|  | 	.description	= "Ip6 Checksum Error", | ||||||
|  | 	.rxid		= RTNL_LINK_IP6_CSUMERRORS, | ||||||
|  | 	.txid		= -1, | ||||||
|  | }, | ||||||
| { | { | ||||||
| 	.name		= "ip6reasmtimeo", | 	.name		= "ip6reasmtimeo", | ||||||
| 	.type		= ATTR_TYPE_COUNTER, | 	.type		= ATTR_TYPE_COUNTER, | ||||||
| @ -351,6 +393,38 @@ static struct attr_map link_attrs[] = { | |||||||
| 	.description	= "Ip6 Reasm/Frag Requests", | 	.description	= "Ip6 Reasm/Frag Requests", | ||||||
| 	.rxid		= RTNL_LINK_IP6_REASMREQDS, | 	.rxid		= RTNL_LINK_IP6_REASMREQDS, | ||||||
| 	.txid		= RTNL_LINK_IP6_FRAGCREATES, | 	.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 rdata { | ||||||
|  | 	struct nl_cache *	class_cache; | ||||||
| 	struct element *	parent; | 	struct element *	parent; | ||||||
| 	int 			level; | 	int 			level; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| static struct nl_sock *sock; | 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) | 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 handle_qdisc(struct nl_object *obj, void *); | ||||||
| static void find_classes(uint32_t, struct rdata *); | 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, | 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]; | 	char buf[IFNAME_MAX], name[IFNAME_MAX]; | ||||||
| 	uint32_t id = rtnl_tc_get_handle(tc); | 	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)", | 	snprintf(name, sizeof(name), "%s %s (%s)", | ||||||
| 		 prefix, buf, rtnl_tc_get_kind(tc)); | 		 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; | 		return NULL; | ||||||
|  |  | ||||||
| 	if (e->e_flags & ELEMENT_FLAG_CREATED) { | 	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") || | 		if (element_set_key_attr(e, "tc_bytes", "tc_packets") || | ||||||
| 		    element_set_usage_attr(e, "tc_bytes")) | 		    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 rtnl_tc *tc = (struct rtnl_tc *) obj; | ||||||
| 	struct element *e; | 	struct element *e; | ||||||
| 	struct rdata *rdata = arg; | 	const struct rdata *rdata = arg; | ||||||
| 	struct rdata ndata = { | 	struct rdata ndata = { | ||||||
|  | 		.class_cache = rdata->class_cache, | ||||||
| 		.level = rdata->level + 1, | 		.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)); | 		element_set_txmax(e, rtnl_htb_get_rate((struct rtnl_class *) tc)); | ||||||
|  |  | ||||||
| 	find_classes(rtnl_tc_get_handle(tc), &ndata); | 	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; | 	struct rtnl_qdisc *filter; | ||||||
|  |  | ||||||
| @ -543,6 +622,7 @@ static void find_qdiscs(uint32_t parent, struct rdata *rdata) | |||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
| 	rtnl_tc_set_parent((struct rtnl_tc *) filter, parent); | 	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), | 	nl_cache_foreach_filter(qdisc_cache, OBJ_CAST(filter), | ||||||
| 				handle_qdisc, rdata); | 				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); | 	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); | 				handle_class, rdata); | ||||||
|  |  | ||||||
| 	rtnl_class_put(filter); | 	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 rtnl_tc *tc = (struct rtnl_tc *) obj; | ||||||
| 	struct element *e; | 	struct element *e; | ||||||
| 	struct rdata *rdata = arg; | 	const struct rdata *rdata = arg; | ||||||
| 	struct rdata ndata = { | 	struct rdata ndata = { | ||||||
|  | 		.class_cache = rdata->class_cache, | ||||||
| 		.level = rdata->level + 1, | 		.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) | static void handle_tc(struct element *e, struct rtnl_link *link) | ||||||
| { | { | ||||||
| 	struct rtnl_qdisc *qdisc; | 	struct rtnl_qdisc *qdisc; | ||||||
|  | 	struct nl_cache *class_cache; | ||||||
| 	int ifindex = rtnl_link_get_ifindex(link); | 	int ifindex = rtnl_link_get_ifindex(link); | ||||||
| 	struct rdata rdata = { | 	struct rdata rdata = { | ||||||
| 		.level = 1, | 		.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) | 	if (rtnl_class_alloc_cache(sock, ifindex, &class_cache) < 0) | ||||||
| 		return; | 		return; | ||||||
|  |  | ||||||
|  | 	rdata.class_cache = class_cache; | ||||||
|  |  | ||||||
| 	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); | 	qdisc = rtnl_qdisc_get_by_parent(qdisc_cache, ifindex, TC_H_ROOT); | ||||||
| 	if (qdisc) { | 	if (qdisc) { | ||||||
| 		handle_qdisc(OBJ_CAST(qdisc), &rdata); | 		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); | 		attr_update(e, m->attrid, c_rx, c_tx, flags); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if (!c_notc) | 	if (!c_notc && qdisc_cache) | ||||||
| 		handle_tc(e, link); | 		handle_tc(e, link); | ||||||
|  |  | ||||||
| 	element_notify_update(e, NULL); | 	element_notify_update(e, NULL); | ||||||
| @ -752,7 +836,8 @@ static void netlink_read(void) | |||||||
| 		goto disable; | 		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)); | 		fprintf(stderr, "Unable to resync qdisc cache: %s\n", nl_geterror(err)); | ||||||
| 		goto disable; | 		goto disable; | ||||||
| 	} | 	} | ||||||
| @ -772,9 +857,20 @@ static void netlink_shutdown(void) | |||||||
| 	nl_socket_free(sock); | 	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) | static int netlink_do_init(void) | ||||||
| { | { | ||||||
| 	int err, i; | 	int err; | ||||||
|  |  | ||||||
| 	if (!(sock = nl_socket_alloc())) { | 	if (!(sock = nl_socket_alloc())) { | ||||||
| 		fprintf(stderr, "Unable to allocate netlink socket\n"); | 		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) { | 	if ((err = rtnl_qdisc_alloc_cache(sock, &qdisc_cache)) < 0) { | ||||||
| 		fprintf(stderr, "Unable to allocate qdisc cache: %s\n", nl_geterror(err)); | 		fprintf(stderr, "Warning: Unable to allocate qdisc cache: %s\n", nl_geterror(err)); | ||||||
| 		goto disable; | 		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)) || | 	if (attr_map_load(link_attrs, ARRAY_SIZE(link_attrs)) || | ||||||
| 	    attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs))) | 	    attr_map_load(tc_attrs, ARRAY_SIZE(tc_attrs))) | ||||||
| 		BUG(); | 		BUG(); | ||||||
|  | |||||||
| @ -101,7 +101,7 @@ static void proc_read(void) | |||||||
| { | { | ||||||
| 	struct element *e; | 	struct element *e; | ||||||
| 	FILE *fd; | 	FILE *fd; | ||||||
| 	char buf[512], *p, *s, *unused; | 	char buf[512], *p, *s, *unused __unused__; | ||||||
| 	int w; | 	int w; | ||||||
| 	 | 	 | ||||||
| 	if (!(fd = fopen(c_path, "r"))) | 	if (!(fd = fopen(c_path, "r"))) | ||||||
|  | |||||||
| @ -163,6 +163,7 @@ sysctl_read(void) | |||||||
| 		struct element *e, *e_parent = NULL; | 		struct element *e, *e_parent = NULL; | ||||||
| 		struct if_msghdr *ifm, *nextifm; | 		struct if_msghdr *ifm, *nextifm; | ||||||
| 		struct sockaddr_dl *sdl; | 		struct sockaddr_dl *sdl; | ||||||
|  | 		char info_buf[64]; | ||||||
|  |  | ||||||
| 		ifm = (struct if_msghdr *) next; | 		ifm = (struct if_msghdr *) next; | ||||||
| 		if (ifm->ifm_type != RTM_IFINFO) | 		if (ifm->ifm_type != RTM_IFINFO) | ||||||
| @ -225,6 +226,20 @@ sysctl_read(void) | |||||||
| 			attr_update(e, m->attrid, rx, tx, flags); | 			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_notify_update(e, NULL); | ||||||
| 		element_lifesign(e, 1); | 		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) | int module_set(struct bmon_subsys *ss, const char *name) | ||||||
| { | { | ||||||
| 	struct bmon_module *mod; | 	struct bmon_module *mod; | ||||||
| 	struct list_head *list; |  | ||||||
| 	LIST_HEAD(tmp_list); | 	LIST_HEAD(tmp_list); | ||||||
| 	module_conf_t *m; | 	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; | 	char *rx_u, *tx_u; | ||||||
| 	int rxprec, txprec; | 	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, | 				   a->a_def->ad_unit, | ||||||
| 				   &rx_u, &rxprec); | 				   &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, | 				   a->a_def->ad_unit, | ||||||
| 				   &tx_u, &txprec); | 				   &tx_u, &txprec); | ||||||
|  |  | ||||||
| @ -212,6 +212,7 @@ static void ascii_draw_group(struct element_group *g, void *arg) | |||||||
| static void ascii_draw(void) | static void ascii_draw(void) | ||||||
| { | { | ||||||
| 	group_foreach(ascii_draw_group, NULL); | 	group_foreach(ascii_draw_group, NULL); | ||||||
|  | 	fflush(stdout); | ||||||
|  |  | ||||||
| 	if (c_quit_after > 0) | 	if (c_quit_after > 0) | ||||||
| 		if (--c_quit_after == 0) | 		if (--c_quit_after == 0) | ||||||
|  | |||||||
| @ -45,6 +45,8 @@ enum { | |||||||
| 	KEY_TOGGLE_DETAILS	= 'd', | 	KEY_TOGGLE_DETAILS	= 'd', | ||||||
| 	KEY_TOGGLE_INFO		= 'i', | 	KEY_TOGGLE_INFO		= 'i', | ||||||
| 	KEY_COLLECT_HISTORY	= 'h', | 	KEY_COLLECT_HISTORY	= 'h', | ||||||
|  | 	KEY_CTRL_N	= 14, | ||||||
|  | 	KEY_CTRL_P	= 16, | ||||||
| }; | }; | ||||||
|  |  | ||||||
| #define DETAILS_COLS		40 | #define DETAILS_COLS		40 | ||||||
| @ -137,7 +139,7 @@ static void apply_layout(int layout) | |||||||
| 		attrset(cfg_layout[layout].l_attr); | 		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); | 	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, ...) | static void put_line(const char *fmt, ...) | ||||||
| { | { | ||||||
| 	va_list args; | 	va_list args; | ||||||
| 	char buf[2048]; | 	char *buf; | ||||||
| 	int x, y; | 	int len; | ||||||
|  | 	int x, y __unused__; | ||||||
|  |  | ||||||
| 	memset(buf, 0, sizeof(buf)); |  | ||||||
| 	getyx(stdscr, y, x); | 	getyx(stdscr, y, x); | ||||||
|  |  | ||||||
|  | 	len = cols - x; | ||||||
|  | 	buf = xcalloc(len+1, 1); | ||||||
|  |  | ||||||
| 	va_start(args, fmt); | 	va_start(args, fmt); | ||||||
| 	vsnprintf(buf, sizeof(buf), fmt, args); | 	vsnprintf(buf, len+1, fmt, args); | ||||||
| 	va_end(args); | 	va_end(args); | ||||||
|  |  | ||||||
| 	if (strlen(buf) > cols-x) | 	if (strlen(buf) < len) | ||||||
| 		buf[cols - x] = '\0'; | 		memset(&buf[strlen(buf)], ' ', len - strlen(buf)); | ||||||
| 	else |  | ||||||
| 		memset(&buf[strlen(buf)], ' ', cols - strlen(buf)-x); |  | ||||||
|  |  | ||||||
| 	addstr(buf); | 	addstr(buf); | ||||||
|  | 	xfree(buf); | ||||||
| } | } | ||||||
|  |  | ||||||
| static void center_text(const char *fmt, ...) | 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; | 	int rxprec, txprec, ncol; | ||||||
| 	struct detail_arg *da = arg; | 	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, | 				   a->a_def->ad_unit, | ||||||
| 				   &rx_u, &rxprec); | 				   &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, | 				   a->a_def->ad_unit, | ||||||
| 				   &tx_u, &txprec); | 				   &tx_u, &txprec); | ||||||
|  |  | ||||||
| @ -258,7 +262,7 @@ static void draw_attr_detail(struct element *e, struct attr *a, void *arg) | |||||||
| 	if (ncol > 0) | 	if (ncol > 0) | ||||||
| 		addch(ACS_VLINE); | 		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_def->ad_description, | ||||||
| 		 (a->a_flags & ATTR_RX_ENABLED) ? | 		 (a->a_flags & ATTR_RX_ENABLED) ? | ||||||
| 		 float2str(rx, 8, rxprec, buf1, sizeof(buf1)) : "-", rx_u, | 		 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+15, x+3, "H             Start recording history data", -1); | ||||||
| 	mvaddnstr(y+16, x+3, "TAB           Switch time unit of graph", -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+17, x+3, "<, >          Change number of graphs", -1); | ||||||
|  | 	mvaddnstr(y+18, x+3, "r             Reset counter of element", -1); | ||||||
|  |  | ||||||
| 	attroff(A_STANDOUT); | 	attroff(A_STANDOUT); | ||||||
|  |  | ||||||
| @ -419,6 +424,7 @@ static void draw_header(void) | |||||||
| 	move(row, COLS - strlen(PACKAGE_STRING) - 1); | 	move(row, COLS - strlen(PACKAGE_STRING) - 1); | ||||||
| 	put_line("%s", PACKAGE_STRING); | 	put_line("%s", PACKAGE_STRING); | ||||||
| 	move(row, 0); | 	move(row, 0); | ||||||
|  | 	apply_layout(LAYOUT_LIST); | ||||||
| } | } | ||||||
|  |  | ||||||
| static int lines_required_for_statusbar(void) | static int lines_required_for_statusbar(void) | ||||||
| @ -430,7 +436,7 @@ static void draw_statusbar(void) | |||||||
| { | { | ||||||
| 	static const char *help_text = "Press ? for help"; | 	static const char *help_text = "Press ? for help"; | ||||||
| 	char s[27]; | 	char s[27]; | ||||||
| 	time_t t = time(0); | 	time_t t = time(NULL); | ||||||
|  |  | ||||||
| 	apply_layout(LAYOUT_STATUSBAR); | 	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) | static void draw_group(struct element_group *g, void *arg) | ||||||
| { | { | ||||||
|  | 	apply_layout(LAYOUT_HEADER); | ||||||
| 	int *line = arg; | 	int *line = arg; | ||||||
|  |  | ||||||
| 	if (line_visible(*line)) { | 	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, | static void draw_table(struct graph *g, struct graph_table *tbl, | ||||||
| 		       struct attr *a, struct history *h, | 		       struct attr *a, struct history *h, | ||||||
| 		       const char *hdr, int ncol) | 		       const char *hdr, int ncol, int layout) | ||||||
| { | { | ||||||
| 	int i, save_row; | 	int i, save_row; | ||||||
| 	char buf[32]; | 	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); | 	//move(row, ncol + g->g_cfg.gc_width - 3); | ||||||
| 	//put_line("[err %.2f%%]", rtiming.rt_variance.v_error); | 	//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--) { | 	for (i = (g->g_cfg.gc_height - 1); i >= 0; i--) { | ||||||
| 		move(++row, ncol); | 		move(++row, ncol); | ||||||
| 		put_line("%'8.2f %s", |         sprintf(buf, "%'8.2f ", tbl->gt_scale[i]); | ||||||
| 			tbl->gt_scale[i], |         addstr(buf); | ||||||
| 			tbl->gt_table + (i * graph_row_size(&g->g_cfg))); |         apply_layout(layout); | ||||||
|  |         put_line("%s", tbl->gt_table + (i * graph_row_size(&g->g_cfg))); | ||||||
|  |         apply_layout(LAYOUT_LIST); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	move(++row, ncol); | 	move(++row, ncol); | ||||||
| @ -746,14 +756,14 @@ static void draw_history_graph(struct attr *a, struct history *h) | |||||||
| 	graph_refill(g, h); | 	graph_refill(g, h); | ||||||
|  |  | ||||||
| 	save_row = row; | 	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) { | 	if (graph_display == GRAPH_DISPLAY_SIDE_BY_SIDE) { | ||||||
| 		ncol = cols / 2; | 		ncol = cols / 2; | ||||||
| 		row = save_row; | 		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); | 	graph_free(g); | ||||||
| } | } | ||||||
| @ -973,8 +983,10 @@ draw: | |||||||
| 	 */ | 	 */ | ||||||
| 	NEXT_ROW(); | 	NEXT_ROW(); | ||||||
| 	hline(ACS_HLINE, cols); | 	hline(ACS_HLINE, cols); | ||||||
|  | 	if (c_show_list) { | ||||||
| 		mvaddch(row, LIST_COL_1, ACS_BTEE); | 		mvaddch(row, LIST_COL_1, ACS_BTEE); | ||||||
| 		mvaddch(row, LIST_COL_2, ACS_BTEE); | 		mvaddch(row, LIST_COL_2, ACS_BTEE); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	if (!c_show_graph) | 	if (!c_show_graph) | ||||||
| 		center_text(" Press %c to enable graphical statistics ", | 		center_text(" Press %c to enable graphical statistics ", | ||||||
| @ -1016,6 +1028,12 @@ draw: | |||||||
| 	NEXT_ROW(); | 	NEXT_ROW(); | ||||||
| 	hline(ACS_HLINE, cols); | 	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) | 	if (!c_show_info) | ||||||
| 		center_text(" Press %c to enable additional information ", | 		center_text(" Press %c to enable additional information ", | ||||||
| 			    KEY_TOGGLE_INFO); | 			    KEY_TOGGLE_INFO); | ||||||
| @ -1079,6 +1097,16 @@ out: | |||||||
| 	refresh(); | 	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) | static int handle_input(int ch) | ||||||
| { | { | ||||||
| 	switch (ch)  | 	switch (ch)  | ||||||
| @ -1160,10 +1188,12 @@ static int handle_input(int ch) | |||||||
| 			return 1; | 			return 1; | ||||||
|  |  | ||||||
| 		case KEY_DOWN: | 		case KEY_DOWN: | ||||||
|  | 		case KEY_CTRL_N: | ||||||
| 			element_select_next(); | 			element_select_next(); | ||||||
| 			return 1; | 			return 1; | ||||||
|  |  | ||||||
| 		case KEY_UP: | 		case KEY_UP: | ||||||
|  | 		case KEY_CTRL_P: | ||||||
| 			element_select_prev(); | 			element_select_prev(); | ||||||
| 			return 1; | 			return 1; | ||||||
|  |  | ||||||
| @ -1198,6 +1228,10 @@ static int handle_input(int ch) | |||||||
| 		case '\t': | 		case '\t': | ||||||
| 			history_select_next(); | 			history_select_next(); | ||||||
| 			return 1; | 			return 1; | ||||||
|  |  | ||||||
|  | 		case 'r': | ||||||
|  | 			reset_counters(); | ||||||
|  | 			return 1; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return 0; | 	return 0; | ||||||
| @ -1232,7 +1266,7 @@ static void print_module_help(void) | |||||||
| 	"  Author: Thomas Graf <tgraf@suug.ch>\n" \ | 	"  Author: Thomas Graf <tgraf@suug.ch>\n" \ | ||||||
| 	"\n" \ | 	"\n" \ | ||||||
| 	"  Options:\n" \ | 	"  Options:\n" \ | ||||||
| 	"    fgchar=CHAR    Foreground character (default: '*')\n" \ | 	"    fgchar=CHAR    Foreground character (default: '|')\n" \ | ||||||
| 	"    bgchar=CHAR    Background character (default: '.')\n" \ | 	"    bgchar=CHAR    Background character (default: '.')\n" \ | ||||||
| 	"    nchar=CHAR     Noise character (default: ':')\n" \ | 	"    nchar=CHAR     Noise character (default: ':')\n" \ | ||||||
| 	"    uchar=CHAR     Unknown 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" \ | 	"    nocolors       Do not use colors\n" \ | ||||||
| 	"    graph          Show graphical stats by default\n" \ | 	"    graph          Show graphical stats by default\n" \ | ||||||
| 	"    details        Show detailed 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"); | 	"    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; | 		c_show_graph = !!c_ngraph; | ||||||
| 	} else if (!strcasecmp(type, "details")) | 	} else if (!strcasecmp(type, "details")) | ||||||
| 		c_show_details = 1; | 		c_show_details = 1; | ||||||
|  | 	else if (!strcasecmp(type, "info")) | ||||||
|  | 		c_show_info = 1; | ||||||
| 	else if (!strcasecmp(type, "nocolors")) | 	else if (!strcasecmp(type, "nocolors")) | ||||||
| 		c_use_colors = 0; | 		c_use_colors = 0; | ||||||
| 	else if (!strcasecmp(type, "minlist") && value) | 	else if (!strcasecmp(type, "minlist") && value) | ||||||
|  | |||||||
| @ -119,25 +119,23 @@ static char *get_token(struct element_group *g, struct element *e, | |||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if (!(a = attr_lookup(e, def->ad_id))) { | 		if (!(a = attr_lookup(e, def->ad_id))) | ||||||
| 			fprintf(stderr, "Unable to find attribute %u (%s)\n", |  | ||||||
| 				def->ad_id, name); |  | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		if (!strncasecmp(type, "rx:", 3)) { | 		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; | 			return buf; | ||||||
| 		} else if (!strncasecmp(type, "tx:", 3)) { | 		} 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; | 			return buf; | ||||||
| 		} else if (!strncasecmp(type, "rxrate:", 7)) { | 		} else if (!strncasecmp(type, "rxrate:", 7)) { | ||||||
| 			snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate); | 			snprintf(buf, len, "%.2f", a->a_rx_rate.r_rate); | ||||||
| 			return buf; | 			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); | 			snprintf(buf, len, "%.2f", a->a_tx_rate.r_rate); | ||||||
| 			return buf; | 			return buf; | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	fprintf(stderr, "Unknown field \"%s\"\n", token); | 	fprintf(stderr, "Unknown field \"%s\"\n", token); | ||||||
| out: | out: | ||||||
| @ -168,6 +166,7 @@ static void draw_element(struct element_group *g, struct element *e, void *arg) | |||||||
| static void format_draw(void) | static void format_draw(void) | ||||||
| { | { | ||||||
| 	group_foreach_recursive(draw_element, NULL); | 	group_foreach_recursive(draw_element, NULL); | ||||||
|  | 	fflush(stdout); | ||||||
|  |  | ||||||
| 	if (c_quit_after > 0) | 	if (c_quit_after > 0) | ||||||
| 		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" \ | 	"  Supported Escape Sequences: \\n, \\t, \\r, \\v, \\b, \\f, \\a\n" \ | ||||||
| 	"\n" \ | 	"\n" \ | ||||||
| 	"  Examples:\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" \ | 	"    lo      12074   12074\n" \ | ||||||
| 	"\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" \ | 	"    eth0 33 5\n" \ | ||||||
| 	"\n" \ | 	"\n" \ | ||||||
| 	"    \"Element: $(element:name)\\nBytes Rate: \" \\\n" \ | 	"    'Item: $(element:name)\\nBytes Rate: $(attr:rxrate:bytes)/" \ | ||||||
| 	"        \"$(attr:rxrate:bytes)/$(attr:txrate:bytes)\\nPackets Rate: \" \\\n" \ | 	"$(attr:txrate:bytes)\\nPackets Rate: $(attr:rxrate:packets)/" \ | ||||||
| 	"        \"$(attr:rxrate:packets)/$(attr:txrate:packets)\\n\"\n" \ | 	"$(attr:txrate:packets)\\n'\n" \ | ||||||
| 	"    Item: eth0\n" \ | 	"    Item: eth0\n" \ | ||||||
| 	"    Bytes Rate: 49130/2119\n" \ | 	"    Bytes Rate: 49130/2119\n" \ | ||||||
| 	"    Packets Rate: 40/11\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/utils.h> | ||||||
| #include <bmon/unit.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); | static LIST_HEAD(units); | ||||||
|  |  | ||||||
|  | |||||||
							
								
								
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/utils.c
									
									
									
									
									
								
							| @ -27,6 +27,11 @@ | |||||||
| #include <bmon/conf.h> | #include <bmon/conf.h> | ||||||
| #include <bmon/utils.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 *xcalloc(size_t n, size_t s) | ||||||
| { | { | ||||||
| 	void *d = calloc(n, s); | 	void *d = calloc(n, s); | ||||||
| @ -112,12 +117,21 @@ int timestamp_is_negative(timestamp_t *ts) | |||||||
|  |  | ||||||
| void update_timestamp(timestamp_t *dst) | 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; | 	clock_gettime(CLOCK_MONOTONIC, &tp); | ||||||
| 	dst->tv_usec = tv.tv_usec; | #endif | ||||||
|  |  | ||||||
|  | 	dst->tv_sec = tp.tv_sec; | ||||||
|  | 	dst->tv_usec = tp.tv_nsec / 1000; | ||||||
| } | } | ||||||
|  |  | ||||||
| void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2) | void copy_timestamp(timestamp_t *ts1, timestamp_t *ts2) | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	