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