INFO: Implementation of 64-Bit Statistics in Network Interface Card (NIC) Drivers (263131)



The information in this article applies to:

  • Microsoft Windows 2000 Server
  • Microsoft Windows 2000 Advanced Server
  • Microsoft Windows 2000 Professional
  • Microsoft Windows 2000 Driver Development Kit (DDK)
  • Microsoft Windows XP Driver Development Kit (DDK)

This article was previously published under Q263131

SUMMARY

Miniport statistics are maintained in 32-bit counters. These counters can overflow very quickly given today's media speeds (for example, it takes about 68 seconds at a sustained throughput of 500 megabits per second [Mpbs] to overflow a 32-bit byte counter). Larger counters are therefore needed. This article shows how to implement 64-bit counters in your driver to resolve this problem (at a sustained throughput of 10 gigabits per second, it takes 467 years to overflow a 64-bit byte counter).

MORE INFORMATION

All Gigabit Ethernet drivers must support 64-bit counters for at least the following object identifiers (OIDs). Microsoft recommends that all 100 Mbps and above network interface card (NIC) drivers should support 64-bit counters. Drivers may support 64-bit counters for other statistics OIDs (for example, OID_GEN_XMIT_ERROR):
//  Required statistics.
#define OID_GEN_XMIT_OK                         0x00020101
#define OID_GEN_RCV_OK                          0x00020102

//  Optional statistics.
#define OID_GEN_DIRECTED_BYTES_XMIT             0x00020201
#define OID_GEN_DIRECTED_FRAMES_XMIT            0x00020202
#define OID_GEN_MULTICAST_BYTES_XMIT            0x00020203
#define OID_GEN_MULTICAST_FRAMES_XMIT           0x00020204
#define OID_GEN_BROADCAST_BYTES_XMIT            0x00020205
#define OID_GEN_BROADCAST_FRAMES_XMIT           0x00020206
#define OID_GEN_DIRECTED_BYTES_RCV              0x00020207
#define OID_GEN_DIRECTED_FRAMES_RCV             0x00020208
#define OID_GEN_MULTICAST_BYTES_RCV             0x00020209
#define OID_GEN_MULTICAST_FRAMES_RCV            0x0002020A
#define OID_GEN_BROADCAST_BYTES_RCV             0x0002020B
#define OID_GEN_BROADCAST_FRAMES_RCV            0x0002020C
				

Implementation

The length of the buffer (InformationBufferLength) that is passed in an NDIS_REQUEST for a statistics OID is used to determine how many bits (64, 128, 256, and so on) are required.

The semantics of fields in NDIS_REQUEST.DATA.QUERY_INFORMATION for statistics is as follows:

On Input to NDIS/Miniport

InformationBufferLength = 4 // or 8 bytes depending on what the requestor needs.
				

On Completion

BytesWritten = MIN(InformationBufferLength, N)
				
where N is the maximum bytes of statistics implemented by the miniport:
BytesNeeded = N
				
A miniport that implements 64-bit counters follows the algorithm above to copy the right amount of data to satisfy the request. A code example follows:
// 
// The driver's adapter structure:
// 
typedef struct _NICDRIVER_ADAPTER
{
    ...
    ULONG64			TransmitsOk;
    ...
} _NICDRIVER_ADAPTER, *PNICDRIVER_ADAPTER;

NDIS_STATUS
NicDriverQueryInformation(
                     IN NDIS_HANDLE MiniportAdapterContext,
                     IN NDIS_OID Oid,
                     IN PVOID InformationBuffer,
                     IN ULONG InformationBufferLength,
                     OUT PULONG BytesWritten,
                     OUT PULONG BytesNeeded
                     )
{
    PNICDRIVER_ADAPTER	pAdapter;
    PVOID			MoveSource;
    ULONG			MoveBytes;
    ULONG			GenericUlong;
    ULONG64                     GenericLargeCounter;
    ULONG			MyBytesNeeded;
    NDIS_STATUS		Status;

    pAdapter = (PNICDRIVER_ADAPTER)MiniportAdapterContext;
    MoveSource = &GenericUlong;
    MoveBytes = sizeof(GenericUlong);
    MyBytesNeeded = MoveBytes;
    Status = NDIS_STATUS_SUCCESS;

    switch (Oid)
    {
        case OID_GEN_MAC_OPTIONS:
            GenericUlong = (ULONG)(NDIS_MAC_OPTION_TRANSFERS_NOT_PEND   |                                           
                            NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA  |
                            NDIS_MAC_OPTION_NO_LOOPBACK);
            break;

        case OID_GEN_XMIT_OK:
            // 
            // Modified code to handle 64-bit statistics:
            // 

            GenericLargeCounter = pAdapter->TransmitsOk;
            MoveSource = &GenericLargeCounter;
            MyBytesNeeded = sizeof(GenericLargeCounter);

            // 
            // A statistics counter is at least a ULONGs worth.
            // 

            if (InformationBufferLength < sizeof(ULONG))
            {
            	// Set up for failure return below.
            	MoveBytes = MyBytesNeeded;
            	break;
            }
            MoveBytes = MIN(InformationBufferLength, MyBytesNeeded);
            break;
        
        // Case statements for other OIDs.
    }


    if (Status == NDIS_STATUS_SUCCESS)
    {
    	*BytesNeeded = MyBytesNeeded;
        if (MoveBytes > InformationBufferLength)
        {
            Status = NDIS_STATUS_BUFFER_TOO_SHORT;
        }
        else
        {
            *BytesWritten = MoveBytes;
            if (MoveBytes != 0)
            {
            	NdisMoveMemory(InformationBuffer, MoveSource, MoveBytes);
            }
        }
    }
				

Modification Type:MinorLast Reviewed:7/27/2004
Keywords:kbinfo kbNDIS kbnetwork KB263131