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