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