2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
25 #define OVS_DBG_MOD OVS_DBG_IPHELPER
29 * Fow now, we assume only one internal adapter
32 KSTART_ROUTINE OvsStartIpHelper;
36 * Only when the internal IP is configured and virtual
37 * internal port is connected, the IP helper request can be
40 static BOOLEAN ovsInternalIPConfigured;
41 static BOOLEAN ovsInternalAdapterUp;
42 static GUID ovsInternalNetCfgId;
43 static MIB_IF_ROW2 ovsInternalRow;
44 static MIB_IPINTERFACE_ROW ovsInternalIPRow;
46 /* we only keep one internal IP for reference, it will not be used for
47 * determining SRC IP of Tunnel
49 static UINT32 ovsInternalIP;
53 * FWD_ENTRY --------> IPFORWARD_ENTRY
55 * |--------------------------------------> IPENIGH_ENTRY
57 * IPFORWARD_ENTRY ------> FWD_ENTRY LIST with same IPFORWARD
59 * IPNEIGH_ENTRY ------> FWD_ENTRY LIST with same IPNEIGH
63 static PLIST_ENTRY ovsFwdHashTable; // based on DST IP
64 static PLIST_ENTRY ovsRouteHashTable; // based on DST PREFIX
65 static PLIST_ENTRY ovsNeighHashTable; // based on DST IP
66 static LIST_ENTRY ovsSortedIPNeighList;
67 static UINT32 ovsNumFwdEntries;
70 static PNDIS_RW_LOCK_EX ovsTableLock;
71 static NDIS_SPIN_LOCK ovsIpHelperLock;
73 static LIST_ENTRY ovsIpHelperRequestList;
74 static UINT32 ovsNumIpHelperRequests;
76 static HANDLE ipInterfaceNotificationHandle;
77 static HANDLE ipRouteNotificationHandle;
78 static HANDLE unicastIPNotificationHandle;
80 static OVS_IP_HELPER_THREAD_CONTEXT ovsIpHelperThreadContext;
82 static POVS_IPFORWARD_ENTRY OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix);
83 static VOID OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf);
84 static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);
85 static VOID OvsCleanupIpHelperRequestList(VOID);
86 static VOID OvsCleanupFwdTable(VOID);
87 static VOID OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn);
90 OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
92 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
93 ifRow->InterfaceLuid.Info.NetLuidIndex,
94 ifRow->InterfaceLuid.Info.IfType);
95 OVS_LOG_INFO("InterfaceIndex: %d", ifRow->InterfaceIndex);
97 OVS_LOG_INFO("Interface GUID: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
98 ifRow->InterfaceGuid.Data1,
99 ifRow->InterfaceGuid.Data2,
100 ifRow->InterfaceGuid.Data3,
101 *(UINT16 *)ifRow->InterfaceGuid.Data4,
102 ifRow->InterfaceGuid.Data4[2],
103 ifRow->InterfaceGuid.Data4[3],
104 ifRow->InterfaceGuid.Data4[4],
105 ifRow->InterfaceGuid.Data4[5],
106 ifRow->InterfaceGuid.Data4[6],
107 ifRow->InterfaceGuid.Data4[7]);
108 OVS_LOG_INFO("Perm MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
109 ifRow->PermanentPhysicalAddress[0],
110 ifRow->PermanentPhysicalAddress[1],
111 ifRow->PermanentPhysicalAddress[2],
112 ifRow->PermanentPhysicalAddress[3],
113 ifRow->PermanentPhysicalAddress[4],
114 ifRow->PermanentPhysicalAddress[5]);
119 OvsDumpIfTable(PMIB_IF_TABLE2 ifTable)
124 OVS_LOG_INFO("======Number of entries: %d========", ifTable->NumEntries);
126 for (i = 0; i < ifTable->NumEntries; i++) {
127 ifRow = &ifTable->Table[i];
134 OvsGetIfEntry(GUID *interfaceGuid, PMIB_IF_ROW2 ifEntry)
137 PMIB_IF_TABLE2 ifTable;
140 if (interfaceGuid == NULL || ifEntry == NULL) {
141 return STATUS_INVALID_PARAMETER;
144 status = GetIfTable2Ex(MibIfTableNormal, &ifTable);
146 if (status != STATUS_SUCCESS) {
147 OVS_LOG_INFO("Fail to get if table, status: %x", status);
150 status = STATUS_NOT_FOUND;
152 for (i = 0; i < ifTable->NumEntries; i++) {
155 ifRow = &ifTable->Table[i];
156 if (!memcmp(interfaceGuid, &ifRow->InterfaceGuid, sizeof (GUID))) {
157 RtlCopyMemory(ifEntry, ifRow, sizeof (MIB_IF_ROW2));
158 status = STATUS_SUCCESS;
159 OvsDumpIfRow(ifEntry);
164 FreeMibTable(ifTable);
170 OvsDumpIPInterfaceEntry(PMIB_IPINTERFACE_ROW ipRow)
172 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
173 ipRow->InterfaceLuid.Info.NetLuidIndex,
174 ipRow->InterfaceLuid.Info.IfType);
175 OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
177 OVS_LOG_INFO("MaxReassembleSize: %u", ipRow->MaxReassemblySize);
182 OvsGetIPInterfaceEntry(NET_LUID luid,
183 PMIB_IPINTERFACE_ROW ipRow)
188 return STATUS_INVALID_PARAMETER;
191 ipRow->Family = AF_INET;
192 ipRow->InterfaceLuid.Value = luid.Value;
194 status = GetIpInterfaceEntry(ipRow);
196 if (status != STATUS_SUCCESS) {
197 OVS_LOG_INFO("Fail to get internal IP Interface mib row, status: %x",
201 OvsDumpIPInterfaceEntry(ipRow);
207 OvsDumpIPEntry(PMIB_UNICASTIPADDRESS_ROW ipRow)
211 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
212 ipRow->InterfaceLuid.Info.NetLuidIndex,
213 ipRow->InterfaceLuid.Info.IfType);
215 OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
217 ASSERT(ipRow->Address.si_family == AF_INET);
219 ipAddr = ipRow->Address.Ipv4.sin_addr.s_addr;
220 OVS_LOG_INFO("Unicast Address: %d.%d.%d.%d\n",
221 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
222 (ipAddr >> 16) & 0xff, ipAddr >> 24);
227 OvsGetIPEntry(NET_LUID interfaceLuid,
228 PMIB_UNICASTIPADDRESS_ROW ipEntry)
230 PMIB_UNICASTIPADDRESS_TABLE ipTable;
234 if (ipEntry == NULL || ipEntry == NULL) {
235 return STATUS_INVALID_PARAMETER;
238 status = GetUnicastIpAddressTable(AF_INET, &ipTable);
240 if (status != STATUS_SUCCESS) {
241 OVS_LOG_INFO("Fail to get unicast address table, status: %x", status);
245 status = STATUS_NOT_FOUND;
247 for (i = 0; i < ipTable->NumEntries; i++) {
248 PMIB_UNICASTIPADDRESS_ROW ipRow;
250 ipRow = &ipTable->Table[i];
251 if (ipRow->InterfaceLuid.Value == interfaceLuid.Value) {
252 RtlCopyMemory(ipEntry, ipRow, sizeof (*ipRow));
253 OvsDumpIPEntry(ipEntry);
254 status = STATUS_SUCCESS;
259 FreeMibTable(ipTable);
263 #ifdef OVS_ENABLE_IPPATH
265 OvsDumpIPPath(PMIB_IPPATH_ROW ipPath)
267 UINT32 ipAddr = ipPath->Source.Ipv4.sin_addr.s_addr;
269 OVS_LOG_INFO("Source: %d.%d.%d.%d",
270 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
271 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
273 ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
274 OVS_LOG_INFO("Destination: %d.%d.%d.%d",
275 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
276 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
278 ipAddr = ipPath->CurrentNextHop.Ipv4.sin_addr.s_addr;
279 OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
280 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
281 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
286 OvsGetIPPathEntry(PMIB_IPPATH_ROW ipPath)
289 UINT32 ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
291 status = GetIpPathEntry(ipPath);
293 if (status != STATUS_SUCCESS) {
294 OVS_LOG_INFO("Fail to get IP path to %d.%d.%d.%d, status:%x",
295 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
296 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
299 OvsDumpIPPath(ipPath);
305 OvsDumpRoute(const SOCKADDR_INET *sourceAddress,
306 const SOCKADDR_INET *destinationAddress,
307 PMIB_IPFORWARD_ROW2 route)
309 UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
311 OVS_LOG_INFO("Destination: %d.%d.%d.%d",
312 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
313 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
315 ipAddr = sourceAddress->Ipv4.sin_addr.s_addr;
316 OVS_LOG_INFO("Source: %d.%d.%d.%d",
317 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
318 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
320 ipAddr = route->NextHop.Ipv4.sin_addr.s_addr;
321 OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
322 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
323 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
328 OvsGetRoute(NET_LUID interfaceLuid,
329 const SOCKADDR_INET *destinationAddress,
330 PMIB_IPFORWARD_ROW2 route,
331 SOCKADDR_INET *sourceAddress)
335 if (destinationAddress == NULL || route == NULL) {
336 return STATUS_INVALID_PARAMETER;
339 status = GetBestRoute2(&interfaceLuid, 0,
340 NULL, destinationAddress,
341 0, route, sourceAddress);
343 if (status != STATUS_SUCCESS) {
344 UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
345 OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
346 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
347 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
351 OvsDumpRoute(sourceAddress, destinationAddress, route);
356 OvsDumpIPNeigh(PMIB_IPNET_ROW2 ipNeigh)
358 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
360 OVS_LOG_INFO("Neigh: %d.%d.%d.%d",
361 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
362 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
363 OVS_LOG_INFO("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
364 ipNeigh->PhysicalAddress[0],
365 ipNeigh->PhysicalAddress[1],
366 ipNeigh->PhysicalAddress[2],
367 ipNeigh->PhysicalAddress[3],
368 ipNeigh->PhysicalAddress[4],
369 ipNeigh->PhysicalAddress[5]);
374 OvsGetIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
380 status = GetIpNetEntry2(ipNeigh);
382 if (status != STATUS_SUCCESS) {
383 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
384 OVS_LOG_INFO("Fail to get ARP entry: %d.%d.%d.%d, status: %x",
385 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
386 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
389 if (ipNeigh->State == NlnsReachable ||
390 ipNeigh->State == NlnsPermanent) {
391 OvsDumpIPNeigh(ipNeigh);
392 return STATUS_SUCCESS;
394 return STATUS_FWP_TCPIP_NOT_READY;
399 OvsResolveIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
404 status = ResolveIpNetEntry2(ipNeigh, NULL);
406 if (status != STATUS_SUCCESS) {
407 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
408 OVS_LOG_INFO("Fail to resolve ARP entry: %d.%d.%d.%d, status: %x",
409 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
410 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
414 if (ipNeigh->State == NlnsReachable ||
415 ipNeigh->State == NlnsPermanent) {
416 OvsDumpIPNeigh(ipNeigh);
417 return STATUS_SUCCESS;
419 return STATUS_FWP_TCPIP_NOT_READY;
424 OvsGetOrResolveIPNeigh(UINT32 ipAddr,
425 PMIB_IPNET_ROW2 ipNeigh)
431 RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
432 ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
433 ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
434 ipNeigh->Address.si_family = AF_INET;
435 ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
437 status = OvsGetIPNeighEntry(ipNeigh);
439 if (status != STATUS_SUCCESS) {
440 RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
441 ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
442 ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
443 ipNeigh->Address.si_family = AF_INET;
444 ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
445 status = OvsResolveIPNeighEntry(ipNeigh);
452 OvsChangeCallbackIpInterface(PVOID context,
453 PMIB_IPINTERFACE_ROW ipRow,
454 MIB_NOTIFICATION_TYPE notificationType)
456 UNREFERENCED_PARAMETER(context);
457 switch (notificationType) {
458 case MibParameterNotification:
460 if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
461 ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
462 ipRow->InterfaceLuid.Info.IfType ==
463 ovsInternalRow.InterfaceLuid.Info.IfType &&
464 ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
466 * Update the IP Interface Row
468 NdisAcquireSpinLock(&ovsIpHelperLock);
469 RtlCopyMemory(&ovsInternalIPRow, ipRow,
470 sizeof (PMIB_IPINTERFACE_ROW));
471 ovsInternalIPConfigured = TRUE;
472 NdisReleaseSpinLock(&ovsIpHelperLock);
474 OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",
475 ipRow->InterfaceLuid.Info.NetLuidIndex,
476 ipRow->InterfaceLuid.Info.IfType,
477 notificationType == MibAddInstance ? "added" : "modified");
479 case MibDeleteInstance:
480 OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d, deleted",
481 ipRow->InterfaceLuid.Info.NetLuidIndex,
482 ipRow->InterfaceLuid.Info.IfType);
483 if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
484 ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
485 ipRow->InterfaceLuid.Info.IfType ==
486 ovsInternalRow.InterfaceLuid.Info.IfType &&
487 ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
489 NdisAcquireSpinLock(&ovsIpHelperLock);
490 ovsInternalIPConfigured = FALSE;
491 NdisReleaseSpinLock(&ovsIpHelperLock);
493 OvsCleanupIpHelperRequestList();
495 OvsCleanupFwdTable();
499 case MibInitialNotification:
500 OVS_LOG_INFO("Get Initial notification for IP Interface change.");
508 OvsChangeCallbackIpRoute(PVOID context,
509 PMIB_IPFORWARD_ROW2 ipRoute,
510 MIB_NOTIFICATION_TYPE notificationType)
512 UINT32 ipAddr, nextHop;
514 UNREFERENCED_PARAMETER(context);
515 switch (notificationType) {
519 ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
520 nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
522 OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d added",
523 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
524 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
525 ipRoute->DestinationPrefix.PrefixLength,
526 nextHop & 0xff, (nextHop >> 8) & 0xff,
527 (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff);
530 case MibParameterNotification:
531 case MibDeleteInstance:
533 ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
534 nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
536 OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d %s.",
537 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
538 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
539 ipRoute->DestinationPrefix.PrefixLength,
540 nextHop & 0xff, (nextHop >> 8) & 0xff,
541 (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
542 notificationType == MibDeleteInstance ? "deleted" :
545 if (ipRoute->InterfaceLuid.Info.NetLuidIndex ==
546 ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
547 ipRoute->InterfaceLuid.Info.IfType ==
548 ovsInternalRow.InterfaceLuid.Info.IfType &&
549 ipRoute->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
551 POVS_IPFORWARD_ENTRY ipf;
552 LOCK_STATE_EX lockState;
554 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
555 ipf = OvsLookupIPForwardEntry(&ipRoute->DestinationPrefix);
557 OvsRemoveIPForwardEntry(ipf);
559 NdisReleaseRWLock(ovsTableLock, &lockState);
563 case MibInitialNotification:
564 OVS_LOG_INFO("Get Initial notification for IP Route change.");
572 OvsChangeCallbackUnicastIpAddress(PVOID context,
573 PMIB_UNICASTIPADDRESS_ROW unicastRow,
574 MIB_NOTIFICATION_TYPE notificationType)
578 UNREFERENCED_PARAMETER(context);
579 switch (notificationType) {
580 case MibParameterNotification:
583 ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
584 if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
585 ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
586 unicastRow->InterfaceLuid.Info.IfType ==
587 ovsInternalRow.InterfaceLuid.Info.IfType &&
588 unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
589 ovsInternalIP = ipAddr;
591 OVS_LOG_INFO("IP Address: %d.%d.%d.%d is %s",
592 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
593 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
594 notificationType == MibAddInstance ? "added": "modified");
597 case MibDeleteInstance:
599 ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
600 OVS_LOG_INFO("IP Address removed: %d.%d.%d.%d",
601 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
602 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
603 if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
604 ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
605 unicastRow->InterfaceLuid.Info.IfType ==
606 ovsInternalRow.InterfaceLuid.Info.IfType &&
607 unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
609 LOCK_STATE_EX lockState;
610 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
611 OvsRemoveAllFwdEntriesWithSrc(ipAddr);
612 NdisReleaseRWLock(ovsTableLock, &lockState);
617 case MibInitialNotification:
618 OVS_LOG_INFO("Get Initial notification for Unicast IP Address change.");
626 OvsCancelChangeNotification()
628 if (ipInterfaceNotificationHandle != NULL) {
629 CancelMibChangeNotify2(ipInterfaceNotificationHandle);
630 ipInterfaceNotificationHandle = NULL;
632 if (ipRouteNotificationHandle != NULL) {
633 CancelMibChangeNotify2(ipRouteNotificationHandle);
634 ipRouteNotificationHandle = NULL;
636 if (unicastIPNotificationHandle != NULL) {
637 CancelMibChangeNotify2(unicastIPNotificationHandle);
638 unicastIPNotificationHandle = NULL;
644 OvsRegisterChangeNotification()
649 status = NotifyIpInterfaceChange(AF_INET, OvsChangeCallbackIpInterface,
651 &ipInterfaceNotificationHandle);
652 if (status != STATUS_SUCCESS) {
653 OVS_LOG_ERROR("Fail to register Notify IP interface change, status:%x.",
658 status = NotifyRouteChange2(AF_INET, OvsChangeCallbackIpRoute, NULL,
659 TRUE, &ipRouteNotificationHandle);
660 if (status != STATUS_SUCCESS) {
661 OVS_LOG_ERROR("Fail to regiter ip route change, status: %x.",
663 goto register_cleanup;
665 status = NotifyUnicastIpAddressChange(AF_INET,
666 OvsChangeCallbackUnicastIpAddress,
668 &unicastIPNotificationHandle);
669 if (status != STATUS_SUCCESS) {
670 OVS_LOG_ERROR("Fail to regiter unicast ip change, status: %x.", status);
673 if (status != STATUS_SUCCESS) {
674 OvsCancelChangeNotification();
681 static POVS_IPNEIGH_ENTRY
682 OvsLookupIPNeighEntry(UINT32 ipAddr)
685 POVS_IPNEIGH_ENTRY entry;
686 UINT32 hash = OvsJhashWords(&ipAddr, 1, OVS_HASH_BASIS);
688 LIST_FORALL(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK], link) {
689 entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, link);
690 if (entry->ipAddr == ipAddr) {
699 OvsHashIPPrefix(PIP_ADDRESS_PREFIX prefix)
701 UINT64 words = (UINT64)prefix->Prefix.Ipv4.sin_addr.s_addr << 32 |
702 (UINT32)prefix->PrefixLength;
703 return OvsJhashWords((UINT32 *)&words, 2, OVS_HASH_BASIS);
707 static POVS_IPFORWARD_ENTRY
708 OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
712 POVS_IPFORWARD_ENTRY ipfEntry;
714 ASSERT(prefix->Prefix.si_family == AF_INET);
716 hash = RtlUlongByteSwap(prefix->Prefix.Ipv4.sin_addr.s_addr);
718 ASSERT(prefix->PrefixLength >= 32 ||
719 (hash & (((UINT32)1 << (32 - prefix->PrefixLength)) - 1)) == 0);
721 hash = OvsHashIPPrefix(prefix);
722 LIST_FORALL(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK], link) {
723 ipfEntry = CONTAINING_RECORD(link, OVS_IPFORWARD_ENTRY, link);
724 if (ipfEntry->prefix.PrefixLength == prefix->PrefixLength &&
725 ipfEntry->prefix.Prefix.Ipv4.sin_addr.s_addr ==
726 prefix->Prefix.Ipv4.sin_addr.s_addr) {
734 static POVS_FWD_ENTRY
735 OvsLookupIPFwdEntry(UINT32 dstIp)
738 POVS_FWD_ENTRY entry;
739 UINT32 hash = OvsJhashWords(&dstIp, 1, OVS_HASH_BASIS);
741 LIST_FORALL(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK], link) {
742 entry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
743 if (entry->info.dstIpAddr == dstIp) {
752 OvsLookupIPFwdInfo(UINT32 dstIp,
755 POVS_FWD_ENTRY entry;
756 LOCK_STATE_EX lockState;
757 NTSTATUS status = STATUS_NOT_FOUND;
759 NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
760 entry = OvsLookupIPFwdEntry(dstIp);
762 info->value[0] = entry->info.value[0];
763 info->value[1] = entry->info.value[1];
764 info->value[2] = entry->info.value[2];
765 status = STATUS_SUCCESS;
767 NdisReleaseRWLock(ovsTableLock, &lockState);
772 static POVS_IPNEIGH_ENTRY
773 OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
776 POVS_IPNEIGH_ENTRY entry;
779 ASSERT(ipNeigh != NULL);
780 entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemoryWithTag(
781 sizeof(OVS_IPNEIGH_ENTRY), OVS_IPHELPER_POOL_TAG);
786 RtlZeroMemory(entry, sizeof (OVS_IPNEIGH_ENTRY));
787 entry->ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
788 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
789 entry->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
790 RtlCopyMemory(entry->macAddr, ipNeigh->PhysicalAddress,
792 InitializeListHead(&entry->fwdList);
798 static POVS_IPFORWARD_ENTRY
799 OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
802 POVS_IPFORWARD_ENTRY entry;
806 entry = (POVS_IPFORWARD_ENTRY)OvsAllocateMemoryWithTag(
807 sizeof(OVS_IPFORWARD_ENTRY), OVS_IPHELPER_POOL_TAG);
812 RtlZeroMemory(entry, sizeof (OVS_IPFORWARD_ENTRY));
813 RtlCopyMemory(&entry->prefix, &ipRoute->DestinationPrefix,
814 sizeof (IP_ADDRESS_PREFIX));
815 entry->nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
816 InitializeListHead(&entry->fwdList);
822 static POVS_FWD_ENTRY
823 OvsCreateFwdEntry(POVS_FWD_INFO fwdInfo)
825 POVS_FWD_ENTRY entry;
827 entry = (POVS_FWD_ENTRY)OvsAllocateMemoryWithTag(
828 sizeof(OVS_FWD_ENTRY), OVS_IPHELPER_POOL_TAG);
833 RtlZeroMemory(entry, sizeof (OVS_FWD_ENTRY));
834 RtlCopyMemory(&entry->info, fwdInfo, sizeof (OVS_FWD_INFO));
840 OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
842 POVS_IPFORWARD_ENTRY ipf;
843 POVS_IPNEIGH_ENTRY ipn;
848 RemoveEntryList(&fwdEntry->link);
851 RemoveEntryList(&fwdEntry->ipfLink);
854 RemoveEntryList(&fwdEntry->ipnLink);
857 if (ipf->refCount == 0) {
858 ASSERT(IsListEmpty(&ipf->fwdList));
859 RemoveEntryList(&ipf->link);
860 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
863 if (ipn->refCount == 0) {
864 ASSERT(IsListEmpty(&ipn->fwdList));
865 RemoveEntryList(&ipn->link);
866 NdisAcquireSpinLock(&ovsIpHelperLock);
867 RemoveEntryList(&ipn->slink);
868 NdisReleaseSpinLock(&ovsIpHelperLock);
869 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
872 OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
877 OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf)
879 POVS_FWD_ENTRY fwdEntry;
880 PLIST_ENTRY link, next;
884 LIST_FORALL_SAFE(&ipf->fwdList, link, next) {
885 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
886 OvsRemoveFwdEntry(fwdEntry);
888 ASSERT(ipf->refCount == 1);
890 RemoveEntryList(&ipf->link);
891 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
896 OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn)
898 PLIST_ENTRY link, next;
899 POVS_FWD_ENTRY fwdEntry;
903 LIST_FORALL_SAFE(&ipn->fwdList, link, next) {
904 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
905 OvsRemoveFwdEntry(fwdEntry);
908 if (ipn->refCount == 1) {
909 RemoveEntryList(&ipn->link);
910 NdisAcquireSpinLock(&ovsIpHelperLock);
911 RemoveEntryList(&ipn->slink);
912 NdisReleaseSpinLock(&ovsIpHelperLock);
913 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
919 OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn)
922 POVS_IPNEIGH_ENTRY entry;
924 if (!IsListEmpty(&ovsSortedIPNeighList)) {
925 link = ovsSortedIPNeighList.Blink;
926 entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
927 if (entry->timeout > ipn->timeout) {
931 InsertTailList(&ovsSortedIPNeighList, &ipn->slink);
936 OvsAddIPFwdCache(POVS_FWD_ENTRY fwdEntry,
937 POVS_IPFORWARD_ENTRY ipf,
938 POVS_IPNEIGH_ENTRY ipn)
943 if (ipn->refCount == 0) {
944 NdisAcquireSpinLock(&ovsIpHelperLock);
945 OvsAddToSortedNeighList(ipn);
946 NdisReleaseSpinLock(&ovsIpHelperLock);
947 hash = OvsJhashWords(&ipn->ipAddr, 1, OVS_HASH_BASIS);
948 InsertHeadList(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK],
951 if (ipf->refCount == 0) {
952 hash = OvsHashIPPrefix(&ipf->prefix);
953 InsertHeadList(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK],
957 InsertHeadList(&ipf->fwdList, &fwdEntry->ipfLink);
961 InsertHeadList(&ipn->fwdList, &fwdEntry->ipnLink);
965 hash = OvsJhashWords(&fwdEntry->info.dstIpAddr, 1, OVS_HASH_BASIS);
966 InsertHeadList(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK],
973 OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr)
976 POVS_FWD_ENTRY fwdEntry;
977 PLIST_ENTRY link, next;
979 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
980 LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
981 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
982 if (fwdEntry->info.srcIpAddr == ipAddr) {
983 OvsRemoveFwdEntry(fwdEntry);
991 OvsCleanupFwdTable(VOID)
993 PLIST_ENTRY link, next;
994 POVS_IPNEIGH_ENTRY ipn;
996 LOCK_STATE_EX lockState;
998 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
999 if (ovsNumFwdEntries) {
1000 LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) {
1001 ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1002 OvsRemoveIPNeighEntry(ipn);
1005 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1006 ASSERT(IsListEmpty(&ovsFwdHashTable[i]));
1008 for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1009 ASSERT(IsListEmpty(&ovsRouteHashTable[i]));
1011 NdisReleaseRWLock(ovsTableLock, &lockState);
1016 OvsCleanupIpHelperRequestList(VOID)
1019 PLIST_ENTRY next, link;
1020 POVS_IP_HELPER_REQUEST request;
1022 NdisAcquireSpinLock(&ovsIpHelperLock);
1023 if (ovsNumIpHelperRequests == 0) {
1024 NdisReleaseSpinLock(&ovsIpHelperLock);
1028 InitializeListHead(&list);
1029 OvsAppendList(&list, &ovsIpHelperRequestList);
1030 ovsNumIpHelperRequests = 0;
1031 NdisReleaseSpinLock(&ovsIpHelperLock);
1033 LIST_FORALL_SAFE(&list, link, next) {
1034 request = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1036 if (request->command == OVS_IP_HELPER_FWD_REQUEST &&
1037 request->fwdReq.cb) {
1038 request->fwdReq.cb(request->fwdReq.nbl,
1039 request->fwdReq.inPort,
1040 &request->fwdReq.tunnelKey,
1041 request->fwdReq.cbData1,
1042 request->fwdReq.cbData2,
1043 STATUS_DEVICE_NOT_READY,
1046 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1053 OvsWakeupIPHelper(VOID)
1055 KeSetEvent(&ovsIpHelperThreadContext.event, 0, FALSE);
1059 OvsInternalAdapterDown(VOID)
1061 NdisAcquireSpinLock(&ovsIpHelperLock);
1062 ovsInternalAdapterUp = FALSE;
1063 ovsInternalIPConfigured = FALSE;
1064 NdisReleaseSpinLock(&ovsIpHelperLock);
1066 OvsCleanupIpHelperRequestList();
1068 OvsCleanupFwdTable();
1073 OvsInternalAdapterUp(GUID *netCfgInstanceId)
1075 POVS_IP_HELPER_REQUEST request;
1077 RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
1078 RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
1080 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1081 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1082 if (request == NULL) {
1083 OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1086 RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
1087 request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
1089 NdisAcquireSpinLock(&ovsIpHelperLock);
1090 ovsInternalAdapterUp = TRUE;
1091 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1092 ovsNumIpHelperRequests++;
1093 if (ovsNumIpHelperRequests == 1) {
1094 OvsWakeupIPHelper();
1096 NdisReleaseSpinLock(&ovsIpHelperLock);
1101 OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
1104 MIB_UNICASTIPADDRESS_ROW ipEntry;
1105 GUID *netCfgInstanceId = &ovsInternalNetCfgId;
1107 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1109 status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
1111 if (status != STATUS_SUCCESS) {
1112 OVS_LOG_ERROR("Fali to get IF entry for internal port with GUID"
1113 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1114 netCfgInstanceId->Data1,
1115 netCfgInstanceId->Data2,
1116 netCfgInstanceId->Data3,
1117 *(UINT16 *)netCfgInstanceId->Data4,
1118 netCfgInstanceId->Data4[2],
1119 netCfgInstanceId->Data4[3],
1120 netCfgInstanceId->Data4[4],
1121 netCfgInstanceId->Data4[5],
1122 netCfgInstanceId->Data4[6],
1123 netCfgInstanceId->Data4[7]);
1127 status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
1130 if (status == STATUS_SUCCESS) {
1131 NdisAcquireSpinLock(&ovsIpHelperLock);
1132 ovsInternalIPConfigured = TRUE;
1133 NdisReleaseSpinLock(&ovsIpHelperLock);
1138 status = OvsGetIPEntry(ovsInternalRow.InterfaceLuid, &ipEntry);
1139 if (status != STATUS_SUCCESS) {
1140 OVS_LOG_INFO("Fali to get IP entry for internal port with GUID"
1141 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1142 netCfgInstanceId->Data1,
1143 netCfgInstanceId->Data2,
1144 netCfgInstanceId->Data3,
1145 *(UINT16 *)netCfgInstanceId->Data4,
1146 netCfgInstanceId->Data4[2],
1147 netCfgInstanceId->Data4[3],
1148 netCfgInstanceId->Data4[4],
1149 netCfgInstanceId->Data4[5],
1150 netCfgInstanceId->Data4[6],
1151 netCfgInstanceId->Data4[7]);
1157 OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
1160 NdisAcquireSpinLock(&ovsIpHelperLock);
1162 if (ovsInternalAdapterUp == FALSE ||
1163 ovsInternalIPConfigured == FALSE) {
1164 NdisReleaseSpinLock(&ovsIpHelperLock);
1165 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1166 return STATUS_NDIS_ADAPTER_NOT_READY;
1168 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1169 ovsNumIpHelperRequests++;
1170 if (ovsNumIpHelperRequests == 1) {
1171 OvsWakeupIPHelper();
1173 NdisReleaseSpinLock(&ovsIpHelperLock);
1174 return STATUS_SUCCESS;
1180 OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
1182 const OvsIPv4TunnelKey *tunnelKey,
1183 OvsIPHelperCallback cb,
1187 POVS_IP_HELPER_REQUEST request;
1189 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1190 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1192 if (request == NULL) {
1193 return STATUS_INSUFFICIENT_RESOURCES;
1195 request->command = OVS_IP_HELPER_FWD_REQUEST;
1196 request->fwdReq.nbl = nbl;
1197 request->fwdReq.inPort = inPort;
1198 RtlCopyMemory(&request->fwdReq.tunnelKey, tunnelKey,
1199 sizeof (*tunnelKey));
1200 request->fwdReq.cb = cb;
1201 request->fwdReq.cbData1 = cbData1;
1202 request->fwdReq.cbData2 = cbData2;
1204 return OvsEnqueueIpHelperRequest(request);
1209 OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
1211 SOCKADDR_INET dst, src;
1212 NTSTATUS status = STATUS_SUCCESS;
1213 MIB_IPFORWARD_ROW2 ipRoute;
1214 MIB_IPNET_ROW2 ipNeigh;
1215 OVS_FWD_INFO fwdInfo;
1218 POVS_FWD_ENTRY fwdEntry = NULL;
1219 POVS_IPFORWARD_ENTRY ipf = NULL;
1220 POVS_IPNEIGH_ENTRY ipn = NULL;
1221 LOCK_STATE_EX lockState;
1222 BOOLEAN newIPF = FALSE;
1223 BOOLEAN newIPN = FALSE;
1224 BOOLEAN newFWD = FALSE;
1226 status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.dst,
1228 if (status == STATUS_SUCCESS) {
1229 goto fwd_handle_nbl;
1233 RtlZeroMemory(&dst, sizeof(dst));
1234 RtlZeroMemory(&src, sizeof(src));
1235 RtlZeroMemory(&ipRoute, sizeof (MIB_IPFORWARD_ROW2));
1236 dst.si_family = AF_INET;
1237 dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
1239 status = OvsGetRoute(ovsInternalRow.InterfaceLuid, &dst, &ipRoute, &src);
1240 if (status != STATUS_SUCCESS) {
1241 goto fwd_handle_nbl;
1243 srcAddr = src.Ipv4.sin_addr.s_addr;
1246 ipAddr = ipRoute.NextHop.Ipv4.sin_addr.s_addr;
1248 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1249 ipn = OvsLookupIPNeighEntry(ipAddr);
1251 goto fwd_request_done;
1253 NdisReleaseRWLock(ovsTableLock, &lockState);
1255 RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
1256 ipNeigh.InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
1258 ipAddr = request->fwdReq.tunnelKey.dst;
1260 status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1261 if (status != STATUS_SUCCESS) {
1262 goto fwd_handle_nbl;
1265 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1272 ipf = OvsLookupIPForwardEntry(&ipRoute.DestinationPrefix);
1274 ipf = OvsCreateIPForwardEntry(&ipRoute);
1276 NdisReleaseRWLock(ovsTableLock, &lockState);
1277 status = STATUS_INSUFFICIENT_RESOURCES;
1278 goto fwd_handle_nbl;
1283 link = ipf->fwdList.Flink;
1284 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
1285 srcAddr = fwdEntry->info.srcIpAddr;
1292 ipn = OvsLookupIPNeighEntry(ipAddr);
1294 ipn = OvsCreateIPNeighEntry(&ipNeigh);
1296 NdisReleaseRWLock(ovsTableLock, &lockState);
1297 status = STATUS_INSUFFICIENT_RESOURCES;
1298 goto fwd_handle_nbl;
1305 * initialize fwdEntry
1307 fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
1308 fwdInfo.srcIpAddr = srcAddr;
1309 RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
1310 RtlCopyMemory(fwdInfo.srcMacAddr, ovsInternalRow.PhysicalAddress,
1312 fwdInfo.srcPortNo = request->fwdReq.inPort;
1314 fwdEntry = OvsCreateFwdEntry(&fwdInfo);
1315 if (fwdEntry == NULL) {
1316 NdisReleaseRWLock(ovsTableLock, &lockState);
1317 status = STATUS_INSUFFICIENT_RESOURCES;
1318 goto fwd_handle_nbl;
1324 OvsAddIPFwdCache(fwdEntry, ipf, ipn);
1325 NdisReleaseRWLock(ovsTableLock, &lockState);
1329 if (status != STATUS_SUCCESS) {
1331 ASSERT(fwdEntry != NULL);
1332 OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
1335 ASSERT(ipf && ipf->refCount == 0);
1336 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
1339 ASSERT(ipn && ipn->refCount == 0);
1340 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
1342 ipAddr = request->fwdReq.tunnelKey.dst;
1343 OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
1344 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
1345 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
1347 if (request->fwdReq.cb) {
1348 request->fwdReq.cb(request->fwdReq.nbl,
1349 request->fwdReq.inPort,
1350 &request->fwdReq.tunnelKey,
1351 request->fwdReq.cbData1,
1352 request->fwdReq.cbData2,
1354 status == STATUS_SUCCESS ? &fwdInfo : NULL);
1356 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1361 OvsUpdateIPNeighEntry(UINT32 ipAddr,
1362 PMIB_IPNET_ROW2 ipNeigh,
1366 POVS_IPNEIGH_ENTRY ipn;
1367 LOCK_STATE_EX lockState;
1368 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1370 * if mac changed, update all relevant fwdEntry
1372 if (status != STATUS_SUCCESS) {
1373 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1375 NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
1377 ipn = OvsLookupIPNeighEntry(ipAddr);
1379 NdisReleaseRWLock(ovsTableLock, &lockState);
1382 if (status != STATUS_SUCCESS) {
1383 OvsRemoveIPNeighEntry(ipn);
1384 NdisReleaseRWLock(ovsTableLock, &lockState);
1388 if (memcmp((const PVOID)ipn->macAddr,
1389 (const PVOID)ipNeigh->PhysicalAddress,
1390 (size_t)ETH_ADDR_LEN)) {
1392 POVS_FWD_ENTRY fwdEntry;
1393 NdisReleaseRWLock(ovsTableLock, &lockState);
1395 * need update, release and acquire write lock
1396 * This is not the common case.
1399 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1400 ipn = OvsLookupIPNeighEntry(ipAddr);
1403 NdisReleaseRWLock(ovsTableLock, &lockState);
1407 LIST_FORALL(&ipn->fwdList, link) {
1408 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1409 RtlCopyMemory(fwdEntry->info.dstMacAddr,
1410 ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
1414 * update timeout and move to the end of
1418 NdisAcquireSpinLock(&ovsIpHelperLock);
1419 RemoveEntryList(&ipn->slink);
1420 ipn->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1421 OvsAddToSortedNeighList(ipn);
1422 NdisReleaseSpinLock(&ovsIpHelperLock);
1423 NdisReleaseRWLock(ovsTableLock, &lockState);
1428 OvsHandleIPNeighTimeout(UINT32 ipAddr)
1430 MIB_IPNET_ROW2 ipNeigh;
1433 status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1435 OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
1440 *----------------------------------------------------------------------------
1441 * IP Helper system threash handle following request
1442 * 1. Intialize Internal port row when internal port is connected
1443 * 2. Handle FWD request
1444 * 3. Handle IP Neigh timeout
1446 * IP Interface, unicast address, and IP route change will be handled
1447 * by the revelant callback.
1448 *----------------------------------------------------------------------------
1451 OvsStartIpHelper(PVOID data)
1453 POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
1454 POVS_IP_HELPER_REQUEST req;
1455 POVS_IPNEIGH_ENTRY ipn;
1457 UINT64 timeVal, timeout;
1459 OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
1461 NdisAcquireSpinLock(&ovsIpHelperLock);
1462 while (!context->exit) {
1465 while (!IsListEmpty(&ovsIpHelperRequestList)) {
1466 if (context->exit) {
1467 goto ip_helper_wait;
1469 link = ovsIpHelperRequestList.Flink;
1470 RemoveEntryList(link);
1471 NdisReleaseSpinLock(&ovsIpHelperLock);
1472 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1473 switch (req->command) {
1474 case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
1475 OvsHandleInternalAdapterUp(req);
1477 case OVS_IP_HELPER_FWD_REQUEST:
1478 OvsHandleFwdRequest(req);
1481 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1483 NdisAcquireSpinLock(&ovsIpHelperLock);
1486 /* for now, let us hold the lock here, if this cause any issue
1487 * we will change to use IpHelper lock only to protect
1490 while (!IsListEmpty(&ovsSortedIPNeighList)) {
1492 if (context->exit) {
1493 goto ip_helper_wait;
1495 link = ovsSortedIPNeighList.Flink;
1496 ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1497 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1498 if (ipn->timeout > timeVal) {
1499 timeout = ipn->timeout;
1502 ipAddr = ipn->ipAddr;
1504 NdisReleaseSpinLock(&ovsIpHelperLock);
1506 OvsHandleIPNeighTimeout(ipAddr);
1508 NdisAcquireSpinLock(&ovsIpHelperLock);
1510 if (!IsListEmpty(&ovsIpHelperRequestList)) {
1515 if (context->exit) {
1519 KeClearEvent(&context->event);
1520 NdisReleaseSpinLock(&ovsIpHelperLock);
1522 KeWaitForSingleObject(&context->event, Executive, KernelMode,
1523 FALSE, (LARGE_INTEGER *)&timeout);
1524 NdisAcquireSpinLock(&ovsIpHelperLock);
1526 NdisReleaseSpinLock(&ovsIpHelperLock);
1527 OvsCleanupFwdTable();
1528 OvsCleanupIpHelperRequestList();
1530 OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
1532 PsTerminateSystemThread(STATUS_SUCCESS);
1537 OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
1540 HANDLE threadHandle;
1543 ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1544 sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1546 ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1547 sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1549 ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1550 sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1552 RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
1553 RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
1556 ovsInternalAdapterUp = FALSE;
1558 InitializeListHead(&ovsSortedIPNeighList);
1560 ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
1561 NdisAllocateSpinLock(&ovsIpHelperLock);
1563 InitializeListHead(&ovsIpHelperRequestList);
1564 ovsNumIpHelperRequests = 0;
1565 ipInterfaceNotificationHandle = NULL;
1566 ipRouteNotificationHandle = NULL;
1567 unicastIPNotificationHandle = NULL;
1569 if (ovsFwdHashTable == NULL ||
1570 ovsRouteHashTable == NULL ||
1571 ovsNeighHashTable == NULL ||
1572 ovsTableLock == NULL) {
1573 status = STATUS_INSUFFICIENT_RESOURCES;
1577 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1578 InitializeListHead(&ovsFwdHashTable[i]);
1581 for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1582 InitializeListHead(&ovsRouteHashTable[i]);
1585 for (i = 0; i < OVS_NEIGH_HASH_TABLE_SIZE; i++) {
1586 InitializeListHead(&ovsNeighHashTable[i]);
1590 KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
1592 status = OvsRegisterChangeNotification();
1593 ovsIpHelperThreadContext.exit = 0;
1594 if (status == STATUS_SUCCESS) {
1595 status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE,
1596 NULL, NULL, NULL, OvsStartIpHelper,
1597 &ovsIpHelperThreadContext);
1598 if (status != STATUS_SUCCESS) {
1601 ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL,
1603 &ovsIpHelperThreadContext.threadObject,
1605 ZwClose(threadHandle);
1610 if (status != STATUS_SUCCESS) {
1611 OvsCancelChangeNotification();
1612 if (ovsFwdHashTable) {
1613 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1614 ovsFwdHashTable = NULL;
1616 if (ovsRouteHashTable) {
1617 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1618 ovsRouteHashTable = NULL;
1620 if (ovsNeighHashTable) {
1621 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1622 ovsNeighHashTable = NULL;
1625 NdisFreeRWLock(ovsTableLock);
1626 ovsTableLock = NULL;
1628 NdisFreeSpinLock(&ovsIpHelperLock);
1630 return STATUS_SUCCESS;
1635 OvsCleanupIpHelper(VOID)
1637 OvsCancelChangeNotification();
1639 NdisAcquireSpinLock(&ovsIpHelperLock);
1640 ovsIpHelperThreadContext.exit = 1;
1641 OvsWakeupIPHelper();
1642 NdisReleaseSpinLock(&ovsIpHelperLock);
1644 KeWaitForSingleObject(ovsIpHelperThreadContext.threadObject, Executive,
1645 KernelMode, FALSE, NULL);
1646 ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
1648 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1649 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1650 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1652 NdisFreeRWLock(ovsTableLock);
1653 NdisFreeSpinLock(&ovsIpHelperLock);
1657 OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
1659 PLIST_ENTRY link, next;
1660 POVS_IP_HELPER_REQUEST req;
1662 InitializeListHead(&list);
1664 NdisAcquireSpinLock(&ovsIpHelperLock);
1665 LIST_FORALL_SAFE(&ovsIpHelperRequestList, link, next) {
1666 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1667 if (req->command == OVS_IP_HELPER_FWD_REQUEST &&
1668 (nbl == NULL || req->fwdReq.nbl == nbl)) {
1669 RemoveEntryList(link);
1670 InsertHeadList(&list, link);
1676 NdisReleaseSpinLock(&ovsIpHelperLock);
1678 LIST_FORALL_SAFE(&list, link, next) {
1679 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1680 if (req->fwdReq.cb) {
1681 req->fwdReq.cb(req->fwdReq.nbl, req->fwdReq.inPort,
1682 &req->fwdReq.tunnelKey,
1683 req->fwdReq.cbData1,
1684 req->fwdReq.cbData2,
1685 STATUS_DEVICE_NOT_READY,
1688 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);