class Scriptroute::Tulip::Train

generic train ################

Attributes

dsts[R]
num_losses[R]
numpackets[R]
packets[R]
resolution[R]
reverse_ttls[R]
shuffle[R]
ttls[R]
types[R]

Public Class Methods

new(dsts, numpackets, resolution, types, ttls, shuffle=false) click to toggle source
# File lib/scriptroute/tulip/helper.rb, line 312
def initialize(dsts, numpackets, resolution, types, ttls, shuffle=false) 
  @dsts, @numpackets, @resolution, @types, @ttls, @shuffle = dsts, numpackets, resolution, types, ttls, shuffle;
  @reverse_ttls, @rem_srcs, @num_losses, @packets = Array.new(), Array.new(), Array.new(), Array.new();
  (@dsts).each_index { |i| 
    @packets[i], @reverse_ttls[i], @rem_srcs[i], @num_losses[i] = Array.new(),  Array.new(), Array.new(), 0;
  }

  num_dsts = @dsts.length;
  max_train = (MAX_TRAIN/num_dsts).floor;
  seq_id = 0; order = 0;
  allResponsePackets = Array.new();
  ( 0 .. (numpackets/max_train).ceil ).each { |trainnum|
    packetsThisRound = (numpackets < (trainnum+1)*max_train)? (numpackets - trainnum*max_train) : max_train;
    delayedPackets = Array.new();
    ( seq_id .. seq_id + packetsThisRound-1).each { |rep|
      
      ##construct probe packets
      probes = Array.new();
      (@dsts).each_index { |i|
        case types[i]
        when "tcp"
          probes[i] = Scriptroute::TCP.new(12);
        when "udp"
          probes[i] = Scriptroute::UDP.new(12);
          probes[i].uh_dport = 33444 ## unknown effect; five-tuple balancing may occur
        when "echo"
          probes[i] = Scriptroute::ICMP.new(0)
          probes[i].icmp_type = Scriptroute::ICMP::ICMP_ECHO;
          probes[i].icmp_code = 0;
          probes[i].icmp_seq = rep;
        when "tstamp"
          probes[i] = Scriptroute::ICMP.new(0)
          probes[i].icmp_type = Scriptroute::ICMP::ICMP_TSTAMP;
          probes[i].icmp_code = 0;
          probes[i].icmp_seq = rep;
        else 
          raise("ERROR: unsupported packettype #{types[i]} in sendAndReceiveTrain\n");
        end  
        probes[i].ip_ttl = @ttls[i];
        probes[i].ip_dst = @dsts[i];
        @dsts[i] = probes[i].ip_dst; # accomplishes a name lookup so responses can be classified - nspring

      }

      ##insert probe packets in the order desired
      (@dsts).each_index { |i|
        delay = (i==0)? resolution : 0;
        #puts "delay: #{delay} (#{i})";
        insert = (order + i) % num_dsts;
        delayedPackets.push(Struct::DelayedPacket.new(delay, probes[insert]));
        order = (order + 1) % num_dsts if (@shuffle);
      }        
    } ##each rep

    #puts "before real =  %.3f" % [Time.now.to_f*1000];
    allResponsePackets.push(Scriptroute::send_train(delayedPackets));
    #puts "after real =  %.3f" % [Time.now.to_f*1000];

  } ##each trainnum
  allResponsePackets.flatten!
  #allResponsePackets.sort!{ |a,b| a.probe.time <=> b.probe.time }

  allResponsePackets.each { |pr|
    if (pr and pr.probe and pr.probe.time) 
      i = getIndex(pr);
      @packets[i].push(pr);
      if (pr.response) then
        @reverse_ttls[i].push(pr.response.packet.ip_ttl) if !@reverse_ttls[i].index(pr.response.packet.ip_ttl);
        @rem_srcs[i].push(pr.response.packet.ip_src) if !@rem_srcs[i].index(pr.response.packet.ip_src);
      else
        @num_losses[i] += 1;
      end
    end
  }

  # nspring thinks the following is a no-op.
  (@dsts).each_index { |i| 
    @packets[i].sort! { |a,b| a.probe.time <=> b.probe.time }
  }

  ##check sanity of the train
  (@dsts).each_index { |i|
    if (@reverse_ttls[i].length > 1) 
      puts "WARNING: too many reverse TTLs for index #{i}: #{@reverse_ttls[i].join(" ")}";
    end
    
    if (@rem_srcs[i].length > 1) 
      puts "WARNING: too many remote sources for index #{i}: #{@rem_srcs[i].join(" ")}";
    end

    ##todo: should really check a pattern in losses
    ##      to distinguish between high loss rate and rate-limiting
    if (@num_losses[i] > 0.2*@numpackets) 
      #STDERR.puts "WARNING: too many losses #{@num_losses[i]} for index #{i}";
    end
  }

end

Public Instance Methods

getIndex(pr) click to toggle source
# File lib/scriptroute/tulip/helper.rb, line 300
def getIndex (pr)
  pkt = pr.probe.packet;
  @dsts.each_index { |i|
    if (pkt.ip_dst == @dsts[i] and  
        pkt.ip_ttl == @ttls[i] and 
        getType(pkt) == @types[i]) 
      return i;
    end
  }
  raise "ERROR: could not classify packet: #{pkt.to_s}";
end
getType(pkt) click to toggle source
# File lib/scriptroute/tulip/helper.rb, line 285
def getType (pkt) 
  if (pkt.is_a?(Scriptroute::TCP)) 
    return "tcp";
  elsif (pkt.is_a?(Scriptroute::UDP)) 
    return "udp";
  elsif (pkt.is_a?(Scriptroute::ICMP))
    if (pkt.icmp_type == Scriptroute::ICMP::ICMP_ECHO)
      return "echo";
    elsif (pkt.icmp_type == Scriptroute::ICMP::ICMP_TSTAMP)
      return "tstamp";
    end
  end
  raise "ERROR: unknown packet type: #{pkt.to_s}";
end
to_s() click to toggle source
# File lib/scriptroute/tulip/helper.rb, line 411
def to_s
  str = "train: #{@dsts} #{@numpackets} #{@resolution} (#{@types}) (#{@ttls})\n";
  @packets[0].each_index { |i| 
    (@dsts).each_index { |j|
      pr = @packets[j][i];
      stime = pr.probe.time.to_f * 1000;
      srcid = pr.probe.packet.ip_id;
      rtt = (pr.probe and pr.response) ? (pr.response.time - pr.probe.time) * 1000 : -1;
      str += "#{@dsts[j]} %d %.3f %d " %[rtt, stime, srcid];
      if (@types[j] == "tstamp") then 
        rem_time =  (pr.response)? pr.response.packet.icmp_ttime : 0;
        ott = (pr.response)? stime - pr.response.packet.icmp_ttime : -1;
        str += "#{rem_time} %.3f " % [ott];
      end
    }
    str += "\n";
  }
  str += "losses: #{@num_losses.join(" ")}\n";
  return str;
end