Recepción de datos de red con anillos netos

Los controladores de cliente netAdapterCx reciben datos de red cuando el marco invoca su función de devolución de llamada EvtPacketQueueAdvance para una cola de recepción. Durante esta devolución de llamada, los controladores de cliente indican que recibe purgando fragmentos y paquetes recibidos en el sistema operativo y, a continuación, publique nuevos búferes en el hardware.

Introducción a la operación de post y purga de recepción (Rx)

En la siguiente animación se muestra cómo un controlador de cliente para una tarjeta de interfaz de red PCI simple (NIC) realiza operaciones posteriores y purgas para una cola de recepción (Rx). Los búferes de fragmentos de este escenario de ejemplo se asignan y adjuntan al anillo de fragmento mediante el sistema operativo. En este ejemplo se supone una relación uno a uno entre la cola de recepción de hardware y la cola de recepción del sistema operativo.

Animación que ilustra las operaciones de post y purga de anillos netos para recibir una tarjeta de interfaz de red PCI.

En esta animación, los paquetes propiedad del controlador cliente se resaltan en azul claro y azul oscuro, y los fragmentos propiedad del controlador cliente se resaltan en amarillo y naranja. Los colores más claros representan la subsección de purga de los elementos que posee el controlador, mientras que los colores más oscuros representan la subsección posterior de los elementos que posee el controlador.

Recepción de datos en orden

Esta es una secuencia típica para un controlador que recibe datos en orden, con un fragmento por paquete.

  1. Llame a NetRxQueueGetRingCollection para recuperar la estructura de colección de anillos de la cola de recepción. Puede almacenarlo en el espacio de contexto de la cola para reducir las llamadas del controlador. Use la colección de anillos para recuperar el iterador de purga para el anillo de fragmentos y el anillo de paquetes de la cola de recepción.
  2. Indique los datos recibidos en el sistema operativo mediante la purga de los anillos netos:
    1. Asigne variables UINT32 para realizar el seguimiento del índice actual del anillo de fragmento y el índice actual del anillo de paquetes. Establezca estas variables en beginIndex de sus respectivos anillos netos, que es el principio de la subsección de purga del anillo. Asigne una variable UINT32 para el final de la sección de purga del anillo de fragmento estableciendola en nextIndex del anillo de fragmento.
    2. Realice lo siguiente en un bucle:
      1. Compruebe si el hardware ha recibido el fragmento. Si no es así, descompone el bucle.
      2. Llame a NetRingGetFragmentAtIndex para obtener un fragmento.
      3. Rellene la información del fragmento, como su ValidLength, en función de su descriptor de hardware coincidente.
      4. Obtenga un paquete para este fragmento llamando a NetRingGetPacketAtIndex.
      5. Enlace el fragmento al paquete estableciendo fragmentIndex del paquete en el índice actual del fragmento en el anillo de fragmento y estableciendo el número de fragmentos correctamente (en este ejemplo, se establece en 1).
      6. Opcionalmente, rellene cualquier otra información de paquete, como la información de suma de comprobación.
      7. Avance el índice de fragmento llamando a NetRingIncrementIndex.
      8. Avance el índice de paquetes llamando a NetRingIncrementIndex.
    3. Actualice beginIndex del anillo de fragmento a la variable de índice del fragmento actual y actualice beginIndex del anillo de paquetes al índice de paquetes actual para finalizar que indique los paquetes recibidos y sus fragmentos al sistema operativo.
  3. Los búferes de fragmentos posteriores al hardware reciben:
    1. Establezca el índice de fragmento actual en nextIndex del anillo de fragmento, que es el principio de la subsección posterior del anillo. Establezca el índice final del fragmento en endIndex del anillo de fragmento.
    2. Realice lo siguiente en un bucle:
      1. Publique la información del fragmento en el descriptor de hardware coincidente.
      2. Avance el índice de fragmento llamando a NetRingIncrementIndex.
    3. Actualice nextIndex del anillo de fragmento a la variable de índice del fragmento actual para finalizar la publicación de fragmentos en el hardware.

Estos pasos podrían tener este aspecto en el código:

void
MyEvtRxQueueAdvance(
    NETPACKETQUEUE RxQueue
)
{
    //
    // Retrieve the receive queue's ring collection and net rings. 
    // This example stores the Rx queue's ring collection in its queue context space.
    //
    PMY_RX_QUEUE_CONTEXT rxQueueContext = MyGetRxQueueContext(RxQueue);
    NET_RING_COLLECTION const * ringCollection = rxQueueContext->RingCollection;
    NET_RING * packetRing = ringCollection->Rings[NET_RING_TYPE_PACKET];
    NET_RING * fragmentRing = ringCollection->Rings[NET_RING_TYPE_FRAGMENT];
    UINT32 currentPacketIndex = 0;
    UINT32 currentFragmentIndex = 0;
    UINT32 fragmentEndIndex = 0;

    //
    // Indicate receives by draining the rings
    //
    currentPacketIndex = packetRing->BeginIndex;
    currentFragmentIndex = fragmentRing->BeginIndex;
    fragmentEndIndex = fragmentRing->NextIndex;
    while(currentFragmentIndex != fragmentEndIndex)
    {
        // Test for fragment reception. Break if fragment has not been received.
        ...
        //

        NET_FRAGMENT * fragment = NetRingGetFragmentAtIndex(fragmentRing, currentFragmentIndex);
        fragment->ValidLength = ... ;
        NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
        packet->FragmentIndex = currentFragmentIndex;
        packet->FragmentCount = 1;

        if(rxQueueContext->IsChecksumExtensionEnabled)
        {
            // Fill in checksum info
            ...
            //
        }        

        currentFragmentIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex);
        currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
    }
    fragmentRing->BeginIndex = currentFragmentIndex;
    packetRing->BeginIndex = currentPacketIndex;

    //
    // Post fragment buffers to hardware
    //
    currentFragmentIndex = fragmentRing->NextIndex;
    fragmentEndIndex = fragmentRing->EndIndex;
    while(currentFragmentIndex != fragmentEndIndex)
    {
        // Post fragment information to hardware descriptor
        ...
        //

        currentFragmentIndex = NetRingIncrementIndex(fragmentRing, currentFragmentIndex);
    }
    fragmentRing->NextIndex = currentFragmentIndex;
}

Recepción de datos desordenados

A diferencia de una cola Tx , los controladores de cliente no suelen recibir datos desordenados si tienen una cola de recepción del sistema operativo por cola de recepción de hardware. Esto es independientemente del tipo de NIC del controlador cliente. Si el dispositivo está basado en PCI y el sistema operativo asigna y posee los búferes de recepción, o si el dispositivo está basado en USB y la pila USB posee los búferes de recepción, el controlador de cliente inicializa un paquete para cada fragmento recibido e indica al sistema operativo. El orden no es importante en este caso.

Si el hardware admite más de una cola de recepción del sistema operativo por cola de recepción de hardware, debe sincronizar el acceso a los búferes de recepción. El ámbito de hacerlo está fuera de este tema y depende del diseño del hardware.