aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorM.Gergő2019-01-30 21:41:25 +0100
committerM.Gergő2019-01-30 21:41:25 +0100
commit3eadef4bb31e4ff39ce0b54dd7f3197aee6f8f24 (patch)
tree4940868feff3e734082ae74886e0db84c0f9be8e
parent06b56d32bbb222689d723a47843e0a24be53009c (diff)
downloadmunin-unifi-3eadef4bb31e4ff39ce0b54dd7f3197aee6f8f24.tar.gz
munin-unifi-3eadef4bb31e4ff39ce0b54dd7f3197aee6f8f24.zip
PHP multiprocesses for SNMP get
-rw-r--r--README.md8
-rw-r--r--ubnt_unifi.php217
2 files changed, 162 insertions, 63 deletions
diff --git a/README.md b/README.md
index 784d228..1712338 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
This is a [Munin](http://munin-monitoring.org/) plugin to monitor your [Ubiquiti Unifi](https://www.ubnt.com/products/#unifi) wireless network status.
-It uses SNMPv2 to get network data.
+It uses SNMPv2 and php child-processes to get network data.
### The original version of code is aviable here: [http://git.bmrg.hu/unifi-munin.git](http://git.bmrg.hu/unifi-munin.git/)
@@ -55,6 +55,7 @@ Edit the **/etc/munin/plugin-conf.d/munin-node**, and use the following configur
env.devices - A "space" separated list of the hostnames or IP addresses of wireless APs.
env.timeout - The maximum timeout in milliseconds of SNMP requests. (must enough to get all data!).
env.retry - Number of retry after failed/time out SNMP requets.
+ env.maxproc - Maximum nuber of child processes (for SNMP get)
env.devnetw - The network of the APs. (It is expreimental yet.)
@@ -64,8 +65,9 @@ For example:
timeout 240
env.controller unifi.company.com
env.devices ap01.wl.company.lan ap02.wl.company.lan ap03.wl.company.lan 10.10.1.6 10.10.1.7 10.10.1.8
+ env.maxproc 32
env.devnetw 10.10.1.10/24
- env.timeout 170
+ env.timeout 500
env.retry 1
@@ -73,7 +75,7 @@ For example:
### AUTHOR
-Copyright (C) 2018 Gergő J. Miklós.
+Copyright (C) 2018-2019 Gergő J. Miklós.
diff --git a/ubnt_unifi.php b/ubnt_unifi.php
index 6dc1051..1158190 100644
--- a/ubnt_unifi.php
+++ b/ubnt_unifi.php
@@ -11,7 +11,9 @@ $controller = getenv('controller');
$hosts = getenv('devices');
$timeout = getenv('timeout');
$retry = getenv('retry');
-//$devnetw = getenv('devnetw');
+$maxproc = getenv('maxproc');
+$devnetw = getenv('devnet');
+
$replace_chars = array("\"","\$","@","^","`",",","|","%",";",".","~","(",")","/","\\","{","}",":","?","[","]","=","+","#","!","-",); // Special chars replace
function print_header($inp){ // prints Munin-config data from processed data array
@@ -79,7 +81,7 @@ function collect_radio_summary($inp,$host){
$ret['g_multi'] = "radio_".str_replace( array(".", ":"), "_" ,$controller).".".str_replace( array(".", ":"), "_" ,$host);
$ret['g_controller'] = $controller;
$location = str_replace("\"", "", explode(": ", $inp[$host]["iso.3.6.1.2.1.1.6.0"])[1]);
- if( $location != "Unknown" and $location != "" ){ $ret['g_title'] = "Unifi Clients on: ".$location ; } // if the Location is not filled in Controller settings, use the hostname or ip address
+ if( $location != "Unknown" and $location != "" ){ $ret['g_title'] = "Unifi Clients on: ".$location ; } // if the Location is not filled in Controller settings, use the hostname or ip address
else { $ret['g_title'] = "Unifi Clients on: ".$host; };
$ret['g_vlabel'] = "Users";
$ret['g_category'] = "wl_clients_ap";
@@ -93,26 +95,26 @@ function collect_radio_summary($inp,$host){
$ret['g_info'] = "ubnt_wireless";
}
- $ret['head'][0]['name'] = "sum_clients";
- $ret['head'][0]['label'] = "Total clients";
- $ret['head'][0]['draw'] = "LINE1.2";
- $ret['head'][0]['info'] = "Total Clients";
- $ret['head'][0]['type'] = "GAUGE";
- $ret['head'][0]['min'] = "0";
-
- $ret['head'][1]['name'] = "2g_clients";
- $ret['head'][1]['label'] = "2.4Ghz";
- $ret['head'][1]['draw'] = "LINE1.2";
- $ret['head'][1]['info'] = "2.4Ghz Clients";
- $ret['head'][1]['type'] = "GAUGE";
- $ret['head'][1]['min'] = "0";
-
- $ret['head'][2]['name'] = "5g_clients";
- $ret['head'][2]['label'] = "5Ghz";
- $ret['head'][2]['draw'] = "LINE1.2";
- $ret['head'][2]['info'] = "2.4Ghz Clients";
- $ret['head'][2]['type'] = "GAUGE";
- $ret['head'][2]['min'] = "0";
+ $ret['head'][0]['name'] = "sum_clients";
+ $ret['head'][0]['label'] = "Total clients";
+ $ret['head'][0]['draw'] = "LINE1.2";
+ $ret['head'][0]['info'] = "Total Clients";
+ $ret['head'][0]['type'] = "GAUGE";
+ $ret['head'][0]['min'] = "0";
+
+ $ret['head'][1]['name'] = "2g_clients";
+ $ret['head'][1]['label'] = "2.4Ghz";
+ $ret['head'][1]['draw'] = "LINE1.2";
+ $ret['head'][1]['info'] = "2.4Ghz Clients";
+ $ret['head'][1]['type'] = "GAUGE";
+ $ret['head'][1]['min'] = "0";
+
+ $ret['head'][2]['name'] = "5g_clients";
+ $ret['head'][2]['label'] = "5Ghz";
+ $ret['head'][2]['draw'] = "LINE1.2";
+ $ret['head'][2]['info'] = "2.4Ghz Clients";
+ $ret['head'][2]['type'] = "GAUGE";
+ $ret['head'][2]['min'] = "0";
if(isset($host) and $host !== null and $host != "" ){ // trim raw data array to current device (in $host) or use the whole array when calculating controller's data
@@ -129,8 +131,8 @@ function collect_radio_summary($inp,$host){
$ret['data'][1]['name'] = "2g_clients";
@$ret['data'][1]['value'] += explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.8.".$i])[1];
} else { // 5Ghz clients
- $ret['data'][2]['name'] = "5g_clients";
- @$ret['data'][2]['value'] += explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.8.".$i])[1];
+ $ret['data'][2]['name'] = "5g_clients";
+ @$ret['data'][2]['value'] += explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.8.".$i])[1];
}
}
$ret['data'][0]['name'] = "sum_clients";
@@ -157,8 +159,8 @@ function collect_radio_summary($inp,$host){
"label" => str_replace("\"", "",explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1] ),
"draw" => "LINE1.2",
"info" => explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1],
- "type" => "GAUGE",
- "min" => "0",
+ "type" => "GAUGE",
+ "min" => "0",
);
}
@@ -184,8 +186,8 @@ function collect_netw_summary($inp,$host){ //network information
$multiplier = 8;
$divider = 1;
} else { //because the normal INTEGER(32) would be overflowed
- $multiplier = 8*4*1024; // When showing the controller's summary
- $divider = 4*1024;
+ $multiplier = 8*1024*4; // When showing the controller's summary
+ $divider = 1024*4;
}
@@ -198,7 +200,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['g_vlabel'] = "bits in(-) / out(+) per second";
$ret['g_category'] = "Wl_netw_ap";
$ret['g_info'] = "ubnt_network";
- $ret['g_order'] = "rx_all tx_all rx_2g tx_2g rx_5g tx_5g";
+ $ret['g_order'] = "rx_all tx_all rx_2g tx_2g rx_5g tx_5g";
} else {
$ret['g_multi'] = "netw_".str_replace( array(".", ":"), "_" ,$controller);
@@ -207,7 +209,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['g_vlabel'] = "bits in(-) / out(+) per second";
$ret['g_category'] = "Wl_netw_all";
$ret['g_info'] = "ubnt_network";
- $ret['g_order'] = "rx_all tx_all rx_2g tx_2g rx_5g tx_5g";
+ $ret['g_order'] = "rx_all tx_all rx_2g tx_2g rx_5g tx_5g";
}
$ret['head'][0]['name'] = "rx_all";
@@ -216,9 +218,9 @@ function collect_netw_summary($inp,$host){ //network information
$ret['head'][0]['info'] = "Total Received";
$ret['head'][0]['type'] = "DERIVE";
$ret['head'][0]['min'] = "0";
- $ret['head'][0]['graph'] = "no";
- $ret['head'][0]['cdef'] = "unifi_rx_all,$multiplier,*";
- $ret['head'][0]['max'] = "1000000000";
+ $ret['head'][0]['graph'] = "no";
+ $ret['head'][0]['cdef'] = "unifi_rx_all,$multiplier,*";
+ $ret['head'][0]['max'] = "1000000000";
$ret['head'][1]['name'] = "tx_all";
$ret['head'][1]['label'] = "Total (bps)";
@@ -228,7 +230,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['head'][1]['min'] = "0";
$ret['head'][1]['cdef'] = "unifi_tx_all,$multiplier,*";
$ret['head'][1]['max'] = "1000000000";
- $ret['head'][1]['negative'] = "unifi_rx_all";
+ $ret['head'][1]['negative'] = "unifi_rx_all";
$ret['head'][2]['name'] = "rx_2g";
$ret['head'][2]['label'] = "2G (bps)";
@@ -248,7 +250,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['head'][3]['min'] = "0";
$ret['head'][3]['cdef'] = "unifi_tx_2g,$multiplier,*";
$ret['head'][3]['max'] = "1000000000";
- $ret['head'][3]['negative'] = "unifi_rx_2g";
+ $ret['head'][3]['negative'] = "unifi_rx_2g";
$ret['head'][4]['name'] = "rx_5g";
$ret['head'][4]['label'] = "5G (bps)";
@@ -256,7 +258,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['head'][4]['info'] = "Total Received";
$ret['head'][4]['type'] = "DERIVE";
$ret['head'][4]['min'] = "0";
- $ret['head'][4]['graph'] = "no";
+ $ret['head'][4]['graph'] = "no";
$ret['head'][4]['cdef'] = "unifi_rx_5g,$multiplier,*";
$ret['head'][4]['max'] = "1000000000";
@@ -268,7 +270,7 @@ function collect_netw_summary($inp,$host){ //network information
$ret['head'][5]['min'] = "0";
$ret['head'][5]['cdef'] = "unifi_tx_5g,$multiplier,*";
$ret['head'][5]['max'] = "1000000000";
- $ret['head'][5]['negative'] = "unifi_rx_5g";
+ $ret['head'][5]['negative'] = "unifi_rx_5g";
foreach($inp as $key => $val){
@@ -277,7 +279,7 @@ function collect_netw_summary($inp,$host){ //network information
if( explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.4.".$i])[1] < 15 ){ //2.4Ghz client
$ret['data'][2]['name'] = "rx_2g";
@$ret['data'][2]['value'] += round((explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.10.".$i])[1]) / $divider);
- $ret['data'][3]['name'] = "tx_2g";
+ $ret['data'][3]['name'] = "tx_2g";
@$ret['data'][3]['value'] += round((explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.16.".$i])[1]) / $divider);
} else { // 5Ghz clients
@@ -310,15 +312,15 @@ function collect_netw_summary($inp,$host){ //network information
"value" => round((explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.10.".$i])[1]) / $divider) ,
);
$ret['head'][] = array( "name" => "rx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]),
- "label" => "RX_".str_replace("\"", "",explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1] )."(bps)",
+ "label" => "RX_".str_replace("\"", "",explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1] )." (bps)",
"draw" => "LINE1.2",
"info" => "Rx_".explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1],
"type" => "DERIVE",
"min" => "0",
- "graph" => "no",
- "cdef" => "unifi_rx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]).",$multiplier,*",
- "max" => "1000000000",
- );
+ "graph" => "no",
+ "cdef" => "unifi_rx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]).",$multiplier,*",
+ "max" => "1000000000",
+ );
}
@@ -334,7 +336,7 @@ function collect_netw_summary($inp,$host){ //network information
} else { //ssid not found, new record
$ret['data'][] = array( "name" => "tx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]),
"value" => round((explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.16.".$i])[1]) / $divider) ,
- );
+ );
$ret['head'][] = array( "name" => "tx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]),
"label" => "".str_replace("\"", "",explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1] )." (bps)",
"draw" => "LINE1.2",
@@ -343,8 +345,8 @@ function collect_netw_summary($inp,$host){ //network information
"min" => "0",
"cdef" => "unifi_tx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]).",$multiplier,*",
"max" => "1000000000",
- "negative" => "unifi_rx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]),
- );
+ "negative" => "unifi_rx_".str_replace($replace_chars, "_", explode(": ", $inp[$key]["iso.3.6.1.4.1.41112.1.6.1.2.1.6.".$i])[1]),
+ );
}
@@ -367,7 +369,6 @@ if($mask != 0 ){
}
}
-
foreach($hosts as $key => $val){ // delete addresses which are given by hostname
if(in_array(gethostbyname($val), $hosts2)){
unset($hosts2[ array_keys($hosts2, gethostbyname($val))[0] ]);
@@ -375,28 +376,124 @@ foreach($hosts as $key => $val){ // delete addresses which are given by hostna
}
$hosts = array_merge($hosts, $hosts2);
+unset($hosts2);
+
+$numhost = count($hosts);
+$shm_key = ftok($argv[0], 'c');
+$shm = shmop_open($shm_key, "c", 0640, ceil($numhost/$maxproc)*32768);
+$sf = sem_get($shm_key,1,0640,1);
+$child = array();
+$raw = array();
+$hostsr = $hosts;
+unset($hosts);
+$hostst = array();
+
-$raw=array();
-foreach($hosts as $key => $val){ // get raw snmp data from unifi devices
- if($hosts[$key] == ""){
- unset($hosts[$key]);
+for($i=0,$j=0; $i<$numhost; $i++){ //Sorting addresses for child-processes
+
+ if($j >= $maxproc){ //With permutation
+ $j = 0;
+ }
+ if(array_key_exists($j, $hostst) === FALSE){
+ $hostst[$j] = array();
}
- if($val != "") {
- $raw[$val] = @snmp2_real_walk($val, "public", ".1.3.6.1.4.1.41112.1.6.1.2.1", $timeout*1000, $retry ); // wl network info
- $raw[$val]["iso.3.6.1.2.1.1.6.0"] = @snmp2_get($val, "public", ".1.3.6.1.2.1.1.6.0", $timeout*1000, $retry ) ; // location info
- $raw[$val]["iso.3.6.1.2.1.1.1.0"] = @snmp2_get($val, "public", ".1.3.6.1.2.1.1.1.0", $timeout*1000, $retry ) ; // descr. info
+
+ $hostst[$j] = array_merge($hostst[$j], array($hostsr[$i])); //With permutation
+ $j++;
+}
+
+
+
+
+for ($p=0; $p<$maxproc; $p++){ //Starts child processes to retrieve SNMP data.
+
+ unset($hosts);
+ $hosts = array();
+ if(array_key_exists($p,$hostst)){
+ $hosts = $hostst[$p];
}
- if( !isset($raw[$val]["iso.3.6.1.4.1.41112.1.6.1.2.1.1.1"]) ){
- unset($raw[$val]);
- unset($hosts[$key]);
+
+
+ $pid = pcntl_fork();
+
+ if($pid == -1){
+ die('could not fork');
}
+
+ else if($pid){ // we are the parent process
+ $child[$p] = $pid;
+ }
+
+ else { // child
+ $raw=array();
+ foreach($hosts as $key => $val){ // get raw snmp data from unifi devices
+ if($hosts[$key] == ""){
+ unset($hosts[$key]);
+ }
+ if($val != "") {
+ $raw[$val] = @snmp2_real_walk($val, "public", ".1.3.6.1.4.1.41112.1.6.1.2.1", $timeout*1000, $retry ); // wl network info
+ $raw[$val]["iso.3.6.1.2.1.1.6.0"] = @snmp2_get($val, "public", ".1.3.6.1.2.1.1.6.0", $timeout*1000, $retry ) ; // location info
+ $raw[$val]["iso.3.6.1.2.1.1.1.0"] = @snmp2_get($val, "public", ".1.3.6.1.2.1.1.1.0", $timeout*1000, $retry ) ; // descr. info
+ }
+ if( !isset($raw[$val]["iso.3.6.1.4.1.41112.1.6.1.2.1.1.1"]) ){
+ unset($raw[$val]);
+ unset($hosts[$key]);
+ }
+
+ $null="";
+ for($f=0; $f<(32768 - strlen(json_encode($raw))); $f++)
+ {
+ $null .= "\0"; //Because the json_decode() error.
+ }
+
+ sem_acquire($sf);
+ while(ord(shmop_read($shm, 0, 0)) ) {continue;} //waiting for master to pull the data
+ shmop_write($shm, json_encode($raw).$null, 0);
+ sem_release($sf);
+ }
+ exit;
+ }
+
+}
+unset($hostst);
+unset($hosts);
+
+function numchild($child, $n){ //How many child process is alive
+ $l=0;
+ for($i=0; $i<$n; $i++){
+ if($child[$i] > 0){
+ $l++;
+ }
+ }
+ return $l;
}
+while(numchild($child, $maxproc)){ //Receive the raw data segments and wait for child processes
+
+ for($p=0; $p<$maxproc; $p++){
+ if( abs($pid = pcntl_waitpid($child[$p], $status, WNOHANG)) > 0) {//Protect against Zombie children
+ $child[$p] = 0;
+ }
+ }
+
+ $ret = shmop_read($shm, 0, 0); //Read from shared memory
+ if(ord($ret)){
+ $ret = preg_replace('/[[:cntrl:]]/', '', $ret); // for json_decode
+ $raw = array_merge($raw, json_decode($ret, true));
+ shmop_write($shm,"\0\0\0\0\0", 0);
+ }
+ usleep(100); //
+}
+
+sem_remove($sf);
+shmop_delete($shm);
+shmop_close($shm);
+$hosts = $hostsr;
//print_r($raw);
//print_r($hosts);
-//$valami = collect_netw_summary($raw,"ap12.wireless.lan");
-//print_r($valami);
+//$test = collect_netw_summary($raw,"ap12.wireless.lan");
+//print_r($test);
if (isset($argv[1]) and $argv[1] == "config"){ // munin config