]> git.proxmox.com Git - mirror_ovs.git/blame - datapath-windows/ovsext/IpHelper.c
datapath-windows: fix excessive stack usage in iphelper
[mirror_ovs.git] / datapath-windows / ovsext / IpHelper.c
CommitLineData
c803536e
SS
1/*
2 * Copyright (c) 2014 VMware, Inc.
3 *
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:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "precomp.h"
fa1324c9
SG
18#include "IpHelper.h"
19#include "Switch.h"
20#include "Jhash.h"
c803536e 21
cd30b346
AS
22extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
23
c803536e
SS
24#ifdef OVS_DBG_MOD
25#undef OVS_DBG_MOD
26#endif
27#define OVS_DBG_MOD OVS_DBG_IPHELPER
fa1324c9 28#include "Debug.h"
c803536e
SS
29
30/*
cd30b346 31 * IpHelper supports multiple internal adapters.
c803536e
SS
32 */
33
34KSTART_ROUTINE OvsStartIpHelper;
35
cd30b346
AS
36/* Contains the entries of internal adapter objects. */
37static LIST_ENTRY ovsInstanceList;
38
39/* Passive-level lock used to protect the internal adapter object list. */
40static ERESOURCE ovsInstanceListLock;
c803536e
SS
41
42/*
cd30b346
AS
43 * This structure is used to define each adapter instance.
44 *
45 * Note:
c803536e
SS
46 * Only when the internal IP is configured and virtual
47 * internal port is connected, the IP helper request can be
48 * queued.
cd30b346
AS
49 *
50 * We only keep internal IP for reference, it will not be used for determining
51 * SRC IP of the Tunnel.
52 *
53 * The lock must not raise the IRQL higher than PASSIVE_LEVEL in order for the
54 * route manipulation functions, i.e. GetBestRoute, to work.
c803536e 55 */
cd30b346
AS
56typedef struct _OVS_IPHELPER_INSTANCE
57{
58 LIST_ENTRY link;
59
60 BOOLEAN isIpConfigured;
61 UINT32 portNo;
62 GUID netCfgId;
63 MIB_IF_ROW2 internalRow;
64 MIB_IPINTERFACE_ROW internalIPRow;
65 UINT32 ipAddress;
c803536e 66
cd30b346
AS
67 ERESOURCE lock;
68} OVS_IPHELPER_INSTANCE, *POVS_IPHELPER_INSTANCE;
c803536e
SS
69
70/*
71 * FWD_ENTRY --------> IPFORWARD_ENTRY
72 * |
73 * |--------------------------------------> IPENIGH_ENTRY
74 *
75 * IPFORWARD_ENTRY ------> FWD_ENTRY LIST with same IPFORWARD
76 *
77 * IPNEIGH_ENTRY ------> FWD_ENTRY LIST with same IPNEIGH
78 *
79 */
80
81static PLIST_ENTRY ovsFwdHashTable; // based on DST IP
82static PLIST_ENTRY ovsRouteHashTable; // based on DST PREFIX
83static PLIST_ENTRY ovsNeighHashTable; // based on DST IP
84static LIST_ENTRY ovsSortedIPNeighList;
85static UINT32 ovsNumFwdEntries;
86
87
88static PNDIS_RW_LOCK_EX ovsTableLock;
89static NDIS_SPIN_LOCK ovsIpHelperLock;
90
91static LIST_ENTRY ovsIpHelperRequestList;
92static UINT32 ovsNumIpHelperRequests;
93
94static HANDLE ipInterfaceNotificationHandle;
95static HANDLE ipRouteNotificationHandle;
96static HANDLE unicastIPNotificationHandle;
97
98static OVS_IP_HELPER_THREAD_CONTEXT ovsIpHelperThreadContext;
99
100static POVS_IPFORWARD_ENTRY OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix);
101static VOID OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf);
102static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);
cd30b346 103static VOID OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo);
c803536e
SS
104static VOID OvsCleanupIpHelperRequestList(VOID);
105static VOID OvsCleanupFwdTable(VOID);
106static VOID OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn);
cd30b346
AS
107static POVS_IPHELPER_INSTANCE OvsIpHelperAllocateInstance(
108 POVS_IP_HELPER_REQUEST request);
109static VOID OvsIpHelperDeleteInstance(POVS_IPHELPER_INSTANCE instance);
110
111
112static VOID
113OvsDumpMessageWithGuid(char* message, GUID guid)
114{
115 OVS_LOG_INFO(message, guid.Data1, guid.Data2, guid.Data3,
116 *(UINT16 *)guid.Data4, guid.Data4[2], guid.Data4[3],
117 guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
118}
c803536e
SS
119
120static VOID
121OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
122{
123 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
124 ifRow->InterfaceLuid.Info.NetLuidIndex,
125 ifRow->InterfaceLuid.Info.IfType);
126 OVS_LOG_INFO("InterfaceIndex: %d", ifRow->InterfaceIndex);
127
cd30b346
AS
128 OvsDumpMessageWithGuid("Interface GUID: "
129 "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
130 ifRow->InterfaceGuid);
c803536e
SS
131 OVS_LOG_INFO("Perm MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
132 ifRow->PermanentPhysicalAddress[0],
133 ifRow->PermanentPhysicalAddress[1],
134 ifRow->PermanentPhysicalAddress[2],
135 ifRow->PermanentPhysicalAddress[3],
136 ifRow->PermanentPhysicalAddress[4],
137 ifRow->PermanentPhysicalAddress[5]);
138}
139
c803536e
SS
140static VOID
141OvsDumpIfTable(PMIB_IF_TABLE2 ifTable)
142{
143 PMIB_IF_ROW2 ifRow;
144 UINT32 i;
145
146 OVS_LOG_INFO("======Number of entries: %d========", ifTable->NumEntries);
147
148 for (i = 0; i < ifTable->NumEntries; i++) {
149 ifRow = &ifTable->Table[i];
150 OvsDumpIfRow(ifRow);
151 }
152}
153
154
155NTSTATUS
156OvsGetIfEntry(GUID *interfaceGuid, PMIB_IF_ROW2 ifEntry)
157{
158 NTSTATUS status;
159 PMIB_IF_TABLE2 ifTable;
160 UINT32 i;
161
162 if (interfaceGuid == NULL || ifEntry == NULL) {
163 return STATUS_INVALID_PARAMETER;
164 }
165
166 status = GetIfTable2Ex(MibIfTableNormal, &ifTable);
167
168 if (status != STATUS_SUCCESS) {
169 OVS_LOG_INFO("Fail to get if table, status: %x", status);
170 return status;
171 }
172 status = STATUS_NOT_FOUND;
173
174 for (i = 0; i < ifTable->NumEntries; i++) {
175 PMIB_IF_ROW2 ifRow;
176
177 ifRow = &ifTable->Table[i];
178 if (!memcmp(interfaceGuid, &ifRow->InterfaceGuid, sizeof (GUID))) {
179 RtlCopyMemory(ifEntry, ifRow, sizeof (MIB_IF_ROW2));
180 status = STATUS_SUCCESS;
181 OvsDumpIfRow(ifEntry);
182 break;
183 }
184 }
185
186 FreeMibTable(ifTable);
187 return status;
188}
189
190
191static VOID
192OvsDumpIPInterfaceEntry(PMIB_IPINTERFACE_ROW ipRow)
193{
194 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
195 ipRow->InterfaceLuid.Info.NetLuidIndex,
196 ipRow->InterfaceLuid.Info.IfType);
197 OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
198
199 OVS_LOG_INFO("MaxReassembleSize: %u", ipRow->MaxReassemblySize);
200}
201
202
203NTSTATUS
204OvsGetIPInterfaceEntry(NET_LUID luid,
205 PMIB_IPINTERFACE_ROW ipRow)
206{
207 NTSTATUS status;
208
209 if (ipRow == NULL) {
210 return STATUS_INVALID_PARAMETER;
211 }
212
213 ipRow->Family = AF_INET;
214 ipRow->InterfaceLuid.Value = luid.Value;
215
216 status = GetIpInterfaceEntry(ipRow);
217
218 if (status != STATUS_SUCCESS) {
219 OVS_LOG_INFO("Fail to get internal IP Interface mib row, status: %x",
220 status);
221 return status;
222 }
223 OvsDumpIPInterfaceEntry(ipRow);
224 return status;
225}
226
227
228static VOID
229OvsDumpIPEntry(PMIB_UNICASTIPADDRESS_ROW ipRow)
230{
231 UINT32 ipAddr;
232
233 OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
234 ipRow->InterfaceLuid.Info.NetLuidIndex,
235 ipRow->InterfaceLuid.Info.IfType);
236
237 OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
238
239 ASSERT(ipRow->Address.si_family == AF_INET);
240
241 ipAddr = ipRow->Address.Ipv4.sin_addr.s_addr;
242 OVS_LOG_INFO("Unicast Address: %d.%d.%d.%d\n",
243 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
244 (ipAddr >> 16) & 0xff, ipAddr >> 24);
245}
246
247
248NTSTATUS
249OvsGetIPEntry(NET_LUID interfaceLuid,
250 PMIB_UNICASTIPADDRESS_ROW ipEntry)
251{
252 PMIB_UNICASTIPADDRESS_TABLE ipTable;
253 NTSTATUS status;
254 UINT32 i;
255
5278f698 256 if (ipEntry == NULL) {
c803536e
SS
257 return STATUS_INVALID_PARAMETER;
258 }
259
260 status = GetUnicastIpAddressTable(AF_INET, &ipTable);
261
262 if (status != STATUS_SUCCESS) {
263 OVS_LOG_INFO("Fail to get unicast address table, status: %x", status);
264 return status;
265 }
266
267 status = STATUS_NOT_FOUND;
268
269 for (i = 0; i < ipTable->NumEntries; i++) {
270 PMIB_UNICASTIPADDRESS_ROW ipRow;
271
272 ipRow = &ipTable->Table[i];
273 if (ipRow->InterfaceLuid.Value == interfaceLuid.Value) {
274 RtlCopyMemory(ipEntry, ipRow, sizeof (*ipRow));
275 OvsDumpIPEntry(ipEntry);
276 status = STATUS_SUCCESS;
277 break;
278 }
279 }
280
281 FreeMibTable(ipTable);
282 return status;
283}
284
285#ifdef OVS_ENABLE_IPPATH
286static VOID
287OvsDumpIPPath(PMIB_IPPATH_ROW ipPath)
288{
289 UINT32 ipAddr = ipPath->Source.Ipv4.sin_addr.s_addr;
290
291 OVS_LOG_INFO("Source: %d.%d.%d.%d",
292 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
293 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
294
295 ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
296 OVS_LOG_INFO("Destination: %d.%d.%d.%d",
297 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
298 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
299
300 ipAddr = ipPath->CurrentNextHop.Ipv4.sin_addr.s_addr;
301 OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
302 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
303 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
304}
305
306
307NTSTATUS
308OvsGetIPPathEntry(PMIB_IPPATH_ROW ipPath)
309{
310 NTSTATUS status;
311 UINT32 ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
312
313 status = GetIpPathEntry(ipPath);
314
315 if (status != STATUS_SUCCESS) {
316 OVS_LOG_INFO("Fail to get IP path to %d.%d.%d.%d, status:%x",
317 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
318 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
319 return status;
320 }
321 OvsDumpIPPath(ipPath);
322 return status;
323}
324#endif
325
326static VOID
327OvsDumpRoute(const SOCKADDR_INET *sourceAddress,
328 const SOCKADDR_INET *destinationAddress,
329 PMIB_IPFORWARD_ROW2 route)
330{
331 UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
332
333 OVS_LOG_INFO("Destination: %d.%d.%d.%d",
334 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
335 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
336
337 ipAddr = sourceAddress->Ipv4.sin_addr.s_addr;
338 OVS_LOG_INFO("Source: %d.%d.%d.%d",
339 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
340 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
341
342 ipAddr = route->NextHop.Ipv4.sin_addr.s_addr;
343 OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
344 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
345 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
346}
347
348
349NTSTATUS
cd30b346 350OvsGetRoute(SOCKADDR_INET *destinationAddress,
c803536e 351 PMIB_IPFORWARD_ROW2 route,
cd30b346
AS
352 SOCKADDR_INET *sourceAddress,
353 POVS_IPHELPER_INSTANCE *instance,
354 POVS_VPORT_ENTRY* vport,
355 UINT32 srcIp)
c803536e 356{
cd30b346
AS
357 NTSTATUS status = STATUS_NETWORK_UNREACHABLE;
358 NTSTATUS result = STATUS_SUCCESS;
359 PLIST_ENTRY head, link, next;
360 ULONG minMetric = MAXULONG;
c803536e
SS
361
362 if (destinationAddress == NULL || route == NULL) {
363 return STATUS_INVALID_PARAMETER;
364 }
365
cd30b346
AS
366 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
367 head = &(ovsInstanceList);
368 LIST_FORALL_SAFE(head, link, next) {
369 SOCKADDR_INET crtSrcAddr = { 0 };
370 MIB_IPFORWARD_ROW2 crtRoute = { 0 };
371 POVS_IPHELPER_INSTANCE crtInstance = NULL;
4f967565 372 WCHAR interfaceName[IF_MAX_STRING_SIZE + 1] = { 0 };
c803536e 373
cd30b346
AS
374 crtInstance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
375
376 ExAcquireResourceExclusiveLite(&crtInstance->lock, TRUE);
377 result = GetBestRoute2(&crtInstance->internalRow.InterfaceLuid, 0,
378 NULL, destinationAddress, 0, &crtRoute,
379 &crtSrcAddr);
380
381 if (result != STATUS_SUCCESS) {
382 ExReleaseResourceLite(&crtInstance->lock);
383 continue;
384 }
385
386 if (minMetric > crtRoute.Metric &&
387 (!srcIp || srcIp == crtSrcAddr.Ipv4.sin_addr.S_un.S_addr)) {
388 status = STATUS_SUCCESS;
389 size_t len = 0;
390 minMetric = crtRoute.Metric;
391 LOCK_STATE_EX lockState;
392
393 RtlCopyMemory(sourceAddress, &crtSrcAddr, sizeof(*sourceAddress));
394 RtlCopyMemory(route, &crtRoute, sizeof(*route));
395 *instance = crtInstance;
396
397 ConvertInterfaceLuidToAlias(&crtInstance->internalRow.InterfaceLuid,
398 interfaceName, IF_MAX_STRING_SIZE + 1);
399 RtlStringCbLengthW(interfaceName, IF_MAX_STRING_SIZE, &len);
400
401 if (gOvsSwitchContext != NULL) {
402 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock,
403 &lockState, 0);
404 *vport = OvsFindVportByHvNameW(gOvsSwitchContext,
405 interfaceName,
406 len);
407 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
408 }
409 }
410 ExReleaseResourceLite(&crtInstance->lock);
c803536e 411 }
cd30b346 412 ExReleaseResourceLite(&ovsInstanceListLock);
c803536e
SS
413
414 OvsDumpRoute(sourceAddress, destinationAddress, route);
cd30b346 415
c803536e
SS
416 return status;
417}
418
419static VOID
420OvsDumpIPNeigh(PMIB_IPNET_ROW2 ipNeigh)
421{
422 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
423
424 OVS_LOG_INFO("Neigh: %d.%d.%d.%d",
cd30b346
AS
425 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
426 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
c803536e
SS
427 OVS_LOG_INFO("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
428 ipNeigh->PhysicalAddress[0],
429 ipNeigh->PhysicalAddress[1],
430 ipNeigh->PhysicalAddress[2],
431 ipNeigh->PhysicalAddress[3],
432 ipNeigh->PhysicalAddress[4],
433 ipNeigh->PhysicalAddress[5]);
434}
435
436
437NTSTATUS
438OvsGetIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
439{
440 NTSTATUS status;
441
442 ASSERT(ipNeigh);
443
444 status = GetIpNetEntry2(ipNeigh);
445
446 if (status != STATUS_SUCCESS) {
447 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
448 OVS_LOG_INFO("Fail to get ARP entry: %d.%d.%d.%d, status: %x",
449 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
450 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
451 return status;
452 }
453 if (ipNeigh->State == NlnsReachable ||
454 ipNeigh->State == NlnsPermanent) {
455 OvsDumpIPNeigh(ipNeigh);
456 return STATUS_SUCCESS;
457 }
458 return STATUS_FWP_TCPIP_NOT_READY;
459}
460
461
462NTSTATUS
463OvsResolveIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
464{
465 NTSTATUS status;
466
467 ASSERT(ipNeigh);
468 status = ResolveIpNetEntry2(ipNeigh, NULL);
469
470 if (status != STATUS_SUCCESS) {
471 UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
472 OVS_LOG_INFO("Fail to resolve ARP entry: %d.%d.%d.%d, status: %x",
473 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
474 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
475 return status;
476 }
477
478 if (ipNeigh->State == NlnsReachable ||
479 ipNeigh->State == NlnsPermanent) {
480 OvsDumpIPNeigh(ipNeigh);
481 return STATUS_SUCCESS;
482 }
483 return STATUS_FWP_TCPIP_NOT_READY;
484}
485
486
487NTSTATUS
1c5875f7 488OvsGetOrResolveIPNeigh(PMIB_IF_ROW2 ipRow,
cd30b346 489 UINT32 ipAddr,
c803536e
SS
490 PMIB_IPNET_ROW2 ipNeigh)
491{
492 NTSTATUS status;
493
494 ASSERT(ipNeigh);
495
496 RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
1c5875f7
AS
497 ipNeigh->InterfaceLuid.Value = ipRow->InterfaceLuid.Value;
498 ipNeigh->InterfaceIndex = ipRow->InterfaceIndex;
c803536e
SS
499 ipNeigh->Address.si_family = AF_INET;
500 ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
501
502 status = OvsGetIPNeighEntry(ipNeigh);
503
504 if (status != STATUS_SUCCESS) {
505 RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
1c5875f7
AS
506 ipNeigh->InterfaceLuid.Value = ipRow->InterfaceLuid.Value;
507 ipNeigh->InterfaceIndex = ipRow->InterfaceIndex;
c803536e
SS
508 ipNeigh->Address.si_family = AF_INET;
509 ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
510 status = OvsResolveIPNeighEntry(ipNeigh);
511 }
512 return status;
513}
514
cd30b346
AS
515static __inline BOOLEAN
516OvsCheckInstanceRow(PMIB_IF_ROW2 instanceRow,
517 PNET_LUID netLuid,
518 NET_IFINDEX ifIndex)
519{
520 return (instanceRow->InterfaceLuid.Info.NetLuidIndex ==
521 netLuid->Info.NetLuidIndex &&
522 instanceRow->InterfaceLuid.Info.IfType ==
523 netLuid->Info.IfType &&
524 instanceRow->InterfaceIndex ==
525 ifIndex);
526}
c803536e
SS
527
528static VOID
cd30b346 529OvsUpdateIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
c803536e 530{
cd30b346
AS
531 PLIST_ENTRY head, link, next;
532
533 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
534 head = &(ovsInstanceList);
535 LIST_FORALL_SAFE(head, link, next) {
536 POVS_IPHELPER_INSTANCE instance = NULL;
537
538 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
539
540 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
541 if (OvsCheckInstanceRow(&instance->internalRow,
542 &ipRow->InterfaceLuid,
543 ipRow->InterfaceIndex)) {
544
c803536e
SS
545 /*
546 * Update the IP Interface Row
547 */
cd30b346
AS
548 RtlCopyMemory(&instance->internalIPRow, ipRow,
549 sizeof(PMIB_IPINTERFACE_ROW));
550 instance->isIpConfigured = TRUE;
551
552 OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",
553 ipRow->InterfaceLuid.Info.NetLuidIndex,
554 ipRow->InterfaceLuid.Info.IfType,
555 "modified");
556
557 ExReleaseResourceLite(&instance->lock);
558 break;
c803536e 559 }
cd30b346
AS
560 ExReleaseResourceLite(&instance->lock);
561 }
562 ExReleaseResourceLite(&ovsInstanceListLock);
c803536e 563
cd30b346
AS
564 return;
565}
566
567static VOID
568OvsAddIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
569{
570 PLIST_ENTRY head, link, next;
571 BOOLEAN found = FALSE;
572
573 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
574 head = &(ovsInstanceList);
575 LIST_FORALL_SAFE(head, link, next) {
576 POVS_IPHELPER_INSTANCE instance = NULL;
577
578 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
579
580 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
581 if (OvsCheckInstanceRow(&instance->internalRow, &ipRow->InterfaceLuid,
582 ipRow->InterfaceIndex)) {
583
584 instance->isIpConfigured = FALSE;
585 ExReleaseResourceLite(&instance->lock);
586
587 found = TRUE;
588
589 break;
590 }
591 ExReleaseResourceLite(&instance->lock);
592 }
593 ExReleaseResourceLite(&ovsInstanceListLock);
c803536e 594
cd30b346
AS
595 if (found != TRUE) {
596 NTSTATUS status;
597 POVS_IPHELPER_INSTANCE instance = NULL;
598 MIB_UNICASTIPADDRESS_ROW ipEntry;
599 BOOLEAN error = TRUE;
600 LOCK_STATE_EX lockState;
c803536e 601
cd30b346
AS
602 instance = (POVS_IPHELPER_INSTANCE)OvsAllocateMemoryWithTag(
603 sizeof(*instance), OVS_IPHELPER_POOL_TAG);
604 if (instance == NULL) {
605 goto error;
606 }
607 RtlZeroMemory(instance, sizeof(*instance));
608
609 InitializeListHead(&instance->link);
610 ExInitializeResourceLite(&instance->lock);
4f967565 611 WCHAR interfaceName[IF_MAX_STRING_SIZE + 1] = { 0 };
cd30b346
AS
612 status = ConvertInterfaceLuidToAlias(&ipRow->InterfaceLuid,
613 interfaceName,
614 IF_MAX_STRING_SIZE + 1);
615 if (gOvsSwitchContext == NULL) {
616 goto error;
617 }
618 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
619 POVS_VPORT_ENTRY vport = OvsFindVportByHvNameW(gOvsSwitchContext,
620 interfaceName,
621 sizeof(WCHAR) *
622 wcslen(interfaceName));
623
624 if (vport != NULL) {
625 RtlCopyMemory(&instance->netCfgId,
626 &vport->netCfgInstanceId,
627 sizeof(instance->netCfgId));
628 instance->portNo = vport->portNo;
629 }
630 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
631 RtlZeroMemory(&instance->internalRow, sizeof(MIB_IF_ROW2));
632 RtlZeroMemory(&instance->internalIPRow, sizeof(MIB_IPINTERFACE_ROW));
633 status = OvsGetIfEntry(&instance->netCfgId,
634 &instance->internalRow);
635
636 if (status != STATUS_SUCCESS) {
637 OvsDumpMessageWithGuid("Fail to get IF entry for internal port with GUID"
638 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
639 instance->netCfgId);
640 goto error;
c803536e
SS
641 }
642
cd30b346
AS
643 status = OvsGetIPInterfaceEntry(instance->internalRow.InterfaceLuid,
644 &instance->internalIPRow);
645
646 if (status == STATUS_SUCCESS) {
647 instance->isIpConfigured = TRUE;
648 } else {
649 goto error;
650 }
651
652 status = OvsGetIPEntry(instance->internalRow.InterfaceLuid, &ipEntry);
653 if (status != STATUS_SUCCESS) {
654 OvsDumpMessageWithGuid("Failed to get IP entry for internal port with GUID"
655 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
656 instance->netCfgId);
657 }
658
659 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
660 InsertHeadList(&ovsInstanceList, &instance->link);
661 ExReleaseResourceLite(&ovsInstanceListLock);
662
663 error = FALSE;
664
665error:
666 if (error) {
667 OvsIpHelperDeleteInstance(instance);
668 }
669 }
670
671 return;
672}
673
674static VOID
675OvsRemoveIpInterfaceNotification(PMIB_IPINTERFACE_ROW ipRow)
676{
677 PLIST_ENTRY head, link, next;
678
679 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
680 head = &(ovsInstanceList);
681 LIST_FORALL_SAFE(head, link, next) {
682 POVS_IPHELPER_INSTANCE instance = NULL;
683
684 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
685
686 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
687 if (OvsCheckInstanceRow(&instance->internalRow, &ipRow->InterfaceLuid,
688 ipRow->InterfaceIndex)) {
689
690 instance->isIpConfigured = FALSE;
691 RemoveEntryList(&instance->link);
692
693 ExReleaseResourceLite(&instance->lock);
694 OvsIpHelperDeleteInstance(instance);
695
696 OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is "\
697 "deleted",
698 ipRow->InterfaceLuid.Info.NetLuidIndex,
699 ipRow->InterfaceLuid.Info.IfType);
700
701 break;
702 }
703 ExReleaseResourceLite(&instance->lock);
704 }
705 ExReleaseResourceLite(&ovsInstanceListLock);
706
707 if (IsListEmpty(&ovsInstanceList)) {
708 OvsCleanupIpHelperRequestList();
709 OvsCleanupFwdTable();
710 }
711
712 return;
713}
714
715static VOID
716OvsChangeCallbackIpInterface(PVOID context,
717 PMIB_IPINTERFACE_ROW ipRow,
718 MIB_NOTIFICATION_TYPE notificationType)
719{
720 UNREFERENCED_PARAMETER(context);
721 switch (notificationType) {
722 case MibParameterNotification:
723 OvsUpdateIpInterfaceNotification(ipRow);
724 break;
725 case MibAddInstance:
726 OvsAddIpInterfaceNotification(ipRow);
727 break;
728
729 case MibDeleteInstance:
730 OvsRemoveIpInterfaceNotification(ipRow);
c803536e
SS
731 break;
732 case MibInitialNotification:
cd30b346 733 OVS_LOG_INFO("Got Initial notification for IP Interface change.");
c803536e
SS
734 default:
735 return;
736 }
737}
738
739
740static VOID
741OvsChangeCallbackIpRoute(PVOID context,
742 PMIB_IPFORWARD_ROW2 ipRoute,
743 MIB_NOTIFICATION_TYPE notificationType)
744{
745 UINT32 ipAddr, nextHop;
746
747 UNREFERENCED_PARAMETER(context);
748 switch (notificationType) {
749 case MibAddInstance:
750
751 ASSERT(ipRoute);
752 ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
753 nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
754
755 OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d added",
756 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
757 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
758 ipRoute->DestinationPrefix.PrefixLength,
759 nextHop & 0xff, (nextHop >> 8) & 0xff,
760 (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff);
761 break;
762
763 case MibParameterNotification:
764 case MibDeleteInstance:
cd30b346 765 {
c803536e
SS
766 ASSERT(ipRoute);
767 ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
768 nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
769
cd30b346
AS
770 POVS_IPFORWARD_ENTRY ipf;
771 LOCK_STATE_EX lockState;
772
773 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
774 ipf = OvsLookupIPForwardEntry(&ipRoute->DestinationPrefix);
775 if (ipf != NULL) {
776 OvsRemoveIPForwardEntry(ipf);
777 }
778 NdisReleaseRWLock(ovsTableLock, &lockState);
779
c803536e
SS
780 OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d %s.",
781 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
782 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
783 ipRoute->DestinationPrefix.PrefixLength,
784 nextHop & 0xff, (nextHop >> 8) & 0xff,
785 (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
786 notificationType == MibDeleteInstance ? "deleted" :
787 "modified");
c803536e 788 break;
cd30b346 789 }
c803536e
SS
790
791 case MibInitialNotification:
792 OVS_LOG_INFO("Get Initial notification for IP Route change.");
793 default:
794 return;
795 }
796}
797
798
799static VOID
800OvsChangeCallbackUnicastIpAddress(PVOID context,
801 PMIB_UNICASTIPADDRESS_ROW unicastRow,
802 MIB_NOTIFICATION_TYPE notificationType)
803{
804 UINT32 ipAddr;
805
806 UNREFERENCED_PARAMETER(context);
807 switch (notificationType) {
808 case MibParameterNotification:
809 case MibAddInstance:
cd30b346
AS
810 {
811 PLIST_ENTRY head, link, next;
812
c803536e
SS
813 ASSERT(unicastRow);
814 ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
cd30b346
AS
815
816 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
817 head = &(ovsInstanceList);
818 LIST_FORALL_SAFE(head, link, next) {
819 POVS_IPHELPER_INSTANCE instance = NULL;
820
821 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
822
823 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
824 if (instance->isIpConfigured &&
825 OvsCheckInstanceRow(&instance->internalRow,
826 &unicastRow->InterfaceLuid,
827 unicastRow->InterfaceIndex)) {
828
829 instance->ipAddress = ipAddr;
830
831 OVS_LOG_INFO("IP Address: %d.%d.%d.%d is %s",
832 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
833 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
834 notificationType == MibAddInstance ? "added": "modified");
835
836 ExReleaseResourceLite(&instance->lock);
837 break;
838 }
839 ExReleaseResourceLite(&instance->lock);
c803536e 840 }
cd30b346
AS
841 ExReleaseResourceLite(&ovsInstanceListLock);
842
c803536e 843 break;
cd30b346 844 }
c803536e
SS
845
846 case MibDeleteInstance:
cd30b346
AS
847 {
848 PLIST_ENTRY head, link, next;
849 LOCK_STATE_EX lockState;
850 BOOLEAN found = FALSE;
851
c803536e
SS
852 ASSERT(unicastRow);
853 ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
c803536e 854
cd30b346
AS
855 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
856 head = &(ovsInstanceList);
857 LIST_FORALL_SAFE(head, link, next) {
858 POVS_IPHELPER_INSTANCE instance = NULL;
859
860 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
861
862 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
863 if (instance->isIpConfigured &&
864 OvsCheckInstanceRow(&instance->internalRow,
865 &unicastRow->InterfaceLuid,
866 unicastRow->InterfaceIndex)) {
867
868 found = TRUE;
869
870 ExReleaseResourceLite(&instance->lock);
871 break;
872 }
873 ExReleaseResourceLite(&instance->lock);
874 }
875 ExReleaseResourceLite(&ovsInstanceListLock);
876
877 if (found) {
c803536e
SS
878 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
879 OvsRemoveAllFwdEntriesWithSrc(ipAddr);
880 NdisReleaseRWLock(ovsTableLock, &lockState);
881
cd30b346
AS
882 OVS_LOG_INFO("IP Address removed: %d.%d.%d.%d",
883 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
884 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
c803536e 885 }
cd30b346 886
c803536e 887 break;
cd30b346 888 }
c803536e
SS
889
890 case MibInitialNotification:
891 OVS_LOG_INFO("Get Initial notification for Unicast IP Address change.");
892 default:
893 return;
894 }
895}
896
897
898static VOID
899OvsCancelChangeNotification()
900{
901 if (ipInterfaceNotificationHandle != NULL) {
902 CancelMibChangeNotify2(ipInterfaceNotificationHandle);
903 ipInterfaceNotificationHandle = NULL;
904 }
905 if (ipRouteNotificationHandle != NULL) {
906 CancelMibChangeNotify2(ipRouteNotificationHandle);
907 ipRouteNotificationHandle = NULL;
908 }
909 if (unicastIPNotificationHandle != NULL) {
910 CancelMibChangeNotify2(unicastIPNotificationHandle);
911 unicastIPNotificationHandle = NULL;
912 }
913}
914
915
916static NTSTATUS
917OvsRegisterChangeNotification()
918{
919 NTSTATUS status;
f0aeea81 920 UINT dummy = 0;
c803536e
SS
921
922
923 status = NotifyIpInterfaceChange(AF_INET, OvsChangeCallbackIpInterface,
924 NULL, TRUE,
925 &ipInterfaceNotificationHandle);
926 if (status != STATUS_SUCCESS) {
927 OVS_LOG_ERROR("Fail to register Notify IP interface change, status:%x.",
cd30b346 928 status);
c803536e
SS
929 return status;
930 }
931
f0aeea81
AS
932 /* The CallerContext is dummy and should never be used */
933 status = NotifyRouteChange2(AF_INET, OvsChangeCallbackIpRoute, &dummy,
c803536e
SS
934 TRUE, &ipRouteNotificationHandle);
935 if (status != STATUS_SUCCESS) {
936 OVS_LOG_ERROR("Fail to regiter ip route change, status: %x.",
cd30b346 937 status);
c803536e
SS
938 goto register_cleanup;
939 }
940 status = NotifyUnicastIpAddressChange(AF_INET,
941 OvsChangeCallbackUnicastIpAddress,
942 NULL, TRUE,
943 &unicastIPNotificationHandle);
944 if (status != STATUS_SUCCESS) {
945 OVS_LOG_ERROR("Fail to regiter unicast ip change, status: %x.", status);
946 }
947register_cleanup:
948 if (status != STATUS_SUCCESS) {
949 OvsCancelChangeNotification();
950 }
951
952 return status;
953}
954
955
956static POVS_IPNEIGH_ENTRY
957OvsLookupIPNeighEntry(UINT32 ipAddr)
958{
959 PLIST_ENTRY link;
c803536e
SS
960 UINT32 hash = OvsJhashWords(&ipAddr, 1, OVS_HASH_BASIS);
961
962 LIST_FORALL(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK], link) {
cd30b346
AS
963 POVS_IPNEIGH_ENTRY entry;
964
c803536e
SS
965 entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, link);
966 if (entry->ipAddr == ipAddr) {
967 return entry;
968 }
969 }
970 return NULL;
971}
972
973
974static UINT32
975OvsHashIPPrefix(PIP_ADDRESS_PREFIX prefix)
976{
977 UINT64 words = (UINT64)prefix->Prefix.Ipv4.sin_addr.s_addr << 32 |
978 (UINT32)prefix->PrefixLength;
979 return OvsJhashWords((UINT32 *)&words, 2, OVS_HASH_BASIS);
980}
981
982
983static POVS_IPFORWARD_ENTRY
984OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
985{
986
987 PLIST_ENTRY link;
c803536e
SS
988 UINT32 hash;
989 ASSERT(prefix->Prefix.si_family == AF_INET);
990
991 hash = RtlUlongByteSwap(prefix->Prefix.Ipv4.sin_addr.s_addr);
992
993 ASSERT(prefix->PrefixLength >= 32 ||
994 (hash & (((UINT32)1 << (32 - prefix->PrefixLength)) - 1)) == 0);
995
996 hash = OvsHashIPPrefix(prefix);
997 LIST_FORALL(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK], link) {
cd30b346
AS
998 POVS_IPFORWARD_ENTRY ipfEntry;
999
c803536e
SS
1000 ipfEntry = CONTAINING_RECORD(link, OVS_IPFORWARD_ENTRY, link);
1001 if (ipfEntry->prefix.PrefixLength == prefix->PrefixLength &&
1002 ipfEntry->prefix.Prefix.Ipv4.sin_addr.s_addr ==
1003 prefix->Prefix.Ipv4.sin_addr.s_addr) {
1004 return ipfEntry;
1005 }
1006 }
1007 return NULL;
1008}
1009
1010
1011static POVS_FWD_ENTRY
cd30b346 1012OvsLookupIPFwdEntry(UINT32 srcIp, UINT32 dstIp)
c803536e
SS
1013{
1014 PLIST_ENTRY link;
c803536e
SS
1015 UINT32 hash = OvsJhashWords(&dstIp, 1, OVS_HASH_BASIS);
1016
1017 LIST_FORALL(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK], link) {
cd30b346
AS
1018 POVS_FWD_ENTRY entry;
1019
c803536e 1020 entry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
cd30b346
AS
1021 if (entry->info.dstIpAddr == dstIp &&
1022 (!srcIp || entry->info.srcIpAddr == srcIp)) {
c803536e
SS
1023 return entry;
1024 }
1025 }
1026 return NULL;
1027}
1028
1029
1030NTSTATUS
cd30b346
AS
1031OvsLookupIPFwdInfo(UINT32 srcIp,
1032 UINT32 dstIp,
c803536e
SS
1033 POVS_FWD_INFO info)
1034{
1035 POVS_FWD_ENTRY entry;
1036 LOCK_STATE_EX lockState;
1037 NTSTATUS status = STATUS_NOT_FOUND;
1038
1039 NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
cd30b346 1040 entry = OvsLookupIPFwdEntry(srcIp, dstIp);
c803536e 1041 if (entry) {
cd30b346
AS
1042 RtlCopyMemory(info->value, entry->info.value,
1043 sizeof entry->info.value);
c803536e
SS
1044 status = STATUS_SUCCESS;
1045 }
1046 NdisReleaseRWLock(ovsTableLock, &lockState);
1047 return status;
1048}
1049
1050
1051static POVS_IPNEIGH_ENTRY
cd30b346
AS
1052OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh,
1053 POVS_IPHELPER_INSTANCE instance)
c803536e
SS
1054{
1055
1056 POVS_IPNEIGH_ENTRY entry;
1057 UINT64 timeVal;
1058
1059 ASSERT(ipNeigh != NULL);
f68ddba9
SV
1060 entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemoryWithTag(
1061 sizeof(OVS_IPNEIGH_ENTRY), OVS_IPHELPER_POOL_TAG);
c803536e
SS
1062 if (entry == NULL) {
1063 return NULL;
1064 }
1065
1066 RtlZeroMemory(entry, sizeof (OVS_IPNEIGH_ENTRY));
1067 entry->ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
1068 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1069 entry->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1070 RtlCopyMemory(entry->macAddr, ipNeigh->PhysicalAddress,
b3123b20 1071 ETH_ADDR_LEN);
c803536e 1072 InitializeListHead(&entry->fwdList);
cd30b346 1073 entry->context = (PVOID)instance;
c803536e
SS
1074
1075 return entry;
1076}
1077
1078
1079static POVS_IPFORWARD_ENTRY
1080OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
1081{
c803536e
SS
1082 POVS_IPFORWARD_ENTRY entry;
1083
1084 ASSERT(ipRoute);
1085
f68ddba9
SV
1086 entry = (POVS_IPFORWARD_ENTRY)OvsAllocateMemoryWithTag(
1087 sizeof(OVS_IPFORWARD_ENTRY), OVS_IPHELPER_POOL_TAG);
c803536e
SS
1088 if (entry == NULL) {
1089 return NULL;
1090 }
1091
1092 RtlZeroMemory(entry, sizeof (OVS_IPFORWARD_ENTRY));
1093 RtlCopyMemory(&entry->prefix, &ipRoute->DestinationPrefix,
1094 sizeof (IP_ADDRESS_PREFIX));
1095 entry->nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
1096 InitializeListHead(&entry->fwdList);
1097
1098 return entry;
1099}
1100
1101
1102static POVS_FWD_ENTRY
1103OvsCreateFwdEntry(POVS_FWD_INFO fwdInfo)
1104{
1105 POVS_FWD_ENTRY entry;
1106
f68ddba9
SV
1107 entry = (POVS_FWD_ENTRY)OvsAllocateMemoryWithTag(
1108 sizeof(OVS_FWD_ENTRY), OVS_IPHELPER_POOL_TAG);
c803536e
SS
1109 if (entry == NULL) {
1110 return NULL;
1111 }
1112
1113 RtlZeroMemory(entry, sizeof (OVS_FWD_ENTRY));
1114 RtlCopyMemory(&entry->info, fwdInfo, sizeof (OVS_FWD_INFO));
1115 return entry;
1116}
1117
1118
1119static VOID
1120OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
1121{
1122 POVS_IPFORWARD_ENTRY ipf;
1123 POVS_IPNEIGH_ENTRY ipn;
1124
1125 ipf = fwdEntry->ipf;
1126 ipn = fwdEntry->ipn;
1127
1128 RemoveEntryList(&fwdEntry->link);
1129 ovsNumFwdEntries--;
1130
1131 RemoveEntryList(&fwdEntry->ipfLink);
1132 ipf->refCount--;
1133
1134 RemoveEntryList(&fwdEntry->ipnLink);
1135 ipn->refCount--;
1136
1137 if (ipf->refCount == 0) {
1138 ASSERT(IsListEmpty(&ipf->fwdList));
1139 RemoveEntryList(&ipf->link);
f68ddba9 1140 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1141 }
1142
1143 if (ipn->refCount == 0) {
1144 ASSERT(IsListEmpty(&ipn->fwdList));
1145 RemoveEntryList(&ipn->link);
1146 NdisAcquireSpinLock(&ovsIpHelperLock);
1147 RemoveEntryList(&ipn->slink);
1148 NdisReleaseSpinLock(&ovsIpHelperLock);
f68ddba9 1149 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1150 }
1151
f68ddba9 1152 OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1153}
1154
1155
1156static VOID
1157OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf)
1158{
c803536e
SS
1159 PLIST_ENTRY link, next;
1160
1161 ipf->refCount++;
1162
1163 LIST_FORALL_SAFE(&ipf->fwdList, link, next) {
cd30b346
AS
1164 POVS_FWD_ENTRY fwdEntry;
1165
c803536e
SS
1166 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
1167 OvsRemoveFwdEntry(fwdEntry);
1168 }
1169 ASSERT(ipf->refCount == 1);
1170
1171 RemoveEntryList(&ipf->link);
f68ddba9 1172 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1173}
1174
1175
1176static VOID
1177OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn)
1178{
1179 PLIST_ENTRY link, next;
c803536e
SS
1180
1181 ipn->refCount++;
1182
1183 LIST_FORALL_SAFE(&ipn->fwdList, link, next) {
cd30b346
AS
1184 POVS_FWD_ENTRY fwdEntry;
1185
c803536e
SS
1186 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1187 OvsRemoveFwdEntry(fwdEntry);
1188 }
1189
1190 if (ipn->refCount == 1) {
1191 RemoveEntryList(&ipn->link);
1192 NdisAcquireSpinLock(&ovsIpHelperLock);
1193 RemoveEntryList(&ipn->slink);
1194 NdisReleaseSpinLock(&ovsIpHelperLock);
f68ddba9 1195 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1196 }
1197}
1198
1199
1200static VOID
1201OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn)
1202{
1203 PLIST_ENTRY link;
c803536e
SS
1204
1205 if (!IsListEmpty(&ovsSortedIPNeighList)) {
1206 link = ovsSortedIPNeighList.Blink;
cd30b346 1207 POVS_IPNEIGH_ENTRY entry;
c803536e
SS
1208 entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1209 if (entry->timeout > ipn->timeout) {
1210 ipn->timeout++;
1211 }
1212 }
1213 InsertTailList(&ovsSortedIPNeighList, &ipn->slink);
1214}
1215
1216
1217static VOID
1218OvsAddIPFwdCache(POVS_FWD_ENTRY fwdEntry,
1219 POVS_IPFORWARD_ENTRY ipf,
1220 POVS_IPNEIGH_ENTRY ipn)
1221
1222{
1223 UINT32 hash;
1224
1225 if (ipn->refCount == 0) {
1226 NdisAcquireSpinLock(&ovsIpHelperLock);
1227 OvsAddToSortedNeighList(ipn);
1228 NdisReleaseSpinLock(&ovsIpHelperLock);
1229 hash = OvsJhashWords(&ipn->ipAddr, 1, OVS_HASH_BASIS);
1230 InsertHeadList(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK],
1231 &ipn->link);
1232 }
1233 if (ipf->refCount == 0) {
1234 hash = OvsHashIPPrefix(&ipf->prefix);
1235 InsertHeadList(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK],
1236 &ipf->link);
1237 }
1238
1239 InsertHeadList(&ipf->fwdList, &fwdEntry->ipfLink);
1240 ipf->refCount++;
1241 fwdEntry->ipf = ipf;
1242
1243 InsertHeadList(&ipn->fwdList, &fwdEntry->ipnLink);
1244 ipn->refCount++;
1245 fwdEntry->ipn = ipn;
1246
1247 hash = OvsJhashWords(&fwdEntry->info.dstIpAddr, 1, OVS_HASH_BASIS);
1248 InsertHeadList(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK],
1249 &fwdEntry->link);
1250 ovsNumFwdEntries++;
1251}
1252
1253
1254static VOID
1255OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr)
1256{
1257 UINT32 i;
c803536e
SS
1258 PLIST_ENTRY link, next;
1259
1260 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1261 LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
cd30b346
AS
1262 POVS_FWD_ENTRY fwdEntry;
1263
c803536e
SS
1264 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
1265 if (fwdEntry->info.srcIpAddr == ipAddr) {
1266 OvsRemoveFwdEntry(fwdEntry);
1267 }
1268 }
1269 }
1270}
1271
1272
cd30b346
AS
1273static VOID
1274OvsRemoveAllFwdEntriesWithPortNo(UINT32 portNo)
1275{
1276 UINT32 i;
1277 PLIST_ENTRY link, next;
1278
1279 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1280 LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
1281 POVS_FWD_ENTRY fwdEntry;
1282
1283 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
1284 if (fwdEntry->info.srcPortNo == portNo) {
1285 OvsRemoveFwdEntry(fwdEntry);
1286 }
1287 }
1288 }
1289}
1290
c803536e
SS
1291static VOID
1292OvsCleanupFwdTable(VOID)
1293{
1294 PLIST_ENTRY link, next;
c803536e
SS
1295 UINT32 i;
1296 LOCK_STATE_EX lockState;
1297
1298 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1299 if (ovsNumFwdEntries) {
cd30b346
AS
1300 LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) {
1301 POVS_IPNEIGH_ENTRY ipn;
1302
1303 ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1304 OvsRemoveIPNeighEntry(ipn);
1305 }
c803536e
SS
1306 }
1307 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1308 ASSERT(IsListEmpty(&ovsFwdHashTable[i]));
1309 }
1310 for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1311 ASSERT(IsListEmpty(&ovsRouteHashTable[i]));
1312 }
1313 NdisReleaseRWLock(ovsTableLock, &lockState);
1314}
1315
1316
1317static VOID
1318OvsCleanupIpHelperRequestList(VOID)
1319{
1320 LIST_ENTRY list;
1321 PLIST_ENTRY next, link;
c803536e
SS
1322
1323 NdisAcquireSpinLock(&ovsIpHelperLock);
c803536e 1324 InitializeListHead(&list);
cd30b346 1325 OvsAppendList(&list, &ovsIpHelperRequestList);
c803536e
SS
1326 ovsNumIpHelperRequests = 0;
1327 NdisReleaseSpinLock(&ovsIpHelperLock);
1328
1329 LIST_FORALL_SAFE(&list, link, next) {
cd30b346
AS
1330 POVS_IP_HELPER_REQUEST request;
1331
c803536e
SS
1332 request = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1333
1334 if (request->command == OVS_IP_HELPER_FWD_REQUEST &&
1335 request->fwdReq.cb) {
1336 request->fwdReq.cb(request->fwdReq.nbl,
1337 request->fwdReq.inPort,
1338 &request->fwdReq.tunnelKey,
1339 request->fwdReq.cbData1,
1340 request->fwdReq.cbData2,
1341 STATUS_DEVICE_NOT_READY,
1342 NULL);
1343 }
f68ddba9 1344 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1345 }
1346}
1347
1348
1349
1350static VOID
1351OvsWakeupIPHelper(VOID)
1352{
1353 KeSetEvent(&ovsIpHelperThreadContext.event, 0, FALSE);
1354}
1355
1356VOID
cd30b346
AS
1357OvsInternalAdapterDown(UINT32 portNo,
1358 GUID netCfgInstanceId)
c803536e 1359{
cd30b346 1360 POVS_IP_HELPER_REQUEST request;
c803536e 1361
cd30b346
AS
1362 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1363 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1364 if (request == NULL) {
1365 OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1366 return;
1367 }
1368 RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
1369 RtlCopyMemory(&request->instanceReq.netCfgInstanceId,
1370 &netCfgInstanceId,
1371 sizeof(netCfgInstanceId));
1372 request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN;
1373 request->instanceReq.portNo = portNo;
c803536e 1374
cd30b346
AS
1375 NdisAcquireSpinLock(&ovsIpHelperLock);
1376 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1377 ovsNumIpHelperRequests++;
1378 if (ovsNumIpHelperRequests == 1) {
1379 OvsWakeupIPHelper();
1380 }
1381 NdisReleaseSpinLock(&ovsIpHelperLock);
c803536e
SS
1382}
1383
1384
1385VOID
cd30b346
AS
1386OvsInternalAdapterUp(UINT32 portNo,
1387 GUID *netCfgInstanceId)
c803536e
SS
1388{
1389 POVS_IP_HELPER_REQUEST request;
1390
f68ddba9
SV
1391 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1392 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
c803536e
SS
1393 if (request == NULL) {
1394 OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1395 return;
1396 }
1397 RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
cd30b346
AS
1398 RtlCopyMemory(&request->instanceReq.netCfgInstanceId,
1399 netCfgInstanceId,
1400 sizeof(*netCfgInstanceId));
c803536e 1401 request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
cd30b346 1402 request->instanceReq.portNo = portNo;
c803536e
SS
1403
1404 NdisAcquireSpinLock(&ovsIpHelperLock);
c803536e
SS
1405 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1406 ovsNumIpHelperRequests++;
1407 if (ovsNumIpHelperRequests == 1) {
278d07c4 1408 NdisReleaseSpinLock(&ovsIpHelperLock);
c803536e 1409 OvsWakeupIPHelper();
278d07c4
SR
1410 } else {
1411 NdisReleaseSpinLock(&ovsIpHelperLock);
c803536e 1412 }
c803536e
SS
1413}
1414
1415
cd30b346
AS
1416static POVS_IPHELPER_INSTANCE
1417OvsIpHelperAllocateInstance(POVS_IP_HELPER_REQUEST request)
1418{
1419 POVS_IPHELPER_INSTANCE instance = NULL;
1420
1421 instance = (POVS_IPHELPER_INSTANCE)OvsAllocateMemoryWithTag(
1422 sizeof(*instance), OVS_IPHELPER_POOL_TAG);
1423 if (instance) {
1424 RtlZeroMemory(instance, sizeof(*instance));
1425
1426 RtlCopyMemory(&instance->netCfgId,
1427 &request->instanceReq.netCfgInstanceId,
1428 sizeof(instance->netCfgId));
1429 instance->portNo = request->instanceReq.portNo;
1430
1431 InitializeListHead(&instance->link);
1432 ExInitializeResourceLite(&instance->lock);
1433 }
1434
1435 return instance;
1436}
1437
1438
1439static VOID
1440OvsIpHelperDeleteInstance(POVS_IPHELPER_INSTANCE instance)
1441{
1442 if (instance) {
1443 ExDeleteResourceLite(&instance->lock);
1444 OvsFreeMemoryWithTag(instance, OVS_IPHELPER_POOL_TAG);
1445 }
1446}
1447
1448
1449static VOID
1450OvsIpHelperDeleteAllInstances()
1451{
1452 PLIST_ENTRY head, link, next;
1453
1454 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
1455 head = &ovsInstanceList;
1456 if (!IsListEmpty(head)) {
1457 LIST_FORALL_SAFE(head, link, next) {
1458 POVS_IPHELPER_INSTANCE instance = NULL;
1459 instance = CONTAINING_RECORD(link, OVS_IPHELPER_INSTANCE, link);
1460
1461 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
1462
1463 instance->isIpConfigured = FALSE;
1464 RemoveEntryList(&instance->link);
1465
1466 ExReleaseResourceLite(&instance->lock);
1467
1468 OvsIpHelperDeleteInstance(instance);
1469 }
1470 }
1471 ExReleaseResourceLite(&ovsInstanceListLock);
1472}
1473
1474
c803536e
SS
1475static VOID
1476OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
1477{
1478 NTSTATUS status;
cd30b346 1479 POVS_IPHELPER_INSTANCE instance = NULL;
c803536e 1480 MIB_UNICASTIPADDRESS_ROW ipEntry;
cd30b346 1481 BOOLEAN error = TRUE;
c803536e 1482
cd30b346
AS
1483 do {
1484 instance = OvsIpHelperAllocateInstance(request);
1485 if (instance == NULL) {
1486 break;
1487 }
1488 RtlZeroMemory(&instance->internalRow, sizeof(MIB_IF_ROW2));
1489 RtlZeroMemory(&instance->internalIPRow, sizeof(MIB_IPINTERFACE_ROW));
1490 status = OvsGetIfEntry(&instance->netCfgId,
1491 &instance->internalRow);
c803536e 1492
cd30b346
AS
1493 if (status != STATUS_SUCCESS) {
1494 OvsDumpMessageWithGuid("Fail to get IF entry for internal port with GUID"
1495 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1496 instance->netCfgId);
1497 break;
1498 }
c803536e 1499
cd30b346
AS
1500 status = OvsGetIPInterfaceEntry(instance->internalRow.InterfaceLuid,
1501 &instance->internalIPRow);
c803536e 1502
cd30b346
AS
1503 if (status == STATUS_SUCCESS) {
1504 instance->isIpConfigured = TRUE;
1505 } else {
1506 break;
1507 }
c803536e 1508
cd30b346
AS
1509 status = OvsGetIPEntry(instance->internalRow.InterfaceLuid, &ipEntry);
1510 if (status != STATUS_SUCCESS) {
1511 OvsDumpMessageWithGuid("Fail to get IP entry for internal port with GUID"
1512 " %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1513 instance->netCfgId);
1514 }
c803536e 1515
cd30b346
AS
1516 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
1517 InsertHeadList(&ovsInstanceList, &instance->link);
1518 ExReleaseResourceLite(&ovsInstanceListLock);
1519
1520 error = FALSE;
1521 } while (error);
1522
1523 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1524 if (error) {
1525 OvsIpHelperDeleteInstance(instance);
c803536e
SS
1526 }
1527}
1528
1529
1530static NTSTATUS
1531OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
1532{
cd30b346 1533 if (IsListEmpty(&ovsInstanceList)) {
f68ddba9 1534 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1535 return STATUS_NDIS_ADAPTER_NOT_READY;
1536 } else {
cd30b346 1537 NdisAcquireSpinLock(&ovsIpHelperLock);
c803536e
SS
1538 InsertHeadList(&ovsIpHelperRequestList, &request->link);
1539 ovsNumIpHelperRequests++;
1540 if (ovsNumIpHelperRequests == 1) {
1541 OvsWakeupIPHelper();
1542 }
1543 NdisReleaseSpinLock(&ovsIpHelperLock);
1544 return STATUS_SUCCESS;
1545 }
1546}
1547
1548
1549NTSTATUS
1550OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
1551 UINT32 inPort,
1552 const OvsIPv4TunnelKey *tunnelKey,
1553 OvsIPHelperCallback cb,
1554 PVOID cbData1,
1555 PVOID cbData2)
1556{
1557 POVS_IP_HELPER_REQUEST request;
1558
f68ddba9
SV
1559 request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1560 sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
c803536e
SS
1561
1562 if (request == NULL) {
1563 return STATUS_INSUFFICIENT_RESOURCES;
1564 }
1565 request->command = OVS_IP_HELPER_FWD_REQUEST;
1566 request->fwdReq.nbl = nbl;
1567 request->fwdReq.inPort = inPort;
1568 RtlCopyMemory(&request->fwdReq.tunnelKey, tunnelKey,
1569 sizeof (*tunnelKey));
1570 request->fwdReq.cb = cb;
1571 request->fwdReq.cbData1 = cbData1;
1572 request->fwdReq.cbData2 = cbData2;
1573
1574 return OvsEnqueueIpHelperRequest(request);
1575}
1576
1577
1578static VOID
1579OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
1580{
1581 SOCKADDR_INET dst, src;
5278f698 1582 NTSTATUS status;
c803536e
SS
1583 MIB_IPFORWARD_ROW2 ipRoute;
1584 MIB_IPNET_ROW2 ipNeigh;
cd30b346 1585 OVS_FWD_INFO fwdInfo = { 0 };
c803536e
SS
1586 UINT32 ipAddr;
1587 UINT32 srcAddr;
1588 POVS_FWD_ENTRY fwdEntry = NULL;
1589 POVS_IPFORWARD_ENTRY ipf = NULL;
1590 POVS_IPNEIGH_ENTRY ipn = NULL;
1591 LOCK_STATE_EX lockState;
1592 BOOLEAN newIPF = FALSE;
1593 BOOLEAN newIPN = FALSE;
1594 BOOLEAN newFWD = FALSE;
cd30b346 1595 POVS_IPHELPER_INSTANCE instance = NULL;
c803536e 1596
cd30b346
AS
1597 status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.src,
1598 request->fwdReq.tunnelKey.dst,
c803536e
SS
1599 &fwdInfo);
1600 if (status == STATUS_SUCCESS) {
1601 goto fwd_handle_nbl;
1602 }
1603
1604 /* find IPRoute */
1605 RtlZeroMemory(&dst, sizeof(dst));
1606 RtlZeroMemory(&src, sizeof(src));
1607 RtlZeroMemory(&ipRoute, sizeof (MIB_IPFORWARD_ROW2));
1608 dst.si_family = AF_INET;
1609 dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
1610
cd30b346
AS
1611 status = OvsGetRoute(&dst, &ipRoute, &src, &instance, &fwdInfo.vport, request->fwdReq.tunnelKey.src);
1612 if (request->fwdReq.tunnelKey.src && request->fwdReq.tunnelKey.src != src.Ipv4.sin_addr.s_addr) {
6abf4943 1613 UINT32 tempAddr = dst.Ipv4.sin_addr.s_addr;
cd30b346 1614 OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
6abf4943
AS
1615 tempAddr & 0xff, (tempAddr >> 8) & 0xff,
1616 (tempAddr >> 16) & 0xff, (tempAddr >> 24) & 0xff, status);
cd30b346
AS
1617 goto fwd_handle_nbl;
1618 }
1619 if (status != STATUS_SUCCESS || instance == NULL) {
6abf4943 1620 UINT32 tempAddr = dst.Ipv4.sin_addr.s_addr;
cd30b346 1621 OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
6abf4943
AS
1622 tempAddr & 0xff, (tempAddr >> 8) & 0xff,
1623 (tempAddr >> 16) & 0xff, (tempAddr >> 24) & 0xff, status);
c803536e
SS
1624 goto fwd_handle_nbl;
1625 }
cd30b346
AS
1626
1627 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
c803536e
SS
1628 srcAddr = src.Ipv4.sin_addr.s_addr;
1629
1630 /* find IPNeigh */
1631 ipAddr = ipRoute.NextHop.Ipv4.sin_addr.s_addr;
1632 if (ipAddr != 0) {
1633 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1634 ipn = OvsLookupIPNeighEntry(ipAddr);
1635 if (ipn) {
1636 goto fwd_request_done;
1637 }
1638 NdisReleaseRWLock(ovsTableLock, &lockState);
1639 }
cd30b346 1640
c803536e 1641 RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
cd30b346 1642 ipNeigh.InterfaceLuid.Value = instance->internalRow.InterfaceLuid.Value;
c803536e
SS
1643 if (ipAddr == 0) {
1644 ipAddr = request->fwdReq.tunnelKey.dst;
1645 }
1c5875f7 1646 status = OvsGetOrResolveIPNeigh(&instance->internalRow,
cd30b346 1647 ipAddr, &ipNeigh);
c803536e 1648 if (status != STATUS_SUCCESS) {
cd30b346 1649 ExReleaseResourceLite(&instance->lock);
c803536e
SS
1650 goto fwd_handle_nbl;
1651 }
1652
1653 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1654
1655fwd_request_done:
1656
1657 /*
1658 * Initialize ipf
1659 */
1660 ipf = OvsLookupIPForwardEntry(&ipRoute.DestinationPrefix);
1661 if (ipf == NULL) {
1662 ipf = OvsCreateIPForwardEntry(&ipRoute);
1663 if (ipf == NULL) {
1664 NdisReleaseRWLock(ovsTableLock, &lockState);
cd30b346 1665 ExReleaseResourceLite(&instance->lock);
c803536e
SS
1666 status = STATUS_INSUFFICIENT_RESOURCES;
1667 goto fwd_handle_nbl;
1668 }
1669 newIPF = TRUE;
1670 } else {
1671 PLIST_ENTRY link;
1672 link = ipf->fwdList.Flink;
1673 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
cd30b346
AS
1674 if (fwdEntry->info.srcIpAddr != srcAddr) {
1675 OvsRemoveFwdEntry(fwdEntry);
1676 NdisReleaseRWLock(ovsTableLock, &lockState);
1677 ExReleaseResourceLite(&instance->lock);
1678 status = STATUS_INSUFFICIENT_RESOURCES;
1679 goto fwd_handle_nbl;
1680 }
c803536e
SS
1681 srcAddr = fwdEntry->info.srcIpAddr;
1682 }
1683
1684 /*
1685 * initialize ipn
1686 */
1687 if (ipn == NULL) {
1688 ipn = OvsLookupIPNeighEntry(ipAddr);
1689 if (ipn == NULL) {
cd30b346 1690 ipn = OvsCreateIPNeighEntry(&ipNeigh, instance);
c803536e
SS
1691 if (ipn == NULL) {
1692 NdisReleaseRWLock(ovsTableLock, &lockState);
cd30b346 1693 ExReleaseResourceLite(&instance->lock);
c803536e
SS
1694 status = STATUS_INSUFFICIENT_RESOURCES;
1695 goto fwd_handle_nbl;
1696 }
1697 newIPN = TRUE;
1698 }
1699 }
1700
1701 /*
1702 * initialize fwdEntry
1703 */
1704 fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
1705 fwdInfo.srcIpAddr = srcAddr;
b3123b20 1706 RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
cd30b346 1707 RtlCopyMemory(fwdInfo.srcMacAddr, instance->internalRow.PhysicalAddress,
b3123b20 1708 ETH_ADDR_LEN);
c803536e
SS
1709 fwdInfo.srcPortNo = request->fwdReq.inPort;
1710
1711 fwdEntry = OvsCreateFwdEntry(&fwdInfo);
1712 if (fwdEntry == NULL) {
1713 NdisReleaseRWLock(ovsTableLock, &lockState);
cd30b346 1714 ExReleaseResourceLite(&instance->lock);
c803536e
SS
1715 status = STATUS_INSUFFICIENT_RESOURCES;
1716 goto fwd_handle_nbl;
1717 }
1718 newFWD = TRUE;
cd30b346
AS
1719 if (status == STATUS_SUCCESS) {
1720 /*
1721 * Cache the result
1722 */
1723 OvsAddIPFwdCache(fwdEntry, ipf, ipn);
1724 NdisReleaseRWLock(ovsTableLock, &lockState);
1725 ExReleaseResourceLite(&instance->lock);
1726 }
c803536e
SS
1727
1728fwd_handle_nbl:
1729
1730 if (status != STATUS_SUCCESS) {
1731 if (newFWD) {
1732 ASSERT(fwdEntry != NULL);
f68ddba9 1733 OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1734 }
1735 if (newIPF) {
1736 ASSERT(ipf && ipf->refCount == 0);
f68ddba9 1737 OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1738 }
1739 if (newIPN) {
1740 ASSERT(ipn && ipn->refCount == 0);
f68ddba9 1741 OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1742 }
1743 ipAddr = request->fwdReq.tunnelKey.dst;
1744 OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
1745 ipAddr & 0xff, (ipAddr >> 8) & 0xff,
1746 (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
1747 }
1748 if (request->fwdReq.cb) {
1749 request->fwdReq.cb(request->fwdReq.nbl,
1750 request->fwdReq.inPort,
1751 &request->fwdReq.tunnelKey,
1752 request->fwdReq.cbData1,
1753 request->fwdReq.cbData2,
1754 status,
1755 status == STATUS_SUCCESS ? &fwdInfo : NULL);
1756 }
f68ddba9 1757 OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1758}
1759
1760
1761static VOID
1762OvsUpdateIPNeighEntry(UINT32 ipAddr,
1763 PMIB_IPNET_ROW2 ipNeigh,
1764 NTSTATUS status)
1765{
1766 UINT64 timeVal;
1767 POVS_IPNEIGH_ENTRY ipn;
1768 LOCK_STATE_EX lockState;
1769 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1770 /*
1771 * if mac changed, update all relevant fwdEntry
1772 */
1773 if (status != STATUS_SUCCESS) {
1774 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1775 } else {
1776 NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
1777 }
1778 ipn = OvsLookupIPNeighEntry(ipAddr);
1779 if (ipn == NULL) {
1780 NdisReleaseRWLock(ovsTableLock, &lockState);
1781 return;
1782 }
1783 if (status != STATUS_SUCCESS) {
1784 OvsRemoveIPNeighEntry(ipn);
1785 NdisReleaseRWLock(ovsTableLock, &lockState);
1786 return;
1787 }
1788
1789 if (memcmp((const PVOID)ipn->macAddr,
1790 (const PVOID)ipNeigh->PhysicalAddress,
b3123b20 1791 (size_t)ETH_ADDR_LEN)) {
c803536e 1792 PLIST_ENTRY link;
c803536e
SS
1793 NdisReleaseRWLock(ovsTableLock, &lockState);
1794 /*
1795 * need update, release and acquire write lock
1796 * This is not the common case.
1797 */
1798
1799 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1800 ipn = OvsLookupIPNeighEntry(ipAddr);
1801
1802 if (ipn == NULL) {
1803 NdisReleaseRWLock(ovsTableLock, &lockState);
1804 return;
1805 }
1806
1807 LIST_FORALL(&ipn->fwdList, link) {
cd30b346 1808 POVS_FWD_ENTRY fwdEntry;
c803536e
SS
1809 fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1810 RtlCopyMemory(fwdEntry->info.dstMacAddr,
b3123b20 1811 ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
c803536e
SS
1812 }
1813 }
1814 /*
1815 * update timeout and move to the end of
1816 * the sorted list
1817 */
1818
1819 NdisAcquireSpinLock(&ovsIpHelperLock);
1820 RemoveEntryList(&ipn->slink);
1821 ipn->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1822 OvsAddToSortedNeighList(ipn);
1823 NdisReleaseSpinLock(&ovsIpHelperLock);
1824 NdisReleaseRWLock(ovsTableLock, &lockState);
1825}
1826
c803536e
SS
1827/*
1828 *----------------------------------------------------------------------------
cd30b346 1829 * IP Helper system thread handles the following requests:
c803536e
SS
1830 * 1. Intialize Internal port row when internal port is connected
1831 * 2. Handle FWD request
1832 * 3. Handle IP Neigh timeout
1833 *
1834 * IP Interface, unicast address, and IP route change will be handled
cd30b346 1835 * by the revelant callbacks.
c803536e
SS
1836 *----------------------------------------------------------------------------
1837 */
1838VOID
1839OvsStartIpHelper(PVOID data)
1840{
1841 POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
1842 POVS_IP_HELPER_REQUEST req;
1843 POVS_IPNEIGH_ENTRY ipn;
1844 PLIST_ENTRY link;
1845 UINT64 timeVal, timeout;
278d07c4 1846 PLARGE_INTEGER threadSleepTimeout;
c803536e
SS
1847
1848 OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
1849
1850 NdisAcquireSpinLock(&ovsIpHelperLock);
1851 while (!context->exit) {
1852
278d07c4 1853 threadSleepTimeout = NULL;
c803536e
SS
1854 timeout = 0;
1855 while (!IsListEmpty(&ovsIpHelperRequestList)) {
1856 if (context->exit) {
1857 goto ip_helper_wait;
1858 }
1859 link = ovsIpHelperRequestList.Flink;
1860 RemoveEntryList(link);
278d07c4 1861 ovsNumIpHelperRequests--;
c803536e
SS
1862 NdisReleaseSpinLock(&ovsIpHelperLock);
1863 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1864 switch (req->command) {
1865 case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
1866 OvsHandleInternalAdapterUp(req);
1867 break;
cd30b346
AS
1868 case OVS_IP_HELPER_INTERNAL_ADAPTER_DOWN:
1869 {
6abf4943 1870 PLIST_ENTRY head, current, next;
cd30b346
AS
1871 UINT32 portNo = req->instanceReq.portNo;
1872 GUID netCfgInstanceId = req->instanceReq.netCfgInstanceId;
1873
1874 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
1875 head = &ovsInstanceList;
6abf4943 1876 LIST_FORALL_SAFE(head, current, next) {
cd30b346
AS
1877 POVS_IPHELPER_INSTANCE instance = NULL;
1878 LOCK_STATE_EX lockState;
1879
6abf4943
AS
1880 instance = CONTAINING_RECORD(current, OVS_IPHELPER_INSTANCE,
1881 link);
cd30b346
AS
1882
1883 ExAcquireResourceExclusiveLite(&instance->lock, TRUE);
1884 if (instance->portNo == portNo &&
1885 IsEqualGUID(&instance->netCfgId, &netCfgInstanceId)) {
1886
1887 NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1888 OvsRemoveAllFwdEntriesWithPortNo(instance->portNo);
1889 NdisReleaseRWLock(ovsTableLock, &lockState);
1890
1891 RemoveEntryList(&instance->link);
1892
1893 ExReleaseResourceLite(&instance->lock);
1894
1895 OvsIpHelperDeleteInstance(instance);
1896 break;
1897 }
1898 ExReleaseResourceLite(&instance->lock);
1899 }
1900
1901 if (IsListEmpty(&ovsInstanceList)) {
1902 OvsCleanupIpHelperRequestList();
1903
1904 OvsCleanupFwdTable();
1905 }
1906 ExReleaseResourceLite(&ovsInstanceListLock);
1907 }
c803536e
SS
1908 case OVS_IP_HELPER_FWD_REQUEST:
1909 OvsHandleFwdRequest(req);
1910 break;
1911 default:
f68ddba9 1912 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
c803536e
SS
1913 }
1914 NdisAcquireSpinLock(&ovsIpHelperLock);
1915 }
1916
1917 /* for now, let us hold the lock here, if this cause any issue
1918 * we will change to use IpHelper lock only to protect
1919 * IPN
1920 */
1921 while (!IsListEmpty(&ovsSortedIPNeighList)) {
1922 UINT32 ipAddr;
1923 if (context->exit) {
1924 goto ip_helper_wait;
1925 }
1926 link = ovsSortedIPNeighList.Flink;
1927 ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1928 KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1929 if (ipn->timeout > timeVal) {
1930 timeout = ipn->timeout;
278d07c4 1931 threadSleepTimeout = (PLARGE_INTEGER)&timeout;
c803536e
SS
1932 break;
1933 }
1934 ipAddr = ipn->ipAddr;
cd30b346
AS
1935 MIB_IPNET_ROW2 ipNeigh;
1936 NTSTATUS status;
1937 POVS_IPHELPER_INSTANCE instance = (POVS_IPHELPER_INSTANCE)ipn->context;
c803536e 1938 NdisReleaseSpinLock(&ovsIpHelperLock);
cd30b346 1939 ExAcquireResourceExclusiveLite(&ovsInstanceListLock, TRUE);
c803536e 1940
1c5875f7 1941 status = OvsGetOrResolveIPNeigh(&instance->internalRow,
cd30b346
AS
1942 ipAddr, &ipNeigh);
1943 OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
1944
1945 ExReleaseResourceLite(&ovsInstanceListLock);
c803536e
SS
1946
1947 NdisAcquireSpinLock(&ovsIpHelperLock);
1948 }
1949 if (!IsListEmpty(&ovsIpHelperRequestList)) {
1950 continue;
1951 }
1952
1953ip_helper_wait:
1954 if (context->exit) {
1955 break;
1956 }
1957
1958 KeClearEvent(&context->event);
1959 NdisReleaseSpinLock(&ovsIpHelperLock);
1960
278d07c4
SR
1961 /*
1962 * Wait indefinitely for the thread to be woken up.
1963 * Passing NULL as the Timeout value in the below
1964 * call to KeWaitForSingleObject achieves this.
1965 */
c803536e 1966 KeWaitForSingleObject(&context->event, Executive, KernelMode,
278d07c4 1967 FALSE, threadSleepTimeout);
c803536e
SS
1968 NdisAcquireSpinLock(&ovsIpHelperLock);
1969 }
1970 NdisReleaseSpinLock(&ovsIpHelperLock);
1971 OvsCleanupFwdTable();
1972 OvsCleanupIpHelperRequestList();
c803536e
SS
1973 OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
1974
1975 PsTerminateSystemThread(STATUS_SUCCESS);
1976}
1977
1978
1979NTSTATUS
1980OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
1981{
cd30b346 1982 NTSTATUS status = NDIS_STATUS_SUCCESS;
c803536e
SS
1983 HANDLE threadHandle;
1984 UINT32 i;
1985
f68ddba9
SV
1986 ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1987 sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
c803536e 1988
f68ddba9
SV
1989 ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1990 sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
c803536e 1991
f68ddba9
SV
1992 ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1993 sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
c803536e 1994
c803536e
SS
1995 InitializeListHead(&ovsSortedIPNeighList);
1996
1997 ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
1998 NdisAllocateSpinLock(&ovsIpHelperLock);
1999
2000 InitializeListHead(&ovsIpHelperRequestList);
2001 ovsNumIpHelperRequests = 0;
2002 ipInterfaceNotificationHandle = NULL;
2003 ipRouteNotificationHandle = NULL;
2004 unicastIPNotificationHandle = NULL;
2005
cd30b346
AS
2006 ExInitializeResourceLite(&ovsInstanceListLock);
2007 InitializeListHead(&ovsInstanceList);
2008
c803536e
SS
2009 if (ovsFwdHashTable == NULL ||
2010 ovsRouteHashTable == NULL ||
2011 ovsNeighHashTable == NULL ||
2012 ovsTableLock == NULL) {
2013 status = STATUS_INSUFFICIENT_RESOURCES;
2014 goto init_cleanup;
2015 }
2016
2017 for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
2018 InitializeListHead(&ovsFwdHashTable[i]);
2019 }
2020
2021 for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
2022 InitializeListHead(&ovsRouteHashTable[i]);
2023 }
2024
2025 for (i = 0; i < OVS_NEIGH_HASH_TABLE_SIZE; i++) {
2026 InitializeListHead(&ovsNeighHashTable[i]);
2027 }
2028
2029
2030 KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
2031 FALSE);
2032 status = OvsRegisterChangeNotification();
2033 ovsIpHelperThreadContext.exit = 0;
2034 if (status == STATUS_SUCCESS) {
2035 status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE,
2036 NULL, NULL, NULL, OvsStartIpHelper,
2037 &ovsIpHelperThreadContext);
2038 if (status != STATUS_SUCCESS) {
2039 goto init_cleanup;
2040 }
2041 ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL,
2042 KernelMode,
2043 &ovsIpHelperThreadContext.threadObject,
2044 NULL);
2045 ZwClose(threadHandle);
2046 }
2047
2048init_cleanup:
2049
2050 if (status != STATUS_SUCCESS) {
2051 OvsCancelChangeNotification();
2052 if (ovsFwdHashTable) {
f68ddba9 2053 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
c803536e
SS
2054 ovsFwdHashTable = NULL;
2055 }
2056 if (ovsRouteHashTable) {
f68ddba9 2057 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
c803536e
SS
2058 ovsRouteHashTable = NULL;
2059 }
2060 if (ovsNeighHashTable) {
f68ddba9 2061 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
c803536e
SS
2062 ovsNeighHashTable = NULL;
2063 }
2064 if (ovsTableLock) {
2065 NdisFreeRWLock(ovsTableLock);
2066 ovsTableLock = NULL;
2067 }
cd30b346 2068 ExDeleteResourceLite(&ovsInstanceListLock);
c803536e
SS
2069 NdisFreeSpinLock(&ovsIpHelperLock);
2070 }
2071 return STATUS_SUCCESS;
2072}
2073
2074
2075VOID
2076OvsCleanupIpHelper(VOID)
2077{
2078 OvsCancelChangeNotification();
2079
2080 NdisAcquireSpinLock(&ovsIpHelperLock);
2081 ovsIpHelperThreadContext.exit = 1;
2082 OvsWakeupIPHelper();
2083 NdisReleaseSpinLock(&ovsIpHelperLock);
2084
2085 KeWaitForSingleObject(ovsIpHelperThreadContext.threadObject, Executive,
2086 KernelMode, FALSE, NULL);
2087 ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
2088
f68ddba9
SV
2089 OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
2090 OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
2091 OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
c803536e
SS
2092
2093 NdisFreeRWLock(ovsTableLock);
2094 NdisFreeSpinLock(&ovsIpHelperLock);
cd30b346
AS
2095
2096 OvsIpHelperDeleteAllInstances();
2097 ExDeleteResourceLite(&ovsInstanceListLock);
c803536e
SS
2098}
2099
2100VOID
2101OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
2102{
2103 PLIST_ENTRY link, next;
2104 POVS_IP_HELPER_REQUEST req;
2105 LIST_ENTRY list;
2106 InitializeListHead(&list);
2107
2108 NdisAcquireSpinLock(&ovsIpHelperLock);
2109 LIST_FORALL_SAFE(&ovsIpHelperRequestList, link, next) {
2110 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
2111 if (req->command == OVS_IP_HELPER_FWD_REQUEST &&
2112 (nbl == NULL || req->fwdReq.nbl == nbl)) {
2113 RemoveEntryList(link);
2114 InsertHeadList(&list, link);
2115 if (nbl != NULL) {
2116 break;
2117 }
2118 }
2119 }
2120 NdisReleaseSpinLock(&ovsIpHelperLock);
2121
2122 LIST_FORALL_SAFE(&list, link, next) {
2123 req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
2124 if (req->fwdReq.cb) {
2125 req->fwdReq.cb(req->fwdReq.nbl, req->fwdReq.inPort,
2126 &req->fwdReq.tunnelKey,
2127 req->fwdReq.cbData1,
2128 req->fwdReq.cbData2,
2129 STATUS_DEVICE_NOT_READY,
2130 NULL);
2131 }
f68ddba9 2132 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
c803536e
SS
2133 }
2134}