]> git.proxmox.com Git - ovs.git/blame - datapath-windows/ovsext/User.c
datapath-windows: Add support for handling DEI bit of VLAN header
[ovs.git] / datapath-windows / ovsext / User.c
CommitLineData
c803536e 1/*
7b383a56 2 * Copyright (c) 2014, 2016 VMware, Inc.
c803536e
SS
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
ee25964a 25#include "Actions.h"
ae1fd386 26#include "Datapath.h"
7b383a56
AS
27#include "Debug.h"
28#include "Event.h"
fa1324c9 29#include "Flow.h"
65ae4384 30#include "Jhash.h"
7b383a56
AS
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"
c803536e
SS
38
39#ifdef OVS_DBG_MOD
40#undef OVS_DBG_MOD
41#endif
42#define OVS_DBG_MOD OVS_DBG_USER
c803536e 43
c803536e
SS
44POVS_PACKET_QUEUE_ELEM OvsGetNextPacket(POVS_OPEN_INSTANCE instance);
45extern PNDIS_SPIN_LOCK gOvsCtrlLock;
46extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
47OVS_USER_STATS ovsUserStats;
48
3fd9ec0b
NR
49static VOID _MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr, PNL_ATTR *nlAttrs,
50 PNL_ATTR *keyAttrs,
51 OvsPacketExecute *execute);
efa753a8 52extern NL_POLICY nlFlowKeyPolicy[];
b8b00f0c 53extern UINT32 nlFlowKeyPolicyLen;
3871d4fb
NR
54extern NL_POLICY nlFlowTunnelKeyPolicy[];
55extern UINT32 nlFlowTunnelKeyPolicyLen;
7fba2303 56DRIVER_CANCEL OvsCancelIrpDatapath;
c803536e 57
f0187396
AS
58_IRQL_raises_(DISPATCH_LEVEL)
59_IRQL_saves_global_(OldIrql, gOvsSwitchContext->pidHashLock)
60_Acquires_lock_(gOvsSwitchContext->pidHashLock)
4a3c9b70
AS
61static __inline VOID
62OvsAcquirePidHashLock()
63{
64 NdisAcquireSpinLock(&(gOvsSwitchContext->pidHashLock));
65}
66
cfc854f0
AS
67_IRQL_requires_(DISPATCH_LEVEL)
68_IRQL_restores_global_(OldIrql, gOvsSwitchContext->pidHashLock)
69_Requires_lock_held_(gOvsSwitchContext->pidHashLock)
70_Releases_lock_(gOvsSwitchContext->pidHashLock)
4a3c9b70
AS
71static __inline VOID
72OvsReleasePidHashLock()
73{
74 NdisReleaseSpinLock(&(gOvsSwitchContext->pidHashLock));
75}
76
77
c803536e
SS
78static VOID
79OvsPurgePacketQueue(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);
d016f841 101 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
c803536e
SS
102 }
103}
104
c803536e
SS
105VOID
106OvsCleanupPacketQueue(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
777d2bbd 114 ASSERT(instance);
c803536e
SS
115 InitializeListHead(&tmp);
116 queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
117 if (queue) {
118 PDRIVER_CANCEL cancelRoutine;
119 NdisAcquireSpinLock(&queue->queueLock);
ae1fd386
EE
120 ASSERT(queue->instance == instance);
121 /* XXX Should not happen */
c803536e
SS
122 if (queue->instance != instance) {
123 NdisReleaseSpinLock(&queue->queueLock);
ae1fd386 124 NdisFreeSpinLock(&queue->queueLock);
c803536e
SS
125 return;
126 }
127
128 if (queue->numPackets) {
129 OvsAppendList(&tmp, &queue->packetList);
130 queue->numPackets = 0;
131 }
132 queue->instance = NULL;
c803536e
SS
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);
ae1fd386 143 NdisFreeSpinLock(&queue->queueLock);
c803536e
SS
144 }
145 LIST_FORALL_SAFE(&tmp, link, next) {
146 RemoveEntryList(link);
147 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
d016f841 148 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
c803536e
SS
149 }
150 if (irp) {
151 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
152 }
ae1fd386 153 if (queue) {
d016f841 154 OvsFreeMemoryWithTag(queue, OVS_USER_POOL_TAG);
ae1fd386 155 }
777d2bbd 156
3b60a203 157 /* Verify if gOvsSwitchContext exists. */
3b60a203
SV
158 if (gOvsSwitchContext) {
159 /* Remove the instance from pidHashArray */
160 OvsAcquirePidHashLock();
161 OvsDelPidInstance(gOvsSwitchContext, instance->pid);
162 OvsReleasePidHashLock();
163 }
c803536e
SS
164}
165
166NTSTATUS
ae1fd386
EE
167OvsSubscribeDpIoctl(PVOID instanceP,
168 UINT32 pid,
169 UINT8 join)
c803536e 170{
c803536e 171 POVS_USER_PACKET_QUEUE queue;
ae1fd386
EE
172 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)instanceP;
173
174 if (instance->packetQueue && !join) {
175 /* unsubscribe */
c803536e 176 OvsCleanupPacketQueue(instance);
ae1fd386 177 } else if (instance->packetQueue == NULL && join) {
d016f841
SV
178 queue = (POVS_USER_PACKET_QUEUE) OvsAllocateMemoryWithTag(
179 sizeof *queue, OVS_USER_POOL_TAG);
ae1fd386
EE
180 if (queue == NULL) {
181 return STATUS_NO_MEMORY;
c803536e 182 }
75752ef5 183 InitializeListHead(&(instance->pidLink));
ae1fd386
EE
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;
c803536e
SS
190 queue->instance = instance;
191 instance->packetQueue = queue;
c803536e 192 NdisReleaseSpinLock(&queue->queueLock);
10023cb5 193
4a3c9b70 194 OvsAcquirePidHashLock();
10023cb5
AS
195 /* Insert the instance to pidHashArray */
196 OvsAddPidInstance(gOvsSwitchContext, pid, instance);
4a3c9b70 197 OvsReleasePidHashLock();
10023cb5 198
c803536e 199 } else {
ae1fd386 200 /* user mode should call only once for subscribe */
c803536e
SS
201 return STATUS_INVALID_PARAMETER;
202 }
10023cb5 203
c803536e
SS
204 return STATUS_SUCCESS;
205}
206
207
208NTSTATUS
209OvsReadDpIoctl(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;
0d2cb708
EE
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);
c803536e 244 sum = CopyAndCalculateChecksum((UINT8 *)outputBuffer + size,
0d2cb708 245 (UINT8 *)&elem->packet.data + size,
c803536e
SS
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 {
befa5b43 253 RtlCopyMemory(outputBuffer, &elem->packet.data, len);
c803536e
SS
254 }
255
256 *replyLen = len;
d016f841 257 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
c803536e
SS
258 }
259 return STATUS_SUCCESS;
260}
261
094a1315
AS
262/*
263 *----------------------------------------------------------------------------
264 * OvsNlExecuteCmdHandler --
265 * Handler for OVS_PACKET_CMD_EXECUTE command.
266 *----------------------------------------------------------------------------
267 */
268NTSTATUS
269OvsNlExecuteCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
270 UINT32 *replyLen)
271{
efa753a8
AS
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,
39ccaaf7
AK
294 .optional = TRUE},
295 [OVS_PACKET_ATTR_MRU] = { .type = NL_A_U16, .optional = TRUE }
efa753a8
AS
296 };
297
298 RtlZeroMemory(&execute, sizeof(OvsPacketExecute));
299
300 /* Get all the top level Flow attributes */
301 if ((NlAttrParse(nlMsgHdr, attrOffset, NlMsgAttrsLen(nlMsgHdr),
b8b00f0c
SV
302 nlPktExecPolicy, ARRAY_SIZE(nlPktExecPolicy),
303 nlAttrs, ARRAY_SIZE(nlAttrs)))
efa753a8
AS
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]),
b8b00f0c
SV
317 nlFlowKeyPolicy, nlFlowKeyPolicyLen,
318 keyAttrs, ARRAY_SIZE(keyAttrs))) != TRUE) {
efa753a8
AS
319 OVS_LOG_ERROR("Key Attr Parsing failed for msg: %p", nlMsgHdr);
320 status = STATUS_UNSUCCESSFUL;
321 goto done;
322 }
323
324 execute.dpNo = ovsHdr->dp_ifindex;
325
3fd9ec0b 326 _MapNlAttrToOvsPktExec(nlMsgHdr, nlAttrs, keyAttrs, &execute);
efa753a8
AS
327
328 status = OvsExecuteDpIoctl(&execute);
329
7c5d9f17 330 /* Default reply that we want to send */
efa753a8 331 if (status == STATUS_SUCCESS) {
1ad44ad4
NR
332 BOOLEAN ok;
333
efa753a8
AS
334 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
335 usrParamsCtx->outputLength);
336
337 /* Prepare nl Msg headers */
1ad44ad4 338 ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
efa753a8
AS
339 nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
340 genlMsgHdr->cmd, OVS_PACKET_VERSION,
341 ovsHdr->dp_ifindex);
342
1ad44ad4 343 if (ok) {
efa753a8 344 *replyLen = msgOut->nlMsg.nlmsgLen;
1ad44ad4
NR
345 } else {
346 status = STATUS_INVALID_BUFFER_SIZE;
efa753a8 347 }
7c5d9f17
AS
348 } else {
349 /* Map NTSTATUS to NL_ERROR */
350 nlError = NlMapStatusToNlErr(status);
351
352 /* As of now there are no transactional errors in the implementation.
353 * Once we have them then we need to map status to correct
354 * nlError value, so that below mentioned code gets hit. */
355 if ((nlError != NL_ERROR_SUCCESS) &&
356 (usrParamsCtx->outputBuffer)) {
357
358 POVS_MESSAGE_ERROR msgError = (POVS_MESSAGE_ERROR)
359 usrParamsCtx->outputBuffer;
e6b298ef 360
7e98ed23
NR
361 ASSERT(msgError);
362 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
7c5d9f17
AS
363 status = STATUS_SUCCESS;
364 goto done;
365 }
efa753a8
AS
366 }
367
368done:
369 return status;
370}
371
372/*
373 *----------------------------------------------------------------------------
374 * _MapNlAttrToOvsPktExec --
375 * Maps input Netlink attributes to OvsPacketExecute.
376 *----------------------------------------------------------------------------
377 */
378static VOID
3fd9ec0b
NR
379_MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr, PNL_ATTR *nlAttrs,
380 PNL_ATTR *keyAttrs, OvsPacketExecute *execute)
efa753a8
AS
381{
382 execute->packetBuf = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_PACKET]);
383 execute->packetLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_PACKET]);
094a1315 384
3fd9ec0b
NR
385 execute->nlMsgHdr = nlMsgHdr;
386
efa753a8
AS
387 execute->actions = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
388 execute->actionsLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
094a1315 389
3871d4fb 390 ASSERT(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
efa753a8 391 execute->inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
877a19b7 392 execute->keyAttrs = keyAttrs;
39ccaaf7
AK
393
394 if (nlAttrs[OVS_PACKET_ATTR_MRU]) {
395 execute->mru = NlAttrGetU16(nlAttrs[OVS_PACKET_ATTR_MRU]);
396 }
094a1315
AS
397}
398
c803536e 399NTSTATUS
a74933bc 400OvsExecuteDpIoctl(OvsPacketExecute *execute)
c803536e
SS
401{
402 NTSTATUS status = STATUS_SUCCESS;
ee25964a 403 NTSTATUS ndisStatus = STATUS_SUCCESS;
c803536e 404 LOCK_STATE_EX lockState;
ee25964a
SV
405 PNET_BUFFER_LIST pNbl = NULL;
406 PNL_ATTR actions = NULL;
c803536e 407 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
ee25964a
SV
408 OvsFlowKey key = { 0 };
409 OVS_PACKET_HDR_INFO layers = { 0 };
410 POVS_VPORT_ENTRY vport = NULL;
3871d4fb
NR
411 PNL_ATTR tunnelAttrs[__OVS_TUNNEL_KEY_ATTR_MAX];
412 OvsFlowKey tempTunKey = {0};
39ccaaf7 413 POVS_BUFFER_CONTEXT ctx;
c803536e 414
c803536e
SS
415 if (execute->packetLen == 0) {
416 status = STATUS_INVALID_PARAMETER;
3ed424e5 417 goto exit;
c803536e
SS
418 }
419
a74933bc
AS
420 actions = execute->actions;
421
422 ASSERT(actions);
c803536e
SS
423
424 /*
425 * Allocate the NBL, copy the data from the userspace buffer. Allocate
426 * also, the forwarding context for the packet.
427 */
9a80ee14
SV
428 pNbl = OvsAllocateNBLFromBuffer(gOvsSwitchContext, execute->packetBuf,
429 execute->packetLen);
c803536e
SS
430 if (pNbl == NULL) {
431 status = STATUS_NO_MEMORY;
3ed424e5 432 goto exit;
c803536e
SS
433 }
434
435 fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
b2d9d3e8
NR
436 vport = OvsFindVportByPortNo(gOvsSwitchContext, execute->inPort);
437 if (vport) {
438 fwdDetail->SourcePortId = vport->portId;
439 fwdDetail->SourceNicIndex = vport->nicIndex;
440 } else {
441 fwdDetail->SourcePortId = NDIS_SWITCH_DEFAULT_PORT_ID;
442 fwdDetail->SourceNicIndex = 0;
443 }
c803536e
SS
444 // XXX: Figure out if any of the other members of fwdDetail need to be set.
445
877a19b7
SV
446 status = OvsGetFlowMetadata(&key, execute->keyAttrs);
447 if (status != STATUS_SUCCESS) {
448 goto dropit;
449 }
450
3871d4fb
NR
451 if (execute->keyAttrs[OVS_KEY_ATTR_TUNNEL]) {
452 UINT32 tunnelKeyAttrOffset;
453
454 tunnelKeyAttrOffset = (UINT32)((PCHAR)
455 (execute->keyAttrs[OVS_KEY_ATTR_TUNNEL])
456 - (PCHAR)execute->nlMsgHdr);
457
458 /* Get tunnel keys attributes */
459 if ((NlAttrParseNested(execute->nlMsgHdr, tunnelKeyAttrOffset,
460 NlAttrLen(execute->keyAttrs[OVS_KEY_ATTR_TUNNEL]),
461 nlFlowTunnelKeyPolicy, nlFlowTunnelKeyPolicyLen,
462 tunnelAttrs, ARRAY_SIZE(tunnelAttrs)))
463 != TRUE) {
464 OVS_LOG_ERROR("Tunnel key Attr Parsing failed for msg: %p",
465 execute->nlMsgHdr);
466 status = STATUS_INVALID_PARAMETER;
467 goto dropit;
468 }
469
470 MapTunAttrToFlowPut(execute->keyAttrs, tunnelAttrs, &tempTunKey);
471 }
472
473 ndisStatus = OvsExtractFlow(pNbl, execute->inPort, &key, &layers,
474 tempTunKey.tunKey.dst == 0 ? NULL : &tempTunKey.tunKey);
475
9d71ade0
SR
476 if (ndisStatus != NDIS_STATUS_SUCCESS) {
477 /* Invalid network header */
478 goto dropit;
479 }
480
39ccaaf7
AK
481 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(pNbl);
482 ctx->mru = execute->mru;
483
c803536e 484 if (ndisStatus == NDIS_STATUS_SUCCESS) {
3ed424e5 485 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
c803536e 486 ndisStatus = OvsActionsExecute(gOvsSwitchContext, NULL, pNbl,
c5c2c273 487 vport ? vport->portNo :
12e888ba 488 OVS_DPPORT_NUMBER_INVALID,
b2d9d3e8
NR
489 NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP,
490 &key, NULL, &layers, actions,
491 execute->actionsLen);
c803536e
SS
492 pNbl = NULL;
493 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
494 }
495 if (ndisStatus != NDIS_STATUS_SUCCESS) {
7c5d9f17
AS
496 if (ndisStatus == NDIS_STATUS_NOT_SUPPORTED) {
497 status = STATUS_NOT_SUPPORTED;
498 } else {
499 status = STATUS_UNSUCCESSFUL;
500 }
c803536e
SS
501 }
502
877a19b7 503dropit:
c803536e
SS
504 if (pNbl) {
505 OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
506 }
3ed424e5 507exit:
c803536e
SS
508 return status;
509}
510
511
512NTSTATUS
513OvsPurgeDpIoctl(PFILE_OBJECT fileObject)
514{
515 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
516 POVS_USER_PACKET_QUEUE queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
517
518 if (queue == NULL) {
519 return STATUS_INVALID_PARAMETER;
520 }
521 OvsPurgePacketQueue(queue, instance);
522 return STATUS_SUCCESS;
523}
524
525VOID
526OvsCancelIrpDatapath(PDEVICE_OBJECT deviceObject,
527 PIRP irp)
528{
529 PIO_STACK_LOCATION irpSp;
530 PFILE_OBJECT fileObject;
531 POVS_OPEN_INSTANCE instance;
532 POVS_USER_PACKET_QUEUE queue = NULL;
533
534 UNREFERENCED_PARAMETER(deviceObject);
535
536 IoReleaseCancelSpinLock(irp->CancelIrql);
537 irpSp = IoGetCurrentIrpStackLocation(irp);
538 fileObject = irpSp->FileObject;
539
540 if (fileObject == NULL) {
541 goto done;
542 }
543 NdisAcquireSpinLock(gOvsCtrlLock);
544 instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
545 if (instance) {
546 queue = instance->packetQueue;
547 }
548 if (instance == NULL || queue == NULL) {
549 NdisReleaseSpinLock(gOvsCtrlLock);
550 goto done;
551 }
552 NdisReleaseSpinLock(gOvsCtrlLock);
553 NdisAcquireSpinLock(&queue->queueLock);
554 if (queue->pendingIrp == irp) {
555 queue->pendingIrp = NULL;
556 }
557 NdisReleaseSpinLock(&queue->queueLock);
558done:
559 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
560}
561
562
563NTSTATUS
564OvsWaitDpIoctl(PIRP irp, PFILE_OBJECT fileObject)
565{
566 POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)fileObject->FsContext;
567 POVS_USER_PACKET_QUEUE queue =
568 (POVS_USER_PACKET_QUEUE)instance->packetQueue;
569 NTSTATUS status = STATUS_SUCCESS;
570 BOOLEAN cancelled = FALSE;
571
572 if (queue == NULL) {
573 return STATUS_INVALID_PARAMETER;
574 }
575 NdisAcquireSpinLock(&queue->queueLock);
576 if (queue->instance != instance) {
577 NdisReleaseSpinLock(&queue->queueLock);
578 return STATUS_INVALID_PARAMETER;
579 }
580 if (queue->pendingIrp) {
581 NdisReleaseSpinLock(&queue->queueLock);
582 return STATUS_DEVICE_BUSY;
583 }
584 if (queue->numPackets == 0) {
585 PDRIVER_CANCEL cancelRoutine;
586 IoMarkIrpPending(irp);
587 IoSetCancelRoutine(irp, OvsCancelIrpDatapath);
588 if (irp->Cancel) {
589 cancelRoutine = IoSetCancelRoutine(irp, NULL);
590 if (cancelRoutine) {
591 cancelled = TRUE;
592 }
593 } else {
594 queue->pendingIrp = irp;
595 }
596 status = STATUS_PENDING;
597 }
598 NdisReleaseSpinLock(&queue->queueLock);
599 if (cancelled) {
600 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
601 OVS_LOG_INFO("Datapath IRP cancelled: %p", irp);
602 }
603 return status;
604}
605
606
607POVS_PACKET_QUEUE_ELEM
608OvsGetNextPacket(POVS_OPEN_INSTANCE instance)
609{
610 POVS_USER_PACKET_QUEUE queue;
611 PLIST_ENTRY link;
612 queue = (POVS_USER_PACKET_QUEUE)instance->packetQueue;
613 if (queue == NULL) {
614 return NULL;
615 }
616 NdisAcquireSpinLock(&queue->queueLock);
617 if (queue->instance != instance || queue->numPackets == 0) {
618 NdisReleaseSpinLock(&queue->queueLock);
619 return NULL;
620 }
621 link = RemoveHeadList(&queue->packetList);
622 queue->numPackets--;
623 NdisReleaseSpinLock(&queue->queueLock);
624 return CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
625}
626
d0ce1160
AS
627/*
628 * ---------------------------------------------------------------------------
629 * Given a pid, returns the corresponding USER_PACKET_QUEUE.
d0ce1160
AS
630 * ---------------------------------------------------------------------------
631 */
c803536e 632POVS_USER_PACKET_QUEUE
ae1fd386 633OvsGetQueue(UINT32 pid)
c803536e 634{
d0ce1160
AS
635 POVS_OPEN_INSTANCE instance;
636 POVS_USER_PACKET_QUEUE ret = NULL;
637
638 instance = OvsGetPidInstance(gOvsSwitchContext, pid);
639
640 if (instance) {
641 ret = instance->packetQueue;
642 }
643
644 return ret;
c803536e
SS
645}
646
65ae4384
AS
647/*
648 * ---------------------------------------------------------------------------
649 * Given a pid, returns the corresponding instance.
4a3c9b70 650 * pidHashLock must be acquired before calling this API.
65ae4384
AS
651 * ---------------------------------------------------------------------------
652 */
653POVS_OPEN_INSTANCE
654OvsGetPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
655{
656 POVS_OPEN_INSTANCE instance;
657 PLIST_ENTRY head, link;
658 UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
659 OVS_HASH_BASIS);
660 head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
661 LIST_FORALL(head, link) {
662 instance = CONTAINING_RECORD(link, OVS_OPEN_INSTANCE, pidLink);
663 if (instance->pid == pid) {
664 return instance;
665 }
666 }
667 return NULL;
668}
669
670/*
671 * ---------------------------------------------------------------------------
672 * Given a pid and an instance. This API adds instance to pidHashArray.
4a3c9b70 673 * pidHashLock must be acquired before calling this API.
65ae4384
AS
674 * ---------------------------------------------------------------------------
675 */
676VOID
677OvsAddPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid,
678 POVS_OPEN_INSTANCE instance)
679{
680 PLIST_ENTRY head;
681 UINT32 hash = OvsJhashBytes((const VOID *)&pid, sizeof(pid),
682 OVS_HASH_BASIS);
683 head = &(switchContext->pidHashArray[hash & OVS_PID_MASK]);
684 InsertHeadList(head, &(instance->pidLink));
685}
686
687/*
688 * ---------------------------------------------------------------------------
689 * Given a pid and an instance. This API removes instance from pidHashArray.
4a3c9b70 690 * pidHashLock must be acquired before calling this API.
65ae4384
AS
691 * ---------------------------------------------------------------------------
692 */
693VOID
694OvsDelPidInstance(POVS_SWITCH_CONTEXT switchContext, UINT32 pid)
695{
696 POVS_OPEN_INSTANCE instance = OvsGetPidInstance(switchContext, pid);
697
698 if (instance) {
699 RemoveEntryList(&(instance->pidLink));
700 }
701}
702
c803536e 703VOID
4a3c9b70 704OvsQueuePackets(PLIST_ENTRY packetList,
c803536e
SS
705 UINT32 numElems)
706{
4a3c9b70 707 POVS_USER_PACKET_QUEUE upcallQueue = NULL;
c803536e 708 POVS_PACKET_QUEUE_ELEM elem;
c803536e
SS
709 PLIST_ENTRY link;
710 UINT32 num = 0;
4a3c9b70 711 LIST_ENTRY dropPackets;
c803536e 712
4a3c9b70 713 OVS_LOG_LOUD("Enter: numELems: %u", numElems);
c803536e 714
4a3c9b70 715 InitializeListHead(&dropPackets);
c803536e 716
c803536e
SS
717 while (!IsListEmpty(packetList)) {
718 link = RemoveHeadList(packetList);
719 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
4a3c9b70
AS
720
721 ASSERT(elem);
722
723 OvsAcquirePidHashLock();
724
725 upcallQueue = OvsGetQueue(elem->upcallPid);
726 if (!upcallQueue) {
727 /* No upcall queue found, drop this packet. */
728 InsertTailList(&dropPackets, &elem->link);
729 } else {
730 NdisAcquireSpinLock(&upcallQueue->queueLock);
731
732 if (upcallQueue->instance == NULL) {
733 InsertTailList(&dropPackets, &elem->link);
734 } else {
735 InsertTailList(&upcallQueue->packetList, &elem->link);
736 upcallQueue->numPackets++;
737 if (upcallQueue->pendingIrp) {
57d7a5f5 738 PIRP irp = upcallQueue->pendingIrp;
4a3c9b70 739 PDRIVER_CANCEL cancelRoutine;
4a3c9b70
AS
740 upcallQueue->pendingIrp = NULL;
741 cancelRoutine = IoSetCancelRoutine(irp, NULL);
57d7a5f5
NR
742 if (cancelRoutine != NULL) {
743 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
4a3c9b70
AS
744 }
745 }
746 }
4a3c9b70
AS
747 NdisReleaseSpinLock(&upcallQueue->queueLock);
748 }
4a3c9b70
AS
749 OvsReleasePidHashLock();
750 }
751
752 while (!IsListEmpty(&dropPackets)) {
753 link = RemoveHeadList(&dropPackets);
754 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
d016f841 755 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
c803536e
SS
756 num++;
757 }
4a3c9b70 758
c803536e
SS
759 OVS_LOG_LOUD("Exit: drop %u packets", num);
760}
761
c803536e
SS
762/*
763 *----------------------------------------------------------------------------
764 * OvsCreateAndAddPackets --
765 *
766 * Create a packet and forwarded to user space.
767 *
768 * This function would fragment packet if needed, and queue
769 * each segment to user space.
770 *----------------------------------------------------------------------------
771 */
772NTSTATUS
640ebde7 773OvsCreateAndAddPackets(PVOID userData,
c803536e
SS
774 UINT32 userDataLen,
775 UINT32 cmd,
4c470e88 776 POVS_VPORT_ENTRY vport,
640ebde7 777 OvsFlowKey *key,
c803536e
SS
778 PNET_BUFFER_LIST nbl,
779 BOOLEAN isRecv,
780 POVS_PACKET_HDR_INFO hdrInfo,
781 POVS_SWITCH_CONTEXT switchContext,
782 LIST_ENTRY *list,
783 UINT32 *num)
784{
785 POVS_PACKET_QUEUE_ELEM elem;
786 PNET_BUFFER_LIST newNbl = NULL;
787 PNET_BUFFER nb;
788
789 if (hdrInfo->isTcp) {
790 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo;
791 UINT32 packetLength;
792
c3e85147
PB
793 tsoInfo.Value = NET_BUFFER_LIST_INFO(nbl,
794 TcpLargeSendNetBufferListInfo);
c803536e
SS
795 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
796 packetLength = NET_BUFFER_DATA_LENGTH(nb);
797
798 OVS_LOG_TRACE("MSS %u packet len %u",
799 tsoInfo.LsoV1Transmit.MSS, packetLength);
800 if (tsoInfo.LsoV1Transmit.MSS) {
801 OVS_LOG_TRACE("l4Offset %d", hdrInfo->l4Offset);
802 newNbl = OvsTcpSegmentNBL(switchContext, nbl, hdrInfo,
ac8df9f6 803 tsoInfo.LsoV1Transmit.MSS , 0, FALSE);
c803536e
SS
804 if (newNbl == NULL) {
805 return NDIS_STATUS_FAILURE;
806 }
807 nbl = newNbl;
808 }
809 }
810
811 nb = NET_BUFFER_LIST_FIRST_NB(nbl);
812 while (nb) {
640ebde7 813 elem = OvsCreateQueueNlPacket(userData, userDataLen,
4c470e88 814 cmd, vport, key, nbl, nb,
c803536e
SS
815 isRecv, hdrInfo);
816 if (elem) {
817 InsertTailList(list, &elem->link);
818 (*num)++;
819 }
820 nb = NET_BUFFER_NEXT_NB(nb);
821 }
822 if (newNbl) {
823 OvsCompleteNBL(switchContext, newNbl, TRUE);
824 }
825 return NDIS_STATUS_SUCCESS;
826}
1293a628
EE
827
828static __inline UINT32
829OvsGetUpcallMsgSize(PVOID userData,
830 UINT32 userDataLen,
831 OvsIPv4TunnelKey *tunnelKey,
832 UINT32 payload)
833{
834 UINT32 size = NLMSG_ALIGN(sizeof(struct ovs_header)) +
835 NlAttrSize(payload) +
836 NlAttrSize(OvsFlowKeyAttrSize());
837
838 /* OVS_PACKET_ATTR_USERDATA */
839 if (userData) {
840 size += NlAttrTotalSize(userDataLen);
841 }
842 /* OVS_PACKET_ATTR_EGRESS_TUN_KEY */
898dcef1 843 /* Is it included in the flow key attr XXX */
1293a628
EE
844 if (tunnelKey) {
845 size += NlAttrTotalSize(OvsTunKeyAttrSize());
846 }
847 return size;
848}
849
850/*
851 *----------------------------------------------------------------------------
852 * This function completes the IP Header csum. record the L4 payload offset and
853 * if there is a need to calculate the TCP or UDP csum. The actual csum will be
854 * caluculated simopultaneossly with the copy of the payload to the destination
855 * buffer when the packet is read.
856 *----------------------------------------------------------------------------
857 */
858static VOID
859OvsCompletePacketHeader(UINT8 *packet,
860 BOOLEAN isRecv,
861 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo,
862 POVS_PACKET_HDR_INFO hdrInfoIn,
863 POVS_PACKET_HDR_INFO hdrInfoOut)
864{
865 if ((isRecv && csumInfo.Receive.IpChecksumValueInvalid) ||
866 (!isRecv && csumInfo.Transmit.IsIPv4 &&
867 csumInfo.Transmit.IpHeaderChecksum)) {
868 PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet + hdrInfoOut->l3Offset);
869 ASSERT(hdrInfoIn->isIPv4);
870 ASSERT(ipHdr->Version == 4);
871 ipHdr->HeaderChecksum = IPChecksum((UINT8 *)ipHdr,
872 ipHdr->HeaderLength << 2,
873 (UINT16)~ipHdr->HeaderChecksum);
874 ovsUserStats.ipCsum++;
875 }
876 ASSERT(hdrInfoIn->tcpCsumNeeded == 0 && hdrInfoOut->udpCsumNeeded == 0);
877 /*
878 * calculate TCP/UDP pseudo checksum
879 */
880 if (isRecv && csumInfo.Receive.TcpChecksumValueInvalid) {
881 /*
882 * Only this case, we need to reclaculate pseudo checksum
883 * all other cases, it is assumed the pseudo checksum is
884 * filled already.
885 *
886 */
887 PTCP_HDR tcpHdr = (PTCP_HDR)(packet + hdrInfoIn->l4Offset);
888 if (hdrInfoIn->isIPv4) {
889 PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet + hdrInfoIn->l3Offset);
890 hdrInfoOut->l4PayLoad = (UINT16)(ntohs(ipHdr->TotalLength) -
891 (ipHdr->HeaderLength << 2));
892 tcpHdr->th_sum = IPPseudoChecksum((UINT32 *)&ipHdr->SourceAddress,
893 (UINT32 *)&ipHdr->DestinationAddress,
894 IPPROTO_TCP, hdrInfoOut->l4PayLoad);
895 } else {
c3e85147
PB
896 PIPV6_HEADER ipv6Hdr = (PIPV6_HEADER)(packet +
897 hdrInfoIn->l3Offset);
1293a628
EE
898 hdrInfoOut->l4PayLoad =
899 (UINT16)(ntohs(ipv6Hdr->PayloadLength) +
900 hdrInfoIn->l3Offset + sizeof(IPV6_HEADER)-
901 hdrInfoIn->l4Offset);
902 ASSERT(hdrInfoIn->isIPv6);
903 tcpHdr->th_sum =
904 IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
905 (UINT32 *)&ipv6Hdr->DestinationAddress,
906 IPPROTO_TCP, hdrInfoOut->l4PayLoad);
907 }
908 hdrInfoOut->tcpCsumNeeded = 1;
909 ovsUserStats.recalTcpCsum++;
910 } else if (!isRecv) {
c3e85147 911 if (hdrInfoIn->isTcp && csumInfo.Transmit.TcpChecksum) {
1293a628 912 hdrInfoOut->tcpCsumNeeded = 1;
c3e85147 913 } else if (hdrInfoIn->isUdp && csumInfo.Transmit.UdpChecksum) {
1293a628
EE
914 hdrInfoOut->udpCsumNeeded = 1;
915 }
916 if (hdrInfoOut->tcpCsumNeeded || hdrInfoOut->udpCsumNeeded) {
917#ifdef DBG
918 UINT16 sum, *ptr;
919 UINT8 proto =
920 hdrInfoOut->tcpCsumNeeded ? IPPROTO_TCP : IPPROTO_UDP;
921#endif
922 if (hdrInfoIn->isIPv4) {
c3e85147
PB
923 PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet +
924 hdrInfoIn->l3Offset);
1293a628
EE
925 hdrInfoOut->l4PayLoad = (UINT16)(ntohs(ipHdr->TotalLength) -
926 (ipHdr->HeaderLength << 2));
927#ifdef DBG
928 sum = IPPseudoChecksum((UINT32 *)&ipHdr->SourceAddress,
929 (UINT32 *)&ipHdr->DestinationAddress,
930 proto, hdrInfoOut->l4PayLoad);
931#endif
932 } else {
933 PIPV6_HEADER ipv6Hdr = (PIPV6_HEADER)(packet +
934 hdrInfoIn->l3Offset);
935 hdrInfoOut->l4PayLoad =
936 (UINT16)(ntohs(ipv6Hdr->PayloadLength) +
937 hdrInfoIn->l3Offset + sizeof(IPV6_HEADER)-
938 hdrInfoIn->l4Offset);
939 ASSERT(hdrInfoIn->isIPv6);
940#ifdef DBG
941 sum = IPv6PseudoChecksum((UINT32 *)&ipv6Hdr->SourceAddress,
942 (UINT32 *)&ipv6Hdr->DestinationAddress,
943 proto, hdrInfoOut->l4PayLoad);
944#endif
945 }
946#ifdef DBG
947 ptr = (UINT16 *)(packet + hdrInfoIn->l4Offset +
948 (hdrInfoOut->tcpCsumNeeded ?
949 TCP_CSUM_OFFSET : UDP_CSUM_OFFSET));
950 ASSERT(*ptr == sum);
951#endif
952 }
953 }
954}
955
956static NTSTATUS
957OvsGetPid(POVS_VPORT_ENTRY vport, PNET_BUFFER nb, UINT32 *pid)
958{
959 UNREFERENCED_PARAMETER(nb);
960
4a3c9b70
AS
961 ASSERT(vport);
962
1293a628
EE
963 /* XXX select a pid from an array of pids using a flow based hash */
964 *pid = vport->upcallPid;
965 return STATUS_SUCCESS;
966}
967
968/*
969 *----------------------------------------------------------------------------
970 * OvsCreateQueueNlPacket --
971 *
972 * Create a packet which will be forwarded to user space.
973 *
974 * InputParameter:
975 * userData: when cmd is user action, this field contain
976 * user action data.
977 * userDataLen: as name indicated
978 * cmd: either miss or user action
979 * inPort: datapath port id from which the packet is received.
980 * key: flow Key with a tunnel key if available
981 * nbl: the NET_BUFFER_LIST which contain the packet
982 * nb: the packet
983 * isRecv: This is used to decide how to interprete the csum info
984 * hdrInfo: include hdr info initialized during flow extraction.
985 *
986 * Results:
987 * NULL if fail to create the packet
988 * The packet element otherwise
989 *----------------------------------------------------------------------------
990 */
991POVS_PACKET_QUEUE_ELEM
992OvsCreateQueueNlPacket(PVOID userData,
993 UINT32 userDataLen,
994 UINT32 cmd,
4c470e88 995 POVS_VPORT_ENTRY vport,
1293a628
EE
996 OvsFlowKey *key,
997 PNET_BUFFER_LIST nbl,
998 PNET_BUFFER nb,
999 BOOLEAN isRecv,
1000 POVS_PACKET_HDR_INFO hdrInfo)
1001{
1002#define VLAN_TAG_SIZE 4
205b80eb 1003 UINT32 allocLen, dataLen, extraLen = 0;
1293a628
EE
1004 POVS_PACKET_QUEUE_ELEM elem;
1005 UINT8 *src, *dst;
1006 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
205b80eb
AK
1007 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo = NULL;
1008 PVOID vlanTag;
1293a628
EE
1009 OvsIPv4TunnelKey *tunnelKey = (OvsIPv4TunnelKey *)&key->tunKey;
1010 UINT32 pid;
1011 UINT32 nlMsgSize;
1012 NL_BUFFER nlBuf;
befa5b43 1013 PNL_MSG_HDR nlMsg;
39ccaaf7 1014 POVS_BUFFER_CONTEXT ctx;
1293a628 1015
1293a628 1016 if (vport == NULL){
befa5b43 1017 /* No vport is not fatal. */
1293a628
EE
1018 return NULL;
1019 }
1020
0e55eddc
AS
1021 OvsGetPid(vport, nb, &pid);
1022
1023 if (!pid) {
1293a628
EE
1024 /*
1025 * There is no userspace queue created yet, so there is no point for
1026 * creating a new packet to be queued.
1027 */
1028 return NULL;
1029 }
1030
1031 csumInfo.Value = NET_BUFFER_LIST_INFO(nbl, TcpIpChecksumNetBufferListInfo);
1032
1033 if (isRecv && (csumInfo.Receive.TcpChecksumFailed ||
c3e85147
PB
1034 (csumInfo.Receive.UdpChecksumFailed && !hdrInfo->udpCsumZero) ||
1035 csumInfo.Receive.IpChecksumFailed)) {
1293a628
EE
1036 OVS_LOG_INFO("Packet dropped due to checksum failure.");
1037 ovsUserStats.dropDuetoChecksum++;
1038 return NULL;
1039 }
1040
205b80eb
AK
1041 vlanTag = NET_BUFFER_LIST_INFO(nbl, Ieee8021QNetBufferListInfo);
1042 if (vlanTag) {
1043 vlanInfo = (PNDIS_NET_BUFFER_LIST_8021Q_INFO)(PVOID *)&vlanTag;
1044 if (vlanInfo->Value) {
1045 extraLen = VLAN_TAG_SIZE;
1046 }
1047 }
1293a628
EE
1048
1049 dataLen = NET_BUFFER_DATA_LENGTH(nb);
1050
1051 if (NlAttrSize(dataLen) > MAXUINT16) {
1052 return NULL;
1053 }
1054
1055 nlMsgSize = OvsGetUpcallMsgSize(userData, userDataLen, tunnelKey,
1056 dataLen + extraLen);
1057
1058 allocLen = sizeof (OVS_PACKET_QUEUE_ELEM) + nlMsgSize;
d016f841
SV
1059 elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
1060 OVS_USER_POOL_TAG);
1293a628
EE
1061 if (elem == NULL) {
1062 ovsUserStats.dropDuetoResource++;
1063 return NULL;
1064 }
1065 elem->hdrInfo.value = hdrInfo->value;
4a3c9b70 1066 elem->upcallPid = pid;
1293a628
EE
1067 elem->packet.totalLen = nlMsgSize;
1068 /* XXX remove queueid */
1069 elem->packet.queue = 0;
1070 /* XXX no need as the length is already in the NL attrib */
1071 elem->packet.userDataLen = userDataLen;
4c470e88 1072 elem->packet.inPort = vport->portNo;
1293a628
EE
1073 elem->packet.cmd = cmd;
1074 if (cmd == (UINT32)OVS_PACKET_CMD_MISS) {
1075 ovsUserStats.miss++;
1076 } else if (cmd == (UINT32)OVS_PACKET_CMD_ACTION) {
1077 ovsUserStats.action++;
1078 } else {
1079 ASSERT(FALSE);
1080 goto fail;
1081 }
1082 /* XXX Should we have both packetLen and TotalLen*/
1083 elem->packet.packetLen = dataLen + extraLen;
1084
1085 NlBufInit(&nlBuf, (PCHAR)elem->packet.data, nlMsgSize);
1086
1087 /*
1088 * Initialize the OVS header
1089 * Since we are pre allocating memory for the NL buffer
1090 * the attribute settings should not fail
1091 */
1ad44ad4 1092 if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
1293a628 1093 0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
1ad44ad4 1094 gOvsSwitchContext->dpNo)) {
1293a628
EE
1095 goto fail;
1096 }
1097
1098 if (MapFlowKeyToNlKey(&nlBuf, key, OVS_PACKET_ATTR_KEY,
1099 OVS_KEY_ATTR_TUNNEL) != STATUS_SUCCESS) {
1100 goto fail;
1101 }
1102
39ccaaf7
AK
1103 /* Set MRU attribute */
1104 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(nbl);
1105 if (ctx->mru != 0) {
1106 if (!NlMsgPutTailU16(&nlBuf, OVS_PACKET_ATTR_MRU, (UINT16)ctx->mru)) {
1107 goto fail;
1108 }
1109 }
1110
1293a628
EE
1111 /* XXX must send OVS_PACKET_ATTR_EGRESS_TUN_KEY if set by vswtchd */
1112 if (userData){
1113 if (!NlMsgPutTailUnspec(&nlBuf, OVS_PACKET_ATTR_USERDATA,
1114 userData, (UINT16)userDataLen)) {
1115 goto fail;
1116 }
1117 }
1118
1119 /*
1120 * Make space for the payload to be copied and set the attribute
1121 * XXX Uninit set initilizes the buffer with xero, we don't actually need
1122 * that the payload to be initailized
1123 */
1124 dst = (UINT8 *)NlMsgPutTailUnspecUninit(&nlBuf, OVS_PACKET_ATTR_PACKET,
1125 (UINT16)(dataLen + extraLen));
1126 if (!dst) {
1127 goto fail;
1128 }
1129
1130 /* Store the payload for csum calculation when packet is read */
1131 elem->packet.payload = dst;
1132 dst += extraLen;
1133
1134 src = NdisGetDataBuffer(nb, dataLen, dst, 1, 0);
1135 if (src == NULL) {
1136 ovsUserStats.dropDuetoResource++;
1137 goto fail;
1138 } else if (src != dst) {
1139 /* Copy the data from the NDIS buffer to dst. */
1140 RtlCopyMemory(dst, src, dataLen);
1141 }
1142
1143 /* Set csum if was offloaded */
1144 OvsCompletePacketHeader(dst, isRecv, csumInfo, hdrInfo, &elem->hdrInfo);
1145
1146 /*
1147 * Finally insert VLAN tag
1148 */
1149 if (extraLen) {
1150 dst = elem->packet.payload;
1151 src = dst + extraLen;
1152 ((UINT32 *)dst)[0] = ((UINT32 *)src)[0];
1153 ((UINT32 *)dst)[1] = ((UINT32 *)src)[1];
1154 ((UINT32 *)dst)[2] = ((UINT32 *)src)[2];
1155 dst += 12;
1156 ((UINT16 *)dst)[0] = htons(0x8100);
205b80eb
AK
1157 ((UINT16 *)dst)[1] = htons(vlanInfo->TagHeader.VlanId |
1158 (vlanInfo->TagHeader.CanonicalFormatId << 12) |
1159 (vlanInfo->TagHeader.UserPriority << 13));
1293a628
EE
1160 elem->hdrInfo.l3Offset += VLAN_TAG_SIZE;
1161 elem->hdrInfo.l4Offset += VLAN_TAG_SIZE;
1162 ovsUserStats.vlanInsert++;
1163 }
befa5b43
NR
1164
1165 nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
1166 nlMsg->nlmsgLen = NlBufSize(&nlBuf);
1167 /* 'totalLen' should be size of valid data. */
1168 elem->packet.totalLen = nlMsg->nlmsgLen;
1169
1293a628
EE
1170 return elem;
1171fail:
d016f841 1172 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
1293a628
EE
1173 return NULL;
1174}
6375650a
NR
1175
1176/*
1177 * --------------------------------------------------------------------------
1178 * Handler for the subscription for a packet queue
1179 * --------------------------------------------------------------------------
1180 */
1181NTSTATUS
1182OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
ad61c98d 1183 UINT32 *replyLen)
6375650a
NR
1184{
1185 NDIS_STATUS status;
1186 BOOLEAN rc;
1187 UINT8 join;
1188 UINT32 pid;
1189 const NL_POLICY policy[] = {
1190 [OVS_NL_ATTR_PACKET_PID] = {.type = NL_A_U32 },
1191 [OVS_NL_ATTR_PACKET_SUBSCRIBE] = {.type = NL_A_U8 }
1192 };
1193 PNL_ATTR attrs[ARRAY_SIZE(policy)];
1194
1195 UNREFERENCED_PARAMETER(replyLen);
1196
1197 POVS_OPEN_INSTANCE instance =
1198 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1199 POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
1200
1201 rc = NlAttrParse(&msgIn->nlMsg, sizeof (*msgIn),
1202 NlMsgAttrsLen((PNL_MSG_HDR)msgIn), policy, ARRAY_SIZE(policy),
1203 attrs, ARRAY_SIZE(attrs));
1204 if (!rc) {
1205 status = STATUS_INVALID_PARAMETER;
1206 goto done;
1207 }
1208
ad61c98d 1209 join = NlAttrGetU8(attrs[OVS_NL_ATTR_PACKET_SUBSCRIBE]);
6375650a
NR
1210 pid = NlAttrGetU32(attrs[OVS_NL_ATTR_PACKET_PID]);
1211
1212 /* The socket subscribed with must be the same socket we perform receive*/
1213 ASSERT(pid == instance->pid);
1214
1215 status = OvsSubscribeDpIoctl(instance, pid, join);
1216
1217 /*
1218 * XXX Need to add this instance to a global data structure
1219 * which hold all packet based instances. The data structure (hash)
1220 * should be searched through the pid field of the instance for
1221 * placing the missed packet into the correct queue
1222 */
1223done:
1224 return status;
1225}
1226
1227/*
1228 * --------------------------------------------------------------------------
1229 * Handler for queueing an IRP used for missed packet notification. The IRP is
1230 * completed when a packet received and mismatched. STATUS_PENDING is returned
1231 * on success. User mode keep a pending IRP at all times.
1232 * --------------------------------------------------------------------------
1233 */
1234NTSTATUS
1235OvsPendPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1236 UINT32 *replyLen)
1237{
1238 UNREFERENCED_PARAMETER(replyLen);
1239
1240 POVS_OPEN_INSTANCE instance =
1241 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1242
1243 /*
1244 * XXX access to packet queue must be through acquiring a lock as user mode
1245 * could unsubscribe and the instnace will be freed.
1246 */
1247 return OvsWaitDpIoctl(usrParamsCtx->irp, instance->fileObject);
1248}
1249
1250/*
1251 * --------------------------------------------------------------------------
1252 * Handler for reading missed pacckets from the driver event queue. This
1253 * handler is executed when user modes issues a socket receive on a socket
1254 * --------------------------------------------------------------------------
1255 */
1256NTSTATUS
1257OvsReadPacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
1258 UINT32 *replyLen)
1259{
1260#ifdef DBG
1261 POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
1262#endif
1263 POVS_OPEN_INSTANCE instance =
1264 (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
1265 NTSTATUS status;
1266
1267 ASSERT(usrParamsCtx->devOp == OVS_READ_DEV_OP);
1268
1269 /* Should never read events with a dump socket */
1270 ASSERT(instance->dumpState.ovsMsg == NULL);
1271
1272 /* Must have an packet queue */
1273 ASSERT(instance->packetQueue != NULL);
1274
1275 /* Output buffer has been validated while validating read dev op. */
1276 ASSERT(msgOut != NULL && usrParamsCtx->outputLength >= sizeof *msgOut);
1277
1278 /* Read a packet from the instance queue */
1279 status = OvsReadDpIoctl(instance->fileObject, usrParamsCtx->outputBuffer,
1280 usrParamsCtx->outputLength, replyLen);
1281 return status;
12e888ba 1282}