[[TOC]] This driver adds functionality to OMF so that you can use a Teltonika WiMAX USB device in an OMF script. The syntax to connect to a WiMAX channel in OMF is (for example, if the center frequency of the channel is 2.59GHz and the channel bandwidth is 10MHz): {{{ node.net.t0.channel = "2595000,10" }}} Note: this work assumes default settings on the Teltonika device (e.g. default telnet settings, IP settings, etc.) == Installing the driver == === Patches to omf-resctl === In /usr/share/omf-resctl-5.3/omf-resctl/omf_agent/nodeAgent.rb: {{{ tel_count = 0 if (LSUSB) IO.popen("#{LSUSB} | grep 'Intel Corp. WiMAX Connection 2400m' | wc -l") {|u| wimax_count += u.gets.to_i } # Note: look for vendor:product rather than string to make sure usb-modeswitch works IO.popen("#{LSUSB} | grep '148e:099a' | wc -l") {|u| tel_count += u.gets.to_i } end if wimax_count > 0 require 'omf-resctl/omf_driver/wimaxcu' MObject.info "Found Intel WiMAX - using wimaxcu interface" AgentCommands::DEV_MAPPINGS['net/x0'] = WimaxcuDevice.new('net/x0', 'wmx0') AgentCommands::DEV_MAPPINGS['net/x1'] = WimaxcuDevice.new('net/x1', 'wmx1') end if tel_count > 0 require 'omf-resctl/omf_driver/teltonika' MObject.info "Found Teltonika WiMAX - using teltonika interface" AgentCommands::DEV_MAPPINGS['net/t0'] = TeltonikaDevice.new('net/t0', 'tel0') AgentCommands::DEV_MAPPINGS['net/t1'] = TeltonikaDevice.new('net/t1', 'tel1') end end }}} In /usr/share/omf-resctl-5.3/omf-resctl/omf_driver/teltonika.rb: {{{ # == Description # # This file defines the class TeltonikaDevice which is a sub-class of # WimaxcuDevice. # require 'omf-resctl/omf_driver/wimax' require 'net/telnet' require 'ipaddr' class TeltonikaDevice < WimaxDevice def unload # don't unload the kernel module #super() debug "Disconnecting WiMAX #{@deviceName}" dconnect = `#{@wget} --http-user admin --http-password admin -qO - "http://192.168.0.1/cgi/cli?stopSs"` clear = `#{@wget} --http-user admin --http-password admin -qO - "http://192.168.0.1/cgi/cli?clearScannerChannels"` if @deldef == false unroute = `#{@route} delete default gw 192.168.0.1` else unroute = `#{@route} del -net #{@routip} netmask #{@fnm} gw 192.168.0.1` end clearIP = deconfig @mode = @chnnl = @frequency = @bandwidth = @ip = @subnet = @nm = @fnm = @gw = @routip = @oldroutip = @oldnetmask = nil; @deldef = false end def deconfig host = Net::Telnet::new("Host" => "192.168.0.1", "Timeout" => 10, "Port" => 700, "Prompt" => /[$%#>] \z/n) host.login("admin", "admin01") { |c| print c } host.cmd("export interface=icc0"){ |c| print c } host.cmd("/etc/udhcpc.script deconfig"){ |c| print c } host.close end def telnetIfConf # If values are not set, use defaults ip = @ip || "0.0.0.0" netmask = @nm || "255.255.255.0" subnet = @subnet || 24 router = @gw || "" rip = IPAddr.new "#{ip}" @routip = rip.mask(subnet) deldef = @deldef if !deldef and ip != "0.0.0.0" tlres = "#{@route} del default gw 192.168.0.1; sleep 2; #{@route} add -net #{@routip} netmask #{netmask} gw 192.168.0.1" @deldef = true @oldroutip = @routip @oldnetmask = netmask end if netmask != "255.255.255.0" and deldef and ip != "0.0.0.0"#del route and add a new one if the netmask is different than the default tlres = "#{@route} del -net #{@oldroutip} netmask #{@oldnetmask} gw 192.168.0.1; sleep 2; #{@route} add -net #{@routip} netmask #{netmask} gw 192.168.0.1" end host = Net::Telnet::new("Host" => "192.168.0.1", "Timeout" => 10, "Port" => 700, "Prompt" => /[$%#>] \z/n) host.login("admin", "admin01") { |c| print c } host.cmd("ifconfig icc0 #{ip} netmask #{netmask}") { |c| print c } host.cmd("export ip=#{ip}"){ |c| print c } host.cmd("export subnet=#{subnet}"){ |c| print c } host.cmd("export interface=icc0"){ |c| print c } host.cmd("export router=#{router}"){ |c| print c } host.cmd("/etc/udhcpc.script bound"){ |c| print c } host.close @fnm = netmask #final netmask. This will be used in 'unload' return tlres end def initialize(logicalName, deviceName) super(logicalName, deviceName) @mode = @ip = @subnet = @nm = @gw = nil @ifconfig = '/sbin/ifconfig' @wget = '/usr/bin/wget' @route = '/sbin/route' @deldef = false IO.popen("#{@ifconfig} #{deviceName} 192.168.0.8 netmask 255.255.255.0") end def buildCmd return nil if @mode.nil? cmd = nil case @mode when :channel return nil if @chnnl.nil? cmd = "#{@wget} --http-user admin --http-password admin -qO - 'http://192.168.0.1/cgi/cli?stopSs'; #{@wget} --http-user admin --http-password admin -qO - 'http://192.168.0.1/cgi/cli?addChannel frequency=#{@frequency} bandwidth=#{@bandwidth}'; #{@wget} --http-user admin --http-password admin -qO - 'http://192.168.0.1/cgi/cli?startSs'; #{@route} add default gw 192.168.0.1" when :ip return nil if @ip.nil? comRes = telnetIfConf cmd = comRes unless comRes.nil? when :netmask return nil if @nm.nil? comRes = telnetIfConf cmd = comRes unless comRes.nil? when :gway return nil if @gw.nil? comRes = telnetIfConf cmd = comRes unless comRes.nil? else raise "Unknown mode '#{@mode}'. Should be 'initiate', 'channel', 'mtu' or 'ip'" end return cmd end # # Return the specific command required to configure a given property of this # device. When a property does not exist for this device, check if it does # for its super-class. # # - prop = the property to configure # - value = the value to configure that property to # def getConfigCmd(prop, value) @propertyList[prop.to_sym] = value case prop when "ip" #ifconfig 192... etc.. @mode = :ip @ip = value return buildCmd when "netmask" #ifconfig 192... etc.. @mode = :netmask @nm = value @subnet = IPAddr.new("#{@nm}").to_i.to_s(2).count("1") return buildCmd when "gway" @mode = :gway @gw = value return buildCmd when "channel" #assign a frequency and a bandwidth @mode = :channel @chnnl = value.split(/, */,2) @frequency = @chnnl[0] @bandwidth = @chnnl[1] return buildCmd end super end def get_property_value(prop) # Note: for now we are returning values set by a CONFIGURE command # when refactoring the device handling scheme, we may want to query # the system here to find out the real value of the property result = super(prop) #gets mac and ip addresses from ethernetDevice.rb result = @propertyList[prop] if !result return result end end }}} === Patches to omf-expctl === In /usr/share/omf-expctl-5.3/omf-expctl/node/nodeSetPath.rb: {{{ class NodeSetPath < MObject attr_reader :nodeSet, :path # List of valid 'PATHS' for a NodeSet VALID_PATHS_WITH_VALUES = { "mode=" => %r{net/[ew][01]}, "profile=" => %r{net/[x][01]}, "network=" => %r{net/[x][01]}, "type=" => %r{net/[ew][01]}, "rts=" => %r{net/[ew][01]}, "rate=" => %r{net/[ew][01]}, "essid=" => %r{net/[ew][01]}, "ip=" => %r{net/[ewxt][01]}, "channel=" => %r{net/[ewt][01]}, "tx_power=" => %r{net/[ew][01]}, "netmask=" => %r{net/[ewxt][01]}, "mac=" => %r{net/[ewx][01]}, "mtu=" => %r{net/[ewxt][01]}, "arp=" => %r{net/[ewx][01]}, "enforce_link=" => %r{net/[ewx][01]}, "route" => %r{net/[ewxt][01]}, "gway" => %r{net/[t][01]}, "filter" => %r{net/[ewx][01]}, "net" => // } VALID_PATHS_WITHOUT_VALUES = { "down" => %r{net/[ewxt][01]}, "up" => %r{net/[ewxt][01]}, } VALID_PATHS = VALID_PATHS_WITH_VALUES.merge(VALID_PATHS_WITHOUT_VALUES) VALID_PATHS_RE = { /[ewxt][01]/ => /net/ } }}} === Other required configuration on node === Install usb-modeswitch-data and usb-modeswitch (need recent version, >=1.1.9, such as the one provided for oneiric) In /etc/udev/rules.d/70-persistent-net.rules, add the following (so that teltonika device will get the name tel0): {{{ KERNEL=="eth*", DRIVERS=="cdc_ether", NAME="tel0" }}} == Usage: Sample Scripts == === With Dynamic Addressing === {{{ defProperty('runtime',20,"Time in second for the experiment is to run") defProperty('client',"128.238.66.220","IP address of iperf server") defProperty('interval', 1, "Interval of Iperf measurements") defProperty('sender', 'omf.witest.node10', "ID of sender node") defGroup('Group', property.sender) do |node| node.net.t0.channel = "2595000,10" node.net.t0.mtu=1470 node.addApplication("test:app:iperf") do |app| app.setProperty('client', property.client) app.setProperty('interval', property.interval) app.setProperty('time', property.runtime) app.measure('TCP_Info', :samples =>1) end end onEvent(:ALL_UP_AND_INSTALLED) do |event| wait 50 info "This is an iperf experiment using a teltonika modem" allGroups.startApplications wait property.runtime wait 2 allGroups.stopApplications wait 2 Experiment.done end }}} === With Static Addressing === {{{ defProperty('runtime',20,"Time in second for the experiment is to run") defProperty('client',"192.168.10.1","IP address of iperf server") defProperty('interval', 1, "Interval of Iperf measurements") defProperty('sender', 'omf.witest.node10', "ID of sender node") defProperty('sender', 'omf.witest.node1', "ID of sender node") defGroup('Group', property.sender) do |node| node.net.t0.channel = "2595000,10" node.net.t0.mtu=1470 node.net.t0.ip = "192.168.10.110" node.net.t0.netmask = "255.255.255.0" node.addApplication("test:app:iperf") do |app| app.setProperty('client', property.client) app.setProperty('interval', property.interval) app.setProperty('time', property.runtime) app.measure('TCP_Info', :samples =>1) end end defGroup('Group', property.receiver) do |node| node.net.x0.profile = '51' node.net.x0.ip = property.client node.net.x0.netmask = "255.255.255.0" node.addApplication("test:app:iperf") do |app| app.setProperty('server', true) app.setProperty('interval', property.interval) app.measure('TCP_Info', :samples =>1) end end onEvent(:ALL_UP_AND_INSTALLED) do |event| wait 50 info "This is an iperf experiment using a teltonika modem" allGroups.startApplications wait property.runtime wait 2 allGroups.stopApplications wait 2 Experiment.done end }}}