Поделиться через


Отмена сетевых данных с помощью кольцевых сетей

Клиентские драйверы NetAdapterCx отменяют сетевые данные, когда платформа вызывает их EvtPacketQueueCancel функцию обратного вызова для очереди пакетов. Этот обратный вызов используется для того, чтобы драйверы клиентов выполняли любую обработку, необходимую до того, как фреймворк удалит очереди пакетов.

Отмена очереди передачи

В вашей функции обратного вызова EvtPacketQueueCancel для очереди передачи у вас есть возможность завершить все незавершённые пакеты передачи. В отличие от очереди получения, вам не нужно это делать. Если вы оставляете незавершенные пакеты, NetAdapterCx вызывает EvtPacketQueueAdvance для очереди на передачу, где они обрабатываются как часть обычной операции.

Если ваше оборудование поддерживает отмену передач в процессе выполнения, следует также переместить итератор отправленных пакетов в кольце через все отмененные пакеты. Это может выглядеть следующим образом:

void
MyEvtTxQueueCancel(
    NETPACKETQUEUE TxQueue
)
{
    // Get the transmit queue's context to retrieve the net ring collection
    PMY_TX_QUEUE_CONTEXT txQueueContext = MyGetTxQueueContext(TxQueue);
    NET_RING_COLLECTION const * ringCollection = txQueueContext->RingCollection;
    NET_RING * packetRing = ringCollection->Rings[NET_RING_TYPE_PACKET];
    UINT32 currentPacketIndex = packetRing->BeginIndex;
    UINT32 packetEndIndex = packetRing->EndIndex;

    while (currentPacketIndex != packetEndIndex)
    {
        // Mark this packet as canceled with the scratch field, then move past it
        NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
        packet->Scratch = 1;
        currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
    }
    
    packetRing->BeginIndex = packetRing->EndIndex;
}

Если ваше оборудование не поддерживает отмену, функция обратного вызова может закончить выполнение без выполнения какого-либо действия.

Отмена очереди получения

В вашей функции обратного вызова EvtPacketQueueCancel для очереди получения вы должны завершить все невыполненные пакеты получения. Если вы не возвращаете все пакеты, операционная система не удаляет очередь, а NetAdapterCx перестает вызывать обратные вызовы для очереди.

Чтобы возвращать пакеты, сначала следует попытаться указать любые полученные пакеты, которые могли быть указаны во время отключения пути приёма, а затем задать игнорирование всех пакетов и вернуть все фрагменты в ОС. Это может выглядеть следующим примером кода.

Заметка

В этом примере упущены детали, необходимые для указания получения. Пример кода получения данных см. раздел Получение сетевых данных с сетевыми кольцами.

void
MyEvtRxQueueCancel(
    NETPACKETQUEUE RxQueue
)
{
    // Get the receive queue's context to retrieve the net ring collection
    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 = packetRing->BeginIndex;
    UINT32 packetEndIndex = packetRing->EndIndex;

    // Set hardware register for cancellation
    ...
    //

    // Indicate receives
    ...
    //

    // Get all packets and mark them for ignoring
    currentPacketIndex = packetRing->BeginIndex;
    while(currentPacketIndex != packetEndIndex)
    {
        NET_PACKET * packet = NetRingGetPacketAtIndex(packetRing, currentPacketIndex);
        packet->Ignore = 1;
        currentPacketIndex = NetRingIncrementIndex(packetRing, currentPacketIndex);
    }
    
    packetRing->BeginIndex = packetRing->EndIndex;

    // Return all fragments to the OS
    fragmentRing->BeginIndex = fragmentRing->EndIndex;
}