Computer Science Department

U-Net Development Team

Cornell University

A Breif Introduction to U-Net

over Fast Ethernet

using LIBUNET.C

by

Hoi Sheung So

so@cs.cornell.edu

11 February, 1997.

I. Introduction

This is a brief introduction to writing a U-Net application using the libunet library on a Fast Ethernet network. Note that libunet is only a way of using U-Net service. Once a user understands the concept of creating end-points and channels, he or she should be able to customize libunet to maximize efficiency.

II. Overview of the U-Net

A machine running U-Net can support multiple network adapters of different types such as ATM, Fast Ethernet etc. Each adapter is a device. Multiple endpoints can be created on a single device. To send a packet from one endpoint to another, we need to create a channel between them.

III. Procedure of Sending/Receiving a packet

The following section explains every imporatant step in the sample program unettest.c to demonstrate how to use libunet library. Please refer to the sample program servertest.c when you read the following descriptions. This test program sends out a packet from the client and expects the server to reply with the specified number of packets.

1. Start the Device Driver

To use U-Net service over Fast Ethernet(the TULIP Board), we must first install U-Net device driver and type the followings at command prompt:

c:\>net start unet

c:\>net start tulip

2. Open the Device in Your Program

hDriver = unet_opendev(UNET_DEVID_TULIP, 0, &info)
UNET_DEVID_TULIP you want to use the TULIP board
0 this is the first TULIP board
info when unet_opendev returns, info will return information regarding this device

3. Open an Endpoint

Before opening an endpoint, we need to tell the device driver more about the charateristics of the desired endpoint. A UNET_CREATE_ENDPOINT_REQUEST struct contains such information. The fields are:
devType specific adapter type such as TULIP
devIndex first adapter of devType will have devIndex=0 and so on
numTxFifoEntries number of entries in outgoing queue
numFreeFifoEntries number of entries in the queue containing pointers pointing to free space in the buffer area
numRxFifoEntries number of entries in incoming queue
bufferAreaSize set it to 0 (This field is retained for backward compatability.)
rxBufferSize the size of each buffer containing an outgoing packet

endpt = unet_create_endpt(hDriver, &info, &create, TX_FIFO_SIZE);
hDriver handle of device driver
info the infomation returned by unet_opendev()
create described above
TX_FIFO_SIZE max. number of entries of the outgoing queue

4. Open a Channel between 2 Endpoints

4.1 Similar to creating an endpoint, we need to tell U-Net which are the 2 endpoints being connected. This information is stored in a UNET_ACTIVATE_CHANNEL_REQUEST struct.
TxAddr pointer to a special address structure representing the address of this machine

(see str_to_addr() below)

rxAddr pointer to a special address structure representing the address of peer machine
endpointId endpoint ID of the endpoint you just created (endpt->endponintID)
chan a unique channer number you choose; it has only local importance

4.2 str_to_addr()

str_to_addr() converts a string representing an address of typeto the U-Net internal representation of such address

str_to_addr(UNET_DEVID_TULIP, input, &(activate.rxAddr));
UNET_DEVID_TULIP this is a TULIP device
input a string of the format
(XX:XX:XX:XX:XX:XX.PP)

XX's are in hexadecimal and they represents the Etherent address

PP's is the port number in hex

port number is similar to TCP port

&(activate.rxAddr) the pointer to the pointer to the address structure

5. Sending a Packet

5.1 Creating a Transmission Buffer Descriptor (txbd)

In order to send a packet, we need to tell U-Net the location and legth of our packet. TXBD contains this information.
Buf address of the packet
length length of the packet
chan channel returned by unet_activate_chan()

5.2 Push txbd into the queue

First, we need to make sure the outgoing queue is not full.

/* outgoing queue is full if this assertion is true */

endpt->tx_next == endpt->tx_first + *(endpt->tx_wall)

If unfortunately, the outgoing queue is full, we must wait until U-Net has serviced at least one of the previous requests. For 80X86 machines running NT, we need to call a fast trap to the kernel so that the U-Net device driver can service requests. Therefore, we keep calling UNET_TRAP() until the queue is not full.

while (OUT_GOING_IS_FULL)

UNET_TRAP(hDriver, endpt->endpointId);

/* actually push the txbd onto the queue */

*(endpt->tx_next) = txbd;

/* call a fast trap to send out the packet */

UNET_TRAP(…);

Note that this TRAP is not necessary, we can push several descriptors at a time and wait until the queue is full before we call UNET_TRAP(). Trapping after pushing each descriptor will indeed lower the efficiency.

5.3 Increment TX_NEXT pointer

Incresing TX_NEXT pointer indicates the next location a new txbd should be pushed. tx_next wraps around if necessary.

if (endpt->tx_next == endpt->tx_last)

endpt->tx_next = endpt->tx_first;

else

endpt->tx_next++;

6. Receiving a Packet

6.1 Receive Buffer Descriptor (rxbd)

When a packet arrives at a U-Net device, U-Net will forward it to the correct endpoint depending on the port number of incoming packet. A descriptor similar to txbd containing the information of the packet is pushed onto the receive queue of the corresponding endpoint.
rxbd -> chan channel condition {FREE | BUSY | ERROR}
rxbd -> length length of incoming packet
rxbd -> pay_or_buf contains either i) a packet if the packet is small or ii) an array of pointers pointing to several buffers containing the packet

6.2 Polling the Receive Queue (rx_next->chan)

If endpt->rx_next->chan == UNET_CHANNEL_FREE, no packet has been received. A value of UNET_CHANNEL_BUSY indicates a packet has been received. A value of UNET_CHANNEL_ERROR indicates an error in receiving the packet.

6.2 Locating the Packet Data (rx_next->pay_or_buf)

If the whole can fix entirely in rxbd,

rx_next->pay_or_buf[0..(endpt->rx_next->length-1)]

contains the data, otherwise,

rx_next->pay_or_buf[] is an array of pointers each of which points to a buffer that altogether forms the packet. Number of buffer(s) is:

(len/endpt->rxb_buffsize_used) + 1

6.3 Reusing the Packet Buffer

After the incoming packet has been inspected or copied, the buffer(s) can be used to accommodate a new incoming packet. Therefore, we must push the buffer(s) back onto the free queue. Note that this is necessary only if the packet did not fit in rxbd; otherwise, no buffers were used to store incoming data in the first place.

Of course, the next step is to increment endpt->free_next and wrap around it if necessary.

6.4 Adjust rx_next & rx_wall

After we have inpected the incoming packet, we should notify U-Net that a spot on the rx queue has been freed. This is done by setting the channel condition to FREE

endpt->next->chan = UNET_CHANNEL_FREE

and incrementing the rx wall pointer.

7. Clean Up and Shut Down

7.1 Shut Down a Channel

deactivate is of type UNET_DEACTIVATE_CHANNEL_REQUEST
deactivate.endpointId endpt->endpointId;
deactivate.chan chan;

unet_deactivate_chan(hDriver, &deactivate);

7.2 Destroy an Endpoint

It is important to destroy and endpoint so that the U-Net device driver can free up the space for storing rx, tx queues.

unet_destroy_endpt(hDriver, endpt->endpointId);

7.3 Close the Device Driver

CloseHandle(hDriver);