wiki:WiMAX/TeltonikaOmfDriver
close Warning: Can't synchronize with repository "(default)" (/common/SVN/wimax does not appear to be a Subversion repository.). Look in the Trac log for more information.

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.595GHz 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 (on the node)

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 = @dip = @subnet = @nm = @fnm = @gw = @routip = @oldroutip = @oldnetmask = nil;
    @deldef = false
    $chflag = 0 
  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.cmd("/bin/iptables -t nat -F") { |c| print c }
    host.close
  end
 
  def telnet_dynamicIP
    debug "Configuring iptables for dynamic IP"
    host = Net::Telnet::new("Host" => "192.168.0.1",
                             "Timeout" => 10,
                             "Port" => 700,
                             "Prompt" => /[$%#>] \z/n)
    host.login("admin", "admin01") { |c| print c }
 
    begin
      str = host.cmd("ifconfig icc0") { |c| print c }
      #get the dynamic IP address: 
      lines = str.split("\n")
      lines=lines.drop(2)
      lines=lines.reverse.drop(6).reverse 
      vals=lines.collect { |row|
        column = row.split(" ")
        column[1]
      }
 
      addr=vals[0]
      addrAr=addr.split("\:")
      dynIP=addrAr[1]    
    end while "#{dynIP}" <= ""
    host.close
 
    debug "Dynamic IP is: #{dynIP} \n" 
    #add the rules to the iptables:
    rule1 = "/bin/iptables -t nat -A PREROUTING -p udp -d #{dynIP} -j DNAT --to 192.168.0.8"
    rule2 = "/bin/iptables -t nat -A PREROUTING -p tcp -d #{dynIP} -j DNAT --to 192.168.0.8"
    debug "Running #{rule1} \n"
    debug "Running #{rule2} \n"
   #second telnet session to add the rules:
    host = Net::Telnet::new("Host" => "192.168.0.1",
                             "Timeout" => 10,
                             "Port" => 700,
                             "Prompt" => /[$%#>] \z/n)
    host.login("admin", "admin01") { |c| print c }
    begin
      host.cmd("#{rule1}") { |c| print c }
      host.cmd("#{rule2}") { |c| print c }
      rtrn = host.cmd("/bin/iptables -t nat -L") { |c| print c }
    end while !(rtrn.include? "192.168.0.8")
    host.close
    return dynIP
  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.cmd("/bin/iptables -t nat -A PREROUTING -p udp -d #{ip} -j DNAT --to 192.168.0.8"){ |c| print c }
    host.cmd("/bin/iptables -t nat -A PREROUTING -p tcp -d #{ip} -j DNAT --to 192.168.0.8"){ |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 = @dip = @subnet = @nm = @gw = nil
    @ifconfig = '/sbin/ifconfig'
    @wget = '/usr/bin/wget'
    @route = '/sbin/route'
    @deldef = false
    $chflag = 0
    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"
        $chflag = 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?
      when :dynip
        return nil if @dip.nil?
        if $chflag == 1
          comRes = telnet_dynamicIP
        else
          raise "CONNECT THE DEVICE (setup the channel first!) BEFORE ASSIGNING AN IP..."
        end
        cmd = nil        
    else
      raise "Unknown mode '#{@mode}'. Should be 'channel', 'mtu', gway, dynip, netmask, 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 "dynip"
        @mode = :dynip
        @dip = value
        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

These changes should be made on the OMF server where the EC runs. (If you plan to run experiments in OMF Disconnected Mode, you should also patch the EC on the node).

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]},
    "dynip=" => %r{net/[t][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"

If /etc/udev/rules.d/75-persistent-net-generator.rules exists, remove it so that your /etc/udev/rules.d/70-persistent-net.rules will not be overwritten. Make sure you have all the other rules you need (e.g. for Ethernet control interface) in /etc/udev/rules.d/70-persistent-net.rules because new ones will not be generated anymore.

Usage: Sample Scripts

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
Last modified 11 years ago Last modified on Mar 15, 2013, 3:38:46 AM
Note: See TracWiki for help on using the wiki.