The cnet network simulator - the simulation model
Keywords: network simulator simulation protocol undergraduate teaching

### Topology files, node attributes and link attributes

cnet supports a model of networking in which nodes are connected by point-to-point links (not shared physical media, such as buses or rings). Nodes may be either hosts or routers; introductory protocols will only use hosts. Hosts are like workstations, with each having an Application Layer which generates messages for delivery to the Application Layers on other hosts (messages are never generated for oneself).

Links are numbered within each node from `0` to the number of physical links that the node has, with `0` representing the `LOOPBACK` link. The first ``real'' link is number `1` and every node will have a link number `1`.

Perhaps surprisingly, the nodes initially have very little knowledge of the network. Nodes do not know how many other nodes there are, what the other nodes are called, nor the attributes of any nodes or links other than their own. All inter-node communication necessary to learn this information must traverse the Physical Layer.

### Topology files

cnet accepts (many) command line options to control its execution. However, more important is cnet's use of a topology file to define the attributes and connections in each network simulation. Consider the following topology file which defines a 2 node network. An implementation of the stopandwait protocol is being developed to provide a reliable data-link layer protocol. cnet keywords are presented in bold font.

If necessary, the topology file is first preprocessed by the C-preprocessor, enabling us to use `#include`, `#define` and conditional ``compilation'' directives if required. Simple /* C and C++ style comments */ are also supported.

        /* A simple 2 node network topology */

        compile          = "stopandwait.c"
        messagerate      = 500ms,
        propagationdelay = 700ms,
        probframecorrupt = 3,
        ostype           = "linux"

        host Perth {
    	x=100, y=100
    	messagerate  = 1000ms,

    	link to Melbourne
        }

        host Melbourne {
    	east of Perth

    	link to Perth
    	    { probframeloss = 2 }
        }

Node attributes and link attributes declared before any nodes are considered global attributes - these will be the defaults unless redefined locally within a node or link definition. Local attributes are declared in a new ``block'', by opening a curly bracket (as in C). In the above topology, the default `messagerate` (the rate at which the Application Layer will generate a new message for delivery) is `500ms`. This becomes the default `messagerate` for all nodes, but node Perth later declares its own (local) `messagerate` as `1000ms`.

The `compile` attribute indicates which C source files are to be compiled and executed by cnet. Here, an instance of the source code in the single file stopandwait.c will be executed by each of Perth and Melbourne. Each node will have its own copy of all variables declared in the file stopandwait.c (globals, static globals, locals and static locals).

### Node attributes

The initial values of node attributes (global or per-node) may be specified in cnet's topology files. Some node attributes may be modified while the simulation is running. Node attributes include the rate of new message generation, minimum and maximum message sizes, whether or not to trace all node activity, and the expected rates of node failure and repair.

All times are stored internally in milliseconds though in the topology file their integral values may be followed by suffixes such as `ms` and `s`.

All data sizes are stored internally in bytes though in the topology file their integral values may be followed by suffixes such as `bytes`, `Kbytes`, `KB`, and `MB`.

Boolean attributes may take on the values `true`, `false`, and `toggle`.

Strings are enclosed within double quotes.

Node attribute | Datatype | Meaning | Examples
--- | --- | --- | ---
address | integer | the unique network address of each node | address = 238
compile | string | a compilation string to declare the sourcefile names containing the protocols for each node (locally overrides the -C option) | compile = "protocol.c stats.c -lm"
messagerate | time | the rate at which the Application Layer can generate new messages for delivery | messagerate = 100ms messagerate = 2s
minmessagesize | bytes | the minimum size of messages generated by the Application Layer | minmessagesize = 100bytes minmessagesize = 4KB
maxmessagesize | bytes | the maximum size of messages generated by the Application Layer (bounded by `MAX_MESSAGE_SIZE` | maxmessagesize = 200bytes maxmessagesize = 8KB
nodemtbf | time | the expected time between node hardware failures | nodemtbf = 600000ms nodemtbf = 1000s
nodemttr | time | the expected time taken to repair a hardware failure | nodemttr = 5000ms nodemttr = 100s
ostype | string | the name of the operating system that runs on the node (only used to set the node's icon). Possible values are bsd, hurd, irix, linux, macintosh, nextstep, os2, solaris, or winnt. Gimmick. | ostype = "linux"
outputfile | string | the output file for each node. When used as a global attribute, outputfile is used as a filename prefix (as with the -o option). When used locally, outputfile indicates the complete filename | outputfile = "output"
rebootnode | string | the ANSI-C function to call when the node reboots (locally overrides the -R option) | rebootnode = "reboot_function"
trace | boolean | a boolean indicating if event tracing is required (overrides the -t option) | trace = true
winopen | boolean | boolean attribute requesting that a node's window be opened on startup | winopen = false
winx, winy | integer | screen coordinates of the node's window under Tcl/Tk | winx = 100, winy = 200
x, y | integer | coordinates of the node's icon on the main window | x = 80, y = 120

When executing, each node's protocol code (in C) has access to its own `CnetNodeinfo` structure describing the node's attributes. This structure is best considered read-only as its contents are ``refreshed'' as each node is scheduled for execution.

        typedef struct {
          CnetNodetype  nodetype;       /* Either a NT_HOST or a NT_ROUTER */
          int           nodenumber;     /* Ranging from 0.._NNODES-1 */
          CnetAddr      address;        /* Possibly different to the nodenumber */
          char          *nodename;      /* this node's unique name */
          int           nlinks;         /* Ranging from 0(=LOOPBACK) .. nlinks */
          int           minmessagesize; /* min size (in bytes) of msgs generated */
          int           maxmessagesize; /* max size (in bytes) of msgs generated */
          int           messagerate;    /* rate of msg generation (in ms) */
          long          time_in_ms;     /* a monotonically increasing clock */
          struct {
    	  long      sec;
    	  long      msec;
          }             time_of_day;    /* a reflection of the wall-clock time */
        } CnetNodeinfo;

        CnetNodeinfo  nodeinfo;

### Link attributes

The Physical Layer delivers frames between nodes on unreliable, bidirectional links. The initial values of link attributes (global or per-node) may be specified in cnet's topology files. Some link attributes may be modified while the simulation is running. Link attributes include the propagation delay between endpoints, the probabilities of frame loss and corruption, the link bandwidth, the expected rates of link failure and repair, the transmit buffer size, and relative costs of frame transmission (these last few only concern more detailed protocols).

Link bandwidths are stored internally in bits-per-second though in the topology file their integral values may be followed by suffixes such as `bps`, `Kbps`, and `Mbps`.

Probabilities specify a uniform distribution, with their value being the `log-base-2` of the chance of failure (yes, this is ugly). In the topology file above, the global `probframecorrupt` attribute declares that a frame will be corrupted with probability of 1 in 8 (2 to the power 3) and the link from Melbourne to Perth will lose (on average) every fourth frame. A probability of `0` (the default) means that no errors will be introduced.

Link attribute | Datatype | Meaning | Examples
--- | --- | --- | ---
bandwidth | datarate | the bandwidth along a link | bandwidth = 1000000bps bandwidth = 56Kbps
costperbyte | cents | the cost per byte along this link | costperbyte = 1c
costperframe | cents | the cost per frame along this link | costperframe = 5c
linkmtbf | time | the expected time between link hardware failures | linkmtbf = 600000ms linkmtbf = 1000s
linkmttr | time | the expected time taken to repair a link hardware failure | linkmttr = 5000ms linkmttr = 100s
probframecorrupt | probability | the probability that a frame on this link will be corrupted | probframecorrupt = 3 /* 1 in 8 */
probframeloss | probability | the probability that a frame on this link will be lost altogether | probframecorrupt = 4 /* 1 in 16 */
propagationdelay | time | the propagation delay along a link | propagationdelay = 20ms propagationdelay = 1s

When executing, each node's protocol code (in C) has access to its own `CnetLinkinfo` structure describing the link's attributes. This structure is best considered read-only as its contents are ``refreshed'' as each node is scheduled for execution. The global variable `linkinfo` is a vector of `CnetLinkinfo` structures. `linkinfo[0]` maintains attributes of the pseudo `LOOPBACK` link, `linkinfo[1]` maintains attributes of the first true physical link, and so on.

        typedef struct {
    	int       linkup;               /* TRUE if link not severed */
    	int       bandwidth;            /* in bits per second */
    	int       propagationdelay;     /* in ms */
    	int       transmitbufsize;      /* in bytes */
    	int       costperbyte;          /* in cents(?) */
    	int       costperframe;         /* in cents(?) */
        } CnetLinkinfo;

        CnetLinkinfo *linkinfo;    /* linkinfo[0]..linkinfo[nodeinfo.nlinks] */

To find the propagation delay of the first ``real'' link in a 2 node simulation, each node would simply access `linkinfo[1].propagationdelay` .

### Compilation strings

Because cnet must dynamically link compiled versions of protocols at run-time, cnet performs all necessary compilation and linking. You neither compile nor link protocols yourself, nor use make(3) to do it for you. Invoking cnet with a valid topology file will perform all necessary compilation and linking before commencing the simulation. cnet performs the rudimentary actions of make(3), compiling and linking files if the required target does not exist or is out-of-date with respect to sourcefiles.

Strings are used to declare the location (filenames) of the source and shared object codes for the Application, ``Central'' and Physical layers used in each simulation. These strings may be provided on the command line, via the -A, -C, and -P options. The compilation string to compile the ``Central'' layers may also be specified with the `compile` node attribute in the topology file.

In their simplest form, compilation strings may present just a single C sourcefile name, such as `"protocol.c"`. If necessary, cnet, will compile the file `protocol.c` into the object file `protocol.o` and then link this file to form the final shared object `protocol.cnet`. This final shared object file will then be used to provide the code for each node's relevant layer(s).

In its more complex form, a compilation string may also include compilation switches, a number of sourcefile names, and linker switches. For example, the compilation string

`"-DDEBUG ftp.c tables.c -lm"`

includes an embedded (actually preprocessor) switch which is passed onto the compilation process, two sourcefile names and a linker switch (in this case to link with the mathematics library). Each source file is compiled (if necessary) to create its object file, and all object files are then linked together to form a single shared object. The shared object's name is derived from the first sourcefile found, in this case it will be ftp.cnet. The embedded switches `-l` and `-L` are recognized as (assumed to be) linker switches; all other switches are assumed to be preprocessor and compiler switches.

cnet was written and is maintained by Chris McDonald (chris@cs.uwa.edu.au)