3 # Copyright (c) 2014, Ixia
4 # Copyright (c) 2015-2016, Intel Corporation
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
11 # 1. Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # 3. Neither the name of the copyright holder nor the names of its
19 # contributors may be used to endorse or promote products derived
20 # from this software without specific prior written permission.
22 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 # POSSIBILITY OF SUCH DAMAGE.
35 # This file is a modified version of a script generated by Ixia
38 lappend auto_path [list $lib_path]
42 ###################################################################
43 ########################## Configuration ##########################
44 ###################################################################
46 # Verify that the IXIA chassis spec is given
48 set reqVars [list "host" "card" "port1" "port2"]
50 foreach var $reqVars {
51 set var_ns [namespace which -variable "$var"]
52 if { [string compare $var_ns ""] == 0 } {
53 errorMsg "The '$var' variable is undefined. Did you set it?"
60 set fullHex "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"
61 set hexToC5 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5"
63 #set payloadLookup(64) [string range $fullHex 0 11]
64 set payloadLookup(64) "000102030405"
65 set payloadLookup(128) "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445"
66 set payloadLookup(256) "$hexToC5"
67 set payloadLookup(512) "$fullHex$hexToC5"
68 set payloadLookup(1024) "$fullHex$fullHex$fullHex$hexToC5"
70 ###################################################################
71 ###################### Chassis Configuration ######################
72 ###################################################################
75 if {[ixConnectToTclServer $host]} {
76 errorMsg "Error connecting to Tcl Server $host"
81 ######### Chassis #########
83 # Now connect to the chassis
84 if [ixConnectToChassis $host] {
89 # Get the chassis ID to use in port lists
90 set chassis [ixGetChassisID $host]
92 ######### Ports #########
94 set portList [list [list $chassis $card $port1] \
95 [list $chassis $card $port2]]
97 # Clear ownership of the ports we’ll use
98 if [ixClearOwnership $portList force] {
103 # Take ownership of the ports we’ll use
104 if [ixTakeOwnership $portList] {
105 ixPuts $::ixErrorInfo
109 foreach portElem $portList {
110 set chasNum [lindex $portElem 0]
111 set cardNum [lindex $portElem 1]
112 set portNum [lindex $portElem 2]
114 port setFactoryDefaults $chasNum $cardNum $portNum
115 port config -speed 10000
116 port config -flowControl true
117 port config -transmitMode portTxModeAdvancedScheduler
118 port config -receiveMode [expr $::portCapture|$::portRxModeWidePacketGroup]
119 port config -advertise100FullDuplex false
120 port config -advertise100HalfDuplex false
121 port config -advertise10FullDuplex false
122 port config -advertise10HalfDuplex false
123 port config -portMode port10GigLanMode
124 port config -enableTxRxSyncStatsMode true
125 port config -txRxSyncInterval 2000
126 port config -enableTransparentDynamicRateChange true
127 port config -enableDynamicMPLSMode true
128 if {[port set $chasNum $cardNum $portNum]} {
129 errorMsg "Error calling port set $chasNum $cardNum $portNum"
132 packetGroup setDefault
133 packetGroup config -numTimeBins 1
134 if {[packetGroup setRx $chasNum $cardNum $portNum]} {
135 errorMsg "Error calling packetGroup setRx $chasNum $cardNum $portNum"
139 sfpPlus config -enableAutomaticDetect false
140 sfpPlus config -txPreTapControlValue 1
141 sfpPlus config -txMainTapControlValue 63
142 sfpPlus config -txPostTapControlValue 2
143 sfpPlus config -rxEqualizerControlValue 0
144 if {[sfpPlus set $chasNum $cardNum $portNum]} {
145 errorMsg "Error calling sfpPlus set $chasNum $cardNum $portNum"
149 filter config -captureTriggerFrameSizeFrom 48
150 filter config -captureTriggerFrameSizeTo 48
151 filter config -captureFilterFrameSizeFrom 48
152 filter config -captureFilterFrameSizeTo 48
153 filter config -userDefinedStat1FrameSizeFrom 48
154 filter config -userDefinedStat1FrameSizeTo 48
155 filter config -userDefinedStat2FrameSizeFrom 48
156 filter config -userDefinedStat2FrameSizeTo 48
157 filter config -asyncTrigger1FrameSizeFrom 48
158 filter config -asyncTrigger1FrameSizeTo 48
159 filter config -asyncTrigger2FrameSizeFrom 48
160 filter config -asyncTrigger2FrameSizeTo 48
161 filter config -userDefinedStat1Enable true
162 filter config -userDefinedStat2Enable true
163 filter config -asyncTrigger1Enable true
164 filter config -asyncTrigger2Enable true
165 if {[filter set $chasNum $cardNum $portNum]} {
166 errorMsg "Error calling filter set $chasNum $cardNum $portNum"
169 filterPallette setDefault
170 filterPallette config -pattern1 00
171 filterPallette config -patternMask1 00
172 filterPallette config -patternOffset1 20
173 filterPallette config -patternOffset2 20
174 if {[filterPallette set $chasNum $cardNum $portNum]} {
175 errorMsg "Error calling filterPallette set $chasNum $cardNum $portNum"
179 capture config -sliceSize 65536
180 if {[capture set $chasNum $cardNum $portNum]} {
181 errorMsg "Error calling capture set $chasNum $cardNum $portNum"
184 if {[interfaceTable select $chasNum $cardNum $portNum]} {
185 errorMsg "Error calling interfaceTable select $chasNum $cardNum $portNum"
188 interfaceTable setDefault
189 if {[interfaceTable set]} {
190 errorMsg "Error calling interfaceTable set"
193 interfaceTable clearAllInterfaces
194 if {[interfaceTable write]} {
195 errorMsg "Error calling interfaceTable write"
198 ixEnablePortIntrinsicLatencyAdjustment $chasNum $cardNum $portNum true
201 ixWritePortsToHardware portList
203 if {[ixCheckLinkState $portList] != 0} {
204 errorMsg "One or more port links are down"
207 proc sendTraffic { flowSpec trafficSpec } {
208 # Send traffic from IXIA.
210 # Transmits traffic from Rx port (port1), and captures traffic at
214 # flowSpec - a dict detailing how the packet should be sent. Should be
216 # {type, numpkts, duration, framerate}
217 # trafficSpec - a dict describing the packet to be sent. Should be
220 # where each item is in turn a dict detailing the configuration of each
221 # layer of the packet
223 # Output from Rx end of Ixia if duration != 0, else 0
225 ##################################################
226 ################# Initialisation #################
227 ##################################################
229 # Configure global variables. See documentation on 'global' for more
230 # information on why this is necessary
231 # https://www.tcl.tk/man/tcl8.5/tutorial/Tcl13.html
234 # Extract the provided dictionaries to local variables to simplify the
239 set streamType [dict get $flowSpec type]
240 set numPkts [dict get $flowSpec numpkts]
241 set duration [expr {[dict get $flowSpec duration] * 1000}]
242 set frameRate [dict get $flowSpec framerate]
246 # extract nested dictionaries
247 set trafficSpec_l2 [dict get $trafficSpec l2]
248 set trafficSpec_l3 [dict get $trafficSpec l3]
249 set trafficSpec_l4 [dict get $trafficSpec l4]
250 set trafficSpec_vlan [dict get $trafficSpec vlan]
252 set frameSize [dict get $trafficSpec_l2 framesize]
253 set srcMac [dict get $trafficSpec_l2 srcmac]
254 set dstMac [dict get $trafficSpec_l2 dstmac]
255 set srcPort [dict get $trafficSpec_l4 srcport]
256 set dstPort [dict get $trafficSpec_l4 dstport]
258 set proto [dict get $trafficSpec_l3 proto]
259 set srcIp [dict get $trafficSpec_l3 srcip]
260 set dstIp [dict get $trafficSpec_l3 dstip]
262 if {[dict exists $trafficSpec_l3 protocolpadbytes]} {
263 set protocolPad [dict get $trafficSpec_l4 protocolpad]
264 set protocolPadBytes [dict get $trafficSpec_l4 protocolpadbytes]
267 set vlanEnabled [dict get $trafficSpec_vlan enabled]
268 if {$vlanEnabled == 1 } {
269 # these keys won't exist if vlan wasn't enabled
270 set vlanId [dict get $trafficSpec_vlan id]
271 set vlanUserPrio [dict get $trafficSpec_vlan priority]
272 set vlanCfi [dict get $trafficSpec_vlan cfi]
275 ##################################################
276 ##################### Streams ####################
277 ##################################################
279 streamRegion get $::chassis $::card $::port1
280 if {[streamRegion enableGenerateWarningList $::chassis $::card $::port1 false]} {
281 errorMsg "Error calling streamRegion enableGenerateWarningList $::chassis $::card $::port1 false"
287 stream config -ifg 9.6
288 stream config -ifgMIN 19.2
289 stream config -ifgMAX 25.6
290 stream config -ibg 9.6
291 stream config -isg 9.6
292 stream config -rateMode streamRateModePercentRate
293 stream config -percentPacketRate $frameRate
294 stream config -framesize $frameSize
295 stream config -frameType "08 00"
296 stream config -sa $srcMac
297 stream config -da $dstMac
298 stream config -numSA 16
299 stream config -numDA 16
300 stream config -asyncIntEnable true
301 stream config -dma $streamType
302 stream config -numBursts 1
303 stream config -numFrames $numPkts
304 stream config -patternType incrByte
305 stream config -dataPattern x00010203
306 stream config -pattern "00 01 02 03"
309 protocol config -name ipV4
310 protocol config -ethernetType ethernetII
311 if {$vlanEnabled == 1} {
312 protocol config -enable802dot1qTag vlanSingle
315 if {[info exists protocolPad]} {
316 protocol config -enableProtocolPad $protocolPad
320 ip config -ipProtocol ipV4Protocol[string totitle $proto]
321 ip config -checksum "f6 75"
322 ip config -sourceIpAddr $srcIp
323 ip config -sourceIpAddrRepeatCount 10
324 ip config -sourceClass classA
325 ip config -destIpAddr $dstIp
326 ip config -destIpAddrRepeatCount 10
327 ip config -destClass classA
328 ip config -destMacAddr $dstMac
329 ip config -destDutIpAddr 0.0.0.0
331 if {[ip set $::chassis $::card $::port1]} {
332 errorMsg "Error calling ip set $::chassis $::card $::port1"
336 "$proto" config -checksum "25 81"
337 if {["$proto" set $::chassis $::card $::port1]} {
338 errorMsg "Error calling $proto set $::chassis $::card $::port"
341 if {[info exists protocolPad]} {
342 protocolPad setDefault
343 # VxLAN header with VNI 99 (0x63)
344 # Inner SRC 01:02:03:04:05:06
345 # Inner DST 06:05:04:03:02:01
347 # IP DST 192.168.240.9
348 # SRC port 3000 (0x0BB8)
349 # DST port 3001 (0x0BB9)
351 # UDP Checksum 0x2E93
353 # From encap case capture
354 protocolPad config -dataBytes "$protocolPadBytes"
355 if {[protocolPad set $::chassis $::card $::port1]} {
356 errorMsg "Error calling protocolPad set $::chassis $::card $::port"
357 set retCode $::TCL_ERROR
361 if {$vlanEnabled == 1 } {
363 vlan config -vlanID $vlanId
364 vlan config -userPriority $vlanUserPrio
365 vlan config -cfi $vlanCfi
366 vlan config -mode vIdle
367 vlan config -repeat 10
369 vlan config -maskval "0000XXXXXXXXXXXX"
370 vlan config -protocolTagId vlanProtocolTag8100
373 if {[vlan set $::chassis $::card $::port1]} {
374 errorMsg "Error calling vlan set $::chassis $::card $::port1"
377 if {[port isValidFeature $::chassis $::card $::port1 $::portFeatureTableUdf]} {
379 tableUdf clearColumns
380 if {[tableUdf set $::chassis $::card $::port1]} {
381 errorMsg "Error calling tableUdf set $::chassis $::card $::port1"
385 if {[port isValidFeature $::chassis $::card $::port1 $::portFeatureRandomFrameSizeWeightedPair]} {
386 weightedRandomFramesize setDefault
387 if {[weightedRandomFramesize set $::chassis $::card $::port1]} {
388 errorMsg "Error calling weightedRandomFramesize set $::chassis $::card $::port1"
392 if {$proto == "tcp"} {
394 tcp config -sourcePort $srcPort
395 tcp config -destPort $dstPort
396 if {[tcp set $::chassis $::card $::port1 ]} {
397 errorMsg "Error setting tcp on port $::chassis.$::card.$::port1"
400 if {$vlanEnabled != 1} {
403 udf config -continuousCount true
404 udf config -initval {00 00 00 01}
405 udf config -updown uuuu
406 udf config -cascadeType udfCascadeNone
409 packetGroup setDefault
410 packetGroup config -insertSequenceSignature true
411 packetGroup config -sequenceNumberOffset 38
412 packetGroup config -signatureOffset 42
413 packetGroup config -signature "08 71 18 05"
414 packetGroup config -groupIdOffset 52
415 packetGroup config -groupId $streamId
416 packetGroup config -allocateUdf true
417 if {[packetGroup setTx $::chassis $::card $::port1 $streamId]} {
418 errorMsg "Error calling packetGroup setTx $::chassis $::card $::port1 $streamId"
421 } elseif {$proto == "udp"} {
423 udp config -sourcePort $srcPort
424 udp config -destPort $dstPort
425 if {[dict exists $trafficSpec_l3 packetsize]} {
426 set packetSize [dict get $trafficSpec_l3 packetsize]
428 set packetSize $frameSize
430 stream config -framesize $packetSize
431 if {[udp set $::chassis $::card $::port1]} {
432 errorMsg "Error setting udp on port $::chassis.$::card.$::port1"
434 errorMsg "frameSize: $frameSize, packetSize: $packetSize, srcMac: $srcMac, dstMac: $dstMac, srcPort: $srcPort, dstPort: $dstPort"
435 if {[info exists protocolPad]} {
436 errorMsg "protocolPad: $protocolPad, protocolPadBytes: $protocolPadBytes"
440 if {[stream set $::chassis $::card $::port1 $streamId]} {
441 errorMsg "Error calling stream set $::chassis $::card $::port1 $streamId"
445 streamRegion generateWarningList $::chassis $::card $::port1
446 ixWriteConfigToHardware portList -noProtocolServer
448 if {[packetGroup getRx $::chassis $::card $::port2]} {
449 errorMsg "Error calling packetGroup getRx $::chassis $::card $::port2"
452 ##################################################
453 ######### Traffic Transmit and Results ###########
454 ##################################################
458 logMsg "Clearing stats for all ports"
459 ixClearStats portList
461 logMsg "Starting packet groups on port $::port2"
462 ixStartPortPacketGroups $::chassis $::card $::port2
464 logMsg "Starting Capture on port $::port2"
465 ixStartPortCapture $::chassis $::card $::port2
467 logMsg "Starting transmit on port $::port1"
468 ixStartPortTransmit $::chassis $::card $::port1
470 # If duration=0 is passed, exit after starting transmit
472 if {$duration == 0} {
473 logMsg "Sending traffic until interrupted"
477 logMsg "Waiting for $duration ms"
479 # Wait for duration - 1 second to get traffic rate
481 after [expr "$duration - 1"]
485 set result [stopTraffic]
487 if {$streamType == "contPacket"} {
489 } elseif {$streamType == "stopStream"} {
492 set captureLimit 3000
494 # explode results from 'stopTraffic' for ease of use later
495 set framesSent [lindex $result 0]
496 set framesRecv [lindex $result 1]
497 set bytesSent [lindex $result 2]
498 set bytesRecv [lindex $result 3]
500 if {$framesSent <= $captureLimit} {
501 captureBuffer get $::chassis $::card $::port2 1 $framesSent
502 set capturedFrames [captureBuffer cget -numFrames]
504 set notCaptured [expr "$framesRecv - $capturedFrames"]
505 if {$notCaptured != 0} {
506 errorMsg "'$notCaptured' frames were not captured"
509 if {$proto == "tcp"} {
510 for {set z 1} {$z <= $capturedFrames} {incr z} {
511 captureBuffer getframe $z
512 set capFrame [captureBuffer cget -frame]
513 regsub -all " " $capFrame "" frameNoSpaces
517 set endPayload [expr "[expr "$frameSize * 2"] - 9"]
518 set payload [string range $frameNoSpaces $startPayload $endPayload]
520 if {$vlanEnabled != 1} {
523 set sequence [string range $frameNoSpaces $startSequence $endSequence]
524 scan $sequence %x seqDecimal
526 if {"$payload" != $::payloadLookup($frameSize)} {
527 errorMsg "frame '$z' payload: invalid payload"
530 # variable z increments from 1 to total number of packets
531 # captured TCP sequence numbers start at 0, not 1. When
532 # comparing sequence numbers for captured frames, reduce
533 # variable z by 1 i.e. frame 1 with sequence 0 is compared
534 # to expected sequence 0.
535 if {$seqDecimal != $z-1} {
536 errorMsg "frame '$z' sequence number: Found '$seqDecimal'. Expected '$z'"
542 logMsg "Sequence Errors: $seqError"
543 logMsg "Payload Errors: $payError\n"
545 errorMsg "Too many packets for capture."
548 set result [list $framesSent $framesRecv $bytesSent $bytesRecv $payError $seqError]
551 errorMsg "streamtype is not supported: '$streamType'"
555 proc stopTraffic {} {
556 # Stop sending traffic from IXIA.
558 # Stops Transmit of traffic from Rx port.
561 # Output from Rx end of Ixia.
563 ##################################################
564 ################# Initialisation #################
565 ##################################################
567 # Configure global variables. See documentation on 'global' for more
568 # information on why this is necessary
569 # https://www.tcl.tk/man/tcl8.5/tutorial/Tcl13.html
572 ##################################################
573 ####### Stop Traffic Transmit and Results ########
574 ##################################################
576 # Read frame rate of transmission
578 if {[stat getRate statAllStats $::chassis $::card $::port1]} {
579 errorMsg "Error reading stat rate on port $::chassis $::card $::port1"
583 set sendRate [stat cget -framesSent]
584 set sendRateBytes [stat cget -bytesSent]
586 if {[stat getRate statAllStats $::chassis $::card $::port2]} {
587 errorMsg "Error reading stat rate on port $::chassis $::card $::port2"
591 set recvRate [stat cget -framesReceived]
592 set recvRateBytes [stat cget -bytesReceived]
594 # Wait for a second, else we get funny framerate statistics
597 # Stop transmission of traffic
598 ixStopTransmit portList
600 if {[ixCheckTransmitDone portList] == $::TCL_ERROR} {
603 logMsg "Transmission is complete.\n"
606 ixStopPacketGroups portList
607 ixStopCapture portList
611 if {[stat get statAllStats $::chassis $::card $::port1]} {
612 errorMsg "Error reading stat on port $::chassis $::card $::port1"
616 set bytesSent [stat cget -bytesSent]
617 set framesSent [stat cget -framesSent]
619 if {[stat get statAllStats $::chassis $::card $::port2]} {
620 errorMsg "Error reading stat on port $::chassis $::card $::port2"
624 set bytesRecv [stat cget -bytesReceived]
625 set framesRecv [stat cget -framesReceived]
627 set bytesDropped [expr "$bytesSent - $bytesRecv"]
628 set framesDropped [expr "$framesSent - $framesRecv"]
630 logMsg "Frames Sent: $framesSent"
631 logMsg "Frames Recv: $framesRecv"
632 logMsg "Frames Dropped: $framesDropped\n"
634 logMsg "Bytes Sent: $bytesSent"
635 logMsg "Bytes Recv: $bytesRecv"
636 logMsg "Bytes Dropped: $bytesDropped\n"
638 logMsg "Frame Rate Sent: $sendRate"
639 logMsg "Frame Rate Recv: $recvRate\n"
641 set result [list $framesSent $framesRecv $bytesSent $bytesRecv $sendRate $recvRate $sendRateBytes $recvRateBytes]
646 proc rfcThroughputTest { testSpec trafficSpec } {
647 # Execute RFC tests from IXIA.
649 # Wraps the sendTraffic proc, repeatedly calling it, storing the result and
650 # performing an iterative binary search to find the highest possible RFC
651 # transmission rate. Abides by the specification of RFC2544 as given by the
654 # https://www.ietf.org/rfc/rfc2544.txt
657 # testSpec - a dict detailing how the test should be run. Should be
659 # {numtrials, duration, lossrate}
660 # trafficSpec - a dict describing the packet to be sent. Should be
663 # where each item is in turn a dict detailing the configuration of each
664 # layer of the packet
666 # Highest rate with acceptable packet loss.
668 ##################################################
669 ################# Initialisation #################
670 ##################################################
672 # Configure global variables. See documentation on 'global' for more
673 # information on why this is necessary
674 # https://www.tcl.tk/man/tcl8.5/tutorial/Tcl13.html
677 # Extract the provided dictionaries to local variables to simplify the
682 # RFC2544 to IXIA terminology mapping (it affects Ixia configuration below):
685 set numTrials [dict get $testSpec tests] ;# we don't use this yet
686 set duration [dict get $testSpec duration]
687 set lossRate [dict get $testSpec lossrate]
688 set multipleStream [dict get $testSpec multipleStreams] ;# we don't use this yet
690 # variables used for binary search of results
693 set diff [expr "$max - $min"]
695 set result [list 0 0 0 0 0 0 0 0] ;# best result found so far
696 set percentRate 100 ;# starting throughput percentage rate
698 ##################################################
699 ######### Traffic Transmit and Results ###########
700 ##################################################
702 # iterate a maximum of 20 times, sending packets at a set rate to
703 # find fastest possible rate with acceptable packetloss
705 # As a reminder, the binary search works something like this:
707 # percentRate < idealValue --> min = percentRate
708 # percentRate > idealValue --> max = percentRate
709 # percentRate = idealValue --> max = min = percentRate
711 for {set i 0} {$i < 20} {incr i} {
712 dict set flowSpec type "contPacket"
713 dict set flowSpec numpkts 100 ;# this can be bypassed
714 dict set flowSpec duration $duration
715 dict set flowSpec framerate $percentRate
717 set flowStats [sendTraffic $flowSpec $trafficSpec]
719 # explode results from 'sendTraffic' for ease of use later
720 set framesSent [lindex $flowStats 0]
721 set framesRecv [lindex $flowStats 1]
722 set sendRate [lindex $flowStats 4]
724 set framesDropped [expr "$framesSent - $framesRecv"]
725 if {$framesSent > 0} {
726 set framesDroppedRate [expr "double($framesDropped) / $framesSent"]
728 set framesDroppedRate 100
731 # check if we've already found the rate before 10 iterations, i.e.
732 # 'percentRate = idealValue'. This is as accurate as we can get with
734 if {[expr "$max - $min"] <= 0.5 } {
738 # handle 'percentRate <= idealValue' case
739 if {$framesDroppedRate <= $lossRate} {
740 logMsg "Frame sendRate of '$sendRate' pps succeeded ('$framesDropped' frames dropped)"
742 set result $flowStats
745 set percentRate [expr "$percentRate + ([expr "$max - $min"] * 0.5)"]
746 # handle the 'percentRate > idealValue' case
748 if {$framesDropped == $framesSent} {
749 errorMsg "Dropped all frames!"
752 errorMsg "Frame sendRate of '$sendRate' pps failed ('$framesDropped' frames dropped)"
755 set percentRate [expr "$percentRate - ([expr "$max - $min"] * 0.5)"]
759 set bestRate [lindex $result 4]
761 logMsg "$lossRate% packet loss rate: $bestRate"