]> git.proxmox.com Git - ovs.git/blame - datapath-windows/ovsext/User.c
bump version to 2.15.0+ds1-2+deb11u3.1
[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
c8915346
AK
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
efa753a8
AS
343 execute.dpNo = ovsHdr->dp_ifindex;
344
3fd9ec0b 345 _MapNlAttrToOvsPktExec(nlMsgHdr, nlAttrs, keyAttrs, &execute);
efa753a8
AS
346
347 status = OvsExecuteDpIoctl(&execute);
348
7c5d9f17 349 /* Default reply that we want to send */
efa753a8 350 if (status == STATUS_SUCCESS) {
1ad44ad4
NR
351 BOOLEAN ok;
352
efa753a8
AS
353 NlBufInit(&nlBuf, usrParamsCtx->outputBuffer,
354 usrParamsCtx->outputLength);
355
356 /* Prepare nl Msg headers */
1ad44ad4 357 ok = NlFillOvsMsg(&nlBuf, nlMsgHdr->nlmsgType, 0,
efa753a8
AS
358 nlMsgHdr->nlmsgSeq, nlMsgHdr->nlmsgPid,
359 genlMsgHdr->cmd, OVS_PACKET_VERSION,
360 ovsHdr->dp_ifindex);
361
1ad44ad4 362 if (ok) {
efa753a8 363 *replyLen = msgOut->nlMsg.nlmsgLen;
1ad44ad4
NR
364 } else {
365 status = STATUS_INVALID_BUFFER_SIZE;
efa753a8 366 }
7c5d9f17
AS
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;
e6b298ef 379
7e98ed23
NR
380 ASSERT(msgError);
381 NlBuildErrorMsg(msgIn, msgError, nlError, replyLen);
7c5d9f17
AS
382 status = STATUS_SUCCESS;
383 goto done;
384 }
efa753a8
AS
385 }
386
387done:
388 return status;
389}
390
391/*
392 *----------------------------------------------------------------------------
393 * _MapNlAttrToOvsPktExec --
394 * Maps input Netlink attributes to OvsPacketExecute.
395 *----------------------------------------------------------------------------
396 */
397static VOID
3fd9ec0b
NR
398_MapNlAttrToOvsPktExec(PNL_MSG_HDR nlMsgHdr, PNL_ATTR *nlAttrs,
399 PNL_ATTR *keyAttrs, OvsPacketExecute *execute)
efa753a8
AS
400{
401 execute->packetBuf = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_PACKET]);
402 execute->packetLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_PACKET]);
094a1315 403
3fd9ec0b
NR
404 execute->nlMsgHdr = nlMsgHdr;
405
efa753a8
AS
406 execute->actions = NlAttrGet(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
407 execute->actionsLen = NlAttrGetSize(nlAttrs[OVS_PACKET_ATTR_ACTIONS]);
094a1315 408
3871d4fb 409 ASSERT(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
efa753a8 410 execute->inPort = NlAttrGetU32(keyAttrs[OVS_KEY_ATTR_IN_PORT]);
877a19b7 411 execute->keyAttrs = keyAttrs;
39ccaaf7
AK
412
413 if (nlAttrs[OVS_PACKET_ATTR_MRU]) {
414 execute->mru = NlAttrGetU16(nlAttrs[OVS_PACKET_ATTR_MRU]);
415 }
094a1315
AS
416}
417
c803536e 418NTSTATUS
a74933bc 419OvsExecuteDpIoctl(OvsPacketExecute *execute)
c803536e
SS
420{
421 NTSTATUS status = STATUS_SUCCESS;
ee25964a 422 NTSTATUS ndisStatus = STATUS_SUCCESS;
c803536e 423 LOCK_STATE_EX lockState;
ee25964a
SV
424 PNET_BUFFER_LIST pNbl = NULL;
425 PNL_ATTR actions = NULL;
c803536e 426 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail;
ee25964a
SV
427 OvsFlowKey key = { 0 };
428 OVS_PACKET_HDR_INFO layers = { 0 };
429 POVS_VPORT_ENTRY vport = NULL;
3871d4fb
NR
430 PNL_ATTR tunnelAttrs[__OVS_TUNNEL_KEY_ATTR_MAX];
431 OvsFlowKey tempTunKey = {0};
39ccaaf7 432 POVS_BUFFER_CONTEXT ctx;
c803536e 433
c803536e
SS
434 if (execute->packetLen == 0) {
435 status = STATUS_INVALID_PARAMETER;
3ed424e5 436 goto exit;
c803536e
SS
437 }
438
a74933bc
AS
439 actions = execute->actions;
440
441 ASSERT(actions);
c803536e
SS
442
443 /*
444 * Allocate the NBL, copy the data from the userspace buffer. Allocate
445 * also, the forwarding context for the packet.
446 */
9a80ee14
SV
447 pNbl = OvsAllocateNBLFromBuffer(gOvsSwitchContext, execute->packetBuf,
448 execute->packetLen);
c803536e
SS
449 if (pNbl == NULL) {
450 status = STATUS_NO_MEMORY;
3ed424e5 451 goto exit;
c803536e
SS
452 }
453
454 fwdDetail = NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl);
c803536e
SS
455 // XXX: Figure out if any of the other members of fwdDetail need to be set.
456
877a19b7
SV
457 status = OvsGetFlowMetadata(&key, execute->keyAttrs);
458 if (status != STATUS_SUCCESS) {
459 goto dropit;
460 }
461
3871d4fb
NR
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
9d71ade0
SR
487 if (ndisStatus != NDIS_STATUS_SUCCESS) {
488 /* Invalid network header */
489 goto dropit;
490 }
491
39ccaaf7
AK
492 ctx = (POVS_BUFFER_CONTEXT)NET_BUFFER_LIST_CONTEXT_DATA_START(pNbl);
493 ctx->mru = execute->mru;
494
c803536e 495 if (ndisStatus == NDIS_STATUS_SUCCESS) {
3ed424e5 496 NdisAcquireRWLockRead(gOvsSwitchContext->dispatchLock, &lockState, 0);
3cdf29c5
AGS
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 }
c803536e 505 ndisStatus = OvsActionsExecute(gOvsSwitchContext, NULL, pNbl,
c5c2c273 506 vport ? vport->portNo :
12e888ba 507 OVS_DPPORT_NUMBER_INVALID,
b2d9d3e8
NR
508 NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP,
509 &key, NULL, &layers, actions,
510 execute->actionsLen);
c803536e
SS
511 pNbl = NULL;
512 NdisReleaseRWLock(gOvsSwitchContext->dispatchLock, &lockState);
513 }
514 if (ndisStatus != NDIS_STATUS_SUCCESS) {
7c5d9f17
AS
515 if (ndisStatus == NDIS_STATUS_NOT_SUPPORTED) {
516 status = STATUS_NOT_SUPPORTED;
517 } else {
518 status = STATUS_UNSUCCESSFUL;
519 }
c803536e
SS
520 }
521
877a19b7 522dropit:
c803536e
SS
523 if (pNbl) {
524 OvsCompleteNBL(gOvsSwitchContext, pNbl, TRUE);
525 }
3ed424e5 526exit:
c803536e
SS
527 return status;
528}
529
530
531NTSTATUS
532OvsPurgeDpIoctl(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
544VOID
545OvsCancelIrpDatapath(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);
577done:
578 OvsCompleteIrpRequest(irp, 0, STATUS_CANCELLED);
579}
580
581
582NTSTATUS
583OvsWaitDpIoctl(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
626POVS_PACKET_QUEUE_ELEM
627OvsGetNextPacket(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
d0ce1160
AS
646/*
647 * ---------------------------------------------------------------------------
648 * Given a pid, returns the corresponding USER_PACKET_QUEUE.
d0ce1160
AS
649 * ---------------------------------------------------------------------------
650 */
c803536e 651POVS_USER_PACKET_QUEUE
ae1fd386 652OvsGetQueue(UINT32 pid)
c803536e 653{
d0ce1160
AS
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;
c803536e
SS
664}
665
65ae4384
AS
666/*
667 * ---------------------------------------------------------------------------
668 * Given a pid, returns the corresponding instance.
4a3c9b70 669 * pidHashLock must be acquired before calling this API.
65ae4384
AS
670 * ---------------------------------------------------------------------------
671 */
672POVS_OPEN_INSTANCE
673OvsGetPidInstance(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.
4a3c9b70 692 * pidHashLock must be acquired before calling this API.
65ae4384
AS
693 * ---------------------------------------------------------------------------
694 */
695VOID
696OvsAddPidInstance(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.
4a3c9b70 709 * pidHashLock must be acquired before calling this API.
65ae4384
AS
710 * ---------------------------------------------------------------------------
711 */
712VOID
713OvsDelPidInstance(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
c803536e 722VOID
4a3c9b70 723OvsQueuePackets(PLIST_ENTRY packetList,
c803536e
SS
724 UINT32 numElems)
725{
4a3c9b70 726 POVS_USER_PACKET_QUEUE upcallQueue = NULL;
c803536e 727 POVS_PACKET_QUEUE_ELEM elem;
c803536e
SS
728 PLIST_ENTRY link;
729 UINT32 num = 0;
4a3c9b70 730 LIST_ENTRY dropPackets;
c803536e 731
4a3c9b70 732 OVS_LOG_LOUD("Enter: numELems: %u", numElems);
c803536e 733
4a3c9b70 734 InitializeListHead(&dropPackets);
c803536e 735
c803536e
SS
736 while (!IsListEmpty(packetList)) {
737 link = RemoveHeadList(packetList);
738 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
4a3c9b70
AS
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) {
57d7a5f5 757 PIRP irp = upcallQueue->pendingIrp;
4a3c9b70 758 PDRIVER_CANCEL cancelRoutine;
4a3c9b70
AS
759 upcallQueue->pendingIrp = NULL;
760 cancelRoutine = IoSetCancelRoutine(irp, NULL);
57d7a5f5
NR
761 if (cancelRoutine != NULL) {
762 OvsCompleteIrpRequest(irp, 0, STATUS_SUCCESS);
4a3c9b70
AS
763 }
764 }
765 }
4a3c9b70
AS
766 NdisReleaseSpinLock(&upcallQueue->queueLock);
767 }
4a3c9b70
AS
768 OvsReleasePidHashLock();
769 }
770
771 while (!IsListEmpty(&dropPackets)) {
772 link = RemoveHeadList(&dropPackets);
773 elem = CONTAINING_RECORD(link, OVS_PACKET_QUEUE_ELEM, link);
d016f841 774 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
c803536e
SS
775 num++;
776 }
4a3c9b70 777
c803536e
SS
778 OVS_LOG_LOUD("Exit: drop %u packets", num);
779}
780
c803536e
SS
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 */
791NTSTATUS
640ebde7 792OvsCreateAndAddPackets(PVOID userData,
c803536e
SS
793 UINT32 userDataLen,
794 UINT32 cmd,
4c470e88 795 POVS_VPORT_ENTRY vport,
640ebde7 796 OvsFlowKey *key,
c803536e
SS
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
c3e85147
PB
812 tsoInfo.Value = NET_BUFFER_LIST_INFO(nbl,
813 TcpLargeSendNetBufferListInfo);
c803536e
SS
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,
ac8df9f6 822 tsoInfo.LsoV1Transmit.MSS , 0, FALSE);
c803536e
SS
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) {
640ebde7 832 elem = OvsCreateQueueNlPacket(userData, userDataLen,
e14fbdbb 833 cmd, vport, key, NULL, nbl, nb,
c803536e
SS
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}
1293a628
EE
846
847static __inline UINT32
848OvsGetUpcallMsgSize(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 */
898dcef1 862 /* Is it included in the flow key attr XXX */
1293a628
EE
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 */
877static VOID
878OvsCompletePacketHeader(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 {
c3e85147
PB
915 PIPV6_HEADER ipv6Hdr = (PIPV6_HEADER)(packet +
916 hdrInfoIn->l3Offset);
1293a628
EE
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) {
c3e85147 930 if (hdrInfoIn->isTcp && csumInfo.Transmit.TcpChecksum) {
1293a628 931 hdrInfoOut->tcpCsumNeeded = 1;
c3e85147 932 } else if (hdrInfoIn->isUdp && csumInfo.Transmit.UdpChecksum) {
1293a628
EE
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) {
c3e85147
PB
942 PIPV4_HEADER ipHdr = (PIPV4_HEADER)(packet +
943 hdrInfoIn->l3Offset);
1293a628
EE
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
975static NTSTATUS
976OvsGetPid(POVS_VPORT_ENTRY vport, PNET_BUFFER nb, UINT32 *pid)
977{
978 UNREFERENCED_PARAMETER(nb);
979
4a3c9b70
AS
980 ASSERT(vport);
981
1293a628
EE
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 */
1010POVS_PACKET_QUEUE_ELEM
1011OvsCreateQueueNlPacket(PVOID userData,
1012 UINT32 userDataLen,
1013 UINT32 cmd,
4c470e88 1014 POVS_VPORT_ENTRY vport,
1293a628 1015 OvsFlowKey *key,
e14fbdbb 1016 OvsIPv4TunnelKey *tunnelKey,
1293a628
EE
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
205b80eb 1023 UINT32 allocLen, dataLen, extraLen = 0;
1293a628
EE
1024 POVS_PACKET_QUEUE_ELEM elem;
1025 UINT8 *src, *dst;
1026 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo;
205b80eb
AK
1027 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo = NULL;
1028 PVOID vlanTag;
1293a628
EE
1029 UINT32 pid;
1030 UINT32 nlMsgSize;
1031 NL_BUFFER nlBuf;
befa5b43 1032 PNL_MSG_HDR nlMsg;
39ccaaf7 1033 POVS_BUFFER_CONTEXT ctx;
1293a628 1034
1293a628 1035 if (vport == NULL){
befa5b43 1036 /* No vport is not fatal. */
1293a628
EE
1037 return NULL;
1038 }
1039
0e55eddc
AS
1040 OvsGetPid(vport, nb, &pid);
1041
1042 if (!pid) {
1293a628
EE
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 ||
c3e85147
PB
1053 (csumInfo.Receive.UdpChecksumFailed && !hdrInfo->udpCsumZero) ||
1054 csumInfo.Receive.IpChecksumFailed)) {
1293a628
EE
1055 OVS_LOG_INFO("Packet dropped due to checksum failure.");
1056 ovsUserStats.dropDuetoChecksum++;
1057 return NULL;
1058 }
1059
205b80eb
AK
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 }
1293a628
EE
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;
d016f841
SV
1078 elem = (POVS_PACKET_QUEUE_ELEM)OvsAllocateMemoryWithTag(allocLen,
1079 OVS_USER_POOL_TAG);
1293a628
EE
1080 if (elem == NULL) {
1081 ovsUserStats.dropDuetoResource++;
1082 return NULL;
1083 }
1084 elem->hdrInfo.value = hdrInfo->value;
4a3c9b70 1085 elem->upcallPid = pid;
1293a628
EE
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;
4c470e88 1091 elem->packet.inPort = vport->portNo;
1293a628
EE
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 */
1ad44ad4 1111 if (!NlFillOvsMsg(&nlBuf, OVS_WIN_NL_PACKET_FAMILY_ID, 0,
1293a628 1112 0, pid, (UINT8)cmd, OVS_PACKET_VERSION,
1ad44ad4 1113 gOvsSwitchContext->dpNo)) {
1293a628
EE
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
39ccaaf7
AK
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
e14fbdbb
AH
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 }
1293a628
EE
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);
205b80eb
AK
1182 ((UINT16 *)dst)[1] = htons(vlanInfo->TagHeader.VlanId |
1183 (vlanInfo->TagHeader.CanonicalFormatId << 12) |
1184 (vlanInfo->TagHeader.UserPriority << 13));
1293a628
EE
1185 elem->hdrInfo.l3Offset += VLAN_TAG_SIZE;
1186 elem->hdrInfo.l4Offset += VLAN_TAG_SIZE;
1187 ovsUserStats.vlanInsert++;
1188 }
befa5b43
NR
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
1293a628
EE
1195 return elem;
1196fail:
d016f841 1197 OvsFreeMemoryWithTag(elem, OVS_USER_POOL_TAG);
1293a628
EE
1198 return NULL;
1199}
6375650a
NR
1200
1201/*
1202 * --------------------------------------------------------------------------
1203 * Handler for the subscription for a packet queue
1204 * --------------------------------------------------------------------------
1205 */
1206NTSTATUS
1207OvsSubscribePacketCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
ad61c98d 1208 UINT32 *replyLen)
6375650a
NR
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
ad61c98d 1234 join = NlAttrGetU8(attrs[OVS_NL_ATTR_PACKET_SUBSCRIBE]);
6375650a
NR
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 */
1248done:
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 */
1259NTSTATUS
1260OvsPendPacketCmdHandler(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 */
1281NTSTATUS
1282OvsReadPacketCmdHandler(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;
12e888ba 1307}