datapath-windows: Process tunnel filter requests iteratively
[cascardo/ovs.git] / datapath-windows / ovsext / IpHelper.c
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"
18 #include "IpHelper.h"
19 #include "Switch.h"
20 #include "Jhash.h"
21
22 #ifdef OVS_DBG_MOD
23 #undef OVS_DBG_MOD
24 #endif
25 #define OVS_DBG_MOD OVS_DBG_IPHELPER
26 #include "Debug.h"
27
28 /*
29  * Fow now, we assume only one internal adapter
30  */
31
32 KSTART_ROUTINE             OvsStartIpHelper;
33
34
35 /*
36  * Only when the internal IP is configured and virtual
37  * internal port is connected, the IP helper request can be
38  * queued.
39  */
40 static BOOLEAN             ovsInternalIPConfigured;
41 static UINT32              ovsInternalPortNo;
42 static GUID                ovsInternalNetCfgId;
43 static MIB_IF_ROW2         ovsInternalRow;
44 static MIB_IPINTERFACE_ROW ovsInternalIPRow;
45
46 /* we only keep one internal IP for reference, it will not be used for
47  * determining SRC IP of Tunnel
48  */
49 static UINT32               ovsInternalIP;
50
51
52 /*
53  * FWD_ENTRY -------->  IPFORWARD_ENTRY
54  *      |
55  *      |--------------------------------------> IPENIGH_ENTRY
56  *
57  * IPFORWARD_ENTRY  ------> FWD_ENTRY LIST with same IPFORWARD
58  *
59  * IPNEIGH_ENTRY    ------> FWD_ENTRY LIST with same IPNEIGH
60  *
61  */
62
63 static PLIST_ENTRY          ovsFwdHashTable;    // based on DST IP
64 static PLIST_ENTRY          ovsRouteHashTable;  // based on DST PREFIX
65 static PLIST_ENTRY          ovsNeighHashTable;  // based on DST IP
66 static LIST_ENTRY           ovsSortedIPNeighList;
67 static UINT32               ovsNumFwdEntries;
68
69
70 static PNDIS_RW_LOCK_EX     ovsTableLock;
71 static NDIS_SPIN_LOCK       ovsIpHelperLock;
72
73 static LIST_ENTRY           ovsIpHelperRequestList;
74 static UINT32               ovsNumIpHelperRequests;
75
76 static HANDLE               ipInterfaceNotificationHandle;
77 static HANDLE               ipRouteNotificationHandle;
78 static HANDLE               unicastIPNotificationHandle;
79
80 static OVS_IP_HELPER_THREAD_CONTEXT ovsIpHelperThreadContext;
81
82 static POVS_IPFORWARD_ENTRY OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix);
83 static VOID OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf);
84 static VOID OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr);
85 static VOID OvsCleanupIpHelperRequestList(VOID);
86 static VOID OvsCleanupFwdTable(VOID);
87 static VOID OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn);
88
89 static VOID
90 OvsDumpIfRow(PMIB_IF_ROW2 ifRow)
91 {
92     OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
93                  ifRow->InterfaceLuid.Info.NetLuidIndex,
94                  ifRow->InterfaceLuid.Info.IfType);
95     OVS_LOG_INFO("InterfaceIndex: %d", ifRow->InterfaceIndex);
96
97     OVS_LOG_INFO("Interface GUID: %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
98                  ifRow->InterfaceGuid.Data1,
99                  ifRow->InterfaceGuid.Data2,
100                  ifRow->InterfaceGuid.Data3,
101                  *(UINT16 *)ifRow->InterfaceGuid.Data4,
102                  ifRow->InterfaceGuid.Data4[2],
103                  ifRow->InterfaceGuid.Data4[3],
104                  ifRow->InterfaceGuid.Data4[4],
105                  ifRow->InterfaceGuid.Data4[5],
106                  ifRow->InterfaceGuid.Data4[6],
107                  ifRow->InterfaceGuid.Data4[7]);
108     OVS_LOG_INFO("Perm MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
109                  ifRow->PermanentPhysicalAddress[0],
110                  ifRow->PermanentPhysicalAddress[1],
111                  ifRow->PermanentPhysicalAddress[2],
112                  ifRow->PermanentPhysicalAddress[3],
113                  ifRow->PermanentPhysicalAddress[4],
114                  ifRow->PermanentPhysicalAddress[5]);
115 }
116
117
118 static VOID
119 OvsDumpIfTable(PMIB_IF_TABLE2 ifTable)
120 {
121     PMIB_IF_ROW2 ifRow;
122     UINT32 i;
123
124     OVS_LOG_INFO("======Number of entries: %d========", ifTable->NumEntries);
125
126     for (i = 0; i < ifTable->NumEntries; i++) {
127         ifRow = &ifTable->Table[i];
128         OvsDumpIfRow(ifRow);
129     }
130 }
131
132
133 NTSTATUS
134 OvsGetIfEntry(GUID *interfaceGuid, PMIB_IF_ROW2 ifEntry)
135 {
136     NTSTATUS status;
137     PMIB_IF_TABLE2 ifTable;
138     UINT32 i;
139
140     if (interfaceGuid == NULL || ifEntry == NULL) {
141         return STATUS_INVALID_PARAMETER;
142     }
143
144     status = GetIfTable2Ex(MibIfTableNormal, &ifTable);
145
146     if (status != STATUS_SUCCESS) {
147         OVS_LOG_INFO("Fail to get if table, status: %x", status);
148         return status;
149     }
150     status = STATUS_NOT_FOUND;
151
152     for (i = 0; i < ifTable->NumEntries; i++) {
153         PMIB_IF_ROW2 ifRow;
154
155         ifRow = &ifTable->Table[i];
156         if (!memcmp(interfaceGuid, &ifRow->InterfaceGuid, sizeof (GUID))) {
157             RtlCopyMemory(ifEntry, ifRow, sizeof (MIB_IF_ROW2));
158             status = STATUS_SUCCESS;
159             OvsDumpIfRow(ifEntry);
160             break;
161         }
162     }
163
164     FreeMibTable(ifTable);
165     return status;
166 }
167
168
169 static VOID
170 OvsDumpIPInterfaceEntry(PMIB_IPINTERFACE_ROW ipRow)
171 {
172     OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
173                  ipRow->InterfaceLuid.Info.NetLuidIndex,
174                  ipRow->InterfaceLuid.Info.IfType);
175     OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
176
177     OVS_LOG_INFO("MaxReassembleSize: %u", ipRow->MaxReassemblySize);
178 }
179
180
181 NTSTATUS
182 OvsGetIPInterfaceEntry(NET_LUID luid,
183                        PMIB_IPINTERFACE_ROW ipRow)
184 {
185     NTSTATUS status;
186
187     if (ipRow == NULL) {
188         return STATUS_INVALID_PARAMETER;
189     }
190
191     ipRow->Family = AF_INET;
192     ipRow->InterfaceLuid.Value = luid.Value;
193
194     status = GetIpInterfaceEntry(ipRow);
195
196     if (status != STATUS_SUCCESS) {
197         OVS_LOG_INFO("Fail to get internal IP Interface mib row, status: %x",
198                      status);
199         return status;
200     }
201     OvsDumpIPInterfaceEntry(ipRow);
202     return status;
203 }
204
205
206 static VOID
207 OvsDumpIPEntry(PMIB_UNICASTIPADDRESS_ROW ipRow)
208 {
209     UINT32 ipAddr;
210
211     OVS_LOG_INFO("InterfaceLuid: NetLuidIndex: %d, type: %d",
212                  ipRow->InterfaceLuid.Info.NetLuidIndex,
213                  ipRow->InterfaceLuid.Info.IfType);
214
215     OVS_LOG_INFO("InterfaceIndex: %d", ipRow->InterfaceIndex);
216
217     ASSERT(ipRow->Address.si_family == AF_INET);
218
219     ipAddr = ipRow->Address.Ipv4.sin_addr.s_addr;
220     OVS_LOG_INFO("Unicast Address: %d.%d.%d.%d\n",
221                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
222                  (ipAddr >> 16) & 0xff, ipAddr >> 24);
223 }
224
225
226 NTSTATUS
227 OvsGetIPEntry(NET_LUID interfaceLuid,
228               PMIB_UNICASTIPADDRESS_ROW ipEntry)
229 {
230     PMIB_UNICASTIPADDRESS_TABLE ipTable;
231     NTSTATUS status;
232     UINT32 i;
233
234     if (ipEntry == NULL || ipEntry == NULL) {
235         return STATUS_INVALID_PARAMETER;
236     }
237
238     status = GetUnicastIpAddressTable(AF_INET, &ipTable);
239
240     if (status != STATUS_SUCCESS) {
241         OVS_LOG_INFO("Fail to get unicast address table, status: %x", status);
242         return status;
243     }
244
245     status = STATUS_NOT_FOUND;
246
247     for (i = 0; i < ipTable->NumEntries; i++) {
248         PMIB_UNICASTIPADDRESS_ROW ipRow;
249
250         ipRow = &ipTable->Table[i];
251         if (ipRow->InterfaceLuid.Value == interfaceLuid.Value) {
252             RtlCopyMemory(ipEntry, ipRow, sizeof (*ipRow));
253             OvsDumpIPEntry(ipEntry);
254             status = STATUS_SUCCESS;
255             break;
256         }
257     }
258
259     FreeMibTable(ipTable);
260     return status;
261 }
262
263 #ifdef OVS_ENABLE_IPPATH
264 static VOID
265 OvsDumpIPPath(PMIB_IPPATH_ROW ipPath)
266 {
267     UINT32 ipAddr = ipPath->Source.Ipv4.sin_addr.s_addr;
268
269     OVS_LOG_INFO("Source: %d.%d.%d.%d",
270                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
271                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
272
273     ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
274     OVS_LOG_INFO("Destination: %d.%d.%d.%d",
275                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
276                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
277
278     ipAddr = ipPath->CurrentNextHop.Ipv4.sin_addr.s_addr;
279     OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
280                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
281                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
282 }
283
284
285 NTSTATUS
286 OvsGetIPPathEntry(PMIB_IPPATH_ROW ipPath)
287 {
288     NTSTATUS status;
289     UINT32 ipAddr = ipPath->Destination.Ipv4.sin_addr.s_addr;
290
291     status = GetIpPathEntry(ipPath);
292
293     if (status != STATUS_SUCCESS) {
294         OVS_LOG_INFO("Fail to get IP path to %d.%d.%d.%d, status:%x",
295                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
296                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
297         return status;
298     }
299     OvsDumpIPPath(ipPath);
300     return status;
301 }
302 #endif
303
304 static VOID
305 OvsDumpRoute(const SOCKADDR_INET *sourceAddress,
306              const SOCKADDR_INET *destinationAddress,
307              PMIB_IPFORWARD_ROW2 route)
308 {
309     UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
310
311     OVS_LOG_INFO("Destination: %d.%d.%d.%d",
312                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
313                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
314
315     ipAddr = sourceAddress->Ipv4.sin_addr.s_addr;
316     OVS_LOG_INFO("Source: %d.%d.%d.%d",
317                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
318                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
319
320     ipAddr = route->NextHop.Ipv4.sin_addr.s_addr;
321     OVS_LOG_INFO("NextHop: %d.%d.%d.%d",
322                  ipAddr & 0xff, (ipAddr >> 8) & 0xff,
323                  (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
324 }
325
326
327 NTSTATUS
328 OvsGetRoute(NET_LUID interfaceLuid,
329             const SOCKADDR_INET *destinationAddress,
330             PMIB_IPFORWARD_ROW2 route,
331             SOCKADDR_INET *sourceAddress)
332 {
333     NTSTATUS status;
334
335     if (destinationAddress == NULL || route == NULL) {
336         return STATUS_INVALID_PARAMETER;
337     }
338
339     status = GetBestRoute2(&interfaceLuid, 0,
340                            NULL, destinationAddress,
341                            0, route, sourceAddress);
342
343     if (status != STATUS_SUCCESS) {
344         UINT32 ipAddr = destinationAddress->Ipv4.sin_addr.s_addr;
345         OVS_LOG_INFO("Fail to get route to %d.%d.%d.%d, status: %x",
346                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
347                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
348         return status;
349     }
350
351     OvsDumpRoute(sourceAddress, destinationAddress, route);
352     return status;
353 }
354
355 static VOID
356 OvsDumpIPNeigh(PMIB_IPNET_ROW2 ipNeigh)
357 {
358     UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
359
360     OVS_LOG_INFO("Neigh: %d.%d.%d.%d",
361                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
362                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
363     OVS_LOG_INFO("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x",
364                  ipNeigh->PhysicalAddress[0],
365                  ipNeigh->PhysicalAddress[1],
366                  ipNeigh->PhysicalAddress[2],
367                  ipNeigh->PhysicalAddress[3],
368                  ipNeigh->PhysicalAddress[4],
369                  ipNeigh->PhysicalAddress[5]);
370 }
371
372
373 NTSTATUS
374 OvsGetIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
375 {
376     NTSTATUS status;
377
378     ASSERT(ipNeigh);
379
380     status = GetIpNetEntry2(ipNeigh);
381
382     if (status != STATUS_SUCCESS) {
383         UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
384         OVS_LOG_INFO("Fail to get ARP entry: %d.%d.%d.%d, status: %x",
385                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
386                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
387         return status;
388     }
389     if (ipNeigh->State == NlnsReachable ||
390         ipNeigh->State == NlnsPermanent) {
391         OvsDumpIPNeigh(ipNeigh);
392         return STATUS_SUCCESS;
393     }
394     return STATUS_FWP_TCPIP_NOT_READY;
395 }
396
397
398 NTSTATUS
399 OvsResolveIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
400 {
401     NTSTATUS status;
402
403     ASSERT(ipNeigh);
404     status = ResolveIpNetEntry2(ipNeigh, NULL);
405
406     if (status != STATUS_SUCCESS) {
407         UINT32 ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
408         OVS_LOG_INFO("Fail to resolve ARP entry: %d.%d.%d.%d, status: %x",
409                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
410                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff, status);
411         return status;
412     }
413
414     if (ipNeigh->State == NlnsReachable ||
415         ipNeigh->State == NlnsPermanent) {
416         OvsDumpIPNeigh(ipNeigh);
417         return STATUS_SUCCESS;
418     }
419     return STATUS_FWP_TCPIP_NOT_READY;
420 }
421
422
423 NTSTATUS
424 OvsGetOrResolveIPNeigh(UINT32 ipAddr,
425                        PMIB_IPNET_ROW2 ipNeigh)
426 {
427     NTSTATUS status;
428
429     ASSERT(ipNeigh);
430
431     RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
432     ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
433     ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
434     ipNeigh->Address.si_family = AF_INET;
435     ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
436
437     status = OvsGetIPNeighEntry(ipNeigh);
438
439     if (status != STATUS_SUCCESS) {
440         RtlZeroMemory(ipNeigh, sizeof (*ipNeigh));
441         ipNeigh->InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
442         ipNeigh->InterfaceIndex = ovsInternalRow.InterfaceIndex;
443         ipNeigh->Address.si_family = AF_INET;
444         ipNeigh->Address.Ipv4.sin_addr.s_addr = ipAddr;
445         status = OvsResolveIPNeighEntry(ipNeigh);
446     }
447     return status;
448 }
449
450
451 static VOID
452 OvsChangeCallbackIpInterface(PVOID context,
453                              PMIB_IPINTERFACE_ROW ipRow,
454                              MIB_NOTIFICATION_TYPE notificationType)
455 {
456     UNREFERENCED_PARAMETER(context);
457     switch (notificationType) {
458     case MibParameterNotification:
459     case MibAddInstance:
460         if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
461             ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
462             ipRow->InterfaceLuid.Info.IfType ==
463             ovsInternalRow.InterfaceLuid.Info.IfType &&
464             ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
465             /*
466              * Update the IP Interface Row
467              */
468             NdisAcquireSpinLock(&ovsIpHelperLock);
469             RtlCopyMemory(&ovsInternalIPRow, ipRow,
470                           sizeof (PMIB_IPINTERFACE_ROW));
471             ovsInternalIPConfigured = TRUE;
472             NdisReleaseSpinLock(&ovsIpHelperLock);
473         }
474         OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d is %s",
475                      ipRow->InterfaceLuid.Info.NetLuidIndex,
476                      ipRow->InterfaceLuid.Info.IfType,
477                      notificationType == MibAddInstance ? "added" : "modified");
478         break;
479     case MibDeleteInstance:
480         OVS_LOG_INFO("IP Interface with NetLuidIndex: %d, type: %d, deleted",
481                      ipRow->InterfaceLuid.Info.NetLuidIndex,
482                      ipRow->InterfaceLuid.Info.IfType);
483         if (ipRow->InterfaceLuid.Info.NetLuidIndex ==
484             ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
485             ipRow->InterfaceLuid.Info.IfType ==
486             ovsInternalRow.InterfaceLuid.Info.IfType &&
487             ipRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
488
489             NdisAcquireSpinLock(&ovsIpHelperLock);
490             ovsInternalIPConfigured = FALSE;
491             NdisReleaseSpinLock(&ovsIpHelperLock);
492
493             OvsCleanupIpHelperRequestList();
494
495             OvsCleanupFwdTable();
496         }
497
498         break;
499     case MibInitialNotification:
500         OVS_LOG_INFO("Get Initial notification for IP Interface change.");
501     default:
502         return;
503     }
504 }
505
506
507 static VOID
508 OvsChangeCallbackIpRoute(PVOID context,
509                          PMIB_IPFORWARD_ROW2 ipRoute,
510                          MIB_NOTIFICATION_TYPE notificationType)
511 {
512     UINT32 ipAddr, nextHop;
513
514     UNREFERENCED_PARAMETER(context);
515     switch (notificationType) {
516     case MibAddInstance:
517
518         ASSERT(ipRoute);
519         ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
520         nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
521
522         OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d added",
523                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
524                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
525                      ipRoute->DestinationPrefix.PrefixLength,
526                      nextHop & 0xff, (nextHop >> 8) & 0xff,
527                      (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff);
528         break;
529
530     case MibParameterNotification:
531     case MibDeleteInstance:
532         ASSERT(ipRoute);
533         ipAddr = ipRoute->DestinationPrefix.Prefix.Ipv4.sin_addr.s_addr;
534         nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
535
536         OVS_LOG_INFO("IPRoute: To %d.%d.%d.%d/%d through %d.%d.%d.%d %s.",
537                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
538                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
539                      ipRoute->DestinationPrefix.PrefixLength,
540                      nextHop & 0xff, (nextHop >> 8) & 0xff,
541                      (nextHop >> 16) & 0xff, (nextHop >> 24) & 0xff,
542                      notificationType == MibDeleteInstance ? "deleted" :
543                      "modified");
544
545         if (ipRoute->InterfaceLuid.Info.NetLuidIndex ==
546             ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
547             ipRoute->InterfaceLuid.Info.IfType ==
548             ovsInternalRow.InterfaceLuid.Info.IfType &&
549             ipRoute->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
550
551             POVS_IPFORWARD_ENTRY ipf;
552             LOCK_STATE_EX lockState;
553
554             NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
555             ipf = OvsLookupIPForwardEntry(&ipRoute->DestinationPrefix);
556             if (ipf != NULL) {
557                 OvsRemoveIPForwardEntry(ipf);
558             }
559             NdisReleaseRWLock(ovsTableLock, &lockState);
560         }
561         break;
562
563     case MibInitialNotification:
564         OVS_LOG_INFO("Get Initial notification for IP Route change.");
565     default:
566         return;
567     }
568 }
569
570
571 static VOID
572 OvsChangeCallbackUnicastIpAddress(PVOID context,
573                                   PMIB_UNICASTIPADDRESS_ROW unicastRow,
574                                   MIB_NOTIFICATION_TYPE notificationType)
575 {
576     UINT32 ipAddr;
577
578     UNREFERENCED_PARAMETER(context);
579     switch (notificationType) {
580     case MibParameterNotification:
581     case MibAddInstance:
582         ASSERT(unicastRow);
583         ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
584         if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
585             ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
586             unicastRow->InterfaceLuid.Info.IfType ==
587             ovsInternalRow.InterfaceLuid.Info.IfType &&
588             unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
589             ovsInternalIP = ipAddr;
590         }
591         OVS_LOG_INFO("IP Address: %d.%d.%d.%d is %s",
592                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
593                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff,
594                      notificationType == MibAddInstance ? "added": "modified");
595         break;
596
597     case MibDeleteInstance:
598         ASSERT(unicastRow);
599         ipAddr = unicastRow->Address.Ipv4.sin_addr.s_addr;
600         OVS_LOG_INFO("IP Address removed: %d.%d.%d.%d",
601                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
602                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
603         if (unicastRow->InterfaceLuid.Info.NetLuidIndex ==
604             ovsInternalRow.InterfaceLuid.Info.NetLuidIndex &&
605             unicastRow->InterfaceLuid.Info.IfType ==
606             ovsInternalRow.InterfaceLuid.Info.IfType &&
607             unicastRow->InterfaceIndex == ovsInternalRow.InterfaceIndex) {
608
609             LOCK_STATE_EX lockState;
610             NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
611             OvsRemoveAllFwdEntriesWithSrc(ipAddr);
612             NdisReleaseRWLock(ovsTableLock, &lockState);
613
614         }
615         break;
616
617     case MibInitialNotification:
618         OVS_LOG_INFO("Get Initial notification for Unicast IP Address change.");
619     default:
620         return;
621     }
622 }
623
624
625 static VOID
626 OvsCancelChangeNotification()
627 {
628     if (ipInterfaceNotificationHandle != NULL) {
629         CancelMibChangeNotify2(ipInterfaceNotificationHandle);
630         ipInterfaceNotificationHandle = NULL;
631     }
632     if (ipRouteNotificationHandle != NULL) {
633         CancelMibChangeNotify2(ipRouteNotificationHandle);
634         ipRouteNotificationHandle = NULL;
635     }
636     if (unicastIPNotificationHandle != NULL) {
637         CancelMibChangeNotify2(unicastIPNotificationHandle);
638         unicastIPNotificationHandle = NULL;
639     }
640 }
641
642
643 static NTSTATUS
644 OvsRegisterChangeNotification()
645 {
646     NTSTATUS status;
647
648
649     status = NotifyIpInterfaceChange(AF_INET, OvsChangeCallbackIpInterface,
650                                      NULL, TRUE,
651                                      &ipInterfaceNotificationHandle);
652     if (status != STATUS_SUCCESS) {
653         OVS_LOG_ERROR("Fail to register Notify IP interface change, status:%x.",
654                      status);
655         return status;
656     }
657
658     status = NotifyRouteChange2(AF_INET, OvsChangeCallbackIpRoute, NULL,
659                                 TRUE, &ipRouteNotificationHandle);
660     if (status != STATUS_SUCCESS) {
661         OVS_LOG_ERROR("Fail to regiter ip route change, status: %x.",
662                      status);
663         goto register_cleanup;
664     }
665     status = NotifyUnicastIpAddressChange(AF_INET,
666                                           OvsChangeCallbackUnicastIpAddress,
667                                           NULL, TRUE,
668                                           &unicastIPNotificationHandle);
669     if (status != STATUS_SUCCESS) {
670         OVS_LOG_ERROR("Fail to regiter unicast ip change, status: %x.", status);
671     }
672 register_cleanup:
673     if (status != STATUS_SUCCESS) {
674         OvsCancelChangeNotification();
675     }
676
677     return status;
678 }
679
680
681 static POVS_IPNEIGH_ENTRY
682 OvsLookupIPNeighEntry(UINT32 ipAddr)
683 {
684     PLIST_ENTRY link;
685     POVS_IPNEIGH_ENTRY entry;
686     UINT32 hash = OvsJhashWords(&ipAddr, 1, OVS_HASH_BASIS);
687
688     LIST_FORALL(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK], link) {
689         entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, link);
690         if (entry->ipAddr == ipAddr) {
691             return entry;
692         }
693     }
694     return NULL;
695 }
696
697
698 static UINT32
699 OvsHashIPPrefix(PIP_ADDRESS_PREFIX prefix)
700 {
701     UINT64 words = (UINT64)prefix->Prefix.Ipv4.sin_addr.s_addr << 32 |
702                    (UINT32)prefix->PrefixLength;
703     return OvsJhashWords((UINT32 *)&words, 2, OVS_HASH_BASIS);
704 }
705
706
707 static POVS_IPFORWARD_ENTRY
708 OvsLookupIPForwardEntry(PIP_ADDRESS_PREFIX prefix)
709 {
710
711     PLIST_ENTRY link;
712     POVS_IPFORWARD_ENTRY ipfEntry;
713     UINT32 hash;
714     ASSERT(prefix->Prefix.si_family == AF_INET);
715
716     hash = RtlUlongByteSwap(prefix->Prefix.Ipv4.sin_addr.s_addr);
717
718     ASSERT(prefix->PrefixLength >= 32 ||
719            (hash & (((UINT32)1 <<  (32 - prefix->PrefixLength)) - 1)) == 0);
720
721     hash = OvsHashIPPrefix(prefix);
722     LIST_FORALL(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK], link) {
723         ipfEntry = CONTAINING_RECORD(link, OVS_IPFORWARD_ENTRY, link);
724         if (ipfEntry->prefix.PrefixLength == prefix->PrefixLength &&
725             ipfEntry->prefix.Prefix.Ipv4.sin_addr.s_addr ==
726             prefix->Prefix.Ipv4.sin_addr.s_addr) {
727             return ipfEntry;
728         }
729     }
730     return NULL;
731 }
732
733
734 static POVS_FWD_ENTRY
735 OvsLookupIPFwdEntry(UINT32 dstIp)
736 {
737     PLIST_ENTRY link;
738     POVS_FWD_ENTRY entry;
739     UINT32 hash = OvsJhashWords(&dstIp, 1, OVS_HASH_BASIS);
740
741     LIST_FORALL(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK], link) {
742         entry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
743         if (entry->info.dstIpAddr == dstIp) {
744             return entry;
745         }
746     }
747     return NULL;
748 }
749
750
751 NTSTATUS
752 OvsLookupIPFwdInfo(UINT32 dstIp,
753                    POVS_FWD_INFO info)
754 {
755     POVS_FWD_ENTRY entry;
756     LOCK_STATE_EX lockState;
757     NTSTATUS status = STATUS_NOT_FOUND;
758
759     NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
760     entry = OvsLookupIPFwdEntry(dstIp);
761     if (entry) {
762         info->value[0] = entry->info.value[0];
763         info->value[1] = entry->info.value[1];
764         info->value[2] = entry->info.value[2];
765         status = STATUS_SUCCESS;
766     }
767     NdisReleaseRWLock(ovsTableLock, &lockState);
768     return status;
769 }
770
771
772 static POVS_IPNEIGH_ENTRY
773 OvsCreateIPNeighEntry(PMIB_IPNET_ROW2 ipNeigh)
774 {
775
776     POVS_IPNEIGH_ENTRY entry;
777     UINT64 timeVal;
778
779     ASSERT(ipNeigh != NULL);
780     entry = (POVS_IPNEIGH_ENTRY)OvsAllocateMemoryWithTag(
781         sizeof(OVS_IPNEIGH_ENTRY), OVS_IPHELPER_POOL_TAG);
782     if (entry == NULL) {
783         return NULL;
784     }
785
786     RtlZeroMemory(entry, sizeof (OVS_IPNEIGH_ENTRY));
787     entry->ipAddr = ipNeigh->Address.Ipv4.sin_addr.s_addr;
788     KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
789     entry->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
790     RtlCopyMemory(entry->macAddr, ipNeigh->PhysicalAddress,
791                   ETH_ADDR_LEN);
792     InitializeListHead(&entry->fwdList);
793
794     return entry;
795 }
796
797
798 static POVS_IPFORWARD_ENTRY
799 OvsCreateIPForwardEntry(PMIB_IPFORWARD_ROW2 ipRoute)
800 {
801
802     POVS_IPFORWARD_ENTRY entry;
803
804     ASSERT(ipRoute);
805
806     entry = (POVS_IPFORWARD_ENTRY)OvsAllocateMemoryWithTag(
807         sizeof(OVS_IPFORWARD_ENTRY), OVS_IPHELPER_POOL_TAG);
808     if (entry == NULL) {
809         return NULL;
810     }
811
812     RtlZeroMemory(entry, sizeof (OVS_IPFORWARD_ENTRY));
813     RtlCopyMemory(&entry->prefix, &ipRoute->DestinationPrefix,
814                   sizeof (IP_ADDRESS_PREFIX));
815     entry->nextHop = ipRoute->NextHop.Ipv4.sin_addr.s_addr;
816     InitializeListHead(&entry->fwdList);
817
818     return entry;
819 }
820
821
822 static POVS_FWD_ENTRY
823 OvsCreateFwdEntry(POVS_FWD_INFO fwdInfo)
824 {
825     POVS_FWD_ENTRY entry;
826
827     entry = (POVS_FWD_ENTRY)OvsAllocateMemoryWithTag(
828         sizeof(OVS_FWD_ENTRY), OVS_IPHELPER_POOL_TAG);
829     if (entry == NULL) {
830         return NULL;
831     }
832
833     RtlZeroMemory(entry, sizeof (OVS_FWD_ENTRY));
834     RtlCopyMemory(&entry->info, fwdInfo, sizeof (OVS_FWD_INFO));
835     return entry;
836 }
837
838
839 static VOID
840 OvsRemoveFwdEntry(POVS_FWD_ENTRY fwdEntry)
841 {
842     POVS_IPFORWARD_ENTRY ipf;
843     POVS_IPNEIGH_ENTRY ipn;
844
845     ipf = fwdEntry->ipf;
846     ipn = fwdEntry->ipn;
847
848     RemoveEntryList(&fwdEntry->link);
849     ovsNumFwdEntries--;
850
851     RemoveEntryList(&fwdEntry->ipfLink);
852     ipf->refCount--;
853
854     RemoveEntryList(&fwdEntry->ipnLink);
855     ipn->refCount--;
856
857     if (ipf->refCount == 0) {
858         ASSERT(IsListEmpty(&ipf->fwdList));
859         RemoveEntryList(&ipf->link);
860         OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
861     }
862
863     if (ipn->refCount == 0) {
864         ASSERT(IsListEmpty(&ipn->fwdList));
865         RemoveEntryList(&ipn->link);
866         NdisAcquireSpinLock(&ovsIpHelperLock);
867         RemoveEntryList(&ipn->slink);
868         NdisReleaseSpinLock(&ovsIpHelperLock);
869         OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
870     }
871
872     OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
873 }
874
875
876 static VOID
877 OvsRemoveIPForwardEntry(POVS_IPFORWARD_ENTRY ipf)
878 {
879     POVS_FWD_ENTRY fwdEntry;
880     PLIST_ENTRY link, next;
881
882     ipf->refCount++;
883
884     LIST_FORALL_SAFE(&ipf->fwdList, link, next) {
885         fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
886         OvsRemoveFwdEntry(fwdEntry);
887     }
888     ASSERT(ipf->refCount == 1);
889
890     RemoveEntryList(&ipf->link);
891     OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
892 }
893
894
895 static VOID
896 OvsRemoveIPNeighEntry(POVS_IPNEIGH_ENTRY ipn)
897 {
898     PLIST_ENTRY link, next;
899     POVS_FWD_ENTRY fwdEntry;
900
901     ipn->refCount++;
902
903     LIST_FORALL_SAFE(&ipn->fwdList, link, next) {
904         fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
905         OvsRemoveFwdEntry(fwdEntry);
906     }
907
908     if (ipn->refCount == 1) {
909         RemoveEntryList(&ipn->link);
910         NdisAcquireSpinLock(&ovsIpHelperLock);
911         RemoveEntryList(&ipn->slink);
912         NdisReleaseSpinLock(&ovsIpHelperLock);
913         OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
914     }
915 }
916
917
918 static VOID
919 OvsAddToSortedNeighList(POVS_IPNEIGH_ENTRY ipn)
920 {
921     PLIST_ENTRY link;
922     POVS_IPNEIGH_ENTRY entry;
923
924     if (!IsListEmpty(&ovsSortedIPNeighList)) {
925         link = ovsSortedIPNeighList.Blink;
926         entry = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
927         if (entry->timeout > ipn->timeout) {
928             ipn->timeout++;
929         }
930     }
931     InsertTailList(&ovsSortedIPNeighList, &ipn->slink);
932 }
933
934
935 static VOID
936 OvsAddIPFwdCache(POVS_FWD_ENTRY fwdEntry,
937                  POVS_IPFORWARD_ENTRY ipf,
938                  POVS_IPNEIGH_ENTRY ipn)
939
940 {
941     UINT32 hash;
942
943     if (ipn->refCount == 0) {
944         NdisAcquireSpinLock(&ovsIpHelperLock);
945         OvsAddToSortedNeighList(ipn);
946         NdisReleaseSpinLock(&ovsIpHelperLock);
947         hash = OvsJhashWords(&ipn->ipAddr, 1, OVS_HASH_BASIS);
948         InsertHeadList(&ovsNeighHashTable[hash & OVS_NEIGH_HASH_TABLE_MASK],
949                        &ipn->link);
950     }
951     if (ipf->refCount == 0) {
952         hash = OvsHashIPPrefix(&ipf->prefix);
953         InsertHeadList(&ovsRouteHashTable[hash & OVS_ROUTE_HASH_TABLE_MASK],
954                        &ipf->link);
955     }
956
957     InsertHeadList(&ipf->fwdList, &fwdEntry->ipfLink);
958     ipf->refCount++;
959     fwdEntry->ipf = ipf;
960
961     InsertHeadList(&ipn->fwdList, &fwdEntry->ipnLink);
962     ipn->refCount++;
963     fwdEntry->ipn = ipn;
964
965     hash = OvsJhashWords(&fwdEntry->info.dstIpAddr, 1, OVS_HASH_BASIS);
966     InsertHeadList(&ovsFwdHashTable[hash & OVS_FWD_HASH_TABLE_MASK],
967                    &fwdEntry->link);
968     ovsNumFwdEntries++;
969 }
970
971
972 static VOID
973 OvsRemoveAllFwdEntriesWithSrc(UINT32 ipAddr)
974 {
975     UINT32 i;
976     POVS_FWD_ENTRY fwdEntry;
977     PLIST_ENTRY link, next;
978
979     for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
980         LIST_FORALL_SAFE(&ovsFwdHashTable[i], link, next) {
981             fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, link);
982             if (fwdEntry->info.srcIpAddr == ipAddr) {
983                 OvsRemoveFwdEntry(fwdEntry);
984             }
985         }
986     }
987 }
988
989
990 static VOID
991 OvsCleanupFwdTable(VOID)
992 {
993     PLIST_ENTRY link, next;
994     POVS_IPNEIGH_ENTRY ipn;
995     UINT32 i;
996     LOCK_STATE_EX lockState;
997
998     NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
999     if (ovsNumFwdEntries) {
1000        LIST_FORALL_SAFE(&ovsSortedIPNeighList, link, next) {
1001            ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1002            OvsRemoveIPNeighEntry(ipn);
1003        }
1004     }
1005     for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1006         ASSERT(IsListEmpty(&ovsFwdHashTable[i]));
1007     }
1008     for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1009         ASSERT(IsListEmpty(&ovsRouteHashTable[i]));
1010     }
1011     NdisReleaseRWLock(ovsTableLock, &lockState);
1012 }
1013
1014
1015 static VOID
1016 OvsCleanupIpHelperRequestList(VOID)
1017 {
1018     LIST_ENTRY list;
1019     PLIST_ENTRY next, link;
1020     POVS_IP_HELPER_REQUEST request;
1021
1022     NdisAcquireSpinLock(&ovsIpHelperLock);
1023     if (ovsNumIpHelperRequests == 0) {
1024        NdisReleaseSpinLock(&ovsIpHelperLock);
1025        return;
1026     }
1027
1028     InitializeListHead(&list);
1029     OvsAppendList(&list,  &ovsIpHelperRequestList);
1030     ovsNumIpHelperRequests = 0;
1031     NdisReleaseSpinLock(&ovsIpHelperLock);
1032
1033     LIST_FORALL_SAFE(&list, link, next) {
1034         request = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1035
1036         if (request->command == OVS_IP_HELPER_FWD_REQUEST &&
1037             request->fwdReq.cb) {
1038             request->fwdReq.cb(request->fwdReq.nbl,
1039                                request->fwdReq.inPort,
1040                                &request->fwdReq.tunnelKey,
1041                                request->fwdReq.cbData1,
1042                                request->fwdReq.cbData2,
1043                                STATUS_DEVICE_NOT_READY,
1044                                NULL);
1045         }
1046         OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1047     }
1048 }
1049
1050
1051
1052 static VOID
1053 OvsWakeupIPHelper(VOID)
1054 {
1055     KeSetEvent(&ovsIpHelperThreadContext.event, 0, FALSE);
1056 }
1057
1058 VOID
1059 OvsInternalAdapterDown(VOID)
1060 {
1061     NdisAcquireSpinLock(&ovsIpHelperLock);
1062     ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
1063     ovsInternalIPConfigured = FALSE;
1064     NdisReleaseSpinLock(&ovsIpHelperLock);
1065
1066     OvsCleanupIpHelperRequestList();
1067
1068     OvsCleanupFwdTable();
1069 }
1070
1071
1072 VOID
1073 OvsInternalAdapterUp(UINT32 portNo,
1074                      GUID *netCfgInstanceId)
1075 {
1076     POVS_IP_HELPER_REQUEST request;
1077
1078     RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
1079     RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
1080
1081     request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1082         sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1083     if (request == NULL) {
1084         OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1085         return;
1086     }
1087     RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
1088     request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
1089
1090     NdisAcquireSpinLock(&ovsIpHelperLock);
1091     ovsInternalPortNo = portNo;
1092     InsertHeadList(&ovsIpHelperRequestList, &request->link);
1093     ovsNumIpHelperRequests++;
1094     if (ovsNumIpHelperRequests == 1) {
1095         OvsWakeupIPHelper();
1096     }
1097     NdisReleaseSpinLock(&ovsIpHelperLock);
1098 }
1099
1100
1101 static VOID
1102 OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
1103 {
1104     NTSTATUS status;
1105     MIB_UNICASTIPADDRESS_ROW ipEntry;
1106     GUID *netCfgInstanceId = &ovsInternalNetCfgId;
1107
1108     OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1109
1110     status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
1111
1112     if (status != STATUS_SUCCESS) {
1113         OVS_LOG_ERROR("Fali to get IF entry for internal port with GUID"
1114                       "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1115                       netCfgInstanceId->Data1,
1116                       netCfgInstanceId->Data2,
1117                       netCfgInstanceId->Data3,
1118                       *(UINT16 *)netCfgInstanceId->Data4,
1119                       netCfgInstanceId->Data4[2],
1120                       netCfgInstanceId->Data4[3],
1121                       netCfgInstanceId->Data4[4],
1122                       netCfgInstanceId->Data4[5],
1123                       netCfgInstanceId->Data4[6],
1124                       netCfgInstanceId->Data4[7]);
1125         return;
1126     }
1127
1128     status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
1129                                     &ovsInternalIPRow);
1130
1131     if (status == STATUS_SUCCESS) {
1132         NdisAcquireSpinLock(&ovsIpHelperLock);
1133         ovsInternalIPConfigured = TRUE;
1134         NdisReleaseSpinLock(&ovsIpHelperLock);
1135     } else {
1136         return;
1137     }
1138
1139     status = OvsGetIPEntry(ovsInternalRow.InterfaceLuid, &ipEntry);
1140     if (status != STATUS_SUCCESS) {
1141         OVS_LOG_INFO("Fali to get IP entry for internal port with GUID"
1142                      "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1143                      netCfgInstanceId->Data1,
1144                      netCfgInstanceId->Data2,
1145                      netCfgInstanceId->Data3,
1146                      *(UINT16 *)netCfgInstanceId->Data4,
1147                      netCfgInstanceId->Data4[2],
1148                      netCfgInstanceId->Data4[3],
1149                      netCfgInstanceId->Data4[4],
1150                      netCfgInstanceId->Data4[5],
1151                      netCfgInstanceId->Data4[6],
1152                      netCfgInstanceId->Data4[7]);
1153     }
1154 }
1155
1156
1157 static NTSTATUS
1158 OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
1159 {
1160
1161     NdisAcquireSpinLock(&ovsIpHelperLock);
1162
1163     if (ovsInternalPortNo == OVS_DEFAULT_PORT_NO ||
1164         ovsInternalIPConfigured == FALSE) {
1165         NdisReleaseSpinLock(&ovsIpHelperLock);
1166         OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1167         return STATUS_NDIS_ADAPTER_NOT_READY;
1168     } else {
1169         InsertHeadList(&ovsIpHelperRequestList, &request->link);
1170         ovsNumIpHelperRequests++;
1171         if (ovsNumIpHelperRequests == 1) {
1172             OvsWakeupIPHelper();
1173         }
1174         NdisReleaseSpinLock(&ovsIpHelperLock);
1175         return STATUS_SUCCESS;
1176     }
1177 }
1178
1179
1180 NTSTATUS
1181 OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
1182                       UINT32 inPort,
1183                       const OvsIPv4TunnelKey *tunnelKey,
1184                       OvsIPHelperCallback cb,
1185                       PVOID cbData1,
1186                       PVOID cbData2)
1187 {
1188     POVS_IP_HELPER_REQUEST request;
1189
1190     request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1191         sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1192
1193     if (request == NULL) {
1194         return STATUS_INSUFFICIENT_RESOURCES;
1195     }
1196     request->command = OVS_IP_HELPER_FWD_REQUEST;
1197     request->fwdReq.nbl = nbl;
1198     request->fwdReq.inPort = inPort;
1199     RtlCopyMemory(&request->fwdReq.tunnelKey, tunnelKey,
1200                   sizeof (*tunnelKey));
1201     request->fwdReq.cb = cb;
1202     request->fwdReq.cbData1 = cbData1;
1203     request->fwdReq.cbData2 = cbData2;
1204
1205     return OvsEnqueueIpHelperRequest(request);
1206 }
1207
1208
1209 static VOID
1210 OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
1211 {
1212     SOCKADDR_INET dst, src;
1213     NTSTATUS status = STATUS_SUCCESS;
1214     MIB_IPFORWARD_ROW2 ipRoute;
1215     MIB_IPNET_ROW2 ipNeigh;
1216     OVS_FWD_INFO fwdInfo;
1217     UINT32 ipAddr;
1218     UINT32 srcAddr;
1219     POVS_FWD_ENTRY fwdEntry = NULL;
1220     POVS_IPFORWARD_ENTRY ipf = NULL;
1221     POVS_IPNEIGH_ENTRY ipn = NULL;
1222     LOCK_STATE_EX lockState;
1223     BOOLEAN  newIPF = FALSE;
1224     BOOLEAN  newIPN = FALSE;
1225     BOOLEAN  newFWD = FALSE;
1226
1227     status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.dst,
1228                                 &fwdInfo);
1229     if (status == STATUS_SUCCESS) {
1230         goto fwd_handle_nbl;
1231     }
1232
1233     /* find IPRoute */
1234     RtlZeroMemory(&dst, sizeof(dst));
1235     RtlZeroMemory(&src, sizeof(src));
1236     RtlZeroMemory(&ipRoute, sizeof (MIB_IPFORWARD_ROW2));
1237     dst.si_family = AF_INET;
1238     dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
1239
1240     status = OvsGetRoute(ovsInternalRow.InterfaceLuid, &dst, &ipRoute, &src);
1241     if (status != STATUS_SUCCESS) {
1242         goto fwd_handle_nbl;
1243     }
1244     srcAddr = src.Ipv4.sin_addr.s_addr;
1245
1246     /* find IPNeigh */
1247     ipAddr = ipRoute.NextHop.Ipv4.sin_addr.s_addr;
1248     if (ipAddr != 0) {
1249         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1250         ipn = OvsLookupIPNeighEntry(ipAddr);
1251         if (ipn) {
1252             goto fwd_request_done;
1253         }
1254         NdisReleaseRWLock(ovsTableLock, &lockState);
1255     }
1256     RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
1257     ipNeigh.InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
1258     if (ipAddr == 0) {
1259         ipAddr = request->fwdReq.tunnelKey.dst;
1260     }
1261     status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1262     if (status != STATUS_SUCCESS) {
1263         goto fwd_handle_nbl;
1264     }
1265
1266     NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1267
1268 fwd_request_done:
1269
1270     /*
1271      * Initialize ipf
1272      */
1273     ipf = OvsLookupIPForwardEntry(&ipRoute.DestinationPrefix);
1274     if (ipf == NULL) {
1275         ipf = OvsCreateIPForwardEntry(&ipRoute);
1276         if (ipf == NULL) {
1277             NdisReleaseRWLock(ovsTableLock, &lockState);
1278             status = STATUS_INSUFFICIENT_RESOURCES;
1279             goto fwd_handle_nbl;
1280         }
1281         newIPF = TRUE;
1282     } else {
1283         PLIST_ENTRY link;
1284         link = ipf->fwdList.Flink;
1285         fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
1286         srcAddr = fwdEntry->info.srcIpAddr;
1287     }
1288
1289     /*
1290      * initialize ipn
1291      */
1292     if (ipn == NULL) {
1293         ipn = OvsLookupIPNeighEntry(ipAddr);
1294         if (ipn == NULL) {
1295             ipn = OvsCreateIPNeighEntry(&ipNeigh);
1296             if (ipn == NULL) {
1297                 NdisReleaseRWLock(ovsTableLock, &lockState);
1298                 status = STATUS_INSUFFICIENT_RESOURCES;
1299                 goto fwd_handle_nbl;
1300             }
1301             newIPN = TRUE;
1302         }
1303     }
1304
1305     /*
1306      * initialize fwdEntry
1307      */
1308     fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
1309     fwdInfo.srcIpAddr = srcAddr;
1310     RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
1311     RtlCopyMemory(fwdInfo.srcMacAddr, ovsInternalRow.PhysicalAddress,
1312                   ETH_ADDR_LEN);
1313     fwdInfo.srcPortNo = request->fwdReq.inPort;
1314
1315     fwdEntry = OvsCreateFwdEntry(&fwdInfo);
1316     if (fwdEntry == NULL) {
1317         NdisReleaseRWLock(ovsTableLock, &lockState);
1318         status = STATUS_INSUFFICIENT_RESOURCES;
1319         goto fwd_handle_nbl;
1320     }
1321     newFWD = TRUE;
1322     /*
1323      * Cache the result
1324      */
1325     OvsAddIPFwdCache(fwdEntry, ipf, ipn);
1326     NdisReleaseRWLock(ovsTableLock, &lockState);
1327
1328 fwd_handle_nbl:
1329
1330     if (status != STATUS_SUCCESS) {
1331         if (newFWD) {
1332             ASSERT(fwdEntry != NULL);
1333             OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
1334         }
1335         if (newIPF) {
1336             ASSERT(ipf && ipf->refCount == 0);
1337             OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
1338         }
1339         if (newIPN) {
1340             ASSERT(ipn && ipn->refCount == 0);
1341             OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
1342         }
1343         ipAddr = request->fwdReq.tunnelKey.dst;
1344         OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
1345                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
1346                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
1347     }
1348     if (request->fwdReq.cb) {
1349         request->fwdReq.cb(request->fwdReq.nbl,
1350                            request->fwdReq.inPort,
1351                            &request->fwdReq.tunnelKey,
1352                            request->fwdReq.cbData1,
1353                            request->fwdReq.cbData2,
1354                            status,
1355                            status == STATUS_SUCCESS ? &fwdInfo : NULL);
1356     }
1357     OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1358 }
1359
1360
1361 static VOID
1362 OvsUpdateIPNeighEntry(UINT32 ipAddr,
1363                       PMIB_IPNET_ROW2 ipNeigh,
1364                       NTSTATUS status)
1365 {
1366     UINT64 timeVal;
1367     POVS_IPNEIGH_ENTRY ipn;
1368     LOCK_STATE_EX lockState;
1369     KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1370     /*
1371      * if mac changed, update all relevant fwdEntry
1372      */
1373     if (status != STATUS_SUCCESS) {
1374         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1375     } else {
1376         NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
1377     }
1378     ipn = OvsLookupIPNeighEntry(ipAddr);
1379     if (ipn == NULL) {
1380         NdisReleaseRWLock(ovsTableLock, &lockState);
1381         return;
1382     }
1383     if (status != STATUS_SUCCESS) {
1384         OvsRemoveIPNeighEntry(ipn);
1385         NdisReleaseRWLock(ovsTableLock, &lockState);
1386         return;
1387     }
1388
1389     if (memcmp((const PVOID)ipn->macAddr,
1390                (const PVOID)ipNeigh->PhysicalAddress,
1391                (size_t)ETH_ADDR_LEN)) {
1392         PLIST_ENTRY link;
1393         POVS_FWD_ENTRY fwdEntry;
1394         NdisReleaseRWLock(ovsTableLock, &lockState);
1395         /*
1396          * need update, release and acquire write lock
1397          * This is not the common case.
1398          */
1399
1400         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1401         ipn = OvsLookupIPNeighEntry(ipAddr);
1402
1403         if (ipn == NULL) {
1404             NdisReleaseRWLock(ovsTableLock, &lockState);
1405             return;
1406         }
1407
1408         LIST_FORALL(&ipn->fwdList, link) {
1409             fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1410             RtlCopyMemory(fwdEntry->info.dstMacAddr,
1411                           ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
1412         }
1413     }
1414     /*
1415      * update timeout and move to the end of
1416      * the sorted list
1417      */
1418
1419     NdisAcquireSpinLock(&ovsIpHelperLock);
1420     RemoveEntryList(&ipn->slink);
1421     ipn->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1422     OvsAddToSortedNeighList(ipn);
1423     NdisReleaseSpinLock(&ovsIpHelperLock);
1424     NdisReleaseRWLock(ovsTableLock, &lockState);
1425 }
1426
1427
1428 static VOID
1429 OvsHandleIPNeighTimeout(UINT32 ipAddr)
1430 {
1431     MIB_IPNET_ROW2 ipNeigh;
1432     NTSTATUS status;
1433
1434     status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1435
1436     OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
1437 }
1438
1439
1440 /*
1441  *----------------------------------------------------------------------------
1442  *  IP Helper system threash handle following request
1443  *    1. Intialize Internal port row when internal port is connected
1444  *    2. Handle FWD request
1445  *    3. Handle IP Neigh timeout
1446  *
1447  *    IP Interface, unicast address, and IP route change will be handled
1448  *    by the revelant callback.
1449  *----------------------------------------------------------------------------
1450  */
1451 VOID
1452 OvsStartIpHelper(PVOID data)
1453 {
1454     POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
1455     POVS_IP_HELPER_REQUEST req;
1456     POVS_IPNEIGH_ENTRY ipn;
1457     PLIST_ENTRY link;
1458     UINT64   timeVal, timeout;
1459
1460     OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
1461
1462     NdisAcquireSpinLock(&ovsIpHelperLock);
1463     while (!context->exit) {
1464
1465         timeout = 0;
1466         while (!IsListEmpty(&ovsIpHelperRequestList)) {
1467             if (context->exit) {
1468                 goto ip_helper_wait;
1469             }
1470             link = ovsIpHelperRequestList.Flink;
1471             RemoveEntryList(link);
1472             NdisReleaseSpinLock(&ovsIpHelperLock);
1473             req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1474             switch (req->command) {
1475             case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
1476                 OvsHandleInternalAdapterUp(req);
1477                 break;
1478             case OVS_IP_HELPER_FWD_REQUEST:
1479                 OvsHandleFwdRequest(req);
1480                 break;
1481             default:
1482                 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1483             }
1484             NdisAcquireSpinLock(&ovsIpHelperLock);
1485         }
1486
1487         /* for now, let us hold the lock here, if this cause any issue
1488          * we will change to use IpHelper lock only to protect
1489          * IPN
1490          */
1491         while (!IsListEmpty(&ovsSortedIPNeighList)) {
1492             UINT32 ipAddr;
1493             if (context->exit) {
1494                 goto ip_helper_wait;
1495             }
1496             link = ovsSortedIPNeighList.Flink;
1497             ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1498             KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1499             if (ipn->timeout > timeVal) {
1500                 timeout = ipn->timeout;
1501                 break;
1502             }
1503             ipAddr = ipn->ipAddr;
1504
1505             NdisReleaseSpinLock(&ovsIpHelperLock);
1506
1507             OvsHandleIPNeighTimeout(ipAddr);
1508
1509             NdisAcquireSpinLock(&ovsIpHelperLock);
1510         }
1511         if (!IsListEmpty(&ovsIpHelperRequestList)) {
1512             continue;
1513         }
1514
1515 ip_helper_wait:
1516         if (context->exit) {
1517             break;
1518         }
1519
1520         KeClearEvent(&context->event);
1521         NdisReleaseSpinLock(&ovsIpHelperLock);
1522
1523         KeWaitForSingleObject(&context->event, Executive, KernelMode,
1524                               FALSE, (LARGE_INTEGER *)&timeout);
1525         NdisAcquireSpinLock(&ovsIpHelperLock);
1526     }
1527     NdisReleaseSpinLock(&ovsIpHelperLock);
1528     OvsCleanupFwdTable();
1529     OvsCleanupIpHelperRequestList();
1530
1531     OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
1532
1533     PsTerminateSystemThread(STATUS_SUCCESS);
1534 }
1535
1536
1537 NTSTATUS
1538 OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
1539 {
1540     NTSTATUS status;
1541     HANDLE threadHandle;
1542     UINT32 i;
1543
1544     ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1545         sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1546
1547     ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1548         sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1549
1550     ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1551         sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1552
1553     RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
1554     RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
1555     ovsInternalIP = 0;
1556
1557     ovsInternalPortNo = OVS_DEFAULT_PORT_NO;
1558
1559     InitializeListHead(&ovsSortedIPNeighList);
1560
1561     ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
1562     NdisAllocateSpinLock(&ovsIpHelperLock);
1563
1564     InitializeListHead(&ovsIpHelperRequestList);
1565     ovsNumIpHelperRequests = 0;
1566     ipInterfaceNotificationHandle = NULL;
1567     ipRouteNotificationHandle = NULL;
1568     unicastIPNotificationHandle = NULL;
1569
1570     if (ovsFwdHashTable == NULL ||
1571         ovsRouteHashTable == NULL ||
1572         ovsNeighHashTable == NULL ||
1573         ovsTableLock == NULL) {
1574         status = STATUS_INSUFFICIENT_RESOURCES;
1575         goto init_cleanup;
1576     }
1577
1578     for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1579         InitializeListHead(&ovsFwdHashTable[i]);
1580     }
1581
1582     for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1583         InitializeListHead(&ovsRouteHashTable[i]);
1584     }
1585
1586     for (i = 0; i < OVS_NEIGH_HASH_TABLE_SIZE; i++) {
1587         InitializeListHead(&ovsNeighHashTable[i]);
1588     }
1589
1590
1591     KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
1592                       FALSE);
1593     status = OvsRegisterChangeNotification();
1594     ovsIpHelperThreadContext.exit = 0;
1595     if (status == STATUS_SUCCESS) {
1596         status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE,
1597                                       NULL, NULL, NULL, OvsStartIpHelper,
1598                                       &ovsIpHelperThreadContext);
1599         if (status != STATUS_SUCCESS) {
1600             goto init_cleanup;
1601         }
1602         ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL,
1603                                   KernelMode,
1604                                   &ovsIpHelperThreadContext.threadObject,
1605                                   NULL);
1606         ZwClose(threadHandle);
1607     }
1608
1609 init_cleanup:
1610
1611     if (status != STATUS_SUCCESS) {
1612         OvsCancelChangeNotification();
1613         if (ovsFwdHashTable) {
1614             OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1615             ovsFwdHashTable = NULL;
1616         }
1617         if (ovsRouteHashTable) {
1618             OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1619             ovsRouteHashTable = NULL;
1620         }
1621         if (ovsNeighHashTable) {
1622             OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1623             ovsNeighHashTable = NULL;
1624         }
1625         if (ovsTableLock) {
1626             NdisFreeRWLock(ovsTableLock);
1627             ovsTableLock = NULL;
1628         }
1629         NdisFreeSpinLock(&ovsIpHelperLock);
1630     }
1631     return STATUS_SUCCESS;
1632 }
1633
1634
1635 VOID
1636 OvsCleanupIpHelper(VOID)
1637 {
1638     OvsCancelChangeNotification();
1639
1640     NdisAcquireSpinLock(&ovsIpHelperLock);
1641     ovsIpHelperThreadContext.exit = 1;
1642     OvsWakeupIPHelper();
1643     NdisReleaseSpinLock(&ovsIpHelperLock);
1644
1645     KeWaitForSingleObject(ovsIpHelperThreadContext.threadObject, Executive,
1646                           KernelMode, FALSE, NULL);
1647     ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
1648
1649     OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1650     OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1651     OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1652
1653     NdisFreeRWLock(ovsTableLock);
1654     NdisFreeSpinLock(&ovsIpHelperLock);
1655 }
1656
1657 VOID
1658 OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
1659 {
1660     PLIST_ENTRY link, next;
1661     POVS_IP_HELPER_REQUEST req;
1662     LIST_ENTRY list;
1663     InitializeListHead(&list);
1664
1665     NdisAcquireSpinLock(&ovsIpHelperLock);
1666     LIST_FORALL_SAFE(&ovsIpHelperRequestList, link, next) {
1667         req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1668         if (req->command == OVS_IP_HELPER_FWD_REQUEST &&
1669             (nbl == NULL || req->fwdReq.nbl == nbl)) {
1670             RemoveEntryList(link);
1671             InsertHeadList(&list, link);
1672             if (nbl != NULL) {
1673                 break;
1674             }
1675         }
1676     }
1677     NdisReleaseSpinLock(&ovsIpHelperLock);
1678
1679     LIST_FORALL_SAFE(&list, link, next) {
1680         req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1681         if (req->fwdReq.cb) {
1682             req->fwdReq.cb(req->fwdReq.nbl, req->fwdReq.inPort,
1683                            &req->fwdReq.tunnelKey,
1684                            req->fwdReq.cbData1,
1685                            req->fwdReq.cbData2,
1686                            STATUS_DEVICE_NOT_READY,
1687                            NULL);
1688         }
1689         OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1690     }
1691 }