Generic LAN Driver Overview
GLD is a multi-threaded, clonable, loadable kernel module providing support to device drivers
for local area networks. Local area network (LAN) device drivers in the Solaris
OS are STREAMS-based drivers that use DLPI to communicate with network protocol stacks.
These protocol stacks use the network drivers to send and receive packets on
a local area network.
A network device driver must implement and conform to these requirements:
GLD implements most STREAMS and DLPI functionality required of a Solaris LAN driver.
Several Solaris network drivers are implemented using GLD.
A Solaris network driver that is implemented using GLD is made up of
two distinct parts: a generic component that deals with STREAMS and DLPI interfaces,
and a device-specific component that deals with the particular hardware device. The device-specific
module indicates its dependency on the GLD module, which is found at /kernel/misc/gld.
The device-specific module then registers with GLD from within the driver's attach(9E) function. After
the device-specific module is successfully loaded, the driver is DLPI-compliant. The device-specific
part of the driver calls gld(9F) functions when that part receives data or
needs some service from GLD. When the device-specific driver registers with the GLD,
the driver provides pointers to the entry points for later use by GLD.
GLD makes calls into the gld(9E) using these pointers. The gld_mac_info(9S)
structure is the main data interface between GLD and the device-specific driver.
The GLD facility currently supports the following types of devices:
DL_ETHER, that is, ISO 8802-3, IEEE 802.3 protocol
DL_TPR, that is, IEEE 802.5, Token Passing Ring
DL_FDDI, that is, ISO 9314-2, Fibre Distributed Data Interface
GLD drivers are expected to process fully formed MAC-layer packets and should not perform
logical link control (LLC) handling.
In some cases, a full DLPI-compliant driver can be implemented without using the
GLD facility. One case would be devices that are not ISO 8802-style, that
is, IEEE 802, LAN devices. Another case would be devices or services that
are not supported by GLD.
Type DL_ETHER: Ethernet V2 and ISO 8802-3 (IEEE 802.3)
For devices designated type DL_ETHER, GLD provides support for both Ethernet V2 and
ISO 8802-3 (IEEE 802.3) packet processing. Ethernet V2 enables a user to access
a conforming provider of data link services without special knowledge of the provider's
protocol. A service access point (SAP) is the point through which the user
communicates with the service provider.
Streams bound to SAP values in the range [0-255] are treated as equivalent
and denote that the user wants to use 8802-3 mode. If the SAP
value of the DL_BIND_REQ is within this range, GLD computes the length of
each subsequent DL_UNITDATA_REQ message on that stream. The length does not include
the 14-byte media access control (MAC) header. GLD then transmits 8802-3 frames that have
those lengths in the MAC frame header type fields. Such lengths never
exceed 1500.
All frames that are received from the media that have a type
field in the range [0-1500] are assumed to be 8802-3 frames. These frames
are routed up all open streams in 8802-3 mode. Those streams with SAP
values in the [0-255] range are considered to be in 8802-3 mode. If
more than one stream is in 8802-3 mode, the incoming frame is duplicated
and routed up these streams.
Those streams that are bound to SAP values that are greater than 1500
are assumed to be in Ethernet V2 mode. These streams receive incoming packets
whose Ethernet MAC header type value exactly matches the value of the SAP
to which the stream is bound.
Types DL_TPR and DL_FDDI: SNAP Processing
For media types DL_TPR and DL_FDDI, GLD implements minimal SNAP (Sub-Net Access Protocol)
processing. This processing is for any stream that is bound to a SAP
value that is greater than 255. SAP values in the range [0-255] are LLC
SAP values. Such values are carried naturally by the media packet format. SAP
values that are greater than 255 require a SNAP header, subordinate to the
LLC header, to carry the 16-bit Ethernet V2-style SAP value.
SNAP headers are carried under LLC headers with destination SAP 0xAA. Outbound
packets with SAP values that are greater than 255 require an LLC+SNAP header
take the following form:
AA AA 03 00 00 00 XX XX
``XX XX'' represents the 16-bit SAP, corresponding to the Ethernet V2 style ``type.''
This header is unique in supporting non-zero organizational unique identifier fields. LLC
control fields other than 03 are considered to be LLC packets with SAP
0xAA. Clients wanting to use SNAP formats other than this format must use LLC
and bind to SAP 0xAA.
Incoming packets are checked for conformance with the above format. Packets that conform
are matched to any streams that have been bound to the packet's 16-bit
SNAP type. In addition, these packets are considered to match the LLC
SNAP SAP 0xAA.
Packets received for any LLC SAP are passed up all streams that are
bound to an LLC SAP, as described for media type DL_ETHER.
Type DL_TPR: Source Routing
For type DL_TPR devices, GLD implements minimal support for source routing. Source routing
support includes the following items:
Specify routing information for a packet to be sent across a bridged medium. The routing information is stored in the MAC header. This information is used to determine the route.
Learn routes.
Solicit and respond to requests for information about possible multiple routes
Select among available routes.
Source routing adds routing information fields to the MAC headers of outgoing packets.
In addition, this support recognizes such fields in incoming packets.
GLD's source routing support does not implement the full route determination entity (RDE)
specified in Section 9 of ISO 8802-2 (IEEE 802.2). However, this support can interoperate with any
RDE implementations that might exist in the same or a bridged network.
Style 1 and Style 2 DLPI Providers
GLD implements both Style 1 and Style 2 DLPI providers. A physical point
of attachment (PPA) is the point at which a system attaches itself to
a physical communication medium. All communication on that physical medium funnels through the
PPA. The Style 1 provider attaches the streams to a particular PPA based
on the major or minor device that has been opened. The Style 2
provider requires the DLS, that is, the data link service, user to
explicitly identify the desired PPA using DL_ATTACH_REQ. In this case, open(9E) creates a stream between
the user and GLD, and DL_ATTACH_REQ subsequently associates a particular PPA with that
stream. Style 2 is denoted by a minor number of zero. If a
device node whose minor number is not zero is opened, Style 1 is
indicated and the associated PPA is the minor number minus 1. In both
Style 1 and Style 2 opens, the device is cloned.
Implemented DLPI Primitives
GLD implements several DLPI primitives. The DL_INFO_REQ primitive requests information about the DLPI streams.
The message consists of one M_PROTO message block. GLD returns device-dependent values in
the DL_INFO_ACK response to this request. These values are based on information that
the GLD-based driver specified in the gldm_mac_info(9S) structure that was passed to
gld_register().
GLD returns the following values on behalf of all GLD-based drivers:
Version is DL_VERSION_2
Service mode is DL_CLDLS, GLD implements connectionless-mode service.
Provider style is DL_STYLE1 or DL_STYLE2, depending on how the stream was opened.
No optional Quality of Service (QOS) support is present. The QOS fields are zero.
Note - Contrary to the DLPI specification, GLD returns the device's correct address length and
broadcast address in DL_INFO_ACK even before the stream has been attached to a
PPA.
The DL_ATTACH_REQ primitive is used to associate a PPA with a stream. This
request is needed for Style 2 DLS providers to identify the physical medium
over which the communication is sent. Upon completion, the state changes from DL_UNATTACHED
to DL_UNBOUND. The message consists of one M_PROTO message block. This request is not
allowed when Style 1 mode is used. Streams that are opened using Style
1 are already attached to a PPA by the time the open completes.
The DL_DETACH_REQ primitive requests to detach the PPA from the stream. This detachment
is allowed only if the stream was opened using Style 2.
The DL_BIND_REQ and DL_UNBIND_REQ primitives bind and unbind a DLSAP (data link service
access point) to the stream. The PPA that is associated with a stream
completes initialization before the completion of the processing of the DL_BIND_REQ on that
stream. You can bind multiple streams to the same SAP. Each stream in this
case receives a copy of any packets that were received for that
SAP.
The DL_ENABMULTI_REQ and DL_DISABMULTI_REQ primitives enable and disable reception of individual multicast group
addresses. Through iterative use of these primitives, an application or other DLS user
can create or modify a set of multicast addresses. The streams must be
attached to a PPA for these primitives to be accepted.
The DL_PROMISCON_REQ and DL_PROMISCOFF_REQ primitives turn promiscuous mode on or off on a
per-stream basis. These controls operate at either at a physical level or at
the SAP level. The DL Provider routes all received messages on the media
to the DLS user. Routing continues until a DL_DETACH_REQ is received, a DL_PROMISCOFF_REQ
is received, or the stream is closed. You can specify physical level promiscuous
reception of all packets on the medium or of multicast packets only.
Note - The streams must be attached to a PPA for these promiscuous mode primitives
to be accepted.
The DL_UNITDATA_REQ primitive is used to send data in a connectionless transfer. Because
this service is not acknowledged, delivery is not guaranteed. The message consists of
one M_PROTO message block followed by one or more M_DATA blocks containing at
least one byte of data.
The DL_UNITDATA_IND type is used when a packet is to be passed on
upstream. The packet is put into an M_PROTO message with the primitive set
to DL_UNITDATA_IND.
The DL_PHYS_ADDR_REQ primitive requests the MAC address currently associated with the PPA attached
to the streams. The address is returned by the DL_PHYS_ADDR_ACK primitive. When using Style
2, this primitive is only valid following a successful DL_ATTACH_REQ.
The DL_SET_PHYS_ADDR_REQ primitive changes the MAC address currently associated with the PPA attached
to the streams. This primitive affects all other current and future streams attached
to this device. Once changed, all streams currently or subsequently opened and attached to
this device obtain this new physical address. The new physical address remains
in effect until this primitive changes the physical address again or the driver
is reloaded.
Note - The superuser is allowed to change the physical address of a PPA
while other streams are bound to the same PPA.
The DL_GET_STATISTICS_REQ primitive requests a DL_GET_STATISTICS_ACK response containing statistics information associated with the PPA
attached to the stream. Style 2 Streams must be attached to a particular
PPA using DL_ATTACH_REQ before this primitive can succeed.
Implemented ioctl Functions
GLD implements the ioctl ioc_cmd function described below. If GLD receives an unrecognizable
ioctl command, GLD passes the command to the device-specific driver's gldm_ioctl() routine, as described
in gld(9E).
The DLIOCRAW ioctl function is used by some DLPI applications, most notably the
snoop(1M) command. The DLIOCRAW command puts the stream into a raw mode. In raw
mode, the driver passes full MAC-level incoming packets upstream in M_DATA messages instead
of transforming the packets into the DL_UNITDATA_IND form. The DL_UNITDATA_IND form is normally
used for reporting incoming packets. Packet SAP filtering is still performed on
streams that are in raw mode. If a stream user wants to receive
all incoming packets, the user must also select the appropriate promiscuous modes. After
successfully selecting raw mode, the application is also allowed to send fully formatted
packets to the driver as M_DATA messages for transmission. DLIOCRAW takes no arguments. Once
enabled, the stream remains in this mode until closed.
GLD Driver Requirements
GLD-based drivers must include the header file <sys/gld.h>.
GLD-based drivers must be linked with the -N“misc/gld” option:
%ld -r -N"misc/gld" xx.o -o xx
GLD implements the following functions on behalf of the device-specific driver:
The mi_idname element of the module_info(9S) structure is a string that specifies the
name of the driver. This string must exactly match the name of the
driver module as defined in the file system.
The read-side qinit(9S) structure should specify the following elements:
- qi_putp
NULL
- qi_srvp
gld_rsrv
- qi_qopen
gld_open
- qi_qclose
gld_close
The write-side qinit(9S) structure should specify these elements:
- qi_putp
gld_wput
- qi_srvp
gld_wsrv
- qi_qopen
NULL
- qi_qclose
NULL
The devo_getinfo element of the dev_ops(9S) structure should specify gld_getinfo as the getinfo(9E)
routine.
The driver's attach(9E) function associates the hardware-specific device driver with the GLD facility.
attach() then prepares the device and driver for use.
The attach(9E) function allocates a gld_mac_info(9S) structure using gld_mac_alloc(). The driver usually needs to
save more information per device than is defined in the macinfo structure. The
driver should allocate the additional required data structure and save a pointer to
the structure in the gldm_private member of the gld_mac_info(9S) structure.
The attach(9E) routine must initialize the macinfo structure as described in the gld_mac_info(9S)
man page. The attach() routine should then call gld_register() to link the driver
with the GLD module. The driver should map registers if necessary and be
fully initialized and prepared to accept interrupts before calling gld_register(). The attach(9E) function
should add interrupts but should not enable the device to generate these interrupts.
The driver should reset the hardware before calling gld_register() to ensure the hardware is
quiescent. A device must not be put into a state where the
device might generate an interrupt before gld_register() is called. The device is started
later when GLD calls the driver's gldm_start() entry point, which is described in
the gld(9E) man page. After gld_register() succeeds, the gld(9E) entry points might be
called by GLD at any time.
The attach(9E) routine should return DDI_SUCCESS if gld_register() succeeds. If gld_register() fails,
DDI_FAILURE is returned. If a failure occurs, the attach(9E) routine should deallocate any
resources that were allocated before gld_register() was called. The attach routine
should then also return DDI_FAILURE. A failed macinfo structure should never be reused.
Such a structure should be deallocated using gld_mac_free().
The detach(9E)function should attempt to unregister the driver from GLD by calling gld_unregister(). For
more information about gld_unregister(), see the gld(9F) man page. The detach(9E) routine can
get a pointer to the needed gld_mac_info(9S) structure from the device's private data
using ddi_get_driver_private(9F). gld_unregister() checks certain conditions that could require that the driver not
be detached. If the checks fail, gld_unregister() returns DDI_FAILURE, in which case the driver's
detach(9E) routine must leave the device operational and return DDI_FAILURE.
If the checks succeed, gld_unregister() ensures that the device interrupts are stopped. The
driver's gldm_stop() routine is called if necessary. The driver is unlinked from the
GLD framework. gld_unregister() then returns DDI_SUCCESS. In this case, the detach(9E) routine should
remove interrupts and use gld_mac_free() to deallocate any macinfo data structures that were allocated
in the attach(9E) routine. The detach() routine should then return DDI_SUCCESS. The routine
must remove the interrupt before calling gld_mac_free().
Network Statistics
Solaris network drivers must implement statistics variables. GLD tallies some network statistics, but other
statistics must be counted by each GLD-based driver. GLD provides support for GLD-based
drivers to report a standard set of network driver statistics. Statistics are reported
by GLD using the kstat(7D) and kstat(9S) mechanisms. The DL_GET_STATISTICS_REQ DLPI command
can also be used to retrieve the current statistics counters. All statistics are
maintained as unsigned. The statistics are 32 bits unless otherwise noted.
GLD maintains and reports the following statistics.
- rbytes64
Total bytes successfully received on the interface. Stores 64-bit statistics.
- rbytes
Total bytes successfully received on the interface
- obytes64
Total bytes that have requested transmission on the interface. Stores 64-bit statistics.
- obytes
Total bytes that have requested transmission on the interface.
- ipackets64
Total packets successfully received on the interface. Stores 64-bit statistics.
- ipackets
Total packets successfully received on the interface.
- opackets64
Total packets that have requested transmission on the interface. Stores 64-bit statistics.
- opackets
Total packets that have requested transmission on the interface.
- multircv
Multicast packets successfully received, including group and functional addresses (long).
- multixmt
Multicast packets requested to be transmitted, including group and functional addresses (long).
- brdcstrcv
Broadcast packets successfully received (long).
- brdcstxmt
Broadcast packets that have requested transmission (long).
- unknowns
Valid received packets not accepted by any stream (long).
- noxmtbuf
Packets discarded on output because transmit buffer was busy, or no buffer could be allocated for transmit (long).
- blocked
Number of times a received packet could not be put up a stream because the queue was flow-controlled (long).
- xmtretry
Times transmit was retried after having been delayed due to lack of resources (long).
- promisc
Current “promiscuous” state of the interface (string).
The device-dependent driver tracks the following statistics in a private per-instance structure. To
report statistics, GLD calls the driver's gldm_get_stats() entry point. gldm_get_stats() then updates device-specific statistics in
the gld_stats(9S) structure. See the gldm_get_stats(9E) man page for more information. GLD then
reports the updated statistics using the named statistics variables that are shown below.
- ifspeed
Current estimated bandwidth of the interface in bits per second. Stores 64-bit statistics.
- media
Current media type in use by the device (string).
- intr
Number of times that the interrupt handler was called, causing an interrupt (long).
- norcvbuf
Number of times a valid incoming packet was known to have been discarded because no buffer could be allocated for receive (long).
- ierrors
Total number of packets that were received but could not be processed due to errors (long).
- oerrors
Total packets that were not successfully transmitted because of errors (long).
- missed
Packets known to have been dropped by the hardware on receive (long).
- uflo
Times FIFO underflowed on transmit (long).
- oflo
Times receiver overflowed during receive (long).
The following group of statistics applies to networks of type DL_ETHER. These statistics are
maintained by device-specific drivers of that type, as shown previously.
- align_errors
Packets that were received with framing errors, that is, the packets did not contain an integral number of octets (long).
- fcs_errors
Packets received with CRC errors (long).
- duplex
Current duplex mode of the interface (string).
- carrier_errors
Number of times carrier was lost or never detected on a transmission attempt (long).
- collisions
Ethernet collisions during transmit (long).
- ex_collisions
Frames where excess collisions occurred on transmit, causing transmit failure (long).
- tx_late_collisions
Number of times a transmit collision occurred late, that is, after 512 bit times (long).
- defer_xmts
Packets without collisions where first transmit attempt was delayed because the medium was busy (long).
- first_collisions
Packets successfully transmitted with exactly one collision.
- multi_collisions
Packets successfully transmitted with multiple collisions.
- sqe_errors
Number of times that SQE test error was reported.
- macxmt_errors
Packets encountering transmit MAC failures, except carrier and collision failures.
- macrcv_errors
Packets received with MAC errors, except align_errors, fcs_errors, and toolong_errors.
- toolong_errors
Packets received larger than the maximum allowed length.
- runt_errors
Packets received smaller than the minimum allowed length (long).
The following group of statistics applies to networks of type DL_TPR. These
statistics are maintained by device-specific drivers of that type, as shown above.
- line_errors
Packets received with non-data bits or FCS errors.
- burst_errors
Number of times an absence of transitions for five half-bit timers was detected.
- signal_losses
Number of times loss of signal condition on the ring was detected.
- ace_errors
Number of times that an AMP or SMP frame, in which A is equal to C is equal to 0, is followed by another SMP frame without an intervening AMP frame.
- internal_errors
Number of times the station recognized an internal error.
- lost_frame_errors
Number of times the TRR timer expired during transmit.
- frame_copied_errors
Number of times a frame addressed to this station was received with the FS field `A' bit set to 1.
- token_errors
Number of times the station acting as the active monitor recognized an error condition that needed a token transmitted.
- freq_errors
Number of times the frequency of the incoming signal differed from the expected frequency.
The following group of statistics applies to networks of type DL_FDDI. These
statistics are maintained by device-specific drivers of that type, as shown above.
- mac_errors
Frames detected in error by this MAC that had not been detected in error by another MAC.
- mac_lost_errors
Frames received with format errors such that the frame was stripped.
- mac_tokens
Number of tokens that were received, that is, the total of non-restricted and restricted tokens.
- mac_tvx_expired
Number of times that TVX has expired.
- mac_late
Number of TRT expirations since either this MAC was reset or a token was received.
- mac_ring_ops
Number of times the ring has entered the “Ring Operational” state from the “Ring Not Operational” state.