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.
22 #include "PacketParser.h"
27 #define OVS_DBG_MOD OVS_DBG_FLOW
30 #pragma warning( push )
31 #pragma warning( disable:4127 )
33 extern PNDIS_SPIN_LOCK gOvsCtrlLock;
34 extern POVS_SWITCH_CONTEXT gOvsSwitchContext;
35 extern UINT64 ovsTimeIncrementPerTick;
37 static NTSTATUS ReportFlowInfo(OvsFlow *flow, UINT32 getFlags,
38 UINT32 getActionsLen, OvsFlowInfo *info);
39 static NTSTATUS HandleFlowPut(OvsFlowPut *put,
40 OVS_DATAPATH *datapath,
41 struct OvsFlowStats *stats);
42 static NTSTATUS OvsPrepareFlow(OvsFlow **flow, const OvsFlowPut *put,
44 static VOID RemoveFlow(OVS_DATAPATH *datapath, OvsFlow **flow);
45 static VOID DeleteAllFlows(OVS_DATAPATH *datapath);
46 static NTSTATUS AddFlow(OVS_DATAPATH *datapath, OvsFlow *flow);
47 static VOID FreeFlow(OvsFlow *flow);
48 static VOID __inline *GetStartAddrNBL(const NET_BUFFER_LIST *_pNB);
50 #define OVS_FLOW_TABLE_SIZE 2048
51 #define OVS_FLOW_TABLE_MASK (OVS_FLOW_TABLE_SIZE -1)
52 #define HASH_BUCKET(hash) ((hash) & OVS_FLOW_TABLE_MASK)
55 *----------------------------------------------------------------------------
56 * OvsDeleteFlowTable --
58 * NDIS_STATUS_SUCCESS always.
59 *----------------------------------------------------------------------------
62 OvsDeleteFlowTable(OVS_DATAPATH *datapath)
64 if (datapath == NULL || datapath->flowTable == NULL) {
65 return NDIS_STATUS_SUCCESS;
68 DeleteAllFlows(datapath);
69 OvsFreeMemory(datapath->flowTable);
70 datapath->flowTable = NULL;
71 NdisFreeRWLock(datapath->lock);
73 return NDIS_STATUS_SUCCESS;
77 *----------------------------------------------------------------------------
78 * OvsAllocateFlowTable --
80 * NDIS_STATUS_SUCCESS on success.
81 * NDIS_STATUS_RESOURCES if memory couldn't be allocated
82 *----------------------------------------------------------------------------
85 OvsAllocateFlowTable(OVS_DATAPATH *datapath,
86 POVS_SWITCH_CONTEXT switchContext)
91 datapath->flowTable = OvsAllocateMemory(OVS_FLOW_TABLE_SIZE *
93 if (!datapath->flowTable) {
94 return NDIS_STATUS_RESOURCES;
96 for (i = 0; i < OVS_FLOW_TABLE_SIZE; i++) {
97 bucket = &(datapath->flowTable[i]);
98 InitializeListHead(bucket);
100 datapath->lock = NdisAllocateRWLock(switchContext->NdisFilterHandle);
102 return NDIS_STATUS_SUCCESS;
107 *----------------------------------------------------------------------------
109 * Get the virtual address of the frame.
112 * Virtual address of the frame.
113 *----------------------------------------------------------------------------
115 static __inline VOID *
116 GetStartAddrNBL(const NET_BUFFER_LIST *_pNB)
124 // Ethernet Header is a guaranteed safe access.
125 curMdl = (NET_BUFFER_LIST_FIRST_NB(_pNB))->CurrentMdl;
126 curBuffer = MmGetSystemAddressForMdlSafe(curMdl, LowPagePriority);
131 curHeader = (PEthHdr)
132 (curBuffer + (NET_BUFFER_LIST_FIRST_NB(_pNB))->CurrentMdlOffset);
134 return (VOID *) curHeader;
138 OvsFlowUsed(OvsFlow *flow,
139 const NET_BUFFER_LIST *packet,
140 const POVS_PACKET_HDR_INFO layers)
142 LARGE_INTEGER tickCount;
144 KeQueryTickCount(&tickCount);
145 flow->used = tickCount.QuadPart * ovsTimeIncrementPerTick;
147 flow->byteCount += OvsPacketLenNBL(packet);
148 flow->tcpFlags |= OvsGetTcpFlags(packet, &flow->key, layers);
153 DeleteAllFlows(OVS_DATAPATH *datapath)
158 for (i = 0; i < OVS_FLOW_TABLE_SIZE; i++) {
160 bucket = &(datapath->flowTable[i]);
161 while (!IsListEmpty(bucket)) {
163 next = bucket->Flink;
164 flow = CONTAINING_RECORD(next, OvsFlow, ListEntry);
165 RemoveFlow(datapath, &flow);
171 *----------------------------------------------------------------------------
172 * Initializes 'flow' members from 'packet', 'skb_priority', 'tun_id', and
175 * Initializes 'packet' header pointers as follows:
177 * - packet->l2 to the start of the Ethernet header.
179 * - packet->l3 to just past the Ethernet header, or just past the
180 * vlan_header if one is present, to the first byte of the payload of the
183 * - packet->l4 to just past the IPv4 header, if one is present and has a
184 * correct length, and otherwise NULL.
186 * - packet->l7 to just past the TCP or UDP or ICMP header, if one is
187 * present and has a correct length, and otherwise NULL.
189 * Returns NDIS_STATUS_SUCCESS normally. Fails only if packet data cannot be accessed
190 * (e.g. if Pkt_CopyBytesOut() returns an error).
191 *----------------------------------------------------------------------------
194 OvsExtractFlow(const NET_BUFFER_LIST *packet,
197 POVS_PACKET_HDR_INFO layers,
198 OvsIPv4TunnelKey *tunKey)
200 struct Eth_Header *eth;
207 ASSERT(tunKey->dst != 0);
208 RtlMoveMemory(&flow->tunKey, tunKey, sizeof flow->tunKey);
211 flow->tunKey.dst = 0;
212 flow->l2.offset = OVS_WIN_TUNNEL_KEY_SIZE;
215 flow->l2.inPort = inPort;
217 if ( OvsPacketLenNBL(packet) < ETH_HEADER_LEN_DIX) {
218 flow->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + 8 - flow->l2.offset;
219 return NDIS_STATUS_SUCCESS;
223 eth = (Eth_Header *)GetStartAddrNBL((NET_BUFFER_LIST *)packet);
224 memcpy(flow->l2.dlSrc, eth->src, ETH_ADDR_LENGTH);
225 memcpy(flow->l2.dlDst, eth->dst, ETH_ADDR_LENGTH);
230 vlanTagValue = NET_BUFFER_LIST_INFO(packet, Ieee8021QNetBufferListInfo);
232 PNDIS_NET_BUFFER_LIST_8021Q_INFO vlanTag =
233 (PNDIS_NET_BUFFER_LIST_8021Q_INFO)(PVOID *)&vlanTagValue;
234 flow->l2.vlanTci = htons(vlanTag->TagHeader.VlanId | OVSWIN_VLAN_CFI |
235 (vlanTag->TagHeader.UserPriority << 13));
237 if (eth->dix.typeNBO == ETH_TYPE_802_1PQ_NBO) {
238 Eth_802_1pq_Tag *tag= (Eth_802_1pq_Tag *)ð->dix.typeNBO;
239 flow->l2.vlanTci = ((UINT16)tag->priority << 13) |
241 ((UINT16)tag->vidHi << 8) | tag->vidLo;
242 offset = sizeof (Eth_802_1pq_Tag);
244 flow->l2.vlanTci = 0;
248 * Please note after this point, src mac and dst mac should
249 * not be accessed through eth
251 eth = (Eth_Header *)((UINT8 *)eth + offset);
257 * XXX assume that at least the first
258 * 12 bytes of received packets are mapped. This code has the stronger
259 * assumption that at least the first 22 bytes of 'packet' is mapped (if my
260 * arithmetic is right).
262 if (ETH_TYPENOT8023(eth->dix.typeNBO)) {
263 flow->l2.dlType = eth->dix.typeNBO;
264 layers->l3Offset = ETH_HEADER_LEN_DIX + offset;
265 } else if (OvsPacketLenNBL(packet) >= ETH_HEADER_LEN_802_3 &&
266 eth->e802_3.llc.dsap == 0xaa &&
267 eth->e802_3.llc.ssap == 0xaa &&
268 eth->e802_3.llc.control == ETH_LLC_CONTROL_UFRAME &&
269 eth->e802_3.snap.snapOrg[0] == 0x00 &&
270 eth->e802_3.snap.snapOrg[1] == 0x00 &&
271 eth->e802_3.snap.snapOrg[2] == 0x00) {
272 flow->l2.dlType = eth->e802_3.snap.snapType.typeNBO;
273 layers->l3Offset = ETH_HEADER_LEN_802_3 + offset;
275 flow->l2.dlType = htons(OVSWIN_DL_TYPE_NONE);
276 layers->l3Offset = ETH_HEADER_LEN_DIX + offset;
279 flow->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + OVS_L2_KEY_SIZE - flow->l2.offset;
281 if (flow->l2.dlType == htons(ETH_TYPE_IPV4)) {
282 struct IPHdr ip_storage;
283 const struct IPHdr *nh;
284 IpKey *ipKey = &flow->ipKey;
286 flow->l2.keyLen += OVS_IP_KEY_SIZE;
288 nh = OvsGetIp(packet, layers->l3Offset, &ip_storage);
290 layers->l4Offset = layers->l3Offset + nh->ihl * 4;
292 ipKey->nwSrc = nh->saddr;
293 ipKey->nwDst = nh->daddr;
294 ipKey->nwProto = nh->protocol;
296 ipKey->nwTos = nh->tos;
297 if (nh->frag_off & htons(IP_MF | IP_OFFSET)) {
298 ipKey->nwFrag = OVSWIN_NW_FRAG_ANY;
299 if (nh->frag_off & htons(IP_OFFSET)) {
300 ipKey->nwFrag |= OVSWIN_NW_FRAG_LATER;
306 ipKey->nwTtl = nh->ttl;
310 if (!(nh->frag_off & htons(IP_OFFSET))) {
311 if (ipKey->nwProto == SOCKET_IPPROTO_TCP) {
312 OvsParseTcp(packet, &ipKey->l4, layers);
313 } else if (ipKey->nwProto == SOCKET_IPPROTO_UDP) {
314 OvsParseUdp(packet, &ipKey->l4, layers);
315 } else if (ipKey->nwProto == SOCKET_IPPROTO_ICMP) {
319 icmp = OvsGetIcmp(packet, layers->l4Offset, &icmpStorage);
321 ipKey->l4.tpSrc = htons(icmp->type);
322 ipKey->l4.tpDst = htons(icmp->code);
323 layers->l7Offset = layers->l4Offset + sizeof *icmp;
328 ((UINT64 *)ipKey)[0] = 0;
329 ((UINT64 *)ipKey)[1] = 0;
331 } else if (flow->l2.dlType == htons(ETH_TYPE_IPV6)) {
333 flow->l2.keyLen += OVS_IPV6_KEY_SIZE;
334 status = OvsParseIPv6(packet, flow, layers);
335 if (status != NDIS_STATUS_SUCCESS) {
336 memset(&flow->ipv6Key, 0, sizeof (Ipv6Key));
340 flow->ipv6Key.l4.tpSrc = 0;
341 flow->ipv6Key.l4.tpDst = 0;
342 flow->ipv6Key.pad = 0;
344 if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_TCP) {
345 OvsParseTcp(packet, &(flow->ipv6Key.l4), layers);
346 } else if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_UDP) {
347 OvsParseUdp(packet, &(flow->ipv6Key.l4), layers);
348 } else if (flow->ipv6Key.nwProto == SOCKET_IPPROTO_ICMPV6) {
349 OvsParseIcmpV6(packet, flow, layers);
350 flow->l2.keyLen += (OVS_ICMPV6_KEY_SIZE - OVS_IPV6_KEY_SIZE);
352 } else if (flow->l2.dlType == htons(ETH_TYPE_ARP)) {
355 ArpKey *arpKey = &flow->arpKey;
356 ((UINT64 *)arpKey)[0] = 0;
357 ((UINT64 *)arpKey)[1] = 0;
358 ((UINT64 *)arpKey)[2] = 0;
359 flow->l2.keyLen += OVS_ARP_KEY_SIZE;
360 arp = OvsGetArp(packet, layers->l3Offset, &arpStorage);
361 if (arp && arp->ea_hdr.ar_hrd == htons(1) &&
362 arp->ea_hdr.ar_pro == htons(ETH_TYPE_IPV4) &&
363 arp->ea_hdr.ar_hln == ETH_ADDR_LENGTH &&
364 arp->ea_hdr.ar_pln == 4) {
365 /* We only match on the lower 8 bits of the opcode. */
366 if (ntohs(arp->ea_hdr.ar_op) <= 0xff) {
367 arpKey->nwProto = (UINT8)ntohs(arp->ea_hdr.ar_op);
369 if (arpKey->nwProto == ARPOP_REQUEST
370 || arpKey->nwProto == ARPOP_REPLY) {
371 memcpy(&arpKey->nwSrc, arp->arp_spa, 4);
372 memcpy(&arpKey->nwDst, arp->arp_tpa, 4);
373 memcpy(arpKey->arpSha, arp->arp_sha, ETH_ADDR_LENGTH);
374 memcpy(arpKey->arpTha, arp->arp_tha, ETH_ADDR_LENGTH);
379 return NDIS_STATUS_SUCCESS;
383 FlowEqual(UINT64 *src, UINT64 *dst, UINT32 size)
386 ASSERT((size & 0x7) == 0);
387 ASSERT(((UINT64)src & 0x7) == 0);
388 ASSERT(((UINT64)dst & 0x7) == 0);
389 for (i = 0; i < (size >> 3); i++) {
390 if (src[i] != dst[i]) {
399 * ----------------------------------------------------------------------------
401 * Add a flow to flow table.
404 * NDIS_STATUS_SUCCESS if no same flow in the flow table.
405 * ----------------------------------------------------------------------------
408 AddFlow(OVS_DATAPATH *datapath, OvsFlow *flow)
412 if (OvsLookupFlow(datapath, &flow->key, &flow->hash, TRUE) != NULL) {
413 return STATUS_INVALID_HANDLE;
416 head = &(datapath->flowTable[HASH_BUCKET(flow->hash)]);
418 * We need fence here to make sure flow's nextPtr is updated before
419 * head->nextPtr is updated.
423 //KeAcquireSpinLock(&FilterDeviceExtension->NblQueueLock, &oldIrql);
424 InsertTailList(head, &flow->ListEntry);
425 //KeReleaseSpinLock(&FilterDeviceExtension->NblQueueLock, oldIrql);
429 return STATUS_SUCCESS;
433 /* ----------------------------------------------------------------------------
435 * Remove a flow from flow table, and added to wait list
436 * ----------------------------------------------------------------------------
439 RemoveFlow(OVS_DATAPATH *datapath,
444 UNREFERENCED_PARAMETER(datapath);
446 ASSERT(datapath->nFlows);
448 // Remove the flow from queue
449 RemoveEntryList(&f->ListEntry);
455 * ----------------------------------------------------------------------------
458 * Find flow from flow table based on flow key.
459 * Caller should either hold portset handle or should
460 * have a flowRef in datapath or Acquired datapath.
463 * Flow pointer if lookup successful.
464 * NULL if not exists.
465 * ----------------------------------------------------------------------------
468 OvsLookupFlow(OVS_DATAPATH *datapath,
469 const OvsFlowKey *key,
473 PLIST_ENTRY link, head;
474 UINT16 offset = key->l2.offset;
475 UINT16 size = key->l2.keyLen;
478 ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey));
479 ASSERT(!key->tunKey.dst || offset == 0);
481 start = (UINT8 *)key + offset;
484 *hash = OvsJhashBytes(start, size, 0);
487 head = &datapath->flowTable[HASH_BUCKET(*hash)];
489 while (link != head) {
490 OvsFlow *flow = CONTAINING_RECORD(link, OvsFlow, ListEntry);
492 if (flow->hash == *hash &&
493 flow->key.l2.val == key->l2.val &&
494 FlowEqual((UINT64 *)((uint8 *)&flow->key + offset),
495 (UINT64 *)start, size)) {
505 * ----------------------------------------------------------------------------
507 * Calculate the hash for the given flow key.
508 * ----------------------------------------------------------------------------
511 OvsHashFlow(const OvsFlowKey *key)
513 UINT16 offset = key->l2.offset;
514 UINT16 size = key->l2.keyLen;
517 ASSERT(key->tunKey.dst || offset == sizeof (OvsIPv4TunnelKey));
518 ASSERT(!key->tunKey.dst || offset == 0);
519 start = (UINT8 *)key + offset;
520 return OvsJhashBytes(start, size, 0);
525 * ----------------------------------------------------------------------------
527 * Free a flow and its actions.
528 * ----------------------------------------------------------------------------
531 FreeFlow(OvsFlow *flow)
538 OvsDoDumpFlows(OvsFlowDumpInput *dumpInput,
539 OvsFlowDumpOutput *dumpOutput,
543 OVS_DATAPATH *datapath = NULL;
545 PLIST_ENTRY node, head;
547 UINT32 rowIndex, columnIndex;
548 LOCK_STATE_EX dpLockState;
549 NTSTATUS status = STATUS_SUCCESS;
550 BOOLEAN findNextNonEmpty = FALSE;
552 dpNo = dumpInput->dpNo;
553 NdisAcquireSpinLock(gOvsCtrlLock);
554 if (gOvsSwitchContext == NULL ||
555 gOvsSwitchContext->dpNo != dpNo) {
556 status = STATUS_INVALID_PARAMETER;
560 rowIndex = dumpInput->position[0];
561 if (rowIndex >= OVS_FLOW_TABLE_SIZE) {
563 *replyLen = sizeof(*dumpOutput);
567 columnIndex = dumpInput->position[1];
569 datapath = &gOvsSwitchContext->datapath;
571 OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
573 head = &datapath->flowTable[rowIndex];
576 while (column < columnIndex) {
585 findNextNonEmpty = TRUE;
589 if (findNextNonEmpty) {
590 while (head == node) {
591 if (++rowIndex >= OVS_FLOW_TABLE_SIZE) {
595 head = &datapath->flowTable[rowIndex];
600 ASSERT(node != head);
601 ASSERT(rowIndex < OVS_FLOW_TABLE_SIZE);
603 flow = CONTAINING_RECORD(node, OvsFlow, ListEntry);
604 status = ReportFlowInfo(flow, dumpInput->getFlags, dumpInput->actionsLen,
607 if (status == STATUS_BUFFER_TOO_SMALL) {
608 dumpOutput->n = sizeof(OvsFlowDumpOutput) + flow->actionsLen;
609 *replyLen = sizeof(*dumpOutput);
611 dumpOutput->n = 1; //one flow reported.
612 *replyLen = sizeof(*dumpOutput) + dumpOutput->flow.actionsLen;
615 dumpOutput->position[0] = rowIndex;
616 dumpOutput->position[1] = ++columnIndex;
619 OvsReleaseDatapath(datapath, &dpLockState);
622 NdisReleaseSpinLock(gOvsCtrlLock);
627 OvsDumpFlowIoctl(PVOID inputBuffer,
633 OvsFlowDumpOutput *dumpOutput = (OvsFlowDumpOutput *)outputBuffer;
634 OvsFlowDumpInput *dumpInput = (OvsFlowDumpInput *)inputBuffer;
636 if (inputBuffer == NULL || outputBuffer == NULL) {
637 return STATUS_INVALID_PARAMETER;
640 if ((inputLength != sizeof(OvsFlowDumpInput))
641 || (outputLength != sizeof *dumpOutput + dumpInput->actionsLen)) {
642 return STATUS_INFO_LENGTH_MISMATCH;
645 return OvsDoDumpFlows(dumpInput, dumpOutput, replyLen);
649 ReportFlowInfo(OvsFlow *flow,
651 UINT32 getActionsLen,
654 NTSTATUS status = STATUS_SUCCESS;
656 if (getFlags & FLOW_GET_KEY) {
657 // always copy the tunnel key part
658 RtlCopyMemory(&info->key, &flow->key,
659 flow->key.l2.keyLen + flow->key.l2.offset);
662 if (getFlags & FLOW_GET_STATS) {
663 OvsFlowStats *stats = &info->stats;
664 stats->packetCount = flow->packetCount;
665 stats->byteCount = flow->byteCount;
666 stats->used = (UINT32)flow->used;
667 stats->tcpFlags = flow->tcpFlags;
670 if (getFlags & FLOW_GET_ACTIONS) {
671 if (flow->actionsLen == 0) {
672 info->actionsLen = 0;
673 } else if (flow->actionsLen > getActionsLen) {
674 info->actionsLen = 0;
675 status = STATUS_BUFFER_TOO_SMALL;
677 RtlCopyMemory(info->actions, flow->actions, flow->actionsLen);
678 info->actionsLen = flow->actionsLen;
686 OvsPutFlowIoctl(PVOID inputBuffer,
692 NTSTATUS status = STATUS_SUCCESS;
693 OVS_DATAPATH *datapath = NULL;
694 struct OvsFlowStats stats;
698 LOCK_STATE_EX dpLockState;
700 if ((inputLength < sizeof(OvsFlowPut)) || (inputBuffer == NULL)) {
701 return STATUS_INFO_LENGTH_MISMATCH;
704 if ((outputLength != sizeof(stats)) || (outputBuffer == NULL)) {
705 return STATUS_INFO_LENGTH_MISMATCH;
708 put = (OvsFlowPut *)inputBuffer;
709 if (put->actionsLen > 0) {
710 actionsLen = put->actionsLen;
714 if (inputLength != actionsLen + sizeof(*put)) {
715 return STATUS_INFO_LENGTH_MISMATCH;
719 NdisAcquireSpinLock(gOvsCtrlLock);
720 if (gOvsSwitchContext == NULL ||
721 gOvsSwitchContext->dpNo != dpNo) {
722 status = STATUS_INVALID_PARAMETER;
726 datapath = &gOvsSwitchContext->datapath;
728 RtlZeroMemory(&stats, sizeof(stats));
729 OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
730 status = HandleFlowPut(put, datapath, &stats);
731 OvsReleaseDatapath(datapath, &dpLockState);
733 if (status == STATUS_SUCCESS) {
734 // Copy stats to User mode app
735 NdisMoveMemory(outputBuffer, (PVOID)&stats, sizeof(stats));
736 *replyLen = sizeof stats;
740 NdisReleaseSpinLock(gOvsCtrlLock);
745 /* Handles flow add, modify as well as delete */
747 HandleFlowPut(OvsFlowPut *put,
748 OVS_DATAPATH *datapath,
749 struct OvsFlowStats *stats)
751 BOOLEAN mayCreate, mayModify, mayDelete;
754 NTSTATUS status = STATUS_SUCCESS;
756 mayCreate = (put->flags & OVSWIN_FLOW_PUT_CREATE) != 0;
757 mayModify = (put->flags & OVSWIN_FLOW_PUT_MODIFY) != 0;
758 mayDelete = (put->flags & OVSWIN_FLOW_PUT_DELETE) != 0;
760 if ((mayCreate || mayModify) == mayDelete) {
761 return STATUS_INVALID_PARAMETER;
764 KernelFlow = OvsLookupFlow(datapath, &put->key, &hash, FALSE);
767 return STATUS_INVALID_PARAMETER;
770 status = OvsPrepareFlow(&KernelFlow, put, hash);
771 if (status != STATUS_SUCCESS) {
772 FreeFlow(KernelFlow);
773 return STATUS_UNSUCCESSFUL;
776 status = AddFlow(datapath, KernelFlow);
777 if (status != STATUS_SUCCESS) {
778 FreeFlow(KernelFlow);
779 return STATUS_UNSUCCESSFUL;
782 /* Validate the flow addition */
785 OvsFlow *flow = OvsLookupFlow(datapath, &put->key, &newHash,
788 ASSERT(newHash == hash);
789 if (!flow || newHash != hash) {
790 return STATUS_UNSUCCESSFUL;
794 stats->packetCount = KernelFlow->packetCount;
795 stats->byteCount = KernelFlow->byteCount;
796 stats->tcpFlags = KernelFlow->tcpFlags;
797 stats->used = (UINT32)KernelFlow->used;
801 status = OvsPrepareFlow(&newFlow, put, hash);
802 if (status != STATUS_SUCCESS) {
803 return STATUS_UNSUCCESSFUL;
806 KernelFlow = OvsLookupFlow(datapath, &put->key, &hash, TRUE);
808 if ((put->flags & OVSWIN_FLOW_PUT_CLEAR) == 0) {
809 newFlow->packetCount = KernelFlow->packetCount;
810 newFlow->byteCount = KernelFlow->byteCount;
811 newFlow->tcpFlags = KernelFlow->tcpFlags;
813 RemoveFlow(datapath, &KernelFlow);
815 if ((put->flags & OVSWIN_FLOW_PUT_CLEAR) == 0) {
816 newFlow->packetCount = stats->packetCount;
817 newFlow->byteCount = stats->byteCount;
818 newFlow->tcpFlags = stats->tcpFlags;
821 status = AddFlow(datapath, newFlow);
822 ASSERT(status == STATUS_SUCCESS);
824 /* Validate the flow addition */
827 OvsFlow *testflow = OvsLookupFlow(datapath, &put->key,
830 ASSERT(newHash == hash);
831 if (!testflow || newHash != hash) {
833 return STATUS_UNSUCCESSFUL;
839 RemoveFlow(datapath, &KernelFlow);
842 return STATUS_UNSUCCESSFUL;
846 return STATUS_SUCCESS;
850 OvsPrepareFlow(OvsFlow **flow,
851 const OvsFlowPut *put,
854 OvsFlow *localFlow = *flow;
855 NTSTATUS status = STATUS_SUCCESS;
859 OvsAllocateMemory(sizeof(OvsFlow) + put->actionsLen);
860 if (localFlow == NULL) {
861 status = STATUS_NO_MEMORY;
865 localFlow->key = put->key;
866 localFlow->actionsLen = put->actionsLen;
867 if (put->actionsLen) {
868 NdisMoveMemory((PUCHAR)localFlow->actions, put->actions,
871 localFlow->userActionsLen = 0; // 0 indicate no conversion is made
873 localFlow->packetCount = 0;
874 localFlow->byteCount = 0;
875 localFlow->tcpFlags = 0;
876 localFlow->hash = hash;
883 OvsGetFlowIoctl(PVOID inputBuffer,
889 NTSTATUS status = STATUS_SUCCESS;
890 OVS_DATAPATH *datapath = NULL;
892 UINT32 getFlags, getActionsLen;
893 OvsFlowGetInput *getInput;
894 OvsFlowGetOutput *getOutput;
897 LOCK_STATE_EX dpLockState;
899 if (inputLength != sizeof(OvsFlowGetInput)
900 || inputBuffer == NULL) {
901 return STATUS_INFO_LENGTH_MISMATCH;
904 getInput = (OvsFlowGetInput *) inputBuffer;
905 getFlags = getInput->getFlags;
906 getActionsLen = getInput->actionsLen;
907 if (getInput->getFlags & FLOW_GET_KEY) {
908 return STATUS_INVALID_PARAMETER;
911 if (outputBuffer == NULL
912 || outputLength != (sizeof *getOutput +
913 getInput->actionsLen)) {
914 return STATUS_INFO_LENGTH_MISMATCH;
917 dpNo = getInput->dpNo;
918 NdisAcquireSpinLock(gOvsCtrlLock);
919 if (gOvsSwitchContext == NULL ||
920 gOvsSwitchContext->dpNo != dpNo) {
921 status = STATUS_INVALID_PARAMETER;
925 datapath = &gOvsSwitchContext->datapath;
927 OvsAcquireDatapathRead(datapath, &dpLockState, FALSE);
928 flow = OvsLookupFlow(datapath, &getInput->key, &hash, FALSE);
930 status = STATUS_INVALID_PARAMETER;
934 // XXX: can be optimized to return only how much is written out
935 *replyLen = outputLength;
936 getOutput = (OvsFlowGetOutput *)outputBuffer;
937 ReportFlowInfo(flow, getFlags, getActionsLen, &getOutput->info);
940 OvsReleaseDatapath(datapath, &dpLockState);
942 NdisReleaseSpinLock(gOvsCtrlLock);
947 OvsFlushFlowIoctl(PVOID inputBuffer,
950 NTSTATUS status = STATUS_SUCCESS;
951 OVS_DATAPATH *datapath = NULL;
953 LOCK_STATE_EX dpLockState;
955 if (inputLength != sizeof(UINT32) || inputBuffer == NULL) {
956 return STATUS_INFO_LENGTH_MISMATCH;
959 dpNo = *(UINT32 *)inputBuffer;
960 NdisAcquireSpinLock(gOvsCtrlLock);
961 if (gOvsSwitchContext == NULL ||
962 gOvsSwitchContext->dpNo != dpNo) {
963 status = STATUS_INVALID_PARAMETER;
967 datapath = &gOvsSwitchContext->datapath;
969 OvsAcquireDatapathWrite(datapath, &dpLockState, FALSE);
970 DeleteAllFlows(datapath);
971 OvsReleaseDatapath(datapath, &dpLockState);
974 NdisReleaseSpinLock(gOvsCtrlLock);
978 #pragma warning( pop )