#------------------------------------------------------------------------------
# IPv4 Back-to Back tutorial
#------------------------------------------------------------------------------
#
# This tutorial demonstrates how easy you can set up a Back-to-Back test,
# similar to the one described in the ByteBlower GUI manual.
# It will show you how to setup the test, using the ByteBlower LowerLayer
# API. Only frame creation will be done using the HigherLayer TCL API procedures.
#
# @author ByteBlower development team <byteblower@excentis.com>
# @date 2008/05/06
#
# file reference: tutorial.back-to-back-v4.tcl
# requirements:
#   - basic.utils.tcl from the TCL-HL package
#   - basic.framev4v6.tcl from the TCL-HL package
#------------------------------------------------------------------------------

# --- Where is the fun without the ByteBlower package?
package require ByteBlower

#
# --- Define configuration parameters ---
#
#- Define the IP address or hostname of the ByteBlower server to use
set serverAddress byteblower-6
#- Define the physical port you want to use on the ByteBlower server.
set physicalPort1 trunk-1-1
set physicalPort2 trunk-1-2

#- Define source port Layer2 MAC Address
set srcMacAddress "00:FF:0A:00:00:01"

#- Define destination port Layer2 MAC Address
set destMacAddress "00:FF:0A:00:00:02"

#- Define source port Layer3 IPv4 settings
#- will we use DHCP?
set srcUseDhcp 0
#- Fixed IPv4 settings (used when DHCP is NOT used)
set srcIpAddress "10.10.0.2"
set srcNetmask "255.255.255.0"
set srcIpGW "10.10.0.1"

#- Define destination port Layer3 settings
#- will we use DHCP?
set destUseDhcp 0
#- Fixed IPv4 settings (used when DHCP is NOT used)
set destIpAddress "10.10.0.3"
set destNetmask "255.255.255.0"
set destIpGW "10.10.0.1"

#- We will set up an UDP frame with following settings:
#- Source and destination port for sending from physicalPort1 -> physicalPort2
set srcUdpPort 2001
set destUdpPort 2002

#- Define frame sizes and frame rate
set ethernetLength 124 ;# ByteBlower requires to set ethernet frames without CRC bytes!
set udpLength [ expr $ethernetLength - 42 ]
set numberOfFrames 10000
set interFrameGap 1ms

#
# --- Preparing the test ---
#

#- Connect to the Server
set server [ ByteBlower Server.Add $serverAddress ]

#- Create 2 logical ByteBlower Ports
set backToBackSource [ $server Port.Create $physicalPort1 ]
set backToBackDestination [ $server Port.Create $physicalPort2 ]

#- Source port Layer2 setup
#- Create the Layer2 Configuration Object
set srcL2 [ $backToBackSource Layer2.Set ethII ]
#- Set the MAC address on the Layer2 Object
$srcL2 Mac.Set $srcMacAddress

#- idem for Destination port Layer2 setup
set destL2 [ $backToBackDestination Layer2.Set ethII ]
$destL2 Mac.Set $destMacAddress

#- Source port Layer3 setup
#- Create the Layer3 Configuration Object
set srcL3 [ $backToBackSource Layer3.Set ipv4 ]
if { $srcUseDhcp == 1 } {
    #- Using DHCP
    #- Perform DHCPv4 on the dhcp Object
    [ $srcL3 Dhcp ] Perform
} else {
    #- Using static IP
    #- Set IPv4 address, Netmask and gateway on the Layer3 Object
    $srcL3 Ip.Set $srcIpAddress
    $srcL3 Netmask.Set $srcNetmask
    $srcL3 Gateway.Set $srcIpGW
}

#- idem for Destination port Layer3 setup
set destL3 [ $backToBackDestination Layer3.Set ipv4 ]
if { $destUseDhcp == 1 } {
    #- Using DHCP
    [ $destL3 Dhcp ] Perform
} else {
    #- Using static IP
    $destL3 Ip.Set $destIpAddress
    $destL3 Netmask.Set $destNetmask
    $destL3 Gateway.Set $destIpGW
}

#
# --- Get the destination MAC addresses for our UDP frame to reach the other port ---
#
#- Sending an Arp for the destination IP of our UDP frame.
set dmacBackToBackSource [ $srcL3 Protocol.Arp [ $destL3 Ip.Get ] ]

#
# --- Create UDP frames (UDP length == 82B, EthII length == 128B)
#
#- The HigherLayer API can be used to create the UDP frame.
source "basic.framev4v6.tcl"

#- We leave the IP and ethernet settings to default.
set srcFrameContent [ Frame.Udp.Set $dmacBackToBackSource [ $srcL2 Mac.Get ] [ $destL3 Ip.Get ] [ $srcL3 Ip.Get ] $destUdpPort $srcUdpPort [ list -Length $udpLength ] ]

#
# --- Stream setup on the Back-to-Back source port
#
#- Create the source Stream Object
set srcStream [ $backToBackSource Tx.Stream.Add ]
#- Create a Frame Object on the Source Stream
set srcFrame [ $srcStream Frame.Add ]
#- Set the Frame Contents
$srcFrame Bytes.Set $srcFrameContent
#- Set the frame timing on the Stream object
$srcStream InterFrameGap.Set $interFrameGap
$srcStream NumberOfFrames.Set $numberOfFrames

#
# --- Trigger setup on the Back-to-Back destination port
#
#- Create a basic trigger
set destTrigger [ $backToBackDestination Rx.Trigger.Add basic ]
#- Set BPF filter for the frame we will receive from the source port:
#  filter is set on source and destination IPv4 address and ethernet length.
$destTrigger Filter.Set "(ip src [ $srcL3 Ip.Get ]) and (ip dst [ $destL3 Ip.Get ]) and (len = $ethernetLength)"

#
# --- Get the Description of the current Setup ---
#
# (includes description of all configured streams and flows)
puts ""
puts "*** ByteBlower Server Information ***"
puts ""
puts [ $server Description.Get ]
puts ""
puts "*** Back-to-Back source port Setup ***"
puts ""
puts [ $backToBackSource Description.Get ]
puts ""
puts "*** Back-to-Back destination port Setup ***"
puts ""
puts [ $backToBackDestination Description.Get ]

#
# --- Start the test ---
#
set testInitialTimeToWait [ $srcStream InitialTimeToWait.Get ]
set testInterFrameGap [ $srcStream InterFrameGap.Get ]
set testNumberOfFrames [ $srcStream NumberOfFrames.Get ]
set testRunSeconds [ expr ( ( $testInitialTimeToWait / 1000000 ) + ( ( $testInterFrameGap / 1000000 ) * $testNumberOfFrames ) ) / 1000 ]
$destTrigger Counters.Clear
$srcStream Start
puts "Starting test at [ clock format [ clock seconds ] ] (finish in ${testRunSeconds} seconds)"
set done 0
after [ expr $testRunSeconds * 1000 ] "set done 1"
vwait done
puts "Test finished at [ clock format [ clock seconds ] ]"

puts "Results:"
foreach {name value} [ $destTrigger Counters.Get ] {
    puts " * ${name}\t: ${value}"
}

#
# --- Cleanup ---
#
#- REMARK: Deleting an Object will also Destruct all child Objects,
#  e.g. Layer2, Layer3, Stream, Trigger on a logical Port Objects,
#       Dhcp on the IPv4 Layer3 Objects,
#       Frames on the Stream Objects,
#       etc.
$backToBackSource Destructor
$backToBackDestination Destructor


