URT Core

Memory Buffers (Mbuf)

The Mbuf module provides a re-implementation of the Berkeley memory buffers. Mbufs are used throughout the plexus networking code to pass network data between protocols. Unfortunately, the use of mbufs is currently unsafe and needs to be redesigned. What follows is a brief description of how mbufs are laid out and how they are most commonly used. A more detailed description of the Berkeley memory buffers can be found in TCP/IP Illustrated Volume 2 by Gary R. Wright and W. Richard Stevens.

An mbuf currently has a header structure that defines the type of the mbuf and where data is stored.

TYPE mh_hdrT = RECORD
  mh_next    : T;
  mh_nextpkt : T;
  mh_data    : Word.T; (* ADDRESS; *)
  mh_len     : Ctypes.long;
  mh_type    : Ctypes.int;
  mh_flags   : Ctypes.int;
  mh_union   : ARRAY [0..3] OF ARRAY [1..BYTESIZE(Ctypes.long)] OF CHAR;
END;

TYPE MbufT = RECORD
  mh_hdr : mh_hdrT;
  M_dat  : ARRAY [1..MLEN] OF CHAR;
END;

TYPE T = UNTRACED REF MbufT;

Mbufs can be linked together using the mh_next and mh_nextpkt members. The mh_data members points to the data in the mbuf and the mh_len member specifies its length. It is possible for the data pointer to point internally at the MbufT.M_dat array, or it can point to external data. The mh_type member specifies the type of data contained in the mbuf. In SPIN this typically is either Mbuf.MT_DATA or Mbuf.MT_HEADER. The mh_flags member defines how the mbuf should be treated when it is freed. The last member mh_union is unused.

At the moment clients should only access the data contained by the mbuf using the Mbuf.Array function.

PROCEDURE m_copydata( mbuf : T; off : CARDINAL; len : CARDINAL; cp : T);
Copy data from an mbuf chain starting off bytes from the beginning, continuing for len bytes, into the indicated buffer.

PROCEDURE m_copym( mbuf : T; off : CARDINAL; len : CARDINAL; wait : HowT):T;
Make a copy of an mbuf chain starting off bytes from the beginning, continuing for len bytes. If len is M_COPYALL, copy to end of mbuf. The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.

PROCEDURE m_free(mbuf : T):T;
Free an allocated mbuf, freeing associated cluster if present. If cluster requires special action, place whole mbuf on mfreelater and schedule later freeing (so as not to free from interrupt level).

PROCEDURE m_freem(mbuf : T);
Free an allocated mbuf chain. Calls m_free for each mbuf in the chain.

PROCEDURE m_get( canwait : HowT; type : Ctypes.int):T;
Space allocation routines. Will get a mbuf.

PROCEDURE m_getclr( canwait : HowT; type : Ctypes.int):T;
Space allocation routines. Will get a mbuf with zero'd out data area.

PROCEDURE m_gethdr( canwait : HowT; type : Ctypes.int):T;
Space allocation routines. Will get a mbuf with pkt header.

PROCEDURE m_length(mbuf : T):CARDINAL;
get the length of an mbuf chain.

PROCEDURE m_prepend( mbuf : T; len : CARDINAL; how : HowT):T;
Lesser-used path for M_PREPEND. Allocate new mbuf to prepend to chain, copy junk along.

PROCEDURE m_pullup( mbuf : T; len : CARDINAL):T;
Rearrange an mbuf chain so that len bytes are contiguous and in the data area of an mbuf. Returns the resulting mbuf chain on success, frees it and returns null on failure. If there is room, it will add up to max_protohdr-len extra bytes to the contiguous region in an attempt to avoid being called next time.

PROCEDURE M_PREPEND( mbuf : T; plen : CARDINAL; how : HowT):T;
Arrange to prepend space of size plen to mbuf m. If a new mbuf must be allocated, how specifies whether to wait. If how is M_DONTWAIT and allocation fails, the original mbuf chain is freed and m is set to NULL.

PROCEDURE M_ALIGN( mbuf : T; len : CARDINAL);
Set the m_data member of a newly-allocated mbuf (m_get) to place an object of the specified size at the aligned end of the mbuf.

PROCEDURE MH_ALIGN( mbuf : T; len : CARDINAL);
As above, for mbufs allocated with m_gethdr or initialized by M_COPY_PKTHDR.

Encapsulating data in an Mbuf

It is possible to encapsulate data in an mbuf and send it directly. This is done using the MclGetOa procedure, which will allocate an mbuf that wraps up the user supplied buffer. This feature enables applications to send data without requiring additional copies. The user can provide a method suite that act on the mbuf. For example,
VAR m: Mbuf.T;
    data : REF ARRAY OF CHAR;
BEGIN

  data := NEW(REF ARRAY OF CHAR, 8000);
  m := Mbuf.MclGetOa(data, 8000, methods, NIL);
  
END;
The MclGetOa procedure takes the newly allocated array as its first argument. It is possible to specify separatedly the lenght of the buffer that the mbuf to be less than or equal to the size of the actual array. As the third argument the user can provide some methods that the networking code should uses instead of the default implementations. The current methods supported are free and checksum.
TYPE freeprocT = (* EPHEMERAL *) PROCEDURE (
                     ext_buf  : REF ARRAY OF CHAR; 
                     ext_size : CARDINAL; 
                     ext_arg  : REFANY);

TYPE csumprocT = (* EPHEMERAL *) PROCEDURE (
                     ext_buf  : REF ARRAY OF CHAR; 
                     ext_size : CARDINAL; 
                     ext_arg  : REFANY;
                     offset   : CARDINAL;
                     csum     : Ctypes.unsigned_short): Ctypes.unsigned_short;

TYPE Methods = REF RECORD
  free: freeprocT;
  csum: csumprocT;
END;
Finally, an additional optional argument can be stored with the mbuf that is passed back up to the methods.

Error Reporting (Errno)

The Errno interface defines the standard Unix errno values and corresponding error messages.

IO control (Ioctl)

The ioclt support implements the ioctl value calculation functions (IOR, IOW, IOCBASECMD, etc.) which are necessary to compute the correct ioctl value. This is useful when trying to setup devices from M3 modules. Otherwise, this module should not be used.

Interface Support (If)

The If module implements the support register and look up interfaces devices. It will be obsolete when we complete the SPIN device model.


Marc Fiuczynski
DAY/MONTH/YEAR