traffic.tcl 15.4 KB
Newer Older
1
# -*- tcl -*-
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
4
5
6
7
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# 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) {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
52
53
54
55
56
}

# Agent
Agent instproc init {} {
    $self set node {}
57
58
59
    # 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
60
61
    $self set application {}
    $self set destination {}
62
63
64
    $self set proto {}
    $self set role {}
    $self set port {}
65
    $self set generator "TG"
66
67
    global ::GLOBALS::last_class
    set ::GLOBALS::last_class $self
Leigh B. Stoller's avatar
Leigh B. Stoller committed
68
69
70
}
Agent instproc set_node {node} {
    $self set node $node
71
    $self set port [$node next_portnumber]
Leigh B. Stoller's avatar
Leigh B. Stoller committed
72
}
73
74
75
76
Agent instproc get_node {} {
    $self instvar node
    return $node
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
77
78
Agent instproc set_application {application} { 
    $self set application $application
79
80
    $self set role [$application set role]
    
Leigh B. Stoller's avatar
Leigh B. Stoller committed
81
82
83
84
}
Agent instproc connect {dst} {
    $self instvar destination
    if {$destination != {}} {
85
	perror "\[connect] $self already has a destination: $destination."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
86
87
88
89
	return
    }
    set destination $dst
}
90
91
92
93
94
95
96
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
97

98
99
100
101
102
# 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
103
    var_import ::GLOBALS::objtypes
104
105
106
107
108
    $self instvar application
    $self instvar destination
    $self instvar node
    $self instvar proto
    $self instvar role
109
    $self instvar generator
110
    $self instvar port
111
    $self instvar link
112
113
114
115
116
117
118
119
120
121
122
123

    if {$role == {}} {
	perror "\[updatedb] $self has no role."
	return
    }
    if {$destination == {}} {
	perror "\[updatedb] $self has no destination."
	return
    }
    set target_vnode [$destination set node]
    set target_port [$destination set port]

124
125
126
127
    # 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]

128
    if {$role == "sink"} {
129
	set application $self
130
	set proto [$destination set proto]
131
132
133
	set target_vname [$destination set application]
    } else {
	set target_vname $destination
134
135
136
    }

    # Update the DB
137
    sql exec $DB "insert into virt_trafgens (pid,eid,vnode,vname,role,proto,port,ip,target_vnode,target_vname,target_port,target_ip,generator) values ('$pid','$eid','$node','$application','$role','$proto',$port,'$ip','$target_vnode','$target_vname',$target_port,'$target_ip','$generator')";
138

139
    sql exec $DB "insert into virt_agents (pid,eid,vnode,vname,objecttype) values ('$pid','$eid','$node','$application','$objtypes(TRAFGEN)')";
140
141
142
143
144
145
}

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
148
149
150
151
152
153
# Agent/UDP 
Agent/UDP instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
154

Leigh B. Stoller's avatar
Leigh B. Stoller committed
155
156
    set error 0
    if {$node == {}} {
157
	perror "\[connect] $self is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
158
159
	set error 1
    }
160

Leigh B. Stoller's avatar
Leigh B. Stoller committed
161
162
    set dest [$destination set node]
    if {$dest == {}} {
163
	perror "\[connect] $destination is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
164
165
	set error 1
    }
166
167
168
169
170
171
172
173
174
175


    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
    }

    if {$application == {}} {
	perror "\[connect] $self does not have an attached application."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
176
177
	set error 1
    }
178
179
180
181
#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic generator."
#	set error 1
#    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
182
183
    if {$error} {return}

184
    $self set proto "udp"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
185
186
}

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# Agent/TCP
Agent/TCP instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination

    set error 0
    if {$node == {}} {
	perror "\[connect] $self is not attached to a node."
	set error 1
    }
    set dest [$destination set node]
    if {$dest == {}} {
	perror "\[connect] $destination is not attached to a node."
	set error 1
    }
204
205
206
207
208
209
210
211
212

    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
    }

    if {$application == {}} {
	perror "\[connect] $self does not have an attached application."
213
214
	set error 1
    }
215
216
217
218
#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic generator."
#	set error 1
#    }
219
220
221
222
223
    if {$error} {return}

    $self set proto "tcp"
}

224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# 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
269
    var_import ::GLOBALS::objtypes
270
271
272
273
274
275
276
    $self instvar application
    $self instvar destination
    $self instvar node
    $self instvar proto
    $self instvar role
    $self instvar generator
    $self instvar port
277
    $self instvar link
278
279
280
281
282
283
284
285
286
287
288
289

    if {$role == {}} {
	perror "\[updatedb] $self has no role."
	return
    }
    if {$destination == {}} {
	perror "\[updatedb] $self has no destination."
	return
    }
    set target_vnode [$destination set node]
    set target_port [$destination set port]

290
291
292
293
    # 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]

294
    set vname $self
295
    set target_vname $destination
296
297

    # Update the DB
298
    sql exec $DB "insert into virt_trafgens (pid,eid,vnode,vname,role,proto,port,ip,target_vnode,target_vname,target_port,target_ip,generator) values ('$pid','$eid','$node','$vname','$role','$proto',$port,'$ip','$target_vnode','$target_vname',$target_port,'$target_ip','$generator')";
299

300
    sql exec $DB "insert into virt_agents (pid,eid,vnode,vname,objecttype) values ('$pid','$eid','$node','$vname','$objtypes(TRAFGEN)')";
301

302
303
304
    if {$application != {}} {
	sql exec $DB "insert into virt_agents (pid,eid,vnode,vname,objecttype) values ('$pid','$eid','$node','$application','$objtypes(TRAFGEN)')";
    }
305
306
307
308
309
310
311
312
313
}

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

    $self instvar tcptype
    $self instvar role
    $self instvar simulated
    $self instvar application
314
    $self set objname $self
315
316
317
318
319
320
321
322
323
    
    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
    }

324
325
326
    # we set a global variable to indicate that NSE trafgen
    # is present so that nseinput.tcl can take appropriate
    # action
327
    append nseconfig "set nsetrafgen_present 1\n\n"
328
    if { ($tcptype == "") || ($tcptype == "Reno") } {
329
          append nseconfig "set $self \[new Agent/TCP/FullTcp]\n"
330
    } else {
331
          append nseconfig "set $self \[new Agent/TCP/FullTcp/$tcptype]\n"
332
    }
333

334
335
336
337
338
339
340
341
342
343
344
345
    if { $role == "sink" } {
         append nseconfig "\$$self listen\n\n"
    }

    # 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] {
           if { [$self set $var] != {} } {
             append nseconfig "\$$self set $var [$self set $var]\n"
           }
    }
346
    append nseconfig "\n"
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368

    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

    set error 0
    if {$node == {}} {
        perror "\[connect] $self is not attached to a node."
        set error 1
    }
369
370
371
372
373
374
375
376
 
    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
    }

   if { ($role == "source") && ($application == {}) } {
377
378
379
380
381
382
383
384
385
386
387
388
        perror "\[connect] $self does not have an attached application."
        set error 1
    }
    set dest [$destination set node]
    if {$dest == {}} {
        perror "\[connect] $destination is not attached to a node."
        set error 1
    }

# This was an artifact of SEND-CONSUME CBR model. Now that we run freebsd on the
# traffic generator nodes, all we need to do is either enable OSPF routing by
# default or setup static routes
389
390
391
392
#    if {[llength [$node set portlist]] != 1} {
#        perror "\[connect] $node must have exactly one link to be a traffic generator."
#        set error 1
#    }
393
394
395
396
397
398
399
400
    if {$error} {return}

    $self set proto "tcp"
    $dst set proto "tcp"
    $node set osid "FBSD-STD"
    $dest set osid "FBSD-STD"
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
401
402
403
404
405
406
407
408
# Agent/Null
Agent/Null instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
    set error 0
    if {$node == {}} {
409
	perror "\[connect] $self is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
410
411
412
413
	set error 1
    }
    set dest [$destination set node]
    if {$dest == {}} {
414
	perror "\[connect] $destination is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
415
416
	set error 1
    }
417
418
419
420
421

    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
Leigh B. Stoller's avatar
Leigh B. Stoller committed
422
    }
423
424
425
426
427

#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic consumer."
#	set error 1
#    }
Leigh B. Stoller's avatar
Leigh B. Stoller committed
428
429
    if {$error} {return}

430
    $self set role "sink"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
431
432
}

433
# Agent/Null
434
Agent/TCPSink instproc connect {dst} {
435
436
437
438
439
440
441
442
443
444
445
446
447
448
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
    set error 0
    if {$node == {}} {
	perror "\[connect] $self is not attached to a node."
	set error 1
    }
    set dest [$destination set node]
    if {$dest == {}} {
	perror "\[connect] $destination is not attached to a node."
	set error 1
    }
449
450
451
452
453

    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
454
    }
455
456
457
458
459

#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic consumer."
#	set error 1
#    }
460
461
462
463
464
465
    if {$error} {return}

    $self set role "sink"
    $self set proto "tcp"
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
466
467
468
# Application
Application instproc init {} {
    $self set agent {}
469
    $self set role {}
470
471
    global ::GLOBALS::last_class
    set ::GLOBALS::last_class $self
Leigh B. Stoller's avatar
Leigh B. Stoller committed
472
473
474
475
476
}
Application instproc attach-agent {agent} {
    $self set agent $agent
    $agent set_application $self
}
477
478
479
480
Application instproc get_node {} {
    $self instvar agent
    return [$agent get_node]
}
481
482
Application instproc rename {old new} {
    $self instvar agent
483
    # In normal condition this will never occur.
484
485
486
487
    if {$agent != {}} {
	$agent set_application $self
    }
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
488
489
490
491
492
493
494

# Application/Traffic/CBR
Application/Traffic/CBR instproc init {} {
    $self set packetSize_ 210
    $self set rate_ "100Mbps"
    $self set interval_ {}
    $self next
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    
    $self set role "source"
}

Application/Traffic/CBR instproc get_params {} {
    $self instvar packetSize_
    $self instvar rate_
    $self instvar interval_

    if {$rate_ != {} && $rate_ != 0} {
	set rate [parse_bw $rate_]
    } 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"
    }
    return $param
Leigh B. Stoller's avatar
Leigh B. Stoller committed
517
}
518
519
520
521
522
523
524
525
526
527
528
529
530

# 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"
531
532
    
    append nseconfig "\$$self set objname $self\n"
533
534

    if { $agent != {} } {
535
         append nseconfig "\$$self attach-agent \$$agent\n"
536
    }
537
    append nseconfig "\n"
538
539

    # XXX temporary untill event system changes get in
540
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566

   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"
567
568

    append nseconfig "\$$self set objname $self\n"
569
570
571
               
    append nseconfig "\$$self set interval_ $interval_\n"
    if { $agent != {} } {
572
         append nseconfig "\$$self attach-agent \$$agent\n"
573
    }
574
    append nseconfig "\n"
575
576
        
    # XXX temporary untill event system changes get in
577
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
578
579
580

    return $nseconfig
}
581