|
[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 |