diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
index 04fc97f..1eb2be1 100644
--- a/datapath-windows/automake.mk
+++ b/datapath-windows/automake.mk
@@ -46,6 +46,7 @@ EXTRA_DIST += \
 	datapath-windows/ovsext/PacketIO.h \
 	datapath-windows/ovsext/PacketParser.c \
 	datapath-windows/ovsext/PacketParser.h \
+	datapath-windows/ovsext/Random.h \
 	datapath-windows/ovsext/Recirc.c \
 	datapath-windows/ovsext/Recirc.h \
 	datapath-windows/ovsext/Stt.c \
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c
index d3f9be4..f5b1410 100644
--- a/datapath-windows/ovsext/Actions.c
+++ b/datapath-windows/ovsext/Actions.c
@@ -24,6 +24,7 @@
 #include "NetProto.h"
 #include "Offload.h"
 #include "PacketIO.h"
+#include "Random.h"
 #include "Recirc.h"
 #include "Stt.h"
 #include "Switch.h"
@@ -1585,6 +1586,132 @@ OvsActionExecuteHash(OvsFlowKey *key,
         hash = 1;
 
     key->dpHash = hash;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsOutputUserspaceAction --
+ *      Executes a sample action.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsOutputUserspaceAction(OvsForwardingContext *ovsFwdCtx,
+                         OvsFlowKey *key,
+                         const PNL_ATTR attr)
+{
+    NTSTATUS status = NDIS_STATUS_SUCCESS;
+    PNL_ATTR userdataAttr;
+    PNL_ATTR queueAttr;
+    POVS_PACKET_QUEUE_ELEM elem;
+    POVS_PACKET_HDR_INFO layers = &ovsFwdCtx->layers;
+    BOOLEAN isRecv = FALSE;
+
+    POVS_VPORT_ENTRY vport = OvsFindVportByPortNo(ovsFwdCtx->switchContext,
+                                                  ovsFwdCtx->srcVportNo);
+
+    if (vport) {
+        if (vport->isExternal ||
+            OvsIsTunnelVportType(vport->ovsType)) {
+            isRecv = TRUE;
+        }
+    }
+
+    queueAttr = NlAttrFindNested(attr, OVS_USERSPACE_ATTR_PID);
+    userdataAttr = NlAttrFindNested(attr, OVS_USERSPACE_ATTR_USERDATA);
+
+    elem = OvsCreateQueueNlPacket(NlAttrData(userdataAttr),
+                                  NlAttrGetSize(userdataAttr),
+                                  OVS_PACKET_CMD_ACTION,
+                                  vport, key, ovsFwdCtx->curNbl,
+                                  NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx->curNbl),
+                                  isRecv,
+                                  layers);
+    if (elem) {
+        LIST_ENTRY missedPackets;
+        InitializeListHead(&missedPackets);
+        InsertTailList(&missedPackets, &elem->link);
+        OvsQueuePackets(&missedPackets, 1);
+    } else {
+        status = NDIS_STATUS_FAILURE;
+    }
+
+    return status;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ * OvsExecuteSampleAction --
+ *      Executes a sample action.
+ * --------------------------------------------------------------------------
+ */
+static __inline NDIS_STATUS
+OvsExecuteSampleAction(OvsForwardingContext *ovsFwdCtx,
+                       OvsFlowKey *key,
+                       UINT64 *hashAction,
+                       const PNL_ATTR attr)
+{
+    PNET_BUFFER_LIST newNbl = NULL;
+    PNL_ATTR actionsList = NULL;
+    PNL_ATTR a = NULL;
+    INT rem = 0;
+    UINT64 hash = 0;
+
+    SRand();
+    NL_ATTR_FOR_EACH_UNSAFE(a, rem, NlAttrData(attr), NlAttrGetSize(attr)) {
+        switch (NlAttrType(a)) {
+        case OVS_SAMPLE_ATTR_PROBABILITY:
+        {
+            UINT32 probability = NlAttrGetU32(a);
+
+            if (!probability || Rand() > probability) {
+                return 0;
+            }
+            break;
+        }
+        case OVS_SAMPLE_ATTR_ACTIONS:
+            actionsList = a;
+            break;
+        }
+    }
+
+    if (actionsList) {
+        rem = NlAttrGetSize(actionsList);
+        a = (PNL_ATTR)NlAttrData(actionsList);
+    }
+
+    if (!rem) {
+        /* Actions list is empty, do nothing */
+        return STATUS_SUCCESS;
+    }
+
+    /*
+     * The only known usage of sample action is having a single user-space
+     * action. Treat this usage as a special case.
+     */
+    if (NlAttrType(a) == OVS_ACTION_ATTR_USERSPACE &&
+        NlAttrIsLast(a, rem)) {
+        return OvsOutputUserspaceAction(ovsFwdCtx, key, a);
+    }
+
+    newNbl = OvsPartialCopyNBL(ovsFwdCtx->switchContext, ovsFwdCtx->curNbl,
+                               0, 0, TRUE /*copy NBL info*/);
+    if (newNbl == NULL) {
+        /*
+         * Skip the sample action when out of memory, but continue on with the
+         * rest of the action list.
+         */
+        ovsActionStats.noCopiedNbl++;
+        return STATUS_SUCCESS;
+    }
+
+    hash = hashAction ? *hashAction : OvsHashFlow(key);
+    if (!OvsAddDeferredActions(newNbl, key, hash, a)) {
+        OVS_LOG_INFO(
+            "Deferred actions limit reached, dropping sample action.");
+        OvsCompleteNBL(ovsFwdCtx->switchContext, newNbl, TRUE);
+    }
+
+    return STATUS_SUCCESS;
 }
 
 /*
@@ -1807,43 +1934,15 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
 
         case OVS_ACTION_ATTR_USERSPACE:
         {
-            PNL_ATTR userdataAttr;
-            PNL_ATTR queueAttr;
-            POVS_PACKET_QUEUE_ELEM elem;
-            BOOLEAN isRecv = FALSE;
-
-            POVS_VPORT_ENTRY vport = OvsFindVportByPortNo(switchContext,
-                portNo);
-
-            if (vport) {
-                if (vport->isExternal ||
-                    OvsIsTunnelVportType(vport->ovsType)) {
-                    isRecv = TRUE;
-                }
-            }
-
-            queueAttr = NlAttrFindNested(a, OVS_USERSPACE_ATTR_PID);
-            userdataAttr = NlAttrFindNested(a, OVS_USERSPACE_ATTR_USERDATA);
-
-            elem = OvsCreateQueueNlPacket((PVOID)userdataAttr,
-                                    userdataAttr->nlaLen,
-                                    OVS_PACKET_CMD_ACTION,
-                                    vport, key, ovsFwdCtx.curNbl,
-                                    NET_BUFFER_LIST_FIRST_NB(ovsFwdCtx.curNbl),
-                                    isRecv,
-                                    layers);
-            if (elem) {
-                LIST_ENTRY missedPackets;
-                InitializeListHead(&missedPackets);
-                InsertTailList(&missedPackets, &elem->link);
-                OvsQueuePackets(&missedPackets, 1);
-                dropReason = L"OVS-Completed since packet was copied to "
-                             L"userspace";
-            } else {
+            status = OvsOutputUserspaceAction(&ovsFwdCtx, key,
+                                              (const PNL_ATTR)a);
+            if (status != NDIS_STATUS_SUCCESS) {
                 dropReason = L"OVS-Dropped due to failure to queue to "
                              L"userspace";
                 goto dropit;
             }
+            dropReason = L"OVS-Completed since packet was copied to "
+                         L"userspace";
             break;
         }
         case OVS_ACTION_ATTR_SET:
@@ -1867,6 +1966,24 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext,
             break;
         }
         case OVS_ACTION_ATTR_SAMPLE:
+        {
+            if (ovsFwdCtx.destPortsSizeOut > 0 || ovsFwdCtx.tunnelTxNic != NULL
+                || ovsFwdCtx.tunnelRxNic != NULL) {
+                status = OvsOutputBeforeSetAction(&ovsFwdCtx);
+                if (status != NDIS_STATUS_SUCCESS) {
+                    dropReason = L"OVS-adding destination failed";
+                    goto dropit;
+                }
+            }
+
+            status = OvsExecuteSampleAction(&ovsFwdCtx, key, hash,
+                                            (const PNL_ATTR)a);
+            if (status != NDIS_STATUS_SUCCESS) {
+                dropReason = L"OVS-sample action failed";
+                goto dropit;
+            }
+            break;
+        }
         default:
             status = NDIS_STATUS_NOT_SUPPORTED;
             break;
diff --git a/datapath-windows/ovsext/Random.h b/datapath-windows/ovsext/Random.h
new file mode 100644
index 0000000..d8cc3d5
--- /dev/null
+++ b/datapath-windows/ovsext/Random.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Cloudbase Solutions Srl
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __RANDOM_H_
+#define __RANDOM_H_ 1
+
+#include "precomp.h"
+
+static LARGE_INTEGER seed;
+
+/*
+ *----------------------------------------------------------------------------
+ *  SRand --
+ *    This function sets the starting seed value for the pseudorandom number
+ *    generator.
+ *----------------------------------------------------------------------------
+ */
+static __inline
+VOID SRand()
+{
+    KeQuerySystemTime(&seed);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *  Rand --
+ *    This function generates a pseudorandom number between 0 to UINT_MAX.
+ *----------------------------------------------------------------------------
+ */
+static __inline
+UINT32 Rand()
+{
+    return seed.LowPart *= 0x8088405 + 1;
+}
+
+#endif /* __RANDOM_H_ */
diff --git a/datapath-windows/ovsext/ovsext.vcxproj b/datapath-windows/ovsext/ovsext.vcxproj
index 36187a6..2e697da 100644
--- a/datapath-windows/ovsext/ovsext.vcxproj
+++ b/datapath-windows/ovsext/ovsext.vcxproj
@@ -94,6 +94,7 @@
     <ClInclude Include="PacketIO.h" />
     <ClInclude Include="PacketParser.h" />
     <ClInclude Include="precomp.h" />
+    <ClInclude Include="Random.h" />
     <ClInclude Include="Recirc.h" />
     <ClInclude Include="resource.h" />
     <ClInclude Include="Stt.h" />
