UM EECS 489 Winter 2007 (Background for PA2)

 

1 The Virtual Network

Our virtual network consists of two parts: a virtual host (vrouter henceforth) and a topology seeder. To construct your own private virtual network, you run one copy of seeder and one or more copies of vrouter. The seeder must be run before the vrouter's. Aside from seeding the topology of the virtual network, the seeder also sends some test messages on the virtual network. You might want to start with testing one instance of the vrouter. To do so, log yourself into two Solaris machines, say a.engin and b.ummu. On the respective machines you type:

         a.engin% seeder -n 1
          b.ummu% vrouter -S a.engin

Once you have tried the single instance of your vrouter, you can experiment with multiple instances of it. For example, to create a 4-node virtual network consisting of b.ummu, c.eecs, d.engin, and e.ummu, with the seeder running on a.engin, you do:

         a.engin% seeder -n 4
          b.ummu% vrouter -S a.engin
          c.eecs% vrouter -S a.engin
         d.engin% vrouter -S a.engin
          e.ummu% vrouter -S a.engin
The seeder will consider the first vrouter connected as vrouter 0, the second as vrouter 1, and so on. For this assignment, the seeder will only generate a simple linked-list topology.

2 Addressing on the Virtual Network

 Each of your vrouters is addressed by the IPv4 address of the machine they run on and a well-known port number. The default well-known port number is VROUTER_PORT defined in vnet.h. In case you need to share a machine with someone else running vrouter, you can choose a different port number with the -p option of vrouter. All of your vrouter's must use the same well-known port. For example, to use port number 7896 in the above 4-node scenario, do:

         a.engin% seeder -n 4
          b.ummu% vrouter -S a.engin -p 7896
          c.eecs% vrouter -S a.engin -p 7896
         d.engin% vrouter -S a.engin -p 7896
          e.ummu% vrouter -S a.engin -p 7896

In case your seeder conflicts with another seeder on the same machine, the well-known port number of the seeder can also be changed. To use port number 8707 with your seeder, you do:

         a.engin% seeder -n 4 -p 8707
          b.ummu% vrouter -S a.engin -P 8707 -p 7896
          c.eecs% vrouter -S a.engin -P 8707 -p 7896
         d.engin% vrouter -S a.engin -P 8707 -p 7896
          e.ummu% vrouter -S a.engin -P 8707 -p 7896

To address each other, vrouter's use the virtual internetwork address (vin_addr_t henceforth) depicted in Fig. 1, where the IPv4 Address is the IPv4 address of the machine the vrouter runs on, the Port Number is the well-known port number the vrouter listens on, and the Metric the cost of the link (to be interpreted by higher level protocols). The port number and metric in a vin_addr_t must be kept in network byte-order at all times.

 
Figure 1:  vin_addr_t
vin.gif

3 Virtual Links

Upon start up, each vrouter registers itself with the given seeder. The seeder then determines the connectivity of the virtual network, i.e. which vrouter connects to which other. With prompting from the seeder, each vrouter opens a virtual link (vif) to its designated neighbors. Each vif is assumed to be a bidirectional (full-duplex) link. The virtual link layer is provided to you. In the file vif.c you will find the definition of the following APIs for the vif layer:

int vif_pullup(vif_t *vif, char *buf, int len);
int vif_pullupn(vif_t *vif, char *buf, int len);
int vif_output(vif_t *vif, u_short prot, vmbuf_t *vbp);

When a packet arrives for your vrouter, the vif on which the packet arrives parses the vif header of the packet and calls the appropriate upper layer protocols' APIs. The upper layer protocol calls vif_pullup to pull up its data from the virtual link just like you use recv(3N). Or it can call vif_pullupn to pull up n bytes. The function vif_pullupn tries to pull up n bytes of data in one call. However, it doesn't guarantee that it will always succeed pulling up that many bytes. One should always check the return value of calls to both function to make sure they are not returning error. If vif_pullupn returns error, it usually means there's something wrong in your code, so just dump core and abort.

You call vif_output to put data on the virtual wire. You still need to call htons(), ntohs(), and friends whenever you transmit/receive an integer. See the function definitions in vif.c. (In case you wonder at the choice of the API names and programming style, I try to make them as similar as possible to what one sees in the BSD kernel, so you get an experience of writing kernel code without most of the hassle usually associated with it.) Read the comments in vif.c to find out more fully how to use these vif related functions.

4 Virtual Buffer Chain

One obvious way to encapsulate a higher layer message into a lower layer message is for each layer to allocate enough space for the lower layer header and the upper layer message, and copy the upper layer packet into it. Unfortunately, message copying is very expensive. Actually, memory copy has been identified as one of the most expensive operations in networking code. We would like to reduce copying to a minimum. For that purpose, I have defined a virtual buffer chain (vmbuf_t). Each vmbuf_t element points to a chunk of bytes and records the size of the chunk (in bytes). As a message traverses down the protocol layer stack, each layer creates a new vmbuf_t element for its header and prepends the new element to the virtual buffer chain before passing the chain down to the next lower layer. Fig. 2 depicts the vmbuf chain of a message going down the VTP, VIP, and VIF layers. The virtual link layer at the bottom transmits each vmbuf_t element without making extra copies.

 
Figure 2:  vmbuf Chain Traversing the Protocol Stack.
vmbufchain.gif

5 Virtual Router

Our virtual router (vrouter) speaks 4 protocols:
VIP:
Virtual Internetwork Protocol, a connectionless internetwork protocol.
VCMP:
Virtual Control Message Protocol, an error reporting control message protocol.
VRP:
Virtual Routing Protocol, a distance-vector protocol that implements split-horizon with poisonous reverse, path hold-down, and route poisoning.
VTP:
Virtual Transport Protocol, currently does nothing but prints out the data it receives on the screen.

5.1 VIP: Virtual Internetwork Protocol

 
 
Figure 3:  VIP Packet Header Format.
vip.gif

VIP is a connectionless internetwork protocol. Fig. 3 depicts the packet header format of VIP. The Version field contains the version number, currently set to VIP_VERSION defined in vip.h . Packets with version number different from VIP_VERSION should be discarded. The Hop Limit field contains the number of hops a packet has traversed. At every host, except the packet's destination host, this field should be decremented by one and the packet should be discarded if this field is <= 0. The Pkt Length field contains the size of the packet in bytes, excluding the header. The Protocol field specifies whether this is a vcmp, vrp, or vtp packet. The protocol numbers of VCMP, VRP, and VTP are VIP_PROTOVCMP, VIP_PROTOVRP and VIP_PROTOVTP respectively, as defined in vip.h. There is also a protocol number VIF_PROTOVIP for VIP defined in vif.h. VIP identifies a host by its vin_addr_t as described in Section 2.

5.2 VCMP: Virtual Control Message Protocol

 When a non-VCMP packet encounters one of the following errors, the vrouter holding the packet should report the error back to the packet's sender. The above error codes and messages are defined in vcmp.h and vcmp.c. The format of a VCMP packet is depicted in Fig. 4.
 
Figure 4:  VCMP Packet Header Format.
vcmp.gif

The version should be VCMP_VERSION and the error code one of the above listed. The VIP header of the packet encountering error is returned along with the error code. In generating a VCMP packet, you may find the macro VRP_INFINITY defined in vrp.h useful. No error should be generated when VCMP packets themselves encounter errors.

5.3 VRP: Virtual Routing Protocol

 VRP will be the subject of the next programming assignment. For this programming assignment, you may find the following functions useful:

Read the comments in vrp.c to find out more fully how to use these functions.

5.4 VROUTER: A Virtual Router


 
Figure 5:  Design of the virtual router vrouter.
vhost.gif vhost.gif

The design of the virtual host (vrouter) is depicted in Fig. 5. In the figure, data structures are enclosed in rounded boxes and functions in square boxes. Files with comments suggesting what the functions could contain are available in the assignment directory. (This figure shows vif_input() calling vip_input(). In the code, vif_input() actually returns the VIF and the main() routine in vrouter.c calls vip_input().)