Overview

This page describes how ethernet was configured and run for the RCE under RTEMS 4.7 and 4.9 up until the beginning of March 2011 (before core 2.0).

Figure 1 above shows most of the entities involved and their most important relationships. Most of the relationships are one-to-one but a few are one-to-many with the "many" side marked with an asterisk. A line with a filled diamond means that the thing on the diamond side owns the thing(s) on the other side; they are considered a part of it (composition). The unfilled diamond marks a collection which does not own its members. Arrows denote one-way relationships. For example, if you have a TDE you can find the corresponding Tds but not the other way around.

Name

Type

Purpose

Ethernet plugin

I/O firmware

Implements a raw ethernet.

PIB

I/O firmware

Pending Import Block. Holds a queue of TDEs for completed imports (receives).

FLB

I/O firmware

Free List Block. Holds a queue of TDEs for free buffers usable by the PIB.

PEB

I/O firmware

Pending Export Block. Holds a queue of TDEs for exports awaiting completion.

ECB

I/O firmware

Export Completion Block. Holds a queue of TDEs for exports that have finished.

ehr Task

RTEMS task

Dequeues TDEs from the PIB. Runs code in the Driver.

ehc Task

RTEMS task

Dequeues TDEs from the ECB. Runs code in the Driver.

ehf Task

RTEMS task

Prevents addition of new TDEs to the PEB (by taking a semaphore in the Driver) as long as the PEB is in the Full state. Runs code in the Driver.

Driver

Software

Manages the plugin and the pool of import buffers (represented as a queue of Descr objects).

TDE

Data

Transfer Descriptor Entry. The upper 26 bits of a Tds address, plus six flag bits whose meanings depend on which I/O firmware block the TDE is being used with.

Tds

Data+Software

Transfer DeScriptor. A block of memory which holds pointers to buffers for a packet header, a packet payload and a transfer completion descriptor (which give the completion status). The PIB and PEB know how to find and use these pointers given a TDE. Since only the upper 26 bits of the Tds address may be nonzero the Tds must be aligned on a 64-bye boundary. Since the actual transfer descriptor used by the firmware is much smaller than 64 bytes, the Tds object uses the "extra" space to store some other data such as a Descr address.

Descr

Software

Confusingly named since it isn't a descriptor as known to the firmware. Holds a pointer to its associated Tds and to its associated Handler.

Handler

Software

Part of the layer of interface above the Driver; in the case of ethernet this is the BSD networking layer. It contains the ifnet struct used to describe an attached (usable) network interface to the IP stack. It also contains the pool of export buffers (queue of Descr) used with the PEB.

ifnet

IP stack data

Describes the network interface and its "driver" to the IP stack. Besides parameters describing the network interface it contains function pointers for the various networking operations such as sending, receiving, I/O control calls and so on. These may point to IP stack functions such as ether_output() or may point to wrapper functions which delegate to member functions of the Handler. The if_softc member of the ifnet struct is set to point to the associated Handler.

mbuf

Data

A chainable structure used by the IP stack to hold data for one ethernet packet. The Handler has to copy from mbufs to export buffers and from import buffers to mbufs because mbufs are the only type of network data buffer the IP stack is written to use.

IP stack

RTEMS Software

A version of the Berkeley IP stack swallowed almost intact. It manages the transfer of data (via sockets and mbufs) between application software and the "network interface driver" (Handler). It handles encapsulation and de-encapsulation of user data, routing, mbuf allocation and decides which sockets get an incoming packet. Implements TCP, UDP, ARP, ICMP, etc.

rtems_bsdnet_config

Global RTEMS data

Contains general IP routing information for the host as a whole, e.g., host IP, host netmask, gateway IP, DNS server IPs, NTP server IPs. These can be filled in at the start of network initialization or set to zero and deferred until the interface is already attached and DHCP can be used. Also contains a chain of rtems_bsdnet_ifconfig structs and some general information on the amount of buffering needed per UDP/TCP socket.

rtems_bsdnet_ifconfig

RTEMS data

Configuration information for a single network interface, e.g., its hardware address (ethernet MAC address), name, MTU size, IP address (if known), etc. Also contains a pointer to an attach function used to make the interface ready for use by the IP stack.

Initialization

Pre-driver init

The function rce_bsp_predriver_hook() is run prior to RTEMS driver initialization; it calls RceEthernet::initialize() to create an empty list is RceEthernet::Driver and RceBsdnet::initialize() to create an empty list of RceEthernet::Handler.

The RCE ethernet code (or any plugin code) is not packaged as a "driver" in the sense that RTEMS uses it; it doesn't create or use a device node in the in-memory filesystem. These initializations don't really belong here and will be moved to init_executive().

Configuration fetch

init_executive() calls RceInit::configure_network_from_dhcp() with a hard-coded argument INTF giving the index number of the ethernet interface that is to be attached

RceInit::configure_network_from_dhcp() retrieves ethernet interface (plugin) information from Configuration container 63 (in the configuration flash memory). The first 32-bit word of the container's metadata contains the number NFACES of ethernet plugins. The container itself contains an array ECONFIG of NFACES elements where each element contains the following information:

  • uint8_t PEB ID, ECB ID, FLB ID, PIB ID.
  • Import info:
    • uint32_t type.
    • uint32_t header size, max payload size, number of buffers.
  • Export info:
    • uint32_t type.
    • uint32_t header size, max payload size, number of buffers.
  • The interface name in a 32-byte buffer.
  • The six-byte MAC address (big-endian).

where the type value is one of the values obtainable by using unsigned() on one of the members of the enum {NonContiguous, Contiguous, HeadersOnly, PayloadsOnly, TdsOnly} and occupies four bytes. The type value isn't used by the ethernet software; RceEthernet::Driver member functions always create TDEs with the "contiguous" flag bit set to zero.

Protocol plugin setup

After retrieving the ethernet configuration data RceInit::configure_network_from_dhcp() loops over all ethernets (for i from 0 to NFACES-1) and passes each ECONFIG[i] to RceEthernet::create(). Each call to create() creates a new Driver object for the interface and puts the new object on the list of all Drivers.
The constructor for Driver does the following:

  • Copies the I/O firmware block assignments for the interface.
  • Creates the import buffer pool.
  • Invalidates cache entries for the import buffers.
  • Places TDEs for the import buffer descriptors in the FLB queue.
  • Creates and starts the ehc, ehf and ahr tasks for this interface.
  • Sets FLB thresholds which decide when it enters the Full and Empty states.
  • Enables I/O firmware block events and faults; sets up handling of same.

IP stack (BSD net) setup

After each call to RceEthernet::create() in the loop described in the previous section, RceInit::configure_network_from_dhcp() checks to see whether i is equal to its argument INTF. If it is then the function calls RceBsdnet::create() which does the following:

  • Creates a new rtems_bsdnet_ifconfig struct with these elements set:
    • name="eth<i>" where <i> is the interface index in the loop.
    • attach=bsdnetAttach (our attach function to be used by the stack).
    • ip_address="0.0.0.0". Good enough for DHCP.
    • ip_netmask="0.0.0.0". Good enough for DHCP.
    • rbuf_count=256. The number of mbufs to allocate to this interface for reception.
    • xbuf_count=256. The number of mbufs to allocate to this interface for transmission.
  • Adds the new ifconfig struct to the list starting at rtems_bsdnet_config.ifconfig.
  • Adds a new Handler to the list of all BSDnet Handlers.

RceBsdnet::Handler derives from RceEthernet::Handler. Despite the name, each Handler plays the role of an interface driver from the point of view of the IP stack, whereas a Driver controls an actual plugin. The Handler constructor

  • Passes the Driver reference to the base class constructor which
    • Stores it in its member _ethernet_driver.
    • Sets the Driver's pointer-to-Handler to this Handler.
  • Creates this handler's export wait semaphore (initial state Red).
  • Creates this handler's pool of export buffers (which turns the export wait semaphore Green).
  • Creates and initializes this handler's struct arpcom instance, whose hardware address we set to the ethernet MAC adddress (by copying). The beginning of the struct arpcom is the struct ifnet that will be used to describe this ethernet as an IP network device. We set the following ifnet members (all others are zero/null):
    • if_softc to the address of this Handler.
    • if_unit to the unit number (the index of the ethernet plugin).
    • if_name to "eth".
    • if_init to the address of the function bsdnetInit().
    • if_ioctl to the address of bsdnetIoctl().
    • if_start to the address of bsdnetSend().
    • if_output to the address of ether_output().
    • if_flags to IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST.
    • if_snd.ifq_maxlen to the export buffer count gotten from configuration flash.

The bsdnetXxxx() routines are static functions in the source file for Bsdnet::Handler that redirect the operation the corresponding member of the right Handler. ether_output() is a IP stack routine that knows how to queue data to send for an interface, not a simple matter since you have to check for valid routing and perhaps do ARP resolution.

Routing configuration

After creating all the Drivers and Handlers required configure_network_from_dhcp() calls RceBsdnet::configure() with a null pointer, which means that no routing information is being passed down into the IP stack. This function finishes the filling of the global rtems_bsdnet_config struct:

  • The places reserved for routing info are set to zeros.
  • The bootp member is set to the address of rtems_bsdnet_do_dhcph().
  • The total number of bytes needed for mbufs and for mbuf clusters is filled in. All the rbuf_count values and xbuf_count values in the ifconfig chain are added up to get a total buffer count. Enough clusters bytes are requested to allow a jumbo frame per mbuf. (An mbuf by itself can hold very little data, 100 bytes of so. For larger packets the data are put into a data area called an mbuf cluster which the mbuf refers to).

After that RceBsdnet::configure() calls rtems_bsdnet_initialize_network() which will set up all the buffering, call our attach function, set up primitive routing given the limited information we've given (0.0.0.0 for both IP number and netmask), etc. It will then call our bootp function to finish up the job.

rtems_bsdnet_synchronize_ntp(0, 0) is run after rtems_bsdnet_initialize_network(). The lab 1 DHCP server isn't configured to send any NTP server addresses so this never works.

IP interface attachment

An attach function takes two arguments: a pointer to an rtems_bsdnet_ifconfig struct and an int attach flag which is one for attach and zero for detach. Our attach function bsdnetAttach ignores the attach flag since we never detach our ethernet interfaces. The function finds the Handler for the interface by looking it up by the device name, e.g., "eth0" then gets the address ifp of the ifnet struct embedded in the Handler instance. It then calls if_attach(ifp) and then ether_ifattach(ifp). The former places *ifp on the end of the chain of attached interfaces and allocates some working space for the interface. The latter fills in ethernet-specific values in *ifp such as interface type, address length, header length, MTU (standard 1500), etc.

DHCP

Our bootp function rtems_bsdnet_do_dhcph() looks through the list of attached interfaces and for any that are not loopback or point-to-point devices it calls rtems_bsdnet_do_dhcp_ex() giving our routine handle_dhcp_options() as the callback for one extended DHCP option named "RCE". The standard DHCP option processing included with RTEMS will adjust the parameters of the interface used to send the DHCP request.

The extended option allows the secondary ethernet found on some RCE boards to be configured as well; in our labs the secondary ethernet has no DHCP server of its own. Our extended option callback function gets the secondary hardware address,IP address and netmask from the extended option, finds the Driver with matching hardware address, adds a new RceBsdnet::Handler to the Handler list, calls if_attach() and ether_attach(), then sets the secondary interface's MTU size to jumbo. Then RceNet::DhcpIfConfig::apply() is called to set the actual IP addressing and routing info for the interface.

From /etc/dhcpd.conf on rdsrv100:

# RCE43
host rce43 {
  hardware ethernet 08:00:56:00:43:31;
  fixed-address 172.21.6.70;
  option host-name "rce43";
  option tgt_config.secondary_interfaces = concat(08:00:56:00:42:31,ac:15:6:46,ff:ff:ff:00);
}

Operation

Sending data

The socket code calls the "driver" output function which in this case is the function ether_output() supplied by the IP stack. Assuming that the routing is OK it adds the chain of mbufs to the outgoing chain of the interface and calls the "driver" start function bsdnetSend(). The start function calls the send() member function of the RceBsdnet::Handler; the Handler address was previously stored in the if_softc member of the ifnet struct for the interface. The member function takes the RTEMS central networking semaphore and loops over all mbufs queued to the interface for sending:

  • Wait if necessary for a buffer to become available from the export pool.
  • Copy data into the export buffer from the mbuf. Make only a header if the data in the mbuf is short enough.
  • Release the mbuf back to the IP stack.
  • Call the post() member function of the Driver associated with this Handler, passing the RcePic::Descr describing the export buffer that we just filled.

After running out of queued mbufs we release the central networking semaphore.

The post() member function of the Driver first performs a cache flush for all the memory in the export buffer and the associated Tds, since these are allocated in cached memory. It then pushes a TDE (with the "don't complete" and "contiguous" flags both zero) for the Tds onto the queue in the associated PEB, assuming that the PEB's queue is not full. When a Full event for the PEB occurs the "ehf" task for this interface will take a semaphore which it will release only when some space has been freed on the queue. The TDE posted contains the ID number of the ECB to which the export-completion event will be posted. The "ehc" task for this interface pulls TDEs for completions out of the ECB queue. It traces back from the TDE to the descriptor (class Tds) to the Descr object which it passes to the completed() member function of the associated Handler, which puts the buffer back in the export pool.

Receiving data

The "ehr" task for the interface runs an endless loop in Driver::receive(). When a TDE becomes available the task dequeues it and traces back to the Descr associated with the import buffer that was filled. If no error occurred during reception and the packet is an IP, ARP or reverse-ARP packet the driver passes the Descr to the received() member function of the Handler associated with the interface. That member function takes the central networking semaphore, copies the data into an mbuf and then passes the mbuf into the IP stack by calling ether_input(). Then it releases the central semaphore and calls the release() member function of the Driver, which invalidates any cache entries for the import buffer and Tds then queues a new TDE in the FLB.

In case of a read error the call to ether_input() is skipped; cache entries for the Tds and the only header portion of the import buffer are invalidated before a new TDE is queued (since the payload will not have been referenced by the processor).

Source code structure

The RTEMS copy of the IP stack is all contained in the directory tree RTEMSROOT/src/cpukit/libnetworking/.

The RCE raw ethernet code (RceEthernet::Driver et al.) is in rce/ethernet/.

The RCE interface layer between the raw ethernet code and the IP stack (RceBsdnet::Handler et al.) is in rce/bsdnet.

The network configuration driver function RceInit::configure_network_from_dhcp() and the code to extract ethernet parameters from configuration flash are in rceuser/init/.

The code that implements manipulation of the I/O firmware blocks and which defines the Tds, Descr and Tde classes is in rce/pic/. (PIC, or Protocol Interface Core, is an older generic name for the I/O firmware blocks.)

IP stack data structures in detail

There are several key data structures used by client code to communicate configuration information to the IP stack.

General RTEMS networking configuration

This is a global variable named rtems_bsdnet_config of type struct rtems_bsdnet_config which is defined by client code and used by RTEMS. The definition of the struct is in libnetworking/rtems/rtems_bsdnet.h.

 
struct rtems_bsdnet_config { 
struct rtems_bsdnet_ifconfig *ifconfig; 
void (*bootp)(void); 
rtems_task_priority network_task_priority; 
unsigned long mbuf_bytecount; 
unsigned long mbuf_cluster_bytecount; 
char *hostname; 
char *domainname; 
char *gateway; 
char *log_host; 
char *name_server[3]; 
char *ntp_server[3]; 
unsigned long sb_efficiency; 
unsigned long udp_tx_buf_size; 
unsigned long udp_rx_buf_size; 
unsigned long tcp_tx_buf_size; 
unsigned long tcp_rx_buf_size; 
}; 

The following members don't have default values:

  • ifconfig. A singly-linked list of configuration data structures, each of which describes one network interface. See the next section.
  • bootp. A pointer to a function that configures interfaces using BOOTP, DHCP or some other way of accessing configuration data that is not available on the local host. Should be null if no such member function is to be used.

Any of these values may be set to zero in which case the IP stack will set them to default values or assume that BOOTP/DHCP will be used to set them.

  • network_task_priority [100]. The RTEMS priority of the "ntwk" daemon task.
  • mbuf_bytecount [64K]. The total number of bytes to malloc for mbufs, which are chainable buffers each capable of holding about 100 bytes directly or which can refer to a much larger buffer called an mbuf cluster.
  • mbuf_cluster_bytecount [128K]. The total amount of memory to malloc for non-chainable buffers used to hold packets too large to fit into an mbuf. In our case we require that each cluster be able to hold a jumbo ethernet packet of about 9000 bytes.
  • hostname [DHCP]. The short host name, without any domain.
  • domainname [DHCP]. The rest of the fully qualified domain name with no leading period.
  • gateway [DHCP]. The dotted IP number string for the local router.
  • log_host [DHCP]. The dotted IP number string of a host that will receive log entries from the RTEMS logging package.
  • name_server [DHCP]. Up to three dotted IP number strings of DNS servers.
  • ntp_server [DHCP]. Up to three dotted IP number strings of NTP servers.
  • sb_efficiency [2]. The "socket buffer efficiency" factor. This factor is used to multiply the number of mbufs assigned to a socket for one direction of transfer. The default is simple double-buffering so that one group of mbufs is available while the other is in use by client code or by the network interface.
  • udp_tx_buf_size [9216]. The maximum number of buffered data bytes (to be held in mbuf/cluster buffers) allowed for the transmission side of a UDP socket.
  • udp_rx_buf_size [about 41K]. The maximum number of buffered data bytes allowed per socket for UDP reception.
  • tcp_tx_buf_size [16K]. The maximum number of buffered data bytes per socket for TCP transmission.
  • tcp_rx_buf_size [16K]. The maximum number of buffered data bytes per socket for TCP reception.

Individual network interface configuration

For every interface that we want the IP stack to manage we have to provide it with with an instance of struct rtems_bsdnet_ifconfig declared in libnetworking/rtems/rtems_bsdnet.h. We have to place all the instances in a chain hanging from the ifconfig member of the global rtems_bsdnet_config structure.

 
struct rtems_bsdnet_ifconfig { 
char *name; 
int (*attach)(struct rtems_bsdnet_ifconfig *conf, int attaching); 
struct rtems_bsdnet_ifconfig *next; 
char *ip_address; 
char *ip_netmask; 
void *hardware_address; 
int ignore_broadcast; 
int mtu; 
int rbuf_count; 
int xbuf_count; 

// Plus more members we don't care about. 
}; 

The following values are always required:

  • name. The short device name string in form <type><number>, e.g., "eth0".
  • attach. A pointer to the device attach/detach function, where the value of "attaching" is 1 to attach, else 0.
  • next. A pointer to the next ifconfig in the chain (or null).

These values may be set to zero/null if they're to be obtained via DHCP or some other deferred configuration scheme.

  • ip_address. The dotted IP number string for the local host.
  • ip_netmask. The dotted IP number string for the local netmask.
  • hardware_address. A pointer to the hardware address. For ethernet the hardware address is the 48-bit MAC address in binary form; the address 00:01:02:03:04:05 is represented as the byte sequence
     
    uint8_t mac[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05}; 
    

These values may also be set to zero/null in which case the "driver" supplies them.

  • ignore_broadcast. In this case the driver can't tell if a zero means "accept broadcasts" or "set by driver" so I guess we should always set it to what we really want.
  • mtu. The MTU size in bytes.
  • rbuf_count. The number of reception mbufs (and mbuf clusters) for the network interface.
  • xbuf_count. The number of transmission mbufs (and mbuf clusters) needed for the interface.

Description of an attached network interface

An attached interface, one which is ready to be activated, is described by a struct ifnet node on a global list maintained by the IP stack. This structure is "native" to the IP stack and is not RTEMS-specific. The ifnet structure for a given interface is prepared by the attach function set in the struct rtems_bsdnet_ifconfig we made for the interface. The attach function then passes a pointer to the ifnet structure to the stack's if_attach() function which puts it on the list of attached interfaces. Lastly the attach function passes the struct ifnet* value to the stack's ether_ifattach() function which fills in the ethernet-specific data such as the interface type, MTU size, header size and so on.

 
struct ifnet { 
void *if_softc; /* pointer to driver state, which is anything the driver wants it to be. */ 
char *if_name; /* name, e.g. ``en'' or ``lo'' */ 
struct ifnet *if_next; /* all struct ifnets are chained */ 
struct ifaddr *if_addrlist; /* linked list of addresses per if */ 
int if_pcount; /* number of promiscuous listeners */ 
struct bpf_if *if_bpf; /* packet filter structure */ 
u_short if_index; /* numeric abbreviation for this if */ 
short if_unit; /* sub-unit for lower level driver */ 
short if_timer; /* time 'til if_watchdog called */ 
int if_flags; /* up/down, broadcast, etc. */ 
void *if_linkmib; /* link-type-specific MIB data */ 
size_t if_linkmiblen; /* length of above data */ 
struct if_data if_data; 
/* procedure handles */ 
int (*if_output) /* output routine (enqueue) */ 
(struct ifnet *, struct mbuf *, struct sockaddr *, 
struct rtentry *); 
void (*if_start) /* initiate output routine */ 
(struct ifnet *); 
int (*if_ioctl) /* ioctl routine */ 
(struct ifnet *, ioctl_command_t, caddr_t); 
void (*if_watchdog) /* timer routine */ 
(struct ifnet *); 
int (*if_poll_recv) /* polled receive routine */ 
(struct ifnet *, int *); 
int (*if_poll_xmit) /* polled transmit routine */ 
(struct ifnet *, int *); 
void (*if_poll_intren) /* polled interrupt re-enable routine */ 
(struct ifnet *); 
void (*if_poll_slowinput) /* input routine for slow devices */ 
(struct ifnet *, struct mbuf *); 
void (*if_init) /* Init routine */ 
(void *); 
int (*if_tap) /* Packet filter routine */ 
(struct ifnet *, struct ether_header *, struct mbuf *); 
struct ifqueue if_snd; /* output queue */ 
struct ifqueue *if_poll_slowq; /* input queue for slow devices */ 
}; 

struct if_data { 
/* generic interface information */ 
u_char ifi_type; /* ethernet, tokenring, etc */ 
u_char ifi_physical; /* e.g., AUI, Thinnet, 10base-T, etc */ 
u_char ifi_addrlen; /* media address length */ 
u_char ifi_hdrlen; /* media header length */ 
u_char ifi_recvquota; /* polling quota for receive intrs */ 
u_char ifi_xmitquota; /* polling quota for xmit intrs */ 
u_long ifi_mtu; /* maximum transmission unit */ 
u_long ifi_metric; /* routing metric (external only) */ 
u_long ifi_baudrate; /* linespeed */ 
/* volatile statistics */ 
u_long ifi_ipackets; /* packets received on interface */ 
u_long ifi_ierrors; /* input errors on interface */ 
u_long ifi_opackets; /* packets sent on interface */ 
u_long ifi_oerrors; /* output errors on interface */ 
u_long ifi_collisions; /* collisions on csma interfaces */ 
u_long ifi_ibytes; /* total number of octets received */ 
u_long ifi_obytes; /* total number of octets sent */ 
u_long ifi_imcasts; /* packets received via multicast */ 
u_long ifi_omcasts; /* packets sent via multicast */ 
u_long ifi_iqdrops; /* dropped on input, this interface */ 
u_long ifi_noproto; /* destined for unsupported protocol */ 
u_long ifi_recvtiming; /* usec spent receiving when timing */ 
u_long ifi_xmittiming; /* usec spent xmitting when timing */ 
struct timeval ifi_lastchange; /* time of last administrative change */ 
}; 

Buffer allocation hook

The stack uses the function rtems_bsdnet_malloc_mbuf() to allocate all mbufs, mbuf clusters and cluster reference counts; the type of allocation is given by one of the arguments. The version supplied by RTEMS uses malloc() to do the allocation but we could supply our own version.

Call trees

RTEMS pre-driver stage

  • rce_bsp_predriver_hook()
    • RceEthernet::initialize() (rce/ethernet/src/Ethernet.cc)
      • Create empty List of RceEthernet::Driver.
    • RceBsdnet::initialize() (rce/bsdnet/src/Bsdnet.cc)
      • Create empty List of RceEthernet::Handler

init_executive()

  • init_executive (rceapp/core/devel.cc or prod.cc)
    • RceInit::configure_network_from_dhcp(unsigned interfaceNum) (rceusr/init/src/NetworkingConfig.cc)
      • Retrieves ethernet MAC addresses, number of buffers, header sizes and max payload sizes.
      • Calls RceEthernet::create(const RceEthernet::Params&) for each interface. (rce/ethernet/src/Ethernet.cc)
        • Create new RceEthernet::Driver(const RceEthernet::Params&)
          • Copy PIC block assignments.
          • Create new pool of Descriptors and buffers for import.
          • Invalidate buffer cache entries and place TDEs in the FLB.
          • Create and start the tasks ehc<n> (ECB events), ehr<n> (PIB events) and ehf<n> (PEB full).
          • Set FLB thresholds.
          • Enable PIC block events and faults; set up handling of same.
        • Add new Driver to the List.
      • If i == interfaceNum, calls RceBsdnet::create(name, ip=="0.0.0.0", netmask=="0.0.0.0") (rce/bsdnet/src/Bsdnet.cc)
        • Create a new rtems_bsdnet_ifconfig struct. name=name, attach=bsdnetAttach (defined in the same source file), ip_address="0.0.0.0", ip_netmask="0.0.0.0", rbuf_count=256, xbuf_count=256.
        • Add the new ifconfig struct to the list starting at rtems_bsdnet_config.ifconfig.
        • Add a new Handler(driver,ifconfig) to the list of BSDnet handlers.
      • RceBsdnet::configure(Routing* r==0) (rce/bsdnet/src/Bsdnet.cc)
        • Fills parts of structure rtems_bsdnet_config: network_task_priority=80, hostname=domainname=gateway=name_server[0]=ntp_server[0], bootp=rtems_bsdnet_do_dhcph. Member ifconfig is already set to a linked list of rtems_bsdnet_ifconfig structures.
        • More settings in bsdnet_config using data from the ifconfig list: mbuf_bytecount=number of bytes fneeded for mbuf structs (1 struct per buffer), mbuf_cluster_bytecount=number of network data buffer bytes assuming jumbo packet, where each packet size is rounded up to a number of fixed-sized "clusters".
        • rtems_bsdnet_initialize_network() (4.10.0/src/cpukit/libnetworking/rtems/rtems_glue.c)
          • rtems_bsdnet_initialize() (rtems_glue.c)
            • Set allocation limits for mbufs and clusters based on the byte counts.
            • rtems_set_udp_buffer_sizes() (4.10.0/src/cpukit/libnetworking/netinet/udp_usrreq.c)
              • Sets the max datagram sizes for send and recv but does no allocation.
            • rtems_set_tcp_buffer_sizes() (4.10.0/src/cpukit/libnetworking/netinet/tcp_usrreq.c)
              • Sets the default window sizes for send and receive but does no allocation.
            • rtems_set_sb_efficiency() (4.10.0/src/cpukit/libnetworking/kern/uipc_socket2.c)
            • Wait until seconds-since-boot >= 1brtems_g
            • bsd_init() (rtems_glue.c)
              • rtems_bsdnet_malloc_mbuf()
                • Allocates clusters.
              • rtems_bsdnet_malloc_mbuf()
                • Allocates cluster reference counts.
              • rtems_bsdnet_malloc_mbuf()
                • Allocates mbuf structs.
              • Set domain list (inetdomain for AF_INET followed by routedomain, head ptr is global var "domains"). The global var inetdomain is filled in 4.10.0/src/cpukit/libnetworking/netinet/in_proto.c while routedomain is filled in libnetworking/net/rtsock.c.
              • domaininit(NULL) (4.10.0/src/cpukit/libnetworking/kern/uipc_domain.c)
                • Call dom_init() callback if any for each domain. It's null for PF_INET; it's route_init() for PF_ROUTE (in libnetworking/net/route.c) which sets up the rudimentary routing tables for IP addresses all zeros and all ones.
                • Call pr_init() callback for each protcol in each domain. For PF_INET that's ip_init(), udp_init(), tcp_init(), igmp_init(), div_init() (for DIVERT), rip_init() (for raw IP). For PF_ROUTE that's raw_init() for SOCK_RAW.
                • Set handling routines for fast and slow timeouts (???)
              • sysctl_register_all(0)
                • Set up the "sysctl" tree in memory. It's like a filesystem where the leaf nodes are kernel parameters, in this case only those affecting BSD networking.
              • ifinit(NULL) (libnetworking/net/if.c)
                • Sets interface queue lengths not already specified.
            • rtems_bsdnet_newproc() (rtems_glue.c)
              • Used to create and start a task named "ntwk" with a stack size of 4K and entry point networkDaemon() (also in rtems_glue.c).
          • For each interface call rtems_bsdnet_attach() (rtems_glue.c)
            • In our case this calls bsdnetAttach() in rce/bsdnet/Bsdnet.cc (attaching=1)
              • if_attach() (in if.c)
                • Adds the interface to a global list of attached interfaces and allocates it some working space.
              • ether_ifattach() (libnetworking/net/if_ethersubr.c)
                • Sets interface parameters such as type, address length, header length, MTU (standard 1500), etc.
          • rtems_bsdnet_setup()
            • Set local parameters such as hostname, domain name, host IP, name server IPs, NTP server IP.
            • XXX
          • rtems_bsdnet_do_dhcph() (rce/bsdnet/src/Bsdnet.cc)