# # Author: Yasuhito Takamiya # # Copyright (C) 2008-2012 NEC Corporation # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License, version 2, as # published by the Free Software Foundation. # # 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. # $LOAD_PATH.unshift File.expand_path( File.join File.dirname( __FILE__ ), "ruby" ) $LOAD_PATH.unshift File.expand_path( File.join File.dirname( __FILE__ ), "vendor", "ruby-ifconfig-1.2", "lib" ) require "trema/executables" require "trema/path" require "trema/dsl/parser" import "c/dependencies" import "directedrule" ################################################################################ # Main tasks ################################################################################ desc "Build trema." task :default => [ :libtrema, :rubylib, :switch_manager, :switch, :packetin_filter, :tremashark, :packet_capture, :syslog_relay, :stdin_relay, :vendor, :examples ] task :examples => [ "examples:cbench_switch", "examples:dumper", "examples:hello_trema", "examples:learning_switch", "examples:list_switches", "examples:multi_learning_switch", "examples:openflow_message", "examples:packet_in", "examples:repeater_hub", "examples:packetin_filter_config", "examples:switch_info", "examples:switch_monitor", "examples:traffic_monitor", ] import "clean" desc "Cleanup generated files." gen Clean var[ :clean ] << Trema.objects var[ :clean ] << File.join( Trema.home, "objects/unittests" ) var[ :clean ] << File.join( Trema.home, "unittests/objects" ) var[ :clean ] << Trema::DSL::Context::PATH desc "Cleanup everything." task :distclean => :clean desc "Generate build.rb." task :buildrb do sys "rant-import --force --imports c/dependencies,directedrule,clean,sys/tgz build.rb" sys "chmod +x build.rb" end ################################################################################ # Helpers ################################################################################ def objects path File.join Trema.objects, path end def dependency name file = ".#{ name }.dependency" var[ :clean ] << file ".#{ name }.dependency" end ################################################################################ # !!!!!! DO NOT MODIFY !!!!!! ################################################################################ var :CFLAGS => "-g -std=gnu99 -D_GNU_SOURCE -fno-strict-aliasing -Werror -Wall -Wextra -Wformat=2 -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wfloat-equal -Wpointer-arith" ################################################################################ # Run cbench benchmarks. ################################################################################ def cbench_command File.join Trema.objects, "oflops/bin/cbench" end def cbench_latency_mode_options "--switches 1 --loops 10 --delay 1000" end def cbench_throughput_mode_options cbench_latency_mode_options + " --throughput" end def cbench controller, options begin sys "#{ controller }" sys "#{ cbench_command } #{ options }" ensure sys "./trema killall" end end def cbench_c_controller "./trema run ./objects/examples/cbench_switch/cbench_switch -d" end def cbench_ruby_controller "./trema run src/examples/cbench_switch/cbench-switch.rb -d" end def run_cbench controller cbench controller, cbench_latency_mode_options cbench controller, cbench_throughput_mode_options end var[ :clean ].include sys[ "callgrind.out.*" ] def cbench_profile options valgrind = "valgrind --tool=callgrind --trace-children=yes" begin sys "#{ valgrind } #{ cbench_c_controller }" sys "#{ cbench_command } #{ options }" ensure sys "./trema killall" end end desc "Run the c cbench switch controller to benchmark" task "cbench" => "cbench:c" desc "Run the c cbench switch controller to benchmark" task "cbench:c" => :default do | t | run_cbench cbench_c_controller end desc "Run the ruby cbench switch controller to benchmark" task "cbench:ruby" => :default do | t | run_cbench cbench_ruby_controller end desc "Run cbench with profiling enabled." task "cbench:profile" => :default do cbench_profile cbench_latency_mode_options cbench_profile cbench_throughput_mode_options end ################################################################################ # Build vendor/* ################################################################################ import "sys/tgz" task :vendor => [ "vendor:oflops", "vendor:openflow", "vendor:openvswitch", "vendor:phost", ] task :distclean => [ "vendor:cmockery:distclean", "vendor:oflops:distclean", "vendor:openflow:distclean", "vendor:openvswitch:distclean", "vendor:phost:distclean", ] # # OpenFlow reference implementation # gen Directory, Trema.objects task "vendor:openflow" => Trema.openflow_h file Trema.openflow_h => Trema.objects do sys.unpack_tgz "#{ Trema.vendor_openflow }.tar.gz", :in => Trema.vendor sys.cp_r "#{ Trema.vendor_openflow }/include/openflow", Trema.objects sys "chmod -R +r #{ File.join Trema.objects, "openflow" }" end task "vendor:openflow:distclean" do sys.rm_rf Trema.vendor_openflow end # # Use the Stanford openflow reference software to compile and copy the wireshark # plugin to enable viewing of openflow messages. # The plugin would be compiled and copied to your home directory # (.wireshark/plugins) if it is found, otherwise it is left for you to copy # from openflow.git/utilities/wireshark_dissectors/openflow directory # desc "Build openflow wireshark plugin" task :openflow_wireshark_plugin => Trema.vendor_openflow_git file Trema.vendor_openflow_git do | t | sys.unpack_tgz "#{ t.name }.tar.gz", :in => Trema.vendor subpath = "utilities/wireshark_dissectors/openflow" sys.cd "#{ Trema.vendor_openflow_git }/#{ subpath }" do sys "make" plugin_path = "#{ File.expand_path(" ~ ") }/.wireshark/plugins" sys.cp "packet-openflow.so", plugin_path if File.directory?( plugin_path ) end end task "openflow_wireshark_plugin:clean" => "openflow_wireshark_plugin:distclean" task "openflow_wireshark_plugin:distclean" do sys.rm_rf Trema.vendor_openflow_git end # # Open vSwitch # task "vendor:openvswitch" => Trema::Executables.ovs_openflowd file Trema::Executables.ovs_openflowd do sys.unpack_tgz "#{ Trema.vendor_openvswitch }.tar.gz", :in => Trema.vendor sys.cd Trema.vendor_openvswitch do sys "./configure --prefix=#{ Trema.openvswitch } --with-rundir=#{ Trema.sock }" sys "make install" sys "cp ./tests/test-openflowd #{ Trema::Executables.ovs_openflowd }" end end task "vendor:openvswitch:distclean" do sys.rm_rf Trema.vendor_openvswitch end # # oflops # task "vendor:oflops" => cbench_command file cbench_command => Trema.openflow_h do sys.unpack_tgz "#{ Trema.vendor_oflops }.tar.gz", :in => Trema.vendor sys.cd Trema.vendor_oflops do sys "./configure --prefix=#{ Trema.oflops } --with-openflow-src-dir=#{ Trema.vendor_openflow }" sys "make install" end end task "vendor:oflops:distclean" do sys.rm_rf Trema.vendor_oflops end # # phost # def phost_src File.join Trema.vendor_phost, "src" end task "vendor:phost" => [ Trema::Executables.phost, Trema::Executables.cli ] file Trema::Executables.phost do sys.cd phost_src do sys "make" end sys.mkdir_p File.dirname( Trema::Executables.phost ) sys.install File.join( phost_src, "phost" ), Trema::Executables.phost, :mode => 0755 end file Trema::Executables.cli do sys.cd phost_src do sys "make" end sys.mkdir_p File.dirname( Trema::Executables.cli ) sys.install File.join( phost_src, "cli" ), Trema::Executables.cli, :mode => 0755 end task "vendor:phost:distclean" do begin sys.cd phost_src do sys "make clean" end rescue # ignore. end end # # cmockery # task "vendor:cmockery" => Trema.libcmockery_a file Trema.libcmockery_a do sys.unpack_tgz "#{ Trema.vendor_cmockery }.tar.gz", :in => Trema.vendor sys.cd Trema::vendor_cmockery do sys "./configure --prefix=#{ Trema.cmockery }" sys "make install" end end task "vendor:cmockery:distclean" do sys.rm_rf Trema.vendor_cmockery end ################################################################################ # Build libtrema.a ################################################################################ build_libtrema_a = Proc.new do | t | sys "rm -f #{ t.name }" sys "ar -cq #{ t.name } #{ sys.sp t.prerequisites }" sys "ranlib #{ t.name }" end task dependency( "libtrema" ) => "vendor:openflow" gen C::Dependencies, dependency( "libtrema" ), :search => [ Trema.include, objects( "openflow" ) ], :sources => sys[ "#{ Trema.include }/*.c" ] gen Action do source dependency( "libtrema" ) end gen Directory, Trema.lib gen Directory, "#{ Trema.home }/objects/unittests" libtrema = File.join( Trema.lib, "libtrema.a" ) libtrema_gcov = File.join( "#{ Trema.home }/objects/unittests", "libtrema.a" ) libtrema_o = gen DirectedRule, Trema.lib => [ Trema.include ], :o => :c do | t | sys "gcc -I#{ objects "openflow" } #{ var :CFLAGS } -fPIC -c -o #{ t.name } #{ t.source }" end libtrema_gcov_o = gen DirectedRule, "#{ Trema.home }/objects/unittests" => [ Trema.include ], :o => :c do | t | sys "gcc --coverage -I#{ objects "openflow" } #{ var :CFLAGS } -fPIC -c -o #{ t.name } #{ t.source }" end desc "Build trema library." task :libtrema => libtrema file libtrema => libtrema_o.candidates do | t | build_libtrema_a.call t end desc "Build trema library (coverage)." task "coverage:libtrema" => libtrema_gcov file libtrema_gcov => libtrema_gcov_o.candidates do | t | build_libtrema_a.call t end ################################################################################ # Build trema.so (ruby library) ################################################################################ task :clean => "rubylib:clean" task :distclean => "rubylib:distclean" desc "Build ruby library." task :rubylib => "ruby/trema.so" file "ruby/trema.so" => FileList[ "ruby/trema/*.c", "ruby/trema/*.h", libtrema ] do sys.cd "ruby" do sys "ruby extconf.rb --with-trema-include=#{ Trema.include } --with-trema-lib=#{ Trema.lib } --with-openflow-include=#{ Trema.openflow }" sys "make" end end task "rubylib:clean" do sys.cd "ruby" do sys "make clean" rescue nil end end task "rubylib:distclean" do sys.rm_f "ruby/Makefile" end ################################################################################ # Build switch manager ################################################################################ switch_manager_objects_dir = objects( "switch_manager" ) gen C::Dependencies, dependency( "switch_manager" ), :search => [ "src/switch_manager", Trema.include ], :sources => sys[ "src/switch_manager/*.c" ] gen Action do source dependency( "switch_manager" ) end gen Directory, switch_manager_objects_dir gen DirectedRule, switch_manager_objects_dir => [ "src/switch_manager" ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end switch_manager_objects = [ "dpid_table.o", "switch_manager.o", "secure_channel_listener.o" ].collect do | each | File.join switch_manager_objects_dir, each end desc "Build switch manager." task :switch_manager => Trema::Executables.switch_manager file Trema::Executables.switch_manager => switch_manager_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpthread" end switch_objects = [ "cookie_table.o", "ofpmsg_recv.o", "ofpmsg_send.o", "secure_channel_receiver.o", "secure_channel_sender.o", "service_interface.o", "switch.o", "xid_table.o", ].collect do | each | File.join switch_manager_objects_dir, each end desc "Build switch." task :switch => Trema::Executables.switch file Trema::Executables.switch => switch_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpthread" end ################################################################################ # Build packetin filter ################################################################################ gen C::Dependencies, dependency( "packetin_filter" ), :search => [ "src/packetin_filter", Trema.include ], :sources => sys[ "src/packetin_filter/*.c" ] gen Action do source dependency( "packetin_filter" ) end gen Directory, objects( "packetin_filter" ) packetin_filter_objects = gen DirectedRule, objects( "packetin_filter" ) => [ "src/packetin_filter" ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end desc "Build packetin filter." task :packetin_filter => Trema::Executables.packetin_filter file Trema::Executables.packetin_filter => packetin_filter_objects.candidates + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lpthread -lsqlite3 -ldl -lrt" end ################################################################################ # tremashark ################################################################################ tremashark_objects_dir = objects( "tremashark" ) gen C::Dependencies, dependency( "tremashark" ), :search => [ "src/tremashark", Trema.include ], :sources => sys[ "src/tremashark/*.c" ] gen Action do source dependency( "tremashark" ) end gen Directory, tremashark_objects_dir gen DirectedRule, tremashark_objects_dir => [ "src/tremashark" ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end tremashark_objects = [ "pcap_queue.o", "queue.o", "tremashark.o", ].collect do | each | File.join tremashark_objects_dir, each end desc "Build tremashark." task :tremashark => Trema::Executables.tremashark file Trema::Executables.tremashark => tremashark_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpcap -lpthread" end packet_capture_objects = [ "packet_capture.o", "queue.o", ].collect do | each | File.join tremashark_objects_dir, each end desc "Build packet_capture." task :packet_capture => Trema::Executables.packet_capture file Trema::Executables.packet_capture => packet_capture_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpcap -lpthread" end syslog_relay_objects = [ "syslog_relay.o", ].collect do | each | File.join tremashark_objects_dir, each end desc "Build syslog_relay." task :syslog_relay => Trema::Executables.syslog_relay file Trema::Executables.syslog_relay => syslog_relay_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpcap -lpthread" end stdin_relay_objects = [ "stdin_relay.o", ].collect do | each | File.join tremashark_objects_dir, each end desc "Build stdin_relay." task :stdin_relay => Trema::Executables.stdin_relay file Trema::Executables.stdin_relay => stdin_relay_objects + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpcap -lpthread" end ################################################################################ # Build standalone examples ################################################################################ standalone_examples = [ "cbench_switch", "dumper", "hello_trema", "learning_switch", "list_switches", "multi_learning_switch", "packet_in", "repeater_hub", "switch_info", "switch_monitor", "traffic_monitor", ] standalone_examples.each do | each | objects_dir = objects( "examples/#{ each }" ) target = objects( "examples/#{ each }/#{ each }" ) gen C::Dependencies, dependency( each ), :search => [ "src/examples/#{ each }", Trema.include ], :sources => sys[ "src/examples/#{ each }/*.c" ] gen Action do source dependency( each ) end gen Directory, objects_dir objects = gen DirectedRule, objects_dir => [ "src/examples/#{ each }" ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end desc "Build #{ each } example." task "examples:#{ each }" => target file target => objects.candidates + [ libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ sys.sp t.prerequisites } -ltrema -lsqlite3 -ldl -lrt -lpthread" end end ################################################################################ # Build openflow messages ################################################################################ openflow_messages = [ "echo_reply", "echo_request", "features_request", "hello", "set_config", ] openflow_message_source_dir = "src/examples/openflow_message" openflow_message_objects_dir = objects( "examples/openflow_message" ) gen C::Dependencies, dependency( "openflow_message" ), :search => [ Trema.include ], :sources => sys[ "#{ openflow_message_source_dir }/*.c" ] gen Action do source dependency( "openflow_message" ) end gen Directory, openflow_message_objects_dir gen DirectedRule, openflow_message_objects_dir => [ openflow_message_source_dir ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end openflow_messages.each do | each | target = File.join( openflow_message_objects_dir, each ) task "examples:openflow_message" => target file target => [ File.join( openflow_message_objects_dir, "#{ each }.o" ), libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ t.source } -ltrema -lsqlite3 -ldl -lrt -lpthread" end end ################################################################################ # Build packetin_filter_config ################################################################################ packetin_filter_config = [ "add_filter", "delete_filter", "delete_filter_strict", "dump_filter", "dump_filter_strict", ] packetin_filter_config_source_dir = "src/examples/packetin_filter_config" packetin_filter_config_objects_dir = objects( "examples/packetin_filter_config" ) gen C::Dependencies, dependency( "packetin_filter_config" ), :search => [ Trema.include ], :sources => sys[ "#{ packetin_filter_config_source_dir }/*.c" ] gen Action do source dependency( "packetin_filter_config" ) end gen Directory, packetin_filter_config_objects_dir gen DirectedRule, packetin_filter_config_objects_dir => [ packetin_filter_config_source_dir ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end packetin_filter_config.each do | each | packetin_filter_config_utils_o = File.join( packetin_filter_config_objects_dir, "utils.o" ) target = File.join( packetin_filter_config_objects_dir, each ) task "examples:packetin_filter_config" => target file target => [ File.join( packetin_filter_config_objects_dir, "#{ each }.o" ), packetin_filter_config_utils_o, libtrema ] do | t | sys "gcc -L#{ Trema.lib } -o #{ t.name } #{ t.source } #{ packetin_filter_config_utils_o } -ltrema -lsqlite3 -ldl -lrt -lpthread" end end ################################################################################ # Unit tests. ################################################################################ def libtrema_unit_tests { :byteorder_test => [ :log, :utility, :wrapper, :trema_wrapper ], :daemon_test => [], :ether_test => [ :buffer, :log, :utility, :wrapper, :trema_wrapper ], :messenger_test => [ :doubly_linked_list, :hash_table, :event_handler, :linked_list, :utility, :wrapper, :timer, :log, :trema_wrapper ], :openflow_application_interface_test => [ :buffer, :byteorder, :hash_table, :doubly_linked_list, :linked_list, :log, :openflow_message, :packet_info, :stat, :trema_wrapper, :utility, :wrapper ], :openflow_message_test => [ :buffer, :byteorder, :linked_list, :log, :packet_info, :utility, :wrapper, :trema_wrapper ], :packet_info_test => [ :buffer, :log, :utility, :wrapper, :trema_wrapper ], :stat_test => [ :hash_table, :doubly_linked_list, :log, :utility, :wrapper, :trema_wrapper ], :timer_test => [ :log, :utility, :wrapper, :doubly_linked_list, :trema_wrapper ], :trema_test => [ :utility, :log, :wrapper, :doubly_linked_list, :trema_private, :trema_wrapper ], } end def test_object_files test names = [ test.to_s.gsub( /_test$/, "" ) ] + libtrema_unit_tests[ test ] names.collect do | each | if each == :buffer [ "unittests/objects/buffer.o", "unittests/objects/buffer_stubs.o" ] elsif each == :wrapper [ "unittests/objects/wrapper.o", "unittests/objects/wrapper_stubs.o" ] else "unittests/objects/#{ each }.o" end end.flatten end gen C::Dependencies, dependency( "unittests" ), :search => [ Trema.include, "unittests" ], :sources => sys[ "unittests/lib/*.c", "src/lib/*.c" ] gen Action do source dependency( "unittests" ) end gen Directory, "unittests/objects" gen Directory, "objects/unittests" gen DirectedRule, "unittests/objects" => [ "unittests", "unittests/lib", "src/lib" ], :o => :c do | t | sys "gcc -I#{ Trema.include } -I#{ Trema.openflow } -I#{ File.dirname Trema.cmockery_h } -Iunittests -DUNIT_TESTING --coverage #{ var :CFLAGS } -c -o #{ t.name } #{ t.source }" end libtrema_unit_tests.keys.each do | each | target = "unittests/objects/#{ each }" task :build_old_unittests => target task target => "vendor:cmockery" file target => test_object_files( each ) + [ "#{ target }.o" ] do | t | sys "gcc -L#{ File.dirname Trema.libcmockery_a } -o #{ t.name } #{ sys.sp t.prerequisites } -DUNIT_TESTING -lrt -lcmockery -lsqlite3 -ldl -lpthread --coverage --static" end end # new unittest tests = [ "objects/unittests/buffer_test", "objects/unittests/doubly_linked_list_test", "objects/unittests/ether_test", "objects/unittests/hash_table_test", "objects/unittests/linked_list_test", "objects/unittests/log_test", "objects/unittests/packetin_filter_interface_test", "objects/unittests/packet_info_test", "objects/unittests/packet_parser_test", "objects/unittests/persistent_storage_test", "objects/unittests/trema_private_test", "objects/unittests/utility_test", "objects/unittests/wrapper_test", "objects/unittests/match_table_test", "objects/unittests/message_queue_test", ] file "objects/unittests/cmockery_trema.o" do | t | sys "gcc --coverage -c unittests/#{ File.basename t.name, ".o" }.c -o #{ t.name } #{ var :CFLAGS } -I#{ Trema.include } -I#{ File.dirname Trema.cmockery_h } -Iunittests" end tests.each do | each | task :build_unittests => [ "coverage:libtrema", each ] task each => [ "coverage:libtrema", "vendor:cmockery", "objects/unittests/cmockery_trema.o", "#{ Trema.home }/objects/unittests" ] file each => "unittests/lib/#{ File.basename each }.c" do | t | sys "gcc --coverage -c unittests/lib/#{ File.basename t.name }.c -o #{ each }.o #{ var :CFLAGS } -I#{ Trema.include } -I#{ Trema.openflow } -I#{ File.dirname Trema.cmockery_h } -Iunittests" sys "gcc --coverage -o #{ t.name } #{ each }.o objects/unittests/cmockery_trema.o -Lobjects/unittests -L#{ File.dirname Trema.libcmockery_a } -ltrema -lrt -lcmockery -lsqlite3 -ldl -lpthread --static" end end desc "Run unittests" task :unittests => [ :build_old_unittests, :build_unittests ] do ( sys[ "unittests/objects/*_test" ] + tests ).each do | each | puts "Running #{ each }..." sys each end end ################################################################################ # TODO, FIXME etc. ################################################################################ desc "Print list of notes." task :notes do keywords = [ "TODO", "FIXME", "XXX" ] keywords.each do | key | system "find src unittests -name '*.c' | xargs grep -n #{ key }" system "find ruby spec features -name '*.rb' | xargs grep -n #{ key }" end end ### Local variables: ### mode: Ruby ### coding: utf-8-unix ### indent-tabs-mode: nil ### End: