defTopology

Defining a Topology

The DefTopology command allows the definition of a topology consisting of a set of resources. Many topologies can be defined within a single Experiment Description. Furthermore, a new topology can be defined as a subset of an existing one. Finally, topologies can be saved in stand-alone files, which can then be loaded and re-used by different Experiment descriptions.

OMF and OEDL gives you the option to modify the characteristics of the links between resources in this newly defined topology. Two classes of tools are currently available to enforce such modifications:

  • use of noise injection (only available at ORBIT testbed at Winlab, using the Antenna OEDL command)
  • use of MAC filtering tables (implemented with either: iptables, ebtables, or mackill), refer to the enforce_link OEDL resource path (example here).

Syntax

defTopology( name , arrayOfNode = nil , &block = nil )

where:

  • name: Name of the defined topology.
    • The 'name' argument is a URI string identifying the topology. This URI can then be used to refer to the topology, i.e. using it as a selector for the DefGroup OEDL command). When choosing a 'name' for your topology the following naming convention is encouraged: projectName:topo:topologyName.
    • If you decide to save your topology definition in a stand-alone file, for future re-use in different Experiment, then the filename needs to match your topology name. When using a topology name of the form a:b:c, you have to use the corresponding filename: a_b_c.rb (OMF will automatically convert ":" into "_").
  • arrayOfNode: (optional) the definition of an array of resources (e.g. nodes) to include in this topology.
    • the list of valid definition patterns are:
      • [x,y]: Describes a single node at location x@y
      • [x1..x2, y]: Describes a set of nodes along a line starting at x1@y and ending at x2@y. For instance, [2..4, 5] defines the nodes [2,5], [3,5], [4,5].
      • [x, y1..y2]: Same as previous, but for the y coordinate.
      • [x1..x2, y1..y2]: This defines a rectangle area of nodes within the grid.
      • [[x1,y1], [x2,y2], [x3,y3]]: An arbitrary long list of single nodes.
  • block: (optional) a block of commands that can be used to build/configure this topology.
    • the content of this block of commands follows the Ruby language. Thus, you can use any Ruby statements inside this block (e.g. 'for' loops, 'if' conditions, etc...).
    • OEDL also provides a set of sub-commands that allows convenient topology definition and configuration inside this optional block of commands. These sub-commands are only available within this optional block of defTopology. They are described in details in the following table:
Topology Sub-Commands Description
addNode(x,y) Add node at location x@y to the topology.
removeNode(x,y) Remove node at location x@y from the topology.
addLink (x, y, spec) Adds a link between nodes x and y and configures it with the characteristics defined in the 'spec'.
'spec' is a hash with the following valid keys 
{:rate , :per, :delay, :asymmetric}

:rate       - set the link's rate in Mbps
:per        - set the link's packet error rate in percent (0.3 for 30%)
:delay      - set the link's delay in ms
:asymmetric - set if this link is asymmetric or not ('true' or 'false')

Note: as of June09 only 'asymmetric' has an effect on the link, 
a traffic shaping component is currently being added to OMF in order 
to implement the other attributes.
Refer to the following tutorial for an example on how to use addLink(...)
RemoveLink (x, y) Severs the link between nodes x and y.
size() Return the number of nodes in this topology.
getNode(index) Return the node at the position index in this topology. Return nil if index is greater than the number of nodes in the topology.
getFirstNode() Return the node at the 1st position in this topology.
getLastNode() Return the node at the last position in this topology.
getRandomNode() Return a random node from this topology. Subsequent calls to this method may return the same node.
getUniqueRandomNode() Return a unique random node from this topology. Subsequent calls to this method will never return the same node, i.e. once a node is randomly selected it is removed from the set of nodes of this topology. When all the available nodes in this topology have been drawn, this method will return nil and output a warning message to the console.
eachNode(&block) Execute the commands in block on each node within this topology.
setStrict() Set the strict flag for this topology. When the strict flag is set, adding or removing a node from this topology is not permitted, and will result in an error message on the console and the termination of the experiment. Typically, you set this flag when you want an experiment to proceed only if all the required nodes are present in this topology. By default, the strict flag is NOT set for a topology.
unsetStrict() Clear the "strict" flag. By default, the strict flag is NOT set for a topology.
hasNode(x, y) Return true if the node at location x@y is part of this topology, return false otherwise.

Usage Examples

Example 1

A topology that only contains 4 specific nodes

1 # Define a topology that contains 4 specific nodes
2 #
3 defTopology('test:topo:origin', [[1, 1],[2,5],[10,4],[15,1]]) 

Example 2

A topology, which have nodeNum (=8) nodes arranged in a circle

 1 #
 2 # Define a topology where nodes are arranged in a circle
 3 #
 4 # - This assumes that you have a testbed with available nodes arranged 
 5 #   in a grid pattern (e.g 400 nodes in a 20x20 grid as in ORBIT testbed)
 6 #
 7 # - Then, the following topology definition picks 8 nodes out of the
 8 #   available 400, which are located around a center node at (10,10)
 9 #
10 # - The selected 8+1 (center) nodes are then added to this topology.
11 #
12 
13 defTopology('test:topo:circle') { |t|
14 
15   nodeNum = 8
16   xCenter = 10
17   yCenter = 10
18   radius = nodeNum
19 
20   # use simple 4-way algorithm to pick the nodes
21   #
22   r2 = radius * radius
23   t.addNode(xCenter, yCenter + radius)
24   t.addNode(xCenter, yCenter - radius)
25   (1..radius).each { |x|
26     y = (Math.sqrt(r2 - x*x) + 0.5).to_i
27     t.addNode(xCenter + x, yCenter + y)
28     t.addNode(xCenter + x, yCenter - y)
29     t.addNode(xCenter - x, yCenter + y)
30     t.addNode(xCenter - x, yCenter - y)
31   }
32 }

Example 3

A topology with 8 random nodes, which are selected from another previously defined topology. This previously defined topology was saved in the stand-alone file named 'myproject_topo_allMyNodes.rb'

 1 #
 2 # Define a topology that will have 8 nodes randomly selected from 
 3 # a previously defined topology, which was saved in a stand-alone file.
 4 #
 5 
 6 defTopology('myTopo8Nodes') { |t|
 7 
 8   # Load the previously defined and saved topology 
 9   # (we could also have used: Topology['myproject_topo_allMyNodes']
10   #
11   baseTopo = Topology['myproject:topo:allMyNodes']
12 
13   # Print the size of the base topology
14   #
15   info "Size of the Base Topology: #{baseTopo.size}" 
16 
17   # Repeat the following 8 times 
18   #
19   for count in 1..8
20     # Draw a random node from the base topology
21     aNode = baseTopo.getUniqueRandomNode
22 
23     # Add this random node to this 'myTopo8Nodes' topology
24     t.addNode(aNode.x, aNode.y)
25   end
26 
27   # Print the nodes that belongs to this topology
28   # 
29   info "Size of the 'myTopo8Nodes' Topology: #{t.size}" 
30   t.eachNode { |n|
31     info " - Node: #{n}" 
32   }
33 }
34 

More Examples:

You can find more examples on how to define and use topologies in the following tutorials: