Adding Extensible Switch Destination Port Data to a Packet
This topic describes how Hyper-V extensible switch forwarding extensions can specify the delivery of packets to one or more destination ports. These extensions can also forward packets to individual physical network adapters that are bound to the extensible switch external network adapter.
Note Only a forwarding extension or the switch itself can forward packets to extensible switch ports or individual network adapters.
The following figure shows the data path for packet traffic through the extensible switch driver stack for NDIS 6.40 (Windows Server 2012 R2) and later. Both figures also show the data path for packet traffic to or from the network adapters that are connected to extensible switch ports.
The following figure shows the data path for packet traffic through the extensible switch driver stack for NDIS 6.30 (Windows Server 2012).
Each extensible switch destination port is specified by an NDIS_SWITCH_PORT_DESTINATION element within the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure. This array is contained in the out-of-band (OOB) forwarding context of the packet's NET_BUFFER_LIST structure. For more information on this context, see Hyper-V Extensible Switch Forwarding Context.
If a forwarding extension is bound and enabled in the extensible switch driver stack, it is responsible for determining the destination ports for every packet obtained from the extensible switch ingress data path, unless the packet is an NVGRE packet. For more information about this data path, see Overview of the Hyper-V Extensible Switch Data Path. For more information about NVGRE packets, see Hybrid Forwarding.
Note If a forwarding extension is not bound or enabled in the driver stack, the extensible switch determines the destination ports for packets it obtains from the ingress data path.
The forwarding extension must follow these guidelines when it determines destination ports for a packet obtained on the ingress data path:
The extension must initialize an NDIS_SWITCH_PORT_DESTINATION structure within the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure with the destination port information.
If the destination port is not connected to the external network adapter, the extension must set the NicIndex member of the NDIS_SWITCH_PORT_DESTINATION structure to NDIS_SWITCH_DEFAULT_NIC_INDEX.
If the destination port is connected to the extensible switch external network adapter, the extension can specify the index of an underlying physical network adapter to forward the send request to. The extension does this by setting the NicIndex member to the nonzero NDIS_SWITCH_NIC_INDEX value of the destination network adapter that is bound to the external network adapter.
For more information, see Forwarding Packets to Physical Network Adapters.
The extension must add destination ports to a packet's OOB data only for those ports that have active network adapter connections. If the extension had forwarded an OID_SWITCH_NIC_DISCONNECT request, it must not add a destination port that is associated with the disconnected network adapter.
To improve performance, the extension must only add port destinations that are valid for packet delivery. In this case, the extension must set the IsExcluded member of the destination port's NDIS_SWITCH_PORT_DESTINATION structure to FALSE.
To retain the 802.1Q virtual local area network (VLAN) data in a packet before it is delivered to a port, the extension sets the PreserveVLAN member to TRUE.
To remove the 802.1Q virtual local area network (VLAN) data in a packet before it is delivered to a port, the extension sets the PreserveVLAN member to FALSE.
To retain the 802.1Q priority data in a packet before it is delivered to a port, the extension sets the PreservePriority member to TRUE.
To remove the 802.1Q priority data in a packet before it is delivered to a port, the extension sets the PreservePriority member to FALSE.
If the forwarding extension adds multiple destination ports for a packet, it must follow these steps:
The extension first accesses the packet's NDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO structure by using the NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL macro. The extension then reads the NumAvailableDestinations member to determine how many unused destination port elements are available in the destination port array. If the extension requires more destination ports than are available in the array, it must call the GrowNetBufferListDestinations function to allocate space for additional destination ports in the array.
When the extension calls GrowNetBufferListDestinations, it sets the NumberOfNewDestinations parameter to the number of new destination ports to be added to the packet.
The extension also sets the NetBufferLists parameter to a pointer to the packet's NET_BUFFER_LIST structure.
Note If there are available destination ports in the array, the extension should not call GrowNetBufferListDestinations.
If the GrowNetBufferListDestinations function returns successfully, it has added the additional destination ports to the end of the destination array in the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure. A pointer to this structure is returned in the Destinations parameter.
Note If the GrowNetBufferListDestinations function cannot allocate the requested number of destination ports, it returns NDIS_STATUS_RESOURCES.
The extension specifies new destination port elements in the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure. The extension initializes each new destination port as an NDIS_SWITCH_PORT_DESTINATION structure.
The extension initializes new destination ports to the array starting at the NumDestinations offset. NumDestinations is a member of the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure.
After the extension has finished adding or modifying destination port elements, it must call UpdateNetBufferListDestinations to commit those changes.
If the extension adds a single destination port for a packet, it must follow these steps:
The extension initializes the destination port information for the packet in an extension-allocated NDIS_SWITCH_PORT_DESTINATION structure.
The extension calls AddNetBufferListDestination to commit the changes to the NET_BUFFER_LIST structure for the packet. The extension passes the address of the NDIS_SWITCH_PORT_DESTINATION structure in the Destination parameter.
Note The extension should not call the UpdateNetBufferListDestinations function to commit the changes to a packet with only one destination port.
When the forwarding extension calls AddNetBufferListDestination or UpdateNetBufferListDestinations to commit the changes for destination ports, the extensible switch interface will not delete the extensible switch ports that are specified in the elements of the NDIS_SWITCH_FORWARDING_DESTINATION_ARRAY structure. After the packet send or receive operation is complete, the interface is free to delete the port if it is necessary.
Note After the forwarding extension commits the changes for destination ports to the forwarding context, destination ports cannot be removed and only the IsExcluded member of a destination port's NDIS_SWITCH_PORT_DESTINATION structure can be changed. For more information, see Excluding Packet Delivery to Extensible Switch Destination Ports.
The forwarding extension must synchronize its handling of object identifier (OID) set requests of OID_SWITCH_NIC_DISCONNECT with its code that adds destination ports for the disconnected network adapter.
If the forwarding extension's FilterOidRequest is called for an OID_SWITCH_NIC_DISCONNECT request, the extension can do one of the following:
If the extension called NdisFOidRequest to forward this OID request, it must not specify the port with the disconnected network adapter as a destination port for the packet.
Note If the only destination port for the packet is the one with the disconnected network adapter, the extension must drop the packet.
The extension can return NDIS_STATUS_PENDING to complete the request asynchronously. This allows the extension to add the port with the disconnected network adapter as a destination port for the packet. This also allows the extension to call AddNetBufferListDestination or UpdateNetBufferListDestinations and complete the addition of destination ports to a packet.
The extension may want to do this for packets that it has to forward to a port before it is torn down.
Note If the extension returns NDIS_STATUS_PENDING, it can also call ReferenceSwitchPort to increment the reference counter for the port with the disconnected network adapter. However, the extension cannot forward the OID request until after it calls DereferenceSwitchPort to decrement the reference counter for the port.
If the number of destination ports is zero, the forwarding extension must call NdisMSendNetBufferListsComplete to drop the packet. The extension must also call ReportFilteredNetBufferLists to notify the extensible switch interface about the dropped packet.
Note If the forwarding extension obtained a linked list of NET_BUFFER_LIST structures for multiple packets from the ingress data path, it should create a separate list of dropped packets. By doing this, the extension can call NdisMSendNetBufferListsComplete and ReportFilteredNetBufferLists just once.
If the number of destination ports is greater than zero, the forwarding extension must call NdisFSendNetBufferLists to forward the packet over the ingress data path to the miniport edge of the extensible switch.
Note If the forwarding extension obtained a linked list of NET_BUFFER_LIST structures for multiple packets from the ingress data path, it should create a separate list of forwarded packets. By doing this, the extension can call NdisFSendNetBufferLists just once to forward the list of packets. In addition, the extension should maintain separate lists to forward packets that have the same destination ports. For more information, see Hyper-V Extensible Switch Send and Receive Flags.