scriptroute 0.4.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,145 @@
1
+ module Scriptroute
2
+ module Tulip
3
+
4
+ class LossTrain
5
+ attr_reader :train;
6
+
7
+ def initialize(destination, intra_train, type, ttl)
8
+ @destination, @intra_train, @type, @ttl = destination, intra_train, type, ttl;
9
+ #(dsts, numpackets, intratrain, types, ttls, psizes, numtrains, intertrain)
10
+ @train = Train2.new([destination], 3, @intra_train, [type], [ttl], [-1, 1000, -1], 1, 0);
11
+ end
12
+
13
+ def isLossy?
14
+ return (@train.num_losses[0] > 0);
15
+ end
16
+
17
+ ##todo: principled treatment of pcapping
18
+ def wasPcapped?
19
+ @train.packets.each_index { |j|
20
+ @train.packets[0].each_index { |k|
21
+ pr = @train.packets[j][k];
22
+ return true if (!pr or !pr.probe or !pr.probe.time);
23
+ }
24
+ }
25
+ return false;
26
+ end
27
+
28
+ def to_s
29
+ str = "";
30
+ str += "losstrain #{@destination} #{@intra_train} #{@type} #{@ttl}\n";
31
+ @train.packets.each_index { |j|
32
+ @train.packets[0].each_index { |k|
33
+ pr = @train.packets[j][k];
34
+ if (pr and pr.probe and pr.probe.time) then
35
+ stime, sid = pr.probe.time.to_f * 1000, pr.probe.packet.ip_id;
36
+ rtime = (pr.response) ? pr.response.time.to_f * 1000 : -1;
37
+ rid = (pr.response) ? pr.response.packet.ip_id : -1;
38
+ src = (pr.response)? pr.response.packet.ip_src : -1;
39
+ str += "#{src} %.3f +%.3fms %d %d\n" %[stime, rtime-stime, rid, sid];
40
+ else
41
+ str += "pcap overload\n";
42
+ end
43
+ }
44
+ }
45
+ return str;
46
+ end
47
+
48
+ end
49
+
50
+ class LossDoctor
51
+
52
+ def analyze (hopDetails)
53
+
54
+ hopDetails.each_index { |hop|
55
+ next if (!hopDetails[hop]);
56
+ details = hopDetails[hop];
57
+
58
+ valid = @total[hop] - @undesiredLosses[hop];
59
+ # printf("%d. %s ", $global_tpath.path[hop].hop, details[4]);
60
+ printf("%s ", $global_tpath.path[hop]);
61
+ printf("(ejected) ") if (@ejected.has_key?(hop));
62
+ rt = @total[hop] - @undesiredLosses[hop] - @noLosses[hop];
63
+ printf("rt=%.3f (%d/%d) ",(valid==0)? 0 : rt.to_f/valid, rt, valid);
64
+ if (details[3]) then
65
+ printf("fw=%.3f (%d/%d) ", @forwardLosses[hop].to_f/valid, @forwardLosses[hop], valid);
66
+ consec = @noLosses[hop] - @reorderedResponses[hop];
67
+ consecR = (consec==0)? 0 : @consecutiveIPIDs[hop].to_f/consec;
68
+ printf("co=%.3f (%d/%d) ", consecR, @consecutiveIPIDs[hop], consec);
69
+ printf("ro=%.3f (%d/%d)", @reorderedResponses[hop].to_f/@noLosses[hop], @reorderedResponses[hop], @noLosses[hop]);
70
+ end
71
+ puts "";
72
+ }
73
+ end
74
+
75
+ def initialize (hopDetails)
76
+ @total = Hash.new(0);
77
+ @noLosses = Hash.new(0);
78
+ @undesiredLosses = Hash.new(0);
79
+ @forwardLosses = Hash.new(0);
80
+ @reorderedResponses = Hash.new(0);
81
+ @consecutiveIPIDs = Hash.new(0);
82
+ @ejected = Hash.new(0);
83
+
84
+
85
+ (0..$count-1).each { |num|
86
+ startTime = Time.now;
87
+ hopDetails.each_index { |i|
88
+
89
+ next if (!hopDetails[i] or @ejected.has_key?(i));
90
+ details = hopDetails[i];
91
+
92
+ #(destination, intra_train, type, ttl)
93
+ train = LossTrain.new(details[0], $spread/1000.0, details[2], details[1]);
94
+ puts "#{train}\n" if ($verbose>=10);
95
+
96
+ @total[i] += 1;
97
+ pkts = train.train.packets[0];
98
+
99
+ next if (train.wasPcapped?);
100
+
101
+ if (!train.isLossy?) then
102
+ @noLosses[i] += 1;
103
+ if (details[3]) then
104
+ ids = pkts.map { |p| p.response.packet.ip_id };
105
+ if (ids[1] < ids[0] or ids[2] < ids[1]) then
106
+ @reorderedResponses[i] += 1 if (ids[1] != 0); #don't count routers that return 0 for big probes
107
+ end
108
+ if (ids[0] + 1 == ids[1] and ids[1] + 1 == ids[2]) then
109
+ @consecutiveIPIDs[i] += 1;
110
+ end
111
+ end
112
+ else
113
+ if (!pkts[0].response or !pkts[2].response) then
114
+ @undesiredLosses[i] += 1;
115
+ else
116
+ id0 = pkts[0].response.packet.ip_id;
117
+ id2 = pkts[2].response.packet.ip_id;
118
+ if (id0 == id2 - 1) then
119
+ @forwardLosses[i] += 1;
120
+ end
121
+ end
122
+ if (@noLosses[i] <= 0.25*@total[i] and @total[i] >= 10) then
123
+ @ejected[i] = 1;
124
+ end
125
+ end
126
+ }
127
+
128
+ if ($printFrequency > 0 and (num+1) % $printFrequency == 0 and num != $count-1 ) then
129
+ puts " ---- after #{num+1} measurements ----";
130
+ analyze(hopDetails);
131
+ end
132
+
133
+ sleepTime = startTime + $lag/1000.0 - Time.now;
134
+ if (sleepTime > 0) then Kernel.sleep(sleepTime); end
135
+ }
136
+
137
+ puts " ---- after #{$count} measurements ----";
138
+ analyze(hopDetails);
139
+
140
+ end
141
+ end
142
+
143
+
144
+ end
145
+ end
@@ -0,0 +1,248 @@
1
+ module Scriptroute
2
+ module Tulip
3
+
4
+
5
+ class QueueTrain
6
+ attr_reader :train;
7
+
8
+ def initialize(dst, type, ttl)
9
+ #(dsts, numpackets, resolution, types, ttls, shuffle=false)
10
+ #@train = Train.new([dst], 2, 0, [type], [ttl]);
11
+ @train = Train.new([dst], 1, 0, [type], [ttl]);
12
+ end
13
+
14
+ def isLossy?
15
+ ##losing one of the two timestamps all the time is ok.
16
+ return (@train.num_losses[0] > 1);
17
+ end
18
+
19
+ # def to_s
20
+ # return @train.to_s;
21
+ # end
22
+
23
+ def to_s
24
+ str = "queuetrain: #{@train.dsts} (#{@train.types})\n";
25
+ @train.packets[0].each_index { |i|
26
+ (@train.dsts).each_index { |j|
27
+ pr = @train.packets[j][i];
28
+ stime = pr.probe.time.to_f * 1000;
29
+ rtt = (pr.probe and pr.response) ? (pr.response.time - pr.probe.time) * 1000 : -1;
30
+ str += "#{@train.dsts[j]} %.3fms %.3f " %[rtt, stime];
31
+ if (@train.types[j] == "tstamp") then
32
+ rem_time = (pr.response)? pr.response.packet.icmp_ttime : 0;
33
+ str += "#{rem_time}";
34
+ end
35
+ }
36
+ str += "\n";
37
+ }
38
+ return str;
39
+ end
40
+
41
+ end
42
+
43
+ def convertByteOrder(wrong)
44
+ right = Array.new();
45
+ right[0], right[1], right[2], right[3] = wrong & 255,
46
+ (wrong & (255 << 8)) >> 8,
47
+ (wrong & (255 << 16)) >> 16,
48
+ (wrong & (255 << 24)) >> 24;
49
+ out = ( (right[0] << 24) + (right[1] << 16) + (right[2] << 8) + right[3]);
50
+ #puts "#{wrong} #{out} #{right.join(" ")}\n";
51
+ return out;
52
+ end
53
+
54
+ def fixByteOrder (stamps)
55
+ if (stamps.length > 4 and
56
+ (stamps[0][1] > stamps[1][1] or
57
+ stamps[1][1] > stamps[2][1] or
58
+ stamps[2][1] > stamps[3][1] or
59
+ stamps[3][1] > stamps[4][1]
60
+ )
61
+ ) then
62
+ triplets = Array.new();
63
+ stamps.each_index { |i|
64
+ triplets[i] = Array.new();
65
+ triplets[i][0] = stamps[i][0];
66
+ triplets[i][1] = convertByteOrder(stamps[i][1]);
67
+ triplets[i][2] = stamps[i][2]; ## a better way to do this would be to insert in converted byte order
68
+ }
69
+ return triplets;
70
+ end
71
+ return stamps;
72
+ end
73
+
74
+ def computeRTMed (stamps)
75
+ rtts = Array.new();
76
+ stamps.each { |stamp|
77
+ rtts.push(stamp[2] - stamp[0]);
78
+ }
79
+ rtts.sort!;
80
+ if (rtts.length > 0)
81
+ medianDiff = rtts[rtts.length/2] - rtts[0];
82
+ return [medianDiff, rtts.first, rtts.last];
83
+ else
84
+ return -100;
85
+ end
86
+ end
87
+
88
+ def computeFWMedCing (triplets)
89
+ # triplets = Array.new();
90
+ oldsend, oldrcv = 0,0;
91
+ # stamps.each { |stamp|
92
+ # triplets.push(stamp);
93
+ # }
94
+
95
+ ENV['datalinepattern'] ="newexp";
96
+ ENV['fieldseparator'] = ":";
97
+ ENV['hostfieldnum'] = "3";
98
+ ENV['sentfieldnum'] = "6";
99
+ ENV['receivedfieldnum'] = "7";
100
+ ENV['bouncedfieldnum'] = "9";
101
+ ENV['segmentsecs'] = "12";
102
+ ENV['writefixeddir'] = "./";
103
+ ENV['sourceskew'] = "-";
104
+ ENV['target'] = "1.1.1.1";
105
+ ENV['showquality'] = "1";
106
+
107
+ pid = Process.pid;
108
+ tmp = File.new("/tmp/fixLC.#{pid}", "w");
109
+
110
+ if (triplets.length == 0) then
111
+ return -100;
112
+ end
113
+
114
+ base = triplets[0][0];
115
+ triplets.each_index { |j|
116
+ tup = triplets[j];
117
+ tmp.puts "0.000:newexp:1.1.1.1:%u:0:%u:%u:0:%u" %[j, tup[0] - base, tup[1], tup[2] - base];
118
+ }
119
+ tmp.close();
120
+ cmd = sprintf("#{FIXCLOCK} /tmp/fixLC.#{pid}");
121
+ output = `#{cmd}`.split("\n");
122
+ match = nil;
123
+ quality = [nil, nil];
124
+ output.each { |o|
125
+ if ( o =~ "inferred stdroundtrip" ) then
126
+ words = o.split;
127
+ quality = [words[4], words[6]];
128
+ end
129
+ }
130
+
131
+ otts = Array.new();
132
+ rejected = 0;
133
+ tmp = File.new("./fixLC.#{pid}.fix");
134
+ tmp.each { |line|
135
+ words = line.split(":");
136
+ snd,rem,zero,rcv = words[5..8].map { |i| i.to_i; }
137
+ # if (snd <= rem and rem <= rcv) then
138
+ otts.push(rem - snd);
139
+ # else
140
+ # rejected += 1;
141
+ # end
142
+ }
143
+ tmp.close();
144
+ File.delete("/tmp/fixLC.#{pid}", "./fixLC.#{pid}.fix", "./fixLC.#{pid}.rej");
145
+
146
+ #puts "conglib-warning: rejected #{rejected} cing corrections\n" if (rejected > 0);
147
+
148
+ otts.sort!;
149
+ #STDERR.puts "WARNING: too few ott samples: #{otts.length}" if (otts.length < 5);
150
+
151
+ medianDiff = (otts.length > 0)? (otts[otts.length/2] - otts[0]) : -100;
152
+ #puts "otts (#{otts.length}, #{medianDiff}): #{otts.join(" ")}";
153
+ return [[medianDiff, otts.last], quality];
154
+ end
155
+
156
+
157
+ class QueuingDoctor
158
+
159
+ def validOTT (ott, rtt)
160
+ return false if (ott < 0);
161
+ #return false if (ott > 3 and rtt < 1);
162
+ #return false if (ott > rtt/2);
163
+ return true;
164
+ end
165
+
166
+ def analyze (hopDetails)
167
+
168
+ hopDetails.each_index { |hop|
169
+ next if (!hopDetails[hop]);
170
+ details = hopDetails[hop];
171
+
172
+ valid = @total[hop] - @ratelimited[hop];
173
+ # printf("%d. %s ", $global_tpath.path[hop].hop, details[4]);
174
+ printf("%s ", $global_tpath.path[hop]);
175
+ printf("(ejected) ") if (@ejected.has_key?(hop));
176
+ round = computeRTMed(@stamps[hop]);
177
+ printf("rt: median=%.3f min=%.3f max=%.3f ", round[0]+round[1], round[1], round[2]);
178
+ if (details[3]) then
179
+ triplets = fixByteOrder(@stamps[hop]);
180
+ cing = computeFWMedCing(triplets);
181
+ q = (cing[1][1].to_f==0)? 1 : cing[1][0].to_f/cing[1][1].to_f;
182
+ if (validOTT(cing[0][0], round[0])) then
183
+ printf("fw: median=%.3f max=%s quality=%.3f (%s/%s)", cing[0][0], cing[0][1], q, cing[1][0], cing[1][1]);
184
+ else
185
+ printf("fw: median=-1 max=-1 quality=-1");
186
+ end
187
+ end
188
+ puts "";
189
+ }
190
+ end
191
+
192
+ def initialize (hopDetails)
193
+
194
+ @total = Hash.new(0);
195
+ @ratelimited = Hash.new(0)
196
+ @stamps = Hash.new();
197
+ hopDetails.each_index { |i| @stamps[i] = Array.new() if (hopDetails[i]);}
198
+ @ejected = Hash.new();
199
+
200
+ ##todo: implement the correlation thingy
201
+ @pairs = Hash.new();
202
+
203
+ (0..$count-1).each { |num|
204
+ startTime = Time.now;
205
+ hopDetails.each_index { |i|
206
+
207
+ next if (!hopDetails[i] or @ejected.has_key?(i));
208
+ details = hopDetails[i];
209
+
210
+ #(dst, types, ttl)
211
+
212
+ #puts "before train = %.3f" % [Time.now.to_f*1000];
213
+ train = QueueTrain.new(details[0], details[2], details[1]);
214
+ #puts "after train = %.3f" % [Time.now.to_f*1000];
215
+
216
+ puts "#{train}\n" if ($verbose>=10);
217
+
218
+ @total[i] += 1;
219
+ if (train.isLossy?) then
220
+ @ratelimited[i] += 1;
221
+ @ejected[i] = 1 if (@ratelimited[i] >= 0.5*@total[i] and @total[i] >= 10);
222
+ else
223
+ p = train.train.packets[0][0];
224
+ if (p and p.probe and p.response and p.probe.time and p.response.time) then
225
+ @stamps[i].push([p.probe.time.to_f * 1000.0, p.response.packet.icmp_ttime, p.response.time.to_f*1000.0]);
226
+ else
227
+ @total[i] -= 1;
228
+ end
229
+ end
230
+ }
231
+
232
+ if ($printFrequency > 0 and (num+1) % $printFrequency == 0 and num != $count-1) then
233
+ puts " ---- after #{num+1} measurements ----";
234
+ analyze(hopDetails);
235
+ end
236
+
237
+ sleepTime = startTime + $lag/1000.0 - Time.now;
238
+ #puts "sleep = #{sleepTime} %.3f" % [Time.now.to_f*1000];
239
+ if (sleepTime > 0 and num != $count-1) then Kernel.sleep(sleepTime); end
240
+ }
241
+
242
+ puts " ---- after #{$count} measurements ----";
243
+ analyze(hopDetails);
244
+ end
245
+ end
246
+
247
+ end
248
+ end
@@ -0,0 +1,129 @@
1
+ module Scriptroute
2
+ module Tulip
3
+
4
+
5
+ class ReordTrain
6
+ attr_reader :destination,:intra_train, :type, :ttl, :train;
7
+
8
+ def initialize(destination, intra_train, type, ttl)
9
+ @destination, @intra_train, @type, @ttl =
10
+ destination, intra_train, type, ttl;
11
+
12
+ #(dsts, numpackets, resolution, types, ttls, shuffle=false)
13
+ @train = Train.new([@destination], 2, @intra_train, [@type], [@ttl]);
14
+ end
15
+
16
+ def isLossy?
17
+ return (@train.num_losses[0] > 0);
18
+ end
19
+
20
+ def isRTro?
21
+ return false if (isLossy?);
22
+ rt1, rt2 = [0,1].map { |v| @train.packets[0][v].response.time; }
23
+ (rt1 > rt2)? true : false;
24
+ end
25
+
26
+ def isFWro?
27
+ return false if (isLossy?);
28
+ id1, id2 = [0,1].map { |v| @train.packets[0][v].response.packet.ip_id; }
29
+ (id1 > id2)? true : false;
30
+ end
31
+
32
+ def wasPcapped?
33
+ @train.packets[0].each_index { |k|
34
+ pr = @train.packets[0][k];
35
+ return true if (!pr or !pr.probe or !pr.probe.time)
36
+ }
37
+ return false;
38
+ end
39
+
40
+ def to_s
41
+ str = "";
42
+ str += "reordtrain %s %s %s %s\n" % [@destination, @ttl, @type, @intra_train];
43
+ @train.packets[0].each_index { |k|
44
+ pr = @train.packets[0][k];
45
+ stime, sid = pr.probe.time.to_f * 1000, pr.probe.packet.ip_id;
46
+ rtime = (pr.response) ? pr.response.time.to_f * 1000 : -1;
47
+ sid = pr.probe.packet.ip_id;
48
+ rid = (pr.response) ? pr.response.packet.ip_id : -1;
49
+ src = (pr.response)? pr.response.packet.ip_src : -1;
50
+ str += "#{src} %.3f +%.3fms %d %d" %[stime, rtime-stime, rid, sid];
51
+ str += "\n";
52
+ }
53
+ return str;
54
+ end
55
+ end
56
+
57
+
58
+ class ReorderingDoctor
59
+
60
+ def analyze (hopDetails)
61
+
62
+ hopDetails.each_index { |hop|
63
+ next if (!hopDetails[hop]);
64
+ details = hopDetails[hop];
65
+
66
+ valid = 1.0*@total[hop] - @ratelimited[hop];
67
+ # printf("%d. %s ", $global_tpath.path[hop].hop, details[4]);
68
+ printf("%s ", $global_tpath.path[hop]);
69
+ # printf("%d. %s %s ", $global_tpath.path[hop].hop, IPSocket.getname($global_tpath.path[hop].hop), details[4]);
70
+ printf("(ejected) ") if (@ejected.has_key?(hop));
71
+ printf("rt=%.3f (%d/%d) ", @rtreord[hop].to_f/valid, @rtreord[hop], valid);
72
+ if (details[3]) then
73
+ printf("fw=%.3f (%d/%d)\n", @fwreord[hop].to_f/valid, @fwreord[hop], valid)
74
+ else
75
+ printf("\n")
76
+ end
77
+ }
78
+ end
79
+
80
+ def initialize (hopDetails)
81
+
82
+ @total = Hash.new(0);
83
+ @fwreord = Hash.new(0);
84
+ @rtreord = Hash.new(0);
85
+ @ratelimited = Hash.new(0)
86
+ @ejected = Hash.new(0);
87
+
88
+ (0..$count-1).each { |num|
89
+ startTime = Time.now;
90
+ hopDetails.each_index { |i|
91
+
92
+ next if (!hopDetails[i] or @ejected.has_key?(i));
93
+ details = hopDetails[i];
94
+
95
+ #(destination, intra_train, type, ttl)
96
+ train = ReordTrain.new(details[0], $spread/1000.0, details[2], details[1]);
97
+ puts "#{train}\n" if ($verbose>=10);
98
+
99
+ next if (train.wasPcapped?);
100
+
101
+ @total[i] += 1;
102
+ if (train.isLossy?) then
103
+ @ratelimited[i] += 1;
104
+ if ($skipRTrtrs and @ratelimited[i] >= 0.5*@total[i] and @total[i] >= 10) then
105
+ @ejected[i] = 1;
106
+ end
107
+ else
108
+ @fwreord[i] += (train.isFWro?)? 1 : 0
109
+ @rtreord[i] += (train.isRTro?)? 1 : 0
110
+ end
111
+ }
112
+
113
+ if ($printFrequency > 0 and (num+1) % $printFrequency == 0 and num != $count-1) then
114
+ puts " ---- after #{num+1} measurements ----";
115
+ analyze(hopDetails);
116
+ end
117
+
118
+ sleepTime = startTime + $lag/1000.0 - Time.now;
119
+ if (sleepTime > 0) then Kernel.sleep(sleepTime); end
120
+ }
121
+
122
+ puts " ---- after #{$count} measurements ----";
123
+ analyze(hopDetails);
124
+
125
+ end
126
+ end
127
+
128
+ end
129
+ end