2 * Copyright (c) 2014, 2016 VMware, Inc.
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:
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * Manage packet queue for packet miss for userAction.
35 #include "TunnelIntf.h"
42 #define OVS_DBG_MOD OVS_DBG_USER
44 POVS_PACKET_QUEUE_ELEM
OvsGetNextPacket(POVS_OPEN_INSTANCE instance
);
45 extern PNDIS_SPIN_LOCK gOvsCtrlLock
;
46 extern POVS_SWITCH_CONTEXT gOvsSwitchContext
;
47 OVS_USER_STATS ovsUserStats
;
49 static VOID
_MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr
, PNL_ATTR
*nlAttrs
,
51 OvsPacketExecute
*execute
);
52 extern NL_POLICY nlFlowKeyPolicy
[];
53 extern UINT32 nlFlowKeyPolicyLen
;
54 extern NL_POLICY nlFlowTunnelKeyPolicy
[];
55 extern UINT32 nlFlowTunnelKeyPolicyLen
;
56 DRIVER_CANCEL OvsCancelIrpDatapath
;
58 _IRQL_raises_(DISPATCH_LEVEL
)
59 _IRQL_saves_global_(OldIrql
, gOvsSwitchContext
->pidHashLock
)
60 _Acquires_lock_(gOvsSwitchContext
->pidHashLock
)
62 OvsAcquirePidHashLock()
64 NdisAcquireSpinLock(&(gOvsSwitchContext
->pidHashLock
));
67 _IRQL_requires_(DISPATCH_LEVEL
)
68 _IRQL_restores_global_(OldIrql
, gOvsSwitchContext
->pidHashLock
)
69 _Requires_lock_held_(gOvsSwitchContext
->pidHashLock
)
70 _Releases_lock_(gOvsSwitchContext
->pidHashLock
)
72 OvsReleasePidHashLock()
74 NdisReleaseSpinLock(&(gOvsSwitchContext
->pidHashLock
));
79 OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue
,
80 POVS_OPEN_INSTANCE instance
)
82 PLIST_ENTRY link
, next
;
84 POVS_PACKET_QUEUE_ELEM elem
;
86 InitializeListHead(&tmp
);
87 NdisAcquireSpinLock(&queue
->queueLock
);
88 if (queue
->instance
!= instance
) {
89 NdisReleaseSpinLock(&queue
->queueLock
);
93 if (queue
->numPackets
) {
94 OvsAppendList(&tmp
, &queue
->packetList
);
95 queue
->numPackets
= 0;
97 NdisReleaseSpinLock(&queue
->queueLock
);
98 LIST_FORALL_SAFE(&tmp
, link
, next
) {
99 RemoveEntryList(link
);
100 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
101 OvsFreeMemoryWithTag(elem
, OVS_USER_POOL_TAG
);
106 OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance
)
108 POVS_USER_PACKET_QUEUE queue
;
109 POVS_PACKET_QUEUE_ELEM elem
;
110 PLIST_ENTRY link
, next
;
115 InitializeListHead(&tmp
);
116 queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
118 PDRIVER_CANCEL cancelRoutine
;
119 NdisAcquireSpinLock(&queue
->queueLock
);
120 ASSERT(queue
->instance
== instance
);
121 /* XXX Should not happen */
122 if (queue
->instance
!= instance
) {
123 NdisReleaseSpinLock(&queue
->queueLock
);
124 NdisFreeSpinLock(&queue
->queueLock
);
128 if (queue
->numPackets
) {
129 OvsAppendList(&tmp
, &queue
->packetList
);
130 queue
->numPackets
= 0;
132 queue
->instance
= NULL
;
133 instance
->packetQueue
= NULL
;
134 irp
= queue
->pendingIrp
;
135 queue
->pendingIrp
= NULL
;
137 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
138 if (cancelRoutine
== NULL
) {
142 NdisReleaseSpinLock(&queue
->queueLock
);
143 NdisFreeSpinLock(&queue
->queueLock
);
145 LIST_FORALL_SAFE(&tmp
, link
, next
) {
146 RemoveEntryList(link
);
147 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
148 OvsFreeMemoryWithTag(elem
, OVS_USER_POOL_TAG
);
151 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
154 OvsFreeMemoryWithTag(queue
, OVS_USER_POOL_TAG
);
157 /* Verify if gOvsSwitchContext exists. */
158 if (gOvsSwitchContext
) {
159 /* Remove the instance from pidHashArray */
160 OvsAcquirePidHashLock();
161 OvsDelPidInstance(gOvsSwitchContext
, instance
->pid
);
162 OvsReleasePidHashLock();
167 OvsSubscribeDpIoctl(PVOID instanceP
,
171 POVS_USER_PACKET_QUEUE queue
;
172 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)instanceP
;
174 if (instance
->packetQueue
&& !join
) {
176 OvsCleanupPacketQueue(instance
);
177 } else if (instance
->packetQueue
== NULL
&& join
) {
178 queue
= (POVS_USER_PACKET_QUEUE
) OvsAllocateMemoryWithTag(
179 sizeof *queue
, OVS_USER_POOL_TAG
);
181 return STATUS_NO_MEMORY
;
183 InitializeListHead(&(instance
->pidLink
));
184 instance
->packetQueue
= queue
;
185 RtlZeroMemory(queue
, sizeof (*queue
));
186 NdisAllocateSpinLock(&queue
->queueLock
);
187 NdisAcquireSpinLock(&queue
->queueLock
);
188 InitializeListHead(&queue
->packetList
);
190 queue
->instance
= instance
;
191 instance
->packetQueue
= queue
;
192 NdisReleaseSpinLock(&queue
->queueLock
);
194 OvsAcquirePidHashLock();
195 /* Insert the instance to pidHashArray */
196 OvsAddPidInstance(gOvsSwitchContext
, pid
, instance
);
197 OvsReleasePidHashLock();
200 /* user mode should call only once for subscribe */
201 return STATUS_INVALID_PARAMETER
;
204 return STATUS_SUCCESS
;
209 OvsReadDpIoctl(PFILE_OBJECT fileObject
,
214 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
215 POVS_PACKET_QUEUE_ELEM elem
;
218 #define TCP_CSUM_OFFSET 16
219 #define UDP_CSUM_OFFSET 6
222 if (instance
->packetQueue
== NULL
) {
223 return STATUS_INVALID_PARAMETER
;
225 if (outputLength
< (sizeof (OVS_PACKET_INFO
) + OVS_MIN_PACKET_SIZE
)) {
226 return STATUS_BUFFER_TOO_SMALL
;
229 elem
= OvsGetNextPacket(instance
);
232 * XXX revisit this later
234 len
= elem
->packet
.totalLen
> outputLength
? outputLength
:
235 elem
->packet
.totalLen
;
237 if ((elem
->hdrInfo
.tcpCsumNeeded
|| elem
->hdrInfo
.udpCsumNeeded
) &&
238 len
== elem
->packet
.totalLen
) {
240 UINT16 size
= (UINT16
)(elem
->packet
.payload
- elem
->packet
.data
+
241 elem
->hdrInfo
.l4Offset
);
242 RtlCopyMemory(outputBuffer
, &elem
->packet
.data
, size
);
243 ASSERT(len
- size
>= elem
->hdrInfo
.l4PayLoad
);
244 sum
= CopyAndCalculateChecksum((UINT8
*)outputBuffer
+ size
,
245 (UINT8
*)&elem
->packet
.data
+ size
,
246 elem
->hdrInfo
.l4PayLoad
, 0);
247 ptr
=(UINT16
*)((UINT8
*)outputBuffer
+ size
+
248 (elem
->hdrInfo
.tcpCsumNeeded
?
249 TCP_CSUM_OFFSET
: UDP_CSUM_OFFSET
));
251 ovsUserStats
.l4Csum
++;
253 RtlCopyMemory(outputBuffer
, &elem
->packet
.data
, len
);
257 OvsFreeMemoryWithTag(elem
, OVS_USER_POOL_TAG
);
259 return STATUS_SUCCESS
;
263 *----------------------------------------------------------------------------
264 * OvsNlExecuteCmdHandler --
265 * Handler for OVS_PACKET_CMD_EXECUTE command.
266 *----------------------------------------------------------------------------
269 OvsNlExecuteCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
272 NTSTATUS status
= STATUS_SUCCESS
;
273 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
274 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
275 PNL_MSG_HDR nlMsgHdr
= &(msgIn
->nlMsg
);
276 PGENL_MSG_HDR genlMsgHdr
= &(msgIn
->genlMsg
);
277 POVS_HDR ovsHdr
= &(msgIn
->ovsHdr
);
279 PNL_ATTR nlAttrs
[__OVS_PACKET_ATTR_MAX
];
280 PNL_ATTR keyAttrs
[__OVS_KEY_ATTR_MAX
] = {NULL
};
282 UINT32 attrOffset
= NLMSG_HDRLEN
+ GENL_HDRLEN
+ OVS_HDRLEN
;
283 UINT32 keyAttrOffset
= 0;
284 OvsPacketExecute execute
;
285 NL_ERROR nlError
= NL_ERROR_SUCCESS
;
288 static const NL_POLICY nlPktExecPolicy
[] = {
289 [OVS_PACKET_ATTR_PACKET
] = {.type
= NL_A_UNSPEC
, .optional
= FALSE
},
290 [OVS_PACKET_ATTR_KEY
] = {.type
= NL_A_UNSPEC
, .optional
= FALSE
},
291 [OVS_PACKET_ATTR_ACTIONS
] = {.type
= NL_A_UNSPEC
, .optional
= FALSE
},
292 [OVS_PACKET_ATTR_USERDATA
] = {.type
= NL_A_UNSPEC
, .optional
= TRUE
},
293 [OVS_PACKET_ATTR_EGRESS_TUN_KEY
] = {.type
= NL_A_UNSPEC
,
295 [OVS_PACKET_ATTR_MRU
] = { .type
= NL_A_U16
, .optional
= TRUE
}
298 RtlZeroMemory(&execute
, sizeof(OvsPacketExecute
));
300 /* Get all the top level Flow attributes */
301 if ((NlAttrParse(nlMsgHdr
, attrOffset
, NlMsgAttrsLen(nlMsgHdr
),
302 nlPktExecPolicy
, ARRAY_SIZE(nlPktExecPolicy
),
303 nlAttrs
, ARRAY_SIZE(nlAttrs
)))
305 OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
307 status
= STATUS_UNSUCCESSFUL
;
311 keyAttrOffset
= (UINT32
)((PCHAR
)nlAttrs
[OVS_PACKET_ATTR_KEY
] -
314 /* Get flow keys attributes */
315 if ((NlAttrParseNested(nlMsgHdr
, keyAttrOffset
,
316 NlAttrLen(nlAttrs
[OVS_PACKET_ATTR_KEY
]),
317 nlFlowKeyPolicy
, nlFlowKeyPolicyLen
,
318 keyAttrs
, ARRAY_SIZE(keyAttrs
))) != TRUE
) {
319 OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p", nlMsgHdr
);
320 status
= STATUS_UNSUCCESSFUL
;
324 if (keyAttrs
[OVS_KEY_ATTR_ENCAP
]) {
325 UINT32 encapOffset
= 0;
326 PNL_ATTR encapAttrs
[__OVS_KEY_ATTR_MAX
];
327 encapOffset
= (UINT32
)((PCHAR
)(keyAttrs
[OVS_KEY_ATTR_ENCAP
])
330 if ((NlAttrParseNested(nlMsgHdr
, encapOffset
,
331 NlAttrLen(keyAttrs
[OVS_KEY_ATTR_ENCAP
]),
334 encapAttrs
, ARRAY_SIZE(encapAttrs
)))
336 OVS_LOG_ERROR("Encap Key Attr Parsing failed for msg: %p",
338 status
= STATUS_UNSUCCESSFUL
;
343 execute
.dpNo
= ovsHdr
->dp_ifindex
;
345 _MapNlAttrToOvsPktExec(nlMsgHdr
, nlAttrs
, keyAttrs
, &execute
);
347 status
= OvsExecuteDpIoctl(&execute
);
349 /* Default reply that we want to send */
350 if (status
== STATUS_SUCCESS
) {
353 NlBufInit(&nlBuf
, usrParamsCtx
->outputBuffer
,
354 usrParamsCtx
->outputLength
);
356 /* Prepare nl Msg headers */
357 ok
= NlFillOvsMsg(&nlBuf
, nlMsgHdr
->nlmsgType
, 0,
358 nlMsgHdr
->nlmsgSeq
, nlMsgHdr
->nlmsgPid
,
359 genlMsgHdr
->cmd
, OVS_PACKET_VERSION
,
363 *replyLen
= msgOut
->nlMsg
.nlmsgLen
;
365 status
= STATUS_INVALID_BUFFER_SIZE
;
368 /* Map NTSTATUS to NL_ERROR */
369 nlError
= NlMapStatusToNlErr(status
);
371 /* As of now there are no transactional errors in the implementation.
372 * Once we have them then we need to map status to correct
373 * nlError value, so that below mentioned code gets hit. */
374 if ((nlError
!= NL_ERROR_SUCCESS
) &&
375 (usrParamsCtx
->outputBuffer
)) {
377 POVS_MESSAGE_ERROR msgError
= (POVS_MESSAGE_ERROR
)
378 usrParamsCtx
->outputBuffer
;
381 NlBuildErrorMsg(msgIn
, msgError
, nlError
, replyLen
);
382 status
= STATUS_SUCCESS
;
392 *----------------------------------------------------------------------------
393 * _MapNlAttrToOvsPktExec --
394 * Maps input Netlink attributes to OvsPacketExecute.
395 *----------------------------------------------------------------------------
398 _MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr
, PNL_ATTR
*nlAttrs
,
399 PNL_ATTR
*keyAttrs
, OvsPacketExecute
*execute
)
401 execute
->packetBuf
= NlAttrGet(nlAttrs
[OVS_PACKET_ATTR_PACKET
]);
402 execute
->packetLen
= NlAttrGetSize(nlAttrs
[OVS_PACKET_ATTR_PACKET
]);
404 execute
->nlMsgHdr
= nlMsgHdr
;
406 execute
->actions
= NlAttrGet(nlAttrs
[OVS_PACKET_ATTR_ACTIONS
]);
407 execute
->actionsLen
= NlAttrGetSize(nlAttrs
[OVS_PACKET_ATTR_ACTIONS
]);
409 ASSERT(keyAttrs
[OVS_KEY_ATTR_IN_PORT
]);
410 execute
->inPort
= NlAttrGetU32(keyAttrs
[OVS_KEY_ATTR_IN_PORT
]);
411 execute
->keyAttrs
= keyAttrs
;
413 if (nlAttrs
[OVS_PACKET_ATTR_MRU
]) {
414 execute
->mru
= NlAttrGetU16(nlAttrs
[OVS_PACKET_ATTR_MRU
]);
419 OvsExecuteDpIoctl(OvsPacketExecute
*execute
)
421 NTSTATUS status
= STATUS_SUCCESS
;
422 NTSTATUS ndisStatus
= STATUS_SUCCESS
;
423 LOCK_STATE_EX lockState
;
424 PNET_BUFFER_LIST pNbl
= NULL
;
425 PNL_ATTR actions
= NULL
;
426 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail
;
427 OvsFlowKey key
= { 0 };
428 OVS_PACKET_HDR_INFO layers
= { 0 };
429 POVS_VPORT_ENTRY vport
= NULL
;
430 PNL_ATTR tunnelAttrs
[__OVS_TUNNEL_KEY_ATTR_MAX
];
431 OvsFlowKey tempTunKey
= {0};
432 POVS_BUFFER_CONTEXT ctx
;
434 if (execute
->packetLen
== 0) {
435 status
= STATUS_INVALID_PARAMETER
;
439 actions
= execute
->actions
;
444 * Allocate the NBL, copy the data from the userspace buffer. Allocate
445 * also, the forwarding context for the packet.
447 pNbl
= OvsAllocateNBLFromBuffer(gOvsSwitchContext
, execute
->packetBuf
,
450 status
= STATUS_NO_MEMORY
;
454 fwdDetail
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl
);
455 // XXX: Figure out if any of the other members of fwdDetail need to be set.
457 status
= OvsGetFlowMetadata(&key
, execute
->keyAttrs
);
458 if (status
!= STATUS_SUCCESS
) {
462 if (execute
->keyAttrs
[OVS_KEY_ATTR_TUNNEL
]) {
463 UINT32 tunnelKeyAttrOffset
;
465 tunnelKeyAttrOffset
= (UINT32
)((PCHAR
)
466 (execute
->keyAttrs
[OVS_KEY_ATTR_TUNNEL
])
467 - (PCHAR
)execute
->nlMsgHdr
);
469 /* Get tunnel keys attributes */
470 if ((NlAttrParseNested(execute
->nlMsgHdr
, tunnelKeyAttrOffset
,
471 NlAttrLen(execute
->keyAttrs
[OVS_KEY_ATTR_TUNNEL
]),
472 nlFlowTunnelKeyPolicy
, nlFlowTunnelKeyPolicyLen
,
473 tunnelAttrs
, ARRAY_SIZE(tunnelAttrs
)))
475 OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
477 status
= STATUS_INVALID_PARAMETER
;
481 MapTunAttrToFlowPut(execute
->keyAttrs
, tunnelAttrs
, &tempTunKey
);
484 ndisStatus
= OvsExtractFlow(pNbl
, execute
->inPort
, &key
, &layers
,
485 tempTunKey
.tunKey
.dst
== 0 ? NULL
: &tempTunKey
.tunKey
);
487 if (ndisStatus
!= NDIS_STATUS_SUCCESS
) {
488 /* Invalid network header */
492 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(pNbl
);
493 ctx
->mru
= execute
->mru
;
495 if (ndisStatus
== NDIS_STATUS_SUCCESS
) {
496 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
, 0);
497 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, execute
->inPort
);
499 fwdDetail
->SourcePortId
= vport
->portId
;
500 fwdDetail
->SourceNicIndex
= vport
->nicIndex
;
502 fwdDetail
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
503 fwdDetail
->SourceNicIndex
= 0;
505 ndisStatus
= OvsActionsExecute(gOvsSwitchContext
, NULL
, pNbl
,
506 vport
? vport
->portNo
:
507 OVS_DPPORT_NUMBER_INVALID
,
508 NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP
,
509 &key
, NULL
, &layers
, actions
,
510 execute
->actionsLen
);
512 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
514 if (ndisStatus
!= NDIS_STATUS_SUCCESS
) {
515 if (ndisStatus
== NDIS_STATUS_NOT_SUPPORTED
) {
516 status
= STATUS_NOT_SUPPORTED
;
518 status
= STATUS_UNSUCCESSFUL
;
524 OvsCompleteNBL(gOvsSwitchContext
, pNbl
, TRUE
);
532 OvsPurgeDpIoctl(PFILE_OBJECT fileObject
)
534 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
535 POVS_USER_PACKET_QUEUE queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
538 return STATUS_INVALID_PARAMETER
;
540 OvsPurgePacketQueue(queue
, instance
);
541 return STATUS_SUCCESS
;
545 OvsCancelIrpDatapath(PDEVICE_OBJECT deviceObject
,
548 PIO_STACK_LOCATION irpSp
;
549 PFILE_OBJECT fileObject
;
550 POVS_OPEN_INSTANCE instance
;
551 POVS_USER_PACKET_QUEUE queue
= NULL
;
553 UNREFERENCED_PARAMETER(deviceObject
);
555 IoReleaseCancelSpinLock(irp
->CancelIrql
);
556 irpSp
= IoGetCurrentIrpStackLocation(irp
);
557 fileObject
= irpSp
->FileObject
;
559 if (fileObject
== NULL
) {
562 NdisAcquireSpinLock(gOvsCtrlLock
);
563 instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
565 queue
= instance
->packetQueue
;
567 if (instance
== NULL
|| queue
== NULL
) {
568 NdisReleaseSpinLock(gOvsCtrlLock
);
571 NdisReleaseSpinLock(gOvsCtrlLock
);
572 NdisAcquireSpinLock(&queue
->queueLock
);
573 if (queue
->pendingIrp
== irp
) {
574 queue
->pendingIrp
= NULL
;
576 NdisReleaseSpinLock(&queue
->queueLock
);
578 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
583 OvsWaitDpIoctl(PIRP irp
, PFILE_OBJECT fileObject
)
585 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
586 POVS_USER_PACKET_QUEUE queue
=
587 (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
588 NTSTATUS status
= STATUS_SUCCESS
;
589 BOOLEAN cancelled
= FALSE
;
592 return STATUS_INVALID_PARAMETER
;
594 NdisAcquireSpinLock(&queue
->queueLock
);
595 if (queue
->instance
!= instance
) {
596 NdisReleaseSpinLock(&queue
->queueLock
);
597 return STATUS_INVALID_PARAMETER
;
599 if (queue
->pendingIrp
) {
600 NdisReleaseSpinLock(&queue
->queueLock
);
601 return STATUS_DEVICE_BUSY
;
603 if (queue
->numPackets
== 0) {
604 PDRIVER_CANCEL cancelRoutine
;
605 IoMarkIrpPending(irp
);
606 IoSetCancelRoutine(irp
, OvsCancelIrpDatapath
);
608 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
613 queue
->pendingIrp
= irp
;
615 status
= STATUS_PENDING
;
617 NdisReleaseSpinLock(&queue
->queueLock
);
619 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
620 OVS_LOG_INFO("Datapath IRP cancelled: %p", irp
);
626 POVS_PACKET_QUEUE_ELEM
627 OvsGetNextPacket(POVS_OPEN_INSTANCE instance
)
629 POVS_USER_PACKET_QUEUE queue
;
631 queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
635 NdisAcquireSpinLock(&queue
->queueLock
);
636 if (queue
->instance
!= instance
|| queue
->numPackets
== 0) {
637 NdisReleaseSpinLock(&queue
->queueLock
);
640 link
= RemoveHeadList(&queue
->packetList
);
642 NdisReleaseSpinLock(&queue
->queueLock
);
643 return CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
647 * ---------------------------------------------------------------------------
648 * Given a pid, returns the corresponding USER_PACKET_QUEUE.
649 * ---------------------------------------------------------------------------
651 POVS_USER_PACKET_QUEUE
652 OvsGetQueue(UINT32 pid
)
654 POVS_OPEN_INSTANCE instance
;
655 POVS_USER_PACKET_QUEUE ret
= NULL
;
657 instance
= OvsGetPidInstance(gOvsSwitchContext
, pid
);
660 ret
= instance
->packetQueue
;
667 * ---------------------------------------------------------------------------
668 * Given a pid, returns the corresponding instance.
669 * pidHashLock must be acquired before calling this API.
670 * ---------------------------------------------------------------------------
673 OvsGetPidInstance(POVS_SWITCH_CONTEXT switchContext
, UINT32 pid
)
675 POVS_OPEN_INSTANCE instance
;
676 PLIST_ENTRY head
, link
;
677 UINT32 hash
= OvsJhashBytes((const VOID
*)&pid
, sizeof(pid
),
679 head
= &(switchContext
->pidHashArray
[hash
& OVS_PID_MASK
]);
680 LIST_FORALL(head
, link
) {
681 instance
= CONTAINING_RECORD(link
, OVS_OPEN_INSTANCE
, pidLink
);
682 if (instance
->pid
== pid
) {
690 * ---------------------------------------------------------------------------
691 * Given a pid and an instance. This API adds instance to pidHashArray.
692 * pidHashLock must be acquired before calling this API.
693 * ---------------------------------------------------------------------------
696 OvsAddPidInstance(POVS_SWITCH_CONTEXT switchContext
, UINT32 pid
,
697 POVS_OPEN_INSTANCE instance
)
700 UINT32 hash
= OvsJhashBytes((const VOID
*)&pid
, sizeof(pid
),
702 head
= &(switchContext
->pidHashArray
[hash
& OVS_PID_MASK
]);
703 InsertHeadList(head
, &(instance
->pidLink
));
707 * ---------------------------------------------------------------------------
708 * Given a pid and an instance. This API removes instance from pidHashArray.
709 * pidHashLock must be acquired before calling this API.
710 * ---------------------------------------------------------------------------
713 OvsDelPidInstance(POVS_SWITCH_CONTEXT switchContext
, UINT32 pid
)
715 POVS_OPEN_INSTANCE instance
= OvsGetPidInstance(switchContext
, pid
);
718 RemoveEntryList(&(instance
->pidLink
));
723 OvsQueuePackets(PLIST_ENTRY packetList
,
726 POVS_USER_PACKET_QUEUE upcallQueue
= NULL
;
727 POVS_PACKET_QUEUE_ELEM elem
;
730 LIST_ENTRY dropPackets
;
732 OVS_LOG_LOUD("Enter: numELems: %u", numElems
);
734 InitializeListHead(&dropPackets
);
736 while (!IsListEmpty(packetList
)) {
737 link
= RemoveHeadList(packetList
);
738 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
742 OvsAcquirePidHashLock();
744 upcallQueue
= OvsGetQueue(elem
->upcallPid
);
746 /* No upcall queue found, drop this packet. */
747 InsertTailList(&dropPackets
, &elem
->link
);
749 NdisAcquireSpinLock(&upcallQueue
->queueLock
);
751 if (upcallQueue
->instance
== NULL
) {
752 InsertTailList(&dropPackets
, &elem
->link
);
754 InsertTailList(&upcallQueue
->packetList
, &elem
->link
);
755 upcallQueue
->numPackets
++;
756 if (upcallQueue
->pendingIrp
) {
757 PIRP irp
= upcallQueue
->pendingIrp
;
758 PDRIVER_CANCEL cancelRoutine
;
759 upcallQueue
->pendingIrp
= NULL
;
760 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
761 if (cancelRoutine
!= NULL
) {
762 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
766 NdisReleaseSpinLock(&upcallQueue
->queueLock
);
768 OvsReleasePidHashLock();
771 while (!IsListEmpty(&dropPackets
)) {
772 link
= RemoveHeadList(&dropPackets
);
773 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
774 OvsFreeMemoryWithTag(elem
, OVS_USER_POOL_TAG
);
778 OVS_LOG_LOUD("Exit: drop %u packets", num
);
782 *----------------------------------------------------------------------------
783 * OvsCreateAndAddPackets --
785 * Create a packet and forwarded to user space.
787 * This function would fragment packet if needed, and queue
788 * each segment to user space.
789 *----------------------------------------------------------------------------
792 OvsCreateAndAddPackets(PVOID userData
,
795 POVS_VPORT_ENTRY vport
,
797 PNET_BUFFER_LIST nbl
,
799 POVS_PACKET_HDR_INFO hdrInfo
,
800 POVS_SWITCH_CONTEXT switchContext
,
804 POVS_PACKET_QUEUE_ELEM elem
;
805 PNET_BUFFER_LIST newNbl
= NULL
;
808 if (hdrInfo
->isTcp
) {
809 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo
;
812 tsoInfo
.Value
= NET_BUFFER_LIST_INFO(nbl
,
813 TcpLargeSendNetBufferListInfo
);
814 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
815 packetLength
= NET_BUFFER_DATA_LENGTH(nb
);
817 OVS_LOG_TRACE("MSS %u packet len %u",
818 tsoInfo
.LsoV1Transmit
.MSS
, packetLength
);
819 if (tsoInfo
.LsoV1Transmit
.MSS
) {
820 OVS_LOG_TRACE("l4Offset %d", hdrInfo
->l4Offset
);
821 newNbl
= OvsTcpSegmentNBL(switchContext
, nbl
, hdrInfo
,
822 tsoInfo
.LsoV1Transmit
.MSS
, 0, FALSE
);
823 if (newNbl
== NULL
) {
824 return NDIS_STATUS_FAILURE
;
830 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
832 elem
= OvsCreateQueueNlPacket(userData
, userDataLen
,
833 cmd
, vport
, key
, NULL
, nbl
, nb
,
836 InsertTailList(list
, &elem
->link
);
839 nb
= NET_BUFFER_NEXT_NB(nb
);
842 OvsCompleteNBL(switchContext
, newNbl
, TRUE
);
844 return NDIS_STATUS_SUCCESS
;
847 static __inline UINT32
848 OvsGetUpcallMsgSize(PVOID userData
,
850 OvsIPv4TunnelKey
*tunnelKey
,
853 UINT32 size
= NLMSG_ALIGN(sizeof(struct ovs_header
)) +
854 NlAttrSize(payload
) +
855 NlAttrSize(OvsFlowKeyAttrSize());
857 /* OVS_PACKET_ATTR_USERDATA */
859 size
+= NlAttrTotalSize(userDataLen
);
861 /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
862 /* Is it included in the flow key attr XXX */
864 size
+= NlAttrTotalSize(OvsTunKeyAttrSize());
870 *----------------------------------------------------------------------------
871 * This function completes the IP Header csum. record the L4 payload offset and
872 * if there is a need to calculate the TCP or UDP csum. The actual csum will be
873 * caluculated simopultaneossly with the copy of the payload to the destination
874 * buffer when the packet is read.
875 *----------------------------------------------------------------------------
878 OvsCompletePacketHeader(UINT8
*packet
,
880 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo
,
881 POVS_PACKET_HDR_INFO hdrInfoIn
,
882 POVS_PACKET_HDR_INFO hdrInfoOut
)
884 if ((isRecv
&& csumInfo
.Receive
.IpChecksumValueInvalid
) ||
885 (!isRecv
&& csumInfo
.Transmit
.IsIPv4
&&
886 csumInfo
.Transmit
.IpHeaderChecksum
)) {
887 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(packet
+ hdrInfoOut
->l3Offset
);
888 ASSERT(hdrInfoIn
->isIPv4
);
889 ASSERT(ipHdr
->Version
== 4);
890 ipHdr
->HeaderChecksum
= IPChecksum((UINT8
*)ipHdr
,
891 ipHdr
->HeaderLength
<< 2,
892 (UINT16
)~ipHdr
->HeaderChecksum
);
893 ovsUserStats
.ipCsum
++;
895 ASSERT(hdrInfoIn
->tcpCsumNeeded
== 0 && hdrInfoOut
->udpCsumNeeded
== 0);
897 * calculate TCP/UDP pseudo checksum
899 if (isRecv
&& csumInfo
.Receive
.TcpChecksumValueInvalid
) {
901 * Only this case, we need to reclaculate pseudo checksum
902 * all other cases, it is assumed the pseudo checksum is
906 PTCP_HDR tcpHdr
= (PTCP_HDR
)(packet
+ hdrInfoIn
->l4Offset
);
907 if (hdrInfoIn
->isIPv4
) {
908 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(packet
+ hdrInfoIn
->l3Offset
);
909 hdrInfoOut
->l4PayLoad
= (UINT16
)(ntohs(ipHdr
->TotalLength
) -
910 (ipHdr
->HeaderLength
<< 2));
911 tcpHdr
->th_sum
= IPPseudoChecksum((UINT32
*)&ipHdr
->SourceAddress
,
912 (UINT32
*)&ipHdr
->DestinationAddress
,
913 IPPROTO_TCP
, hdrInfoOut
->l4PayLoad
);
915 PIPV6_HEADER ipv6Hdr
= (PIPV6_HEADER
)(packet
+
916 hdrInfoIn
->l3Offset
);
917 hdrInfoOut
->l4PayLoad
=
918 (UINT16
)(ntohs(ipv6Hdr
->PayloadLength
) +
919 hdrInfoIn
->l3Offset
+ sizeof(IPV6_HEADER
)-
920 hdrInfoIn
->l4Offset
);
921 ASSERT(hdrInfoIn
->isIPv6
);
923 IPv6PseudoChecksum((UINT32
*)&ipv6Hdr
->SourceAddress
,
924 (UINT32
*)&ipv6Hdr
->DestinationAddress
,
925 IPPROTO_TCP
, hdrInfoOut
->l4PayLoad
);
927 hdrInfoOut
->tcpCsumNeeded
= 1;
928 ovsUserStats
.recalTcpCsum
++;
929 } else if (!isRecv
) {
930 if (hdrInfoIn
->isTcp
&& csumInfo
.Transmit
.TcpChecksum
) {
931 hdrInfoOut
->tcpCsumNeeded
= 1;
932 } else if (hdrInfoIn
->isUdp
&& csumInfo
.Transmit
.UdpChecksum
) {
933 hdrInfoOut
->udpCsumNeeded
= 1;
935 if (hdrInfoOut
->tcpCsumNeeded
|| hdrInfoOut
->udpCsumNeeded
) {
939 hdrInfoOut
->tcpCsumNeeded
? IPPROTO_TCP
: IPPROTO_UDP
;
941 if (hdrInfoIn
->isIPv4
) {
942 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(packet
+
943 hdrInfoIn
->l3Offset
);
944 hdrInfoOut
->l4PayLoad
= (UINT16
)(ntohs(ipHdr
->TotalLength
) -
945 (ipHdr
->HeaderLength
<< 2));
947 sum
= IPPseudoChecksum((UINT32
*)&ipHdr
->SourceAddress
,
948 (UINT32
*)&ipHdr
->DestinationAddress
,
949 proto
, hdrInfoOut
->l4PayLoad
);
952 PIPV6_HEADER ipv6Hdr
= (PIPV6_HEADER
)(packet
+
953 hdrInfoIn
->l3Offset
);
954 hdrInfoOut
->l4PayLoad
=
955 (UINT16
)(ntohs(ipv6Hdr
->PayloadLength
) +
956 hdrInfoIn
->l3Offset
+ sizeof(IPV6_HEADER
)-
957 hdrInfoIn
->l4Offset
);
958 ASSERT(hdrInfoIn
->isIPv6
);
960 sum
= IPv6PseudoChecksum((UINT32
*)&ipv6Hdr
->SourceAddress
,
961 (UINT32
*)&ipv6Hdr
->DestinationAddress
,
962 proto
, hdrInfoOut
->l4PayLoad
);
966 ptr
= (UINT16
*)(packet
+ hdrInfoIn
->l4Offset
+
967 (hdrInfoOut
->tcpCsumNeeded
?
968 TCP_CSUM_OFFSET
: UDP_CSUM_OFFSET
));
976 OvsGetPid(POVS_VPORT_ENTRY vport
, PNET_BUFFER nb
, UINT32
*pid
)
978 UNREFERENCED_PARAMETER(nb
);
982 /* XXX select a pid from an array of pids using a flow based hash */
983 *pid
= vport
->upcallPid
;
984 return STATUS_SUCCESS
;
988 *----------------------------------------------------------------------------
989 * OvsCreateQueueNlPacket --
991 * Create a packet which will be forwarded to user space.
994 * userData: when cmd is user action, this field contain
996 * userDataLen: as name indicated
997 * cmd: either miss or user action
998 * inPort: datapath port id from which the packet is received.
999 * key: flow Key with a tunnel key if available
1000 * nbl: the NET_BUFFER_LIST which contain the packet
1002 * isRecv: This is used to decide how to interprete the csum info
1003 * hdrInfo: include hdr info initialized during flow extraction.
1006 * NULL if fail to create the packet
1007 * The packet element otherwise
1008 *----------------------------------------------------------------------------
1010 POVS_PACKET_QUEUE_ELEM
1011 OvsCreateQueueNlPacket(PVOID userData
,
1014 POVS_VPORT_ENTRY vport
,
1016 OvsIPv4TunnelKey
*tunnelKey
,
1017 PNET_BUFFER_LIST nbl
,
1020 POVS_PACKET_HDR_INFO hdrInfo
)
1022 #define VLAN_TAG_SIZE 4
1023 UINT32 allocLen
, dataLen
, extraLen
= 0;
1024 POVS_PACKET_QUEUE_ELEM elem
;
1026 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo
;
1027 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo
= NULL
;
1033 POVS_BUFFER_CONTEXT ctx
;
1036 /* No vport is not fatal. */
1040 OvsGetPid(vport
, nb
, &pid
);
1044 * There is no userspace queue created yet, so there is no point for
1045 * creating a new packet to be queued.
1050 csumInfo
.Value
= NET_BUFFER_LIST_INFO(nbl
, TcpIpChecksumNetBufferListInfo
);
1052 if (isRecv
&& (csumInfo
.Receive
.TcpChecksumFailed
||
1053 (csumInfo
.Receive
.UdpChecksumFailed
&& !hdrInfo
->udpCsumZero
) ||
1054 csumInfo
.Receive
.IpChecksumFailed
)) {
1055 OVS_LOG_INFO("Packet dropped due to checksum failure.");
1056 ovsUserStats
.dropDuetoChecksum
++;
1060 vlanTag
= NET_BUFFER_LIST_INFO(nbl
, Ieee8021QNetBufferListInfo
);
1062 vlanInfo
= (PNDIS_NET_BUFFER_LIST_8021Q_INFO
)(PVOID
*)&vlanTag
;
1063 if (vlanInfo
->Value
) {
1064 extraLen
= VLAN_TAG_SIZE
;
1068 dataLen
= NET_BUFFER_DATA_LENGTH(nb
);
1070 if (NlAttrSize(dataLen
) > MAXUINT16
) {
1074 nlMsgSize
= OvsGetUpcallMsgSize(userData
, userDataLen
, tunnelKey
,
1075 dataLen
+ extraLen
);
1077 allocLen
= sizeof (OVS_PACKET_QUEUE_ELEM
) + nlMsgSize
;
1078 elem
= (POVS_PACKET_QUEUE_ELEM
)OvsAllocateMemoryWithTag(allocLen
,
1081 ovsUserStats
.dropDuetoResource
++;
1084 elem
->hdrInfo
.value
= hdrInfo
->value
;
1085 elem
->upcallPid
= pid
;
1086 elem
->packet
.totalLen
= nlMsgSize
;
1087 /* XXX remove queueid */
1088 elem
->packet
.queue
= 0;
1089 /* XXX no need as the length is already in the NL attrib */
1090 elem
->packet
.userDataLen
= userDataLen
;
1091 elem
->packet
.inPort
= vport
->portNo
;
1092 elem
->packet
.cmd
= cmd
;
1093 if (cmd
== (UINT32
)OVS_PACKET_CMD_MISS
) {
1094 ovsUserStats
.miss
++;
1095 } else if (cmd
== (UINT32
)OVS_PACKET_CMD_ACTION
) {
1096 ovsUserStats
.action
++;
1101 /* XXX Should we have both packetLen and TotalLen*/
1102 elem
->packet
.packetLen
= dataLen
+ extraLen
;
1104 NlBufInit(&nlBuf
, (PCHAR
)elem
->packet
.data
, nlMsgSize
);
1107 * Initialize the OVS header
1108 * Since we are pre allocating memory for the NL buffer
1109 * the attribute settings should not fail
1111 if (!NlFillOvsMsg(&nlBuf
, OVS_WIN_NL_PACKET_FAMILY_ID
, 0,
1112 0, pid
, (UINT8
)cmd
, OVS_PACKET_VERSION
,
1113 gOvsSwitchContext
->dpNo
)) {
1117 if (MapFlowKeyToNlKey(&nlBuf
, key
, OVS_PACKET_ATTR_KEY
,
1118 OVS_KEY_ATTR_TUNNEL
) != STATUS_SUCCESS
) {
1122 /* Set MRU attribute */
1123 ctx
= (POVS_BUFFER_CONTEXT
)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl
);
1124 if (ctx
->mru
!= 0) {
1125 if (!NlMsgPutTailU16(&nlBuf
, OVS_PACKET_ATTR_MRU
, (UINT16
)ctx
->mru
)) {
1130 /* Set OVS_PACKET_ATTR_EGRESS_TUN_KEY attribute */
1132 if (MapFlowTunKeyToNlKey(&nlBuf
, tunnelKey
,
1133 OVS_PACKET_ATTR_EGRESS_TUN_KEY
) != STATUS_SUCCESS
) {
1138 if (!NlMsgPutTailUnspec(&nlBuf
, OVS_PACKET_ATTR_USERDATA
,
1139 userData
, (UINT16
)userDataLen
)) {
1145 * Make space for the payload to be copied and set the attribute
1146 * XXX Uninit set initilizes the buffer with xero, we don't actually need
1147 * that the payload to be initailized
1149 dst
= (UINT8
*)NlMsgPutTailUnspecUninit(&nlBuf
, OVS_PACKET_ATTR_PACKET
,
1150 (UINT16
)(dataLen
+ extraLen
));
1155 /* Store the payload for csum calculation when packet is read */
1156 elem
->packet
.payload
= dst
;
1159 src
= NdisGetDataBuffer(nb
, dataLen
, dst
, 1, 0);
1161 ovsUserStats
.dropDuetoResource
++;
1163 } else if (src
!= dst
) {
1164 /* Copy the data from the NDIS buffer to dst. */
1165 RtlCopyMemory(dst
, src
, dataLen
);
1168 /* Set csum if was offloaded */
1169 OvsCompletePacketHeader(dst
, isRecv
, csumInfo
, hdrInfo
, &elem
->hdrInfo
);
1172 * Finally insert VLAN tag
1175 dst
= elem
->packet
.payload
;
1176 src
= dst
+ extraLen
;
1177 ((UINT32
*)dst
)[0] = ((UINT32
*)src
)[0];
1178 ((UINT32
*)dst
)[1] = ((UINT32
*)src
)[1];
1179 ((UINT32
*)dst
)[2] = ((UINT32
*)src
)[2];
1181 ((UINT16
*)dst
)[0] = htons(0x8100);
1182 ((UINT16
*)dst
)[1] = htons(vlanInfo
->TagHeader
.VlanId
|
1183 (vlanInfo
->TagHeader
.CanonicalFormatId
<< 12) |
1184 (vlanInfo
->TagHeader
.UserPriority
<< 13));
1185 elem
->hdrInfo
.l3Offset
+= VLAN_TAG_SIZE
;
1186 elem
->hdrInfo
.l4Offset
+= VLAN_TAG_SIZE
;
1187 ovsUserStats
.vlanInsert
++;
1190 nlMsg
= (PNL_MSG_HDR
)NlBufAt(&nlBuf
, 0, 0);
1191 nlMsg
->nlmsgLen
= NlBufSize(&nlBuf
);
1192 /* 'totalLen' should be size of valid data. */
1193 elem
->packet
.totalLen
= nlMsg
->nlmsgLen
;
1197 OvsFreeMemoryWithTag(elem
, OVS_USER_POOL_TAG
);
1202 * --------------------------------------------------------------------------
1203 * Handler for the subscription for a packet queue
1204 * --------------------------------------------------------------------------
1207 OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1214 const NL_POLICY policy
[] = {
1215 [OVS_NL_ATTR_PACKET_PID
] = {.type
= NL_A_U32
},
1216 [OVS_NL_ATTR_PACKET_SUBSCRIBE
] = {.type
= NL_A_U8
}
1218 PNL_ATTR attrs
[ARRAY_SIZE(policy
)];
1220 UNREFERENCED_PARAMETER(replyLen
);
1222 POVS_OPEN_INSTANCE instance
=
1223 (POVS_OPEN_INSTANCE
)usrParamsCtx
->ovsInstance
;
1224 POVS_MESSAGE msgIn
= (POVS_MESSAGE
)usrParamsCtx
->inputBuffer
;
1226 rc
= NlAttrParse(&msgIn
->nlMsg
, sizeof (*msgIn
),
1227 NlMsgAttrsLen((PNL_MSG_HDR
)msgIn
), policy
, ARRAY_SIZE(policy
),
1228 attrs
, ARRAY_SIZE(attrs
));
1230 status
= STATUS_INVALID_PARAMETER
;
1234 join
= NlAttrGetU8(attrs
[OVS_NL_ATTR_PACKET_SUBSCRIBE
]);
1235 pid
= NlAttrGetU32(attrs
[OVS_NL_ATTR_PACKET_PID
]);
1237 /* The socket subscribed with must be the same socket we perform receive*/
1238 ASSERT(pid
== instance
->pid
);
1240 status
= OvsSubscribeDpIoctl(instance
, pid
, join
);
1243 * XXX Need to add this instance to a global data structure
1244 * which hold all packet based instances. The data structure (hash)
1245 * should be searched through the pid field of the instance for
1246 * placing the missed packet into the correct queue
1253 * --------------------------------------------------------------------------
1254 * Handler for queueing an IRP used for missed packet notification. The IRP is
1255 * completed when a packet received and mismatched. STATUS_PENDING is returned
1256 * on success. User mode keep a pending IRP at all times.
1257 * --------------------------------------------------------------------------
1260 OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1263 UNREFERENCED_PARAMETER(replyLen
);
1265 POVS_OPEN_INSTANCE instance
=
1266 (POVS_OPEN_INSTANCE
)usrParamsCtx
->ovsInstance
;
1269 * XXX access to packet queue must be through acquiring a lock as user mode
1270 * could unsubscribe and the instnace will be freed.
1272 return OvsWaitDpIoctl(usrParamsCtx
->irp
, instance
->fileObject
);
1276 * --------------------------------------------------------------------------
1277 * Handler for reading missed pacckets from the driver event queue. This
1278 * handler is executed when user modes issues a socket receive on a socket
1279 * --------------------------------------------------------------------------
1282 OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx
,
1286 POVS_MESSAGE msgOut
= (POVS_MESSAGE
)usrParamsCtx
->outputBuffer
;
1288 POVS_OPEN_INSTANCE instance
=
1289 (POVS_OPEN_INSTANCE
)usrParamsCtx
->ovsInstance
;
1292 ASSERT(usrParamsCtx
->devOp
== OVS_READ_DEV_OP
);
1294 /* Should never read events with a dump socket */
1295 ASSERT(instance
->dumpState
.ovsMsg
== NULL
);
1297 /* Must have an packet queue */
1298 ASSERT(instance
->packetQueue
!= NULL
);
1300 /* Output buffer has been validated while validating read dev op. */
1301 ASSERT(msgOut
!= NULL
&& usrParamsCtx
->outputLength
>= sizeof *msgOut
);
1303 /* Read a packet from the instance queue */
1304 status
= OvsReadDpIoctl(instance
->fileObject
, usrParamsCtx
->outputBuffer
,
1305 usrParamsCtx
->outputLength
, replyLen
);