Initialization

Top  Previous  Next

Initialization Sequence

You must initialize the stack before it can be used using the following sequence. The installed examples may help you understand this process.

 

1.You start by allocating the buffer space, either statically with global or static arrays, or dynamically from the task's heap. As explained previously, the stack uses two buffer spaces. For the best memory usage efficiency and performance, you should align the space for mbufs on at least an 128B boundary and the space for clusters on a 2048B boundary; any misaligned part of the allocated memory is not used. Also, the sizes of these buffers should be integer multiples of 128 or 2048 respectively.
2.Next, you must attach the emac device driver to the stack by calling eth_emac_attach. The first parameter, n, gives the number of interfaces to be attached: as only one interface is currently supported, this value must be 1. The second parameter gives the MAC address for the interface being attached; the first six bytes are used and any others are ignored.

 

void eth_emac_attach(int n, const char *MACAddr);

 

3.Now you call init_stack to pass in configuration parameters. The only parameter is a structure that currently has six members; future releases may add further members.
 

struct stack_cfg {

   void (*log)(char *text);

   void (*statusUpdate)(struct stackStatus *sstat);

   char  *pMbufs;

   int    sMbufs;

   char  *pClusters;

   int    sClusters;

};

 

log and statusUpdate are pointers to two callback functions.

 

log is called by the stack to pass back information to you of significant events. It is called with string of the form:

        {n}:Description

where n is the severity level as defined in slog.h, and Description is a textual description of the event.

 

statusUpdate is called by the stack to inform you about important status changes. The member linkStatus gives information about the physical link: whether the cable is connected or not, and, if so, the current speed of the link. stackStatus gives the general status of the stack; you can find currently-available values in stackstatus.h.

 

struct stackStatus{

   unsigned int linkStatus;        

   unsigned int stackStatus;

};

 

You can set pointers to callback functions to be NULL if you do not need the information.

 

The other members of stack_cfg are used for buffer initialization. pMbufs points to the memory you have allocated for mbufs (see point 1) and sMbufs gives the size of this space in bytes. Similarly, pClusters points to the memory you have allocated for clusters and sClusters gives its size in bytes.

 

init_stack returns zero if successful; -1 otherwise. It can fail if the buffers are too small.

 

4.The next step is to set the IP address of of the interface using UpdateIP.

 

void UpdateIP(const char *ifname, char *hostip, char *mask);

 

ifname identifies the ethernet interface for which you are setting the IP address. There is only one ethernet interface available and so you must always use “le0”. The second and third parameters are the IP address and network mask for your interface; both addresses are in text format, for example “192.168.0.1”, "255.255.255.0" .

 

5.Set the routing table using add_route

This step is not necessary if you are communicating in your network only. More commonly you will want to connect to different networks thorough gateways and so you need to configure a routing table.

 

void add_route(char *dest, char *gateway, char *netmask, int flags);

 

dest specifies the destination this routing table will be used for. gateway specifies the gateway to be used. netmask gives the netmask if the net is used as a destination. Flags specify the types of records in the routing table. The following constants can be combined (|) to create the required value:

RTF_UP      - the route is usable

RTF_GATEWAY - the destination is a gateway

RTF_STATIC  - manually added the route (it won't be removed automatically)

 

Buffer sizes

The sizes of buffers can strongly influence the performance of the stack. Both processor utilization and transfer rates can be adversely affected if the stack gets short of memory.

 

As mentioned earlier, buffers are split up to two separate spaces: mbufs (128B each) and clusters (2048B each). Transferred data is mostly stored in clusters; mbufs are mostly used for packet headers, options and control information. If a cluster is used at least one mbuf will be used with it for control information. We recommend that you have at least four times as many mbufs as clusters in a real application.

 

During initialization, half of the clusters (but no more than 128) are allocated for receiving. The remaining clusters are used mainly for the following purposes:

 

TCP: storing unacknowledged output data, limited to the TCP output buffer size set as SO_SNDBUF in setsockopt.
TCP: storing received data waiting for calls to the recv function, limited to the TCP receive buffer size set as SO_RCVBUF  in setsockopt.
UDP: storing output data waiting for transmission, limited to the UDP output buffer size set as SO_SNDBUF in setsockopt.
UDP: storing received data waiting for calls to the recv function, limited to the UDP receive buffer size set as SO_RCVBUF in setsockopt.

 

The conservative approach to setting the buffer sizes is to sum the sizes of send and receive buffers of the maximum number of concurrently opened sockets and to allocate a cluster buffer bigger than this resulting size. Since it is improbable that all connections will be working at the highest speed concurrently, you can allocate a smaller amount buffer space than this and allow the stack to get temporarily overloaded. Under these conditions, some requests for connection or data transfer can fail with ENOBUF, or ENOMEM errors. For TCP connections, the transfer rate can then be significantly reduced, or transfers can be blocked temporarily. Because of the unacknowledged nature of UDP transfers,  data can be lost during such overload conditions.