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 UINT32 ovsInternalPortNo;
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 ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
1063 ovsInternalIPConfigured = FALSE;
1064 NdisReleaseSpinLock(&ovsIpHelperLock);
1066 OvsCleanupIpHelperRequestList();
1068 OvsCleanupFwdTable();
1073 OvsInternalAdapterUp(UINT32 portNo,
1074 GUID *netCfgInstanceId)
1076 POVS_IP_HELPER_REQUEST request;
1078 RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
1079 RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
1081 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1082 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1083 if (request == NULL) {
1084 OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1087 RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
1088 request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
1090 NdisAcquireSpinLock(&ovsIpHelperLock);
1091 ovsInternalPortNo = portNo;
1092 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1093 ovsNumIpHelperRequests++;
1094 if (ovsNumIpHelperRequests == 1) {
1095 OvsWakeupIPHelper();
1097 NdisReleaseSpinLock(&ovsIpHelperLock);
1102 OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
1105 MIB_UNICASTIPADDRESS_ROW ipEntry;
1106 GUID *netCfgInstanceId = &ovsInternalNetCfgId;
1108 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1110 status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
1112 if (status != STATUS_SUCCESS) {
1113 OVS_LOG_ERROR("Fali to get IF entry for internal port with GUID"
1114 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1115 netCfgInstanceId->Data1,
1116 netCfgInstanceId->Data2,
1117 netCfgInstanceId->Data3,
1118 *(UINT16 *)netCfgInstanceId->Data4,
1119 netCfgInstanceId->Data4[2],
1120 netCfgInstanceId->Data4[3],
1121 netCfgInstanceId->Data4[4],
1122 netCfgInstanceId->Data4[5],
1123 netCfgInstanceId->Data4[6],
1124 netCfgInstanceId->Data4[7]);
1128 status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
1131 if (status == STATUS_SUCCESS) {
1132 NdisAcquireSpinLock(&ovsIpHelperLock);
1133 ovsInternalIPConfigured = TRUE;
1134 NdisReleaseSpinLock(&ovsIpHelperLock);
1139 status = OvsGetIPEntry(ovsInternalRow.InterfaceLuid, &ipEntry);
1140 if (status != STATUS_SUCCESS) {
1141 OVS_LOG_INFO("Fali to get IP entry for internal port with GUID"
1142 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1143 netCfgInstanceId->Data1,
1144 netCfgInstanceId->Data2,
1145 netCfgInstanceId->Data3,
1146 *(UINT16 *)netCfgInstanceId->Data4,
1147 netCfgInstanceId->Data4[2],
1148 netCfgInstanceId->Data4[3],
1149 netCfgInstanceId->Data4[4],
1150 netCfgInstanceId->Data4[5],
1151 netCfgInstanceId->Data4[6],
1152 netCfgInstanceId->Data4[7]);
1158 OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
1161 NdisAcquireSpinLock(&ovsIpHelperLock);
1163 if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO ||
1164 ovsInternalIPConfigured == FALSE) {
1165 NdisReleaseSpinLock(&ovsIpHelperLock);
1166 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1167 return STATUS_NDIS_ADAPTER_NOT_READY;
1169 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1170 ovsNumIpHelperRequests++;
1171 if (ovsNumIpHelperRequests == 1) {
1172 OvsWakeupIPHelper();
1174 NdisReleaseSpinLock(&ovsIpHelperLock);
1175 return STATUS_SUCCESS;
1181 OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
1183 const OvsIPv4TunnelKey *tunnelKey,
1184 OvsIPHelperCallback cb,
1188 POVS_IP_HELPER_REQUEST request;
1190 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1191 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1193 if (request == NULL) {
1194 return STATUS_INSUFFICIENT_RESOURCES;
1196 request->command = OVS_IP_HELPER_FWD_REQUEST;
1197 request->fwdReq.nbl = nbl;
1198 request->fwdReq.inPort = inPort;
1199 RtlCopyMemory(&request->fwdReq.tunnelKey, tunnelKey,
1200 sizeof (*tunnelKey));
1201 request->fwdReq.cb = cb;
1202 request->fwdReq.cbData1 = cbData1;
1203 request->fwdReq.cbData2 = cbData2;
1205 return OvsEnqueueIpHelperRequest(request);
1210 OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
1212 SOCKADDR_INET dst, src;
1213 NTSTATUS status = STATUS_SUCCESS;
1214 MIB_IPFORWARD_ROW2 ipRoute;
1215 MIB_IPNET_ROW2 ipNeigh;
1216 OVS_FWD_INFO fwdInfo;
1219 POVS_FWD_ENTRY fwdEntry = NULL;
1220 POVS_IPFORWARD_ENTRY ipf = NULL;
1221 POVS_IPNEIGH_ENTRY ipn = NULL;
1222 LOCK_STATE_EX lockState;
1223 BOOLEAN newIPF = FALSE;
1224 BOOLEAN newIPN = FALSE;
1225 BOOLEAN newFWD = FALSE;
1227 status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.dst,
1229 if (status == STATUS_SUCCESS) {
1230 goto fwd_handle_nbl;
1234 RtlZeroMemory(&dst, sizeof(dst));
1235 RtlZeroMemory(&src, sizeof(src));
1236 RtlZeroMemory(&ipRoute, sizeof (MIB_IPFORWARD_ROW2));
1237 dst.si_family = AF_INET;
1238 dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
1240 status = OvsGetRoute(ovsInternalRow.InterfaceLuid, &dst, &ipRoute, &src);
1241 if (status != STATUS_SUCCESS) {
1242 goto fwd_handle_nbl;
1244 srcAddr = src.Ipv4.sin_addr.s_addr;
1247 ipAddr = ipRoute.NextHop.Ipv4.sin_addr.s_addr;
1249 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1250 ipn = OvsLookupIPNeighEntry(ipAddr);
1252 goto fwd_request_done;
1254 NdisReleaseRWLock(ovsTableLock, &lockState);
1256 RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
1257 ipNeigh.InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
1259 ipAddr = request->fwdReq.tunnelKey.dst;
1261 status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1262 if (status != STATUS_SUCCESS) {
1263 goto fwd_handle_nbl;
1266 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1273 ipf = OvsLookupIPForwardEntry(&ipRoute.DestinationPrefix);
1275 ipf = OvsCreateIPForwardEntry(&ipRoute);
1277 NdisReleaseRWLock(ovsTableLock, &lockState);
1278 status = STATUS_INSUFFICIENT_RESOURCES;
1279 goto fwd_handle_nbl;
1284 link = ipf->fwdList.Flink;
1285 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
1286 srcAddr = fwdEntry->info.srcIpAddr;
1293 ipn = OvsLookupIPNeighEntry(ipAddr);
1295 ipn = OvsCreateIPNeighEntry(&ipNeigh);
1297 NdisReleaseRWLock(ovsTableLock, &lockState);
1298 status = STATUS_INSUFFICIENT_RESOURCES;
1299 goto fwd_handle_nbl;
1306 * initialize fwdEntry
1308 fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
1309 fwdInfo.srcIpAddr = srcAddr;
1310 RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
1311 RtlCopyMemory(fwdInfo.srcMacAddr, ovsInternalRow.PhysicalAddress,
1313 fwdInfo.srcPortNo = request->fwdReq.inPort;
1315 fwdEntry = OvsCreateFwdEntry(&fwdInfo);
1316 if (fwdEntry == NULL) {
1317 NdisReleaseRWLock(ovsTableLock, &lockState);
1318 status = STATUS_INSUFFICIENT_RESOURCES;
1319 goto fwd_handle_nbl;
1325 OvsAddIPFwdCache(fwdEntry, ipf, ipn);
1326 NdisReleaseRWLock(ovsTableLock, &lockState);
1330 if (status != STATUS_SUCCESS) {
1332 ASSERT(fwdEntry != NULL);
1333 OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
1336 ASSERT(ipf && ipf->refCount == 0);
1337 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
1340 ASSERT(ipn && ipn->refCount == 0);
1341 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
1343 ipAddr = request->fwdReq.tunnelKey.dst;
1344 OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
1345 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
1346 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
1348 if (request->fwdReq.cb) {
1349 request->fwdReq.cb(request->fwdReq.nbl,
1350 request->fwdReq.inPort,
1351 &request->fwdReq.tunnelKey,
1352 request->fwdReq.cbData1,
1353 request->fwdReq.cbData2,
1355 status == STATUS_SUCCESS ? &fwdInfo : NULL);
1357 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1362 OvsUpdateIPNeighEntry(UINT32 ipAddr,
1363 PMIB_IPNET_ROW2 ipNeigh,
1367 POVS_IPNEIGH_ENTRY ipn;
1368 LOCK_STATE_EX lockState;
1369 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1371 * if mac changed, update all relevant fwdEntry
1373 if (status != STATUS_SUCCESS) {
1374 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1376 NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
1378 ipn = OvsLookupIPNeighEntry(ipAddr);
1380 NdisReleaseRWLock(ovsTableLock, &lockState);
1383 if (status != STATUS_SUCCESS) {
1384 OvsRemoveIPNeighEntry(ipn);
1385 NdisReleaseRWLock(ovsTableLock, &lockState);
1389 if (memcmp((const PVOID)ipn->macAddr,
1390 (const PVOID)ipNeigh->PhysicalAddress,
1391 (size_t)ETH_ADDR_LEN)) {
1393 POVS_FWD_ENTRY fwdEntry;
1394 NdisReleaseRWLock(ovsTableLock, &lockState);
1396 * need update, release and acquire write lock
1397 * This is not the common case.
1400 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1401 ipn = OvsLookupIPNeighEntry(ipAddr);
1404 NdisReleaseRWLock(ovsTableLock, &lockState);
1408 LIST_FORALL(&ipn->fwdList, link) {
1409 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1410 RtlCopyMemory(fwdEntry->info.dstMacAddr,
1411 ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
1415 * update timeout and move to the end of
1419 NdisAcquireSpinLock(&ovsIpHelperLock);
1420 RemoveEntryList(&ipn->slink);
1421 ipn->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1422 OvsAddToSortedNeighList(ipn);
1423 NdisReleaseSpinLock(&ovsIpHelperLock);
1424 NdisReleaseRWLock(ovsTableLock, &lockState);
1429 OvsHandleIPNeighTimeout(UINT32 ipAddr)
1431 MIB_IPNET_ROW2 ipNeigh;
1434 status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1436 OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
1441 *----------------------------------------------------------------------------
1442 * IP Helper system threash handle following request
1443 * 1. Intialize Internal port row when internal port is connected
1444 * 2. Handle FWD request
1445 * 3. Handle IP Neigh timeout
1447 * IP Interface, unicast address, and IP route change will be handled
1448 * by the revelant callback.
1449 *----------------------------------------------------------------------------
1452 OvsStartIpHelper(PVOID data)
1454 POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
1455 POVS_IP_HELPER_REQUEST req;
1456 POVS_IPNEIGH_ENTRY ipn;
1458 UINT64 timeVal, timeout;
1460 OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
1462 NdisAcquireSpinLock(&ovsIpHelperLock);
1463 while (!context->exit) {
1466 while (!IsListEmpty(&ovsIpHelperRequestList)) {
1467 if (context->exit) {
1468 goto ip_helper_wait;
1470 link = ovsIpHelperRequestList.Flink;
1471 RemoveEntryList(link);
1472 NdisReleaseSpinLock(&ovsIpHelperLock);
1473 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1474 switch (req->command) {
1475 case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
1476 OvsHandleInternalAdapterUp(req);
1478 case OVS_IP_HELPER_FWD_REQUEST:
1479 OvsHandleFwdRequest(req);
1482 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1484 NdisAcquireSpinLock(&ovsIpHelperLock);
1487 /* for now, let us hold the lock here, if this cause any issue
1488 * we will change to use IpHelper lock only to protect
1491 while (!IsListEmpty(&ovsSortedIPNeighList)) {
1493 if (context->exit) {
1494 goto ip_helper_wait;
1496 link = ovsSortedIPNeighList.Flink;
1497 ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1498 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1499 if (ipn->timeout > timeVal) {
1500 timeout = ipn->timeout;
1503 ipAddr = ipn->ipAddr;
1505 NdisReleaseSpinLock(&ovsIpHelperLock);
1507 OvsHandleIPNeighTimeout(ipAddr);
1509 NdisAcquireSpinLock(&ovsIpHelperLock);
1511 if (!IsListEmpty(&ovsIpHelperRequestList)) {
1516 if (context->exit) {
1520 KeClearEvent(&context->event);
1521 NdisReleaseSpinLock(&ovsIpHelperLock);
1523 KeWaitForSingleObject(&context->event, Executive, KernelMode,
1524 FALSE, (LARGE_INTEGER *)&timeout);
1525 NdisAcquireSpinLock(&ovsIpHelperLock);
1527 NdisReleaseSpinLock(&ovsIpHelperLock);
1528 OvsCleanupFwdTable();
1529 OvsCleanupIpHelperRequestList();
1531 OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
1533 PsTerminateSystemThread(STATUS_SUCCESS);
1538 OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
1541 HANDLE threadHandle;
1544 ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1545 sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1547 ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1548 sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1550 ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1551 sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1553 RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
1554 RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
1557 ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
1559 InitializeListHead(&ovsSortedIPNeighList);
1561 ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
1562 NdisAllocateSpinLock(&ovsIpHelperLock);
1564 InitializeListHead(&ovsIpHelperRequestList);
1565 ovsNumIpHelperRequests = 0;
1566 ipInterfaceNotificationHandle = NULL;
1567 ipRouteNotificationHandle = NULL;
1568 unicastIPNotificationHandle = NULL;
1570 if (ovsFwdHashTable == NULL ||
1571 ovsRouteHashTable == NULL ||
1572 ovsNeighHashTable == NULL ||
1573 ovsTableLock == NULL) {
1574 status = STATUS_INSUFFICIENT_RESOURCES;
1578 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1579 InitializeListHead(&ovsFwdHashTable[i]);
1582 for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1583 InitializeListHead(&ovsRouteHashTable[i]);
1586 for (i = 0; i < OVS_NEIGH_HASH_TABLE_SIZE; i++) {
1587 InitializeListHead(&ovsNeighHashTable[i]);
1591 KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
1593 status = OvsRegisterChangeNotification();
1594 ovsIpHelperThreadContext.exit = 0;
1595 if (status == STATUS_SUCCESS) {
1596 status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE,
1597 NULL, NULL, NULL, OvsStartIpHelper,
1598 &ovsIpHelperThreadContext);
1599 if (status != STATUS_SUCCESS) {
1602 ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL,
1604 &ovsIpHelperThreadContext.threadObject,
1606 ZwClose(threadHandle);
1611 if (status != STATUS_SUCCESS) {
1612 OvsCancelChangeNotification();
1613 if (ovsFwdHashTable) {
1614 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1615 ovsFwdHashTable = NULL;
1617 if (ovsRouteHashTable) {
1618 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1619 ovsRouteHashTable = NULL;
1621 if (ovsNeighHashTable) {
1622 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1623 ovsNeighHashTable = NULL;
1626 NdisFreeRWLock(ovsTableLock);
1627 ovsTableLock = NULL;
1629 NdisFreeSpinLock(&ovsIpHelperLock);
1631 return STATUS_SUCCESS;
1636 OvsCleanupIpHelper(VOID)
1638 OvsCancelChangeNotification();
1640 NdisAcquireSpinLock(&ovsIpHelperLock);
1641 ovsIpHelperThreadContext.exit = 1;
1642 OvsWakeupIPHelper();
1643 NdisReleaseSpinLock(&ovsIpHelperLock);
1645 KeWaitForSingleObject(ovsIpHelperThreadContext.threadObject, Executive,
1646 KernelMode, FALSE, NULL);
1647 ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
1649 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1650 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1651 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1653 NdisFreeRWLock(ovsTableLock);
1654 NdisFreeSpinLock(&ovsIpHelperLock);
1658 OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
1660 PLIST_ENTRY link, next;
1661 POVS_IP_HELPER_REQUEST req;
1663 InitializeListHead(&list);
1665 NdisAcquireSpinLock(&ovsIpHelperLock);
1666 LIST_FORALL_SAFE(&ovsIpHelperRequestList, link, next) {
1667 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1668 if (req->command == OVS_IP_HELPER_FWD_REQUEST &&
1669 (nbl == NULL || req->fwdReq.nbl == nbl)) {
1670 RemoveEntryList(link);
1671 InsertHeadList(&list, link);
1677 NdisReleaseSpinLock(&ovsIpHelperLock);
1679 LIST_FORALL_SAFE(&list, link, next) {
1680 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1681 if (req->fwdReq.cb) {
1682 req->fwdReq.cb(req->fwdReq.nbl, req->fwdReq.inPort,
1683 &req->fwdReq.tunnelKey,
1684 req->fwdReq.cbData1,
1685 req->fwdReq.cbData2,
1686 STATUS_DEVICE_NOT_READY,
1689 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);