traffic.tcl 13.5 KB
Newer Older
1
# -*- tcl -*-
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2000-2003, 2005, 2006 University of Utah and the Flux Group.
Leigh B. Stoller's avatar
Leigh B. Stoller committed
5
6
7
# All rights reserved.
#

Leigh B. Stoller's avatar
Leigh B. Stoller committed
8
9
10
11
12
13
14
######################################################################
# traffic.tcl
#
#
# This defines the various agents and applications needed to support
# traffic generation.  Specifically it defines Agent/UDP, Agent/Null,
# and Application/Traffic/CBR.
15
16
17
18
19
#
# Added: TCP traffic generation using NSE. Defines
# Agent/TCP/FullTcp, Agent/TCP/FullTcp/Reno, Agent/TCP/FullTcp/Newreno,
# Agent/TCP/FullTcp/Tahoe, Agent/TCP/FullTcp/Sack,
# Application/FTP and Application/Telnet
Leigh B. Stoller's avatar
Leigh B. Stoller committed
20
21
22
23
######################################################################

Class Agent -superclass NSObject
Class Agent/UDP -superclass Agent
24
Class Agent/TCP -superclass Agent
Leigh B. Stoller's avatar
Leigh B. Stoller committed
25
Class Agent/Null -superclass Agent
26
Class Agent/TCPSink -superclass Agent
27
28
29
30
31
Class Agent/TCP/FullTcp -superclass Agent
Class Agent/TCP/FullTcp/Reno -superclass Agent/TCP/FullTcp
Class Agent/TCP/FullTcp/Newreno -superclass Agent/TCP/FullTcp
Class Agent/TCP/FullTcp/Tahoe -superclass Agent/TCP/FullTcp
Class Agent/TCP/FullTcp/Sack -superclass Agent/TCP/FullTcp
Leigh B. Stoller's avatar
Leigh B. Stoller committed
32
33
34

Class Application -superclass NSObject
Class Application/Traffic/CBR -superclass Application
35
36
Class Application/FTP -superclass Application
Class Application/Telnet -superclass Application
37
Class Application/Program -superclass Application
Leigh B. Stoller's avatar
Leigh B. Stoller committed
38
39
40
41

namespace eval GLOBALS {
    set new_classes(Agent/UDP) {}
    set new_classes(Agent/Null) {}
42
    set new_classes(Agent/TCP) {}
43
    set new_classes(Agent/TCPSink) {}
44
45
46
47
48
    set new_classes(Agent/TCP/FullTcp) {}
    set new_classes(Agent/TCP/FullTcp/Reno) {}
    set new_classes(Agent/TCP/FullTcp/Newreno) {}
    set new_classes(Agent/TCP/FullTcp/Tahoe) {}
    set new_classes(Agent/TCP/FullTcp/Sack) {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
49
    set new_classes(Application/Traffic/CBR) {}
50
51
    set new_classes(Application/FTP) {}
    set new_classes(Application/Telnet) {}
52
53
54
55
56
57
58
59
60
61
62
63

    # When generating NSE Traffic Generator code, need to ignore
    # testbed specific variables
    set ignore_nsetrafgen_classvars(destination) {}
    set ignore_nsetrafgen_classvars(application) {}
    set ignore_nsetrafgen_classvars(role) {}
    set ignore_nsetrafgen_classvars(proto) {}
    set ignore_nsetrafgen_classvars(port) {}
    set ignore_nsetrafgen_classvars(node) {}
    set ignore_nsetrafgen_classvars(simulated) {}
    set ignore_nsetrafgen_classvars(generator) {}
    set ignore_nsetrafgen_classvars(osid) {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
64
65
66
67
68
}

# Agent
Agent instproc init {} {
    $self set node {}
69
70
71
    # Which link (interface) on the node this agent is attached to.
    # If not set, default to the only one we currently allow.
    $self set link {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
72
73
    $self set application {}
    $self set destination {}
74
75
76
    $self set proto {}
    $self set role {}
    $self set port {}
77
    $self set generator "TG"
78
79
    global ::GLOBALS::last_class
    set ::GLOBALS::last_class $self
80
    if { ${::GLOBALS::simulated} == 1 } {
81
82
83
84
	$self set simulated 1
    } else {
	$self set simulated 0
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
85
86
87
}
Agent instproc set_node {node} {
    $self set node $node
88
    $self set port [$node next_portnumber]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
89
}
90
91
92
93
Agent instproc get_node {} {
    $self instvar node
    return $node
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
94
95
Agent instproc set_application {application} { 
    $self set application $application
96
97
    $self set role [$application set role]
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
98
99
100
101
}
Agent instproc connect {dst} {
    $self instvar destination
    if {$destination != {}} {
102
	puts stderr "*** WARNING: \[connect] $self is already connected to $destination"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
103
104
105
    }
    set destination $dst
}
106
107
108
109
110
111
112
Agent instproc rename {old new} {
    $self instvar application
    # In normal conditions this will never occur.
    if {$application != {}} {
	$application set agent $new
    }
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
113

114
115
116
117
118
# updatedb DB
# This adds rows to the virt_trafgens table corresponding to this agent.
Agent instproc updatedb {DB} {
    var_import ::GLOBALS::pid
    var_import ::GLOBALS::eid
119
    var_import ::TBCOMPAT::objtypes
120
121
122
123
124
    $self instvar application
    $self instvar destination
    $self instvar node
    $self instvar proto
    $self instvar role
125
    $self instvar generator
126
    $self instvar port
127
    $self instvar link
128
    $self instvar simulated
129

130
131
132
133
    if {$node == {}} {
	perror "\[updatedb] $self is not attached to a node."
	return
    }
134
135
136
137
138
139
140
141
    if {$role == {}} {
	perror "\[updatedb] $self has no role."
	return
    }
    if {$destination == {}} {
	perror "\[updatedb] $self has no destination."
	return
    }
142
143
144
145
    if { ($role == "source") && ($application == {}) } {
        perror "\[updatedb] $self does not have an attached application."
        return
    }
146
147
148
    set target_vnode [$destination set node]
    set target_port [$destination set port]

149
    # At some point allow users to set link. For now, first link (0).
150
151
    set ip [$node ip 0]
    set target_ip [$target_vnode ip 0]
152

153
    if {$role == "sink"} {
154
	set application $self
155
	set proto [$destination set proto]
156
157
158
	set target_vname [$destination set application]
    } else {
	set target_vname $destination
159
160
    }

161
162
163
    if { $simulated == 0 } {
	# Update the DB
	spitxml_data "virt_trafgens" [list "vnode" "vname" "role" "proto" "port" "ip" "target_vnode" "target_vname" "target_port" "target_ip" "generator" ] [list $node $application $role $proto $port $ip $target_vnode $target_vname $target_port $target_ip $generator ]
164

165
166
	spitxml_data "virt_agents" [list "vnode" "vname" "objecttype" ] [list $node $application $objtypes(TRAFGEN)]
    }
167
168
169
170
171
172
}

# get_nseconfig is only defined for subclasses that will be simulated by NSE
# Will be called from Node updatedb
Agent instproc get_nseconfig {} {
   return ""
173
174
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
175
176
177
# Agent/UDP 
Agent/UDP instproc connect {dst} {
    $self next $dst
178
    $self set proto "udp"
179
    $self set role "source"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
180
181
}

182
183
184
185
# Agent/TCP
Agent/TCP instproc connect {dst} {
    $self next $dst
    $self set proto "tcp"
186
    $self set role "source"
187
188
}

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# Agent/TCP/FullTcp
Agent/TCP/FullTcp instproc init args {

    eval $self next $args
    $self set simulated 1
    $self set tcptype ""
    $self set segsize_ 1460
    $self set role "source" 
    $self set generator "NSE"
}

# Agent/TCP/FullTcp/Newreno
Agent/TCP/FullTcp/Newreno instproc init args {
    eval $self next $args
    $self set tcptype "Newreno"
}

# Agent/TCP/FullTcp/Tahoe
Agent/TCP/FullTcp/Tahoe instproc init args {
    eval $self next $args
    $self set tcptype "Tahoe"
}

# Agent/TCP/FullTcp/Sack
Agent/TCP/FullTcp/Sack instproc init args {
    eval $self next $args
    $self set tcptype "Sack"
}

# Agent/TCP/FullTcp
Agent/TCP/FullTcp instproc listen {} {

   $self set role "sink"

}

# updatedb DB
# This adds rows to the virt_trafgens table corresponding to this agent.
# We do things differently from the base class version. For NSE, the
# vname in the table is the FullTcp agent object and not the application
# object connected to it. The important thing is using "$ns at", we can
# send events and control any of these objects
Agent/TCP/FullTcp instproc updatedb {DB} {
    var_import ::GLOBALS::pid
    var_import ::GLOBALS::eid
234
    var_import ::TBCOMPAT::objtypes
235
236
237
238
239
240
241
    $self instvar application
    $self instvar destination
    $self instvar node
    $self instvar proto
    $self instvar role
    $self instvar generator
    $self instvar port
242
    $self instvar link
243
    var_import ::GLOBALS::simulated
244

245
246
247
248
    if {$node == {}} {
	perror "\[updatedb] $self is not attached to a node."
	return
    }
249
250
251
252
253
254
255
256
    if {$role == {}} {
	perror "\[updatedb] $self has no role."
	return
    }
    if {$destination == {}} {
	perror "\[updatedb] $self has no destination."
	return
    }
257
258
259
260
    if { ($role == "source") && ($application == {}) } {
        perror "\[updatedb] $self does not have an attached application."
        return
    }
261
262
263
    set target_vnode [$destination set node]
    set target_port [$destination set port]

264
265
266
267
    # At some point allow users to set link. For now, first link (0).
    set ip [$node ip 0]
    set target_ip [$target_vnode ip 0]

268
    set vname $self
269
    set target_vname $destination
270

271
272
273
    if { $simulated == 0 } {
	# Update the DB
	spitxml_data "virt_trafgens" [list "vnode" "vname" "role" "proto" "port" "ip" "target_vnode" "target_vname" "target_port" "target_ip" "generator" ] [list  $node $vname $role $proto $port $ip $target_vnode $target_vname $target_port $target_ip $generator]
274

275
276
277
278
279
	spitxml_data "virt_agents" [list "vnode" "vname" "objecttype"] [list $node $vname $objtypes(NSE) ]

	if {$application != {}} {
	    spitxml_data "virt_agents" [list "vnode" "vname" "objecttype" ] [list $node $application $objtypes(NSE) ]
	}
280
    }
281
282
283
284
285
286
287
288
289
}

# Agent/TCP/FullTcp
Agent/TCP/FullTcp instproc get_nseconfig {} {

    $self instvar tcptype
    $self instvar role
    $self instvar simulated
    $self instvar application
290
    var_import ::GLOBALS::ignore_nsetrafgen_classvars
291
292
293
294
295
296
297
298
299
    
    set nseconfig ""

    # This agent could possibly be a real one in which case
    # we don't do NSE traffic generation
    if { $simulated != 1 } {
         return $nseconfig
    }

300
301
302
    # we set a global variable to indicate that NSE trafgen
    # is present so that nseinput.tcl can take appropriate
    # action
303
    if { ($tcptype == "") || ($tcptype == "Reno") } {
304
          append nseconfig "set $self \[new Agent/TCP/FullTcp]\n"
305
    } else {
306
          append nseconfig "set $self \[new Agent/TCP/FullTcp/$tcptype]\n"
307
    }
308
    append nseconfig "\$\{$self\} set tbname \{$self\}\n"
309

310
    if { $role == "sink" } {
311
         append nseconfig "\$\{$self\} listen\n\n"
312
313
314
315
316
317
    }

    # We end up including variables present only in TB parser. However
    # that does not matter coz all NS variables end with _ character
    # Pruning can be done later
    foreach var [$self info vars] {
318
319
320
	   if { [info exists ignore_nsetrafgen_classvars($var)] } {
	        continue
	   }
321
           if { [$self set $var] != {} } {
322
             append nseconfig "\$\{$self\} set $var [$self set $var]\n"
323
324
           }
    }
325
    append nseconfig "\n"
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341

    if { $application != {} } {
         append nseconfig [$application get_nseconfig]
    } 

    return $nseconfig
}


# Agent/TCP/FullTcp
Agent/TCP/FullTcp instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
    $self instvar role
342
    var_import ::GLOBALS::sim_osname
343
344
345

    $self set proto "tcp"
    $dst set proto "tcp"
346
347
    $node set osid $sim_osname
    $dst set osid $sim_osname
348
349
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
350
351
352
# Agent/Null
Agent/Null instproc connect {dst} {
    $self next $dst
353
    $self set role "sink"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
354
355
}

356
# Agent/Null
357
Agent/TCPSink instproc connect {dst} {
358
359
360
361
362
    $self next $dst
    $self set role "sink"
    $self set proto "tcp"
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
363
364
365
# Application
Application instproc init {} {
    $self set agent {}
366
    $self set role {}
367
368
    global ::GLOBALS::last_class
    set ::GLOBALS::last_class $self
369
370
371
372
373
374
    var_import ::GLOBALS::simulated
    if { $simulated == 1 } {
	$self set simulated 1
    } else {
	$self set simulated 0
    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
375
376
377
378
379
}
Application instproc attach-agent {agent} {
    $self set agent $agent
    $agent set_application $self
}
380
381
Application instproc get_node {} {
    $self instvar agent
382
383
384
385
    if {$agent == {} } {
	perror "\[Application get_node] $self is not attached to an agent."
	return ""
    }
386
387
    return [$agent get_node]
}
388
389
Application instproc rename {old new} {
    $self instvar agent
390
    # In normal condition this will never occur.
391
392
393
394
    if {$agent != {}} {
	$agent set_application $self
    }
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
395
396
397
398
399
400

# Application/Traffic/CBR
Application/Traffic/CBR instproc init {} {
    $self set packetSize_ 210
    $self set rate_ "100Mbps"
    $self set interval_ {}
401
    $self set iptos_ {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
402
    $self next
403
404
405
406
407
408
409
410
    
    $self set role "source"
}

Application/Traffic/CBR instproc get_params {} {
    $self instvar packetSize_
    $self instvar rate_
    $self instvar interval_
411
    $self instvar iptos_
412
413

    if {$rate_ != {} && $rate_ != 0} {
414
	set rate [parse_bw $rate_ 0]
415
416
417
418
419
420
421
422
423
424
    } else {
	set rate -1
    }
    set param "PACKETSIZE=$packetSize_ RATE=$rate"

    if {$interval_ != {} && $interval_ != 0} {
	set param "$param INTERVAL=$interval_"
    } else {
	set param "$param INTERVAL=-1"
    }
425
426

    if {$iptos_ != {} && $iptos_ != 0} {
427
	set param "$param IPTOS=$iptos_"
428
    } else {
429
	set param "$param IPTOS=-1"
430
431
    }

432
    return $param
Leigh B. Stoller's avatar
Leigh B. Stoller committed
433
}
434
435
436
437
438
439
440
441
442
443
444
445
446

# Application/FTP
Application/FTP instproc init {} {
    $self next
   
    $self set role "source"
}

# Application/FTP
Application/FTP instproc get_nseconfig {} {

    $self instvar agent
    set nseconfig "set $self \[new Application/FTP]\n"
447
    
448
    append nseconfig "\$\{$self\} set tbname \{$self\}\n"
449
450

    if { $agent != {} } {
451
         append nseconfig "\$\{$self\} attach-agent \$$agent\n"
452
    }
453
    append nseconfig "\n"
454
455

    # XXX temporary untill event system changes get in
456
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482

   return $nseconfig
}

# Application/Telnet
Application/Telnet instproc init {} {
    $self next
    $self instvar role
    $self instvar interval_

    $self set role "source"

# NS's default is 1.0 and therefore would result in inter-packet times
# to be chosen from the exponential distribution. If it is 0, it would
# be chosen based on the tcplib distribution. I differ from NS in my
# default because of the realism of tcplib distribution
    $self set interval_ 0.0
}

# Application/Telnet
Application/Telnet instproc get_nseconfig {} {
   
    $self instvar agent
    $self instvar interval_

    set nseconfig "set $self \[new Application/Telnet]\n"
483

484
    append nseconfig "\$\{$self\} set tbname \{$self\}\n"
485
               
486
    append nseconfig "\$\{$self\} set interval_ $interval_\n"
487
    if { $agent != {} } {
488
         append nseconfig "\$\{$self\} attach-agent \$$agent\n"
489
    }
490
    append nseconfig "\n"
491
492
        
    # XXX temporary untill event system changes get in
493
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
494
495
496

    return $nseconfig
}
497