]> git.proxmox.com Git - ovs.git/blob - datapath-windows/ovsext/User.c
ee0e38d99ca3e3e6b00ba1e341fad08e0378a0eb
[ovs.git] / datapath-windows / ovsext / User.c
1 /*
2 * Copyright (c) 2014, 2016 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 /*
18 * OvsUser.c
19 * Manage packet queue for packet miss for userAction.
20 */
21
22
23 #include "precomp.h"
24
25 #include "Actions.h"
26 #include "Datapath.h"
27 #include "Debug.h"
28 #include "Event.h"
29 #include "Flow.h"
30 #include "Jhash.h"
31 #include "NetProto.h"
32 #include "Offload.h"
33 #include "PacketIO.h"
34 #include "Switch.h"
35 #include "TunnelIntf.h"
36 #include "User.h"
37 #include "Vport.h"
38
39 #ifdef OVS_DBG_MOD
40 #undef OVS_DBG_MOD
41 #endif
42 #define OVS_DBG_MOD OVS_DBG_USER
43
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;
48
49 static VOID _MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr, PNL_ATTR *nlAttrs,
50 PNL_ATTR *keyAttrs,
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;
57
58 _IRQL_raises_(DISPATCH_LEVEL)
59 _IRQL_saves_global_(OldIrql, gOvsSwitchContext->pidHashLock)
60 _Acquires_lock_(gOvsSwitchContext->pidHashLock)
61 static __inline VOID
62 OvsAcquirePidHashLock()
63 {
64 NdisAcquireSpinLock(&(gOvsSwitchContext->pidHashLock));
65 }
66
67 _IRQL_requires_(DISPATCH_LEVEL)
68 _IRQL_restores_global_(OldIrql, gOvsSwitchContext->pidHashLock)
69 _Requires_lock_held_(gOvsSwitchContext->pidHashLock)
70 _Releases_lock_(gOvsSwitchContext->pidHashLock)
71 static __inline VOID
72 OvsReleasePidHashLock()
73 {
74 NdisReleaseSpinLock(&(gOvsSwitchContext->pidHashLock));
75 }
76
77
78 static VOID
79 OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue,
80 POVS_OPEN_INSTANCE instance)
81 {
82 PLIST_ENTRY link, next;
83 LIST_ENTRY tmp;
84 POVS_PACKET_QUEUE_ELEM elem;
85
86 InitializeListHead(&tmp);
87 NdisAcquireSpinLock(&queue->queueLock);
88 if (queue->instance != instance) {
89 NdisReleaseSpinLock(&queue->queueLock);
90 return;
91 }
92
93 if (queue->numPackets) {
94 OvsAppendList(&tmp, &queue->packetList);
95 queue->numPackets = 0;
96 }
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);
102 }
103 }
104
105 VOID
106 OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance)
107 {
108 POVS_USER_PACKET_QUEUE queue;
109 POVS_PACKET_QUEUE_ELEM elem;
110 PLIST_ENTRY link, next;
111 LIST_ENTRY tmp;
112 PIRP irp = NULL;
113
114 ASSERT(instance);
115 InitializeListHead(&tmp);
116 queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
117 if (queue) {
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);
125 return;
126 }
127
128 if (queue->numPackets) {
129 OvsAppendList(&tmp, &queue->packetList);
130 queue->numPackets = 0;
131 }
132 queue->instance = NULL;
133 instance->packetQueue = NULL;
134 irp = queue->pendingIrp;
135 queue->pendingIrp = NULL;
136 if (irp) {
137 cancelRoutine = IoSetCancelRoutine(irp, NULL);
138 if (cancelRoutine == NULL) {
139 irp = NULL;
140 }
141 }
142 NdisReleaseSpinLock(&queue->queueLock);
143 NdisFreeSpinLock(&queue->queueLock);
144 }
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);
149 }
150 if (irp) {
151 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
152 }
153 if (queue) {
154 OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG);
155 }
156
157 /* Verify if gOvsSwitchContext exists. */
158 if (gOvsSwitchContext) {
159 /* Remove the instance from pidHashArray */
160 OvsAcquirePidHashLock();
161 OvsDelPidInstance(gOvsSwitchContext, instance->pid);
162 OvsReleasePidHashLock();
163 }
164 }
165
166 NTSTATUS
167 OvsSubscribeDpIoctl(PVOID instanceP,
168 UINT32 pid,
169 UINT8 join)
170 {
171 POVS_USER_PACKET_QUEUE queue;
172 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)instanceP;
173
174 if (instance->packetQueue && !join) {
175 /* unsubscribe */
176 OvsCleanupPacketQueue(instance);
177 } else if (instance->packetQueue == NULL && join) {
178 queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag(
179 sizeof *queue, OVS_USER_POOL_TAG);
180 if (queue == NULL) {
181 return STATUS_NO_MEMORY;
182 }
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);
189 queue->pid = pid;
190 queue->instance = instance;
191 instance->packetQueue = queue;
192 NdisReleaseSpinLock(&queue->queueLock);
193
194 OvsAcquirePidHashLock();
195 /* Insert the instance to pidHashArray */
196 OvsAddPidInstance(gOvsSwitchContext, pid, instance);
197 OvsReleasePidHashLock();
198
199 } else {
200 /* user mode should call only once for subscribe */
201 return STATUS_INVALID_PARAMETER;
202 }
203
204 return STATUS_SUCCESS;
205 }
206
207
208 NTSTATUS
209 OvsReadDpIoctl(PFILE_OBJECT fileObject,
210 PVOID outputBuffer,
211 UINT32 outputLength,
212 UINT32 *replyLen)
213 {
214 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
215 POVS_PACKET_QUEUE_ELEM elem;
216 UINT32 len;
217
218 #define TCP_CSUM_OFFSET 16
219 #define UDP_CSUM_OFFSET 6
220 ASSERT(instance);
221
222 if (instance->packetQueue == NULL) {
223 return STATUS_INVALID_PARAMETER;
224 }
225 if (outputLength < (sizeof (OVS_PACKET_INFO) + OVS_MIN_PACKET_SIZE)) {
226 return STATUS_BUFFER_TOO_SMALL;
227 }
228
229 elem = OvsGetNextPacket(instance);
230 if (elem) {
231 /*
232 * XXX revisit this later
233 */
234 len = elem->packet.totalLen > outputLength ? outputLength :
235 elem->packet.totalLen;
236
237 if ((elem->hdrInfo.tcpCsumNeeded || elem->hdrInfo.udpCsumNeeded) &&
238 len == elem->packet.totalLen) {
239 UINT16 sum, *ptr;
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));
250 *ptr = sum;
251 ovsUserStats.l4Csum++;
252 } else {
253 RtlCopyMemory(outputBuffer, &elem->packet.data, len);
254 }
255
256 *replyLen = len;
257 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
258 }
259 return STATUS_SUCCESS;
260 }
261
262 /*
263 *----------------------------------------------------------------------------
264 * OvsNlExecuteCmdHandler --
265 * Handler for OVS_PACKET_CMD_EXECUTE command.
266 *----------------------------------------------------------------------------
267 */
268 NTSTATUS
269 OvsNlExecuteCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
270 UINT32 *replyLen)
271 {
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);
278
279 PNL_ATTR nlAttrs[__OVS_PACKET_ATTR_MAX];
280 PNL_ATTR keyAttrs[__OVS_KEY_ATTR_MAX] = {NULL};
281
282 UINT32 attrOffset = NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN;
283 UINT32 keyAttrOffset = 0;
284 OvsPacketExecute execute;
285 NL_ERROR nlError = NL_ERROR_SUCCESS;
286 NL_BUFFER nlBuf;
287
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,
294 .optional = TRUE},
295 [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = TRUE }
296 };
297
298 RtlZeroMemory(&execute, sizeof(OvsPacketExecute));
299
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)))
304 != TRUE) {
305 OVS_LOG_ERROR("Attr Parsing failed for msg: %p",
306 nlMsgHdr);
307 status = STATUS_UNSUCCESSFUL;
308 goto done;
309 }
310
311 keyAttrOffset = (UINT32)((PCHAR)nlAttrs[OVS_PACKET_ATTR_KEY] -
312 (PCHAR)nlMsgHdr);
313
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;
321 goto done;
322 }
323
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])
328 - (PCHAR)nlMsgHdr);
329
330 if ((NlAttrParseNested(nlMsgHdr, encapOffset,
331 NlAttrLen(keyAttrs[OVS_KEY_ATTR_ENCAP]),
332 nlFlowKeyPolicy,
333 nlFlowKeyPolicyLen,
334 encapAttrs, ARRAY_SIZE(encapAttrs)))
335 != TRUE) {
336 OVS_LOG_ERROR("Encap Key Attr Parsing failed for msg: %p",
337 nlMsgHdr);
338 status = STATUS_UNSUCCESSFUL;
339 goto done;
340 }
341 }
342
343 execute.dpNo = ovsHdr->dp_ifindex;
344
345 _MapNlAttrToOvsPktExec(nlMsgHdr, nlAttrs, keyAttrs, &execute);
346
347 status = OvsExecuteDpIoctl(&execute);
348
349 /* Default reply that we want to send */
350 if (status == STATUS_SUCCESS) {
351 BOOLEAN ok;
352
353 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
354 usrParamsCtx->outputLength);
355
356 /* Prepare nl Msg headers */
357 ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
358 nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
359 genlMsgHdr->cmd, OVS_PACKET_VERSION,
360 ovsHdr->dp_ifindex);
361
362 if (ok) {
363 *replyLen = msgOut->nlMsg.nlmsgLen;
364 } else {
365 status = STATUS_INVALID_BUFFER_SIZE;
366 }
367 } else {
368 /* Map NTSTATUS to NL_ERROR */
369 nlError = NlMapStatusToNlErr(status);
370
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)) {
376
377 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
378 usrParamsCtx->outputBuffer;
379
380 ASSERT(msgError);
381 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
382 status = STATUS_SUCCESS;
383 goto done;
384 }
385 }
386
387 done:
388 return status;
389 }
390
391 /*
392 *----------------------------------------------------------------------------
393 * _MapNlAttrToOvsPktExec --
394 * Maps input Netlink attributes to OvsPacketExecute.
395 *----------------------------------------------------------------------------
396 */
397 static VOID
398 _MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr, PNL_ATTR *nlAttrs,
399 PNL_ATTR *keyAttrs, OvsPacketExecute *execute)
400 {
401 execute->packetBuf = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_PACKET]);
402 execute->packetLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_PACKET]);
403
404 execute->nlMsgHdr = nlMsgHdr;
405
406 execute->actions = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
407 execute->actionsLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
408
409 ASSERT(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
410 execute->inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
411 execute->keyAttrs = keyAttrs;
412
413 if (nlAttrs[OVS_PACKET_ATTR_MRU]) {
414 execute->mru = NlAttrGetU16(nlAttrs[OVS_PACKET_ATTR_MRU]);
415 }
416 }
417
418 NTSTATUS
419 OvsExecuteDpIoctl(OvsPacketExecute *execute)
420 {
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;
433
434 if (execute->packetLen == 0) {
435 status = STATUS_INVALID_PARAMETER;
436 goto exit;
437 }
438
439 actions = execute->actions;
440
441 ASSERT(actions);
442
443 /*
444 * Allocate the NBL, copy the data from the userspace buffer. Allocate
445 * also, the forwarding context for the packet.
446 */
447 pNbl = OvsAllocateNBLFromBuffer(gOvsSwitchContext, execute->packetBuf,
448 execute->packetLen);
449 if (pNbl == NULL) {
450 status = STATUS_NO_MEMORY;
451 goto exit;
452 }
453
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.
456
457 status = OvsGetFlowMetadata(&key, execute->keyAttrs);
458 if (status != STATUS_SUCCESS) {
459 goto dropit;
460 }
461
462 if (execute->keyAttrs[OVS_KEY_ATTR_TUNNEL]) {
463 UINT32 tunnelKeyAttrOffset;
464
465 tunnelKeyAttrOffset = (UINT32)((PCHAR)
466 (execute->keyAttrs[OVS_KEY_ATTR_TUNNEL])
467 - (PCHAR)execute->nlMsgHdr);
468
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)))
474 != TRUE) {
475 OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
476 execute->nlMsgHdr);
477 status = STATUS_INVALID_PARAMETER;
478 goto dropit;
479 }
480
481 MapTunAttrToFlowPut(execute->keyAttrs, tunnelAttrs, &tempTunKey);
482 }
483
484 ndisStatus = OvsExtractFlow(pNbl, execute->inPort, &key, &layers,
485 tempTunKey.tunKey.dst == 0 ? NULL : &tempTunKey.tunKey);
486
487 if (ndisStatus != NDIS_STATUS_SUCCESS) {
488 /* Invalid network header */
489 goto dropit;
490 }
491
492 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(pNbl);
493 ctx->mru = execute->mru;
494
495 if (ndisStatus == NDIS_STATUS_SUCCESS) {
496 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
497 vport = OvsFindVportByPortNo(gOvsSwitchContext, execute->inPort);
498 if (vport) {
499 fwdDetail->SourcePortId = vport->portId;
500 fwdDetail->SourceNicIndex = vport->nicIndex;
501 } else {
502 fwdDetail->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
503 fwdDetail->SourceNicIndex = 0;
504 }
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);
511 pNbl = NULL;
512 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
513 }
514 if (ndisStatus != NDIS_STATUS_SUCCESS) {
515 if (ndisStatus == NDIS_STATUS_NOT_SUPPORTED) {
516 status = STATUS_NOT_SUPPORTED;
517 } else {
518 status = STATUS_UNSUCCESSFUL;
519 }
520 }
521
522 dropit:
523 if (pNbl) {
524 OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
525 }
526 exit:
527 return status;
528 }
529
530
531 NTSTATUS
532 OvsPurgeDpIoctl(PFILE_OBJECT fileObject)
533 {
534 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
535 POVS_USER_PACKET_QUEUE queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
536
537 if (queue == NULL) {
538 return STATUS_INVALID_PARAMETER;
539 }
540 OvsPurgePacketQueue(queue, instance);
541 return STATUS_SUCCESS;
542 }
543
544 VOID
545 OvsCancelIrpDatapath(PDEVICE_OBJECT deviceObject,
546 PIRP irp)
547 {
548 PIO_STACK_LOCATION irpSp;
549 PFILE_OBJECT fileObject;
550 POVS_OPEN_INSTANCE instance;
551 POVS_USER_PACKET_QUEUE queue = NULL;
552
553 UNREFERENCED_PARAMETER(deviceObject);
554
555 IoReleaseCancelSpinLock(irp->CancelIrql);
556 irpSp = IoGetCurrentIrpStackLocation(irp);
557 fileObject = irpSp->FileObject;
558
559 if (fileObject == NULL) {
560 goto done;
561 }
562 NdisAcquireSpinLock(gOvsCtrlLock);
563 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
564 if (instance) {
565 queue = instance->packetQueue;
566 }
567 if (instance == NULL || queue == NULL) {
568 NdisReleaseSpinLock(gOvsCtrlLock);
569 goto done;
570 }
571 NdisReleaseSpinLock(gOvsCtrlLock);
572 NdisAcquireSpinLock(&queue->queueLock);
573 if (queue->pendingIrp == irp) {
574 queue->pendingIrp = NULL;
575 }
576 NdisReleaseSpinLock(&queue->queueLock);
577 done:
578 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
579 }
580
581
582 NTSTATUS
583 OvsWaitDpIoctl(PIRP irp, PFILE_OBJECT fileObject)
584 {
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;
590
591 if (queue == NULL) {
592 return STATUS_INVALID_PARAMETER;
593 }
594 NdisAcquireSpinLock(&queue->queueLock);
595 if (queue->instance != instance) {
596 NdisReleaseSpinLock(&queue->queueLock);
597 return STATUS_INVALID_PARAMETER;
598 }
599 if (queue->pendingIrp) {
600 NdisReleaseSpinLock(&queue->queueLock);
601 return STATUS_DEVICE_BUSY;
602 }
603 if (queue->numPackets == 0) {
604 PDRIVER_CANCEL cancelRoutine;
605 IoMarkIrpPending(irp);
606 IoSetCancelRoutine(irp, OvsCancelIrpDatapath);
607 if (irp->Cancel) {
608 cancelRoutine = IoSetCancelRoutine(irp, NULL);
609 if (cancelRoutine) {
610 cancelled = TRUE;
611 }
612 } else {
613 queue->pendingIrp = irp;
614 }
615 status = STATUS_PENDING;
616 }
617 NdisReleaseSpinLock(&queue->queueLock);
618 if (cancelled) {
619 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
620 OVS_LOG_INFO("Datapath IRP cancelled: %p", irp);
621 }
622 return status;
623 }
624
625
626 POVS_PACKET_QUEUE_ELEM
627 OvsGetNextPacket(POVS_OPEN_INSTANCE instance)
628 {
629 POVS_USER_PACKET_QUEUE queue;
630 PLIST_ENTRY link;
631 queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
632 if (queue == NULL) {
633 return NULL;
634 }
635 NdisAcquireSpinLock(&queue->queueLock);
636 if (queue->instance != instance || queue->numPackets == 0) {
637 NdisReleaseSpinLock(&queue->queueLock);
638 return NULL;
639 }
640 link = RemoveHeadList(&queue->packetList);
641 queue->numPackets--;
642 NdisReleaseSpinLock(&queue->queueLock);
643 return CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
644 }
645
646 /*
647 * ---------------------------------------------------------------------------
648 * Given a pid, returns the corresponding USER_PACKET_QUEUE.
649 * ---------------------------------------------------------------------------
650 */
651 POVS_USER_PACKET_QUEUE
652 OvsGetQueue(UINT32 pid)
653 {
654 POVS_OPEN_INSTANCE instance;
655 POVS_USER_PACKET_QUEUE ret = NULL;
656
657 instance = OvsGetPidInstance(gOvsSwitchContext, pid);
658
659 if (instance) {
660 ret = instance->packetQueue;
661 }
662
663 return ret;
664 }
665
666 /*
667 * ---------------------------------------------------------------------------
668 * Given a pid, returns the corresponding instance.
669 * pidHashLock must be acquired before calling this API.
670 * ---------------------------------------------------------------------------
671 */
672 POVS_OPEN_INSTANCE
673 OvsGetPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
674 {
675 POVS_OPEN_INSTANCE instance;
676 PLIST_ENTRY head, link;
677 UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
678 OVS_HASH_BASIS);
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) {
683 return instance;
684 }
685 }
686 return NULL;
687 }
688
689 /*
690 * ---------------------------------------------------------------------------
691 * Given a pid and an instance. This API adds instance to pidHashArray.
692 * pidHashLock must be acquired before calling this API.
693 * ---------------------------------------------------------------------------
694 */
695 VOID
696 OvsAddPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid,
697 POVS_OPEN_INSTANCE instance)
698 {
699 PLIST_ENTRY head;
700 UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
701 OVS_HASH_BASIS);
702 head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
703 InsertHeadList(head, &(instance->pidLink));
704 }
705
706 /*
707 * ---------------------------------------------------------------------------
708 * Given a pid and an instance. This API removes instance from pidHashArray.
709 * pidHashLock must be acquired before calling this API.
710 * ---------------------------------------------------------------------------
711 */
712 VOID
713 OvsDelPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
714 {
715 POVS_OPEN_INSTANCE instance = OvsGetPidInstance(switchContext, pid);
716
717 if (instance) {
718 RemoveEntryList(&(instance->pidLink));
719 }
720 }
721
722 VOID
723 OvsQueuePackets(PLIST_ENTRY packetList,
724 UINT32 numElems)
725 {
726 POVS_USER_PACKET_QUEUE upcallQueue = NULL;
727 POVS_PACKET_QUEUE_ELEM elem;
728 PLIST_ENTRY link;
729 UINT32 num = 0;
730 LIST_ENTRY dropPackets;
731
732 OVS_LOG_LOUD("Enter: numELems: %u", numElems);
733
734 InitializeListHead(&dropPackets);
735
736 while (!IsListEmpty(packetList)) {
737 link = RemoveHeadList(packetList);
738 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
739
740 ASSERT(elem);
741
742 OvsAcquirePidHashLock();
743
744 upcallQueue = OvsGetQueue(elem->upcallPid);
745 if (!upcallQueue) {
746 /* No upcall queue found, drop this packet. */
747 InsertTailList(&dropPackets, &elem->link);
748 } else {
749 NdisAcquireSpinLock(&upcallQueue->queueLock);
750
751 if (upcallQueue->instance == NULL) {
752 InsertTailList(&dropPackets, &elem->link);
753 } else {
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);
763 }
764 }
765 }
766 NdisReleaseSpinLock(&upcallQueue->queueLock);
767 }
768 OvsReleasePidHashLock();
769 }
770
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);
775 num++;
776 }
777
778 OVS_LOG_LOUD("Exit: drop %u packets", num);
779 }
780
781 /*
782 *----------------------------------------------------------------------------
783 * OvsCreateAndAddPackets --
784 *
785 * Create a packet and forwarded to user space.
786 *
787 * This function would fragment packet if needed, and queue
788 * each segment to user space.
789 *----------------------------------------------------------------------------
790 */
791 NTSTATUS
792 OvsCreateAndAddPackets(PVOID userData,
793 UINT32 userDataLen,
794 UINT32 cmd,
795 POVS_VPORT_ENTRY vport,
796 OvsFlowKey *key,
797 PNET_BUFFER_LIST nbl,
798 BOOLEAN isRecv,
799 POVS_PACKET_HDR_INFO hdrInfo,
800 POVS_SWITCH_CONTEXT switchContext,
801 LIST_ENTRY *list,
802 UINT32 *num)
803 {
804 POVS_PACKET_QUEUE_ELEM elem;
805 PNET_BUFFER_LIST newNbl = NULL;
806 PNET_BUFFER nb;
807
808 if (hdrInfo->isTcp) {
809 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;
810 UINT32 packetLength;
811
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);
816
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;
825 }
826 nbl = newNbl;
827 }
828 }
829
830 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
831 while (nb) {
832 elem = OvsCreateQueueNlPacket(userData, userDataLen,
833 cmd, vport, key, NULL, nbl, nb,
834 isRecv, hdrInfo);
835 if (elem) {
836 InsertTailList(list, &elem->link);
837 (*num)++;
838 }
839 nb = NET_BUFFER_NEXT_NB(nb);
840 }
841 if (newNbl) {
842 OvsCompleteNBL(switchContext, newNbl, TRUE);
843 }
844 return NDIS_STATUS_SUCCESS;
845 }
846
847 static __inline UINT32
848 OvsGetUpcallMsgSize(PVOID userData,
849 UINT32 userDataLen,
850 OvsIPv4TunnelKey *tunnelKey,
851 UINT32 payload)
852 {
853 UINT32 size = NLMSG_ALIGN(sizeof(struct ovs_header)) +
854 NlAttrSize(payload) +
855 NlAttrSize(OvsFlowKeyAttrSize());
856
857 /* OVS_PACKET_ATTR_USERDATA */
858 if (userData) {
859 size += NlAttrTotalSize(userDataLen);
860 }
861 /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
862 /* Is it included in the flow key attr XXX */
863 if (tunnelKey) {
864 size += NlAttrTotalSize(OvsTunKeyAttrSize());
865 }
866 return size;
867 }
868
869 /*
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 *----------------------------------------------------------------------------
876 */
877 static VOID
878 OvsCompletePacketHeader(UINT8 *packet,
879 BOOLEAN isRecv,
880 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo,
881 POVS_PACKET_HDR_INFO hdrInfoIn,
882 POVS_PACKET_HDR_INFO hdrInfoOut)
883 {
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++;
894 }
895 ASSERT(hdrInfoIn->tcpCsumNeeded == 0 && hdrInfoOut->udpCsumNeeded == 0);
896 /*
897 * calculate TCP/UDP pseudo checksum
898 */
899 if (isRecv && csumInfo.Receive.TcpChecksumValueInvalid) {
900 /*
901 * Only this case, we need to reclaculate pseudo checksum
902 * all other cases, it is assumed the pseudo checksum is
903 * filled already.
904 *
905 */
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);
914 } else {
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);
922 tcpHdr->th_sum =
923 IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
924 (UINT32 *)&ipv6Hdr->DestinationAddress,
925 IPPROTO_TCP, hdrInfoOut->l4PayLoad);
926 }
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;
934 }
935 if (hdrInfoOut->tcpCsumNeeded || hdrInfoOut->udpCsumNeeded) {
936 #ifdef DBG
937 UINT16 sum, *ptr;
938 UINT8 proto =
939 hdrInfoOut->tcpCsumNeeded ? IPPROTO_TCP : IPPROTO_UDP;
940 #endif
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));
946 #ifdef DBG
947 sum = IPPseudoChecksum((UINT32 *)&ipHdr->SourceAddress,
948 (UINT32 *)&ipHdr->DestinationAddress,
949 proto, hdrInfoOut->l4PayLoad);
950 #endif
951 } else {
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);
959 #ifdef DBG
960 sum = IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
961 (UINT32 *)&ipv6Hdr->DestinationAddress,
962 proto, hdrInfoOut->l4PayLoad);
963 #endif
964 }
965 #ifdef DBG
966 ptr = (UINT16 *)(packet + hdrInfoIn->l4Offset +
967 (hdrInfoOut->tcpCsumNeeded ?
968 TCP_CSUM_OFFSET : UDP_CSUM_OFFSET));
969 ASSERT(*ptr == sum);
970 #endif
971 }
972 }
973 }
974
975 static NTSTATUS
976 OvsGetPid(POVS_VPORT_ENTRY vport, PNET_BUFFER nb, UINT32 *pid)
977 {
978 UNREFERENCED_PARAMETER(nb);
979
980 ASSERT(vport);
981
982 /* XXX select a pid from an array of pids using a flow based hash */
983 *pid = vport->upcallPid;
984 return STATUS_SUCCESS;
985 }
986
987 /*
988 *----------------------------------------------------------------------------
989 * OvsCreateQueueNlPacket --
990 *
991 * Create a packet which will be forwarded to user space.
992 *
993 * InputParameter:
994 * userData: when cmd is user action, this field contain
995 * user action data.
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
1001 * nb: the packet
1002 * isRecv: This is used to decide how to interprete the csum info
1003 * hdrInfo: include hdr info initialized during flow extraction.
1004 *
1005 * Results:
1006 * NULL if fail to create the packet
1007 * The packet element otherwise
1008 *----------------------------------------------------------------------------
1009 */
1010 POVS_PACKET_QUEUE_ELEM
1011 OvsCreateQueueNlPacket(PVOID userData,
1012 UINT32 userDataLen,
1013 UINT32 cmd,
1014 POVS_VPORT_ENTRY vport,
1015 OvsFlowKey *key,
1016 OvsIPv4TunnelKey *tunnelKey,
1017 PNET_BUFFER_LIST nbl,
1018 PNET_BUFFER nb,
1019 BOOLEAN isRecv,
1020 POVS_PACKET_HDR_INFO hdrInfo)
1021 {
1022 #define VLAN_TAG_SIZE 4
1023 UINT32 allocLen, dataLen, extraLen = 0;
1024 POVS_PACKET_QUEUE_ELEM elem;
1025 UINT8 *src, *dst;
1026 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
1027 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo = NULL;
1028 PVOID vlanTag;
1029 UINT32 pid;
1030 UINT32 nlMsgSize;
1031 NL_BUFFER nlBuf;
1032 PNL_MSG_HDR nlMsg;
1033 POVS_BUFFER_CONTEXT ctx;
1034
1035 if (vport == NULL){
1036 /* No vport is not fatal. */
1037 return NULL;
1038 }
1039
1040 OvsGetPid(vport, nb, &pid);
1041
1042 if (!pid) {
1043 /*
1044 * There is no userspace queue created yet, so there is no point for
1045 * creating a new packet to be queued.
1046 */
1047 return NULL;
1048 }
1049
1050 csumInfo.Value = NET_BUFFER_LIST_INFO(nbl, TcpIpChecksumNetBufferListInfo);
1051
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++;
1057 return NULL;
1058 }
1059
1060 vlanTag = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
1061 if (vlanTag) {
1062 vlanInfo = (PNDIS_NET_BUFFER_LIST_8021Q_INFO)(PVOID *)&vlanTag;
1063 if (vlanInfo->Value) {
1064 extraLen = VLAN_TAG_SIZE;
1065 }
1066 }
1067
1068 dataLen = NET_BUFFER_DATA_LENGTH(nb);
1069
1070 if (NlAttrSize(dataLen) > MAXUINT16) {
1071 return NULL;
1072 }
1073
1074 nlMsgSize = OvsGetUpcallMsgSize(userData, userDataLen, tunnelKey,
1075 dataLen + extraLen);
1076
1077 allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
1078 elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
1079 OVS_USER_POOL_TAG);
1080 if (elem == NULL) {
1081 ovsUserStats.dropDuetoResource++;
1082 return NULL;
1083 }
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++;
1097 } else {
1098 ASSERT(FALSE);
1099 goto fail;
1100 }
1101 /* XXX Should we have both packetLen and TotalLen*/
1102 elem->packet.packetLen = dataLen + extraLen;
1103
1104 NlBufInit(&nlBuf, (PCHAR)elem->packet.data, nlMsgSize);
1105
1106 /*
1107 * Initialize the OVS header
1108 * Since we are pre allocating memory for the NL buffer
1109 * the attribute settings should not fail
1110 */
1111 if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
1112 0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
1113 gOvsSwitchContext->dpNo)) {
1114 goto fail;
1115 }
1116
1117 if (MapFlowKeyToNlKey(&nlBuf, key, OVS_PACKET_ATTR_KEY,
1118 OVS_KEY_ATTR_TUNNEL) != STATUS_SUCCESS) {
1119 goto fail;
1120 }
1121
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)) {
1126 goto fail;
1127 }
1128 }
1129
1130 /* Set OVS_PACKET_ATTR_EGRESS_TUN_KEY attribute */
1131 if (tunnelKey) {
1132 if (MapFlowTunKeyToNlKey(&nlBuf, tunnelKey,
1133 OVS_PACKET_ATTR_EGRESS_TUN_KEY) != STATUS_SUCCESS) {
1134 goto fail;
1135 }
1136 }
1137 if (userData){
1138 if (!NlMsgPutTailUnspec(&nlBuf, OVS_PACKET_ATTR_USERDATA,
1139 userData, (UINT16)userDataLen)) {
1140 goto fail;
1141 }
1142 }
1143
1144 /*
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
1148 */
1149 dst = (UINT8 *)NlMsgPutTailUnspecUninit(&nlBuf, OVS_PACKET_ATTR_PACKET,
1150 (UINT16)(dataLen + extraLen));
1151 if (!dst) {
1152 goto fail;
1153 }
1154
1155 /* Store the payload for csum calculation when packet is read */
1156 elem->packet.payload = dst;
1157 dst += extraLen;
1158
1159 src = NdisGetDataBuffer(nb, dataLen, dst, 1, 0);
1160 if (src == NULL) {
1161 ovsUserStats.dropDuetoResource++;
1162 goto fail;
1163 } else if (src != dst) {
1164 /* Copy the data from the NDIS buffer to dst. */
1165 RtlCopyMemory(dst, src, dataLen);
1166 }
1167
1168 /* Set csum if was offloaded */
1169 OvsCompletePacketHeader(dst, isRecv, csumInfo, hdrInfo, &elem->hdrInfo);
1170
1171 /*
1172 * Finally insert VLAN tag
1173 */
1174 if (extraLen) {
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];
1180 dst += 12;
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++;
1188 }
1189
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;
1194
1195 return elem;
1196 fail:
1197 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
1198 return NULL;
1199 }
1200
1201 /*
1202 * --------------------------------------------------------------------------
1203 * Handler for the subscription for a packet queue
1204 * --------------------------------------------------------------------------
1205 */
1206 NTSTATUS
1207 OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1208 UINT32 *replyLen)
1209 {
1210 NDIS_STATUS status;
1211 BOOLEAN rc;
1212 UINT8 join;
1213 UINT32 pid;
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 }
1217 };
1218 PNL_ATTR attrs[ARRAY_SIZE(policy)];
1219
1220 UNREFERENCED_PARAMETER(replyLen);
1221
1222 POVS_OPEN_INSTANCE instance =
1223 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1224 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1225
1226 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1227 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1228 attrs, ARRAY_SIZE(attrs));
1229 if (!rc) {
1230 status = STATUS_INVALID_PARAMETER;
1231 goto done;
1232 }
1233
1234 join = NlAttrGetU8(attrs[OVS_NL_ATTR_PACKET_SUBSCRIBE]);
1235 pid = NlAttrGetU32(attrs[OVS_NL_ATTR_PACKET_PID]);
1236
1237 /* The socket subscribed with must be the same socket we perform receive*/
1238 ASSERT(pid == instance->pid);
1239
1240 status = OvsSubscribeDpIoctl(instance, pid, join);
1241
1242 /*
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
1247 */
1248 done:
1249 return status;
1250 }
1251
1252 /*
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 * --------------------------------------------------------------------------
1258 */
1259 NTSTATUS
1260 OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1261 UINT32 *replyLen)
1262 {
1263 UNREFERENCED_PARAMETER(replyLen);
1264
1265 POVS_OPEN_INSTANCE instance =
1266 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1267
1268 /*
1269 * XXX access to packet queue must be through acquiring a lock as user mode
1270 * could unsubscribe and the instnace will be freed.
1271 */
1272 return OvsWaitDpIoctl(usrParamsCtx->irp, instance->fileObject);
1273 }
1274
1275 /*
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 * --------------------------------------------------------------------------
1280 */
1281 NTSTATUS
1282 OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1283 UINT32 *replyLen)
1284 {
1285 #ifdef DBG
1286 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1287 #endif
1288 POVS_OPEN_INSTANCE instance =
1289 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1290 NTSTATUS status;
1291
1292 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1293
1294 /* Should never read events with a dump socket */
1295 ASSERT(instance->dumpState.ovsMsg == NULL);
1296
1297 /* Must have an packet queue */
1298 ASSERT(instance->packetQueue != NULL);
1299
1300 /* Output buffer has been validated while validating read dev op. */
1301 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1302
1303 /* Read a packet from the instance queue */
1304 status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
1305 usrParamsCtx->outputLength, replyLen);
1306 return status;
1307 }