traffic.tcl 16 KB
Newer Older
1
# -*- tcl -*-
Leigh B. Stoller's avatar
Leigh B. Stoller committed
2
3
#
# EMULAB-COPYRIGHT
4
# Copyright (c) 2000-2003 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) {}
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
    # At some point allow users to set link. For now, first link (0).
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
    # XXX Hack for local virtual nodes. Eventually use ipinip tunnels,
    # but for now just send over the existing link.
    if { [$node set isvirt] == 1 &&
         [$node set isremote] == 0 } {
	set foo [$node set fixed]
	set ip [$foo ip 0]
    } else {
	set ip [$node ip 0]
    }
    if { [$target_vnode set isvirt] == 1 &&
         [$target_vnode set isremote] == 0 } {
	set foo [$target_vnode set fixed]
	set target_ip [$foo ip 0]
    } else {
	set target_ip [$target_vnode ip 0]
    }
141

142
    if {$role == "sink"} {
143
	set application $self
144
	set proto [$destination set proto]
145
146
147
	set target_vname [$destination set application]
    } else {
	set target_vname $destination
148
149
150
    }

    # Update the DB
151
    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')";
152

153
    sql exec $DB "insert into virt_agents (pid,eid,vnode,vname,objecttype) values ('$pid','$eid','$node','$application','$objtypes(TRAFGEN)')";
154
155
156
157
158
159
}

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
162
163
164
165
166
167
# Agent/UDP 
Agent/UDP instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
168

Leigh B. Stoller's avatar
Leigh B. Stoller committed
169
170
    set error 0
    if {$node == {}} {
171
	perror "\[connect] $self is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
172
173
	set error 1
    }
174

Leigh B. Stoller's avatar
Leigh B. Stoller committed
175
176
    set dest [$destination set node]
    if {$dest == {}} {
177
	perror "\[connect] $destination is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
178
179
	set error 1
    }
180
181
182
183
184
185
186
187
188
189


    # 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
190
191
	set error 1
    }
192
193
194
195
#    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
196
197
    if {$error} {return}

198
    $self set proto "udp"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
199
200
}

201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# 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
    }
218
219
220
221
222
223
224
225
226

    # 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."
227
228
	set error 1
    }
229
230
231
232
#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic generator."
#	set error 1
#    }
233
234
235
236
237
    if {$error} {return}

    $self set proto "tcp"
}

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
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# 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
283
    var_import ::GLOBALS::objtypes
284
285
286
287
288
289
290
    $self instvar application
    $self instvar destination
    $self instvar node
    $self instvar proto
    $self instvar role
    $self instvar generator
    $self instvar port
291
    $self instvar link
292
293
294
295
296
297
298
299
300
301
302
303

    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]

304
305
306
307
    # 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]

308
    set vname $self
309
    set target_vname $destination
310
311

    # Update the DB
312
    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')";
313

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

316
317
318
    if {$application != {}} {
	sql exec $DB "insert into virt_agents (pid,eid,vnode,vname,objecttype) values ('$pid','$eid','$node','$application','$objtypes(TRAFGEN)')";
    }
319
320
321
322
323
324
325
326
327
}

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

    $self instvar tcptype
    $self instvar role
    $self instvar simulated
    $self instvar application
328
    $self set objname $self
329
330
331
332
333
334
335
336
337
    
    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
    }

338
339
340
    # we set a global variable to indicate that NSE trafgen
    # is present so that nseinput.tcl can take appropriate
    # action
341
    append nseconfig "set nsetrafgen_present 1\n\n"
342
    if { ($tcptype == "") || ($tcptype == "Reno") } {
343
          append nseconfig "set $self \[new Agent/TCP/FullTcp]\n"
344
    } else {
345
          append nseconfig "set $self \[new Agent/TCP/FullTcp/$tcptype]\n"
346
    }
347

348
349
350
351
352
353
354
355
356
357
358
359
    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"
           }
    }
360
    append nseconfig "\n"
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

    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
    }
383
384
385
386
387
388
389
390
 
    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
    }

   if { ($role == "source") && ($application == {}) } {
391
392
393
394
395
396
397
398
399
400
401
402
        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
403
404
405
406
#    if {[llength [$node set portlist]] != 1} {
#        perror "\[connect] $node must have exactly one link to be a traffic generator."
#        set error 1
#    }
407
408
409
410
411
    if {$error} {return}

    $self set proto "tcp"
    $dst set proto "tcp"
    $node set osid "FBSD-STD"
Shashi Guruprasad's avatar
Shashi Guruprasad committed
412
    $node set realtime 1
413
    $dest set osid "FBSD-STD"
Shashi Guruprasad's avatar
Shashi Guruprasad committed
414
    $dest set realtime 1
415
416
}

Leigh B. Stoller's avatar
Leigh B. Stoller committed
417
418
419
420
421
422
423
424
# Agent/Null
Agent/Null instproc connect {dst} {
    $self next $dst
    $self instvar node
    $self instvar application
    $self instvar destination
    set error 0
    if {$node == {}} {
425
	perror "\[connect] $self is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
426
427
428
429
	set error 1
    }
    set dest [$destination set node]
    if {$dest == {}} {
430
	perror "\[connect] $destination is not attached to a node."
Leigh B. Stoller's avatar
Leigh B. Stoller committed
431
432
	set error 1
    }
433
434
435
436
437

    # 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
438
    }
439
440
441
442
443

#    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
444
445
    if {$error} {return}

446
    $self set role "sink"
Leigh B. Stoller's avatar
Leigh B. Stoller committed
447
448
}

449
# Agent/Null
450
Agent/TCPSink instproc connect {dst} {
451
452
453
454
455
456
457
458
459
460
461
462
463
464
    $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
    }
465
466
467
468
469

    # for the case when the node is simulated
    # we just ignore
    if { [$node set simulated] == 1 } {
	return
470
    }
471
472
473
474
475

#    if {[llength [$node set portlist]] != 1} {
#	perror "\[connect] $node must have exactly one link to be a traffic consumer."
#	set error 1
#    }
476
477
478
479
480
481
    if {$error} {return}

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

Leigh B. Stoller's avatar
Leigh B. Stoller committed
482
483
484
# Application
Application instproc init {} {
    $self set agent {}
485
    $self set role {}
486
487
    global ::GLOBALS::last_class
    set ::GLOBALS::last_class $self
Leigh B. Stoller's avatar
Leigh B. Stoller committed
488
489
490
491
492
}
Application instproc attach-agent {agent} {
    $self set agent $agent
    $agent set_application $self
}
493
494
495
496
Application instproc get_node {} {
    $self instvar agent
    return [$agent get_node]
}
497
498
Application instproc rename {old new} {
    $self instvar agent
499
    # In normal condition this will never occur.
500
501
502
503
    if {$agent != {}} {
	$agent set_application $self
    }
}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
504
505
506
507
508
509

# Application/Traffic/CBR
Application/Traffic/CBR instproc init {} {
    $self set packetSize_ 210
    $self set rate_ "100Mbps"
    $self set interval_ {}
510
    $self set iptos_ {}
Leigh B. Stoller's avatar
Leigh B. Stoller committed
511
    $self next
512
513
514
515
516
517
518
519
    
    $self set role "source"
}

Application/Traffic/CBR instproc get_params {} {
    $self instvar packetSize_
    $self instvar rate_
    $self instvar interval_
520
    $self instvar iptos_
521
522
523
524
525
526
527
528
529
530
531
532
533

    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"
    }
534
535

    if {$iptos_ != {} && $iptos_ != 0} {
536
	set param "$param IPTOS=$iptos_"
537
    } else {
538
	set param "$param IPTOS=-1"
539
540
    }

541
    return $param
Leigh B. Stoller's avatar
Leigh B. Stoller committed
542
}
543
544
545
546
547
548
549
550
551
552
553
554
555

# 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"
556
557
    
    append nseconfig "\$$self set objname $self\n"
558
559

    if { $agent != {} } {
560
         append nseconfig "\$$self attach-agent \$$agent\n"
561
    }
562
    append nseconfig "\n"
563
564

    # XXX temporary untill event system changes get in
565
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591

   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"
592
593

    append nseconfig "\$$self set objname $self\n"
594
595
596
               
    append nseconfig "\$$self set interval_ $interval_\n"
    if { $agent != {} } {
597
         append nseconfig "\$$self attach-agent \$$agent\n"
598
    }
599
    append nseconfig "\n"
600
601
        
    # XXX temporary untill event system changes get in
602
    # append nseconfig "\[Simulator instance] at 30.0 \"\$$self start\"\n\n"
603
604
605

    return $nseconfig
}
606