diff options
Diffstat (limited to 'src/pmdas/cisco')
-rw-r--r-- | src/pmdas/cisco/Cisco.pmchart | 11 | ||||
-rw-r--r-- | src/pmdas/cisco/GNUmakefile | 70 | ||||
-rw-r--r-- | src/pmdas/cisco/Install | 156 | ||||
-rw-r--r-- | src/pmdas/cisco/README | 76 | ||||
-rw-r--r-- | src/pmdas/cisco/Remove | 38 | ||||
-rw-r--r-- | src/pmdas/cisco/Samples | 291 | ||||
-rw-r--r-- | src/pmdas/cisco/Tested | 76 | ||||
-rw-r--r-- | src/pmdas/cisco/cisco.c | 265 | ||||
-rw-r--r-- | src/pmdas/cisco/cisco.h | 86 | ||||
-rw-r--r-- | src/pmdas/cisco/cisco.in_util.pmie | 64 | ||||
-rw-r--r-- | src/pmdas/cisco/cisco.out_util.pmie | 64 | ||||
-rw-r--r-- | src/pmdas/cisco/help | 76 | ||||
-rw-r--r-- | src/pmdas/cisco/interface.c | 46 | ||||
-rwxr-xr-x | src/pmdas/cisco/parse.sh | 3 | ||||
-rw-r--r-- | src/pmdas/cisco/pmda.c | 401 | ||||
-rw-r--r-- | src/pmdas/cisco/pmns | 28 | ||||
-rw-r--r-- | src/pmdas/cisco/probe.c | 367 | ||||
-rw-r--r-- | src/pmdas/cisco/root | 10 | ||||
-rw-r--r-- | src/pmdas/cisco/telnet.c | 755 |
19 files changed, 2883 insertions, 0 deletions
diff --git a/src/pmdas/cisco/Cisco.pmchart b/src/pmdas/cisco/Cisco.pmchart new file mode 100644 index 0000000..6baf4e7 --- /dev/null +++ b/src/pmdas/cisco/Cisco.pmchart @@ -0,0 +1,11 @@ +#pmchart +Version 1.2 host dynamic + +Chart Style plot + Plot Color #-cycle Host * Metric cisco.rate_in + +Chart Style plot + Plot Color #-cycle Host * Metric cisco.rate_out + +# +# Created Mon Sep 1 11:34:14 1997 diff --git a/src/pmdas/cisco/GNUmakefile b/src/pmdas/cisco/GNUmakefile new file mode 100644 index 0000000..e6c2733 --- /dev/null +++ b/src/pmdas/cisco/GNUmakefile @@ -0,0 +1,70 @@ +# +# Copyright (c) 2014 Red Hat. +# Copyright (c) 2000,2004 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# + +TOPDIR = ../../.. +include $(TOPDIR)/src/include/builddefs + +IAM = cisco +DOMAIN = CISCO +TARGETS = $(IAM)$(EXECSUFFIX) probe$(EXECSUFFIX) +CFILES = cisco.c pmda.c interface.c telnet.c +HFILES = cisco.h +DFILES = README +LSRCFILES=Install Remove root pmns Cisco.pmchart help Samples Tested $(DFILES) \ + cisco.in_util.pmie cisco.out_util.pmie probe.c parse.sh + +LLDLIBS = $(PCP_PMDALIB) $(LIB_FOR_PTHREADS) + +PMDADIR = $(PCP_PMDAS_DIR)/$(IAM) +PMCHART = $(PCP_VAR_DIR)/config/pmchart +PMIEDIR = $(PCP_VAR_DIR)/config/pmieconf/$(IAM) + +LDIRT = domain.h cisco.log *.dir *.pag so_locations a.out probe.o $(TARGETS) + +default: build-me + +include $(BUILDRULES) + +ifneq "$(TARGET_OS)" "mingw" +build-me: $(TARGETS) + +install: build-me + $(INSTALL) -m 755 -d $(PMDADIR) + $(INSTALL) -m 755 $(IAM) $(PMDADIR)/pmda$(IAM) + $(INSTALL) -m 755 parse.sh $(PMDADIR)/parse + $(INSTALL) -m 755 probe Install Remove $(PMDADIR) + $(INSTALL) -m 644 $(DFILES) root help pmns domain.h $(PMDADIR) + $(INSTALL) -m 644 Cisco.pmchart $(PMCHART)/Cisco + $(INSTALL) -m 755 -d $(PMIEDIR) + $(INSTALL) -m 644 cisco.in_util.pmie $(PMIEDIR)/in_util + $(INSTALL) -m 644 cisco.out_util.pmie $(PMIEDIR)/out_util +else +build-me: +install: +endif + +$(IAM)$(EXECSUFFIX): $(OBJECTS) + +probe$(EXECSUFFIX): probe.o interface.o telnet.o + $(CCF) -o $@ $(LDFLAGS) probe.o interface.o telnet.o $(LDLIBS) + +cisco.o: domain.h + +domain.h: ../../pmns/stdpmid + $(DOMAIN_MAKERULE) + +default_pcp: default + +install_pcp: install diff --git a/src/pmdas/cisco/Install b/src/pmdas/cisco/Install new file mode 100644 index 0000000..5ee4742 --- /dev/null +++ b/src/pmdas/cisco/Install @@ -0,0 +1,156 @@ +#! /bin/sh +# +# Copyright (c) 1997-2003 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# Install the cisco PMDA and/or PMNS +# + +. $PCP_DIR/etc/pcp.env +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +iam=cisco +pmda_interface=2 +forced_restart=false + +# Do it +# +pmdaSetup + +check_delay=20 +pollrate=120 # poll each Cisco interface once every 120 seconds + # -- change this if desired + +# special cisco PMDA args + +if $do_pmda +then + args="-r$pollrate" + default="wanptg" + while true + do + no_host=true + while $no_host + do + echo + $PCP_ECHO_PROG $PCP_ECHO_N "Cisco hostname or IP address? [return to quit Cisco selection] ""$PCP_ECHO_C" + read host + [ "X$host" = X ] && break + echo ' +A username and/or user-level password may be required for the Cisco +"show interface" command. + If you are unsure, try the command + $ telnet '$host' + and if the prompt "Username:" appears, then a username is required, + and if the prompt "Password:" appears, a user-level password is required, + otherwise respond with an empty line for the next two questions. + Once logged in, we need to know the termination string for the command + line prompt (one or more unique characters at the end of the prompt) - + the default is ">", but if this is not correct, enter the prompt + termination string also. +' + $PCP_ECHO_PROG $PCP_ECHO_N "Cisco username? ""$PCP_ECHO_C" + read username + userarg="" + [ "X$username" != X ] && userarg="-U$username" + $PCP_ECHO_PROG $PCP_ECHO_N "User-level Cisco password? ""$PCP_ECHO_C" + read passwd + passarg="" + [ "X$passwd" != X ] && passarg="-P$passwd" + $PCP_ECHO_PROG $PCP_ECHO_N "Cisco command line prompt termination? [>] ""$PCP_ECHO_C" + read prompt + promptarg="" + [ "X$prompt" != X ] && promptarg="-s'$prompt'" + echo "Probing Cisco for list of interfaces ..." + for try in 1 2 3 + do + intf=`eval ./probe $userarg $passarg $promptarg $host 2>$tmp/err` + [ ! -z "$intf" ] && break + sleep 2 + done + if [ -z "$intf" ] + then + echo ' +There appears to be a problem ... after three attempts could not get +interfaces. Output at the last attempt was:' + sed -e 's/^/ /' <$tmp/err + echo ' +You may wish to try the following commands to identify the configured +interfaces for this Cisco. + $ telnet '$host' + ....> terminal length 0 + ....> show interface + ....> quit +' + else + no_host=false + fi + done + [ "X$host" = X ] && break + + if [ -z "$username" ] + then + login="" + else + login="@$username" + fi + [ ! -z "$passwd" ] && login="$login?$passwd" + [ ! -z "$prompt" ] && login="$login!$prompt" + + echo ' +Enter interfaces to monitor, one per line in the format tX where "t" is +a type and one of "e" (Ethernet), "E" (FastEthernet), "f" (Fddi), "s" +(Serial), "a" (ATM), "B" (ISDN BRI) or "h" (HSSC) and "X" is an +interface identifier which is either an integer (e.g. 4000 Series +routers) or two integers separated by a slash (e.g. 7000 Series +routers).' + + while true + do + echo + echo 'The currently unselected interfaces for the Cisco "'$host'" are:' + echo "$intf" | fmt | sed -e 's/^/ /' + echo 'Enter "*" to select all, "quit" to terminate selections for this Cisco.' + + first=`echo "$intf" | sed -e 's/ .*//'` + [ -z "$first" ] && first=quit + $PCP_ECHO_PROG $PCP_ECHO_N "Interface? [$first] ""$PCP_ECHO_C" + read ans + [ "X$ans" = Xquit ] && break + if [ "X$ans" = "X*" ] + then + # do them all + for ans in `echo "$intf"` + do + args="$args $host:$ans$login" + login='' + done + break + fi + [ -z "$ans" ] && ans="$first" + if echo " $intf" | grep " $ans" >/dev/null + then + sed_ans=`echo $ans | sed -e 's;/;\\\\/;g'` + intf=`echo " $intf" | sed -e "s/ $sed_ans//" -e 's/^ //'` + else + echo "Warning: $ans is not in the list, I hope you know what you're doing" + fi + args="$args $host:$ans$login" + login='' + [ -z "$intf" ] && break + done + done +fi + +pmdaInstall + +exit 0 diff --git a/src/pmdas/cisco/README b/src/pmdas/cisco/README new file mode 100644 index 0000000..908c837 --- /dev/null +++ b/src/pmdas/cisco/README @@ -0,0 +1,76 @@ +Performance Co-Pilot PMDA for Monitoring Cisco Routers +====================================================== + +This PMDA is capable of collecting throughput measures from Cisco +routers throughout a network. + +The PMDA needs to be configured to collect performance data from a +designated set of interfaces on nominated Cisco routers. There is one +instance of the metrics for nominated each router-interface pair. + +Metrics +======= + +The file ./help contains descriptions for all of the metrics exported +by this PMDA. + +Once the PMDA has been installed, the following command will list all +the available metrics and their explanatory "help" text: + + $ pminfo -fT cisco + +Installation +============ + + + # cd $PCP_PMDAS_DIR/cisco + + + Check that there is no clash in the Performance Metrics Domain + defined in ./domain.h and the other PMDAs currently in use (see + $PCP_PMCDCONF_PATH). If there is, edit ./domain.h to choose another + domain number. + + + The Cisco PMDA is one that polls the Cisco routers, and caches the + most recent value for the performance metrics. The cached values + are the ones returned via the PMCD to clients requesting Cisco + performance metrics. The default polling rate is once every two + minutes to each Cisco interface being monitored, if you wish to + change this, edit Install and change the value of pollrate near the + start of the script. + + + Then simply use + + # ./Install + + and choose both the "collector" and "monitor" installation + configuration options. + + You will be prompted to identify the Cisco routers and + interfaces you wish to monitor. + +De-installation +=============== + + + Simply use + + # cd $PCP_PMDAS_DIR/cisco + # ./Remove + +Troubleshooting +=============== + + + After installing or restarting the agent, the PMCD log file + ($PCP_LOG_DIR/pmcd/pmcd.log) and the PMDA log file + ($PCP_LOG_DIR/pmcd/cisco.log) should be checked for any warnings + or errors. + + + The configured interfaces on a particular Cisco may be discovered + using the $PCP_PMDAS_DIR/cisco/probe application. See pmdacisco(1) + for more details. + + + The $PCP_PMDAS_DIR/cisco/parse application supports the same + command line options as pmdacisco for identifying interfaces on + Cisco devices and shares the parser for the output from the Cisco + "show interface" command; this application may be used to gain + diagnostic traces of the interaction between the parser code and + the Cisco device in the event that metrics values are not being + returned by the Cisco PMDA. See pmdacisco(1) for more details. diff --git a/src/pmdas/cisco/Remove b/src/pmdas/cisco/Remove new file mode 100644 index 0000000..0f4f109 --- /dev/null +++ b/src/pmdas/cisco/Remove @@ -0,0 +1,38 @@ +#! /bin/sh +# +# Copyright (c) 1997 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# Remove the cisco PMDA and/or PMNS +# + +# Get standard environment +. $PCP_DIR/etc/pcp.env + +# Get the common procedures and variable assignments +# +. $PCP_SHARE_DIR/lib/pmdaproc.sh + +# The name of the PMDA +# +iam=cisco + +# Do it +# +pmdaSetup +pmdaRemove + +exit 0 diff --git a/src/pmdas/cisco/Samples b/src/pmdas/cisco/Samples new file mode 100644 index 0000000..dd25be6 --- /dev/null +++ b/src/pmdas/cisco/Samples @@ -0,0 +1,291 @@ + +Serial 0 is up, line protocol is up + Hardware is MK5025 + Description: frame-relay to MtVA, Tokyo, Hong Kong + Internet address is 155.11.201.172, subnet mask is 255.255.255.128 + MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 15/255 + Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) + LMI DLCI 0, LMI sent 346516, LMI stat recvd 345070, LMI upd recvd 2 + LMI type is ANSI Annex D + Last input 0:00:01, output 0:00:00, output hang never + Last clearing of "show interface" counters never + Output queue 0/8, 298580 drops; input queue 0/75, 0 drops + Five minute input rate 60000 bits/sec, 16 packets/sec + Five minute output rate 4000 bits/sec, 12 packets/sec + 18139408 packets input, 2763796661 bytes, 0 no buffer + Received 0 broadcasts, 0 runts, 0 giants + 189 input errors, 189 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort + 15860554 packets output, 3098844973 bytes, 0 underruns + 0 output errors, 0 collisions, 668 interface resets, 0 restarts + 686 carrier transitions + +Ethernet 0 is up, line protocol is up + Hardware is Lance, address is 0000.0c03.ed85 (bia 0000.0c03.ed85) + Description: Sydney, Australia + Internet address is 155.11.226.3, subnet mask is 255.255.255.128 + MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, rely 255/255, load 1/255 + Encapsulation ARPA, loopback not set, keepalive set (10 sec) + ARP type: ARPA, ARP Timeout 4:00:00 + Last input 0:00:00, output 0:00:00, output hang never + Last clearing of "show interface" counters never + Output queue 0/40, 19188 drops; input queue 1/75, 0 drops + Five minute input rate 5000 bits/sec, 10 packets/sec + Five minute output rate 60000 bits/sec, 13 packets/sec + 12884820 packets input, 1321046112 bytes, 0 no buffer + Received 1570813 broadcasts, 0 runts, 0 giants + 891 input errors, 891 CRC, 634 frame, 0 overrun, 0 ignored, 0 abort + 14717105 packets output, 870622060 bytes, 0 underruns + 98605 output errors, 1883820 collisions, 1 interface resets, 0 restarts + +Fddi2/0 is up, line protocol is up + Hardware is cxBus FDDI, address is 0000.0c38.4360 (bia 0000.0c38.4360) + Internet address is 192.26.80.22, subnet mask is 255.255.255.0 + MTU 4470 bytes, BW 100000 Kbit, DLY 100 usec, rely 255/255, load 1/255 + Encapsulation SNAP, loopback not set, keepalive not set + ARP type: SNAP, ARP Timeout 4:00:00 + Phy-A state is connect, neighbor is unk, cmt signal bits 008/000, status QLS + Phy-B state is active, neighbor is M, cmt signal bits 20C/00E, status ILS + CFM is wrap B, token rotation 5000 usec, ring operational 0:00:58 + Upstream neighbor 0800.6904.155d, downstream neighbor 0040.0b80.a052 + Last input 0:00:00, output 0:00:00, output hang never + Last clearing of "show interface" counters 1w0d + Output queue 0/40, 85 drops; input queue 0/75, 33437 drops + Five minute input rate 160000 bits/sec, 39 packets/sec + Five minute output rate 93000 bits/sec, 108 packets/sec + 33780622 packets input, 4009491185 bytes, 87 no buffer + Received 3768432 broadcasts, 0 runts, 0 giants + 2 input errors, 1 CRC, 1 frame, 0 overrun, 19 ignored, 0 abort + 83194423 packets output, 612803885 bytes, 492 underruns + 0 output errors, 0 collisions, 0 interface resets, 0 restarts + 21602 transitions, 0 traces, 11625 claims, 0 beacon + +Serial1 is up, line protocol is up + Hardware is HD64570 + Description: Frame-relay, MtV, Hong Kong, Sydney + MTU 1500 bytes, BW 1544 Kbit, DLY 20000 usec, rely 255/255, load 5/255 + Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) + LMI enq sent 14998, LMI stat recvd 14885, LMI upd recvd 0, DTE LMI up + LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 + LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE + Broadcast queue 0/200, broadcasts sent/dropped 508604/0 + Last input 0:00:00, output 0:00:00, output hang never + Last clearing of "show interface" counters never + Output queue 0/40, 947 drops; input queue 0/75, 0 drops + Five minute input rate 117000 bits/sec, 29 packets/sec + Five minute output rate 32000 bits/sec, 20 packets/sec + 2578327 packets input, 1105345262 bytes, 0 no buffer + Received 0 broadcasts, 0 runts, 0 giants + 54 input errors, 4 CRC, 0 frame, 0 overrun, 1 ignored, 4 abort + 1975049 packets output, 675844616 bytes, 0 underruns + 0 output errors, 0 collisions, 142 interface resets, 0 restarts + 3 carrier transitions + DCD=up DSR=up DTR=up RTS=up CTS=up + +Ethernet3/5 is up, line protocol is up + Hardware is cxBus Ethernet, address is 0000.0c38.436d (bia 0000.0c38.436d) + Internet address is 198.29.108.4, subnet mask is 255.255.255.0 + MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, rely 255/255, load 2/255 + Encapsulation ARPA, loopback not set, keepalive set (10 sec) + ARP type: ARPA, ARP Timeout 4:00:00 + Last input 0:00:03, output 0:00:01, output hang never + Last clearing of "show interface" counters 6w2d + Output queue 0/40, 54880 drops; input queue 0/75, 1492 drops + 5 minute input rate 1000 bits/sec, 0 packets/sec + 5 minute output rate 91000 bits/sec, 98 packets/sec + 24627812 packets input, 1448819515 bytes, 862 no buffer + Received 3959194 broadcasts, 79 runts, 4 giants + 292 input errors, 195 CRC, 14 frame, 0 overrun, 0 ignored, 0 abort + 0 input packets with dribble condition detected + 150470373 packets output, 3227527737 bytes, 0 underruns + 1274 output errors, 11605581 collisions, 0 interface resets, 0 restarts + +ATM12/0 is up, line protocol is up + Hardware is cxBus ATM + Internet address is 150.166.230.24 255.255.255.0 + MTU 4470 bytes, BW 156250 Kbit, DLY 80 usec, rely 255/255, load 1/255 + Encapsulation ATM, loopback not set, keepalive set (10 sec) + Encapsulation(s): AAL5, PVC mode + 256 TX buffers, 256 RX buffers, 2048 maximum active VCs, 1024 VCs per VP, 15 current VCCs + Last input 0:00:00, output 0:00:00, output hang never + Last clearing of "show interface" counters never + Output queue 0/40, 511 drops; input queue 0/75, 10612 drops + 5 minute input rate 181000 bits/sec, 116 packets/sec + 5 minute output rate 160000 bits/sec, 68 packets/sec + 658262505 packets input, 1239748718 bytes, 199 no buffer + Received 0 broadcasts, 0 runts, 0 giants + 2570 input errors, 2569 CRC, 1 frame, 0 overrun, 0 ignored, 0 abort + 788426419 packets output, 4188341273 bytes, 0 underruns + 0 output errors, 0 collisions, 21 interface resets, 0 restarts + 0 output buffer failures, 63 output buffers swapped out + +Hssi3/0 is administratively down, line protocol is down + Hardware is cxBus HSSI + Description: 45 Meg Microwave Link to Building 27 + Internet address is 150.166.124.1 255.255.255.0 + MTU 4470 bytes, BW 45045 Kbit, DLY 200 usec, rely 255/255, load 1/255 + Encapsulation HDLC, loopback not set, keepalive set (10 sec) + Last input 1:07:12, output 1:07:08, output hang never + Last clearing of "show interface" counters never + Output queue 0/40, 2 drops; input queue 0/75, 37 drops + 5 minute input rate 0 bits/sec, 0 packets/sec + 5 minute output rate 0 bits/sec, 0 packets/sec + 306700515 packets input, 1443052046 bytes, 5 no buffer + Received 1118787 broadcasts, 0 runts, 0 giants + 0 parity + 241 input errors, 0 CRC, 241 frame, 0 overrun, 0 ignored, 0 abort + 246381377 packets output, 3684064154 bytes, 0 underruns + 0 output errors, 0 applique, 210 interface resets, 0 restarts + 0 output buffer failures, 83 output buffers swapped out + 8214 carrier transitions + +FastEthernet1/0 is up, line protocol is up + Hardware is cyBus FastEthernet Interface, address is 0060.3eb0.8c20 (bia 0060.3eb0.8c20) + Internet address is 192.111.17.1 255.255.255.0 + MTU 1500 bytes, BW 100000 Kbit, DLY 100 usec, rely 255/255, load 1/255 + Encapsulation ARPA, loopback not set, keepalive set (10 sec), fdx, MII + ARP type: ARPA, ARP Timeout 4:00:00 + Last input 0:00:05, output 0:00:05, output hang never + Last clearing of "show interface" counters never + Output queue 0/40, 0 drops; input queue 0/75, 362 drops + 5 minute input rate 8000 bits/sec, 1 packets/sec + 5 minute output rate 11000 bits/sec, 0 packets/sec + 4615550 packets input, 1942263093 bytes, 33 no buffer + Received 1947224 broadcasts, 0 runts, 8 giants + 30351 input errors, 30351 CRC, 15187 frame, 0 overrun, 0 ignored, 0 abort + 0 watchdog, 27381 multicast + 0 input packets with dribble condition detected + 11521698 packets output, 1811832796 bytes, 0 underruns + 0 output errors, 0 collisions, 2 interface resets, 0 restarts + 0 babbles, 0 late collision, 0 deferred + 0 lost carrier, 0 no carrier + 0 output buffer failures, 0 output buffers swapped out + +Serial1/0 is up, line protocol is up + Hardware is M4T + Description: frame-relay using subinterfaces + MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 11/255 + Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) + LMI enq sent 10084, LMI stat recvd 9997, LMI upd recvd 0, DTE LMI up + LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 + LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE + FR SVC disabled, LAPF state down + Broadcast queue 0/200, broadcasts sent/dropped 53152/0, interface broadcasts 49826 + Last input 00:00:01, output 00:00:00, output hang never + Last clearing of "show interface" counters never + Queueing strategy: fifo + Output queue 0/8, 0 drops; input queue 0/75, 0 drops + 5 minute input rate 3000 bits/sec, 4 packets/sec + 5 minute output rate 3000 bits/sec, 4 packets/sec + 429076 packets input, 132623595 bytes, 0 no buffer + Received 0 broadcasts, 0 runts, 1 giants, 0 throttles + 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored, 0 abort + 474808 packets output, 73186481 bytes, 0 underruns + 0 output errors, 0 collisions, 31 interface resets + 0 output buffer failures, 0 output buffers swapped out + 35 carrier transitions DCD=up DSR=up DTR=up RTS=up CTS=up + +Serial1/0 is up, line protocol is up + Hardware is M4T + Description: frame-relay using subinterfaces + MTU 1500 bytes, BW 64 Kbit, DLY 20000 usec, rely 255/255, load 31/255 + Encapsulation FRAME-RELAY, loopback not set, keepalive set (10 sec) + LMI enq sent 39756, LMI stat recvd 39753, LMI upd recvd 0, DTE LMI up + LMI enq recvd 0, LMI stat sent 0, LMI upd sent 0 + LMI DLCI 0 LMI type is ANSI Annex D frame relay DTE + FR SVC disabled, LAPF state down + Broadcast queue 0/200, broadcasts sent/dropped 91696/0, interface broadcasts 85069 + Last input 00:00:00, output 00:00:00, output hang never + Last clearing of "show interface" counters never + Queueing strategy: fifo + Output queue 0/8, 0 drops; input queue 0/75, 0 drops + 30 second input rate 62000 bits/sec, 9 packets/sec + 30 second output rate 8000 bits/sec, 5 packets/sec + 2238005 packets input, 630502832 bytes, 0 no buffer + Received 0 broadcasts, 0 runts, 0 giants, 0 throttles + 111 input errors, 108 CRC, 0 frame, 0 overrun, 0 ignored, 3 abort + 2274950 packets output, 230325061 bytes, 0 underruns + 0 output errors, 0 collisions, 2 interface resets + 0 output buffer failures, 0 output buffers swapped out + 3 carrier transitions DCD=up DSR=up DTR=up RTS=up CTS=up + +>show int s2/2.1 +Serial2/2.1 is up, line protocol is up + Hardware is M4T + Description: Frame Relay to Sydney (134.14.63.129) + Internet address is 134.14.63.130/30 + MTU 1500 bytes, BW 512 Kbit, DLY 20000 usec, + reliability 255/255, txload 2/255, rxload 17/255 + Encapsulation FRAME-RELAY + +CIR is BW 512 Kbit == 512*1024/10 bytes/sec (?) + +This number is hand typed, but there is no alternative for the CIR. + +For FrameRelay, utilization > 50% of CIR for alarm. + +>show frame pvc int s2/3.7 + +PVC Statistics for interface Serial2/3.7 (Frame Relay DTE) + + Active Inactive Deleted Static + Local 2 0 0 0 + Switched 0 0 0 0 + Unused 0 0 0 0 + +DLCI = 17, DLCI USAGE = LOCAL, PVC STATUS = ACTIVE, INTERFACE = Serial2/3.7 + + input pkts 1287959 output pkts 1446754 in bytes 811690634 + out bytes 187572881 dropped pkts 0 in FECN pkts 2333 + in BECN pkts 0 out FECN pkts 0 out BECN pkts 0 + in DE pkts 0 out DE pkts 0 + out bcast pkts 43801 out bcast bytes 13172828 + pvc create time 8w3d, last time pvc status changed 1w2d + +>show int Vlan256 +Vlan256 is up, line protocol is up + Hardware is Cat6k RP Virtual Ethernet, address is 0030.b630.b318 (bia 0030.b630.b318) + Description: Uplink to CTC tipctc2 (Area 2) + Internet address is 192.132.156.72/26 + MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, + reliablility 255/255, txload 1/255, rxload 44/255 + Encapsulation ARPA, loopback not set + ARP type: ARPA, ARP Timeout 04:00:00 + Last input 00:00:00, output never, output hang never + Last clearing of "show interface" counters never + Queueing strategy: fifo + Output queue 0/40, 2 drops; input queue 0/75, 1027 drops + 5 minute input rate 1754000 bits/sec, 158 packets/sec + 5 minute output rate 9000 bits/sec, 6 packets/sec + 3087365859 packets input, 816292345 bytes, 224 no buffer + Received 3085491728 broadcasts, 0 runts, 0 giants, 0 throttles + 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored + 110141390 packets output, 3736073981 bytes, 0 underruns + 0 output errors, 3 interface resets + 0 output buffer failures, 0 output buffers swapped out + +>show int e1/0 +Ethernet1/0 is up, line protocol is up + Hardware is AmdP2, address is 0050.7343.f011 (bia 0050.7343.f011) + Description: >>> Connecion to melbourne pix-e1 <<< + Internet address is 134.14.71.241/30 + MTU 1500 bytes, BW 10000 Kbit, DLY 1000 usec, + reliability 255/255, txload 3/255, rxload 1/255 + Encapsulation ARPA, loopback not set + Keepalive set (10 sec) + ARP type: ARPA, ARP Timeout 04:00:00 + Last input 00:09:05, output 00:00:00, output hang never + Last clearing of "show interface" counters never + Queueing strategy: fifo + Output queue 0/40, 0 drops; input queue 0/75, 0 drops + 30 second input rate 26000 bits/sec, 4 packets/sec + 30 second output rate 118000 bits/sec, 97 packets/sec + 3657465 packets input, 2161281566 bytes, 0 no buffer + Received 79047 broadcasts, 0 runts, 0 giants, 0 throttles + 0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored + 0 input packets with dribble condition detected + 13202080 packets output, 4162655553 bytes, 0 underruns + 6 output errors, 249819 collisions, 11 interface resets + 0 babbles, 0 late collision, 207020 deferred + 6 lost carrier, 0 no carrier + 0 output buffer failures, 0 output buffers swapped out + diff --git a/src/pmdas/cisco/Tested b/src/pmdas/cisco/Tested new file mode 100644 index 0000000..fc3d6aa --- /dev/null +++ b/src/pmdas/cisco/Tested @@ -0,0 +1,76 @@ + +Cisco Model : MGS +Interface(s) e2 + +Cisco Model: Cisco 7000 +Interface(s) e1/2 f2/0 + +Cisco Model: Cisco 7000 +Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 + f2/0 f4/0 + +Cisco Model : 4500 +Interface(s) e0 f1 + +Cisco Model : 2500 (68030) processor (revision A) 3000 Software +Interface(s) e0 s0 + +Cisco Model : 4000M +Interface(s) e0#starchild + e1 -P starchild + f0 -P starchild + s0 -P starchild + s1#starchild + s2#starchild + +Cisco Model : 4500 +Interface(s) e0 e1 + f0 f1 + + +Cisco Model : 7513 +Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 + E1/0 E1/1 + s2/0 s2/1 s2/2 s2/3 + h3/0 + f5/0 f8/0 f9/0 f10/0 f11/0 + a12/0 + +Cisco Model : 7000 +Interface(s) e0/0 e0/1 e0/2 e0/3 e0/4 e0/5 + e1/0 e1/1 e1/2 e1/3 e1/4 e1/5 + e2/0 e2/1 e2/2 e2/3 e2/4 e2/5 + f3/0 + a4/0 + +Cisco Model : 2500 +Interfaces e0?cisco e1 s0 s1 + +Cisco Model : 3640 IOS 3600 Version 11.3(6), RELEASE SOFTWARE (fc1) +Interface(s) e0/0 s1/0 s1/1 s1/2 s1/3 + + +Cisco Model: Cat6k-MSFC +Interfaces Vlan32 Vlan33 Vlan34 Vlan35 Vlan36 Vlan37 + Vlan38 Vlan39 Vlan41 Vlan43 Vlan44 Vlan47 + Vlan48 Vlan50 Vlan51 + Vlan140 Vlan149 Vlan156 Vlan240 Vlan249 + Vlan256 + +Cisco Model: Catalyst 6509 +Interfaces Vl2 Vl3 Vl4 Vl5 Vl6 Vl7 Vl8 Vl14 Vl15 + Vl16 Vl17 Vl18 Vl19 Vl20 Vl21 Vl22 Vl23 + Vl101 Vl109 Vl110 Vl111 Vl112 Vl113 + Vl156 Vl209 Vl210 Vl211 Vl212 Vl213 + Vl256 + +Cisco Model: C2960 IOS Version 12.2(25)SEE2, RELEASE SOFTWARE (fc1) +Interfaces + Vl1 Vl50 + E0/1 E0/2 E0/3 E0/4 E0/5 E0/6 E0/7 E0/8 E0/9 E0/10 + E0/11 E0/12 E0/13 E0/14 E0/15 E0/16 E0/17 E0/18 E0/19 E0/20 + E0/21 E0/22 E0/23 E0/24 E0/25 E0/26 E0/27 E0/28 E0/29 E0/30 + E0/31 E0/32 E0/33 E0/34 E0/35 E0/36 E0/37 E0/38 E0/39 E0/40 + E0/41 E0/42 E0/43 E0/44 E0/45 E0/46 E0/47 E0/48 + G0/1 G0/2 + diff --git a/src/pmdas/cisco/cisco.c b/src/pmdas/cisco/cisco.c new file mode 100644 index 0000000..f303480 --- /dev/null +++ b/src/pmdas/cisco/cisco.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 1995-2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <ctype.h> +#include <signal.h> +#include "cisco.h" +#if defined(HAVE_SYS_RESOURCE_H) +#include <sys/resource.h> +#endif +#if defined(HAVE_SYS_WAIT_H) +#include <sys/wait.h> +#endif +#if defined(HAVE_PTHREAD_H) +#include <pthread.h> +#endif +#if defined(HAVE_PRCTL_H) +#include <sys/prctl.h> +#endif + +extern int refreshdelay; + +#ifdef HAVE_SPROC +static pid_t sproc_pid = 0; +#elif defined (HAVE_PTHREAD_H) +#include <pthread.h> +static pthread_t sproc_pid; +#else +#error "Need sproc or pthreads here!" +#endif + +/* + * all metrics supported in this PMD - one table entry for each + */ +static pmdaMetric metrictab[] = { + /* 0,0 ... for direct map, sigh */ + { NULL, { PMDA_PMID(0,0), 0, 0, 0, PMDA_PMUNITS(0,0,0,0,0,0) } }, + /* bytes-in */ + { NULL, { PMDA_PMID(0,1), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + /* bytes-out */ + { NULL, { PMDA_PMID(0,2), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + /* rate-in */ + { NULL, { PMDA_PMID(0,3), PM_TYPE_U32, CISCO_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, + /* rate-out */ + { NULL, { PMDA_PMID(0,4), PM_TYPE_U32, CISCO_INDOM, PM_SEM_INSTANT, + PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, + /* bandwidth */ + { NULL, { PMDA_PMID(0,5), PM_TYPE_U32, CISCO_INDOM, PM_SEM_DISCRETE, + PMDA_PMUNITS(1,-1,0,PM_SPACE_BYTE,PM_TIME_SEC,0) } }, + /* bytes_out_bcast */ + { NULL, { PMDA_PMID(0,6), PM_TYPE_U64, CISCO_INDOM, PM_SEM_COUNTER, + PMDA_PMUNITS(1,0,0,PM_SPACE_BYTE,0,0) } }, + + }; + +/* filled in from command line args in main() ... */ +pmdaIndom indomtab[] = { + { 0, 0, 0 }, +}; + +#ifdef HAVE_SPROC +static RETSIGTYPE +onhup(int s) +{ + signal(SIGHUP, onhup); + exit(0); +} +#endif + +/* + * the sproc starts here to refresh the metric values periodically + */ +void +refresh(void *dummy) +{ + int i; + +#ifdef HAVE_SPROC +#if HAVE_PRCTL + signal(SIGHUP, onhup); +#if HAVE_PR_TERMCHILD + prctl(PR_TERMCHILD); /* SIGHUP when the parent dies */ +#elif HAVE_PR_SET_PDEATHSIG + prctl(PR_SET_PDEATHSIG, SIGHUP); +#endif +#endif +#endif + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "Starting sproc ...\n"); + for (i = 0; i < n_cisco; i++) { + int j; + + fprintf(stderr, "cisco[%d] host: %s username: %s passwd: %s prompt: %s intf:", + i, cisco[i].host, cisco[i].username, cisco[i].passwd, cisco[i].prompt); + + for (j = 0; j < n_intf; j++) { + if (intf[j].cp == (cisco+i)) + fprintf(stderr, " %d-%s", j, intf[j].interface); + } + fputc('\n', stderr); + } + } +#endif + + for ( ; ; ) { + for (i = 0; i < n_intf; i++) { + if (grab_cisco(intf+i) != -1) { + intf[i].fetched = 1; + } + else + intf[i].fetched = 0; + } + + if (parse_only) + exit(0); + + for (i = 0; i < n_cisco; i++) { + if (cisco[i].fout != NULL) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "... %s voluntary disconnect fout=%d\n", cisco[i].host, fileno(cisco[i].fout)); +#endif + /* close CISCO telnet session */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: exit\n"); + } +#endif + fprintf(cisco[i].fout, "exit\n"); + fclose(cisco[i].fout); + cisco[i].fout = NULL; + } + if (cisco[i].fin != NULL) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "... %s close fin=%d\n", cisco[i].host, fileno(cisco[i].fin)); +#endif + fclose(cisco[i].fin); + cisco[i].fin = NULL; + } + } + + sleep(refreshdelay); + } +} + +static int +cisco_fetchCallBack(pmdaMetric *mdesc, unsigned int inst, pmAtomValue *avp) +{ + __pmID_int *idp = (__pmID_int *)&(mdesc->m_desc.pmid); + +#ifndef HAVE_SPROC + /* Check is refresh thread is still with us */ + int err; + + if ( (err = pthread_kill (sproc_pid, 0)) != 0 ) { + exit (1); + } +#endif + + if (!intf[inst].fetched) + return PM_ERR_AGAIN; + + switch (idp->item) { + + case 1: /* bytes_in */ + if (intf[inst].bytes_in == -1) return 0; + avp->ull = intf[inst].bytes_in; + break; + + case 2: /* bytes_out */ + if (intf[inst].bytes_out == -1) return 0; + avp->ull = intf[inst].bytes_out; + break; + + case 3: /* rate_in */ + if (intf[inst].rate_in == -1) return 0; + avp->ul = intf[inst].rate_in; + break; + + case 4: /* rate_out */ + if (intf[inst].rate_out == -1) return 0; + avp->ul = intf[inst].rate_out; + break; + + case 5: /* bandwidth */ + if (intf[inst].bandwidth == -1) return 0; + avp->ul = intf[inst].bandwidth; + break; + + case 6: /* bytes_out_bcast */ + if (intf[inst].bytes_out_bcast == -1) return 0; + avp->ull = intf[inst].bytes_out_bcast; + break; + + default: + return PM_ERR_PMID; + } + + return 1; +} + +void +cisco_init(pmdaInterface *dp) +{ + int i; + + pmdaSetFetchCallBack(dp, cisco_fetchCallBack); + + pmdaInit(dp, indomtab, sizeof(indomtab)/sizeof(indomtab[0]), metrictab, + sizeof(metrictab)/sizeof(metrictab[0])); + + for (i = 0; i < n_intf; i++) + intf[i].fetched = 0; + + /* start the sproc for async fetches */ +#ifdef HAVE_SPROC + i = sproc_pid = sproc(refresh, PR_SADDR); +#elif defined (HAVE_PTHREAD_H) + i = pthread_create(&sproc_pid, NULL, (void (*))refresh, NULL); +#else +#error "Need sproc or pthread here!" +#endif + + if (i < 0) + dp->status = i; + else + dp->status = 0; +} + +void +cisco_done(void) +{ + int i; + + if (sproc_pid > 0) { +#ifndef HAVE_SPROC + pthread_kill(sproc_pid, SIGHUP); +#else + kill(sproc_pid, SIGHUP); +#endif + while (wait(&i) >= 0) + ; + } +} + diff --git a/src/pmdas/cisco/cisco.h b/src/pmdas/cisco/cisco.h new file mode 100644 index 0000000..acf14bc --- /dev/null +++ b/src/pmdas/cisco/cisco.h @@ -0,0 +1,86 @@ +/* + * Instance Domain Data Structures, suitable for a PMDA + * + * Copyright (c) 2012-2014 Red Hat. + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _CISCO_H +#define _CISCO_H + +#include "pmapi.h" +#include "impl.h" +#include "pmda.h" +#include "domain.h" + +typedef struct { + char *host; /* CISCO hostname */ + __pmHostEnt *hostinfo; /* Address info for 'host' */ + int port; /* port */ + char *username; /* username */ + char *passwd; /* password */ + char *prompt; /* command prompt */ + FILE *fout; /* write cmds here */ + FILE *fin; /* read output here */ +} cisco_t; + +typedef struct { + + cisco_t *cp; /* which CISCO? */ + char *interface; /* interface name, e.g. s0 or e10/10 */ + int fetched; /* valid stats? */ + __uint32_t bandwidth; /* peak bandwidth */ + __uint32_t rate_in; + __uint32_t rate_out; + __uint64_t bytes_in; /* stats */ + __uint64_t bytes_out; + __uint64_t bytes_out_bcast; +} intf_t; + +extern cisco_t *cisco; +extern int n_cisco; +extern intf_t *intf; +extern int n_intf; + +/* + * Supported Cisco Interfaces + */ +typedef struct { + char *type; /* NULL to skip, else unique per interface + * type */ + char *name; /* full name as per "show" */ +} intf_tab_t; + +extern intf_tab_t intf_tab[]; +extern int num_intf_tab; + +#define CISCO_INDOM 0 +extern pmdaIndom indomtab[]; +extern pmdaInstid *_router; + +#define PWPROMPT "Password:" +#define USERPROMPT "Username:" + +extern int conn_cisco(cisco_t *); +extern int grab_cisco(intf_t *); +extern int dousername(cisco_t *, char **); +extern int dopasswd(cisco_t *, char *); +extern char *mygetwd(FILE *, char *); + +extern int parse_only; + +#endif /* _CISCO_H */ diff --git a/src/pmdas/cisco/cisco.in_util.pmie b/src/pmdas/cisco/cisco.in_util.pmie new file mode 100644 index 0000000..75ecd08 --- /dev/null +++ b/src/pmdas/cisco/cisco.in_util.pmie @@ -0,0 +1,64 @@ +#pmieconf-rules 1 +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) + +rule cisco.in_util + summary = "$rule$" + enumerate = hosts + predicate = +"some_inst ( + 100 * cisco.rate_in $hosts$ / cisco.bandwidth $hosts$ + > $threshold$ +)" + enabled = no + version = 1 + help = +"Some Cisco router interface exceeded threshold percent of its +peak bandwidth receiving data during the last sample interval. +Use the command: + $ pminfo -f cisco.bandwidth +to discover the list of Cisco router interfaces currently being +monitored by the Cisco PMDA - pmdacisco(1)."; + +string rule + default = "Cisco router inbound bandwidth saturation" + modify = no + display = no; + +percent threshold + default = 90 + help = +"Threshold percentage for Cisco router saturation, in the range 0 +(idle) to 100 (operating at peak bandwidth)"; + +string action_expand + default = %v%util[%i]@%h + display = no + modify = no; + +string email_expand + default = "host: %h Cisco router: %i inbound utilization: %v%" + display = no + modify = no; + + +# Configuration info specific to non-PCP tools follows... +# + +# for SGI Embedded Support Partner integration: +string esp_type + default = "0x200093" + display = no + modify = no; + +# for EnlightenDSM integration: +string enln_test + default = cisco.in_util + display = no + modify = no; +string enln_units + default = %util[%i] + display = no + modify = no; + +# +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) diff --git a/src/pmdas/cisco/cisco.out_util.pmie b/src/pmdas/cisco/cisco.out_util.pmie new file mode 100644 index 0000000..e003f59 --- /dev/null +++ b/src/pmdas/cisco/cisco.out_util.pmie @@ -0,0 +1,64 @@ +#pmieconf-rules 1 +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) + +rule cisco.out_util + summary = "$rule$" + enumerate = hosts + predicate = +"some_inst ( + 100 * cisco.rate_out $hosts$ / cisco.bandwidth $hosts$ + > $threshold$ +)" + enabled = no + version = 1 + help = +"Some Cisco router interface exceeded threshold percent of its +peak bandwidth sending data during the last sample interval. +Use the command: + $ pminfo -f cisco.bandwidth +to discover the list of Cisco router interfaces currently being +monitored by the Cisco PMDA - pmdacisco(1)."; + +string rule + default = "Cisco router outbound bandwidth saturation" + modify = no + display = no; + +percent threshold + default = 90 + help = +"Threshold percentage for Cisco router saturation, in the range 0 +(idle) to 100 (operating at peak bandwidth)"; + +string action_expand + default = %v%util[%i]@%h + display = no + modify = no; + +string email_expand + default = "host: %h Cisco router: %i outbound utilization: %v%" + display = no + modify = no; + + +# Configuration info specific to non-PCP tools follows... +# + +# for SGI Embedded Support Partner integration: +string esp_type + default = "0x200094" + display = no + modify = no; + +# for EnlightenDSM integration: +string enln_test + default = cisco.out_util + display = no + modify = no; +string enln_units + default = %util[%i] + display = no + modify = no; + +# +# --- DO NOT MODIFY THIS FILE --- see pmieconf(4) diff --git a/src/pmdas/cisco/help b/src/pmdas/cisco/help new file mode 100644 index 0000000..eeb8c5f --- /dev/null +++ b/src/pmdas/cisco/help @@ -0,0 +1,76 @@ +# +# Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# cisco PMDA help file in the ASCII format +# +# lines beginning with a # are ignored +# lines beginning @ introduce a new entry of the form +# @ metric-name oneline-text +# help test goes +# here over multiple lines +# ... +# +# the metric-name is decoded against the default PMNS -- as a special case, +# a name of the form NNN.MM (for numeric NNN and MM) is interpreted as an +# instance domain identification, and the text describes the instance domain +# +# blank lines before the @ line are ignored +# + +@ CISCO.1 Interfaces on Cisco router +There is one instance in this domain for each interface on a Cisco router +that the Cisco PMDA (Performance Metrics Domain Agent) has been told about +when the PMDA is started. + +The names of the instances are of the form hostname:tX where "t" is one of +"a" for ATM, "B" for ISDN BRI, "e" for Ethernet, "E" (FastEthernet), "f" for +Fddi, "h" for HSSC, "s" for Serial or "Vl" for Vlan. The "X" is the +interface identifier which is either an integer (e.g. 4000 Series routers) or +two integers separated by a slash (e.g. 7000 Series routers) or three +integers separated by a slash and a period (Frame-Relay PVCs on serial line +subinterfaces). + +@ cisco.bytes_in Total Kbytes input to the Cisco +Total number of Kbytes input to the Cisco on this interface. + +Note that due to network delays in extracting the metrics from the +Cisco routers, any rate computed from this metric over small deltas in time +are likely to be subject to wide variance. + +@ cisco.bytes_out Total Kbytes output from the Cisco +Total number of Kbytes output from the Cisco on this interface. + +Note that due to network delays in extracting the metrics from the +Cisco routers, any rate computed from this metric over small deltas in time +are likely to be subject to wide variance. + +@ cisco.bytes_out_bcast Total broadcast Kbytes output from the Cisco +Total number of broadcast Kbytes output from the Cisco on this interface. + +Note that due to network delays in extracting the metrics from the +Cisco routers, any rate computed from this metric over small deltas in +time are likely to be subject to wide variance. + +@ cisco.rate_in 5 minutes average input rate in bytes (not bits!) per second +Cisco's computed average input rate in bytes per second, over the recent +past, for this interface. + +@ cisco.rate_out 5 minutes average output rate in bytes (not bits!) per second +Cisco's computed average output rate in bytes per second, over the recent +past, for this interface. + +@ cisco.bandwidth peak interface bandwidth in bytes per second diff --git a/src/pmdas/cisco/interface.c b/src/pmdas/cisco/interface.c new file mode 100644 index 0000000..022c8ac --- /dev/null +++ b/src/pmdas/cisco/interface.c @@ -0,0 +1,46 @@ +/* + * Known Cisco Interfaces + * + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "./cisco.h" + +/* + * first letter defines command line argument for interface type + * (0 means not allowed in command line) + * full name of interface is as found in "show interface" command + * output. + */ + +intf_tab_t intf_tab[] = { + { "s", "Serial" }, + { "e", "Ethernet" }, + { "E", "FastEthernet" }, + { "f", "Fddi" }, + { "h", "Hssi" }, + { "a", "ATM" }, + { "B", "BRI" }, + { "Vl", "Vlan" }, + { "G", "GigabitEthernet" }, + { NULL, "Controller" }, + { NULL, "Port-channel" }, + { NULL, "Dialer" }, + { NULL, "Loopback" }, +}; + +int num_intf_tab = sizeof(intf_tab) / sizeof(intf_tab[0]); diff --git a/src/pmdas/cisco/parse.sh b/src/pmdas/cisco/parse.sh new file mode 100755 index 0000000..c35a27c --- /dev/null +++ b/src/pmdas/cisco/parse.sh @@ -0,0 +1,3 @@ +#!/bin/sh +. $PCP_DIR/etc/pcp.env +exec $PCP_PMDAS_DIR/cisco/pmdacisco -n parse -C $@ diff --git a/src/pmdas/cisco/pmda.c b/src/pmdas/cisco/pmda.c new file mode 100644 index 0000000..d78190c --- /dev/null +++ b/src/pmdas/cisco/pmda.c @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2012,2014 Red Hat. + * Copyright (c) 1995-2002 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/* + * Cisco PMDA, based on generic driver for a daemon-based PMDA + * - cisco interfaces to monitor are named in the command line as + * hostname:tX[@username] + * hostname:tX[?passwd] + * hostname:tX[@username?passwd] + * hostname:tX[!prompt] + * hostname:tX[@username!prompt] + * hostname:tX[?passwd!prompt] + * hostname:tX[@username?passwd!prompt] + * + * where t identifies an interface type as defined by intf_tab[] in + * interface.c + * and X is either the ordinal i/f number (base 0, for Series 4000) + * or the card/port number (Series 7000 routers) + * e.g sydcisco.sydney:s0 (Frame-Relay to Mtn View) + * sydcisco.sydney:s1 (ISDN to Melbourne) + * cisco.melbourne:s0 (ISDN to Sydney) + * b8u-cisco1-e15.corp:e0 (Ethernet in Bldg 8 upper) + * b9u-cisco1-81.engr.sgi.com:f2/0 + * wanbris.brisbane:B0 (BRI ISDN) + * If specified the username (after the @ delimiter) and/or the + * user-level password (after the ? delimiter) and/or the prompt (after + * the ! delimiter) over-rides the global username and/or user-level + * password and/or prompt, as specified via -U and/or -P and/or -s + * options and applies for all occurrences of the hostname. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <sys/un.h> +#include <netdb.h> +#include <string.h> +#include "./cisco.h" + +pmdaInstid *_router; +cisco_t *cisco; +int n_cisco; +intf_t *intf; +int n_intf; +int refreshdelay = 120; /* default poll every two minutes */ +char *pmdausername; /* username for the pmda */ +char *username; /* username */ +char *passwd; /* user-level password */ +char *prompt = ">"; /* command prompt */ +int port = 23; +int parse_only; +int no_lookups; + +extern void cisco_init(pmdaInterface *); +extern void cisco_done(void); + +int +main(int argc, char **argv) +{ + int err = 0; + int sep = __pmPathSeparator(); + char *endnum; + pmdaInterface dispatch; + int n; + int i; + int c; + char helptext[MAXPATHLEN]; + + __pmSetProgname(argv[0]); + __pmGetUsername(&pmdausername); + + snprintf(helptext, sizeof(helptext), "%s%c" "cisco" "%c" "help", + pmGetConfig("PCP_PMDAS_DIR"), sep, sep); + pmdaDaemon(&dispatch, PMDA_INTERFACE_3, pmProgname, CISCO, + "cisco.log", helptext); + + while ((c = pmdaGetOpt(argc, argv, "D:d:h:i:l:pu:6:" "CM:Nn:P:r:s:U:x:?", + &dispatch, &err)) != EOF) { + switch (c) { + + case 'C': /* parser checking mode (debugging) */ + pmDebug = DBG_TRACE_APPL0; + parse_only++; + break; + + case 'N': /* do not perform name lookups (debugging) */ + no_lookups = 1; + break; + + case 'n': /* set program name, for parse (debugging) */ + pmProgname = optarg; + break; + + case 'P': /* passwd */ + passwd = optarg; + break; + + case 'r': + refreshdelay = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -r requires numeric (number of seconds) argument\n", + pmProgname); + err++; + } + break; + + case 's': /* command prompt */ + prompt = optarg; + break; + + case 'M': /* username (for the PMDA) */ + pmdausername = optarg; + break; + + case 'U': /* username (for the Cisco) */ + username = optarg; + break; + + case 'x': + port = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -x requires numeric argument\n", + pmProgname); + err++; + } + break; + + case '?': + err++; + } + } + + n_intf = argc - optind; + if (n_intf == 0 || err) { + fprintf(stderr, + "Usage: %s [options] host:{a|B|E|e|f|h|s}N[/M[.I]] [...]\n\n", + pmProgname); + fputs("Options:\n" + " -d domain use domain (numeric) for metrics domain of PMDA\n" + " -i port expect PMCD to connect on given inet port (number or name)\n" + " -l logfile redirect diagnostics and trace output to logfile\n" + " -M username user account to run PMDA under (default \"pcp\")\n" + " -p expect PMCD to supply stdin/stdout (pipe)\n" + " -P password default user-level Cisco password\n" + " -r refresh update metrics every refresh seconds\n" + " -s prompt Cisco command prompt [default >]\n" + " -u socket expect PMCD to connect on given unix domain socket\n" + " -U username Cisco username\n" + " -x port telnet port [default 23]\n" + " -6 port expect PMCD to connect on given ipv6 port (number or name)\n", + stderr); + exit(1); + } + + /* force errors from here on into the log */ + if (!parse_only) { + pmdaOpenLog(&dispatch); + __pmSetProcessIdentity(pmdausername); + } else { + dispatch.version.two.text = NULL; + dispatch.version.two.ext->e_helptext = NULL; + } + + /* + * build the instance domain and cisco data structures from the + * command line arguments. + */ + if ((_router = (pmdaInstid *)malloc(n_intf * sizeof(pmdaInstid))) == NULL) { + __pmNoMem("main.router", n_intf * sizeof(pmdaInstid), PM_FATAL_ERR); + } + if ((intf = (intf_t *)malloc(n_intf * sizeof(intf_t))) == NULL) { + __pmNoMem("main.intf", n_intf * sizeof(intf_t), PM_FATAL_ERR); + } + /* pre-allocated cisco[] to avoid realloc and ptr movement */ + if ((cisco = (cisco_t *)malloc(n_intf * sizeof(cisco_t))) == NULL) { + __pmNoMem("main.cisco", n_intf * sizeof(cisco_t), PM_FATAL_ERR); + } + + indomtab[CISCO_INDOM].it_numinst = n_intf; + indomtab[CISCO_INDOM].it_set = _router; + + for (n = 0 ; optind < argc; optind++, n++) { + char *p = strdup(argv[optind]); + char *q; + char *myusername; + char *mypasswd; + char *myprompt; + + myprompt = strchr(p, '!'); + if (myprompt) { + /* save prompt for later */ + *myprompt++ = '\0'; + } + else + myprompt = NULL; + mypasswd = strchr(p, '?'); + if (mypasswd) { + /* save user-level password for later */ + *mypasswd++ = '\0'; + } + else + mypasswd = passwd; + myusername = strchr(p, '@'); + if (myusername) { + /* save username for later */ + *myusername++ = '\0'; + } + else + myusername = username; + + _router[n].i_inst = n; + _router[n].i_name = strdup(p); + + if ((q = strchr(p, ':')) == NULL) + goto badintfspec; + *q++ = '\0'; + for (i = 0; i < num_intf_tab; i++) { + if (strncmp(q, intf_tab[i].type, strlen(intf_tab[i].type)) == 0) + break; + } + if (i == num_intf_tab) + goto badintfspec; + if (strcmp(intf_tab[i].type, "E") == 0) { + /* + * Cisco parser is case insensitive, so 'E' means "Ethernet" + * and 'F' means "Fddi", need to use "FastEthernet" here + */ + q++; + intf[n].interface = (char *)malloc(strlen("FastEthernet")+strlen(q)+1); + if ((intf[n].interface = (char *)malloc(strlen("FastEthernet")+strlen(q)+1)) == NULL) { + __pmNoMem("main.cisco", strlen("FastEthernet")+strlen(q)+1, PM_FATAL_ERR); + } + strcpy(intf[n].interface, "FastEthernet"); + strcat(intf[n].interface, q); + } + else + intf[n].interface = q; + + for (i = 0; i < n_cisco; i++) { + if (strcmp(p, cisco[i].host) == 0) + break; + } + if (i == n_cisco) { + __pmHostEnt *hostInfo = NULL; + + if (!no_lookups) + hostInfo = __pmGetAddrInfo(p); + + if (!hostInfo && parse_only) { + FILE *f; + + /* + * for debugging, "host" may be a file ... + */ + if ((f = fopen(p, "r")) == NULL) { + fprintf(stderr, "%s: unknown hostname or filename %s: %s\n", + pmProgname, argv[optind], hoststrerror()); + /* abandon this host (cisco) */ + continue; + } + else { + fprintf(stderr, "%s: assuming file %s contains output from \"show int\" command\n", + pmProgname, p); + + cisco[i].host = p; + cisco[i].username = myusername != NULL ? myusername : username; + cisco[i].passwd = mypasswd != NULL ? mypasswd : passwd; + cisco[i].prompt = myprompt != NULL ? myprompt : prompt; + cisco[i].fin = f; + cisco[i].fout = stdout; + n_cisco++; + } + } else if (!hostInfo) { + fprintf(stderr, "%s: unknown hostname %s: %s\n", + pmProgname, p, hoststrerror()); + /* abandon this host (cisco) */ + continue; + } else { + cisco[i].host = p; + cisco[i].username = myusername != NULL ? myusername : username; + cisco[i].passwd = mypasswd != NULL ? mypasswd : passwd; + cisco[i].prompt = myprompt != NULL ? myprompt : prompt; + cisco[i].fin = NULL; + cisco[i].fout = NULL; + cisco[i].hostinfo = hostInfo; + cisco[i].port = port; + + n_cisco++; + fprintf(stderr, "Adding new host %s\n", p); + fflush(stderr); + } + } + else { + if (cisco[i].username == NULL) { + if (myusername != NULL) + /* username on 2nd or later interface ... applies to all */ + cisco[i].username = myusername; + } + else { + if (myusername != NULL) { + if (strcmp(cisco[i].username, myusername) != 0) { + fprintf(stderr, + "%s: conflicting usernames (\"%s\" " + "and \"%s\") for cisco \"%s\"\n", + pmProgname, cisco[i].username, myusername, + cisco[i].host); + exit(1); + } + } + } + if (cisco[i].passwd == NULL) { + if (mypasswd != NULL) + /* passwd on 2nd or later interface ... applies to all */ + cisco[i].passwd = mypasswd; + } + else { + if (mypasswd != NULL) { + if (strcmp(cisco[i].passwd, mypasswd) != 0) { + fprintf(stderr, + "%s: conflicting user-level passwords (\"%s\" " + "and \"%s\") for cisco \"%s\"\n", + pmProgname, cisco[i].passwd, mypasswd, + cisco[i].host); + exit(1); + } + } + } + if (cisco[i].prompt == NULL) { + if (myprompt != NULL) + /* prompt on 2nd or later interface ... applies to all */ + cisco[i].prompt = myprompt; + } + else { + if (myprompt != NULL) { + if (strcmp(cisco[i].prompt, myprompt) != 0) { + fprintf(stderr, + "%s: conflicting user-level prompts (\"%s\" " + "and \"%s\") for cisco \"%s\"\n", + pmProgname, cisco[i].prompt, myprompt, + cisco[i].host); + exit(1); + } + } + } + } + + intf[n].cp = cisco+i; + /* + * special one-trip initialization for Frame-Relay over serial + * lines ... see grab_cisco() + */ + intf[n].bandwidth = -2; + + fprintf(stderr, "Interface %s(%d) is on host %s\n", + intf[n].interface, n, cisco[i].host); + fflush(stderr); + + continue; + +badintfspec: + fprintf(stderr, "%s: bad interface specification \"%s\"\n", pmProgname, argv[optind]); + fprintf(stderr, " should be like sydcisco.sydney:s1 or b9u-cisco1-81.engr.sgi.com:f2/0\n"); + fprintf(stderr, " or cisco.melbourne:e0?secret\n"); + exit(1); + } + + if (n_cisco == 0) { + fprintf(stderr, "%s: Nothing to monitor\n", pmProgname); + exit(1); + } + + if (parse_only) { + fprintf(stderr, "Sleeping while sproc does the work ... SIGINT to terminate\n"); + cisco_init(&dispatch); + for (i = 0; i < n_intf; i++) + intf[i].fetched = 0; + pause(); + } else { + /* set up connection to PMCD */ + cisco_init(&dispatch); + pmdaConnect(&dispatch); + pmdaMain(&dispatch); + } + + cisco_done(); + exit(0); +} diff --git a/src/pmdas/cisco/pmns b/src/pmdas/cisco/pmns new file mode 100644 index 0000000..fc1ce50 --- /dev/null +++ b/src/pmdas/cisco/pmns @@ -0,0 +1,28 @@ +/* + * Metrics for cisco PMDA + * + * Copyright (c) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +cisco { + bandwidth CISCO:0:5 + bytes_in CISCO:0:1 + bytes_out CISCO:0:2 + bytes_out_bcast CISCO:0:6 + rate_in CISCO:0:3 + rate_out CISCO:0:4 +} diff --git a/src/pmdas/cisco/probe.c b/src/pmdas/cisco/probe.c new file mode 100644 index 0000000..5cd5b4d --- /dev/null +++ b/src/pmdas/cisco/probe.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2012 Red Hat. + * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <netdb.h> +#include <fcntl.h> +#include <syslog.h> +#include "./cisco.h" + +int port = 23; +int seen_fr = 0; +char *prompt = ">"; /* unique suffix to IOS prompt */ + +char * +mygetfirstwd(FILE *f) +{ + char *p; + int c; + char line[1024]; + char *lp; + + for ( ; ; ) { + c = fgetc(f); + if (c == EOF) + break; + if (c == '\r' || c == '\n') + continue; + if (c != ' ') { + ungetc(c, f); + break; + } + lp = line; + while ((c = fgetc(f)) != EOF) { + *lp++ = c; + if (c == '\r' || c == '\n') { + *lp = '\0'; + break; + } + } + /* + * some interesting things to look for here ... + */ + if (strncmp(&line[1], "Encapsulation FRAME-RELAY", strlen("Encapsulation FRAME-RELAY")) == 0) { + seen_fr = 1; + } + } + /* either EOF, or line starts with a non-space */ + + p = mygetwd(f, prompt); + + if (p != NULL && (strlen(p) < strlen(prompt) || + strcmp(&p[strlen(p)-strlen(prompt)], prompt)) != 0) { + /* skip to end of line, ready for next one */ + while ((c = fgetc(f)) != EOF) { + if (c == '\r' || c == '\n') + break; + } + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "mygetfirstwd: %s\n", p == NULL ? "<NULL>" : p); +#endif + + return p; +} + +#define PREAMBLE 1 +#define IN_BODY 2 + +static void +probe_cisco(cisco_t * cp) +{ + char *w; + int fd; + int fd2; + int first = 1; + char *pass = NULL; + int defer = 0; + int state = PREAMBLE; + int i; + int namelen; + char *ctype = NULL; + char *name = NULL; + + if (cp->fin == NULL) { + fd = conn_cisco(cp); + if (fd == -1) { + fprintf(stderr, "grab_cisco(%s): connect failed: %s\n", + cp->host, osstrerror()); + return; + } + else { + cp->fin = fdopen (fd, "r"); + if ((fd2 = dup(fd)) < 0) { + perror("dup"); + exit(1); + } + cp->fout = fdopen (fd2, "w"); + if (cp->username != NULL) { + /* + * Username stuff ... + */ + if (dousername(cp, &pass) == 0) { + exit(1); + } + } + if (cp->passwd != NULL) { + /* + * User-level password stuff ... + */ + if (dopasswd(cp, pass) == 0) { + exit(1); + } + } + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: \n"); + fprintf(stderr, "Send: terminal length 0\n"); + } +#endif + fprintf(cp->fout, "\n"); + fflush(cp->fout); + fprintf(cp->fout, "terminal length 0\n"); + fflush(cp->fout); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: show int\n"); + } +#endif + fprintf(cp->fout, "show int\n"); + fflush(cp->fout); + + } + else { + /* + * parsing text from a file, not a TCP/IP connection to a + * Cisco device + */ + ; + } + + for ( ; ; ) { + w = mygetfirstwd(cp->fin); + if (defer && ctype != NULL && name != NULL) { + if (seen_fr) { + if (first) + first = 0; + else + putchar(' '); + printf("%s%s", ctype, name); + free(name); + name = NULL; + } + } + defer = 0; + if (w == NULL) { + /* + * End of File (telenet timeout?) + */ + fprintf(stderr, "grab_cisco(%s): forced disconnect fin=%d\n", + cp->host, fileno(cp->fin)); + return; + } + if (*w == '\0') + continue; + if (state == PREAMBLE) { + if (strcmp(w, "show") == 0) + state = IN_BODY; + else if (strcmp(w, PWPROMPT) == 0) { + fprintf(stderr, + "Error: user-level password required for \"%s\"\n", + cp->host); + exit(1); + } + continue; + } + else { + if (strlen(w) >= strlen(prompt) && + strcmp(&w[strlen(w)-strlen(prompt)], prompt) == 0) + break; + ctype = NULL; + for (i = 0; i < num_intf_tab; i++) { + namelen = strlen(intf_tab[i].name); + if (strncmp(w, intf_tab[i].name, namelen) == 0) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "Match: if=%s word=%s\n", intf_tab[i].name, w); + } +#endif + name = strdup(&w[namelen]); + ctype = intf_tab[i].type; + if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "a") == 0) { + /* + * skip ATMN.M ... need ATMN + */ + if (strchr(&w[namelen], '.') != NULL) + ctype = NULL; + } + else if (intf_tab[i].type != NULL && strcmp(intf_tab[i].type, "s") == 0) { + /* + * skip SerialN.M ... need SerialN, unless frame-relay + */ + if (strchr(&w[namelen], '.') != NULL) + defer = 1; + } + break; + } + } + if (i == num_intf_tab) + fprintf(stderr, "%s: Warning, unknown interface: %s\n", pmProgname, w); + if (ctype != NULL && name != NULL && !defer) { + if (first) + first = 0; + else + putchar(' '); + printf("%s%s", ctype, name); + free(name); + name = NULL; + } + } + } + putchar('\n'); + + /* close CISCO telnet session */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: exit\n"); + } +#endif + fprintf(cp->fout, "exit\n"); + fflush(cp->fout); + + return; +} + +int +main(int argc, char **argv) +{ + int errflag = 0; + int Nflag = 0; + int c; + int sts; + char *endnum; + char *passwd = NULL; + char *username = NULL; + __pmHostEnt *hostInfo = NULL; + + __pmSetProgname(argv[0]); + + while ((c = getopt(argc, argv, "ND:P:s:U:x:?")) != EOF) { + switch (c) { + + case 'N': /* check flag */ + Nflag = 1; + break; + + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; + + case 'P': /* passwd */ + passwd = optarg; + break; + + case 's': /* prompt */ + prompt = optarg; + break; + + case 'U': /* username */ + username = optarg; + break; + + case 'x': + port = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0') { + fprintf(stderr, "%s: -x requires numeric argument\n", + pmProgname); + errflag++; + } + break; + + case '?': + errflag++; + } + } + + if (errflag || optind != argc-1) { + fprintf(stderr, "Usage: %s [-U username] [-P passwd] [-s prompt] [-x port] host\n\n", pmProgname); + exit(1); + } + + if (!Nflag) + hostInfo = __pmGetAddrInfo(argv[optind]); + + if (hostInfo == NULL) { + FILE *f; + + if ((f = fopen(argv[optind], "r")) == NULL) { + fprintf(stderr, "%s: unknown hostname or filename %s: %s\n", + pmProgname, argv[optind], hoststrerror()); + exit(1); + } + else { + cisco_t c; + + fprintf(stderr, "%s: assuming file %s contains output from \"show int\" command\n", + pmProgname, argv[optind]); + + c.host = argv[optind]; + c.username = NULL; + c.passwd = NULL; + c.fin = f; + c.fout = fopen("/dev/null", "w"); + c.prompt = prompt; + + probe_cisco(&c); + } + } else { + cisco_t c; + + c.host = argv[optind]; + c.username = username; + c.passwd = passwd; + c.fin = NULL; + c.fout = NULL; + c.prompt = prompt; + c.hostinfo = hostInfo; + c.port = 23; /* telnet */ + + probe_cisco(&c); + } + + exit(0); +} diff --git a/src/pmdas/cisco/root b/src/pmdas/cisco/root new file mode 100644 index 0000000..e0c1b81 --- /dev/null +++ b/src/pmdas/cisco/root @@ -0,0 +1,10 @@ +/* + * fake "root" for validating the local PMNS subtree + */ + +#include <stdpmid> + +root { cisco } + +#include "pmns" + diff --git a/src/pmdas/cisco/telnet.c b/src/pmdas/cisco/telnet.c new file mode 100644 index 0000000..bcee1db --- /dev/null +++ b/src/pmdas/cisco/telnet.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2012 Red Hat. + * Copyright (c) 1995-2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <syslog.h> +#include "./cisco.h" + +extern int port; + +int +conn_cisco(cisco_t * cp) +{ + __pmFdSet wfds; + __pmSockAddr *myaddr; + void *enumIx; + int flags = 0; + int fd; + int ret; + + fd = -1; + enumIx = NULL; + for (myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx); + myaddr != NULL; + myaddr = __pmHostEntGetSockAddr(cp->hostinfo, &enumIx)) { + /* Create a socket */ + if (__pmSockAddrIsInet(myaddr)) + fd = __pmCreateSocket(); + else if (__pmSockAddrIsIPv6(myaddr)) + fd = __pmCreateIPv6Socket(); + else + continue; + if (fd < 0) { + __pmSockAddrFree(myaddr); + continue; /* Try the next address */ + } + + /* Attempt to connect */ + flags = __pmConnectTo(fd, myaddr, cp->port); + __pmSockAddrFree(myaddr); + + if (flags < 0) { + /* + * Mark failure in case we fall out the end of the loop + * and try next address. fd has been closed in __pmConnectTo(). + */ + setoserror(ECONNREFUSED); + fd = -1; + continue; + } + + /* FNDELAY and we're in progress - wait on select */ + __pmFD_ZERO(&wfds); + __pmFD_SET(fd, &wfds); + ret = __pmSelectWrite(fd+1, &wfds, NULL); + + /* Was the connection successful? */ + if (ret == 0) + setoserror(ETIMEDOUT); + else if (ret > 0) { + ret = __pmConnectCheckError(fd); + if (ret == 0) + break; + setoserror(ret); + } + + /* Unsuccessful connection. */ + __pmCloseSocket(fd); + fd = -1; + } /* loop over addresses */ + + if (fd == -1) { + fprintf(stderr, "conn_cisco(%s): connect: %s\n", + cp->host, netstrerror()); + return -1; + } + + fd = __pmConnectRestoreFlags(fd, flags); + if (fd < 0) { + fprintf(stderr, "conn_cisco(%s): setsockopt: %s\n", + cp->host, netstrerror()); + return -1; + } + + return fd; +} + +static void +skip2eol(FILE *f) +{ + int c; + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "skip2eol:"); +#endif + + while ((c = fgetc(f)) != EOF) { + if (c == '\n') + break; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "%c", c); +#endif + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fputc('\n', stderr); +#endif +} + +char * +mygetwd(FILE *f, char *prompt) +{ + char *p; + int c; + static char buf[1024]; + int len_prompt = strlen(prompt); + int found_prompt = 0; + + p = buf; + + while ((c = fgetc(f)) != EOF) { + if (c == '\r' || c == '\n' || c == ' ' || c == '\t') { + if (p == buf) + continue; + break; + } + *p++ = c; + if (p-buf >= len_prompt && strncmp(&p[-len_prompt], prompt, len_prompt) == 0) { + found_prompt = 1; + break; + } + } + *p = '\0'; + + if (feof(f)) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "mygetwd: EOF fd=%d\n", fileno(f)); +#endif + return NULL; + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "mygetwd: fd=%d wd=\"%s\"%s\n", fileno(f), buf, found_prompt ? " [prompt]" : ""); +#endif + + return buf; +} + +/* + * The CISCO "show interface" command output is parsed. + * + * See the file Samples for examples. + * + * The parser is a Finite State Automaton (FSA) that follows these + * rules: + * + * SHOW_INT style ... uses "show int <interface>" command + * state token next state + * NOISE <interface name> IN_REPORT + * IN_REPORT Description: skip rest of line, IN_REPORT + * IN_REPORT <prompt> DONE + * IN_REPORT minute RATE + * IN_REPORT second RATE + * IN_REPORT input, BYTES_IN + * IN_REPORT output, BYTES_OUT + * IN_REPORT BW BW + * RATE input skip next token, RATE_IN + * RATE output skip next token, RATE_OUT + * RATE_IN <number> (rate_in) IN_REPORT + * RATE_OUT <number> (rate_out) IN_REPORT + * BYTES_IN <number> (bytes_in) IN_REPORT + * BYTES_OUT <number> (bytes_out) IN_REPORT + * BW <number> (bandwidth) IN_REPORT + * + * SHOW_FRAME style ... uses "show frame pvc int <interface>" command + * state token next state + * NOISE <interface name> IN_REPORT + * IN_REPORT Description: skip rest of line, IN_REPORT + * IN_REPORT <prompt> DONE + * IN_REPORT 1st bytes BYTES_IN + * IN_REPORT 2nd bytes BYTES_OUT + * IN_REPORT 3rd bytes BYTES_OUT_BCAST + * BYTES_IN <number> (bytes_in) IN_REPORT + * BYTES_OUT <number> (bytes_out) IN_REPORT + * BYTES_OUT_BCAST <number> (bytes_out_bcast) IN_REPORT + * + * Note lines are terminated with \r + */ + +#define DONE -1 +#define NOISE 0 +#define IN_REPORT 1 +#define RATE 2 +#define RATE_IN 3 +#define RATE_OUT 4 +#define BYTES_IN 5 +#define BYTES_OUT 6 +#define BW 7 +#define BYTES_OUT_BCAST 8 + +#ifdef PCP_DEBUG +static char *statestr[] = { + "done", "noise", "in_report", + "rate", "rate_in", "rate_out", "bytes_in", "bytes_out", "bw", + "bytes_out_bcast" +}; +#endif + +int +dousername(cisco_t *cp, char **pw_prompt) +{ + char *w; + int len, done = 0; + int len_prompt = strlen(cp->prompt); + + for ( ; ; ) { + w = mygetwd(cp->fin, cp->prompt); + if (w == NULL) + break; + if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) + break; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Username:? got - %s\n", w); +#endif + if (strcmp(w, USERPROMPT) == 0) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send username: %s\n", cp->username); + } +#endif + fprintf(cp->fout, "%s\n", cp->username); + fflush(cp->fout); + for ( ; ; ) { + w = mygetwd(cp->fin, cp->prompt); + if (w == NULL || strcmp(w, USERPROMPT) == 0) + /* closed connection or Username re-prompt */ + break; + len = strlen(w); + if ((len >= len_prompt && strncmp(&w[len-len_prompt], cp->prompt, len_prompt) == 0) || + w[len-1] == ':') { + /* command prompt or passwd */ + if (w[len-1] == ':') + *pw_prompt = w; + done = 1; + break; + } + } + break; + } + } + + if (done == 0) { + fprintf(stderr, "Error: Cisco username negotiation failed for \"%s\"\n", + cp->host); + fprintf(stderr, +"To check that a username is required, enter the following command:\n" +" $ telnet %s\n" +"If the prompt \"%s\" does not appear, no username is required.\n" +"Otherwise, enter the username \"%s\" to check that this\n" +"is correct.\n", +cp->host, USERPROMPT, cp->username); + } + + return done; +} + +int +dopasswd(cisco_t *cp, char *pw_prompt) +{ + char *w; + int done = 0; + int len_prompt = strlen(cp->prompt); + + for ( ; ; ) { + if (pw_prompt) /* dousername may have read passwd prompt */ + w = pw_prompt; + else + w = mygetwd(cp->fin, cp->prompt); + pw_prompt = NULL; + if (w == NULL) + break; + if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) + break; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "Password:? got - %s\n", w); +#endif + if (strcmp(w, PWPROMPT) == 0) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send passwd: %s\n", cp->passwd); + } +#endif + fprintf(cp->fout, "%s\n", cp->passwd); + fflush(cp->fout); + for ( ; ; ) { + w = mygetwd(cp->fin, cp->prompt); + if (w == NULL || strcmp(w, PWPROMPT) == 0) + /* closed connection or user-level password re-prompt */ + break; + if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) { + /* command prompt */ + done = 1; + break; + } + } + break; + } + } + + if (done == 0) { + fprintf(stderr, "Error: Cisco user-level password negotiation failed for \"%s\"\n", + cp->host); + fprintf(stderr, +"To check that a user-level password is required, enter the following command:\n" +" $ telnet %s\n" +"If the prompt \"%s\" does not appear, no user-level password is required.\n" +"Otherwise, enter the user-level password \"%s\" to check that this\n" +"is correct.\n", +cp->host, PWPROMPT, cp->passwd); + } + + return done; +} + +static int timeout; + +void +onalarm(int dummy) +{ + timeout = 1; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "Alarm timeout!\n"); + } +#endif + +} + +static int +get_fr_bw(cisco_t *cp, char *interface) +{ + int state = NOISE; + int bandwidth = -1; + char *w; + int len_prompt = strlen(cp->prompt); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: s%s\n", interface); + } +#endif + fprintf(cp->fout, "show int s%s\n", interface); + fflush(cp->fout); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "BW Parse:"); +#endif + while (state != DONE) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) + fprintf(stderr, "[%s] ", statestr[state+1]); +#endif + w = mygetwd(cp->fin, cp->prompt); + if (w == NULL || timeout) { + /* + * End of File (telenet timeout?) + */ + alarm(0); + return -1; + } + switch (state) { + + case NOISE: + if (strncmp(w, "Serial", 6) == 0 && strcmp(&w[6], interface) == 0) + state = IN_REPORT; + break; + + case IN_REPORT: + if (strcmp(w, "Description:") == 0) + skip2eol(cp->fin); + else if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) + state = DONE; + else if (strcmp(w, "BW") == 0) + state = BW; + break; + + case BW: + sscanf(w, "%d", &bandwidth); + bandwidth *= 1000; /* Kbit -> bytes/sec */ + bandwidth /= 8; + state = IN_REPORT; + break; + + } + } + alarm(0); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "Extracted bandwidth: %d bytes/sec\n", bandwidth); + } +#endif + return bandwidth; +} + +#define SHOW_INT 1 +#define SHOW_FRAME 2 + +int +grab_cisco(intf_t *ip) +{ + int style; + int next_state; + int state = NOISE; + int skip = 0; + int i; + int namelen; + char *pw_prompt = NULL; + char *w; + int fd; + int fd2; + int nval = 0; + cisco_t *cp = ip->cp; + intf_t tmp; + int len_prompt = strlen(cp->prompt); + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "grab_cisco(%s:%s):\n", cp->host, ip->interface); + } +#endif + + tmp.bandwidth = tmp.rate_in = tmp.rate_out = -1; + tmp.bytes_in = tmp.bytes_out = tmp.bytes_out_bcast = -1; + + if (cp->fin == NULL) { + fd = conn_cisco(cp); + if (fd < 0) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "grab_cisco(%s:%s): connect failed: %s\n", + cp->host, ip->interface, netstrerror()); +#endif + return -1; + } + else { + cp->fin = fdopen (fd, "r"); + if ((fd2 = dup(fd)) < 0) { + perror("dup"); + exit(1); + } + cp->fout = fdopen (fd2, "w"); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "grab_cisco(%s:%s): connected fin=%d fout=%d", + cp->host, ip->interface, fileno(cp->fin), fileno(cp->fout)); + if (cp->username != NULL) + fprintf(stderr, " username=%s", cp->username); + else + fprintf(stderr, " NO username"); + if (cp->passwd != NULL) + fprintf(stderr, " passwd=%s", cp->passwd); + else + fprintf(stderr, " NO passwd"); + fputc('\n', stderr); + } +#endif + + if (cp->username != NULL) { + /* + * Username stuff ... + */ + if (dousername(cp, &pw_prompt) == 0) { + fclose(cp->fin); + fclose(cp->fout); + cp->fin = cp->fout = NULL; + return -1; + } + } + if (cp->passwd != NULL) { + /* + * User-level password stuff ... + */ + if (dopasswd(cp, pw_prompt) == 0) { + fclose(cp->fin); + fclose(cp->fout); + cp->fin = cp->fout = NULL; + return -1; + } + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: \n"); + } +#endif + fprintf(cp->fout, "\n"); + fflush(cp->fout); + } +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: terminal length 0\n"); + } +#endif + fprintf(cp->fout, "terminal length 0\n"); + fflush(cp->fout); + } + + timeout = 0; + signal(SIGALRM, onalarm); + /* + * Choice of timeout here is somewhat arbitrary ... for a long + * time this was 5 (seconds), but then testing with an entry + * level Model 800 ADSL router revealed that up to 20 seconds + * was required to generate the expected output. + */ + alarm(20); + + style = SHOW_INT; /* default Cisco command */ + if (ip->interface[0] == 's' && strchr(ip->interface, '.') != NULL) { + /* + * Frame-relay PVC on subinterface for s2/3.7 style interface name + */ + style = SHOW_FRAME; + if (ip->bandwidth == -2) { + /* + * one-trip initialzation ... need show int s2/3.7 to + * get bandwidth + */ + ip->bandwidth = get_fr_bw(cp, &ip->interface[1]); + } + tmp.bandwidth = ip->bandwidth; + if (tmp.bandwidth != -1) + nval++; + } + if (style == SHOW_FRAME) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: show frame pvc int s%s\n", &ip->interface[1]); + } +#endif + fprintf(cp->fout, "show frame pvc int s%s\n", &ip->interface[1]); + next_state = BYTES_IN; + } + else { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL1) { + fprintf(stderr, "Send: show int %s\n", ip->interface); + } +#endif + fprintf(cp->fout, "show int %s\n", ip->interface); + } + fflush(cp->fout); + state = NOISE; +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "Parse:"); + fflush(stderr); + } +#endif + while (state != DONE) { +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL2) { + fprintf(stderr, "[%s] ", statestr[state+1]); + fflush(stderr); + } +#endif + w = mygetwd(cp->fin, cp->prompt); + if (w == NULL || timeout) { + /* + * End of File (telenet timeout?) + * ... mark as closed, and try again at next request + */ +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + fprintf(stderr, "grab_cisco(%s:%s): forced disconnect fin=%d\n", + cp->host, ip->interface, fileno(cp->fin)); +#endif + fclose(cp->fin); + fclose(cp->fout); + cp->fin = cp->fout = NULL; + alarm(0); + return -1; + } + switch (state) { + + case NOISE: + for (i = 0; i < num_intf_tab; i++) { + namelen = strlen(intf_tab[i].name); + if (strncmp(w, intf_tab[i].name, namelen) == 0) { + state = IN_REPORT; + break; + } + } + break; + + case IN_REPORT: + if (strcmp(w, "Description:") == 0) + skip2eol(cp->fin); + if (strlen(w) >= len_prompt && strncmp(&w[strlen(w)-len_prompt], cp->prompt, len_prompt) == 0) + state = DONE; + else if (style == SHOW_INT) { + if (strcmp(w, "minute") == 0 || strcmp(w, "second") == 0) + state = RATE; + else if (strcmp(w, "input,") == 0) + state = BYTES_IN; + else if (strcmp(w, "output,") == 0) + state = BYTES_OUT; + else if (strcmp(w, "BW") == 0) + state = BW; + } + else if (style == SHOW_FRAME) { + if (strcmp(w, "bytes") == 0) { + if (next_state == BYTES_IN) { + state = BYTES_IN; + next_state = BYTES_OUT; + } + else if (next_state == BYTES_OUT) { + state = BYTES_OUT; + next_state = BYTES_OUT_BCAST; + } + else if (next_state == BYTES_OUT_BCAST) { + state = BYTES_OUT_BCAST; + next_state = IN_REPORT; + } + else + state = next_state; + } + } + break; + + case RATE: + if (strcmp(w, "input") == 0) { + skip = 1; + state = RATE_IN; + } + else if (strcmp(w, "output") == 0) { + skip = 1; + state = RATE_OUT; + } + break; + + case RATE_IN: + if (skip-- == 0) { + tmp.rate_in = atol(w) / 8; + nval++; + state = IN_REPORT; + } + break; + + case RATE_OUT: + if (skip-- == 0) { + tmp.rate_out = atol(w) / 8; + nval++; + state = IN_REPORT; + } + break; + + case BYTES_IN: + tmp.bytes_in = strtoull(w, NULL, 10); + nval++; + state = IN_REPORT; + break; + + case BYTES_OUT: + tmp.bytes_out = strtoull(w, NULL, 10); + nval++; + state = IN_REPORT; + break; + + case BYTES_OUT_BCAST: + tmp.bytes_out_bcast = strtoull(w, NULL, 10); + nval++; + state = IN_REPORT; + break; + + case BW: + sscanf(w, "%d", &tmp.bandwidth); + tmp.bandwidth *= 1000; /* Kbit -> bytes/sec */ + tmp.bandwidth /= 8; + nval++; + state = IN_REPORT; + break; + + } + } + alarm(0); +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) { + fprintf(stderr, "Extracted %d values ...\n", nval); + if (tmp.bandwidth != 0xffffffff) + fprintf(stderr, "bandwidth: %d bytes/sec\n", tmp.bandwidth); + else + fprintf(stderr, "bandwidth: ? bytes/sec\n"); + fprintf(stderr, "recent rate (bytes/sec):"); + if (tmp.rate_in != 0xffffffff) + fprintf(stderr, " %d in", tmp.rate_in); + else + fprintf(stderr, " ? in"); + if (tmp.rate_out != 0xffffffff) + fprintf(stderr, " %d out", tmp.rate_out); + else + fprintf(stderr, " ? out"); + fprintf(stderr, "\ntotal bytes:"); + if (tmp.bytes_in != 0xffffffffffffffffLL) + fprintf(stderr, " %llu in", (unsigned long long)tmp.bytes_in); + else + fprintf(stderr, " ? in"); + if (tmp.bytes_out != 0xffffffffffffffffLL) + fprintf(stderr, " %llu out", (unsigned long long)tmp.bytes_out); + else + fprintf(stderr, " ? out"); + if (tmp.bytes_out_bcast != 0xffffffffffffffffLL) + fprintf(stderr, " %llu out_bcast", (unsigned long long)tmp.bytes_out_bcast); + else + fprintf(stderr, " ? out_bcast"); + fprintf(stderr, "\n\n"); + } +#endif + + /* pretend this is atomic */ + ip->bandwidth = tmp.bandwidth; + ip->rate_in = tmp.rate_in; + ip->rate_out = tmp.rate_out; + ip->bytes_in = tmp.bytes_in; + ip->bytes_out = tmp.bytes_out; + ip->bytes_out_bcast = tmp.bytes_out_bcast; + + return nval; +} |