test/linear-perf.tcl
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/linear-perf.tcl	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,515 @@
+#
+#    Copyright 2006 Intel Corporation
+# 
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+# 
+#        http://www.apache.org/licenses/LICENSE-2.0
+# 
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+
+import iptables-utils.tcl
+
+#
+# Test options
+#
+test::name linear-perf
+
+set check_large_timeout 0
+
+# number of nodes
+net::default_num_nodes 5
+
+# mode: [dtn | ftp | dtntunnel | mail | theory]
+set testopt(mode)      ""
+
+# hop mode [hop | e2e]
+set testopt(hop_mode) hop
+
+# convergence layer
+set testopt(cl)        tcp
+
+# name of the emulab test (if any)
+set testopt(emulab_test)   ""
+
+# connectivity mode: [conn | partial | shift | random]
+set testopt(conn)     conn
+
+# DTN link options:
+set testopt(link_opts) "min_retry_interval=1 max_retry_interval=1 data_timeout=30000 potential_downtime=99999999"
+#set testopt(link_opts) "min_retry_interval=1 max_retry_interval=1 data_timeout=5000 reactive_frag_enabled=0"
+
+set testopt(frag) true
+
+# File size
+set testopt(size) 1024
+
+# File count
+set testopt(count) 10
+
+# Sleep interval
+set testopt(sleep) 0
+
+# Storage DB type
+set testopt(db_type) filesysdb
+
+# Max test length
+set testopt(test_max) 35
+
+run::parse_test_opts
+
+testlog "Test options: "
+foreach k [lsort [array names testopt]] {
+    testlog "\t$k: $testopt($k)"
+}
+
+switch -- $testopt(mode) {
+    dtn - ftp - dtntunnel - mail - clear - theory {}
+    ""      {error "must specify mode"}
+    default {error "unknown mode '$testopt(mode)'"}
+}
+
+switch -- $testopt(hop_mode) {
+    hop - e2e {}
+    ""      {error "must specify hop mode"}
+    default {error "unknown hop mode '$testopt(hop_mode)'"}
+}
+
+if {$testopt(frag) != true} {
+    append testopt(link_opts) " reactive_frag_enabled=0"
+}
+
+#
+# Test file definitions
+#
+set user          $env(USER)
+
+if {$testopt(emulab_test) != ""} {
+    testlog "Rereading net definition file for emulab"
+    set emulab_test $testopt(emulab_test)
+    import emulab-net
+    set dtnd_exe      /proj/DTN/$user/DTN2/daemon/dtnd
+    set dtnsend_exe   /proj/DTN/$user/DTN2/apps/dtnsend/dtnsend
+    set dtnrecv_exe   /proj/DTN/$user/DTN2/apps/dtnrecv/dtnrecv
+    set dtntunnel_exe /proj/DTN/$user/DTN2/apps/dtntunnel/dtntunnel
+    set randfile_exe  /proj/DTN/$user/oasys/tools/randfile
+    set pproxy_exe    /proj/DTN/$user/PacketProxy/src/pproxy
+    set copy_exe      0
+    
+    set dtn_config_opts "-no_copy_executables -storage_type $testopt(db_type)"
+    
+} else {
+    set dtnd_exe      "dtnd"
+    set dtnsend_exe   "dtnsend"
+    set dtnrecv_exe   "dtnrecv"
+    set dtntunnel_exe "dtntunnel"
+    set randfile_exe  "[dist::get_rundir $net::host(0) 0]/randfile"
+
+    manifest::file ../oasys/tools/randfile randfile
+    set copy_exe      1
+
+    set dtn_config_opts "-storage_type $testopt(db_type)"
+}
+
+if {$testopt(mode) == "ftp" || $testopt(mode) == "dtntunnel"} {
+    manifest::file emulab/simple-ftp.tcl simple-ftp.tcl
+}
+
+if {$testopt(mode) == "mail"} {
+    manifest::file emulab/send-mail.tcl send-mail.tcl
+}
+
+set N [net::num_nodes]
+set last [expr $N - 1]
+
+proc emulab_get_stats {what} {
+    global emulab_test
+    set output [run::run_cmd users.emulab.net /usr/testbed/bin/portstats dtn $emulab_test]
+
+    set L [split $output "\n"]
+
+    for {set i 3} {$i < [llength $L]} {incr i} {
+        set line [lindex $L $i]
+        
+        foreach {link in_bytes in_unicast_pkts in_other_pkts out_bytes out_unicast_pkts out_other_pkts} $line {}
+
+        global emulab_links emulab_stats_in emulab_stats_out
+        set emulab_links($link) 1
+        set emulab_stats_in($what,$link)  $in_bytes
+        set emulab_stats_out($what,$link) $out_bytes
+    }
+}
+
+proc emulab_stat_diff {start end} {
+    global emulab_links emulab_stats_in emulab_stats_out
+
+    foreach link [lsort [array names emulab_links]] {
+        set in_a $emulab_stats_in($start,$link)
+        set in_b $emulab_stats_in($end,$link)
+        set out_a $emulab_stats_out($start,$link)
+        set out_b $emulab_stats_out($end,$link)
+        puts "$link:\tin [expr $in_b - $in_a]\tout [expr $out_b - $out_a]"
+    }
+}
+
+#
+# DTN configuration
+#
+if {$testopt(mode) == "dtn" || $testopt(mode) == "dtntunnel"} {
+    eval dtn::config $dtn_config_opts
+    dtn::config_app_manifest $copy_exe {dtnsend dtnrecv dtntunnel}
+    dtn::config_interface $testopt(cl)
+
+    if {$testopt(hop_mode) == "hop"} {
+        dtn::config_linear_topology ALWAYSON $testopt(cl) true $testopt(link_opts)
+    } else {
+        dtn::config_topology_common true
+        dtn::config_link 0 $last ALWAYSON $testopt(cl) $testopt(link_opts)
+    }
+}
+
+if {$testopt(mode) == "theory"} {
+    set opt(dry_run) 1
+}
+
+test::script {
+    foreach id [net::nodelist] {
+        iptables::flush $id
+    }
+    
+    testlog "Running ping test..."
+    set output ""
+    catch {
+        set output [run::run_cmd $net::host(0) ping -c 4 $net::internal_host($last)]
+    }
+    puts $output
+
+    if {$testopt(emulab_test) != ""} {
+        testlog "Getting initial packet counts"
+        emulab_get_stats start
+    }
+
+    testlog "Generating $testopt(size) byte test file"
+    set srcdir [dist::get_rundir $net::host(0) 0]
+    set dstdir [dist::get_rundir $net::host($last) $last]
+    set file   testfile.data
+
+    run::run_cmd $net::host(0) $randfile_exe -A -L $testopt(size) -O $srcdir/$file 2>/dev/null
+    
+    #
+    # Mode-specific setup phase
+    #
+    if {$testopt(mode) == "dtn" || $testopt(mode) == "dtntunnel"} {
+        set src_eid dtn://host-0/test
+        set dst_eid dtn://host-$last/test
+        
+        testlog "Running dtnds"
+        dtn::run_dtnd * $dtnd_exe
+        
+        testlog "Waiting for dtnds to start up"
+        dtn::wait_for_dtnd *
+
+        #dtn::dump_routes
+        
+        if {$testopt(mode) == "dtn"} {
+            testlog "Running dtn receiver"
+            set rcvpid [dtn::run_app $last dtnrecv \
+                    "-q -n $testopt(count) -o $dstdir/testfile#####.data ${dst_eid}*" $dtnrecv_exe]
+        }
+
+        if {$testopt(mode) == "dtntunnel"} {
+            testlog "Running dtn tunnels"
+            set expiration [expr $testopt(test_max) * 60]
+            set tun1pid [dtn::run_app 0 dtntunnel \
+                    "-t -T 17600:localhost:17601 -e $expiration dtn://host-$last/dtntunnel" $dtntunnel_exe]
+            set tun2pid [dtn::run_app $last dtntunnel "-L -e $expiration" $dtntunnel_exe]
+        }
+    }
+    
+    if {$testopt(mode) == "ftp" && $testopt(hop_mode) == "hop"}  {
+        testlog "Running packet proxies"
+        foreach id [net::nodelist] {
+            if {$id == 0 || $id == $last} { continue }
+            set proxypid_$id [dtn::run_app $id pproxy "-d node-[expr $id + 1] -p 17600 -l 17600 -v 2" $pproxy_exe]
+        }
+    }
+    
+    if {$testopt(mode) == "ftp"} {
+        testlog "Running ftp server"
+        set ftp_server_pid [dtn::run_app $last simple-ftp.tcl "server"]
+    }
+
+    if {$testopt(mode) == "dtntunnel"} {
+        testlog "Running ftp server"
+        set ftp_server_pid [dtn::run_app $last simple-ftp.tcl "server -port 17601"]
+    }
+
+    if {$testopt(mode) == "mail"} {
+        testlog "Setting up sendmail config"
+        if [catch {
+            cd emulab/mail
+            exec ./sendmail-install.sh $emulab_test $N $testopt(hop_mode) >&@stdout
+            cd ../..
+        } err] {
+            puts "error installing sendmail conf: $err"
+            exit 1
+        }
+
+        testlog "Dumping mailq"
+        catch {
+            foreach id [net::nodelist] {
+                set output [run::run_cmd $net::host($id) sudo mailq]
+                puts $output
+            }
+        }
+        
+        testlog "Cleaning delivery directory"
+        run::run_cmd $net::host($last) rm -rf /tmp/test-delivery
+        run::run_cmd $net::host($last) mkdir  /tmp/test-delivery
+        run::run_cmd $net::host($last) rm -f /tmp/delivery_count
+    }
+
+    #
+    # Set up the iptables blocking script
+    #
+    if {$testopt(conn) != "conn"} {
+        testlog "Setting up iptables port blocking"
+        switch $testopt(mode) {
+            dtn - dtntunnel    { set port [dtn::get_port tcp $last] }
+            ftp                { set port 17600 }
+            mail               { set port 25 }
+        }
+        
+        if {$testopt(conn) == "onelink"} {
+            iptables::add_port $last $port fixed [list 60 60 0]
+        }
+        
+        if {$testopt(conn) == "all"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 60 0]
+            }
+        }
+        
+        if {$testopt(conn) == "shift"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 60 [expr 60 - ($id * 15)]]
+            }
+        }
+
+        if {$testopt(conn) == "shift4"} {
+            for {set id 1} {$id < [expr $N - 1]} {incr id} {
+                iptables::add_port $id $port fixed [list 240 240 [expr 240 - $id * 60]]
+            }
+            iptables::add_port [expr $N - 1] $port fixed [list 240 240 0]
+        }
+
+        if {$testopt(conn) == "offset"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 60 [expr ($id % 2) * 60]]
+            }
+        }
+
+        if {$testopt(conn) == "all2"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 180 0]
+            }
+        }
+       
+        if {$testopt(conn) == "offset2"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 180 [expr (($id + 1) % 2) * 120]]
+            }
+        }
+
+        if {$testopt(conn) == "sequential"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 180 [expr ($id-1) * 60]]
+            }
+        }
+
+        if {$testopt(conn) == "shift10"} {
+            for {set id 1} {$id < $N} {incr id} {
+                iptables::add_port $id $port fixed [list 60 180 [expr ($id-1) * 10]]
+            }
+        }
+
+        iptables::run_async
+    }
+    
+    #
+    # Start the clock
+    #
+    set starttime [clock seconds]
+    puts "START: $starttime"
+
+    #
+    # Copy phase
+    #
+    if {$testopt(mode) == "dtn"} {
+        testlog "Running dtnsend for $testopt(count) iterations"
+        set sndpid [dtn::run_app 0 dtnsend "-s $src_eid -d $dst_eid -t t -p $file \
+                -n $testopt(count) -z $testopt(sleep)" $dtnsend_exe]
+
+        testlog "Waiting for senders / receivers to complete (up to $testopt(test_max) mins)"
+        
+        set loop_start [clock seconds]
+        set elapsed_mins 0
+        do_until "waiting for data to flow" [expr $testopt(test_max) * 60] {
+            if {[run::check_pid $net::host($last) $rcvpid] == 0} {
+                break
+            }
+
+            set elapsed [expr ([clock seconds] - $loop_start) / 60]
+            if {$elapsed > $elapsed_mins} {
+                set elapsed_mins $elapsed
+                
+                testlog "$elapsed_mins minutes elapsed... dumping stats"
+                foreach n [net::nodelist] {
+                    puts "Node $n stats: [tell_dtnd $n bundle stats]"
+                }
+            }
+
+            after 500
+        }
+
+        testlog "All bundles received..."
+        dtn::dump_stats
+        
+    } elseif {$testopt(mode) == "ftp" || $testopt(mode) == "dtntunnel"} {
+
+        if {$testopt(mode) == "dtntunnel"} {
+            set dest localhost
+            set timeout 0
+            
+        } else {
+            # ftp mode
+            set timeout 30000
+            if {$testopt(conn) == "conn"} {
+                puts "XXX Overriding timeout for connected mode"
+                set timeout 0
+            }
+            
+            if {$testopt(hop_mode) == "hop"} {
+                set dest $net::internal_host(1)
+                
+            } else {
+                set dest $net::internal_host($last)
+            }
+        }
+
+        puts "Running ftp client..."
+        set ftp_client_pid [dtn::run_app 0 simple-ftp.tcl \
+                "client $file $testopt(count) $dest -port 17600 -timeout $timeout"]
+
+        set loop_start [clock seconds]
+        set elapsed_mins 0
+        do_until "waiting for data to flow" [expr $testopt(test_max) * 60] {
+            if {[run::check_pid $net::host(0) $ftp_client_pid] == 0} {
+                break
+            }
+
+            set elapsed [expr ([clock seconds] - $loop_start) / 60]
+            if {$elapsed > $elapsed_mins} {
+                set elapsed_mins $elapsed
+                
+                testlog "$elapsed_mins minutes elapsed... "
+                if {$testopt(mode) == "dtntunnel"} {
+                    foreach n [net::nodelist] {
+                        puts "Node $n stats: [tell_dtnd $n bundle stats]"
+                    }
+                }
+            }
+            
+            after 500
+        }
+
+        testlog "All files sent..."
+
+    } elseif {$testopt(mode) == "mail"} {
+        puts "Running mail injector..."
+        
+        set mail_dest "$user@$net::host($last)"
+        dtn::run_app 0 send-mail.tcl "$file $testopt(count) $mail_dest"
+
+        set loop_start [clock seconds]
+        set elapsed_mins 0
+            
+        do_until "waiting for mail to flow" [expr $testopt(test_max) * 60] {
+            set num -1
+            if [catch {
+                set num [run::run_cmd $net::host($last) cat /tmp/delivery_count]
+            } err] {
+                puts "warning: reading delivery number: $err"
+            }
+            
+            if {$num == $testopt(count)} {
+                puts "all $num messages delivered"
+                break
+            }
+            
+            set elapsed [expr ([clock seconds] - $loop_start) / 60]
+            if {$elapsed > $elapsed_mins} {
+                set elapsed_mins $elapsed
+                
+                testlog "$elapsed_mins minutes elapsed... "
+                testlog "$num messages delivered"
+            }
+
+            after 500
+        }
+    }
+
+    set endtime [clock seconds]
+    puts "END: $endtime"
+
+    puts "ELAPSED: [expr [clock seconds] - $starttime]"
+    if {$testopt(mode) == "dtn" || $testopt(mode) == "dtntunnel"} {
+        puts "making sure that no bundles are pending in the network..."
+        foreach id [net::nodelist] {
+            dtn::wait_for_bundle_stats $id {0 pending}
+        }
+    }
+    
+    if {$testopt(mode) == "dtn"} {
+        puts "checking that exactly $testopt(count) bundles were delivered..."
+        dtn::wait_for_bundle_stats $last [list 0 pending $testopt(count) delivered]
+    }
+}
+
+test::exit_script {
+    if {$testopt(emulab_test) != ""} {
+        testlog "Getting final packet counts:"
+        emulab_get_stats end
+        emulab_stat_diff start end
+    }
+    
+    if {$testopt(mode) == "ftp" || $testopt(mode) == "dtntunnel"} {
+        testlog "Stopping ftp server"
+        run::kill_pid $last $ftp_server_pid TERM
+    }
+
+    if {$testopt(mode) == "dtntunnel"} {
+        testlog "Stopping dtntunnels"
+        run::kill_pid 0     $tun1pid TERM
+        run::kill_pid $last $tun2pid TERM
+    }
+
+    if {$testopt(mode) == "ftp" && $testopt(hop_mode) == "hop"}  {
+        testlog "Stopping packet proxies"
+        foreach id [net::nodelist] {
+            if {$id == 0 || $id == $last} { continue }
+            run::kill_pid $id proxypid_$id TERM
+        }
+    }
+
+    if {$testopt(mode) == "dtn" || $testopt(mode) == "dtntunnel"} {
+        testlog "Stopping all dtnds"
+        dtn::stop_dtnd *
+    }
+}