2 * Copyright (c) 2014 VMware, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 * Manage packet queue for packet miss for userAction.
26 #include "OvsSwitch.h"
30 #include "OvsPacketIO.h"
31 #include "OvsChecksum.h"
32 #include "OvsNetProto.h"
34 #include "OvsTunnelIntf.h"
39 #define OVS_DBG_MOD OVS_DBG_USER
42 OVS_USER_PACKET_QUEUE ovsPacketQueues
[OVS_MAX_NUM_PACKET_QUEUES
];
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
;
54 POVS_USER_PACKET_QUEUE queue
;
55 for (i
= 0; i
< OVS_MAX_NUM_PACKET_QUEUES
; i
++) {
56 queue
= &ovsPacketQueues
[i
];
57 RtlZeroMemory(queue
, sizeof (*queue
));
58 InitializeListHead(&queue
->packetList
);
59 NdisAllocateSpinLock(&queue
->queueLock
);
61 return STATUS_SUCCESS
;
68 POVS_USER_PACKET_QUEUE queue
;
69 for (i
= 0; i
< OVS_MAX_NUM_PACKET_QUEUES
; i
++) {
70 queue
= &ovsPacketQueues
[i
];
71 ASSERT(IsListEmpty(&queue
->packetList
));
72 ASSERT(queue
->instance
== NULL
);
73 ASSERT(queue
->pendingIrp
== NULL
);
74 NdisFreeSpinLock(&queue
->queueLock
);
79 OvsPurgePacketQueue(POVS_USER_PACKET_QUEUE queue
,
80 POVS_OPEN_INSTANCE instance
)
82 PLIST_ENTRY link
, next
;
84 POVS_PACKET_QUEUE_ELEM elem
;
86 InitializeListHead(&tmp
);
87 NdisAcquireSpinLock(&queue
->queueLock
);
88 if (queue
->instance
!= instance
) {
89 NdisReleaseSpinLock(&queue
->queueLock
);
93 if (queue
->numPackets
) {
94 OvsAppendList(&tmp
, &queue
->packetList
);
95 queue
->numPackets
= 0;
97 NdisReleaseSpinLock(&queue
->queueLock
);
98 LIST_FORALL_SAFE(&tmp
, link
, next
) {
99 RemoveEntryList(link
);
100 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
107 OvsCleanupPacketQueue(POVS_OPEN_INSTANCE instance
)
109 POVS_USER_PACKET_QUEUE queue
;
110 POVS_PACKET_QUEUE_ELEM elem
;
111 PLIST_ENTRY link
, next
;
115 InitializeListHead(&tmp
);
116 queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
118 PDRIVER_CANCEL cancelRoutine
;
119 NdisAcquireSpinLock(&queue
->queueLock
);
120 if (queue
->instance
!= instance
) {
121 NdisReleaseSpinLock(&queue
->queueLock
);
125 if (queue
->numPackets
) {
126 OvsAppendList(&tmp
, &queue
->packetList
);
127 queue
->numPackets
= 0;
129 queue
->instance
= NULL
;
130 queue
->queueId
= OVS_MAX_NUM_PACKET_QUEUES
;
131 instance
->packetQueue
= NULL
;
132 irp
= queue
->pendingIrp
;
133 queue
->pendingIrp
= NULL
;
135 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
136 if (cancelRoutine
== NULL
) {
140 NdisReleaseSpinLock(&queue
->queueLock
);
142 LIST_FORALL_SAFE(&tmp
, link
, next
) {
143 RemoveEntryList(link
);
144 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
148 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
153 OvsSubscribeDpIoctl(PFILE_OBJECT fileObject
,
157 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
159 POVS_USER_PACKET_QUEUE queue
;
160 if (inputLength
< sizeof (UINT32
)) {
161 return STATUS_INVALID_PARAMETER
;
163 queueId
= *(UINT32
*)inputBuffer
;
164 if (instance
->packetQueue
&& queueId
>= OVS_MAX_NUM_PACKET_QUEUES
) {
168 OvsCleanupPacketQueue(instance
);
169 } else if (instance
->packetQueue
== NULL
&&
170 queueId
< OVS_MAX_NUM_PACKET_QUEUES
) {
171 queue
= &ovsPacketQueues
[queueId
];
172 NdisAcquireSpinLock(&queue
->queueLock
);
173 if (ovsPacketQueues
[queueId
].instance
) {
174 if (ovsPacketQueues
[queueId
].instance
!= instance
) {
175 NdisReleaseSpinLock(&queue
->queueLock
);
176 return STATUS_INSUFFICIENT_RESOURCES
;
178 NdisReleaseSpinLock(&queue
->queueLock
);
179 return STATUS_SUCCESS
;
182 queue
->queueId
= queueId
;
183 queue
->instance
= instance
;
184 instance
->packetQueue
= queue
;
185 ASSERT(IsListEmpty(&queue
->packetList
));
186 NdisReleaseSpinLock(&queue
->queueLock
);
188 return STATUS_INVALID_PARAMETER
;
190 return STATUS_SUCCESS
;
195 OvsReadDpIoctl(PFILE_OBJECT fileObject
,
200 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
201 POVS_PACKET_QUEUE_ELEM elem
;
204 #define TCP_CSUM_OFFSET 16
205 #define UDP_CSUM_OFFSET 6
208 if (instance
->packetQueue
== NULL
) {
209 return STATUS_INVALID_PARAMETER
;
211 if (outputLength
< (sizeof (OVS_PACKET_INFO
) + OVS_MIN_PACKET_SIZE
)) {
212 return STATUS_BUFFER_TOO_SMALL
;
215 elem
= OvsGetNextPacket(instance
);
218 * XXX revisit this later
220 len
= elem
->packet
.totalLen
> outputLength
? outputLength
:
221 elem
->packet
.totalLen
;
223 if ((elem
->hdrInfo
.tcpCsumNeeded
|| elem
->hdrInfo
.udpCsumNeeded
) &&
224 len
== elem
->packet
.totalLen
) {
226 UINT16 size
= (UINT16
)(elem
->packet
.userDataLen
+
227 elem
->hdrInfo
.l4Offset
+
228 (UINT16
)sizeof (OVS_PACKET_INFO
));
229 RtlCopyMemory(outputBuffer
, &elem
->packet
, size
);
230 ASSERT(len
- size
>= elem
->hdrInfo
.l4PayLoad
);
231 sum
= CopyAndCalculateChecksum((UINT8
*)outputBuffer
+ size
,
232 (UINT8
*)&elem
->packet
+ size
,
233 elem
->hdrInfo
.l4PayLoad
, 0);
234 ptr
=(UINT16
*)((UINT8
*)outputBuffer
+ size
+
235 (elem
->hdrInfo
.tcpCsumNeeded
?
236 TCP_CSUM_OFFSET
: UDP_CSUM_OFFSET
));
238 ovsUserStats
.l4Csum
++;
240 RtlCopyMemory(outputBuffer
, &elem
->packet
, len
);
246 return STATUS_SUCCESS
;
249 /* Helper function to allocate a Forwarding Context for an NBL */
251 OvsAllocateForwardingContextForNBL(POVS_SWITCH_CONTEXT switchContext
,
252 PNET_BUFFER_LIST nbl
)
254 return switchContext
->NdisSwitchHandlers
.
255 AllocateNetBufferListForwardingContext(
256 switchContext
->NdisSwitchContext
, nbl
);
260 * --------------------------------------------------------------------------
261 * This function allocates all the stuff necessary for creating an NBL from the
262 * input buffer of specified length, namely, a nonpaged data buffer of size
263 * length, an MDL from it, and a NB and NBL from it. It does not allocate an NBL
264 * context yet. It also copies data from the specified buffer to the NBL.
265 * --------------------------------------------------------------------------
268 OvsAllocateNBLForUserBuffer(POVS_SWITCH_CONTEXT switchContext
,
273 PNET_BUFFER_LIST nbl
= NULL
;
277 if (length
> OVS_DEFAULT_DATA_SIZE
) {
278 nbl
= OvsAllocateVariableSizeNBL(switchContext
, length
,
279 OVS_DEFAULT_HEADROOM_SIZE
);
282 nbl
= OvsAllocateFixSizeNBL(switchContext
, length
,
283 OVS_DEFAULT_HEADROOM_SIZE
);
289 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
290 mdl
= NET_BUFFER_CURRENT_MDL(nb
);
291 data
= (PUINT8
)MmGetSystemAddressForMdlSafe(mdl
, LowPagePriority
) +
292 NET_BUFFER_CURRENT_MDL_OFFSET(nb
);
294 OvsCompleteNBL(switchContext
, nbl
, TRUE
);
298 NdisMoveMemory(data
, userBuffer
, length
);
304 OvsExecuteDpIoctl(PVOID inputBuffer
,
308 NTSTATUS status
= STATUS_SUCCESS
;
310 OvsPacketExecute
*execute
;
311 LOCK_STATE_EX lockState
;
312 PNET_BUFFER_LIST pNbl
;
314 PNDIS_SWITCH_FORWARDING_DETAIL_NET_BUFFER_LIST_INFO fwdDetail
;
316 OVS_PACKET_HDR_INFO layers
;
317 POVS_VPORT_ENTRY vport
;
319 if (inputLength
< sizeof(*execute
) || outputLength
!= 0) {
320 return STATUS_INFO_LENGTH_MISMATCH
;
323 NdisAcquireSpinLock(gOvsCtrlLock
);
324 if (gOvsSwitchContext
== NULL
) {
325 status
= STATUS_INVALID_PARAMETER
;
329 execute
= (struct OvsPacketExecute
*) inputBuffer
;
331 if (execute
->packetLen
== 0) {
332 status
= STATUS_INVALID_PARAMETER
;
336 if (inputLength
!= sizeof (*execute
) +
337 execute
->actionsLen
+ execute
->packetLen
) {
338 status
= STATUS_INFO_LENGTH_MISMATCH
;
341 actions
= (PNL_ATTR
)((PCHAR
)&execute
->actions
+ execute
->packetLen
);
344 * Allocate the NBL, copy the data from the userspace buffer. Allocate
345 * also, the forwarding context for the packet.
347 pNbl
= OvsAllocateNBLForUserBuffer(gOvsSwitchContext
, &execute
->packetBuf
,
350 status
= STATUS_NO_MEMORY
;
354 fwdDetail
= NET_BUFFER_LIST_SWITCH_FORWARDING_DETAIL(pNbl
);
355 vport
= OvsFindVportByPortNo(gOvsSwitchContext
, execute
->inPort
);
357 fwdDetail
->SourcePortId
= vport
->portId
;
358 fwdDetail
->SourceNicIndex
= vport
->nicIndex
;
360 fwdDetail
->SourcePortId
= NDIS_SWITCH_DEFAULT_PORT_ID
;
361 fwdDetail
->SourceNicIndex
= 0;
363 // XXX: Figure out if any of the other members of fwdDetail need to be set.
365 ndisStatus
= OvsExtractFlow(pNbl
, fwdDetail
->SourcePortId
, &key
, &layers
,
367 if (ndisStatus
== NDIS_STATUS_SUCCESS
) {
368 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL
);
369 NdisAcquireRWLockRead(gOvsSwitchContext
->dispatchLock
, &lockState
,
370 NDIS_RWL_AT_DISPATCH_LEVEL
);
371 ndisStatus
= OvsActionsExecute(gOvsSwitchContext
, NULL
, pNbl
,
372 vport
? vport
->portNo
:
374 NDIS_SEND_FLAGS_SWITCH_DESTINATION_GROUP
,
375 &key
, NULL
, &layers
, actions
,
376 execute
->actionsLen
);
378 NdisReleaseRWLock(gOvsSwitchContext
->dispatchLock
, &lockState
);
380 if (ndisStatus
!= NDIS_STATUS_SUCCESS
) {
381 status
= STATUS_UNSUCCESSFUL
;
385 OvsCompleteNBL(gOvsSwitchContext
, pNbl
, TRUE
);
388 NdisReleaseSpinLock(gOvsCtrlLock
);
394 OvsPurgeDpIoctl(PFILE_OBJECT fileObject
)
396 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
397 POVS_USER_PACKET_QUEUE queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
400 return STATUS_INVALID_PARAMETER
;
402 OvsPurgePacketQueue(queue
, instance
);
403 return STATUS_SUCCESS
;
407 OvsCancelIrpDatapath(PDEVICE_OBJECT deviceObject
,
410 PIO_STACK_LOCATION irpSp
;
411 PFILE_OBJECT fileObject
;
412 POVS_OPEN_INSTANCE instance
;
413 POVS_USER_PACKET_QUEUE queue
= NULL
;
415 UNREFERENCED_PARAMETER(deviceObject
);
417 IoReleaseCancelSpinLock(irp
->CancelIrql
);
418 irpSp
= IoGetCurrentIrpStackLocation(irp
);
419 fileObject
= irpSp
->FileObject
;
421 if (fileObject
== NULL
) {
424 NdisAcquireSpinLock(gOvsCtrlLock
);
425 instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
427 queue
= instance
->packetQueue
;
429 if (instance
== NULL
|| queue
== NULL
) {
430 NdisReleaseSpinLock(gOvsCtrlLock
);
433 NdisReleaseSpinLock(gOvsCtrlLock
);
434 NdisAcquireSpinLock(&queue
->queueLock
);
435 if (queue
->pendingIrp
== irp
) {
436 queue
->pendingIrp
= NULL
;
438 NdisReleaseSpinLock(&queue
->queueLock
);
440 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
445 OvsWaitDpIoctl(PIRP irp
, PFILE_OBJECT fileObject
)
447 POVS_OPEN_INSTANCE instance
= (POVS_OPEN_INSTANCE
)fileObject
->FsContext
;
448 POVS_USER_PACKET_QUEUE queue
=
449 (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
450 NTSTATUS status
= STATUS_SUCCESS
;
451 BOOLEAN cancelled
= FALSE
;
454 return STATUS_INVALID_PARAMETER
;
456 NdisAcquireSpinLock(&queue
->queueLock
);
457 if (queue
->instance
!= instance
) {
458 NdisReleaseSpinLock(&queue
->queueLock
);
459 return STATUS_INVALID_PARAMETER
;
461 if (queue
->pendingIrp
) {
462 NdisReleaseSpinLock(&queue
->queueLock
);
463 return STATUS_DEVICE_BUSY
;
465 if (queue
->numPackets
== 0) {
466 PDRIVER_CANCEL cancelRoutine
;
467 IoMarkIrpPending(irp
);
468 IoSetCancelRoutine(irp
, OvsCancelIrpDatapath
);
470 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
475 queue
->pendingIrp
= irp
;
477 status
= STATUS_PENDING
;
479 NdisReleaseSpinLock(&queue
->queueLock
);
481 OvsCompleteIrpRequest(irp
, 0, STATUS_CANCELLED
);
482 OVS_LOG_INFO("Datapath IRP cancelled: %p", irp
);
488 POVS_PACKET_QUEUE_ELEM
489 OvsGetNextPacket(POVS_OPEN_INSTANCE instance
)
491 POVS_USER_PACKET_QUEUE queue
;
493 queue
= (POVS_USER_PACKET_QUEUE
)instance
->packetQueue
;
497 NdisAcquireSpinLock(&queue
->queueLock
);
498 if (queue
->instance
!= instance
|| queue
->numPackets
== 0) {
499 NdisReleaseSpinLock(&queue
->queueLock
);
502 link
= RemoveHeadList(&queue
->packetList
);
504 NdisReleaseSpinLock(&queue
->queueLock
);
505 return CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
509 POVS_USER_PACKET_QUEUE
510 OvsGetQueue(UINT32 queueId
)
512 POVS_USER_PACKET_QUEUE queue
;
513 if (queueId
>= OVS_MAX_NUM_PACKET_QUEUES
) {
516 queue
= &ovsPacketQueues
[queueId
];
517 return queue
->instance
!= NULL
? queue
: NULL
;
521 *----------------------------------------------------------------------------
522 * OvsCreateQueuePacket --
524 * Create a packet which will be forwarded to user space.
527 * queueId Identify the queue the packet to be inserted
528 * This will be used when multiple queues is supported
530 * userData: when cmd is user action, this field contain
532 * userDataLen: as name indicated
533 * cmd: either miss or user action
534 * inPort: datapath port id from which the packet is received.
535 * tunnelKey: tunnelKey for tunneled packet
536 * nbl: the NET_BUFFER_LIST which contain the packet
538 * isRecv: This is used to decide how to interprete the csum info
539 * hdrInfo: include hdr info initialized during flow extraction.
542 * NULL if fail to create the packet
543 * The packet element otherwise
544 *----------------------------------------------------------------------------
546 POVS_PACKET_QUEUE_ELEM
547 OvsCreateQueuePacket(UINT32 queueId
,
552 OvsIPv4TunnelKey
*tunnelKey
,
553 PNET_BUFFER_LIST nbl
,
556 POVS_PACKET_HDR_INFO hdrInfo
)
558 #define VLAN_TAG_SIZE 4
559 UINT32 allocLen
, dataLen
, extraLen
= 0;
560 POVS_PACKET_QUEUE_ELEM elem
;
563 NDIS_TCP_IP_CHECKSUM_NET_BUFFER_LIST_INFO csumInfo
;
564 NDIS_NET_BUFFER_LIST_8021Q_INFO vlanInfo
;
566 csumInfo
.Value
= NET_BUFFER_LIST_INFO(nbl
, TcpIpChecksumNetBufferListInfo
);
568 if (isRecv
&& (csumInfo
.Receive
.TcpChecksumFailed
||
569 (csumInfo
.Receive
.UdpChecksumFailed
&&
570 !hdrInfo
->udpCsumZero
) ||
571 csumInfo
.Receive
.IpChecksumFailed
)) {
572 OVS_LOG_INFO("Packet dropped due to checksum failure.");
573 ovsUserStats
.dropDuetoChecksum
++;
577 vlanInfo
.Value
= NET_BUFFER_LIST_INFO(nbl
, Ieee8021QNetBufferListInfo
);
578 if (vlanInfo
.TagHeader
.VlanId
) {
580 * We may also need to check priority XXX
582 extraLen
= VLAN_TAG_SIZE
;
585 dataLen
= NET_BUFFER_DATA_LENGTH(nb
);
586 allocLen
= sizeof (OVS_PACKET_QUEUE_ELEM
) + userDataLen
+ dataLen
+
589 elem
= (POVS_PACKET_QUEUE_ELEM
)OvsAllocateMemory(allocLen
);
591 ovsUserStats
.dropDuetoResource
++;
594 elem
->hdrInfo
.value
= hdrInfo
->value
;
595 elem
->packet
.totalLen
= sizeof (OVS_PACKET_INFO
) + userDataLen
+ dataLen
+
597 elem
->packet
.queue
= queueId
;
598 elem
->packet
.userDataLen
= userDataLen
;
599 elem
->packet
.inPort
= inPort
;
600 elem
->packet
.cmd
= cmd
;
601 if (cmd
== (UINT32
)OVS_PACKET_CMD_MISS
) {
604 ovsUserStats
.action
++;
606 elem
->packet
.packetLen
= dataLen
+ extraLen
;
608 RtlCopyMemory(&elem
->packet
.tunnelKey
, tunnelKey
,
609 sizeof (*tunnelKey
));
611 RtlZeroMemory(&elem
->packet
.tunnelKey
,
612 sizeof (elem
->packet
.tunnelKey
));
615 dst
= elem
->packet
.data
;
617 RtlCopyMemory(dst
, userData
, userDataLen
);
618 dst
= dst
+ userDataLen
;
622 mdl
= NET_BUFFER_CURRENT_MDL(nb
);
623 src
= NdisGetDataBuffer(nb
, dataLen
, dst
, 1, 0);
626 ovsUserStats
.dropDuetoResource
++;
628 } else if (src
!= dst
) {
629 /* Copy the data from the NDIS buffer to dst. */
630 RtlCopyMemory(dst
, src
, dataLen
);
633 dst
= elem
->packet
.data
+ userDataLen
+ extraLen
;
635 * Fix IP hdr if necessary
637 if ((isRecv
&& csumInfo
.Receive
.IpChecksumValueInvalid
) ||
638 (!isRecv
&& csumInfo
.Transmit
.IsIPv4
&&
639 csumInfo
.Transmit
.IpHeaderChecksum
)) {
640 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(dst
+ hdrInfo
->l3Offset
);
641 ASSERT(elem
->hdrInfo
.isIPv4
);
642 ASSERT(ipHdr
->Version
== 4);
643 ipHdr
->HeaderChecksum
= IPChecksum((UINT8
*)ipHdr
,
644 ipHdr
->HeaderLength
<< 2,
645 (UINT16
)~ipHdr
->HeaderChecksum
);
646 ovsUserStats
.ipCsum
++;
648 ASSERT(elem
->hdrInfo
.tcpCsumNeeded
== 0 &&
649 elem
->hdrInfo
.udpCsumNeeded
== 0);
651 * Fow now, we will not do verification
652 * There is no correctness issue here.
656 * calculate TCP/UDP pseudo checksum
658 if (isRecv
&& csumInfo
.Receive
.TcpChecksumValueInvalid
) {
660 * Only this case, we need to reclaculate pseudo checksum
661 * all other cases, it is assumed the pseudo checksum is
665 PTCP_HDR tcpHdr
= (PTCP_HDR
)(dst
+ hdrInfo
->l4Offset
);
666 if (hdrInfo
->isIPv4
) {
667 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(dst
+ hdrInfo
->l3Offset
);
668 elem
->hdrInfo
.l4PayLoad
= (UINT16
)(ntohs(ipHdr
->TotalLength
) -
669 (ipHdr
->HeaderLength
<< 2));
671 IPPseudoChecksum((UINT32
*)&ipHdr
->SourceAddress
,
672 (UINT32
*)&ipHdr
->DestinationAddress
,
673 IPPROTO_TCP
, elem
->hdrInfo
.l4PayLoad
);
675 PIPV6_HEADER ipv6Hdr
= (PIPV6_HEADER
)(dst
+ hdrInfo
->l3Offset
);
676 elem
->hdrInfo
.l4PayLoad
=
677 (UINT16
)(ntohs(ipv6Hdr
->PayloadLength
) +
678 hdrInfo
->l3Offset
+ sizeof(IPV6_HEADER
) -
680 ASSERT(hdrInfo
->isIPv6
);
682 IPv6PseudoChecksum((UINT32
*)&ipv6Hdr
->SourceAddress
,
683 (UINT32
*)&ipv6Hdr
->DestinationAddress
,
684 IPPROTO_TCP
, elem
->hdrInfo
.l4PayLoad
);
686 elem
->hdrInfo
.tcpCsumNeeded
= 1;
687 ovsUserStats
.recalTcpCsum
++;
688 } else if (!isRecv
) {
689 if (csumInfo
.Transmit
.TcpChecksum
) {
690 elem
->hdrInfo
.tcpCsumNeeded
= 1;
691 } else if (csumInfo
.Transmit
.UdpChecksum
) {
692 elem
->hdrInfo
.udpCsumNeeded
= 1;
694 if (elem
->hdrInfo
.tcpCsumNeeded
|| elem
->hdrInfo
.udpCsumNeeded
) {
698 elem
->hdrInfo
.tcpCsumNeeded
? IPPROTO_TCP
: IPPROTO_UDP
;
700 if (hdrInfo
->isIPv4
) {
701 PIPV4_HEADER ipHdr
= (PIPV4_HEADER
)(dst
+ hdrInfo
->l3Offset
);
702 elem
->hdrInfo
.l4PayLoad
= (UINT16
)(ntohs(ipHdr
->TotalLength
) -
703 (ipHdr
->HeaderLength
<< 2));
705 sum
= IPPseudoChecksum((UINT32
*)&ipHdr
->SourceAddress
,
706 (UINT32
*)&ipHdr
->DestinationAddress
,
707 proto
, elem
->hdrInfo
.l4PayLoad
);
710 PIPV6_HEADER ipv6Hdr
= (PIPV6_HEADER
)(dst
+
712 elem
->hdrInfo
.l4PayLoad
=
713 (UINT16
)(ntohs(ipv6Hdr
->PayloadLength
) +
714 hdrInfo
->l3Offset
+ sizeof(IPV6_HEADER
) -
716 ASSERT(hdrInfo
->isIPv6
);
718 sum
= IPv6PseudoChecksum((UINT32
*)&ipv6Hdr
->SourceAddress
,
719 (UINT32
*)&ipv6Hdr
->DestinationAddress
,
720 proto
, elem
->hdrInfo
.l4PayLoad
);
724 ptr
= (UINT16
*)(dst
+ hdrInfo
->l4Offset
+
725 (elem
->hdrInfo
.tcpCsumNeeded
?
726 TCP_CSUM_OFFSET
: UDP_CSUM_OFFSET
));
732 * Finally insert VLAN tag
735 dst
= elem
->packet
.data
+ userDataLen
;
736 src
= dst
+ extraLen
;
737 ((UINT32
*)dst
)[0] = ((UINT32
*)src
)[0];
738 ((UINT32
*)dst
)[1] = ((UINT32
*)src
)[1];
739 ((UINT32
*)dst
)[2] = ((UINT32
*)src
)[2];
741 ((UINT16
*)dst
)[0] = htons(0x8100);
742 ((UINT16
*)dst
)[1] = htons(vlanInfo
.TagHeader
.VlanId
|
743 (vlanInfo
.TagHeader
.UserPriority
<< 13));
744 elem
->hdrInfo
.l3Offset
+= VLAN_TAG_SIZE
;
745 elem
->hdrInfo
.l4Offset
+= VLAN_TAG_SIZE
;
746 ovsUserStats
.vlanInsert
++;
754 OvsQueuePackets(UINT32 queueId
,
755 PLIST_ENTRY packetList
,
758 POVS_USER_PACKET_QUEUE queue
= OvsGetQueue(queueId
);
759 POVS_PACKET_QUEUE_ELEM elem
;
764 OVS_LOG_LOUD("Enter: queueId %u, numELems: %u",
770 NdisAcquireSpinLock(&queue
->queueLock
);
771 if (queue
->instance
== NULL
) {
772 NdisReleaseSpinLock(&queue
->queueLock
);
775 OvsAppendList(&queue
->packetList
, packetList
);
776 queue
->numPackets
+= numElems
;
778 if (queue
->pendingIrp
) {
779 PDRIVER_CANCEL cancelRoutine
;
780 irp
= queue
->pendingIrp
;
781 queue
->pendingIrp
= NULL
;
782 cancelRoutine
= IoSetCancelRoutine(irp
, NULL
);
783 if (cancelRoutine
== NULL
) {
787 NdisReleaseSpinLock(&queue
->queueLock
);
789 OvsCompleteIrpRequest(irp
, 0, STATUS_SUCCESS
);
793 while (!IsListEmpty(packetList
)) {
794 link
= RemoveHeadList(packetList
);
795 elem
= CONTAINING_RECORD(link
, OVS_PACKET_QUEUE_ELEM
, link
);
799 OVS_LOG_LOUD("Exit: drop %u packets", num
);
804 *----------------------------------------------------------------------------
805 * OvsCreateAndAddPackets --
807 * Create a packet and forwarded to user space.
809 * This function would fragment packet if needed, and queue
810 * each segment to user space.
811 *----------------------------------------------------------------------------
814 OvsCreateAndAddPackets(UINT32 queueId
,
819 OvsIPv4TunnelKey
*tunnelKey
,
820 PNET_BUFFER_LIST nbl
,
822 POVS_PACKET_HDR_INFO hdrInfo
,
823 POVS_SWITCH_CONTEXT switchContext
,
827 POVS_PACKET_QUEUE_ELEM elem
;
828 PNET_BUFFER_LIST newNbl
= NULL
;
831 if (hdrInfo
->isTcp
) {
832 NDIS_TCP_LARGE_SEND_OFFLOAD_NET_BUFFER_LIST_INFO tsoInfo
;
835 tsoInfo
.Value
= NET_BUFFER_LIST_INFO(nbl
, TcpLargeSendNetBufferListInfo
);
836 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
837 packetLength
= NET_BUFFER_DATA_LENGTH(nb
);
839 OVS_LOG_TRACE("MSS %u packet len %u",
840 tsoInfo
.LsoV1Transmit
.MSS
, packetLength
);
841 if (tsoInfo
.LsoV1Transmit
.MSS
) {
842 OVS_LOG_TRACE("l4Offset %d", hdrInfo
->l4Offset
);
843 newNbl
= OvsTcpSegmentNBL(switchContext
, nbl
, hdrInfo
,
844 tsoInfo
.LsoV1Transmit
.MSS
, 0);
845 if (newNbl
== NULL
) {
846 return NDIS_STATUS_FAILURE
;
852 nb
= NET_BUFFER_LIST_FIRST_NB(nbl
);
854 elem
= OvsCreateQueuePacket(queueId
, userData
, userDataLen
,
855 cmd
, inPort
, tunnelKey
, nbl
, nb
,
858 InsertTailList(list
, &elem
->link
);
861 nb
= NET_BUFFER_NEXT_NB(nb
);
864 OvsCompleteNBL(switchContext
, newNbl
, TRUE
);
866 return NDIS_STATUS_SUCCESS
;