[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH] Use multicast control if the backend supports it.
This required a bit of re-work in the transmitter code since using multicast control necessitates sending dummy transmit requests with special extra info fragments. As a knock-on I also re-worked the way the IP address table is maintained, removing bits that were in the transmitter code into the general frontend code. Re-work was also required in the mac code since it is also necessary to track addition and removal of individual multicast addresses, rather than just handling a table update. Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> --- src/xenvif/frontend.c | 317 ++++++++++--- src/xenvif/frontend.h | 12 + src/xenvif/mac.c | 343 ++++++++++++-- src/xenvif/mac.h | 19 +- src/xenvif/transmitter.c | 1126 +++++++++++++++++++++++++++++++++------------- src/xenvif/transmitter.h | 27 +- src/xenvif/vif.c | 19 +- 7 files changed, 1435 insertions(+), 428 deletions(-) diff --git a/src/xenvif/frontend.c b/src/xenvif/frontend.c index b389b1c..69aed73 100644 --- a/src/xenvif/frontend.c +++ b/src/xenvif/frontend.c @@ -63,7 +63,6 @@ struct _XENVIF_FRONTEND { XENVIF_FRONTEND_STATE State; BOOLEAN Online; KSPIN_LOCK Lock; - PXENVIF_THREAD MibThread; PXENVIF_THREAD EjectThread; KEVENT EjectEvent; @@ -86,6 +85,10 @@ struct _XENVIF_FRONTEND { PXENVIF_FRONTEND_STATISTICS Statistics; ULONG StatisticsCount; + + PXENVIF_THREAD MibThread; + PSOCKADDR_INET AddressTable; + ULONG AddressCount; }; static const PCHAR @@ -229,7 +232,7 @@ FrontendSetMaxQueues( if (NT_SUCCESS(status) && FrontendMaxQueues < Frontend->MaxQueues) Frontend->MaxQueues = FrontendMaxQueues; - Info("%u\n", Frontend->MaxQueues); + Info("%s: %u\n", __FrontendGetPath(Frontend), Frontend->MaxQueues); } static FORCEINLINE ULONG @@ -503,50 +506,49 @@ found: static NTSTATUS FrontendInsertAddress( - IN OUT PSOCKADDR_INET *AddressTable, - IN const SOCKADDR_INET *Address, - IN OUT PULONG AddressCount + IN PXENVIF_FRONTEND Frontend, + IN const SOCKADDR_INET *Address ) { - ULONG Index; - PSOCKADDR_INET Table; - NTSTATUS status; + ULONG Index; + PSOCKADDR_INET Table; + NTSTATUS status; Trace("====>\n"); - for (Index = 0; Index < *AddressCount; Index++) { - if ((*AddressTable)[Index].si_family != Address->si_family) + for (Index = 0; Index < Frontend->AddressCount; Index++) { + if (Frontend->AddressTable[Index].si_family != Address->si_family) continue; if (Address->si_family == AF_INET) { - if (RtlCompareMemory(&Address->Ipv4.sin_addr.s_addr, - &(*AddressTable)[Index].Ipv4.sin_addr.s_addr, - IPV4_ADDRESS_LENGTH) == IPV4_ADDRESS_LENGTH) + if (RtlEqualMemory(&Address->Ipv4.sin_addr.s_addr, + &Frontend->AddressTable[Index].Ipv4.sin_addr.s_addr, + IPV4_ADDRESS_LENGTH)) goto done; } else { ASSERT3U(Address->si_family, ==, AF_INET6); - if (RtlCompareMemory(&Address->Ipv6.sin6_addr.s6_addr, - &(*AddressTable)[Index].Ipv6.sin6_addr.s6_addr, - IPV6_ADDRESS_LENGTH) == IPV6_ADDRESS_LENGTH) + if (RtlEqualMemory(&Address->Ipv6.sin6_addr.s6_addr, + &Frontend->AddressTable[Index].Ipv6.sin6_addr.s6_addr, + IPV6_ADDRESS_LENGTH)) goto done; } } // We have an address we've not seen before so grow the table - Table = __FrontendAllocate(sizeof (SOCKADDR_INET) * (*AddressCount + 1)); + Table = __FrontendAllocate(sizeof (SOCKADDR_INET) * (Frontend->AddressCount + 1)); status = STATUS_NO_MEMORY; if (Table == NULL) goto fail1; - RtlCopyMemory(Table, *AddressTable, sizeof (SOCKADDR_INET) * *AddressCount); - Table[(*AddressCount)++] = *Address; + RtlCopyMemory(Table, Frontend->AddressTable, sizeof (SOCKADDR_INET) * Frontend->AddressCount); - if (*AddressTable != NULL) - __FrontendFree(*AddressTable); + if (Frontend->AddressCount != 0) + __FrontendFree(Frontend->AddressTable); - *AddressTable = Table; + Table[Frontend->AddressCount++] = *Address; + Frontend->AddressTable = Table; done: Trace("<====\n"); @@ -563,9 +565,7 @@ static NTSTATUS FrontendProcessAddressTable( IN PXENVIF_FRONTEND Frontend, IN PMIB_UNICASTIPADDRESS_TABLE Table, - IN NET_IFINDEX InterfaceIndex, - OUT PSOCKADDR_INET *AddressTable, - OUT PULONG AddressCount + IN NET_IFINDEX InterfaceIndex ) { ULONG Index; @@ -573,8 +573,12 @@ FrontendProcessAddressTable( UNREFERENCED_PARAMETER(Frontend); - *AddressTable = NULL; - *AddressCount = 0; + if (Frontend->AddressCount != 0) { + __FrontendFree(Frontend->AddressTable); + + Frontend->AddressTable = NULL; + Frontend->AddressCount = 0; + } for (Index = 0; Index < Table->NumEntries; Index++) { PMIB_UNICASTIPADDRESS_ROW Row = &Table->Table[Index]; @@ -586,9 +590,7 @@ FrontendProcessAddressTable( Row->Address.si_family != AF_INET6) continue; - status = FrontendInsertAddress(AddressTable, - &Row->Address, - AddressCount); + status = FrontendInsertAddress(Frontend, &Row->Address); if (!NT_SUCCESS(status)) goto fail1; } @@ -598,17 +600,12 @@ FrontendProcessAddressTable( fail1: Error("fail1 (%08x)\n", status); - if (*AddressTable != NULL) - __FrontendFree(*AddressTable); - return status; } static NTSTATUS FrontendDumpAddressTable( - IN PXENVIF_FRONTEND Frontend, - IN PSOCKADDR_INET AddressTable, - IN ULONG AddressCount + IN PXENVIF_FRONTEND Frontend ) { PXENBUS_STORE_TRANSACTION Transaction; @@ -646,19 +643,19 @@ FrontendDumpAddressTable( IpVersion4Count = 0; IpVersion6Count = 0; - for (Index = 0; Index < AddressCount; Index++) { - switch (AddressTable[Index].si_family) { + for (Index = 0; Index < Frontend->AddressCount; Index++) { + switch (Frontend->AddressTable[Index].si_family) { case AF_INET: { IPV4_ADDRESS Address; - CHAR Node[sizeof ("ipv4/XXXXXXXX/addr")]; + CHAR Node[sizeof ("ipv4/address/XXXXXXXX")]; RtlCopyMemory(Address.Byte, - &AddressTable[Index].Ipv4.sin_addr.s_addr, + &Frontend->AddressTable[Index].Ipv4.sin_addr.s_addr, IPV4_ADDRESS_LENGTH); status = RtlStringCbPrintfA(Node, sizeof (Node), - "ipv4/%u/addr", + "ipv4/address/%u", IpVersion4Count); ASSERT(NT_SUCCESS(status)); @@ -687,15 +684,15 @@ FrontendDumpAddressTable( } case AF_INET6: { IPV6_ADDRESS Address; - CHAR Node[sizeof ("ipv6/XXXXXXXX/addr")]; + CHAR Node[sizeof ("ipv6/address/XXXXXXXX")]; RtlCopyMemory(Address.Byte, - &AddressTable[Index].Ipv6.sin6_addr.s6_addr, + &Frontend->AddressTable[Index].Ipv6.sin6_addr.s6_addr, IPV6_ADDRESS_LENGTH); status = RtlStringCbPrintfA(Node, sizeof (Node), - "ipv6/%u/addr", + "ipv6/address/%u", IpVersion6Count); ASSERT(NT_SUCCESS(status)); @@ -848,8 +845,6 @@ FrontendMib( NET_IFINDEX InterfaceIndex; PMIB_UNICASTIPADDRESS_TABLE UnicastIpAddressTable; KIRQL Irql; - PSOCKADDR_INET AddressTable; - ULONG AddressCount; Trace("waiting...\n"); @@ -892,22 +887,11 @@ FrontendMib( status = FrontendProcessAddressTable(Frontend, UnicastIpAddressTable, - InterfaceIndex, - &AddressTable, - &AddressCount); + InterfaceIndex); if (!NT_SUCCESS(status)) goto unlock; - TransmitterUpdateAddressTable(__FrontendGetTransmitter(Frontend), - AddressTable, - AddressCount); - - (VOID) FrontendDumpAddressTable(Frontend, - AddressTable, - AddressCount); - - if (AddressCount != 0) - __FrontendFree(AddressTable); + (VOID) FrontendDumpAddressTable(Frontend); unlock: KeReleaseSpinLock(&Frontend->Lock, Irql); @@ -920,6 +904,13 @@ loop: __FreeMibTable(IfTable); } + if (Frontend->AddressCount != 0) { + __FrontendFree(Frontend->AddressTable); + + Frontend->AddressTable = NULL; + Frontend->AddressCount = 0; + } + status = __CancelMibChangeNotify2(Handle); ASSERT(NT_SUCCESS(status)); @@ -948,6 +939,208 @@ fail1: return status; } +NTSTATUS +FrontendSetMulticastAddresses( + IN PXENVIF_FRONTEND Frontend, + IN PETHERNET_ADDRESS Address, + IN ULONG Count + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_MAC Mac; + KIRQL Irql; + PETHERNET_ADDRESS MulticastAddress; + ULONG MulticastCount; + ULONG MulticastIndex; + ULONG Index; + NTSTATUS status; + + Transmitter = FrontendGetTransmitter(Frontend); + Mac = FrontendGetMac(Frontend); + + KeRaiseIrql(DISPATCH_LEVEL, &Irql); + + status = MacQueryMulticastAddresses(Mac, NULL, &MulticastCount); + ASSERT3U(status, ==, STATUS_BUFFER_OVERFLOW); + + if (MulticastCount != 0) { + MulticastAddress = __FrontendAllocate(sizeof (ETHERNET_ADDRESS) * + MulticastCount); + + status = STATUS_NO_MEMORY; + if (MulticastAddress == NULL) + goto fail1; + + status = MacQueryMulticastAddresses(Mac, + MulticastAddress, + &MulticastCount); + if (!NT_SUCCESS(status)) + goto fail2; + } else + MulticastAddress = NULL; + + for (Index = 0; Index < Count; Index++) { + BOOLEAN Found; + + ASSERT(Address[Index].Byte[0] & 0x01); + + Found = FALSE; + + // If the multicast address has already been added and it + // appears in the updated list then we don't want to remove it. + for (MulticastIndex = 0; + MulticastIndex < MulticastCount; + MulticastIndex++) { + if (RtlEqualMemory(&Address[Index], + &MulticastAddress[MulticastIndex], + ETHERNET_ADDRESS_LENGTH)) { + Found = TRUE; + RtlZeroMemory(&MulticastAddress[MulticastIndex], + ETHERNET_ADDRESS_LENGTH); + break; + } + } + + if (!Found) { + (VOID) MacAddMulticastAddress(Mac, &Address[Index]); + (VOID) TransmitterQueueMulticastControl(Transmitter, + &Address[Index], + TRUE); + } + } + + // Walk the multicast list removing any addresses not in the + // updated list + for (MulticastIndex = 0; + MulticastIndex < MulticastCount; + MulticastIndex++) { + if (!(MulticastAddress[MulticastIndex].Byte[0] & 0x01)) + continue; + + (VOID) TransmitterQueueMulticastControl(Transmitter, + &MulticastAddress[MulticastIndex], + FALSE); + (VOID) MacRemoveMulticastAddress(Mac, + &MulticastAddress[MulticastIndex]); + } + + if (MulticastAddress != NULL) + __FrontendFree(MulticastAddress); + + KeLowerIrql(Irql); + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + + __FrontendFree(MulticastAddress); + +fail1: + Error("fail1 (%08x)\n", status); + + KeLowerIrql(Irql); + + return status; +} + +static NTSTATUS +FrontendNotifyMulticastAddresses( + IN PXENVIF_FRONTEND Frontend, + IN BOOLEAN Add + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_MAC Mac; + PETHERNET_ADDRESS Address; + ULONG Count; + ULONG Index; + NTSTATUS status; + + Transmitter = FrontendGetTransmitter(Frontend); + Mac = FrontendGetMac(Frontend); + + status = MacQueryMulticastAddresses(Mac, NULL, &Count); + ASSERT3U(status, ==, STATUS_BUFFER_OVERFLOW); + + if (Count != 0) { + Address = __FrontendAllocate(sizeof (ETHERNET_ADDRESS) * + Count); + + status = STATUS_NO_MEMORY; + if (Address == NULL) + goto fail1; + + status = MacQueryMulticastAddresses(Mac, Address, &Count); + if (!NT_SUCCESS(status)) + goto fail2; + } else + Address = NULL; + + for (Index = 0; Index < Count; Index++) + (VOID) TransmitterQueueMulticastControl(Transmitter, + &Address[Index], + Add); + + if (Address != NULL) + __FrontendFree(Address); + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + + __FrontendFree(Address); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +VOID +FrontendAdvertiseIpAddresses( + IN PXENVIF_FRONTEND Frontend + ) +{ + PXENVIF_TRANSMITTER Transmitter; + KIRQL Irql; + ULONG Index; + + Transmitter = FrontendGetTransmitter(Frontend); + + KeAcquireSpinLock(&Frontend->Lock, &Irql); + + for (Index = 0; Index < Frontend->AddressCount; Index++) { + switch (Frontend->AddressTable[Index].si_family) { + case AF_INET: { + IPV4_ADDRESS Address; + + RtlCopyMemory(Address.Byte, + &Frontend->AddressTable[Index].Ipv4.sin_addr.s_addr, + IPV4_ADDRESS_LENGTH); + + TransmitterQueueArp(Transmitter, &Address); + break; + } + case AF_INET6: { + IPV6_ADDRESS Address; + + RtlCopyMemory(Address.Byte, + &Frontend->AddressTable[Index].Ipv6.sin6_addr.s6_addr, + IPV6_ADDRESS_LENGTH); + + TransmitterQueueNeighbourAdvertisement(Transmitter, &Address); + break; + } + default: + ASSERT(FALSE); + } + } + + KeReleaseSpinLock(&Frontend->Lock, Irql); +} + static VOID FrontendSetOnline( IN PXENVIF_FRONTEND Frontend @@ -1461,7 +1654,7 @@ FrontendSetNumQueues( Frontend->NumQueues = __min(Frontend->MaxQueues, BackendMaxQueues); - Info("%u\n", Frontend->NumQueues); + Info("%s: %u\n", __FrontendGetPath(Frontend), Frontend->NumQueues); } static FORCEINLINE ULONG @@ -1713,6 +1906,8 @@ FrontendEnable( if (!NT_SUCCESS(status)) goto fail3; + FrontendNotifyMulticastAddresses(Frontend, TRUE); + Trace("<====\n"); return STATUS_SUCCESS; @@ -1739,6 +1934,8 @@ FrontendDisable( { Trace("====>\n"); + FrontendNotifyMulticastAddresses(Frontend, FALSE); + TransmitterDisable(__FrontendGetTransmitter(Frontend)); ReceiverDisable(__FrontendGetReceiver(Frontend)); MacDisable(__FrontendGetMac(Frontend)); diff --git a/src/xenvif/frontend.h b/src/xenvif/frontend.h index 374e9b4..bd39767 100644 --- a/src/xenvif/frontend.h +++ b/src/xenvif/frontend.h @@ -169,4 +169,16 @@ FrontendIncrementStatistic( IN ULONGLONG Delta ); +extern NTSTATUS +FrontendSetMulticastAddresses( + IN PXENVIF_FRONTEND Frontend, + IN PETHERNET_ADDRESS Address, + IN ULONG Count + ); + +extern VOID +FrontendAdvertiseIpAddresses( + IN PXENVIF_FRONTEND Frontend + ); + #endif // _XENVIF_FRONTEND_H diff --git a/src/xenvif/mac.c b/src/xenvif/mac.c index b255d58..91467d6 100644 --- a/src/xenvif/mac.c +++ b/src/xenvif/mac.c @@ -42,6 +42,11 @@ #include "assert.h" #include "util.h" +typedef struct _XENVIF_MAC_MULTICAST { + LIST_ENTRY ListEntry; + ETHERNET_ADDRESS Address; +} XENVIF_MAC_MULTICAST, *PXENVIF_MAC_MULTICAST; + struct _XENVIF_MAC { PXENVIF_FRONTEND Frontend; KSPIN_LOCK Lock; @@ -51,8 +56,9 @@ struct _XENVIF_MAC { ETHERNET_ADDRESS PermanentAddress; ETHERNET_ADDRESS CurrentAddress; ETHERNET_ADDRESS BroadcastAddress; - PETHERNET_ADDRESS MulticastAddress; - ULONG MulticastAddressCount; + LIST_ENTRY MulticastList; + ULONG MulticastCount; + BOOLEAN MulticastControl; XENVIF_MAC_FILTER_LEVEL FilterLevel[ETHERNET_ADDRESS_TYPE_COUNT]; XENBUS_DEBUG_INTERFACE DebugInterface; PXENBUS_DEBUG_CALLBACK DebugCallback; @@ -108,6 +114,15 @@ __MacSetPermanentAddress( Mac->PermanentAddress.Byte[4], Mac->PermanentAddress.Byte[5]); + Info("%s: %02X:%02X:%02X:%02X:%02X:%02X\n", + FrontendGetPrefix(Frontend), + Mac->PermanentAddress.Byte[0], + Mac->PermanentAddress.Byte[1], + Mac->PermanentAddress.Byte[2], + Mac->PermanentAddress.Byte[3], + Mac->PermanentAddress.Byte[4], + Mac->PermanentAddress.Byte[5]); + return STATUS_SUCCESS; fail1: @@ -153,6 +168,15 @@ __MacSetCurrentAddress( Mac->CurrentAddress.Byte[4], Mac->CurrentAddress.Byte[5]); + Info("%s: %02X:%02X:%02X:%02X:%02X:%02X\n", + FrontendGetPrefix(Frontend), + Mac->CurrentAddress.Byte[0], + Mac->CurrentAddress.Byte[1], + Mac->CurrentAddress.Byte[2], + Mac->CurrentAddress.Byte[3], + Mac->CurrentAddress.Byte[4], + Mac->CurrentAddress.Byte[5]); + return STATUS_SUCCESS; fail1: @@ -218,6 +242,7 @@ MacInitialize( goto fail1; KeInitializeSpinLock(&(*Mac)->Lock); + InitializeListHead(&(*Mac)->MulticastList); FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)), &(*Mac)->DebugInterface); @@ -235,6 +260,113 @@ fail1: return status; } +static NTSTATUS +MacDumpMulticastList( + IN PXENVIF_MAC Mac + ) +{ + PXENVIF_FRONTEND Frontend; + PETHERNET_ADDRESS Address; + ULONG Count; + PLIST_ENTRY ListEntry; + ULONG Index; + KIRQL Irql; + NTSTATUS status; + + Trace("====>\n"); + + Frontend = Mac->Frontend; + + KeAcquireSpinLock(&Mac->Lock, &Irql); + + status = STATUS_UNSUCCESSFUL; + if (!Mac->Connected) + goto fail1; + + if (Mac->MulticastCount != 0) { + Address = __MacAllocate(sizeof (ETHERNET_ADDRESS) * + Mac->MulticastCount); + + status = STATUS_NO_MEMORY; + if (Address == NULL) + goto fail2; + + Count = 0; + for (ListEntry = Mac->MulticastList.Flink; + ListEntry != &Mac->MulticastList; + ListEntry = ListEntry->Flink) { + PXENVIF_MAC_MULTICAST Multicast; + + Multicast = CONTAINING_RECORD(ListEntry, + XENVIF_MAC_MULTICAST, + ListEntry); + + Address[Count++] = Multicast->Address; + } + ASSERT3U(Count, ==, Mac->MulticastCount); + } else { + Address = NULL; + Count = 0; + } + + KeReleaseSpinLock(&Mac->Lock, Irql); + + (VOID) XENBUS_STORE(Remove, + &Mac->StoreInterface, + NULL, + FrontendGetPrefix(Frontend), + "mac/multicast"); + + for (Index = 0; Index < Count; Index++) { + CHAR Node[sizeof ("mac/multicast/XX")]; + + status = RtlStringCbPrintfA(Node, + sizeof (Node), + "mac/multicast/%u", + Index); + ASSERT(NT_SUCCESS(status)); + + (VOID) XENBUS_STORE(Printf, + &Mac->StoreInterface, + NULL, + FrontendGetPrefix(Frontend), + Node, + "%02x:%02x:%02x:%02x:%02x:%02x", + Address[Index].Byte[0], + Address[Index].Byte[1], + Address[Index].Byte[2], + Address[Index].Byte[3], + Address[Index].Byte[4], + Address[Index].Byte[5]); + + Trace("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", + FrontendGetPrefix(Frontend), + Address[Index].Byte[0], + Address[Index].Byte[1], + Address[Index].Byte[2], + Address[Index].Byte[3], + Address[Index].Byte[4], + Address[Index].Byte[5]); + } + + if (Address != NULL) + __MacFree(Address); + + Trace("<====\n"); + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + KeReleaseSpinLock(&Mac->Lock, Irql); + + return status; +} + NTSTATUS MacConnect( IN PXENVIF_MAC Mac @@ -292,6 +424,22 @@ MacConnect( Mac->MaximumFrameSize = (ULONG)Mtu + sizeof (ETHERNET_TAGGED_HEADER); + status = XENBUS_STORE(Read, + &Mac->StoreInterface, + NULL, + FrontendGetBackendPath(Frontend), + "feature-multicast-control", + &Buffer); + if (!NT_SUCCESS(status)) { + Mac->MulticastControl = FALSE; + } else { + Mac->MulticastControl = (BOOLEAN)strtol(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Mac->StoreInterface, + Buffer); + } + status = XENBUS_DEBUG(Register, &Mac->DebugInterface, __MODULE__ "|MAC", @@ -301,8 +449,12 @@ MacConnect( if (!NT_SUCCESS(status)) goto fail5; + KeAcquireSpinLockAtDpcLevel(&Mac->Lock); ASSERT(!Mac->Connected); Mac->Connected = TRUE; + KeReleaseSpinLockFromDpcLevel(&Mac->Lock); + + (VOID) MacDumpMulticastList(Mac); return STATUS_SUCCESS; @@ -419,14 +571,18 @@ MacDisconnect( Frontend = Mac->Frontend; + KeAcquireSpinLockAtDpcLevel(&Mac->Lock); ASSERT(Mac->Connected); Mac->Connected = FALSE; + KeReleaseSpinLockFromDpcLevel(&Mac->Lock); XENBUS_DEBUG(Deregister, &Mac->DebugInterface, Mac->DebugCallback); Mac->DebugCallback = NULL; + Mac->MulticastControl = FALSE; + Mac->MaximumFrameSize = 0; RtlZeroMemory(&Mac->BroadcastAddress, sizeof (ETHERNET_ADDRESS)); @@ -449,11 +605,25 @@ MacTeardown( IN PXENVIF_MAC Mac ) { - if (Mac->MulticastAddressCount != 0) { - __MacFree(Mac->MulticastAddress); - Mac->MulticastAddress = NULL; - Mac->MulticastAddressCount = 0; + while (!IsListEmpty(&Mac->MulticastList)) { + PLIST_ENTRY ListEntry; + PXENVIF_MAC_MULTICAST Multicast; + + ListEntry = RemoveHeadList(&Mac->MulticastList); + ASSERT3P(ListEntry, !=, &Mac->MulticastList); + + RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY)); + + Multicast = CONTAINING_RECORD(ListEntry, + XENVIF_MAC_MULTICAST, + ListEntry); + __MacFree(Multicast); + + --Mac->MulticastCount; } + ASSERT3U(Mac->MulticastCount, ==, 0); + + RtlZeroMemory(&Mac->MulticastList, sizeof (LIST_ENTRY)); RtlZeroMemory(&Mac->FilterLevel, ETHERNET_ADDRESS_TYPE_COUNT * sizeof (XENVIF_MAC_FILTER_LEVEL)); @@ -570,50 +740,105 @@ MacQueryMaximumFrameSize( } NTSTATUS -MacSetMulticastAddresses( - IN PXENVIF_MAC Mac, - IN ETHERNET_ADDRESS Address[], - IN ULONG Count +MacAddMulticastAddress( + IN PXENVIF_MAC Mac, + IN PETHERNET_ADDRESS Address ) { - KIRQL Irql; - PETHERNET_ADDRESS MulticastAddress; - ULONG Index; - NTSTATUS status; + PXENVIF_FRONTEND Frontend; + PXENVIF_MAC_MULTICAST Multicast; + KIRQL Irql; + NTSTATUS status; + + Frontend = Mac->Frontend; + + ASSERT(Address->Byte[0] & 0x01); + + Multicast = __MacAllocate(sizeof (XENVIF_MAC_MULTICAST)); + + status = STATUS_NO_MEMORY; + if (Multicast == NULL) + goto fail1; + + Multicast->Address = *Address; KeAcquireSpinLock(&Mac->Lock, &Irql); + InsertTailList(&Mac->MulticastList, &Multicast->ListEntry); + Mac->MulticastCount++; + KeReleaseSpinLock(&Mac->Lock, Irql); - status = STATUS_INVALID_PARAMETER; - for (Index = 0; Index < Count; Index++) { - if (!(Address[Index].Byte[0] & 0x01)) - goto fail1; - } + (VOID) MacDumpMulticastList(Mac); - if (Count != 0) { - MulticastAddress = __MacAllocate(sizeof (ETHERNET_ADDRESS) * Count); + Trace("%s: %02X:%02X:%02X:%02X:%02X:%02X\n", + FrontendGetPrefix(Frontend), + Address->Byte[0], + Address->Byte[1], + Address->Byte[2], + Address->Byte[3], + Address->Byte[4], + Address->Byte[5]); - status = STATUS_NO_MEMORY; - if (MulticastAddress == NULL) - goto fail2; + return STATUS_SUCCESS; - for (Index = 0; Index < Count; Index++) - MulticastAddress[Index] = Address[Index]; - } else { - MulticastAddress = NULL; +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +NTSTATUS +MacRemoveMulticastAddress( + IN PXENVIF_MAC Mac, + IN PETHERNET_ADDRESS Address + ) +{ + PXENVIF_FRONTEND Frontend; + PLIST_ENTRY ListEntry; + PXENVIF_MAC_MULTICAST Multicast; + KIRQL Irql; + NTSTATUS status; + + Frontend = Mac->Frontend; + + KeAcquireSpinLock(&Mac->Lock, &Irql); + + for (ListEntry = Mac->MulticastList.Flink; + ListEntry != &Mac->MulticastList; + ListEntry = ListEntry->Flink) { + Multicast = CONTAINING_RECORD(ListEntry, + XENVIF_MAC_MULTICAST, + ListEntry); + + if (RtlEqualMemory(&Multicast->Address, + Address, + ETHERNET_ADDRESS_LENGTH)) + goto found; } - if (Mac->MulticastAddressCount != 0) - __MacFree(Mac->MulticastAddress); + status = STATUS_OBJECT_NAME_NOT_FOUND; + goto fail1; + +found: + ASSERT(Mac->MulticastCount != 0); + --Mac->MulticastCount; - Mac->MulticastAddress = MulticastAddress; - Mac->MulticastAddressCount = Count; + RemoveEntryList(&Multicast->ListEntry); + __MacFree(Multicast); KeReleaseSpinLock(&Mac->Lock, Irql); - return STATUS_SUCCESS; + (VOID) MacDumpMulticastList(Mac); -fail2: - Error("fail2\n"); + Trace("%s: %02X:%02X:%02X:%02X:%02X:%02X\n", + FrontendGetPrefix(Frontend), + Address->Byte[0], + Address->Byte[1], + Address->Byte[2], + Address->Byte[3], + Address->Byte[4], + Address->Byte[5]); + + return STATUS_SUCCESS; fail1: Error("fail1 (%08x)\n", status); @@ -626,31 +851,40 @@ fail1: NTSTATUS MacQueryMulticastAddresses( IN PXENVIF_MAC Mac, - IN PETHERNET_ADDRESS Address, + IN PETHERNET_ADDRESS Address OPTIONAL, IN OUT PULONG Count ) { + PLIST_ENTRY ListEntry; KIRQL Irql; - ULONG Index; NTSTATUS status; KeAcquireSpinLock(&Mac->Lock, &Irql); status = STATUS_BUFFER_OVERFLOW; - if (*Count < Mac->MulticastAddressCount) + if (Address == NULL || *Count < Mac->MulticastCount) goto fail1; - for (Index = 0; Index < Mac->MulticastAddressCount; Index++) - Address[Index] = Mac->MulticastAddress[Index]; + *Count = 0; + for (ListEntry = Mac->MulticastList.Flink; + ListEntry != &Mac->MulticastList; + ListEntry = ListEntry->Flink) { + PXENVIF_MAC_MULTICAST Multicast; + + Multicast = CONTAINING_RECORD(ListEntry, + XENVIF_MAC_MULTICAST, + ListEntry); - *Count = Mac->MulticastAddressCount; + Address[(*Count)++] = Multicast->Address; + } + ASSERT3U(*Count, ==, Mac->MulticastCount); KeReleaseSpinLock(&Mac->Lock, Irql); return STATUS_SUCCESS; fail1: - *Count = Mac->MulticastAddressCount; + *Count = Mac->MulticastCount; KeReleaseSpinLock(&Mac->Lock, Irql); @@ -770,17 +1004,32 @@ MacApplyFilters( break; case XENVIF_MAC_FILTER_MATCHING: { - ULONG Index; + PLIST_ENTRY ListEntry; + + if (Mac->MulticastControl) { + Allow = TRUE; + break; + } - for (Index = 0; Index < Mac->MulticastAddressCount; Index++) { - if (RtlEqualMemory(&Mac->MulticastAddress[Index], + for (ListEntry = Mac->MulticastList.Flink; + ListEntry != &Mac->MulticastList; + ListEntry = ListEntry->Flink) { + PXENVIF_MAC_MULTICAST Multicast; + + Multicast = CONTAINING_RECORD(ListEntry, + XENVIF_MAC_MULTICAST, + ListEntry); + + if (RtlEqualMemory(&Multicast->Address, DestinationAddress, - ETHERNET_ADDRESS_LENGTH)) + ETHERNET_ADDRESS_LENGTH)) { Allow = TRUE; + break; + } } + break; } - case XENVIF_MAC_FILTER_ALL: Allow = TRUE; break; diff --git a/src/xenvif/mac.h b/src/xenvif/mac.h index d39c523..83ce5b8 100644 --- a/src/xenvif/mac.h +++ b/src/xenvif/mac.h @@ -96,17 +96,22 @@ MacQueryBroadcastAddress( ); extern NTSTATUS -MacQueryMulticastAddresses( +MacAddMulticastAddress( IN PXENVIF_MAC Mac, - OUT PETHERNET_ADDRESS Address OPTIONAL, - IN OUT PULONG Count + OUT PETHERNET_ADDRESS Address ); extern NTSTATUS -MacSetMulticastAddresses( - IN PXENVIF_MAC Mac, - IN PETHERNET_ADDRESS Address OPTIONAL, - IN ULONG Count +MacRemoveMulticastAddress( + IN PXENVIF_MAC Mac, + OUT PETHERNET_ADDRESS Address + ); + +extern NTSTATUS +MacQueryMulticastAddresses( + IN PXENVIF_MAC Mac, + OUT PETHERNET_ADDRESS Address OPTIONAL, + IN OUT PULONG Count ); extern NTSTATUS diff --git a/src/xenvif/transmitter.c b/src/xenvif/transmitter.c index 4cf21db..2d8f613 100644 --- a/src/xenvif/transmitter.c +++ b/src/xenvif/transmitter.c @@ -10,7 +10,7 @@ * following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other + * following disclaimer in the documetation and/or other * materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND @@ -64,16 +64,64 @@ #define MAXNAMELEN 128 +typedef struct _XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS { + IPV4_ADDRESS Address; +} XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS, *PXENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS; + +typedef struct _XENVIF_TRANSMITTER_REQUEST_NEIGHBOUR_ADVERTISEMENT_PARAMETERS { + IPV6_ADDRESS Address; +} XENVIF_TRANSMITTER_REQUEST_NEIGHBOUR_ADVERTISEMENT_PARAMETERS, *PXENVIF_TRANSMITTER_REQUEST_NEIGHBOUR_ADVERTISEMENT_PARAMETERS; + +typedef struct _XENVIF_TRANSMITTER_REQUEST_MULTICAST_CONTROL_PARAMETERS { + ETHERNET_ADDRESS Address; + BOOLEAN Add; +} XENVIF_TRANSMITTER_REQUEST_MULTICAST_CONTROL_PARAMETERS, *PXENVIF_TRANSMITTER_REQUEST_MULTICAST_CONTROL_PARAMETERS; + +typedef enum _XENVIF_TRANSMITTER_REQUEST_TYPE { + XENVIF_TRANSMITTER_REQUEST_TYPE_INVALID = 0, + XENVIF_TRANSMITTER_REQUEST_TYPE_ARP, + XENVIF_TRANSMITTER_REQUEST_TYPE_NEIGHBOUR_ADVERTISEMENT, + XENVIF_TRANSMITTER_REQUEST_TYPE_MULTICAST_CONTROL +} XENVIF_TRANSMITTER_REQUEST_TYPE, *PXENVIF_TRANSMITTER_REQUEST_TYPE; + +#pragma warning(push) +#pragma warning(disable:4201) // nonstandard extension used : nameless struct/union + +typedef struct _XENVIF_TRANSMITTER_REQUEST { + LIST_ENTRY ListEntry; + XENVIF_TRANSMITTER_REQUEST_TYPE Type; + union { + XENVIF_TRANSMITTER_REQUEST_ARP_PARAMETERS Arp; + XENVIF_TRANSMITTER_REQUEST_NEIGHBOUR_ADVERTISEMENT_PARAMETERS NeighbourAdvertisement; + XENVIF_TRANSMITTER_REQUEST_MULTICAST_CONTROL_PARAMETERS MulticastControl; + }; +} XENVIF_TRANSMITTER_REQUEST, *PXENVIF_TRANSMITTER_REQUEST; + +#pragma warning(pop) + typedef struct _XENVIF_TRANSMITTER_BUFFER { PMDL Mdl; PVOID Context; ULONG Reference; } XENVIF_TRANSMITTER_BUFFER, *PXENVIF_TRANSMITTER_BUFFER; +typedef enum _XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE { + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_INVALID = 0, + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_ADD, + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_REMOVE +} XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE, *PXENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE; + +typedef struct _XENVIF_TRANSMITTER_MULTICAST_CONTROL { + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE Type; + ETHERNET_ADDRESS Address; + ULONG Reference; +} XENVIF_TRANSMITTER_MULTICAST_CONTROL, *PXENVIF_TRANSMITTER_MULTICAST_CONTROL; + typedef enum _XENVIF_TRANSMITTER_FRAGMENT_TYPE { XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID = 0, XENVIF_TRANSMITTER_FRAGMENT_TYPE_PACKET, - XENVIF_TRANSMITTER_FRAGMENT_TYPE_BUFFER + XENVIF_TRANSMITTER_FRAGMENT_TYPE_BUFFER, + XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL } XENVIF_TRANSMITTER_FRAGMENT_TYPE, *PXENVIF_TRANSMITTER_FRAGMENT_TYPE; typedef struct _XENVIF_TRANSMITTER_FRAGMENT { @@ -106,9 +154,11 @@ typedef struct _XENVIF_TRANSMITTER_RING { ULONG Index; PCHAR Path; PXENBUS_CACHE BufferCache; + PXENBUS_CACHE MulticastControlCache; PXENBUS_CACHE FragmentCache; PXENBUS_GNTTAB_CACHE GnttabCache; PXENBUS_RANGE_SET RangeSet; + PXENBUS_CACHE RequestCache; PMDL Mdl; netif_tx_front_ring_t Front; netif_tx_sring_t *Shared; @@ -122,7 +172,8 @@ typedef struct _XENVIF_TRANSMITTER_RING { BOOLEAN Stopped; PVOID Lock; PKTHREAD LockThread; - LIST_ENTRY Queued; + LIST_ENTRY PacketQueue; + LIST_ENTRY RequestQueue; XENVIF_TRANSMITTER_STATE State; ULONG PacketsQueued; ULONG PacketsGranted; @@ -135,11 +186,8 @@ typedef struct _XENVIF_TRANSMITTER_RING { ULONG RequestsPushed; ULONG ResponsesProcessed; ULONG PacketsSent; - LIST_ENTRY Completed; + LIST_ENTRY PacketComplete; ULONG PacketsCompleted; - PSOCKADDR_INET AddressTable; - ULONG AddressCount; - ULONG AddressIndex; PXENBUS_DEBUG_CALLBACK DebugCallback; PXENVIF_THREAD WatchdogThread; } XENVIF_TRANSMITTER_RING, *PXENVIF_TRANSMITTER_RING; @@ -155,6 +203,7 @@ struct _XENVIF_TRANSMITTER { LONG NumQueues; LONG_PTR Offset[XENVIF_TRANSMITTER_PACKET_OFFSET_COUNT]; BOOLEAN Split; + BOOLEAN MulticastControl; ULONG DisableIpVersion4Gso; ULONG DisableIpVersion6Gso; ULONG AlwaysCopy; @@ -196,7 +245,7 @@ TransmitterPacketAcquireLock( static VOID TransmitterPacketReleaseLock( - IN PVOID Argument + IN PVOID Argument ) { PXENVIF_TRANSMITTER Transmitter = Argument; @@ -207,8 +256,8 @@ TransmitterPacketReleaseLock( static NTSTATUS TransmitterPacketCtor( - IN PVOID Argument, - IN PVOID Object + IN PVOID Argument, + IN PVOID Object ) { UNREFERENCED_PARAMETER(Argument); @@ -219,8 +268,8 @@ TransmitterPacketCtor( static VOID TransmitterPacketDtor( - IN PVOID Argument, - IN PVOID Object + IN PVOID Argument, + IN PVOID Object ) { UNREFERENCED_PARAMETER(Argument); @@ -360,6 +409,69 @@ __TransmitterPutBuffer( } static NTSTATUS +TransmitterMulticastControlCtor( + IN PVOID Argument, + IN PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Argument); + UNREFERENCED_PARAMETER(Object); + + return STATUS_SUCCESS; +} + +static VOID +TransmitterMulticastControlDtor( + IN PVOID Argument, + IN PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Argument); + UNREFERENCED_PARAMETER(Object); +} + +static FORCEINLINE PXENVIF_TRANSMITTER_MULTICAST_CONTROL +__TransmitterGetMulticastControl( + IN PXENVIF_TRANSMITTER_RING Ring + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control; + + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; + + Control = XENBUS_CACHE(Get, + &Transmitter->CacheInterface, + Ring->MulticastControlCache, + TRUE); + + return Control; +} + +static FORCEINLINE VOID +__TransmitterPutMulticastControl( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; + + ASSERT3U(Control->Reference, ==, 0); + + XENBUS_CACHE(Put, + &Transmitter->CacheInterface, + Ring->MulticastControlCache, + Control, + TRUE); +} + +static NTSTATUS TransmitterFragmentCtor( IN PVOID Argument, IN PVOID Object @@ -457,6 +569,7 @@ __TransmitterPutFragment( ASSERT3U(Fragment->Offset, ==, 0); ASSERT3U(Fragment->Type, ==, XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID); ASSERT3P(Fragment->Context, ==, NULL); + ASSERT3P(Fragment->Entry, ==, NULL); ASSERT(!Fragment->Extra); XENBUS_CACHE(Put, @@ -466,6 +579,65 @@ __TransmitterPutFragment( TRUE); } +static NTSTATUS +TransmitterRequestCtor( + IN PVOID Argument, + IN PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Argument); + UNREFERENCED_PARAMETER(Object); + + return STATUS_SUCCESS; +} + +static VOID +TransmitterRequestDtor( + IN PVOID Argument, + IN PVOID Object + ) +{ + UNREFERENCED_PARAMETER(Argument); + UNREFERENCED_PARAMETER(Object); +} + +static FORCEINLINE PXENVIF_TRANSMITTER_REQUEST +__TransmitterGetRequest( + IN PXENVIF_TRANSMITTER_RING Ring + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_TRANSMITTER_REQUEST Request; + + Transmitter = Ring->Transmitter; + + Request = XENBUS_CACHE(Get, + &Transmitter->CacheInterface, + Ring->RequestCache, + TRUE); + + return Request; +} + +static FORCEINLINE VOID +__TransmitterPutRequest( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PXENVIF_TRANSMITTER_REQUEST Request + ) +{ + PXENVIF_TRANSMITTER Transmitter; + + Transmitter = Ring->Transmitter; + + ASSERT3U(Request->Type, ==, XENVIF_TRANSMITTER_REQUEST_TYPE_INVALID); + + XENBUS_CACHE(Put, + &Transmitter->CacheInterface, + Ring->RequestCache, + Request, + TRUE); +} + static VOID TransmitterRingDebugCallback( IN PVOID Argument, @@ -1188,7 +1360,7 @@ fail1: return status; } -static FORCEINLINE VOID +static FORCEINLINE PXENVIF_TRANSMITTER_PACKET __TransmitterRingUnprepareFragments( IN PXENVIF_TRANSMITTER_RING Ring ) @@ -1196,18 +1368,20 @@ __TransmitterRingUnprepareFragments( PXENVIF_TRANSMITTER Transmitter; PXENVIF_FRONTEND Frontend; PXENVIF_TRANSMITTER_STATE State; + ULONG Count; + PXENVIF_TRANSMITTER_PACKET Packet; Transmitter = Ring->Transmitter; Frontend = Transmitter->Frontend; State = &Ring->State; + Count = State->Count; - while (State->Count != 0) { + while (Count != 0) { PLIST_ENTRY ListEntry; PXENVIF_TRANSMITTER_FRAGMENT Fragment; - PXENVIF_TRANSMITTER_PACKET Packet; - --State->Count; + --Count; ListEntry = RemoveTailList(&State->List); ASSERT3P(ListEntry, !=, &State->List); @@ -1238,8 +1412,8 @@ __TransmitterRingUnprepareFragments( Buffer->Context = NULL; ASSERT(Buffer->Reference != 0); - if (--Buffer->Reference == 0) - __TransmitterPutBuffer(Ring, Buffer); + --Buffer->Reference; + __TransmitterPutBuffer(Ring, Buffer); break; } @@ -1250,16 +1424,64 @@ __TransmitterRingUnprepareFragments( break; - default: + case XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL: { + PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control; + + Control = Fragment->Context; + Fragment->Context = NULL; + Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID; + + switch (Control->Type) { + case XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_ADD: + case XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_REMOVE: + break; + default: + ASSERT(FALSE); + break; + } + + ASSERT(Control->Reference != 0); + --Control->Reference; + __TransmitterPutMulticastControl(Ring, Control); + Packet = NULL; + break; + } + default: ASSERT(FALSE); + Packet = NULL; + break; } - __TransmitterPutFragment(Ring, Fragment); - if (Packet != NULL) Packet->Value--; + + __TransmitterPutFragment(Ring, Fragment); + } + + if (State->Count != 0) { + ASSERT(IsListEmpty(&State->List)); + RtlZeroMemory(&State->List, sizeof (LIST_ENTRY)); + + State->Count = 0; + } + + Packet = State->Packet; + + if (Packet != NULL) { + Ring->PacketsUnprepared++; + + RtlZeroMemory(&State->Payload, sizeof (XENVIF_PACKET_PAYLOAD)); + + Packet->Send = State->Send; + RtlZeroMemory(&State->Send, sizeof (XENVIF_TRANSMITTER_PACKET_SEND_INFO)); + + State->Packet = NULL; } + + ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); + + return Packet; } static FORCEINLINE NTSTATUS @@ -1395,44 +1617,6 @@ fail1: return status; } -static FORCEINLINE PXENVIF_TRANSMITTER_PACKET -__TransmitterRingUnpreparePacket( - IN PXENVIF_TRANSMITTER_RING Ring - ) -{ - PXENVIF_TRANSMITTER_STATE State; - PXENVIF_TRANSMITTER_PACKET Packet; - - State = &Ring->State; - Packet = State->Packet; - - // This has the side effect of freeing up resources associated with a pending - // gratuitous ARP, which is why the call is not conditional on Packet being - // non-NULL - __TransmitterRingUnprepareFragments(Ring); - RtlZeroMemory(&State->Info, sizeof (XENVIF_PACKET_INFO)); - - if (Packet == NULL) - goto done; - - Ring->PacketsUnprepared++; - - ASSERT(IsListEmpty(&State->List)); - RtlZeroMemory(&State->List, sizeof (LIST_ENTRY)); - - RtlZeroMemory(&State->Payload, sizeof (XENVIF_PACKET_PAYLOAD)); - - Packet->Send = State->Send; - RtlZeroMemory(&State->Send, sizeof (XENVIF_TRANSMITTER_PACKET_SEND_INFO)); - - State->Packet = NULL; - - ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); - -done: - return Packet; -} - static FORCEINLINE NTSTATUS __TransmitterRingPrepareArp( IN PXENVIF_TRANSMITTER_RING Ring, @@ -1458,12 +1642,6 @@ __TransmitterRingPrepareArp( ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); - Info("%u.%u.%u.%u\n", - Address->Byte[0], - Address->Byte[1], - Address->Byte[2], - Address->Byte[3]); - Transmitter = Ring->Transmitter; Frontend = Transmitter->Frontend; Mac = FrontendGetMac(Frontend); @@ -1606,16 +1784,6 @@ __TransmitterRingPrepareNeighbourAdvertisement( ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); - Info("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - HTONS(Address->Word[0]), - HTONS(Address->Word[1]), - HTONS(Address->Word[2]), - HTONS(Address->Word[3]), - HTONS(Address->Word[4]), - HTONS(Address->Word[5]), - HTONS(Address->Word[6]), - HTONS(Address->Word[7])); - Transmitter = Ring->Transmitter; Frontend = Transmitter->Frontend; Mac = FrontendGetMac(Frontend); @@ -1758,13 +1926,71 @@ fail1: } static FORCEINLINE NTSTATUS -__TransmitterRingPostFragments( - IN PXENVIF_TRANSMITTER_RING Ring +__TransmitterRingPrepareMulticastControl( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PETHERNET_ADDRESS Address, + IN BOOLEAN Add ) { + PXENVIF_TRANSMITTER_STATE State; + PXENVIF_TRANSMITTER_FRAGMENT Fragment; + PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control; + NTSTATUS status; + + ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); + + State = &Ring->State; + + Control = __TransmitterGetMulticastControl(Ring); + + status = STATUS_NO_MEMORY; + if (Control == NULL) + goto fail1; + + Control->Type = (Add) ? + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_ADD : + XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_REMOVE; + Control->Address = *Address; + + Fragment = __TransmitterGetFragment(Ring); + + status = STATUS_NO_MEMORY; + if (Fragment == NULL) + goto fail2; + + Fragment->Context = Control; + Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL; + Control->Reference++; + + InitializeListHead(&State->List); + + ASSERT(IsZeroMemory(&Fragment->ListEntry, sizeof (LIST_ENTRY))); + InsertTailList(&State->List, &Fragment->ListEntry); + State->Count++; + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + + __TransmitterPutMulticastControl(Ring, Control); + +fail1: + Error("fail1 (%08x)\n", status); + + ASSERT(IsZeroMemory(&Ring->State, sizeof (XENVIF_TRANSMITTER_STATE))); + + return status; +} + #define RING_SLOTS_AVAILABLE(_Front, _req_prod, _rsp_cons) \ (RING_SIZE(_Front) - ((_req_prod) - (_rsp_cons))) +static FORCEINLINE NTSTATUS +__TransmitterRingPostFragments( + IN PXENVIF_TRANSMITTER_RING Ring + ) +{ PXENVIF_TRANSMITTER Transmitter; PXENVIF_FRONTEND Frontend; PXENVIF_TRANSMITTER_STATE State; @@ -1775,6 +2001,8 @@ __TransmitterRingPostFragments( ULONG Extra; ULONG PacketLength; BOOLEAN FirstRequest; + PLIST_ENTRY ListEntry; + PXENVIF_TRANSMITTER_FRAGMENT Fragment; netif_tx_request_t *req; NTSTATUS status; @@ -1793,8 +2021,14 @@ __TransmitterRingPostFragments( req_prod = Ring->Front.req_prod_pvt; rsp_cons = Ring->Front.rsp_cons; + ListEntry = State->List.Flink; + Fragment = CONTAINING_RECORD(ListEntry, + XENVIF_TRANSMITTER_FRAGMENT, + ListEntry); + Extra = (State->Send.OffloadOptions.OffloadIpVersion4LargePacket || - State->Send.OffloadOptions.OffloadIpVersion6LargePacket) ? + State->Send.OffloadOptions.OffloadIpVersion6LargePacket || + Fragment->Type == XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL) ? 1 : 0; @@ -1809,9 +2043,6 @@ __TransmitterRingPostFragments( FirstRequest = TRUE; PacketLength = 0; while (State->Count != 0) { - PLIST_ENTRY ListEntry; - PXENVIF_TRANSMITTER_FRAGMENT Fragment; - --State->Count; ListEntry = RemoveHeadList(&State->List); @@ -1819,16 +2050,20 @@ __TransmitterRingPostFragments( RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY)); - Fragment = CONTAINING_RECORD(ListEntry, XENVIF_TRANSMITTER_FRAGMENT, ListEntry); + Fragment = CONTAINING_RECORD(ListEntry, + XENVIF_TRANSMITTER_FRAGMENT, + ListEntry); req = RING_GET_REQUEST(&Ring->Front, req_prod); req_prod++; Ring->RequestsPosted++; req->id = Fragment->Id; - req->gref = XENBUS_GNTTAB(GetReference, + req->gref = (Fragment->Entry != NULL) ? + XENBUS_GNTTAB(GetReference, &Transmitter->GnttabInterface, - Fragment->Entry); + Fragment->Entry) : + 0; req->offset = (USHORT)Fragment->Offset; req->size = (USHORT)Fragment->Length; req->flags = NETTXF_more_data; @@ -1843,37 +2078,49 @@ __TransmitterRingPostFragments( req->flags |= NETTXF_csum_blank | NETTXF_data_validated; if (State->Send.OffloadOptions.OffloadIpVersion4LargePacket || - State->Send.OffloadOptions.OffloadIpVersion6LargePacket) { - uint8_t type; - uint16_t size; + State->Send.OffloadOptions.OffloadIpVersion6LargePacket || + Fragment->Type == XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL) { struct netif_extra_info *extra; ASSERT(Extra != 0); Fragment->Extra = TRUE; - ASSERT(!(State->Send.OffloadOptions.OffloadIpVersion4LargePacket && - State->Send.OffloadOptions.OffloadIpVersion6LargePacket)); - type = (State->Send.OffloadOptions.OffloadIpVersion4LargePacket) ? - XEN_NETIF_GSO_TYPE_TCPV4 : - XEN_NETIF_GSO_TYPE_TCPV6; - - ASSERT(State->Send.MaximumSegmentSize != 0); - size = State->Send.MaximumSegmentSize; - - ASSERT(req->flags & (NETTXF_csum_blank | NETTXF_data_validated)); - req->flags |= NETTXF_extra_info; - extra = (struct netif_extra_info *)RING_GET_REQUEST(&Ring->Front, req_prod); req_prod++; Ring->RequestsPosted++; - extra->type = XEN_NETIF_EXTRA_TYPE_GSO; - extra->flags = 0; + if (State->Send.OffloadOptions.OffloadIpVersion4LargePacket || + State->Send.OffloadOptions.OffloadIpVersion6LargePacket) { + ASSERT(State->Send.MaximumSegmentSize != 0); + + extra->type = XEN_NETIF_EXTRA_TYPE_GSO; + extra->flags = 0; + + extra->u.gso.type = (State->Send.OffloadOptions.OffloadIpVersion4LargePacket) ? + XEN_NETIF_GSO_TYPE_TCPV4 : + XEN_NETIF_GSO_TYPE_TCPV6;; + extra->u.gso.size = State->Send.MaximumSegmentSize; + extra->u.gso.pad = 0; + extra->u.gso.features = 0; + + ASSERT(req->flags & (NETTXF_csum_blank | NETTXF_data_validated)); + } else { + PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control; + + ASSERT(Fragment->Type == XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL); + Control = Fragment->Context; + + extra->type = (Control->Type == XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_ADD) ? + XEN_NETIF_EXTRA_TYPE_MCAST_ADD : + XEN_NETIF_EXTRA_TYPE_MCAST_DEL; + extra->flags = 0; - extra->u.gso.size = size; - extra->u.gso.type = type; - extra->u.gso.pad = 0; - extra->u.gso.features = 0; + RtlCopyMemory(&extra->u.mcast.addr, + &Control->Address.Byte[0], + ETHERNET_ADDRESS_LENGTH); + } + + req->flags |= NETTXF_extra_info; } // The first fragment length is the length of the entire packet @@ -1886,7 +2133,6 @@ __TransmitterRingPostFragments( Ring->Pending[req->id] = Fragment; } ASSERT(!FirstRequest); - ASSERT(PacketLength != 0); ASSERT(req != NULL); req->flags &= ~NETTXF_more_data; @@ -1902,6 +2148,8 @@ __TransmitterRingPostFragments( PXENVIF_PACKET_INFO Info; PETHERNET_HEADER Header; + ASSERT(PacketLength != 0); + StartVa = State->StartVa; Info = &State->Info; @@ -1930,9 +2178,9 @@ __TransmitterRingPostFragments( fail1: return status; +} #undef RING_SLOTS_AVAILABLE -} static FORCEINLINE VOID __TransmitterRingFakeResponses( @@ -1989,8 +2237,16 @@ __TransmitterRingFakeResponses( ASSERT3U(Ring->Shared->rsp_prod, ==, Ring->Front.req_prod_pvt); - if (Count != 0) - Info("Faked %lu responses\n", Count); + if (Count != 0) { + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; + + Info("%s: faked %lu responses\n", + FrontendGetPath(Frontend), Count); + } } static FORCEINLINE VOID @@ -2055,7 +2311,7 @@ __TransmitterRingCompletePacket( } } - InsertTailList(&Ring->Completed, &Packet->ListEntry); + InsertTailList(&Ring->PacketComplete, &Packet->ListEntry); Ring->PacketsCompleted++; } @@ -2123,8 +2379,8 @@ TransmitterRingPoll( Buffer->Context = NULL; ASSERT(Buffer->Reference != 0); - if (--Buffer->Reference == 0) - __TransmitterPutBuffer(Ring, Buffer); + --Buffer->Reference; + __TransmitterPutBuffer(Ring, Buffer); break; } @@ -2135,20 +2391,46 @@ TransmitterRingPoll( break; - default: - Packet = NULL; - ASSERT(FALSE); + case XENVIF_TRANSMITTER_FRAGMENT_TYPE_MULTICAST_CONTROL: { + PXENVIF_TRANSMITTER_MULTICAST_CONTROL Control; + + Control = Fragment->Context; + Fragment->Context = NULL; + Fragment->Type = XENVIF_TRANSMITTER_FRAGMENT_TYPE_INVALID; + + switch (Control->Type) { + case XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_ADD: + case XENVIF_TRANSMITTER_MULTICAST_CONTROL_TYPE_REMOVE: + break; + default: + ASSERT(FALSE); + break; + } + + ASSERT(Control->Reference != 0); + --Control->Reference; + __TransmitterPutMulticastControl(Ring, Control); + + Packet = NULL; + break; + } + default: + ASSERT(FALSE); + Packet = NULL; + break; } Fragment->Length = 0; Fragment->Offset = 0; - (VOID) XENBUS_GNTTAB(RevokeForeignAccess, - &Transmitter->GnttabInterface, - Ring->GnttabCache, - TRUE, - Fragment->Entry); - Fragment->Entry = NULL; + if (Fragment->Entry != NULL) { + (VOID) XENBUS_GNTTAB(RevokeForeignAccess, + &Transmitter->GnttabInterface, + Ring->GnttabCache, + TRUE, + Fragment->Entry); + Fragment->Entry = NULL; + } Fragment->Extra = FALSE; __TransmitterPutFragment(Ring, Fragment); @@ -2331,7 +2613,8 @@ TransmitterRingSwizzle( ListEntry = List.Flink; if (!IsListEmpty(&List)) { RemoveEntryList(&List); - AppendTailList(&Ring->Queued, ListEntry); + InitializeListHead(&List); + AppendTailList(&Ring->PacketQueue, ListEntry); Ring->PacketsQueued += Count; } } @@ -2349,9 +2632,7 @@ TransmitterRingSchedule( State = &Ring->State; for (;;) { - PLIST_ENTRY ListEntry; - PXENVIF_TRANSMITTER_PACKET Packet; - NTSTATUS status; + NTSTATUS status; if (State->Count != 0) { status = __TransmitterRingPostFragments(Ring); @@ -2367,72 +2648,85 @@ TransmitterRingSchedule( ASSERT3U(State->Count, ==, 0); - if (Ring->AddressIndex != 0) { - ULONG Index = (--Ring->AddressIndex) % Ring->AddressCount; - - switch (Ring->AddressTable[Index].si_family) { - case AF_INET: { - IPV4_ADDRESS Address; + if (!IsListEmpty(&Ring->RequestQueue)) { + PLIST_ENTRY ListEntry; + PXENVIF_TRANSMITTER_REQUEST Request; - RtlCopyMemory(Address.Byte, - &Ring->AddressTable[Index].Ipv4.sin_addr.s_addr, - IPV4_ADDRESS_LENGTH); + ListEntry = RemoveHeadList(&Ring->RequestQueue); + RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY)); - (VOID) __TransmitterRingPrepareArp(Ring, &Address); + Request = CONTAINING_RECORD(ListEntry, + XENVIF_TRANSMITTER_REQUEST, + ListEntry); + switch (Request->Type) { + case XENVIF_TRANSMITTER_REQUEST_TYPE_ARP: + (VOID) __TransmitterRingPrepareArp(Ring, + &Request->Arp.Address); break; - } - case AF_INET6: { - IPV6_ADDRESS Address; - - RtlCopyMemory(Address.Byte, - &Ring->AddressTable[Index].Ipv6.sin6_addr.s6_addr, - IPV6_ADDRESS_LENGTH); - (VOID) __TransmitterRingPrepareNeighbourAdvertisement(Ring, &Address); + case XENVIF_TRANSMITTER_REQUEST_TYPE_NEIGHBOUR_ADVERTISEMENT: + (VOID) __TransmitterRingPrepareNeighbourAdvertisement(Ring, + &Request->NeighbourAdvertisement.Address); + break; + case XENVIF_TRANSMITTER_REQUEST_TYPE_MULTICAST_CONTROL: + (VOID) __TransmitterRingPrepareMulticastControl(Ring, + &Request->MulticastControl.Address, + Request->MulticastControl.Add); break; - } + default: - ASSERT(FALSE); + break; } + Request->Type = XENVIF_TRANSMITTER_REQUEST_TYPE_INVALID; + __TransmitterPutRequest(Ring, Request); continue; } - ListEntry = RemoveHeadList(&Ring->Queued); - if (ListEntry == &Ring->Queued) - break; + if (!IsListEmpty(&Ring->PacketQueue)) { + PLIST_ENTRY ListEntry; + PXENVIF_TRANSMITTER_PACKET Packet; - Packet = CONTAINING_RECORD(ListEntry, XENVIF_TRANSMITTER_PACKET, ListEntry); - Packet->ListEntry.Flink = Packet->ListEntry.Blink = NULL; - Packet->Value = 0; + ListEntry = RemoveHeadList(&Ring->PacketQueue); + RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY)); - status = __TransmitterRingPreparePacket(Ring, Packet); - if (!NT_SUCCESS(status)) { - PXENVIF_TRANSMITTER Transmitter; - PXENVIF_FRONTEND Frontend; + Packet = CONTAINING_RECORD(ListEntry, + XENVIF_TRANSMITTER_PACKET, + ListEntry); - Transmitter = Ring->Transmitter; - Frontend = Transmitter->Frontend; + Packet->Value = 0; - ASSERT(status != STATUS_BUFFER_OVERFLOW); + status = __TransmitterRingPreparePacket(Ring, Packet); + if (!NT_SUCCESS(status)) { + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; - // Fake that we prapared and sent this packet - Ring->PacketsPrepared++; - Ring->PacketsSent++; - Ring->PacketsFaked++; + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; - Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_DROPPED; + ASSERT(status != STATUS_BUFFER_OVERFLOW); - FrontendIncrementStatistic(Frontend, - XENVIF_TRANSMITTER_FRONTEND_ERRORS, - 1); + // Fake that we prapared and sent this packet + Ring->PacketsPrepared++; + Ring->PacketsSent++; + Ring->PacketsFaked++; - __TransmitterRingCompletePacket(Ring, Packet); + Packet->Completion.Status = XENVIF_TRANSMITTER_PACKET_DROPPED; + + FrontendIncrementStatistic(Frontend, + XENVIF_TRANSMITTER_FRONTEND_ERRORS, + 1); + + __TransmitterRingCompletePacket(Ring, Packet); + } + + ASSERT3U(Ring->PacketsPrepared, ==, Ring->PacketsCopied + Ring->PacketsGranted + Ring->PacketsFaked); + continue; } - ASSERT3U(Ring->PacketsPrepared, ==, Ring->PacketsCopied + Ring->PacketsGranted + Ring->PacketsFaked); + break; } __TransmitterRingPushRequests(Ring); @@ -2607,10 +2901,10 @@ __TransmitterRingReleaseLock( TransmitterRingSwizzle(Ring); TransmitterRingSchedule(Ring); - ListEntry = Ring->Completed.Flink; - if (!IsListEmpty(&Ring->Completed)) { - RemoveEntryList(&Ring->Completed); - InitializeListHead(&Ring->Completed); + ListEntry = Ring->PacketComplete.Flink; + if (!IsListEmpty(&Ring->PacketComplete)) { + RemoveEntryList(&Ring->PacketComplete); + InitializeListHead(&Ring->PacketComplete); AppendTailList(&List, ListEntry); } } while (!__TransmitterRingTryReleaseLock(Ring)); @@ -2787,62 +3081,6 @@ TransmitterRingWatchdog( return STATUS_SUCCESS; } -static FORCEINLINE VOID -__TransmitterRingUpdateAddressTable( - IN PXENVIF_TRANSMITTER_RING Ring, - IN PSOCKADDR_INET Table, - IN ULONG Count - ) -{ - NTSTATUS status; - - __TransmitterRingAcquireLock(Ring); - - if (Ring->AddressCount != 0) { - Ring->AddressCount = 0; - - ASSERT(Ring->AddressTable != NULL); - __TransmitterFree(Ring->AddressTable); - Ring->AddressTable = NULL; - } - - if (Count == 0) - goto done; - - Ring->AddressTable = __TransmitterAllocate(sizeof (SOCKADDR_INET) * Count); - - status = STATUS_NO_MEMORY; - if (Ring->AddressTable == NULL) - goto fail1; - - RtlCopyMemory(Ring->AddressTable, Table, sizeof (SOCKADDR_INET) * Count); - Ring->AddressCount = Count; - - // Re-advertize if we were part way through - if (Ring->AddressIndex != 0) - Ring->AddressIndex = Ring->AddressCount * 3; - -done: - __TransmitterRingReleaseLock(Ring); - - return; - -fail1: - Error("fail1 (%08x)\n", status); - - __TransmitterRingReleaseLock(Ring); -} - -static FORCEINLINE VOID -__TransmitterRingAdvertiseAddresses( - IN PXENVIF_TRANSMITTER_RING Ring - ) -{ - __TransmitterRingAcquireLock(Ring); - Ring->AddressIndex = Ring->AddressCount * 3; - __TransmitterRingReleaseLock(Ring); -} - static FORCEINLINE NTSTATUS __TransmitterRingInitialize( IN PXENVIF_TRANSMITTER Transmitter, @@ -2869,8 +3107,9 @@ __TransmitterRingInitialize( if ((*Ring)->Path == NULL) goto fail2; - InitializeListHead(&(*Ring)->Queued); - InitializeListHead(&(*Ring)->Completed); + InitializeListHead(&(*Ring)->PacketQueue); + InitializeListHead(&(*Ring)->RequestQueue); + InitializeListHead(&(*Ring)->PacketComplete); KeInitializeDpc(&(*Ring)->Dpc, TransmitterRingDpc, *Ring); @@ -2901,7 +3140,7 @@ __TransmitterRingInitialize( status = RtlStringCbPrintfA(Name, sizeof (Name), - "%s_transmitter_req_id", + "%s_transmitter_multicast_control", (*Ring)->Path); if (!NT_SUCCESS(status)) goto fail5; @@ -2910,12 +3149,37 @@ __TransmitterRingInitialize( if (Name[Index] == '/') Name[Index] = '_'; + status = XENBUS_CACHE(Create, + &Transmitter->CacheInterface, + Name, + sizeof (XENVIF_TRANSMITTER_MULTICAST_CONTROL), + 0, + TransmitterMulticastControlCtor, + TransmitterMulticastControlDtor, + TransmitterRingAcquireLock, + TransmitterRingReleaseLock, + *Ring, + &(*Ring)->MulticastControlCache); + if (!NT_SUCCESS(status)) + goto fail6; + + status = RtlStringCbPrintfA(Name, + sizeof (Name), + "%s_transmitter_req_id", + (*Ring)->Path); + if (!NT_SUCCESS(status)) + goto fail7; + + for (Index = 0; Name[Index] != '\0'; Index++) + if (Name[Index] == '/') + Name[Index] = '_'; + status = XENBUS_RANGE_SET(Create, &Transmitter->RangeSetInterface, Name, &(*Ring)->RangeSet); if (!NT_SUCCESS(status)) - goto fail6; + goto fail8; status = XENBUS_RANGE_SET(Put, &Transmitter->RangeSetInterface, @@ -2923,14 +3187,14 @@ __TransmitterRingInitialize( 1, XENVIF_TRANSMITTER_MAXIMUM_FRAGMENT_ID); if (!NT_SUCCESS(status)) - goto fail7; + goto fail9; status = RtlStringCbPrintfA(Name, sizeof (Name), "%s_transmitter_fragment", (*Ring)->Path); if (!NT_SUCCESS(status)) - goto fail8; + goto fail10; for (Index = 0; Name[Index] != '\0'; Index++) if (Name[Index] == '/') @@ -2948,29 +3212,65 @@ __TransmitterRingInitialize( *Ring, &(*Ring)->FragmentCache); if (!NT_SUCCESS(status)) - goto fail9; + goto fail11; + + status = RtlStringCbPrintfA(Name, + sizeof (Name), + "%s_transmitter_request", + (*Ring)->Path); + if (!NT_SUCCESS(status)) + goto fail12; + + for (Index = 0; Name[Index] != '\0'; Index++) + if (Name[Index] == '/') + Name[Index] = '_'; + + status = XENBUS_CACHE(Create, + &Transmitter->CacheInterface, + Name, + sizeof (XENVIF_TRANSMITTER_REQUEST), + 0, + TransmitterRequestCtor, + TransmitterRequestDtor, + TransmitterRingAcquireLock, + TransmitterRingReleaseLock, + *Ring, + &(*Ring)->RequestCache); + if (!NT_SUCCESS(status)) + goto fail13; status = ThreadCreate(TransmitterRingWatchdog, *Ring, &(*Ring)->WatchdogThread); if (!NT_SUCCESS(status)) - goto fail10; + goto fail14; return STATUS_SUCCESS; -fail10: - Error("fail10\n"); +fail14: + Error("fail14\n"); + + XENBUS_CACHE(Destroy, + &Transmitter->CacheInterface, + (*Ring)->RequestCache); + (*Ring)->RequestCache = NULL; + +fail13: + Error("fail13\n"); + +fail12: + Error("fail12\n"); XENBUS_CACHE(Destroy, &Transmitter->CacheInterface, (*Ring)->FragmentCache); (*Ring)->FragmentCache = NULL; -fail9: - Error("fail9\n"); +fail11: + Error("fail11\n"); -fail8: - Error("fail8\n"); +fail10: + Error("fail10\n"); (VOID) XENBUS_RANGE_SET(Get, &Transmitter->RangeSetInterface, @@ -2978,14 +3278,25 @@ fail8: 1, XENVIF_TRANSMITTER_MAXIMUM_FRAGMENT_ID); -fail7: - Error("fail7\n"); +fail9: + Error("fail9\n"); XENBUS_RANGE_SET(Destroy, &Transmitter->RangeSetInterface, (*Ring)->RangeSet); (*Ring)->RangeSet = NULL; +fail8: + Error("fail8\n"); + +fail7: + Error("fail7\n"); + + XENBUS_CACHE(Destroy, + &Transmitter->CacheInterface, + (*Ring)->MulticastControlCache); + (*Ring)->MulticastControlCache = NULL; + fail6: Error("fail6\n"); @@ -3005,8 +3316,9 @@ fail3: RtlZeroMemory(&(*Ring)->Dpc, sizeof (KDPC)); - RtlZeroMemory(&(*Ring)->Queued, sizeof (LIST_ENTRY)); - RtlZeroMemory(&(*Ring)->Completed, sizeof (LIST_ENTRY)); + RtlZeroMemory(&(*Ring)->PacketComplete, sizeof (LIST_ENTRY)); + RtlZeroMemory(&(*Ring)->RequestQueue, sizeof (LIST_ENTRY)); + RtlZeroMemory(&(*Ring)->PacketQueue, sizeof (LIST_ENTRY)); FrontendFreePath(Frontend, (*Ring)->Path); (*Ring)->Path = NULL; @@ -3300,13 +3612,27 @@ __TransmitterRingDisable( Ring->Enabled = FALSE; // Release any fragments associated with a pending packet - Packet = __TransmitterRingUnpreparePacket(Ring); + Packet = __TransmitterRingUnprepareFragments(Ring); // Put any packet back on the head of the queue if (Packet != NULL) - InsertHeadList(&Ring->Queued, &Packet->ListEntry); + InsertHeadList(&Ring->PacketQueue, &Packet->ListEntry); + + // Discard any pending requests + while (!IsListEmpty(&Ring->RequestQueue)) { + PLIST_ENTRY ListEntry; + PXENVIF_TRANSMITTER_REQUEST Request; - Ring->AddressIndex = 0; + ListEntry = RemoveHeadList(&Ring->RequestQueue); + ASSERT3P(ListEntry, !=, &Ring->RequestQueue); + + Request = CONTAINING_RECORD(ListEntry, + XENVIF_TRANSMITTER_REQUEST, + ListEntry); + + Request->Type = XENVIF_TRANSMITTER_REQUEST_TYPE_INVALID; + __TransmitterPutRequest(Ring, Request); + } status = XENBUS_STORE(Read, &Transmitter->StoreInterface, @@ -3433,20 +3759,17 @@ __TransmitterRingTeardown( Ring->PacketsPrepared = 0; Ring->PacketsQueued = 0; - if (Ring->AddressCount != 0) { - ASSERT(Ring->AddressTable != NULL); - __TransmitterFree(Ring->AddressTable); - } - - Ring->AddressTable = NULL; - Ring->AddressCount = 0; - ThreadAlert(Ring->WatchdogThread); ThreadJoin(Ring->WatchdogThread); Ring->WatchdogThread = NULL; XENBUS_CACHE(Destroy, &Transmitter->CacheInterface, + Ring->RequestCache); + Ring->RequestCache = NULL; + + XENBUS_CACHE(Destroy, + &Transmitter->CacheInterface, Ring->FragmentCache); Ring->FragmentCache = NULL; @@ -3463,14 +3786,22 @@ __TransmitterRingTeardown( XENBUS_CACHE(Destroy, &Transmitter->CacheInterface, + Ring->MulticastControlCache); + Ring->MulticastControlCache = NULL; + + XENBUS_CACHE(Destroy, + &Transmitter->CacheInterface, Ring->BufferCache); Ring->BufferCache = NULL; - ASSERT(IsListEmpty(&Ring->Queued)); - RtlZeroMemory(&Ring->Queued, sizeof (LIST_ENTRY)); + ASSERT(IsListEmpty(&Ring->PacketComplete)); + RtlZeroMemory(&Ring->PacketComplete, sizeof (LIST_ENTRY)); + + ASSERT(IsListEmpty(&Ring->RequestQueue)); + RtlZeroMemory(&Ring->RequestQueue, sizeof (LIST_ENTRY)); - ASSERT(IsListEmpty(&Ring->Completed)); - RtlZeroMemory(&Ring->Completed, sizeof (LIST_ENTRY)); + ASSERT(IsListEmpty(&Ring->PacketQueue)); + RtlZeroMemory(&Ring->PacketQueue, sizeof (LIST_ENTRY)); FrontendFreePath(Frontend, Ring->Path); Ring->Path = NULL; @@ -3520,12 +3851,12 @@ __TransmitterRingAbortPackets( TransmitterRingSwizzle(Ring); - while (!IsListEmpty(&Ring->Queued)) { + while (!IsListEmpty(&Ring->PacketQueue)) { PLIST_ENTRY ListEntry; PXENVIF_TRANSMITTER_PACKET Packet; - ListEntry = RemoveHeadList(&Ring->Queued); - ASSERT3P(ListEntry, !=, &Ring->Queued); + ListEntry = RemoveHeadList(&Ring->PacketQueue); + ASSERT3P(ListEntry, !=, &Ring->PacketQueue); Packet = CONTAINING_RECORD(ListEntry, XENVIF_TRANSMITTER_PACKET, ListEntry); Packet->ListEntry.Flink = Packet->ListEntry.Blink = NULL; @@ -3548,6 +3879,168 @@ __TransmitterRingAbortPackets( __TransmitterRingReleaseLock(Ring); } +static FORCEINLINE NTSTATUS +__TransmitterRingQueueArp( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PIPV4_ADDRESS Address + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + PXENVIF_TRANSMITTER_REQUEST Request; + NTSTATUS status; + + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; + + __TransmitterRingAcquireLock(Ring); + + status = STATUS_UNSUCCESSFUL; + if (!Ring->Enabled) + goto fail1; + + Request = __TransmitterGetRequest(Ring); + + status = STATUS_NO_MEMORY; + if (Request == NULL) + goto fail2; + + Request->Type = XENVIF_TRANSMITTER_REQUEST_TYPE_ARP; + Request->Arp.Address = *Address; + + InsertTailList(&Ring->RequestQueue, &Request->ListEntry); + + __TransmitterRingReleaseLock(Ring); + + Info("%s: %u.%u.%u.%u\n", + FrontendGetPath(Frontend), + Address->Byte[0], + Address->Byte[1], + Address->Byte[2], + Address->Byte[3]); + + return STATUS_SUCCESS; + +fail2: +fail1: + __TransmitterRingReleaseLock(Ring); + + return status; +} + +static FORCEINLINE NTSTATUS +__TransmitterRingQueueNeighbourAdvertisement( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PIPV6_ADDRESS Address + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + PXENVIF_TRANSMITTER_REQUEST Request; + NTSTATUS status; + + Transmitter = Ring->Transmitter; + Frontend = Transmitter->Frontend; + + __TransmitterRingAcquireLock(Ring); + + status = STATUS_UNSUCCESSFUL; + if (!Ring->Enabled) + goto fail1; + + Request = __TransmitterGetRequest(Ring); + + status = STATUS_NO_MEMORY; + if (Request == NULL) + goto fail2; + + Request->Type = XENVIF_TRANSMITTER_REQUEST_TYPE_NEIGHBOUR_ADVERTISEMENT; + Request->NeighbourAdvertisement.Address = *Address; + + InsertTailList(&Ring->RequestQueue, &Request->ListEntry); + + __TransmitterRingReleaseLock(Ring); + + Info("%s: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + FrontendGetPath(Frontend), + HTONS(Address->Word[0]), + HTONS(Address->Word[1]), + HTONS(Address->Word[2]), + HTONS(Address->Word[3]), + HTONS(Address->Word[4]), + HTONS(Address->Word[5]), + HTONS(Address->Word[6]), + HTONS(Address->Word[7])); + + return STATUS_SUCCESS; + +fail2: +fail1: + __TransmitterRingReleaseLock(Ring); + + return status; +} + +static FORCEINLINE NTSTATUS +__TransmitterRingQueueMulticastControl( + IN PXENVIF_TRANSMITTER_RING Ring, + IN PETHERNET_ADDRESS Address, + IN BOOLEAN Add + ) +{ + PXENVIF_TRANSMITTER Transmitter; + PXENVIF_FRONTEND Frontend; + PXENVIF_TRANSMITTER_REQUEST Request; + NTSTATUS status; + + Transmitter = Ring->Transmitter; + + status = STATUS_NOT_SUPPORTED; + if (!Transmitter->MulticastControl) + goto fail1; + + Frontend = Transmitter->Frontend; + + __TransmitterRingAcquireLock(Ring); + + status = STATUS_UNSUCCESSFUL; + if (!Ring->Enabled) + goto fail2; + + Request = __TransmitterGetRequest(Ring); + + status = STATUS_NO_MEMORY; + if (Request == NULL) + goto fail3; + + Request->Type = XENVIF_TRANSMITTER_REQUEST_TYPE_MULTICAST_CONTROL; + Request->MulticastControl.Address = *Address; + Request->MulticastControl.Add = Add; + + InsertTailList(&Ring->RequestQueue, &Request->ListEntry); + + __TransmitterRingReleaseLock(Ring); + + Info("%s: %s %02X:%02X:%02X:%02X:%02X:%02X\n", + FrontendGetPath(Frontend), + (Add) ? "ADD" : "REMOVE", + Address->Byte[0], + Address->Byte[1], + Address->Byte[2], + Address->Byte[3], + Address->Byte[4], + Address->Byte[5]); + + return STATUS_SUCCESS; + +fail3: +fail2: + __TransmitterRingReleaseLock(Ring); + +fail1: + return status; +} + static VOID TransmitterDebugCallback( IN PVOID Argument, @@ -3796,6 +4289,22 @@ TransmitterConnect( Buffer); } + status = XENBUS_STORE(Read, + &Transmitter->StoreInterface, + NULL, + FrontendGetBackendPath(Frontend), + "feature-multicast-control", + &Buffer); + if (!NT_SUCCESS(status)) { + Transmitter->MulticastControl = FALSE; + } else { + Transmitter->MulticastControl = (BOOLEAN)strtol(Buffer, NULL, 2); + + XENBUS_STORE(Free, + &Transmitter->StoreInterface, + Buffer); + } + Transmitter->NumQueues = FrontendGetNumQueues(Frontend); ASSERT3U(Transmitter->NumQueues, <=, Transmitter->MaxQueues); @@ -3880,22 +4389,38 @@ TransmitterStoreWrite( IN PXENBUS_STORE_TRANSACTION Transaction ) { + PXENVIF_FRONTEND Frontend; NTSTATUS status; LONG Index; + Frontend = Transmitter->Frontend; + + status = XENBUS_STORE(Printf, + &Transmitter->StoreInterface, + Transaction, + FrontendGetPath(Frontend), + "request-multicast-control", + "%u", + TRUE); + if (!NT_SUCCESS(status)) + goto fail1; + Index = 0; while (Index < Transmitter->NumQueues) { PXENVIF_TRANSMITTER_RING Ring = Transmitter->Ring[Index]; status = __TransmitterRingStoreWrite(Ring, Transaction); if (!NT_SUCCESS(status)) - goto fail1; + goto fail2; Index++; } return STATUS_SUCCESS; +fail2: + Error("fail2\n"); + fail1: Error("fail1 (%08x)\n", status); @@ -3954,6 +4479,7 @@ TransmitterDisconnect( Frontend = Transmitter->Frontend; + Transmitter->MulticastControl = FALSE; Transmitter->Split = FALSE; XENBUS_DEBUG(Deregister, @@ -4046,42 +4572,6 @@ TransmitterTeardown( __TransmitterFree(Transmitter); } -VOID -TransmitterUpdateAddressTable( - IN PXENVIF_TRANSMITTER Transmitter, - IN SOCKADDR_INET Table[], - IN ULONG Count - ) -{ - KIRQL Irql; - PXENVIF_TRANSMITTER_RING Ring; - - // Make sure we don't suspend - KeRaiseIrql(DISPATCH_LEVEL, &Irql); - - // Use the first ring for address advertisment - Ring = Transmitter->Ring[0]; - ASSERT3U(Ring, !=, NULL); - - __TransmitterRingUpdateAddressTable(Ring, Table, Count); - - KeLowerIrql(Irql); -} - -VOID -TransmitterAdvertiseAddresses( - IN PXENVIF_TRANSMITTER Transmitter - ) -{ - PXENVIF_TRANSMITTER_RING Ring; - - // Use the first ring for address advertisment - Ring = Transmitter->Ring[0]; - ASSERT3U(Ring, !=, NULL); - - __TransmitterRingAdvertiseAddresses(Ring); -} - NTSTATUS TransmitterSetPacketOffset( IN PXENVIF_TRANSMITTER Transmitter, @@ -4346,6 +4836,40 @@ TransmitterAbortPackets( } VOID +TransmitterQueueArp( + IN PXENVIF_TRANSMITTER Transmitter, + IN PIPV4_ADDRESS Address + ) +{ + PXENVIF_TRANSMITTER_RING Ring = Transmitter->Ring[0]; + + (VOID) __TransmitterRingQueueArp(Ring, Address); +} + +VOID +TransmitterQueueNeighbourAdvertisement( + IN PXENVIF_TRANSMITTER Transmitter, + IN PIPV6_ADDRESS Address + ) +{ + PXENVIF_TRANSMITTER_RING Ring = Transmitter->Ring[0]; + + (VOID) __TransmitterRingQueueNeighbourAdvertisement(Ring, Address); +} + +VOID +TransmitterQueueMulticastControl( + IN PXENVIF_TRANSMITTER Transmitter, + IN PETHERNET_ADDRESS Address, + IN BOOLEAN Add + ) +{ + PXENVIF_TRANSMITTER_RING Ring = Transmitter->Ring[0]; + + (VOID) __TransmitterRingQueueMulticastControl(Ring, Address, Add); +} + +VOID TransmitterQueryRingSize( IN PXENVIF_TRANSMITTER Transmitter, OUT PULONG Size diff --git a/src/xenvif/transmitter.h b/src/xenvif/transmitter.h index fad0762..eddc51b 100644 --- a/src/xenvif/transmitter.h +++ b/src/xenvif/transmitter.h @@ -34,7 +34,9 @@ #include <ntddk.h> #include <netioapi.h> + #include <vif_interface.h> +#include <tcpip.h> #include "frontend.h" @@ -89,21 +91,28 @@ TransmitterAbortPackets( ); extern VOID -TransmitterQueryRingSize( - IN PXENVIF_TRANSMITTER Transmitter, - OUT PULONG Size +TransmitterQueueArp( + IN PXENVIF_TRANSMITTER Transmitter, + IN PIPV4_ADDRESS Address ); extern VOID -TransmitterUpdateAddressTable( - IN PXENVIF_TRANSMITTER Transmitter, - IN PSOCKADDR_INET Table, - IN ULONG Count +TransmitterQueueNeighbourAdvertisement( + IN PXENVIF_TRANSMITTER Transmitter, + IN PIPV6_ADDRESS Address ); extern VOID -TransmitterAdvertiseAddresses( - IN PXENVIF_TRANSMITTER Transmitter +TransmitterQueueMulticastControl( + IN PXENVIF_TRANSMITTER Transmitter, + IN PETHERNET_ADDRESS Address, + IN BOOLEAN Add + ); + +extern VOID +TransmitterQueryRingSize( + IN PXENVIF_TRANSMITTER Transmitter, + OUT PULONG Size ); extern VOID diff --git a/src/xenvif/vif.c b/src/xenvif/vif.c index 35af384..b2bbf05 100644 --- a/src/xenvif/vif.c +++ b/src/xenvif/vif.c @@ -501,16 +501,24 @@ VifMacSetMulticastAddresses( ) { PXENVIF_VIF_CONTEXT Context = Interface->Context; + ULONG Index; NTSTATUS status; + status = STATUS_INVALID_PARAMETER; + for (Index = 0; Index < Count; Index++) { + if (!(Address[Index].Byte[0] & 0x01)) + goto done; + } + AcquireMrswLockShared(&Context->Lock); - status = MacSetMulticastAddresses(FrontendGetMac(Context->Frontend), - Address, - Count); + status = FrontendSetMulticastAddresses(Context->Frontend, + Address, + Count); ReleaseMrswLockShared(&Context->Lock); +done: return status; } @@ -598,7 +606,10 @@ VifSuspendCallbackLate( status = FrontendSetState(Context->Frontend, FRONTEND_ENABLED); ASSERT(NT_SUCCESS(status)); - TransmitterAdvertiseAddresses(FrontendGetTransmitter(Context->Frontend)); + // We do this three times to make sure switches take note + FrontendAdvertiseIpAddresses(Context->Frontend); + FrontendAdvertiseIpAddresses(Context->Frontend); + FrontendAdvertiseIpAddresses(Context->Frontend); } static NTSTATUS -- 2.1.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |