netdev-dpdk: fix mbuf leaks
[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 BOOLEAN             ovsInternalAdapterUp;
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     ovsInternalAdapterUp = FALSE;
1063     ovsInternalIPConfigured = FALSE;
1064     NdisReleaseSpinLock(&ovsIpHelperLock);
1065
1066     OvsCleanupIpHelperRequestList();
1067
1068     OvsCleanupFwdTable();
1069 }
1070
1071
1072 VOID
1073 OvsInternalAdapterUp(GUID *netCfgInstanceId)
1074 {
1075     POVS_IP_HELPER_REQUEST request;
1076
1077     RtlCopyMemory(&ovsInternalNetCfgId, netCfgInstanceId, sizeof (GUID));
1078     RtlZeroMemory(&ovsInternalRow, sizeof (MIB_IF_ROW2));
1079
1080     request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1081         sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1082     if (request == NULL) {
1083         OVS_LOG_ERROR("Fail to initialize Internal Adapter");
1084         return;
1085     }
1086     RtlZeroMemory(request, sizeof (OVS_IP_HELPER_REQUEST));
1087     request->command = OVS_IP_HELPER_INTERNAL_ADAPTER_UP;
1088
1089     NdisAcquireSpinLock(&ovsIpHelperLock);
1090     ovsInternalAdapterUp = TRUE;
1091     InsertHeadList(&ovsIpHelperRequestList, &request->link);
1092     ovsNumIpHelperRequests++;
1093     if (ovsNumIpHelperRequests == 1) {
1094         OvsWakeupIPHelper();
1095     }
1096     NdisReleaseSpinLock(&ovsIpHelperLock);
1097 }
1098
1099
1100 static VOID
1101 OvsHandleInternalAdapterUp(POVS_IP_HELPER_REQUEST request)
1102 {
1103     NTSTATUS status;
1104     MIB_UNICASTIPADDRESS_ROW ipEntry;
1105     GUID *netCfgInstanceId = &ovsInternalNetCfgId;
1106
1107     OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1108
1109     status = OvsGetIfEntry(&ovsInternalNetCfgId, &ovsInternalRow);
1110
1111     if (status != STATUS_SUCCESS) {
1112         OVS_LOG_ERROR("Fali to get IF entry for internal port with GUID"
1113                       "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1114                       netCfgInstanceId->Data1,
1115                       netCfgInstanceId->Data2,
1116                       netCfgInstanceId->Data3,
1117                       *(UINT16 *)netCfgInstanceId->Data4,
1118                       netCfgInstanceId->Data4[2],
1119                       netCfgInstanceId->Data4[3],
1120                       netCfgInstanceId->Data4[4],
1121                       netCfgInstanceId->Data4[5],
1122                       netCfgInstanceId->Data4[6],
1123                       netCfgInstanceId->Data4[7]);
1124         return;
1125     }
1126
1127     status = OvsGetIPInterfaceEntry(ovsInternalRow.InterfaceLuid,
1128                                     &ovsInternalIPRow);
1129
1130     if (status == STATUS_SUCCESS) {
1131         NdisAcquireSpinLock(&ovsIpHelperLock);
1132         ovsInternalIPConfigured = TRUE;
1133         NdisReleaseSpinLock(&ovsIpHelperLock);
1134     } else {
1135         return;
1136     }
1137
1138     status = OvsGetIPEntry(ovsInternalRow.InterfaceLuid, &ipEntry);
1139     if (status != STATUS_SUCCESS) {
1140         OVS_LOG_INFO("Fali to get IP entry for internal port with GUID"
1141                      "  %08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
1142                      netCfgInstanceId->Data1,
1143                      netCfgInstanceId->Data2,
1144                      netCfgInstanceId->Data3,
1145                      *(UINT16 *)netCfgInstanceId->Data4,
1146                      netCfgInstanceId->Data4[2],
1147                      netCfgInstanceId->Data4[3],
1148                      netCfgInstanceId->Data4[4],
1149                      netCfgInstanceId->Data4[5],
1150                      netCfgInstanceId->Data4[6],
1151                      netCfgInstanceId->Data4[7]);
1152     }
1153 }
1154
1155
1156 static NTSTATUS
1157 OvsEnqueueIpHelperRequest(POVS_IP_HELPER_REQUEST request)
1158 {
1159
1160     NdisAcquireSpinLock(&ovsIpHelperLock);
1161
1162     if (ovsInternalAdapterUp == FALSE ||
1163         ovsInternalIPConfigured == FALSE) {
1164         NdisReleaseSpinLock(&ovsIpHelperLock);
1165         OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1166         return STATUS_NDIS_ADAPTER_NOT_READY;
1167     } else {
1168         InsertHeadList(&ovsIpHelperRequestList, &request->link);
1169         ovsNumIpHelperRequests++;
1170         if (ovsNumIpHelperRequests == 1) {
1171             OvsWakeupIPHelper();
1172         }
1173         NdisReleaseSpinLock(&ovsIpHelperLock);
1174         return STATUS_SUCCESS;
1175     }
1176 }
1177
1178
1179 NTSTATUS
1180 OvsFwdIPHelperRequest(PNET_BUFFER_LIST nbl,
1181                       UINT32 inPort,
1182                       const OvsIPv4TunnelKey *tunnelKey,
1183                       OvsIPHelperCallback cb,
1184                       PVOID cbData1,
1185                       PVOID cbData2)
1186 {
1187     POVS_IP_HELPER_REQUEST request;
1188
1189     request = (POVS_IP_HELPER_REQUEST)OvsAllocateMemoryWithTag(
1190         sizeof(OVS_IP_HELPER_REQUEST), OVS_IPHELPER_POOL_TAG);
1191
1192     if (request == NULL) {
1193         return STATUS_INSUFFICIENT_RESOURCES;
1194     }
1195     request->command = OVS_IP_HELPER_FWD_REQUEST;
1196     request->fwdReq.nbl = nbl;
1197     request->fwdReq.inPort = inPort;
1198     RtlCopyMemory(&request->fwdReq.tunnelKey, tunnelKey,
1199                   sizeof (*tunnelKey));
1200     request->fwdReq.cb = cb;
1201     request->fwdReq.cbData1 = cbData1;
1202     request->fwdReq.cbData2 = cbData2;
1203
1204     return OvsEnqueueIpHelperRequest(request);
1205 }
1206
1207
1208 static VOID
1209 OvsHandleFwdRequest(POVS_IP_HELPER_REQUEST request)
1210 {
1211     SOCKADDR_INET dst, src;
1212     NTSTATUS status = STATUS_SUCCESS;
1213     MIB_IPFORWARD_ROW2 ipRoute;
1214     MIB_IPNET_ROW2 ipNeigh;
1215     OVS_FWD_INFO fwdInfo;
1216     UINT32 ipAddr;
1217     UINT32 srcAddr;
1218     POVS_FWD_ENTRY fwdEntry = NULL;
1219     POVS_IPFORWARD_ENTRY ipf = NULL;
1220     POVS_IPNEIGH_ENTRY ipn = NULL;
1221     LOCK_STATE_EX lockState;
1222     BOOLEAN  newIPF = FALSE;
1223     BOOLEAN  newIPN = FALSE;
1224     BOOLEAN  newFWD = FALSE;
1225
1226     status = OvsLookupIPFwdInfo(request->fwdReq.tunnelKey.dst,
1227                                 &fwdInfo);
1228     if (status == STATUS_SUCCESS) {
1229         goto fwd_handle_nbl;
1230     }
1231
1232     /* find IPRoute */
1233     RtlZeroMemory(&dst, sizeof(dst));
1234     RtlZeroMemory(&src, sizeof(src));
1235     RtlZeroMemory(&ipRoute, sizeof (MIB_IPFORWARD_ROW2));
1236     dst.si_family = AF_INET;
1237     dst.Ipv4.sin_addr.s_addr = request->fwdReq.tunnelKey.dst;
1238
1239     status = OvsGetRoute(ovsInternalRow.InterfaceLuid, &dst, &ipRoute, &src);
1240     if (status != STATUS_SUCCESS) {
1241         goto fwd_handle_nbl;
1242     }
1243     srcAddr = src.Ipv4.sin_addr.s_addr;
1244
1245     /* find IPNeigh */
1246     ipAddr = ipRoute.NextHop.Ipv4.sin_addr.s_addr;
1247     if (ipAddr != 0) {
1248         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1249         ipn = OvsLookupIPNeighEntry(ipAddr);
1250         if (ipn) {
1251             goto fwd_request_done;
1252         }
1253         NdisReleaseRWLock(ovsTableLock, &lockState);
1254     }
1255     RtlZeroMemory(&ipNeigh, sizeof (ipNeigh));
1256     ipNeigh.InterfaceLuid.Value = ovsInternalRow.InterfaceLuid.Value;
1257     if (ipAddr == 0) {
1258         ipAddr = request->fwdReq.tunnelKey.dst;
1259     }
1260     status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1261     if (status != STATUS_SUCCESS) {
1262         goto fwd_handle_nbl;
1263     }
1264
1265     NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1266
1267 fwd_request_done:
1268
1269     /*
1270      * Initialize ipf
1271      */
1272     ipf = OvsLookupIPForwardEntry(&ipRoute.DestinationPrefix);
1273     if (ipf == NULL) {
1274         ipf = OvsCreateIPForwardEntry(&ipRoute);
1275         if (ipf == NULL) {
1276             NdisReleaseRWLock(ovsTableLock, &lockState);
1277             status = STATUS_INSUFFICIENT_RESOURCES;
1278             goto fwd_handle_nbl;
1279         }
1280         newIPF = TRUE;
1281     } else {
1282         PLIST_ENTRY link;
1283         link = ipf->fwdList.Flink;
1284         fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipfLink);
1285         srcAddr = fwdEntry->info.srcIpAddr;
1286     }
1287
1288     /*
1289      * initialize ipn
1290      */
1291     if (ipn == NULL) {
1292         ipn = OvsLookupIPNeighEntry(ipAddr);
1293         if (ipn == NULL) {
1294             ipn = OvsCreateIPNeighEntry(&ipNeigh);
1295             if (ipn == NULL) {
1296                 NdisReleaseRWLock(ovsTableLock, &lockState);
1297                 status = STATUS_INSUFFICIENT_RESOURCES;
1298                 goto fwd_handle_nbl;
1299             }
1300             newIPN = TRUE;
1301         }
1302     }
1303
1304     /*
1305      * initialize fwdEntry
1306      */
1307     fwdInfo.dstIpAddr = request->fwdReq.tunnelKey.dst;
1308     fwdInfo.srcIpAddr = srcAddr;
1309     RtlCopyMemory(fwdInfo.dstMacAddr, ipn->macAddr, ETH_ADDR_LEN);
1310     RtlCopyMemory(fwdInfo.srcMacAddr, ovsInternalRow.PhysicalAddress,
1311                   ETH_ADDR_LEN);
1312     fwdInfo.srcPortNo = request->fwdReq.inPort;
1313
1314     fwdEntry = OvsCreateFwdEntry(&fwdInfo);
1315     if (fwdEntry == NULL) {
1316         NdisReleaseRWLock(ovsTableLock, &lockState);
1317         status = STATUS_INSUFFICIENT_RESOURCES;
1318         goto fwd_handle_nbl;
1319     }
1320     newFWD = TRUE;
1321     /*
1322      * Cache the result
1323      */
1324     OvsAddIPFwdCache(fwdEntry, ipf, ipn);
1325     NdisReleaseRWLock(ovsTableLock, &lockState);
1326
1327 fwd_handle_nbl:
1328
1329     if (status != STATUS_SUCCESS) {
1330         if (newFWD) {
1331             ASSERT(fwdEntry != NULL);
1332             OvsFreeMemoryWithTag(fwdEntry, OVS_IPHELPER_POOL_TAG);
1333         }
1334         if (newIPF) {
1335             ASSERT(ipf && ipf->refCount == 0);
1336             OvsFreeMemoryWithTag(ipf, OVS_IPHELPER_POOL_TAG);
1337         }
1338         if (newIPN) {
1339             ASSERT(ipn && ipn->refCount == 0);
1340             OvsFreeMemoryWithTag(ipn, OVS_IPHELPER_POOL_TAG);
1341         }
1342         ipAddr = request->fwdReq.tunnelKey.dst;
1343         OVS_LOG_INFO("Fail to handle IP helper request for dst: %d.%d.%d.%d",
1344                      ipAddr & 0xff, (ipAddr >> 8) & 0xff,
1345                      (ipAddr >> 16) & 0xff, (ipAddr >> 24) & 0xff);
1346     }
1347     if (request->fwdReq.cb) {
1348         request->fwdReq.cb(request->fwdReq.nbl,
1349                            request->fwdReq.inPort,
1350                            &request->fwdReq.tunnelKey,
1351                            request->fwdReq.cbData1,
1352                            request->fwdReq.cbData2,
1353                            status,
1354                            status == STATUS_SUCCESS ? &fwdInfo : NULL);
1355     }
1356     OvsFreeMemoryWithTag(request, OVS_IPHELPER_POOL_TAG);
1357 }
1358
1359
1360 static VOID
1361 OvsUpdateIPNeighEntry(UINT32 ipAddr,
1362                       PMIB_IPNET_ROW2 ipNeigh,
1363                       NTSTATUS status)
1364 {
1365     UINT64 timeVal;
1366     POVS_IPNEIGH_ENTRY ipn;
1367     LOCK_STATE_EX lockState;
1368     KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1369     /*
1370      * if mac changed, update all relevant fwdEntry
1371      */
1372     if (status != STATUS_SUCCESS) {
1373         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1374     } else {
1375         NdisAcquireRWLockRead(ovsTableLock, &lockState, 0);
1376     }
1377     ipn = OvsLookupIPNeighEntry(ipAddr);
1378     if (ipn == NULL) {
1379         NdisReleaseRWLock(ovsTableLock, &lockState);
1380         return;
1381     }
1382     if (status != STATUS_SUCCESS) {
1383         OvsRemoveIPNeighEntry(ipn);
1384         NdisReleaseRWLock(ovsTableLock, &lockState);
1385         return;
1386     }
1387
1388     if (memcmp((const PVOID)ipn->macAddr,
1389                (const PVOID)ipNeigh->PhysicalAddress,
1390                (size_t)ETH_ADDR_LEN)) {
1391         PLIST_ENTRY link;
1392         POVS_FWD_ENTRY fwdEntry;
1393         NdisReleaseRWLock(ovsTableLock, &lockState);
1394         /*
1395          * need update, release and acquire write lock
1396          * This is not the common case.
1397          */
1398
1399         NdisAcquireRWLockWrite(ovsTableLock, &lockState, 0);
1400         ipn = OvsLookupIPNeighEntry(ipAddr);
1401
1402         if (ipn == NULL) {
1403             NdisReleaseRWLock(ovsTableLock, &lockState);
1404             return;
1405         }
1406
1407         LIST_FORALL(&ipn->fwdList, link) {
1408             fwdEntry = CONTAINING_RECORD(link, OVS_FWD_ENTRY, ipnLink);
1409             RtlCopyMemory(fwdEntry->info.dstMacAddr,
1410                           ipNeigh->PhysicalAddress, ETH_ADDR_LEN);
1411         }
1412     }
1413     /*
1414      * update timeout and move to the end of
1415      * the sorted list
1416      */
1417
1418     NdisAcquireSpinLock(&ovsIpHelperLock);
1419     RemoveEntryList(&ipn->slink);
1420     ipn->timeout = timeVal + OVS_IPNEIGH_TIMEOUT;
1421     OvsAddToSortedNeighList(ipn);
1422     NdisReleaseSpinLock(&ovsIpHelperLock);
1423     NdisReleaseRWLock(ovsTableLock, &lockState);
1424 }
1425
1426
1427 static VOID
1428 OvsHandleIPNeighTimeout(UINT32 ipAddr)
1429 {
1430     MIB_IPNET_ROW2 ipNeigh;
1431     NTSTATUS status;
1432
1433     status = OvsGetOrResolveIPNeigh(ipAddr, &ipNeigh);
1434
1435     OvsUpdateIPNeighEntry(ipAddr, &ipNeigh, status);
1436 }
1437
1438
1439 /*
1440  *----------------------------------------------------------------------------
1441  *  IP Helper system threash handle following request
1442  *    1. Intialize Internal port row when internal port is connected
1443  *    2. Handle FWD request
1444  *    3. Handle IP Neigh timeout
1445  *
1446  *    IP Interface, unicast address, and IP route change will be handled
1447  *    by the revelant callback.
1448  *----------------------------------------------------------------------------
1449  */
1450 VOID
1451 OvsStartIpHelper(PVOID data)
1452 {
1453     POVS_IP_HELPER_THREAD_CONTEXT context = (POVS_IP_HELPER_THREAD_CONTEXT)data;
1454     POVS_IP_HELPER_REQUEST req;
1455     POVS_IPNEIGH_ENTRY ipn;
1456     PLIST_ENTRY link;
1457     UINT64   timeVal, timeout;
1458
1459     OVS_LOG_INFO("Start the IP Helper Thread, context: %p", context);
1460
1461     NdisAcquireSpinLock(&ovsIpHelperLock);
1462     while (!context->exit) {
1463
1464         timeout = 0;
1465         while (!IsListEmpty(&ovsIpHelperRequestList)) {
1466             if (context->exit) {
1467                 goto ip_helper_wait;
1468             }
1469             link = ovsIpHelperRequestList.Flink;
1470             RemoveEntryList(link);
1471             NdisReleaseSpinLock(&ovsIpHelperLock);
1472             req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1473             switch (req->command) {
1474             case OVS_IP_HELPER_INTERNAL_ADAPTER_UP:
1475                 OvsHandleInternalAdapterUp(req);
1476                 break;
1477             case OVS_IP_HELPER_FWD_REQUEST:
1478                 OvsHandleFwdRequest(req);
1479                 break;
1480             default:
1481                 OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1482             }
1483             NdisAcquireSpinLock(&ovsIpHelperLock);
1484         }
1485
1486         /* for now, let us hold the lock here, if this cause any issue
1487          * we will change to use IpHelper lock only to protect
1488          * IPN
1489          */
1490         while (!IsListEmpty(&ovsSortedIPNeighList)) {
1491             UINT32 ipAddr;
1492             if (context->exit) {
1493                 goto ip_helper_wait;
1494             }
1495             link = ovsSortedIPNeighList.Flink;
1496             ipn = CONTAINING_RECORD(link, OVS_IPNEIGH_ENTRY, slink);
1497             KeQuerySystemTime((LARGE_INTEGER *)&timeVal);
1498             if (ipn->timeout > timeVal) {
1499                 timeout = ipn->timeout;
1500                 break;
1501             }
1502             ipAddr = ipn->ipAddr;
1503
1504             NdisReleaseSpinLock(&ovsIpHelperLock);
1505
1506             OvsHandleIPNeighTimeout(ipAddr);
1507
1508             NdisAcquireSpinLock(&ovsIpHelperLock);
1509         }
1510         if (!IsListEmpty(&ovsIpHelperRequestList)) {
1511             continue;
1512         }
1513
1514 ip_helper_wait:
1515         if (context->exit) {
1516             break;
1517         }
1518
1519         KeClearEvent(&context->event);
1520         NdisReleaseSpinLock(&ovsIpHelperLock);
1521
1522         KeWaitForSingleObject(&context->event, Executive, KernelMode,
1523                               FALSE, (LARGE_INTEGER *)&timeout);
1524         NdisAcquireSpinLock(&ovsIpHelperLock);
1525     }
1526     NdisReleaseSpinLock(&ovsIpHelperLock);
1527     OvsCleanupFwdTable();
1528     OvsCleanupIpHelperRequestList();
1529
1530     OVS_LOG_INFO("Terminating the OVS IP Helper system thread");
1531
1532     PsTerminateSystemThread(STATUS_SUCCESS);
1533 }
1534
1535
1536 NTSTATUS
1537 OvsInitIpHelper(NDIS_HANDLE ndisFilterHandle)
1538 {
1539     NTSTATUS status;
1540     HANDLE threadHandle;
1541     UINT32 i;
1542
1543     ovsFwdHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1544         sizeof(LIST_ENTRY) * OVS_FWD_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1545
1546     ovsRouteHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1547         sizeof(LIST_ENTRY) * OVS_ROUTE_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1548
1549     ovsNeighHashTable = (PLIST_ENTRY)OvsAllocateMemoryWithTag(
1550         sizeof(LIST_ENTRY) * OVS_NEIGH_HASH_TABLE_SIZE, OVS_IPHELPER_POOL_TAG);
1551
1552     RtlZeroMemory(&ovsInternalRow, sizeof(MIB_IF_ROW2));
1553     RtlZeroMemory(&ovsInternalIPRow, sizeof (MIB_IPINTERFACE_ROW));
1554     ovsInternalIP = 0;
1555
1556     ovsInternalAdapterUp = FALSE;
1557
1558     InitializeListHead(&ovsSortedIPNeighList);
1559
1560     ovsTableLock = NdisAllocateRWLock(ndisFilterHandle);
1561     NdisAllocateSpinLock(&ovsIpHelperLock);
1562
1563     InitializeListHead(&ovsIpHelperRequestList);
1564     ovsNumIpHelperRequests = 0;
1565     ipInterfaceNotificationHandle = NULL;
1566     ipRouteNotificationHandle = NULL;
1567     unicastIPNotificationHandle = NULL;
1568
1569     if (ovsFwdHashTable == NULL ||
1570         ovsRouteHashTable == NULL ||
1571         ovsNeighHashTable == NULL ||
1572         ovsTableLock == NULL) {
1573         status = STATUS_INSUFFICIENT_RESOURCES;
1574         goto init_cleanup;
1575     }
1576
1577     for (i = 0; i < OVS_FWD_HASH_TABLE_SIZE; i++) {
1578         InitializeListHead(&ovsFwdHashTable[i]);
1579     }
1580
1581     for (i = 0; i < OVS_ROUTE_HASH_TABLE_SIZE; i++) {
1582         InitializeListHead(&ovsRouteHashTable[i]);
1583     }
1584
1585     for (i = 0; i < OVS_NEIGH_HASH_TABLE_SIZE; i++) {
1586         InitializeListHead(&ovsNeighHashTable[i]);
1587     }
1588
1589
1590     KeInitializeEvent(&ovsIpHelperThreadContext.event, NotificationEvent,
1591                       FALSE);
1592     status = OvsRegisterChangeNotification();
1593     ovsIpHelperThreadContext.exit = 0;
1594     if (status == STATUS_SUCCESS) {
1595         status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE,
1596                                       NULL, NULL, NULL, OvsStartIpHelper,
1597                                       &ovsIpHelperThreadContext);
1598         if (status != STATUS_SUCCESS) {
1599             goto init_cleanup;
1600         }
1601         ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL,
1602                                   KernelMode,
1603                                   &ovsIpHelperThreadContext.threadObject,
1604                                   NULL);
1605         ZwClose(threadHandle);
1606     }
1607
1608 init_cleanup:
1609
1610     if (status != STATUS_SUCCESS) {
1611         OvsCancelChangeNotification();
1612         if (ovsFwdHashTable) {
1613             OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1614             ovsFwdHashTable = NULL;
1615         }
1616         if (ovsRouteHashTable) {
1617             OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1618             ovsRouteHashTable = NULL;
1619         }
1620         if (ovsNeighHashTable) {
1621             OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1622             ovsNeighHashTable = NULL;
1623         }
1624         if (ovsTableLock) {
1625             NdisFreeRWLock(ovsTableLock);
1626             ovsTableLock = NULL;
1627         }
1628         NdisFreeSpinLock(&ovsIpHelperLock);
1629     }
1630     return STATUS_SUCCESS;
1631 }
1632
1633
1634 VOID
1635 OvsCleanupIpHelper(VOID)
1636 {
1637     OvsCancelChangeNotification();
1638
1639     NdisAcquireSpinLock(&ovsIpHelperLock);
1640     ovsIpHelperThreadContext.exit = 1;
1641     OvsWakeupIPHelper();
1642     NdisReleaseSpinLock(&ovsIpHelperLock);
1643
1644     KeWaitForSingleObject(ovsIpHelperThreadContext.threadObject, Executive,
1645                           KernelMode, FALSE, NULL);
1646     ObDereferenceObject(ovsIpHelperThreadContext.threadObject);
1647
1648     OvsFreeMemoryWithTag(ovsFwdHashTable, OVS_IPHELPER_POOL_TAG);
1649     OvsFreeMemoryWithTag(ovsRouteHashTable, OVS_IPHELPER_POOL_TAG);
1650     OvsFreeMemoryWithTag(ovsNeighHashTable, OVS_IPHELPER_POOL_TAG);
1651
1652     NdisFreeRWLock(ovsTableLock);
1653     NdisFreeSpinLock(&ovsIpHelperLock);
1654 }
1655
1656 VOID
1657 OvsCancelFwdIpHelperRequest(PNET_BUFFER_LIST nbl)
1658 {
1659     PLIST_ENTRY link, next;
1660     POVS_IP_HELPER_REQUEST req;
1661     LIST_ENTRY list;
1662     InitializeListHead(&list);
1663
1664     NdisAcquireSpinLock(&ovsIpHelperLock);
1665     LIST_FORALL_SAFE(&ovsIpHelperRequestList, link, next) {
1666         req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1667         if (req->command == OVS_IP_HELPER_FWD_REQUEST &&
1668             (nbl == NULL || req->fwdReq.nbl == nbl)) {
1669             RemoveEntryList(link);
1670             InsertHeadList(&list, link);
1671             if (nbl != NULL) {
1672                 break;
1673             }
1674         }
1675     }
1676     NdisReleaseSpinLock(&ovsIpHelperLock);
1677
1678     LIST_FORALL_SAFE(&list, link, next) {
1679         req = CONTAINING_RECORD(link, OVS_IP_HELPER_REQUEST, link);
1680         if (req->fwdReq.cb) {
1681             req->fwdReq.cb(req->fwdReq.nbl, req->fwdReq.inPort,
1682                            &req->fwdReq.tunnelKey,
1683                            req->fwdReq.cbData1,
1684                            req->fwdReq.cbData2,
1685                            STATUS_DEVICE_NOT_READY,
1686                            NULL);
1687         }
1688         OvsFreeMemoryWithTag(req, OVS_IPHELPER_POOL_TAG);
1689     }
1690 }