]> git.proxmox.com Git - mirror_ovs.git/blob - datapath-windows/ovsext/IpFragment.c
datapath-windows: Fix possible NULL dereference in IpFragment
[mirror_ovs.git] / datapath-windows / ovsext / IpFragment.c
1 /*
2 * Copyright (c) 2017 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 "Conntrack.h"
18 #include "Debug.h"
19 #include "IpFragment.h"
20 #include "Jhash.h"
21 #include "Offload.h"
22 #include "PacketParser.h"
23
24 #ifdef OVS_DBG_MOD
25 #undef OVS_DBG_MOD
26 #endif
27 #define OVS_DBG_MOD OVS_DBG_IPFRAG
28 /* Based on MIN_FRAGMENT_SIZE.*/
29 #define MAX_FRAGMENTS 164
30 #define MIN_FRAGMENT_SIZE 400
31 #define MAX_IPDATAGRAM_SIZE 65535
32
33 /* Function declarations */
34 static KSTART_ROUTINE OvsIpFragmentEntryCleaner;
35 static VOID OvsIpFragmentEntryDelete(POVS_IPFRAG_ENTRY entry, BOOLEAN checkExpiry);
36
37 /* Global and static variables */
38 static OVS_IPFRAG_THREAD_CTX ipFragThreadCtx;
39 static PNDIS_RW_LOCK_EX ovsIpFragmentHashLockObj;
40 static UINT64 ipTotalEntries;
41 static PLIST_ENTRY OvsIpFragTable;
42
43 NDIS_STATUS
44 OvsInitIpFragment(POVS_SWITCH_CONTEXT context)
45 {
46
47 NDIS_STATUS status;
48 HANDLE threadHandle = NULL;
49
50 /* Init the sync-lock */
51 ovsIpFragmentHashLockObj = NdisAllocateRWLock(context->NdisFilterHandle);
52 if (ovsIpFragmentHashLockObj == NULL) {
53 return STATUS_INSUFFICIENT_RESOURCES;
54 }
55
56 /* Init the Hash Buffer */
57 OvsIpFragTable = OvsAllocateMemoryWithTag(sizeof(LIST_ENTRY)
58 * IP_FRAG_HASH_TABLE_SIZE,
59 OVS_IPFRAG_POOL_TAG);
60 if (OvsIpFragTable == NULL) {
61 NdisFreeRWLock(ovsIpFragmentHashLockObj);
62 ovsIpFragmentHashLockObj = NULL;
63 return STATUS_INSUFFICIENT_RESOURCES;
64 }
65
66 for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE; i++) {
67 InitializeListHead(&OvsIpFragTable[i]);
68 }
69
70 /* Init Cleaner Thread */
71 KeInitializeEvent(&ipFragThreadCtx.event, NotificationEvent, FALSE);
72 status = PsCreateSystemThread(&threadHandle, SYNCHRONIZE, NULL, NULL,
73 NULL, OvsIpFragmentEntryCleaner,
74 &ipFragThreadCtx);
75
76 if (status != STATUS_SUCCESS) {
77 OvsFreeMemoryWithTag(OvsIpFragTable, OVS_IPFRAG_POOL_TAG);
78 OvsIpFragTable = NULL;
79 NdisFreeRWLock(ovsIpFragmentHashLockObj);
80 ovsIpFragmentHashLockObj = NULL;
81 return status;
82 }
83
84 ObReferenceObjectByHandle(threadHandle, SYNCHRONIZE, NULL, KernelMode,
85 &ipFragThreadCtx.threadObject, NULL);
86 ZwClose(threadHandle);
87 threadHandle = NULL;
88 return STATUS_SUCCESS;
89 }
90
91 static __inline UINT32
92 OvsGetIPFragmentHash(POVS_IPFRAG_KEY fragKey)
93 {
94 UINT32 arr[6];
95 arr[0] = (UINT32)fragKey->protocol;
96 arr[1] = (UINT32)fragKey->id;
97 arr[2] = (UINT32)fragKey->sAddr;
98 arr[3] = (UINT32)fragKey->dAddr;
99 arr[4] = (UINT32)((fragKey->tunnelId & 0xFFFFFFFF00000000LL) >> 32);
100 arr[5] = (UINT32)(fragKey->tunnelId & 0xFFFFFFFFLL);
101 return OvsJhashWords(arr, 6, OVS_HASH_BASIS);
102 }
103
104 static __inline POVS_IPFRAG_ENTRY
105 OvsLookupIPFrag(POVS_IPFRAG_KEY fragKey, UINT32 hash)
106 {
107 POVS_IPFRAG_ENTRY entry;
108 PLIST_ENTRY link;
109 LOCK_STATE_EX lockState;
110
111 NdisAcquireRWLockRead(ovsIpFragmentHashLockObj, &lockState, 0);
112 LIST_FORALL(&OvsIpFragTable[hash & IP_FRAG_HASH_TABLE_MASK], link) {
113 entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link);
114 NdisAcquireSpinLock(&(entry->lockObj));
115 if (entry->fragKey.dAddr == fragKey->dAddr &&
116 entry->fragKey.sAddr == fragKey->sAddr &&
117 entry->fragKey.id == fragKey->id &&
118 entry->fragKey.protocol == fragKey->protocol &&
119 entry->fragKey.tunnelId == fragKey->tunnelId) {
120 NdisReleaseSpinLock(&(entry->lockObj));
121 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState);
122 return entry;
123 }
124 NdisReleaseSpinLock(&(entry->lockObj));
125 }
126 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState);
127 return NULL;
128 }
129
130 /*
131 *----------------------------------------------------------------------------
132 * OvsIpv4Reassemble
133 * Reassemble the ipv4 fragments and return newNbl on success.
134 * Should be called after acquiring the lockObj for the entry.
135 *----------------------------------------------------------------------------
136 */
137 NDIS_STATUS
138 OvsIpv4Reassemble(POVS_SWITCH_CONTEXT switchContext,
139 PNET_BUFFER_LIST *curNbl,
140 OvsCompletionList *completionList,
141 NDIS_SWITCH_PORT_ID sourcePort,
142 POVS_IPFRAG_ENTRY entry,
143 PNET_BUFFER_LIST *newNbl)
144 {
145 NDIS_STATUS status = NDIS_STATUS_SUCCESS;
146 NDIS_STRING filterReason;
147 POVS_BUFFER_CONTEXT ctx;
148 PNET_BUFFER curNb;
149 EthHdr *eth;
150 IPHdr *ipHdr, *newIpHdr;
151 CHAR *ethBuf[sizeof(EthHdr)];
152 CHAR *packetBuf;
153 UINT16 ipHdrLen, packetHeader;
154 POVS_FRAGMENT_LIST head = NULL;
155 UINT32 packetLen;
156
157 curNb = NET_BUFFER_LIST_FIRST_NB(*curNbl);
158 ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
159
160 eth = (EthHdr*)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH,
161 (PVOID)&ethBuf, 1, 0);
162 if (eth == NULL) {
163 return NDIS_STATUS_INVALID_PACKET;
164 }
165 ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH);
166 if (ipHdr == NULL) {
167 return NDIS_STATUS_INVALID_PACKET;
168 }
169 ipHdrLen = ipHdr->ihl * 4;
170 if (ipHdrLen + entry->totalLen > MAX_IPDATAGRAM_SIZE) {
171 return NDIS_STATUS_INVALID_LENGTH;
172 }
173 packetLen = ETH_HEADER_LENGTH + ipHdrLen + entry->totalLen;
174 packetBuf = (CHAR*)OvsAllocateMemoryWithTag(packetLen,
175 OVS_IPFRAG_POOL_TAG);
176 if (packetBuf == NULL) {
177 OVS_LOG_ERROR("Insufficient resources, failed to allocate packetBuf");
178 return NDIS_STATUS_RESOURCES;
179 }
180
181 /* copy Ethernet header */
182 NdisMoveMemory(packetBuf, eth, ETH_HEADER_LENGTH);
183 /* copy ipv4 header to packet buff */
184 NdisMoveMemory(packetBuf + ETH_HEADER_LENGTH, ipHdr, ipHdrLen);
185
186 /* update new ip header */
187 newIpHdr = (IPHdr *)(packetBuf + ETH_HEADER_LENGTH);
188 newIpHdr->frag_off = 0;
189 newIpHdr->tot_len = htons(packetLen - ETH_HEADER_LENGTH);
190 newIpHdr->check = 0;
191 newIpHdr->check = IPChecksum((UINT8 *)packetBuf + ETH_HEADER_LENGTH,
192 ipHdrLen, 0);
193 packetHeader = ETH_HEADER_LENGTH + ipHdrLen;
194 head = entry->head;
195 while (head) {
196 if ((UINT32)(packetHeader + head->offset) > packetLen) {
197 status = NDIS_STATUS_INVALID_DATA;
198 goto cleanup;
199 }
200 NdisMoveMemory(packetBuf + packetHeader + head->offset,
201 head->pbuff, head->len);
202 head = head->next;
203 }
204 /* Create new nbl from the flat buffer */
205 *newNbl = OvsAllocateNBLFromBuffer(switchContext, packetBuf, packetLen);
206 if (*newNbl == NULL) {
207 OVS_LOG_ERROR("Insufficient resources, failed to allocate newNbl");
208 status = NDIS_STATUS_RESOURCES;
209 goto cleanup;
210 }
211
212 /* Complete the fragment NBL */
213 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(*curNbl);
214 if (ctx->flags & OVS_BUFFER_NEED_COMPLETE) {
215 RtlInitUnicodeString(&filterReason, L"Complete last fragment");
216 OvsAddPktCompletionList(completionList, TRUE, sourcePort, *curNbl, 1,
217 &filterReason);
218 } else {
219 OvsCompleteNBL(switchContext, *curNbl, TRUE);
220 }
221 /* Store mru in the ovs buffer context. */
222 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(*newNbl);
223 ctx->mru = entry->mru;
224 *curNbl = *newNbl;
225 cleanup:
226 OvsFreeMemoryWithTag(packetBuf, OVS_IPFRAG_POOL_TAG);
227 entry->markedForDelete = TRUE;
228 return status;
229 }
230 /*
231 *----------------------------------------------------------------------------
232 * OvsProcessIpv4Fragment
233 * Reassemble the fragments once all the fragments are recieved and
234 * return NDIS_STATUS_PENDING for the pending fragments
235 * XXX - Instead of copying NBls, Keep the NBLs in limbo state.
236 *----------------------------------------------------------------------------
237 */
238 NDIS_STATUS
239 OvsProcessIpv4Fragment(POVS_SWITCH_CONTEXT switchContext,
240 PNET_BUFFER_LIST *curNbl,
241 OvsCompletionList *completionList,
242 NDIS_SWITCH_PORT_ID sourcePort,
243 ovs_be64 tunnelId,
244 PNET_BUFFER_LIST *newNbl)
245 {
246 NDIS_STATUS status = NDIS_STATUS_PENDING;
247 PNET_BUFFER curNb;
248 CHAR *ethBuf[sizeof(EthHdr)];
249 UINT16 offset, flags;
250 UINT16 payloadLen, ipHdrLen;
251 UINT32 hash;
252 UINT64 currentTime;
253 EthHdr *eth;
254 IPHdr *ipHdr;
255 OVS_IPFRAG_KEY fragKey;
256 POVS_IPFRAG_ENTRY entry;
257 POVS_FRAGMENT_LIST fragStorage;
258 LOCK_STATE_EX htLockState;
259
260 curNb = NET_BUFFER_LIST_FIRST_NB(*curNbl);
261 ASSERT(NET_BUFFER_NEXT_NB(curNb) == NULL);
262
263 eth = (EthHdr*)NdisGetDataBuffer(curNb, ETH_HEADER_LENGTH,
264 (PVOID)&ethBuf, 1, 0);
265 if (eth == NULL) {
266 return NDIS_STATUS_INVALID_PACKET;
267 }
268
269 ipHdr = (IPHdr *)((PCHAR)eth + ETH_HEADER_LENGTH);
270 if (ipHdr == NULL) {
271 return NDIS_STATUS_INVALID_PACKET;
272 }
273 ipHdrLen = ipHdr->ihl * 4;
274 payloadLen = ntohs(ipHdr->tot_len) - ipHdrLen;
275 offset = ntohs(ipHdr->frag_off) & IP_OFFSET;
276 offset <<= 3;
277 flags = ntohs(ipHdr->frag_off) & IP_MF;
278 /* Only the last fragment can be of smaller size.*/
279 if (flags && ntohs(ipHdr->tot_len) < MIN_FRAGMENT_SIZE) {
280 return NDIS_STATUS_INVALID_LENGTH;
281 }
282 /*Copy fragment specific fields. */
283 fragKey.protocol = ipHdr->protocol;
284 fragKey.id = ipHdr->id;
285 fragKey.sAddr = ipHdr->saddr;
286 fragKey.dAddr = ipHdr->daddr;
287 fragKey.tunnelId = tunnelId;
288 /* Padding. */
289 NdisZeroMemory(&fragKey.pad_1, 3);
290 fragKey.pad_2 = 0;
291
292 fragStorage = (POVS_FRAGMENT_LIST )
293 OvsAllocateMemoryWithTag(sizeof(OVS_FRAGMENT_LIST),
294 OVS_IPFRAG_POOL_TAG);
295 if (fragStorage == NULL) {
296 OVS_LOG_ERROR("Insufficient resources, fail to allocate fragStorage");
297 return NDIS_STATUS_RESOURCES;
298 }
299
300 fragStorage->pbuff = (CHAR *)OvsAllocateMemoryWithTag(payloadLen,
301 OVS_IPFRAG_POOL_TAG);
302 if (fragStorage->pbuff == NULL) {
303 OVS_LOG_ERROR("Insufficient resources, fail to allocate pbuff");
304 OvsFreeMemoryWithTag(fragStorage, OVS_IPFRAG_POOL_TAG);
305 return NDIS_STATUS_RESOURCES;
306 }
307
308 /* Copy payload from nbl to fragment storage. */
309 if (OvsGetPacketBytes(*curNbl, payloadLen, ETH_HEADER_LENGTH + ipHdrLen,
310 fragStorage->pbuff) == NULL) {
311 status = NDIS_STATUS_RESOURCES;
312 goto payload_copy_error;
313 }
314 fragStorage->len = payloadLen;
315 fragStorage->offset = offset;
316 fragStorage->next = NULL;
317 hash = OvsGetIPFragmentHash(&fragKey);
318 entry = OvsLookupIPFrag(&fragKey, hash);
319 if (entry == NULL) {
320 entry = (POVS_IPFRAG_ENTRY)
321 OvsAllocateMemoryWithTag(sizeof(OVS_IPFRAG_ENTRY),
322 OVS_IPFRAG_POOL_TAG);
323 if (entry == NULL) {
324 status = NDIS_STATUS_RESOURCES;
325 goto payload_copy_error;
326 }
327 /* Copy the fragmeny key. */
328 NdisZeroMemory(entry, sizeof(OVS_IPFRAG_ENTRY));
329 NdisMoveMemory(&(entry->fragKey), &fragKey,
330 sizeof(OVS_IPFRAG_KEY));
331 /* Init MRU. */
332 entry->mru = ETH_HEADER_LENGTH + ipHdrLen + payloadLen;
333 entry->recvdLen += fragStorage->len;
334 entry->head = entry->tail = fragStorage;
335 entry->numFragments = 1;
336 if (!flags) {
337 entry->totalLen = offset + payloadLen;
338 }
339 NdisGetCurrentSystemTime((LARGE_INTEGER *)&currentTime);
340 entry->expiration = currentTime + IPFRAG_ENTRY_TIMEOUT;
341
342 /* Init the sync-lock. */
343 NdisAllocateSpinLock(&(entry->lockObj));
344 NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &htLockState, 0);
345 InsertHeadList(&OvsIpFragTable[hash & IP_FRAG_HASH_TABLE_MASK],
346 &entry->link);
347
348 ipTotalEntries++;
349 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &htLockState);
350 return NDIS_STATUS_PENDING;
351 } else {
352 /* Acquire the entry lock. */
353 NdisAcquireSpinLock(&(entry->lockObj));
354 NdisGetCurrentSystemTime((LARGE_INTEGER *)&currentTime);
355 if (currentTime > entry->expiration || entry->numFragments == MAX_FRAGMENTS) {
356 /* Mark the entry for delete. */
357 entry->markedForDelete = TRUE;
358 goto fragment_error;
359 }
360 POVS_FRAGMENT_LIST next = entry->head;
361 POVS_FRAGMENT_LIST prev = entry->tail;
362 if (prev != NULL && prev->offset < offset) {
363 next = NULL;
364 goto found;
365 }
366 prev = NULL;
367 for (next = entry->head; next != NULL; next = next->next) {
368 if (next->offset > fragStorage->offset) {
369 break;
370 }
371 prev = next;
372 }
373 found:
374 /*Check for overlap. */
375 if (prev) {
376 /* i bytes overlap. */
377 int i = (prev->offset + prev->len) - fragStorage->offset;
378 if (i > 0) {
379 goto fragment_error;
380 }
381 }
382 if (next) {
383 /* i bytes overlap. */
384 int i = (fragStorage->offset + fragStorage->len) - next->offset;
385 if (i > 0) {
386 goto fragment_error;
387 }
388 }
389
390 if (entry->recvdLen + fragStorage->len > entry->recvdLen) {
391 entry->recvdLen += fragStorage->len;
392 } else {
393 /* Overflow, ignore the fragment.*/
394 goto fragment_error;
395 }
396
397 /*Insert. */
398 if (prev) {
399 prev->next = fragStorage;
400 fragStorage->next = next;
401 } else {
402 fragStorage->next = next;
403 entry->head = fragStorage;
404 }
405 if (!next) {
406 entry->tail = fragStorage;
407 }
408
409 /*Update Maximum recieved Unit */
410 entry->mru = entry->mru > (ETH_HEADER_LENGTH + ipHdrLen + payloadLen) ?
411 entry->mru : (ETH_HEADER_LENGTH + ipHdrLen + payloadLen);
412 entry->numFragments++;
413 if (!flags) {
414 entry->totalLen = offset + payloadLen;
415 }
416 if (entry->recvdLen == entry->totalLen) {
417 status = OvsIpv4Reassemble(switchContext, curNbl, completionList,
418 sourcePort, entry, newNbl);
419 }
420 NdisReleaseSpinLock(&(entry->lockObj));
421 return status;
422 }
423 fragment_error:
424 status = NDIS_STATUS_INVALID_PACKET;
425 /* Release the entry lock. */
426 NdisReleaseSpinLock(&(entry->lockObj));
427 payload_copy_error:
428 OvsFreeMemoryWithTag(fragStorage->pbuff, OVS_IPFRAG_POOL_TAG);
429 OvsFreeMemoryWithTag(fragStorage, OVS_IPFRAG_POOL_TAG);
430 return status;
431 }
432
433
434 /*
435 *----------------------------------------------------------------------------
436 * OvsIpFragmentEntryCleaner
437 * Runs periodically and cleans up the Ip Fragment table
438 * Interval is selected as twice the entry timeout
439 *----------------------------------------------------------------------------
440 */
441 static VOID
442 OvsIpFragmentEntryCleaner(PVOID data)
443 {
444
445 POVS_IPFRAG_THREAD_CTX context = (POVS_IPFRAG_THREAD_CTX)data;
446 PLIST_ENTRY link, next;
447 POVS_IPFRAG_ENTRY entry;
448 LOCK_STATE_EX lockState;
449 BOOLEAN success = TRUE;
450
451 while (success) {
452 if (ovsIpFragmentHashLockObj == NULL) {
453 /* Lock has been freed by 'OvsCleanupIpFragment()' */
454 break;
455 }
456 NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &lockState, 0);
457 if (context->exit) {
458 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState);
459 break;
460 }
461
462 /* Set the timeout for the thread and cleanup. */
463 UINT64 currentTime, threadSleepTimeout;
464 NdisGetCurrentSystemTime((LARGE_INTEGER *)&currentTime);
465 threadSleepTimeout = currentTime + IPFRAG_CLEANUP_INTERVAL;
466 for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE && ipTotalEntries; i++) {
467 LIST_FORALL_SAFE(&OvsIpFragTable[i], link, next) {
468 entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link);
469 OvsIpFragmentEntryDelete(entry, TRUE);
470 }
471 }
472
473 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState);
474 KeWaitForSingleObject(&context->event, Executive, KernelMode,
475 FALSE, (LARGE_INTEGER *)&threadSleepTimeout);
476 }
477
478 PsTerminateSystemThread(STATUS_SUCCESS);
479 }
480
481 static VOID
482 OvsIpFragmentEntryDelete(POVS_IPFRAG_ENTRY entry, BOOLEAN checkExpiry)
483 {
484 NdisAcquireSpinLock(&(entry->lockObj));
485 if (!entry->markedForDelete && checkExpiry) {
486 UINT64 currentTime;
487 NdisGetCurrentSystemTime((LARGE_INTEGER *)&currentTime);
488 if (entry->expiration > currentTime) {
489 NdisReleaseSpinLock(&(entry->lockObj));
490 return;
491 }
492 }
493
494 POVS_FRAGMENT_LIST head = entry->head;
495 POVS_FRAGMENT_LIST temp = NULL;
496 while (head) {
497 temp = head;
498 head = head->next;
499 OvsFreeMemoryWithTag(temp->pbuff, OVS_IPFRAG_POOL_TAG);
500 OvsFreeMemoryWithTag(temp, OVS_IPFRAG_POOL_TAG);
501 }
502 RemoveEntryList(&entry->link);
503 ipTotalEntries--;
504 NdisReleaseSpinLock(&(entry->lockObj));
505 NdisFreeSpinLock(&(entry->lockObj));
506 OvsFreeMemoryWithTag(entry, OVS_IPFRAG_POOL_TAG);
507 }
508
509 VOID
510 OvsCleanupIpFragment(VOID)
511 {
512 PLIST_ENTRY link, next;
513 POVS_IPFRAG_ENTRY entry;
514 LOCK_STATE_EX lockState;
515
516 ipFragThreadCtx.exit = 1;
517 KeSetEvent(&ipFragThreadCtx.event, 0, FALSE);
518 KeWaitForSingleObject(ipFragThreadCtx.threadObject, Executive,
519 KernelMode, FALSE, NULL);
520 ObDereferenceObject(ipFragThreadCtx.threadObject);
521 NdisAcquireRWLockWrite(ovsIpFragmentHashLockObj, &lockState, 0);
522 if (OvsIpFragTable) {
523 for (int i = 0; i < IP_FRAG_HASH_TABLE_SIZE && ipTotalEntries; i++) {
524 LIST_FORALL_SAFE(&OvsIpFragTable[i], link, next) {
525 entry = CONTAINING_RECORD(link, OVS_IPFRAG_ENTRY, link);
526 OvsIpFragmentEntryDelete(entry, FALSE);
527 }
528 }
529 OvsFreeMemoryWithTag(OvsIpFragTable, OVS_IPFRAG_POOL_TAG);
530 OvsIpFragTable = NULL;
531 }
532 NdisReleaseRWLock(ovsIpFragmentHashLockObj, &lockState);
533 NdisFreeRWLock(ovsIpFragmentHashLockObj);
534 ovsIpFragmentHashLockObj = NULL;
535 }