#!/bin/awk -f # # Copyright (c) 2001 InMon Corp. ALL RIGHTS RESERVED # # This script is used in conjunction with the sflowtool # to test implementations of the sFlow agent. # # Instructions: # 1. First configure the sFlow agent to send sFlow packets # to the test host on a specified port (6343 in this example). # 2. Start the test using the following command: # sflowtool -p 6343 | ./sFlowTest.awk # 3. Monitor the test results using a web browser: # netscape stats.html # function cdiff(c1,c2) { if(c1 == 0) return 0; if(c1 <= c2) return c2 - c1; if(c1 < 2**32) return c2 + 2**32 - c1; return c2 + 2**64 - c1; } function error(str) { errorLog[++lastError] = str; } function resetFlowKeys() { newFlow = 0; sourceId = ""; inputPort = ""; outputPort = ""; in_vlan = ""; out_vlan = ""; in_priority = ""; out_priority = ""; headerProtocol = ""; srcMAC = ""; dstMAC = ""; srcIP = ""; dstIP = ""; IPProtocol = ""; IPTOS = ""; TCPSrcPort = ""; TCPDstPort = ""; TCPFlags = ""; nextHop = ""; srcSubnetMask = ""; dstSubnetMask = ""; my_as = ""; src_as = ""; src_peer_as = ""; dst_as_path = ""; } function recordFlow() { if(newFlow == 1) { count[sourceId,inputPort,outputPort,in_vlan,out_vlan,in_priority,out_priority,headerProtocol,srcMAC,dstMAC,srcIP,dstIP,nextHop,srcSubnetMask,dstSubnetMask,my_as,src_as,src_peer_as,dst_as_path] += 1; countBytes[sourceId,inputPort,outputPort,in_vlan,out_vlan,in_priority,out_priority,headerProtocol,srcMAC,dstMAC,srcIP,dstIP,nextHop,srcSubnetMask,dstSubnetMask,my_as,src_as,src_peer_as,dst_as_path] += sampledPacketSize; } resetFlowKeys(); } function printIntervalResults() { print "" >statsFile; print "" >>statsFile; print "" >>statsFile; print "sFlow Test Results" >>statsFile; print "" >>statsFile; print "" >>statsFile; # Time print "

" strftime("%R", lastInt) "

" >>statsFile; # Error Table if(lastError > 0) { print "

Test run failed because of errors. All other data should be treated as unreliable.

" >>statsFile; } # General Information Table print "" >>statsFile; print "" >>statsFile; packetDelta = cdiff(oldPacketSequenceNo,packetSequenceNo); lostDelta = cdiff(oldPacketsLost,packetsLost); lostPercentage = 0; if(packetDelta > 0) lostPercentage = 100 * lostDelta / (lostDelta + packetDelta); printf "", packetDelta / intervalSeconds, lostPercentage >>statsFile; packetSamplesDelta = cdiff(oldPacketSamples,packetSamples); packetSamplesLostDelta = cdiff(oldPacketSamplesLost,packetSamplesLost); packetSamplesLostPercentage = 0; if(packetSamplesDelta > 0) packetSamplesLostPercentage = 100 * packetSamplesLostDelta / (packetSamplesLostDelta + packetSamplesDelta); printf "", packetSamplesDelta / intervalSeconds, packetSamplesLostPercentage >> statsFile; counterSamplesDelta = cdiff(oldCounterSamples,counterSamples); counterSamplesLostDelta = cdiff(oldCounterSamplesLost,counterSamplesLost); counterSamplesLostPercentage = 0; if(counterSamplesDelta > 0) counterSamplesLostPercentage = 100 * counterSamplesLostDelta / (counterSamplesLostDelta + counterSamplesDelta); printf "", counterSamplesDelta / intervalSeconds, counterSamplesLostPercentage >> statsFile; print "
Agent" agent "sysUpTime" sysUpTime "
sFlow packets/s%.2fpercentage lost%.2f
packet samples/s%.2fpercentage lost%.2f
counter samples/s%.2fpercentage lost%.2f
" >>statsFile; print "
" >>statsFile; # Top Flows Table print "" >>statsFile; print "" >>statsFile; print "" >>statsFile; print "" >>statsFile; for(i = 1; i <= maxFlows; i++) { maxCount = 0; maxBytes = 0; maxKey = ""; for(key in count) { if(count[key] > maxCount) { maxCount = count[key]; maxKey = key; } } if(maxCount > 0) { maxBytes = countBytes[maxKey]; n = split(maxKey,a,SUBSEP); id = a[1]; poolDelta = cdiff(oldSamplePool[id],samplePool[id]); samplesDelta = cdiff(oldSamples[id],samples[id]); if(samplesDelta == 0) samplesDelta = 1; print "" >>statsFile; for(j = 1; j <= n; j++) { print "" >>statsFile; } printf "", (maxCount / samplesDelta) * poolDelta / intervalSeconds, (maxCount / samplesDelta) * poolDelta * (maxBytes / maxCount) * 8 / intervalSeconds >>statsFile; print "" >>statsFile; } delete count[maxKey]; } print "
Top " maxFlows " Flows
IDifIndexvlanpriorityProtocolMACIPnext hopsubnetBGP ASFrames/sBits/s
inoutinoutinoutsrcdestsrcdestsrcdestmysrcsrc peerdest path
" a[j] "%.2f%.2f
" >>statsFile; print "
" >>statsFile; # Counters Table print "" >>statsFile; print "" >>statsFile; print "" >>statsFile; print "" >>statsFile; maxID = ""; maxIdx = -1; do { found = 0; id = ""; idx = 1000000; for (i in counters) { n = split(i,a,SUBSEP); if((a[2] > maxIdx) && (a[2] < idx)) { idx = a[2]; id = a[1]; found = 1; } } maxID = id; maxIdx = idx; if(maxIdx < 100000) { print "" >>statsFile; n = split("ifInOctets,ifOutOctets,ifInUcastPkts,ifOutUcastPkts,ifInMulticastPkts,ifOutMulticastPkts,ifInBroadcastPkts,ifOutBroadcastPkts,ifInDiscards,ifOutDiscards,ifInErrors,ifOutErrors", a, ","); for (i = 1; i <= n; i++) { print "" >>statsFile; } print "" >>statsFile; } } while (found == 1); print "
Counters
IDifIndexifSpeedifDirectionifStatusOctetsUcastMulticastBroadcastDiscardsErrors
inoutinoutinoutinoutinoutinout
" maxID "" maxIdx "" counters[maxID,maxIdx,"ifSpeed"] "" counters[maxID,maxIdx,"ifDirection"] "" counters[maxID,maxIdx,"ifStatus"] "" >>statsFile; printf "%.2f", cdiff(oldCounters[maxID,maxIdx,a[i]],counters[maxID,maxIdx,a[i]]) / intervalSeconds >>statsFile; print "
" >>statsFile; print "
" >>statsFile; # Error Table if(lastError > 0) { print "" >>statsFile; print "" >>statsFile; for(i = 1; i <= lastError; i++) { print "" >>statsFile; } print "
Errors
" i "" errorLog[i] "
" >>statsFile; print "
" >>statsFile; } print "" >>statsFile; print "" >>statsFile; close(statsFile); system("mv " statsFile " " finalStatsFile); oldPacketSequenceNo = packetSequenceNo; oldPacketsLost = packetsLost; oldPacketSamples = packetSamples; oldPacketSamplesLost = packetSamplesLost; oldCounterSamples = counterSamples; oldCounterSamplesLost = counterSamplesLost; delete count; delete countBytes; for(i in samplePool) oldSamplePool[i] = samplePool[i]; for(i in samples) oldSamples[i] = samples[i]; for(i in counters) oldCounters[i] = counters[i]; } BEGIN{ statsFile = "stats.bld"; finalStatsFile = "stats.html"; system("rm " statsFile); resetFlowKeys(); maxFlows = 5; maxSeqNoDelta = 10; lastInt = 0; intervalSeconds = 60; lastError = 0; } /startDatagram/{} /unixSecondsUTC/{ currentInt = $2 - ($2 % intervalSeconds); if(currentInt != lastInt) { recordFlow(); printIntervalResults(); lastInt = currentInt; } } /datagramVersion/{datagramVersion = $2;} /agent/{ if(agent) { if(agent != $2) error("Agent IP address changed from " agent " to " $2); } else {agent = $2;} } /sysUpTime/{ if(sysUptime > $2) error("sysUptime went backwards ( old value = " sysUpTime " new value = " $2 " )"); sysUpTime = $2; } /packetSequenceNo/{ if(packetSequenceNo) { delta = cdiff(packetSequenceNo, $2); packetsLost += delta - 1; if(delta == 0) error("packet seq. no. not incrementing (" packetSequenceNo ")"); if((packetSequenceNo > 0) && (delta > maxSeqNoDelta)) error("excessive sflow packet loss, or seq. no. reset (old = " packetSequenceNo " new " $2 " )"); } packetSequenceNo = $2; } /samplesInPacket/{ samplesInPacket = $2; if(samplesInPacket == 0) error("no samples in packet"); } /sampleSequenceNo/{sampleSequenceNo = $2; recordFlow(); } /sourceId/{sourceId = $2;} /sampleType/{ sampleType = $2; oldSeqNo = sSeqNos[sourceId, sampleType]; if(oldSeqNo) { delta = cdiff(oldSeqNo, sampleSequenceNo); if(sampleType == "FLOWSAMPLE") { packetSamples++; packetSamplesLost += delta - 1; } else if(sampleType == "COUNTERSSAMPLE") { counterSamples++; counterSamplesLost += delta - 1; } if(delta == 0) error("sample seq. no. not incrementing (src = " sourceId " type = " sampleType " seq. no. = " sampleSequenceNo ")"); if((packetSequenceNo > 0) && (delta > maxSeqNoDelta)) error("excessive sflow sample loss, or seq. no. reset (src = " sourceId " type = " sampleType " old = " oldSeqNo " new = " sampleSequenceNo " )"); } sSeqNos[sourceId, sampleType] = sampleSequenceNo; if(sampleType == "FLOWSAMPLE") newFlow = 1; } /meanSkipCount/{meanSkipCount[sourceId] = $2;} /samplePool/{samplePool[sourceId] = $2; samples[sourceId] += 1; } /dropEvents/{dropEvents[sourceId] = $2;} /inputPort/{inputPort = $2;} /outputPort/{outputPort = $2;} /headerProtocol/{headerProtocol = $2;} /sampledPacketSize/{sampledPacketSize = $2;} /headerLen/{headerLen = $2;} /headerBytes/{headerBytes = $2;} /dstMAC/{dstMAC = $2;} /srcMAC/{srcMAC = $2;} /srcIP/{srcIP = $2;} /dstIP/{dstIP = $2;} /IPProtocol/{ IPProtocol = $2;} /IPTOS/{IPTOS = $2;} /TCPSrcPort/{TCPSrcPort = $2;} /TCPDstPort/{TCPDstPort = $2;} /TCPFlags/{TCPFlags = $2;} /in_vlan/{in_vlan = $2;} /in_priority/{in_priority = $2;} /out_vlan/{out_vlan = $2;} /out_priority/{out_priority = $2;} /nextHop/{nextHop = $2;} /srcSubnetMask/{srcSubnetMask = $2;} /dstSubnetMask/{dstSubnetMask = $2;} /my_as/{my_as = $2;} /src_as/{src_as = $2;} /src_peer_as/{src_peer_as = $2;} /dst_as_path/{dst_as_path = $2;} /statsSamplingInterval/{statsSamplingInterval = $2;} /counterBlockVersion/{counterBlockVersion = $2;} /networkType/{networkType = $2;} /if/{ counterName = $1; counterValue = $2; if(counterName == "ifIndex") ifIndex = counterValue; else { counters[sourceId,ifIndex,counterName] = counterValue; } } END{}