[ovs-dev] [PATCH v3 2/3] dpif-windows: Implement datapath interface for windows.

Saurabh Shah ssaurabh at vmware.com
Sun Jul 27 23:53:53 UTC 2014


Co-Authored-By: Ankur Sharma <ankursharma at vmware.com>
Signed-off-by: Ankur Sharma <ankursharma at vmware.com>
Co-Authored-By: Eitan Eliahu <eliahue at vmware.com>
Signed-off-by: Eitan Eliahu <eliahue at vmware.com>
Co-Authored-By: Guolin Yang <gyang at vmware.com>
Signed-off-by: Guolin Yang <gyang at vmware.com>
Co-Authored-By: Linda Sun <lsun at vmware.com>
Signed-off-by: Linda Sun <lsun at vmware.com>
Co-Authored-By: Nithin Raju <nithin at vmware.com>
Signed-off-by: Nithin Raju <nithin at vmware.com>
Signed-off-by: Saurabh Shah <ssaurabh at vmware.com>
---
 AUTHORS                               |    3 +
 Makefile.am                           |    4 +-
 datapath-windows/automake.mk          |    3 +
 datapath-windows/include/OvsNetlink.h |  174 ++++
 datapath-windows/include/OvsPub.h     |  498 +++++++++
 include/linux/openvswitch.h           |    8 +-
 lib/automake.mk                       |    3 +
 lib/dpif-provider.h                   |    3 +
 lib/dpif-windows.c                    | 1786 +++++++++++++++++++++++++++++++++
 lib/dpif-windows.h                    |   58 ++
 lib/dpif.c                            |    3 +
 lib/netdev-provider.h                 |    3 +
 lib/netdev-windows.c                  |  714 +++++++++++++
 lib/netdev.c                          |    5 +
 lib/netlink-protocol.h                |    5 +
 lib/util.c                            |   16 +
 lib/util.h                            |    1 +
 17 files changed, 3285 insertions(+), 2 deletions(-)
 create mode 100644 datapath-windows/automake.mk
 create mode 100644 datapath-windows/include/OvsNetlink.h
 create mode 100644 datapath-windows/include/OvsPub.h
 create mode 100644 lib/dpif-windows.c
 create mode 100644 lib/dpif-windows.h
 create mode 100644 lib/netdev-windows.c

diff --git a/AUTHORS b/AUTHORS
index 64ede54..6f77eca 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,6 +13,7 @@ Andrew Lambeth          wal at nicira.com
 Andy Hill               hillad at gmail.com
 Andy Southgate          andy.southgate at citrix.com
 Andy Zhou               azhou at nicira.com
+Ankur Sharma            ankursharma at vmware.com
 Anoob Soman             anoob.soman at citrix.com
 Ansis Atteka            aatteka at nicira.com
 Anupam Chanda           achanda at nicira.com
@@ -46,6 +47,7 @@ Duffie Cooley           dcooley at nicira.com
 Ed Maste                emaste at freebsd.org
 Edouard Bourguignon     madko at linuxed.net
 Edward Tomasz Napierała trasz at freebsd.org
+Eitan Eliahu            eliahue at vmware.com
 Ethan Jackson           ethan at nicira.com
 Flavio Leitner          fbl at redhat.com
 Francesco Fusco         ffusco at redhat.com
@@ -93,6 +95,7 @@ Murphy McCauley         murphy.mccauley at gmail.com
 Natasha Gude            natasha at nicira.com
 Neil McKee              neil.mckee at inmon.com
 Neil Zhu                zhuj at centecnetworks.com
+Nithin Raju             nithin at vmware.com
 Padmanabhan Krishnan    kprad1 at yahoo.com
 Paraneetharan Chandrasekaran    paraneetharanc at gmail.com
 Paul Fazzone            pfazzone at nicira.com
diff --git a/Makefile.am b/Makefile.am
index d479c8b..26ce3d8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,7 @@ AM_LDFLAGS = $(SSL_LDFLAGS)
 
 if WIN32
 AM_CPPFLAGS += -I $(top_srcdir)/include/windows
+AM_CPPFLAGS += -I $(top_srcdir)/datapath-windows/include
 AM_CPPFLAGS += $(PTHREAD_INCLUDES)
 AM_LDFLAGS += $(PTHREAD_LDFLAGS)
 endif
@@ -197,7 +198,7 @@ config-h-check:
 	@cd $(srcdir); \
 	if test -e .git && (git --version) >/dev/null 2>&1 && \
 	   git --no-pager grep -L '#include <config\.h>' `git ls-files | grep '\.c$$' | \
-               grep -vE '^datapath|^lib/sflow|^third-party'`; \
+               grep -vE '^datapath|^lib/sflow|^third-party|^datapath-windows'`; \
 	then \
 	    echo "See above for list of violations of the rule that"; \
 	    echo "every C source file must #include <config.h>."; \
@@ -313,3 +314,4 @@ include python/automake.mk
 include python/compat/automake.mk
 include tutorial/automake.mk
 include vtep/automake.mk
+include datapath-windows/automake.mk
diff --git a/datapath-windows/automake.mk b/datapath-windows/automake.mk
new file mode 100644
index 0000000..8ed738c
--- /dev/null
+++ b/datapath-windows/automake.mk
@@ -0,0 +1,3 @@
+EXTRA_DIST += \
+	datapath-windows/include/OvsNetlink.h \
+	datapath-windows/include/OvsPub.h
diff --git a/datapath-windows/include/OvsNetlink.h b/datapath-windows/include/OvsNetlink.h
new file mode 100644
index 0000000..8a9fc55
--- /dev/null
+++ b/datapath-windows/include/OvsNetlink.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2013, 2014 Nicira, Inc.
+ *
+ * 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 __OVS_NETLINK_H_
+#define __OVS_NETLINK_H_ 1
+
+#include "lib/netlink-protocol.h"
+
+/* Returns X / Y, rounding up.  X must be nonnegative to round correctly. */
+#define DIV_ROUND_UP(X, Y) (((X) + ((Y) - 1)) / (Y))
+
+/* Returns X rounded up to the nearest multiple of Y. */
+#define ROUND_UP(X, Y) (DIV_ROUND_UP(X, Y) * (Y))
+
+static __inline int
+nl_attr_is_valid(const struct nlattr *nla, size_t maxlen)
+{
+    return (maxlen >= sizeof *nla
+            && nla->nla_len >= sizeof *nla
+            && nla->nla_len <= maxlen);
+}
+
+static __inline size_t
+nl_attr_len_pad(const struct nlattr *nla, size_t maxlen)
+{
+    size_t len = NLA_ALIGN(nla->nla_len);
+
+    return len <= maxlen ? len : nla->nla_len;
+}
+
+/* This macro is careful to check for attributes with bad lengths. */
+#define NL_ATTR_FOR_EACH(ITER, LEFT, ATTRS, ATTRS_LEN)                  \
+    for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN);                        \
+         nl_attr_is_valid(ITER, LEFT);                                  \
+         (LEFT) -= nl_attr_len_pad(ITER, LEFT), (ITER) = nl_attr_next(ITER))
+
+/* This macro does not check for attributes with bad lengths.  It should only
+ * be used with messages from trusted sources or with messages that have
+ * already been validated (e.g. with NL_ATTR_FOR_EACH).  */
+#define NL_ATTR_FOR_EACH_UNSAFE(ITER, LEFT, ATTRS, ATTRS_LEN)           \
+    for ((ITER) = (ATTRS), (LEFT) = (ATTRS_LEN);                        \
+         (LEFT) > 0;                                                    \
+         (LEFT) -= NLA_ALIGN((ITER)->nla_len), (ITER) = nl_attr_next(ITER))
+
+/* These were introduced all together in 2.6.24. */
+#ifndef NLA_TYPE_MASK
+#define NLA_F_NESTED        (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK       ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+#endif
+
+/* Netlink attribute iteration. */
+static __inline struct nlattr *
+nl_attr_next(const struct nlattr *nla)
+{
+    return (struct nlattr *) ((uint8_t *) nla + NLA_ALIGN(nla->nla_len));
+}
+
+ /* Returns the bits of 'nla->nla_type' that are significant for determining
+  * its type. */
+static __inline int
+nl_attr_type(const struct nlattr *nla)
+{
+   return nla->nla_type & NLA_TYPE_MASK;
+}
+
+static __inline void *
+nl_attr_data(const struct nlattr *nla)
+{
+    return ((char *)nla + NLA_HDRLEN);
+}
+
+/* Returns the number of bytes in the payload of attribute 'nla'. */
+static __inline uint32_t
+nl_attr_get_size(const struct nlattr *nla)
+{
+    return nla->nla_len - NLA_HDRLEN;
+}
+
+/* Returns the first byte in the payload of attribute 'nla'. */
+static __inline const void *
+nl_attr_get(const struct nlattr *nla)
+{
+    ASSERT(nla->nla_len >= NLA_HDRLEN);
+    return nla + 1;
+}
+
+#define NL_ATTR_GET_AS(NLA, TYPE) \
+        (*(TYPE*) nl_attr_get_unspec(nla, sizeof(TYPE)))
+
+/* Asserts that 'nla''s payload is at least 'size' bytes long, and returns the
+ * first byte of the payload. */
+static const void *
+nl_attr_get_unspec(const struct nlattr *nla, size_t size)
+{
+    DBG_UNREFERENCED_PARAMETER(size);
+    ASSERT(nla->nla_len >= NLA_HDRLEN + size);
+    return nla + 1;
+}
+
+/* Returns the 64-bit network byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 8 bytes long. */
+static __inline __be64
+nl_attr_get_be64(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, __be64);
+}
+
+/* Returns the 32-bit network byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 4 bytes long. */
+static __inline __be32
+nl_attr_get_be32(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, __be32);
+}
+
+/* Returns the 8-bit value in 'nla''s payload. */
+static __inline uint8_t
+nl_attr_get_u8(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, uint8_t);
+}
+
+
+/* Returns the 32-bit host byte order value in 'nla''s payload.
+ *
+ * Asserts that 'nla''s payload is at least 4 bytes long. */
+static __inline uint32_t
+nl_attr_get_u32(const struct nlattr *nla)
+{
+    return NL_ATTR_GET_AS(nla, uint32_t);
+}
+
+
+static __inline const struct nlattr *
+nl_attr_find__(const struct nlattr *attrs, size_t size, uint16_t type)
+{
+    const struct nlattr *nla;
+    size_t left;
+
+    NL_ATTR_FOR_EACH (nla, left, attrs, size) {
+        if (nl_attr_type(nla) == type) {
+            return nla;
+        }
+    }
+    return NULL;
+}
+
+/* Returns the first Netlink attribute within 'nla' with the specified
+ * 'type'.
+ *
+ * This function does not validate the attribute's length. */
+static __inline const struct nlattr *
+nl_attr_find_nested(const struct nlattr *nla, uint16_t type)
+{
+    return nl_attr_find__(nl_attr_get(nla), nl_attr_get_size(nla), type);
+}
+
+#endif /* __OVS_NETLINK_H_ */
diff --git a/datapath-windows/include/OvsPub.h b/datapath-windows/include/OvsPub.h
new file mode 100644
index 0000000..1282996
--- /dev/null
+++ b/datapath-windows/include/OvsPub.h
@@ -0,0 +1,498 @@
+/*
+ * Copyright (c) 2014 VMware, Inc.
+ *
+ * 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 __OVS_PUB_H_
+#define __OVS_PUB_H_ 1
+
+/* Needed by netlink-protocol.h */
+#define BUILD_ASSERT(EXPR) \
+      typedef char AssertOnCompileFailed[(EXPR) ? 1: -1]
+#define BUILD_ASSERT_DECL(EXPR) BUILD_ASSERT(EXPR)
+
+#include "OvsNetlink.h"
+
+#define OVS_DRIVER_MAJOR_VER 1
+#define OVS_DRIVER_MINOR_VER 0
+
+#define OVS_DEVICE_TYPE 45000
+#define OVS_IOCTL_TYPE  OVS_DEVICE_TYPE
+#define OVS_DP_NUMBER   ((uint32_t) 0)
+#define OVSWIN_DEVICE_NAME_MAX_LENGTH 32
+
+#define IFF_RUNNING 0x20
+#define IFF_PROMISC 0x40
+
+#define OVS_MAX_OPAQUE_NETWORK_ID_LEN 128
+
+#define OVS_NT_DEVICE_NAME     L"\\Device\\OvsIoctl"
+#define OVS_DOS_DEVICE_NAME    L"\\DosDevices\\OvsIoctl"
+#define OVS_USER_DEVICE_PATH   TEXT("\\\\.\\OvsIoctl")
+
+#define OVS_IOCTL_DP_START   0x100
+#define OVS_IOCTL_DP_DUMP \
+   CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DP_START + 0x0, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define OVS_IOCTL_DP_GET \
+   CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DP_START + 0x1, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_DP_SET \
+   CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DP_START + 0x2, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_DP_TIMESTAMP_SET \
+   CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DP_START + 0x3, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define OVS_IOCTL_VPORT_START 0x200
+#define OVS_IOCTL_VPORT_DUMP \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x0, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_VPORT_GET \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x1, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_VPORT_SET \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x2, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_VPORT_ADD \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x3, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_VPORT_DEL \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x4, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_VPORT_EXT_INFO \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_VPORT_START + 0x5, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+
+#define OVS_IOCTL_FLOW_START 0x300
+#define OVS_IOCTL_FLOW_DUMP \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_FLOW_START + 0x0, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_FLOW_GET \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_FLOW_START + 0x1, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+
+#define OVS_IOCTL_FLOW_PUT \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_FLOW_START + 0x2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define OVS_IOCTL_FLOW_FLUSH \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_FLOW_START + 0x3, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+
+#define OVS_IOCTL_QOS_START 0x400
+#define OVS_IOCTL_QOS_QUEUE_DUMP \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_QOS_START + 0x0, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_QOS_QUEUE_GET \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_QOS_START + 0x1, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_QOS_QUEUE_SET \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_QOS_START + 0x2, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+
+
+#define OVS_IOCTL_DATAPATH_START 0x500
+#define OVS_IOCTL_DATAPATH_SUBSCRIBE \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x0, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_DATAPATH_READ \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x1, METHOD_OUT_DIRECT, FILE_READ_ACCESS)
+#define OVS_IOCTL_DATAPATH_EXECUTE \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x2, METHOD_IN_DIRECT, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_DATAPATH_OPERATE \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x3, METHOD_IN_DIRECT, FILE_ANY_ACCESS)
+#define OVS_IOCTL_DATAPATH_PURGE \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x4, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define OVS_IOCTL_DATAPATH_WAIT \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_DATAPATH_START + 0x5, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+
+
+#define OVS_IOCTL_EVENT_START 0x600
+#define OVS_IOCTL_EVENT_SUBSCRIBE \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_EVENT_START + 0x0, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+#define OVS_IOCTL_EVENT_POLL \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_EVENT_START + 0x1, METHOD_OUT_DIRECT, FILE_ANY_ACCESS)
+#define OVS_IOCTL_EVENT_WAIT \
+    CTL_CODE (OVS_DEVICE_TYPE, OVS_IOCTL_EVENT_START + 0x2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#define OVS_IOCTL_VERSION_START 0x700
+#define OVS_IOCTL_VERSION_GET \
+    CTL_CODE(OVS_DEVICE_TYPE, OVS_IOCTL_VERSION_START + 0x0, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+typedef __declspec(align(8)) uint64_t Ovs64AlignedU64;
+typedef __declspec(align(8)) ovs_be64 Ovs64AlignedBe64;
+#pragma pack(push, 1)
+
+
+typedef struct _OVS_DP_INFO {
+    char name[128];
+    uint32_t dpNo;
+    uint32_t queue;
+    Ovs64AlignedU64 nHit;
+    Ovs64AlignedU64 nMissed;
+    Ovs64AlignedU64 nLost;
+    Ovs64AlignedU64 nFlows;
+} OVS_DP_INFO, *POVS_DP_INFO;
+
+
+typedef struct _OVS_VERSION {
+    uint8_t mjrDrvVer;
+    uint8_t mnrDrvVer;
+} OVS_VERSION, *POVS_VERSION;
+
+
+
+#define OVS_MAX_PORT_NAME_LENGTH 32
+
+typedef struct _OVS_VPORT_GET {
+    uint32_t dpNo;
+    uint32_t portNo;
+    char     name[OVS_MAX_PORT_NAME_LENGTH];
+} OVS_VPORT_GET, *POVS_VPORT_GET;
+
+
+typedef enum {
+    OVSWIN_VPORT_TYPE_UNKNOWN,
+    OVSWIN_VPORT_TYPE_RESERVED,
+    OVSWIN_VPORT_TYPE_EXTERNAL,
+    OVSWIN_VPORT_TYPE_INTERNAL,
+    OVSWIN_VPORT_TYPE_SYNTHETIC,
+    OVSWIN_VPORT_TYPE_EMULATED,
+    OVSWIN_VPORT_TYPE_GRE,
+    OVSWIN_VPORT_TYPE_GRE64,
+    OVSWIN_VPORT_TYPE_VXLAN,
+    OVSWIN_VPORT_TYPE_LOCAL,    /* For bridge local port. */
+} OVS_VPORT_TYPE;
+
+static __inline const char *
+OvsVportTypeToStr(OVS_VPORT_TYPE t)
+{
+    switch(t) {
+#define STR(t) case OVSWIN_VPORT_TYPE_##t : return "VPORT_##t";
+    STR(UNKNOWN)
+    STR(EXTERNAL)
+    STR(INTERNAL)
+    STR(SYNTHETIC)
+    STR(EMULATED)
+    STR(GRE)
+    STR(GRE64)
+    STR(VXLAN)
+    STR(LOCAL)
+    }
+#undef STR
+
+    return "Invalid type";
+}
+
+#define MAC_ADDRESS_LEN 6
+
+typedef struct _OVS_VPORT_INFO {
+    uint32_t dpNo;
+    uint32_t portNo;
+    char name[OVS_MAX_PORT_NAME_LENGTH];
+    uint32_t type;
+    uint32_t queue;
+
+    Ovs64AlignedU64 rxPackets;
+    Ovs64AlignedU64 txPackets;
+    Ovs64AlignedU64 rxBytes;
+    Ovs64AlignedU64 txBytes;
+    Ovs64AlignedU64 rxErrors;
+    Ovs64AlignedU64 txErrors;
+    Ovs64AlignedU64 rxDropped;
+    Ovs64AlignedU64 txDropped;
+
+    uint8_t macAddress[MAC_ADDRESS_LEN];
+    uint16_t pad;
+} OVS_VPORT_INFO, *POVS_VPORT_INFO;
+
+typedef struct _OVS_VPORT_ADD_REQUEST {
+    uint32_t dpNo;
+    uint32_t type;
+    char name[OVS_MAX_PORT_NAME_LENGTH];
+    uint16_t dstPort;
+    uint16_t pad[3];
+} OVS_VPORT_ADD_REQUEST, *POVS_VPORT_ADD_REQUEST;
+
+
+typedef struct _OVS_VPORT_DELETE_REQUEST {
+    uint32_t dpNo;
+    uint32_t portNo;
+    char name[OVS_MAX_PORT_NAME_LENGTH];
+} OVS_VPORT_DELETE_REQUEST, *POVS_VPORT_DELETE_REQUEST;
+
+
+#define OVS_MAX_VM_UUID_LEN 128
+#define OVS_MAX_VIF_UUID_LEN 128
+
+typedef struct _OVS_VPORT_EXT_INFO {
+    uint32_t dpNo;
+    uint32_t portNo;
+    uint8_t macAddress[MAC_ADDRESS_LEN];
+    uint8_t permMACAddress[MAC_ADDRESS_LEN];
+    uint8_t vmMACAddress[MAC_ADDRESS_LEN];
+    uint16_t nicIndex;
+    uint32_t portId;
+    uint32_t type;
+    uint32_t mtu;
+    char name[OVS_MAX_PORT_NAME_LENGTH];
+    uint32_t status;
+    char vmUUID[OVS_MAX_VM_UUID_LEN];
+    char vifUUID[OVS_MAX_VIF_UUID_LEN];
+} OVS_VPORT_EXT_INFO, *POVS_VPORT_EXT_INFO;
+
+
+/* Flows. */
+#define OVSWIN_VLAN_CFI 0x1000
+#define OVSWIN_INPORT_INVALID 0xffffffff
+
+/* Used for OvsFlowKey's dlType member for frames that have no Ethernet type,
+ * that is, pure 802.2 frames. */
+#define OVSWIN_DL_TYPE_NONE 0x5ff
+
+/* Fragment bits, used for IPv4 and IPv6, always zero for non-IP flows. */
+#define OVSWIN_NW_FRAG_ANY   (1 << 0)   /* Set for any IP frag. */
+#define OVSWIN_NW_FRAG_LATER (1 << 1)   /* Set for IP frag with nonzero
+                                         * offset. */
+#define OVSWIN_NW_FRAG_MASK  (OVSWIN_NW_FRAG_ANY | OVSWIN_NW_FRAG_LATER)
+
+typedef struct L4Key {
+    ovs_be16 tpSrc;              /* TCP/UDP/SCTP source port. */
+    ovs_be16 tpDst;              /* TCP/UDP/SCTP destination port. */
+} L4Key;
+
+typedef struct Ipkey {
+    ovs_be32 nwSrc;              /* IPv4 source address. */
+    ovs_be32 nwDst;              /* IPv4 destination address. */
+    uint8_t nwProto;             /* IP protocol or low 8 bits of ARP opcode. */
+    uint8_t nwTos;               /* IP ToS (including DSCP and ECN). */
+    uint8_t nwTtl;               /* IP TTL/Hop Limit. */
+    uint8_t nwFrag;              /* FLOW_FRAG_* flags. */
+    L4Key   l4;
+} IpKey;  /* Size of 16 byte. */
+
+typedef struct ArpKey {
+    ovs_be32 nwSrc;              /* IPv4 source address. */
+    ovs_be32 nwDst;              /* IPv4 destination address. */
+    uint8_t arpSha[6];           /* ARP/ND source hardware address. */
+    uint8_t arpTha[6];           /* ARP/ND target hardware address. */
+    uint8_t nwProto;             /* IP protocol or low 8 bits of ARP opcode. */
+    uint8_t pad[3];
+} ArpKey; /* Size of 24 byte. */
+
+typedef struct Ipv6Key {
+    struct in6_addr ipv6Src;     /* IPv6 source address. */
+    struct in6_addr ipv6Dst;     /* IPv6 destination address. */
+    ovs_be32 ipv6Label;          /* IPv6 flow label. */
+    uint8_t nwProto;             /* IP protocol or low 8 bits of ARP opcode. */
+    uint8_t nwTos;               /* IP ToS (including DSCP and ECN). */
+    uint8_t nwTtl;               /* IP TTL/Hop Limit. */
+    uint8_t nwFrag;              /* FLOW_FRAG_* flags. */
+    L4Key  l4;
+    uint32_t pad;
+} Ipv6Key;  /* Size of 48 byte. */
+
+typedef struct Icmp6Key {
+    struct in6_addr ipv6Src;     /* IPv6 source address. */
+    struct in6_addr ipv6Dst;     /* IPv6 destination address. */
+    ovs_be32 ipv6Label;          /* IPv6 flow label. */
+    uint8_t nwProto;             /* IP protocol or low 8 bits of ARP opcode. */
+    uint8_t nwTos;               /* IP ToS (including DSCP and ECN). */
+    uint8_t nwTtl;               /* IP TTL/Hop Limit. */
+    uint8_t nwFrag;              /* FLOW_FRAG_* flags. */
+    L4Key  l4;
+    uint8_t arpSha[6];           /* ARP/ND source hardware address. */
+    uint8_t arpTha[6];           /* ARP/ND target hardware address. */
+    struct in6_addr ndTarget;    /* IPv6 neighbor discovery (ND) target. */
+} Icmp6Key; /* Size of 72 byte. */
+
+typedef struct L2Key {
+    uint32_t inPort;             /* Port number of input port. */
+    union {
+        struct {
+            uint16_t offset;
+            uint16_t keyLen;
+        };
+        uint32_t val;
+    };
+    uint8_t dlSrc[6];            /* Ethernet source address. */
+    uint8_t dlDst[6];            /* Ethernet destination address. */
+    ovs_be16 vlanTci;            /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
+    ovs_be16 dlType;             /* Ethernet frame type. */
+} L2Key;  /* Size of 24 byte. */
+
+/* Number of packet attributes required to store OVS tunnel key. */
+#define NUM_PKT_ATTR_REQUIRED 3
+
+typedef union OvsIPv4TunnelKey {
+    struct {
+        ovs_be32 dst;
+        ovs_be32 src;
+        ovs_be64 tunnelId;
+        uint16_t flags;
+        uint8_t  tos;
+        uint8_t  ttl;
+        union {
+            uint32_t pad;
+            struct {
+                ovs_be16 dst_port;
+                uint16_t flow_hash;
+            };
+        };
+    };
+    uint64_t attr[NUM_PKT_ATTR_REQUIRED];
+} OvsIPv4TunnelKey;
+
+typedef __declspec(align(8)) struct OvsFlowKey {
+    OvsIPv4TunnelKey tunKey;     /* 24 bytes */
+    L2Key l2;                    /* 24 bytes */
+    union {
+        IpKey ipKey;             /* size 16 */
+        ArpKey arpKey;           /* size 24 */
+        Ipv6Key ipv6Key;         /* size 48 */
+        Icmp6Key icmp6Key;       /* size 72 */
+    };
+} OvsFlowKey;
+
+#define OVS_WIN_TUNNEL_KEY_SIZE (sizeof (OvsIPv4TunnelKey))
+#define OVS_L2_KEY_SIZE (sizeof (L2Key))
+#define OVS_IP_KEY_SIZE (sizeof (IpKey))
+#define OVS_IPV6_KEY_SIZE (sizeof (Ipv6Key))
+#define OVS_ARP_KEY_SIZE (sizeof (ArpKey))
+#define OVS_ICMPV6_KEY_SIZE (sizeof (Icmp6Key))
+
+typedef struct OvsFlowStats {
+    Ovs64AlignedU64 packetCount;
+    Ovs64AlignedU64 byteCount;
+    uint32_t used;
+    uint8_t tcpFlags;
+} OvsFlowStats;
+
+typedef struct OvsFlowInfo {
+    OvsFlowKey key;
+    struct OvsFlowStats stats;
+    uint32_t actionsLen;
+    struct nlattr actions[0];
+} OvsFlowInfo;
+
+enum GetFlags {
+    FLOW_GET_KEY =       0x00000001,
+    FLOW_GET_STATS =     0x00000010,
+    FLOW_GET_ACTIONS =   0x00000100,
+};
+
+typedef struct OvsFlowDumpInput {
+    uint32_t dpNo;
+    uint32_t position[2];   /* Offset hint to the start of flow dump. */
+                            /* 0 - index of the hash table.
+                             * 1 - nth element in the hash table index. */
+    uint32_t getFlags;      /* Information to get in addition to keys. */
+    uint32_t actionsLen;
+} OvsFlowDumpInput;
+
+
+typedef struct OvsFlowDumpOutput {
+    /* Hint for the next flow dump operation. */
+    uint32_t position[2];
+
+    /* #flows (currently 0 or 1). In case the buffer is too small to output all
+     * actions, this field indicates actual size needed to dump all actions. */
+    uint32_t n;
+
+    OvsFlowInfo flow;
+} OvsFlowDumpOutput;
+
+typedef struct OvsFlowGetInput {
+    uint32_t dpNo;
+    OvsFlowKey key;
+    uint32_t getFlags;           /* Information to get in addition to keys. */
+    uint32_t actionsLen;         /* Sizeof of buffer for actions. */
+} OvsFlowGetInput;
+
+typedef struct OvsFlowGetOutput {
+    OvsFlowInfo info;            /* Variable length. */
+} OvsFlowGetOutput;
+
+
+typedef enum OvsFlowPutFlags {
+    OVSWIN_FLOW_PUT_CREATE = 1 << 0,
+    OVSWIN_FLOW_PUT_MODIFY = 1 << 1,
+    OVSWIN_FLOW_PUT_DELETE = 1 << 2,
+
+    OVSWIN_FLOW_PUT_CLEAR = 1 << 3
+} OvsFlowPutFlags;
+
+
+typedef struct OvsFlowPut {
+    uint32_t dpNo;
+    uint32_t actionsLen;
+    OvsFlowKey key;
+    uint32_t flags;
+    struct nlattr  actions[0];  /* Variable length indicated by actionsLen. */
+} OvsFlowPut;
+
+#define OVS_MIN_PACKET_SIZE 60
+typedef struct _OVS_PACKET_INFO {
+    uint32_t totalLen;
+    uint32_t userDataLen;
+    uint32_t packetLen;
+    uint32_t queue;
+    uint32_t inPort;
+    uint32_t cmd;
+    OvsIPv4TunnelKey tunnelKey;
+    /* Includes user data defined as chain of netlink attributes followed by the
+     * packet data. */
+    uint8_t  data[0];
+} OVS_PACKET_INFO, *POVS_PACKET_INFO;
+
+typedef struct OvsPacketExecute {
+   uint32_t dpNo;
+   uint32_t inPort;
+
+   uint32_t packetLen;
+   uint32_t actionsLen;
+   union {
+       /* Variable size blob with packet data first, followed by action
+        * attrs. */
+       char packetBuf[0];
+       struct nlattr  actions[0];
+   };
+} OvsPacketExecute;
+
+
+typedef struct _OVS_EVENT_SUBSCRIBE {
+    uint32_t cookie;
+    uint32_t dpNo;
+    uint32_t subscribe;
+    uint32_t mask;
+} OVS_EVENT_SUBSCRIBE, *POVS_EVENT_SUBSCRIBE;
+
+typedef struct _OVS_EVENT_POLL {
+    uint32_t cookie;
+    uint32_t dpNo;
+} OVS_EVENT_POLL, *POVS_EVENT_POLL;
+
+enum {
+    OVS_EVENT_CONNECT       = ((uint32_t)0x1 << 0),
+    OVS_EVENT_DISCONNECT    = ((uint32_t)0x1 << 1),
+    OVS_EVENT_LINK_UP       = ((uint32_t)0x1 << 2),
+    OVS_EVENT_LINK_DOWN     = ((uint32_t)0x1 << 3),
+    OVS_EVENT_MAC_CHANGE    = ((uint32_t)0x1 << 4),
+    OVS_EVENT_MTU_CHANGE    = ((uint32_t)0x1 << 5),
+    OVS_EVENT_MASK_ALL      = 0x3f,
+};
+
+
+typedef struct _OVS_EVENT_ENTRY {
+    uint32_t portNo;
+    uint32_t status;
+} OVS_EVENT_ENTRY, *POVS_EVENT_ENTRY;
+
+#define OVS_DEFAULT_PORT_NO 0xffffffff
+#define OVS_DEFAULT_EVENT_STATUS  0xffffffff
+
+typedef struct _OVS_EVENT_STATUS {
+    uint32_t numberEntries;
+    OVS_EVENT_ENTRY eventEntries[0];
+} OVS_EVENT_STATUS, *POVS_EVENT_STATUS;
+
+#pragma pack(pop)
+
+#endif /* __OVS_PUB_H_ */
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index bf27dcb..03c5e32 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -40,8 +40,14 @@
 #ifndef _LINUX_OPENVSWITCH_H
 #define _LINUX_OPENVSWITCH_H 1
 
+#ifndef OVS_WIN_DP
+/*
+ * This file is included by the datapath in the Windows kernel. We need to be
+ * selective about header file inclusions.
+ */
 #include <linux/types.h>
 #include <linux/if_ether.h>
+#endif
 
 /**
  * struct ovs_header - header for OVS Generic Netlink messages.
@@ -323,7 +329,7 @@ enum ovs_key_attr {
 				 * The implementation may restrict
 				 * the accepted length of the array. */
 
-#ifdef __KERNEL__
+#if defined(__KERNEL__) || defined(_WIN32)
 	/* Only used within kernel data path. */
 	OVS_KEY_ATTR_TUNNEL_INFO,  /* struct ovs_tunnel_info */
 #endif
diff --git a/lib/automake.mk b/lib/automake.mk
index 0997df5..e947baa 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -252,9 +252,12 @@ lib_libopenvswitch_la_SOURCES = \
 
 if WIN32
 lib_libopenvswitch_la_SOURCES += \
+	lib/dpif-windows.c \
+	lib/dpif-windows.h \
 	lib/daemon-windows.c \
 	lib/getopt_long.c \
 	lib/getrusage-windows.c \
+	lib/netdev-windows.c \
 	lib/latch-windows.c \
 	lib/route-table-stub.c \
 	lib/strsep.c \
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index b762ac0..12d4d81 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -401,6 +401,9 @@ struct dpif_class {
 };
 
 extern const struct dpif_class dpif_linux_class;
+#ifdef _WIN32
+extern const struct dpif_class dpif_windows_class;
+#endif
 extern const struct dpif_class dpif_netdev_class;
 
 #ifdef  __cplusplus
diff --git a/lib/dpif-windows.c b/lib/dpif-windows.c
new file mode 100644
index 0000000..ca784ec
--- /dev/null
+++ b/lib/dpif-windows.c
@@ -0,0 +1,1786 @@
+/*
+ * Copyright (c) 2014 VMware, Inc.
+ *
+ * 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.
+ */
+
+#include <config.h>
+
+#include "dpif-windows.h"
+#include <unistd.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <sys/ioctl.h>
+#include "byte-order.h"
+#include "openvswitch/types.h"
+#include "dpif-provider.h"
+#include "netdev-provider.h"
+#include "OvsPub.h"
+#include "flow.h"
+#include "odp-util.h"
+#include "ofpbuf.h"
+#include "packets.h"
+#include "sset.h"
+#include "type-props.h"
+#include "poll-loop.h"
+#include "netdev-vport.h"
+#include "vlog.h"
+#include "dynamic-string.h"
+#include "util.h"
+
+VLOG_DEFINE_THIS_MODULE(dpif_windows);
+
+/* Datapath interface for the openvswitch Windows kernel module. */
+struct dpif_windows {
+    struct dpif dpif;
+    uint32_t dp_no;
+
+    struct ovs_mutex upcall_lock;
+    struct hmap ports_tbl;
+    /* Change notification. */
+    struct sset changed_ports;  /* Ports that have changed. */
+    bool new_poll;
+};
+
+struct dpif_windows_datapath_port {
+    struct hmap_node node;
+    uint32_t port_num;
+    uint32_t type;
+    char port_name[OVSWIN_DEVICE_NAME_MAX_LENGTH];
+};
+
+enum { MAX_ACTIONS = 65536 };
+static char *systemType = "system";
+
+static void output_dpif_flow_stats(struct dpif_flow_stats *dst,
+                                   const struct OvsFlowStats *src);
+
+/* We keep separate handles for packet receive and event handling.
+ * They might or might not reside on the same thread. */
+/* Global control handle - for the ioctls */
+static HANDLE ovs_ctl_device = INVALID_HANDLE_VALUE;
+
+/* Handle specifically used for receiving packets from the kernel. */
+static HANDLE ovs_recv_device = INVALID_HANDLE_VALUE;
+static HANDLE ovs_recv_event = NULL;
+static OVERLAPPED ovs_recv_overlapping;
+
+/* Handle specifically used for port events. */
+static HANDLE ovs_event_device = INVALID_HANDLE_VALUE;
+static HANDLE ovs_event_event = NULL;
+static OVERLAPPED ovs_event_overlapping;
+static long long int ovs_dp_timestamp_set_time;
+
+#define OVS_DP_TIMESTAMP_SET_TIME_INTVL 1000 /* In milliseconds. */
+
+/* Socket on the VXLAN port. */
+#define VXLAN_DST_PORT 4789
+static int vxlan_fd = -1;
+
+static struct dpif_windows *
+dpif_windows_cast(const struct dpif *dpif)
+{
+    dpif_assert_class(dpif, &dpif_windows_class);
+    return CONTAINER_OF(dpif, struct dpif_windows, dpif);
+}
+
+static int
+dpif_windows_init(void)
+{
+    int error = 0;
+
+    if (ovs_ctl_device == INVALID_HANDLE_VALUE) {
+        error = dpif_windows_init_handle(&ovs_ctl_device, NULL);
+        if (error) {
+            return -win_error_to_errno(error);
+        }
+    }
+
+    if (ovs_recv_device == INVALID_HANDLE_VALUE) {
+        error = dpif_windows_init_handle(&ovs_recv_device, &ovs_recv_event);
+        if (error) {
+            return -win_error_to_errno(error);
+        }
+        memset(&ovs_recv_overlapping, 0, sizeof ovs_recv_overlapping);
+        ovs_recv_overlapping.hEvent = ovs_recv_event;
+    }
+
+    if (ovs_event_device == INVALID_HANDLE_VALUE) {
+        error = dpif_windows_init_handle(&ovs_event_device, &ovs_event_event);
+        if (error) {
+            return -win_error_to_errno(error);
+        }
+        memset(&ovs_event_overlapping, 0, sizeof ovs_event_overlapping);
+        ovs_event_overlapping.hEvent = ovs_event_event;
+    }
+
+    return error;
+}
+
+/* Wrapper for the Windows IoControl function.
+ * Return values:
+ *   value of reply_len on success.
+ *   -(posix error number) on failure.
+ *   -E2BIG if reply_len is insufficient. The actual required length will be
+ *   set into reply_out_len, if it is not NULL. */
+static int
+dpif_windows_ioctl__(HANDLE handle, uint32_t type, const void *request,
+                     size_t request_len, void *reply, size_t reply_len)
+{
+    int retval;
+    int error = 0;
+    DWORD bytes;
+    DWORD win_error;
+
+    error = dpif_windows_init();
+    if (error) {
+        return error;
+    }
+
+    /* There seems to be a skew between the kernel's version of current time
+     * and the userspace's version of current time. The skew was seen to
+     * monotonically increase as well.
+     *
+     * In order to deal with the situation, we periodically pass down the
+     * userspace's version of the timestamp to the kernel, and let the kernel
+     * calculate the delta. The frequency of this is
+     * OVS_DP_TIMESTAMP_SET_TIME_INTVL. */
+    long long int curtime = time_msec();
+    if (curtime - ovs_dp_timestamp_set_time >
+        OVS_DP_TIMESTAMP_SET_TIME_INTVL) {
+        if (!DeviceIoControl(handle, OVS_IOCTL_DP_TIMESTAMP_SET,
+                             &curtime, sizeof curtime,
+                             NULL, 0, NULL, NULL)) {
+            VLOG_ERR("Failed to set timestamp - %s\n",
+                     ovs_lasterror_to_string());
+        }
+    }
+
+    if (!DeviceIoControl(handle, type, (LPVOID *) request, request_len,
+                         reply, reply_len, &bytes, NULL)) {
+        win_error = GetLastError();
+        /* TODO - Don't massage here, return the raw win_error. */
+        if (win_error == ERROR_MORE_DATA ||
+            win_error == ERROR_INSUFFICIENT_BUFFER) {
+            error = -E2BIG;
+        } else {
+            error = -win_error_to_errno(GetLastError());
+        }
+    } else {
+        ovs_assert(bytes < INT_MAX);
+        error = bytes;
+    }
+
+    return error;
+}
+
+int
+dpif_windows_ioctl(uint32_t type, const void *request, size_t request_len,
+                   void *reply, size_t reply_len)
+{
+    return dpif_windows_ioctl__(ovs_ctl_device, type, request, request_len,
+                                reply, reply_len);
+}
+
+static int
+dpif_windows_init_handle(HANDLE *handle, HANDLE *event)
+{
+    int error = 0;
+    int bytes;
+    OVS_VERSION version;
+
+    *handle = CreateFile(
+        OVS_USER_DEVICE_PATH,
+        GENERIC_READ | GENERIC_WRITE,
+        FILE_SHARE_READ,
+        NULL,                          /* No SECURITY_ATTRIBUTES structure. */
+        OPEN_EXISTING,                 /* No special create flags. */
+        FILE_FLAG_OVERLAPPED,
+        NULL);
+
+    if (*handle == INVALID_HANDLE_VALUE) {
+        error = GetLastError();
+        VLOG_ERR("Failed to open the control device %s - %s\n",
+            OVS_USER_DEVICE_PATH, ovs_format_message(error));
+        return error;
+    }
+
+    memset(&version, 0, sizeof version);
+
+    error = DeviceIoControl(*handle, OVS_IOCTL_VERSION_GET,
+                            NULL, 0,
+                            &version, sizeof version,
+                            &bytes, NULL);
+
+    if (error == 0 || bytes != sizeof version) {
+        error = GetLastError();
+        VLOG_ERR("Failed to get driver version - %s\n",
+                 ovs_format_message(error));
+        goto cleanup;
+    }
+
+    if (version.mjrDrvVer != OVS_DRIVER_MAJOR_VER) {
+        VLOG_ERR("User/Kernel Driver version mismatch :"
+                 "kernel version - %d, user version - %d\n",
+                 version.mjrDrvVer, OVS_DRIVER_MAJOR_VER);
+        error = ERROR_NOT_SUPPORTED;
+        goto cleanup;
+    }
+
+    VLOG_DBG("Driver version %u.%u\n", version.mjrDrvVer, version.mnrDrvVer);
+
+    if (event == NULL) {
+        /* No events associated with this handle. */
+        return 0;
+    }
+
+    if (*event == NULL) {
+        *event = CreateEvent(NULL, FALSE, FALSE, NULL);
+    }
+    if (*event == NULL) {
+        error = GetLastError();
+        VLOG_ERR("Failed to CreateEvent - %s\n", ovs_format_message(error));
+        return error;
+    }
+
+    return 0;
+
+cleanup:
+    CloseHandle(*handle);
+    *handle = INVALID_HANDLE_VALUE;
+    return error;
+}
+
+int
+dpif_windows_dump_numbers(uint32_t command,
+                          const void *request, size_t request_len,
+                          uint32_t **replyp, size_t *n_replyp)
+{
+    size_t capacity;
+
+    for (capacity = 64; capacity < 65536; capacity *= 2) {
+        uint32_t *reply;
+        size_t len;
+        int retval;
+
+        len = capacity * sizeof *reply;
+        reply = xmalloc(len);
+
+        retval = dpif_windows_ioctl(command, request, request_len, reply, len);
+        if (retval >= 0) {
+            *replyp = reply;
+            *n_replyp = retval / sizeof *reply;
+            return 0;
+        }
+        free(reply);
+
+        if (retval != -E2BIG) {
+            return -retval;
+        }
+    }
+
+    return E2BIG;
+}
+
+static int
+get_dps(const uint32_t *dp_nos, POVS_DP_INFO gets, size_t n)
+{
+    size_t i;
+
+    for (i = 0; i < n; i++) {
+        int retval = dpif_windows_ioctl(OVS_IOCTL_DP_GET,
+                                        &dp_nos[i], sizeof dp_nos[i],
+                                        &gets[i], sizeof gets[i]);
+        if (retval < 0) {
+            return -retval;
+        }
+    }
+
+    return 0;
+}
+
+static int
+dpif_windows_get_dps(POVS_DP_INFO *getsp, size_t *n_getsp)
+{
+    int error;
+
+    error = dpif_windows_init();
+    if (error) {
+        return error;
+    }
+
+    for (;;) {
+        uint32_t *dp_nos;
+        POVS_DP_INFO gets;
+        size_t n_dps;
+
+        error = dpif_windows_dump_numbers(OVS_IOCTL_DP_DUMP, NULL, 0,
+                                          &dp_nos, &n_dps);
+        if (error) {
+            return error;
+        }
+
+        gets = xmalloc(n_dps * sizeof *gets);
+        error = get_dps(dp_nos, gets, n_dps);
+
+        free(dp_nos);
+        if (!error) {
+            *getsp = gets;
+            *n_getsp = n_dps;
+        } else {
+            free(gets);
+        }
+
+        if (error != ENOENT) {
+            return error;
+        }
+
+        /* Set of datapaths changed. Try again. */
+    }
+    return 0;
+}
+
+static int
+dpif_windows_enumerate(struct sset *all_dps,
+                       const struct dpif_class *class OVS_UNUSED)
+{
+    POVS_DP_INFO gets;
+    size_t n_gets;
+    int error;
+
+    error = dpif_windows_get_dps(&gets, &n_gets);
+    if (!error) {
+        size_t i;
+
+        for (i = 0; i < n_gets; i++) {
+            sset_add(all_dps, gets[i].name);
+        }
+        free(gets);
+    }
+    return error;
+}
+
+static void
+dpif_windows_datapath_polling_init(struct dpif_windows *dpif)
+{
+    OVS_EVENT_SUBSCRIBE event_subscribe;
+    int retval;
+    int bytes;
+
+    dpif_windows_init();
+
+    event_subscribe.dpNo = OVS_DP_NUMBER;
+    event_subscribe.subscribe = 1;
+    event_subscribe.mask = OVS_EVENT_MASK_ALL;
+    retval = DeviceIoControl(ovs_event_device, OVS_IOCTL_EVENT_SUBSCRIBE,
+                             &event_subscribe, sizeof event_subscribe, NULL, 0,
+                             &bytes, NULL);
+
+    if (retval == 0) {
+        VLOG_ERR("Unable to register for event notifications - %s.\n",
+                 ovs_lasterror_to_string());
+        return;
+    }
+}
+
+static int
+dpif_windows_open(const struct dpif_class *class OVS_UNUSED, const char *name,
+                  bool create, struct dpif **dpifp)
+{
+    POVS_DP_INFO gets;
+    size_t n_gets;
+    int error;
+
+    error = dpif_windows_get_dps(&gets, &n_gets);
+    if (!error) {
+        size_t i;
+
+        error = create ? EOPNOTSUPP : ENOENT;
+        for (i = 0; i < n_gets; i++) {
+            const POVS_DP_INFO get = &gets[i];
+
+            if (!strcmp(get->name, name)) {
+                struct dpif_windows *dpif;
+
+                if (create) {
+                    error = EEXIST;
+                    free(gets);
+                    break;
+                }
+
+                /* XXX Will be moved to Kernel, must be done here since add
+                 * port is not always called. */
+                if (vxlan_fd < 0) {
+                   vxlan_fd = inet_open_passive(SOCK_DGRAM, "4789:0.0.0.0",
+                                                VXLAN_DST_PORT, NULL, 0);
+                }
+
+                dpif = xzalloc(sizeof *dpif);
+                dpif->dp_no = OVS_DP_NUMBER;
+                ovs_mutex_init(&dpif->upcall_lock);
+                dpif_init(&dpif->dpif, &dpif_windows_class, get->name,
+                          dpif->dp_no, dpif->dp_no);
+                *dpifp = &dpif->dpif;
+
+                dpif_windows_datapath_polling_init(dpif);
+                dpif->new_poll = true;
+                hmap_init(&dpif->ports_tbl);
+                sset_init(&dpif->changed_ports);
+                free(gets);
+                error = 0;
+                break;
+            }  else {
+               VLOG_INFO("Name %s doesn't match: %s", name, get->name);
+            }
+            free(gets);
+        }
+    }
+    return error;
+}
+
+static void
+dpif_windows_close(struct dpif *dpif_)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+
+    if (vxlan_fd >= 0) {
+        closesocket(vxlan_fd);
+        vxlan_fd = -1;
+    }
+
+    sset_destroy(&dpif->changed_ports);
+    hmap_destroy(&dpif->ports_tbl);
+    ovs_mutex_destroy(&dpif->upcall_lock);
+    free(dpif);
+}
+
+static int
+dpif_windows_get_stats(const struct dpif *dpif_, struct dpif_dp_stats *stats)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    OVS_DP_INFO get;
+    int retval;
+
+    retval = get_dps(&dpif->dp_no, &get, 1);
+    if (retval < 0) {
+        return -retval;
+    }
+
+    memset(stats, 0, sizeof *stats);
+    stats->n_hit    = get.nHit;
+    stats->n_missed = get.nMissed;
+    stats->n_lost   = get.nLost;
+    stats->n_flows  = get.nFlows;
+    return 0;
+}
+
+static int
+dpif_windows_port_query__(const struct dpif *dpif_ OVS_UNUSED,
+                          uint32_t port_no,
+                          const char *port_name,
+                          struct dpif_port *dpif_port,
+                          struct ovs_vport_stats *stats)
+{
+    OVS_VPORT_INFO info;
+    OVS_VPORT_GET get;
+    int retval;
+
+    memset(&get, 0, sizeof get);
+    get.dpNo = OVS_DP_NUMBER;
+    get.portNo = port_no;
+
+    if (port_name) {
+        if (strlen(port_name) >= sizeof get.name) {
+            return ENODEV;
+        }
+        strcpy(get.name, port_name);
+    }
+
+    retval = dpif_windows_ioctl(OVS_IOCTL_VPORT_GET, &get, sizeof get,
+                                &info, sizeof info);
+
+    if (retval < 0) {
+        return -retval == ENOENT? ENODEV : -retval;
+    }
+
+    if (port_name && strncmp(port_name, info.name, strlen(port_name))) {
+        return ENODEV;
+    }
+
+    if (dpif_port) {
+        dpif_port->name = xstrdup(port_name);
+
+        switch (info.type) {
+        case OVSWIN_VPORT_TYPE_GRE:
+            dpif_port->type = xstrdup("gre");
+            break;
+        case OVSWIN_VPORT_TYPE_GRE64:
+            dpif_port->type = xstrdup("gre64");
+            break;
+        case OVSWIN_VPORT_TYPE_VXLAN:
+            dpif_port->type = xstrdup("vxlan");
+            break;
+        case OVSWIN_VPORT_TYPE_EXTERNAL:
+        case OVSWIN_VPORT_TYPE_INTERNAL:
+        case OVSWIN_VPORT_TYPE_SYNTHETIC:
+        case OVSWIN_VPORT_TYPE_EMULATED:
+            dpif_port->type = xstrdup("system");
+            break;
+
+        case OVSWIN_VPORT_TYPE_LOCAL:
+        case OVSWIN_VPORT_TYPE_UNKNOWN:
+        default:
+            VLOG_ERR("Invalid port type: %d", info.type);
+            return ENOENT;
+        }
+
+        dpif_port->port_no = info.portNo;
+    }
+
+    if (stats) {
+        stats->rx_packets = info.rxPackets;
+        stats->tx_packets = info.txPackets;
+        stats->rx_bytes = info.rxBytes;
+        stats->tx_bytes = info.txBytes;
+        stats->rx_errors = info.rxErrors;
+        stats->tx_errors = info.txErrors;
+        stats->rx_dropped = info.rxDropped;
+        stats->tx_dropped = info.txDropped;
+    }
+
+     return 0;
+}
+
+static int
+dpif_windows_port_add(struct dpif *dpif_, struct netdev *netdev,
+                      uint32_t *port_nop)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    char namebuf[NETDEV_VPORT_NAME_BUFSIZE];
+    const char *name = netdev_vport_get_dpif_port(netdev,
+                                                  namebuf, sizeof namebuf);
+    struct dpif_port dpif_port;
+    const struct netdev_tunnel_config *tnl_cfg;
+    int error;
+
+   /* This API is supposed to pass VPORT_NEW command to the datapath to create
+    * a new port. VPORT_NEW ioctl is not implemented in Windows datapath yet.
+    * Hence, return failure if the port does not already exist.
+    * Returning success will mislead ofproto and bridge
+    * into thinking that there now exists this new port in the datapath. */
+    *port_nop = 0;
+    error = dpif_windows_port_query__(dpif_, 0, name, &dpif_port, NULL);
+    if (error > 0) {
+        const char *type;
+        OVS_VPORT_ADD_REQUEST request;
+        OVS_VPORT_INFO reply;
+
+        type = netdev_get_type(netdev);
+        memset(&request, 0, sizeof request);
+        memset(&reply, 0, sizeof reply);
+        request.dpNo = dpif->dp_no;
+        VLOG_INFO("create port type:%s\n", type);
+
+        if (!strcmp(type, "gre")) {
+            request.type = OVSWIN_VPORT_TYPE_GRE;
+        } else if (!strcmp(type, "gre64")) {
+            request.type = OVSWIN_VPORT_TYPE_GRE64;
+        } else if (!strcmp(type, "vxlan")) {
+            request.type = OVSWIN_VPORT_TYPE_VXLAN;
+        } else {
+            goto done;
+        }
+        strcpy(request.name, name);
+
+        tnl_cfg = netdev_get_tunnel_config(netdev);
+        if (tnl_cfg && tnl_cfg->dst_port != 0) {
+            request.dstPort = ntohs(tnl_cfg->dst_port);
+        } else {
+            request.dstPort = 0;
+        }
+        error = dpif_windows_ioctl(OVS_IOCTL_VPORT_ADD, &request,
+                                   sizeof request, &reply, sizeof reply);
+        if (error >= 0) {
+            *port_nop = reply.portNo;
+            return 0;
+        } else {
+            VLOG_INFO("Fail to add port:%s", name);
+            return -error;
+        }
+    } else {
+        *port_nop = dpif_port.port_no;
+        dpif_port_destroy(&dpif_port);
+    }
+
+done:
+    return error;
+}
+
+static int
+dpif_windows_port_del(struct dpif *dpif_,
+                      uint32_t port_no OVS_UNUSED)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    OVS_VPORT_DELETE_REQUEST request;
+    OVS_VPORT_INFO info;
+    OVS_VPORT_GET get;
+    int retVal;
+    memset(&get, 0, sizeof get);
+    get.dpNo = OVS_DP_NUMBER;
+    get.portNo = port_no;
+
+    retVal = dpif_windows_ioctl(OVS_IOCTL_VPORT_GET, &get, sizeof get,
+                                &info, sizeof info);
+
+    if (retVal == -ENOENT) {
+        /* If the port does not exist in the first place, return success. */
+        return 0;
+    } else if (retVal <= 0) {
+        return -retVal;
+    }
+
+    switch (info.type) {
+    case OVSWIN_VPORT_TYPE_GRE:
+    case OVSWIN_VPORT_TYPE_GRE64:
+    case OVSWIN_VPORT_TYPE_VXLAN:
+        break;
+    case OVSWIN_VPORT_TYPE_LOCAL:
+    case OVSWIN_VPORT_TYPE_EXTERNAL:
+    case OVSWIN_VPORT_TYPE_INTERNAL:
+    case OVSWIN_VPORT_TYPE_SYNTHETIC:
+    case OVSWIN_VPORT_TYPE_EMULATED:
+    default:
+        return 0;
+    }
+
+    memset(&request, 0, sizeof request);
+    request.dpNo = dpif->dp_no;
+    request.portNo = port_no;
+
+    retVal = dpif_windows_ioctl(OVS_IOCTL_VPORT_DEL, &request, sizeof request,
+                                NULL, 0);
+    return -retVal;
+}
+
+static int
+dpif_windows_port_query_by_number(const struct dpif *dpif, uint32_t port_no,
+                                  struct dpif_port *dpif_port)
+{
+    return dpif_windows_port_query__(dpif, port_no, NULL, dpif_port, NULL);
+}
+
+static int
+dpif_windows_port_query_by_name(const struct dpif *dpif, const char *devname,
+                                struct dpif_port *dpif_port)
+{
+    return dpif_windows_port_query__(dpif, 0, devname, dpif_port, NULL);
+}
+
+static uint32_t
+dpif_windows_port_get_pid(const struct dpif *dpif OVS_UNUSED,
+                          uint32_t port_no, uint32_t hash)
+{
+    return port_no != UINT32_MAX?  port_no : 0;
+}
+
+struct dpif_windows_port_state {
+    uint32_t dp_no;
+
+    uint32_t *port_nos;
+    size_t n_ports;
+    size_t pos;
+
+    OVS_VPORT_INFO info;
+};
+
+static int
+dpif_windows_port_dump_start(const struct dpif *dpif_, void **statep)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    struct dpif_windows_port_state *state;
+    int retval;
+
+    *statep = state = xzalloc(sizeof *state);
+    state->dp_no = dpif->dp_no;
+    retval = dpif_windows_dump_numbers(OVS_IOCTL_VPORT_DUMP,
+                                       &dpif->dp_no, sizeof dpif->dp_no,
+                                       &state->port_nos, &state->n_ports);
+    if (retval < 0) {
+        free(state);
+        return -retval;
+    }
+
+    return 0;
+}
+
+static int
+dpif_windows_port_dump_next(const struct dpif *dpif OVS_UNUSED, void *state_,
+                            struct dpif_port *dpif_port)
+{
+    struct dpif_windows_port_state *state = state_;
+
+    while (state->pos < state->n_ports) {
+        OVS_VPORT_GET get;
+        int retval;
+
+        get.dpNo = state->dp_no;
+        get.portNo = state->port_nos[state->pos++];
+        get.name[0] = '\0';
+        retval = dpif_windows_ioctl(OVS_IOCTL_VPORT_GET,
+                                    &get, sizeof get,
+                                    &state->info, sizeof state->info);
+        if (retval > 0) {
+            dpif_port->name = state->info.name;
+            switch (state->info.type) {
+            case OVSWIN_VPORT_TYPE_GRE:
+                dpif_port->type = "gre";
+                break;
+            case OVSWIN_VPORT_TYPE_GRE64:
+                dpif_port->type = "gre64";
+                break;
+            case OVSWIN_VPORT_TYPE_VXLAN:
+                dpif_port->type = "vxlan";
+                break;
+            case OVSWIN_VPORT_TYPE_EXTERNAL:
+            case OVSWIN_VPORT_TYPE_INTERNAL:
+            case OVSWIN_VPORT_TYPE_SYNTHETIC:
+            case OVSWIN_VPORT_TYPE_EMULATED:
+                dpif_port->type = "system";
+                break;
+
+            case OVSWIN_VPORT_TYPE_LOCAL:
+            case OVSWIN_VPORT_TYPE_UNKNOWN:
+            default:
+                VLOG_ERR("Unknown port type %d", state->info.type);
+                return ENOENT;
+            }
+
+            dpif_port->port_no = get.portNo;
+            return 0;
+        } else if (retval == -ENOENT) {
+            VLOG_INFO("Positive retval from ioctl, setting port name from"
+                      " state");
+            /* Probably the port disappeared from the datapath while we were
+             * iterating. Just skip it, so as not to truncate the list of
+             * ports. */
+        } else {
+            VLOG_INFO("Unknown return value from IOCTL");
+            return -retval;
+        }
+    }
+
+    return EOF;
+}
+
+static int
+dpif_windows_port_dump_done(const struct dpif *dpif_ OVS_UNUSED, void *state_)
+{
+    struct dpif_windows_port_state *state = state_;
+    free(state->port_nos);
+    free(state);
+    return 0;
+}
+
+int
+dpif_windows_port_ext_info(uint32_t port_no, const char *name,
+                           POVS_VPORT_EXT_INFO ext_info)
+{
+    OVS_VPORT_GET vport_request;
+    int retval;
+    int bytes;
+
+    vport_request.dpNo = OVS_DP_NUMBER;
+    vport_request.portNo = port_no;
+    if (name) {
+        strncpy(vport_request.name, name, sizeof vport_request.name);
+    } else {
+        vport_request.name[0] = '\0';
+    }
+    retval = DeviceIoControl(ovs_event_device, OVS_IOCTL_VPORT_EXT_INFO,
+                             &vport_request, sizeof vport_request,
+                             ext_info, sizeof *ext_info,
+                             &bytes, NULL);
+    return retval;
+}
+
+static int
+dpif_windows_port_notify(struct dpif_windows *dpif, uint32_t port_no,
+                         uint32_t status)
+{
+    struct dpif_windows_datapath_port *port = NULL;
+    OVS_VPORT_EXT_INFO vport_info;
+    struct hmap_node *node;
+    int retval;
+
+    memset(&vport_info, 0, sizeof vport_info);
+    retval = dpif_windows_port_ext_info(port_no, NULL, &vport_info);
+    if (retval == 0) {
+        return retval;
+    }
+
+    node = hmap_first_with_hash(&dpif->ports_tbl, port_no);
+    if (node) {
+        ASSIGN_CONTAINER(port, node, node);
+        netdev_win_state_notify(port->port_name,
+                status ? status : vport_info.status);
+     } else {
+        port = xmalloc(sizeof *port);
+        port->port_num = vport_info.portNo;
+        port->type = vport_info.type;
+        strncpy(port->port_name, vport_info.name, sizeof port->port_name);
+        hmap_insert(&dpif->ports_tbl, &port->node, port_no);
+     }
+     VLOG_INFO("Port %s status changed\n", port->port_name);
+     sset_add(&dpif->changed_ports, port->port_name);
+
+    return retval;
+}
+
+
+static void
+dpif_windows_poll_datapath(struct dpif_windows *dpif)
+{
+    OVS_EVENT_POLL event_poll;
+    POVS_EVENT_STATUS es;
+    int retval;
+    int bytes;
+    int i;
+    struct dpif_windows_datapath_port *port = NULL;
+    OVS_VPORT_GET vport_request;
+    struct hmap_node *node;
+    int dp_no;
+    size_t n_ports;
+    uint32_t *port_nos;
+#define DPIF_WINDOWS_NUM_PORTS_PER_POLL 32
+    uint32_t event_status[DPIF_WINDOWS_NUM_PORTS_PER_POLL * 2 + 1];
+
+    event_poll.dpNo = OVS_DP_NUMBER;
+    retval = DeviceIoControl(ovs_event_device, OVS_IOCTL_EVENT_POLL,
+                             &event_poll, sizeof event_poll,
+                             event_status, sizeof event_status,
+                             &bytes, NULL);
+    if (retval == 0) {
+        VLOG_INFO("Cannot get ioctl event poll\n");
+        return;
+    }
+
+    es = (POVS_EVENT_STATUS)event_status;
+    if (es->numberEntries == 0) {
+        return;
+    }
+
+    for (i = 0; i < es->numberEntries; i++) {
+        if (es->eventEntries[i].portNo == OVS_DEFAULT_PORT_NO) {
+            dp_no = OVS_DP_NUMBER;
+            retval = dpif_windows_dump_numbers(OVS_IOCTL_VPORT_DUMP,
+                                               &dp_no, sizeof dp_no,
+                                               &port_nos, &n_ports);
+            if (retval < 0) {
+                return;
+            }
+
+            for (i = 0; i < n_ports; i++) {
+                VLOG_INFO("port 0x%x\n", port_nos[i]);
+                retval = dpif_windows_port_notify(dpif, port_nos[i], 0);
+            }
+        } else {
+            VLOG_INFO("port 0x%x status %x\n", es->eventEntries[i].portNo,
+                      es->eventEntries[i].status);
+            if (es->eventEntries[i].status &
+                        (OVS_EVENT_DISCONNECT | OVS_EVENT_LINK_DOWN)) {
+                node = hmap_first_with_hash(&dpif->ports_tbl,
+                                            es->eventEntries[i].portNo);
+                if (node) {
+                    ASSIGN_CONTAINER(port, node, node);
+                    VLOG_INFO("Port %s disconnected\n", port->port_name);
+                    netdev_win_state_notify(port->port_name,
+                                            es->eventEntries[i].status);
+                    sset_add(&dpif->changed_ports, port->port_name);
+                    hmap_remove(&dpif->ports_tbl, &port->node);
+                    free(port);
+                }
+                continue;
+            }
+            retval = dpif_windows_port_notify(dpif, es->eventEntries[i].portNo,
+                                              es->eventEntries[i].status);
+        }
+    }
+}
+
+static int
+dpif_windows_port_poll(const struct dpif *dpif_, char **devnamep)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+
+    if (dpif->new_poll) {
+        dpif_windows_poll_datapath(dpif);
+        dpif->new_poll = false;
+    }
+
+    if (!sset_is_empty(&dpif->changed_ports)) {
+        *devnamep = sset_pop(&dpif->changed_ports);
+    } else {
+        dpif->new_poll = true;
+        return EAGAIN;
+    }
+
+    return 0;
+}
+
+static void
+dpif_windows_port_poll_wait(const struct dpif *dpif_)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    OVS_EVENT_POLL event_poll;
+    int ret = 0;
+    int error;
+    int bytes;
+
+    if (ovs_event_overlapping.Internal != STATUS_PENDING) {
+        event_poll.dpNo = OVS_DP_NUMBER;
+        ret = DeviceIoControl(ovs_event_device, OVS_IOCTL_EVENT_WAIT,
+                              &event_poll, sizeof event_poll,
+                              NULL, 0, &bytes, &ovs_event_overlapping);
+        if (ret == 0) {
+            error = GetLastError();
+            if (error != ERROR_IO_INCOMPLETE && error != ERROR_IO_PENDING) {
+                VLOG_ERR("Windows poll wait failed - %s\n",
+                         ovs_format_message(error));
+                return;
+            }
+        } else {
+            poll_immediate_wake();
+        }
+    }
+
+    poll_fd_wait_event((int)ovs_event_device, ovs_event_event, POLLIN);
+}
+
+/* Checks whether 'flow' can be expressed as an OvsFlowKey.  Returns true if it
+ * can be, false otherwise. */
+static bool
+dpif_windows_flow_is_ok(const struct flow *flow)
+{
+    return flow->pkt_mark == 0;
+}
+
+static bool
+convert_to_flow_key(const struct flow *src, OvsFlowKey *dst)
+{
+    if (!dpif_windows_flow_is_ok(src)) {
+        return false;
+    }
+
+    if (src->tunnel.ip_dst) {
+        dst->tunKey.tunnelId = src->tunnel.tun_id;
+        dst->tunKey.dst = src->tunnel.ip_dst;
+        dst->tunKey.src = src->tunnel.ip_src;
+        dst->tunKey.flags = src->tunnel.flags;
+        dst->tunKey.tos = src->tunnel.ip_tos;
+        dst->tunKey.ttl = src->tunnel.ip_ttl;
+        dst->tunKey.pad = 0;
+        dst->l2.offset = 0;
+    } else {
+        dst->tunKey.attr[0] = 0;
+        dst->tunKey.attr[1] = 0;
+        dst->tunKey.attr[2] = 0;
+        dst->l2.offset = sizeof dst->tunKey;
+    }
+
+    /* L2. */
+    dst->l2.inPort = src->in_port.odp_port;
+    memcpy(dst->l2.dlSrc, src->dl_src, ETH_ADDR_LEN);
+    memcpy(dst->l2.dlDst, src->dl_dst, ETH_ADDR_LEN);
+    BUILD_ASSERT(OVSWIN_VLAN_CFI == VLAN_CFI);
+    BUILD_ASSERT(OVSWIN_DL_TYPE_NONE == FLOW_DL_TYPE_NONE);
+    dst->l2.vlanTci = src->vlan_tci;
+    dst->l2.dlType = src->dl_type;
+
+    /* L3 + L4. */
+    dst->l2.keyLen = OVS_WIN_TUNNEL_KEY_SIZE + OVS_L2_KEY_SIZE
+                     - dst->l2.offset;
+    switch (ntohs(dst->l2.dlType)) {
+    case ETH_TYPE_IP: {
+        IpKey *ipKey = &dst->ipKey;
+        ipKey->nwSrc = src->nw_src;
+        ipKey->nwDst = src->nw_dst;
+        ipKey->nwProto = src->nw_proto;
+        ipKey->nwTos = src->nw_tos;
+        ipKey->nwTtl = src->nw_ttl;
+        ipKey->nwFrag = src->nw_frag;
+        ipKey->l4.tpSrc = src->tp_src;
+        ipKey->l4.tpDst = src->tp_dst;
+        dst->l2.keyLen += OVS_IP_KEY_SIZE;
+        break;
+    }
+    case ETH_TYPE_IPV6: {
+        Ipv6Key *ipv6Key = &dst->ipv6Key;
+        ipv6Key->ipv6Src = src->ipv6_src;
+        ipv6Key->ipv6Dst = src->ipv6_dst;
+        ipv6Key->nwProto = src->nw_proto;
+        ipv6Key->nwTos = src->nw_tos;
+        ipv6Key->nwTtl = src->nw_ttl;
+        ipv6Key->nwFrag = src->nw_frag;
+        ipv6Key->ipv6Label = src->ipv6_label;
+        ipv6Key->l4.tpSrc = src->tp_src;
+        ipv6Key->l4.tpDst = src->tp_dst;
+        ipv6Key->pad = 0;
+        if (src->nw_proto == IPPROTO_ICMPV6) {
+            Icmp6Key *icmp6Key= &dst->icmp6Key;
+            icmp6Key->ndTarget = src->nd_target;
+            memcpy(icmp6Key->arpSha, src->arp_sha, ETH_ADDR_LEN);
+            memcpy(icmp6Key->arpTha, src->arp_tha, ETH_ADDR_LEN);
+            dst->l2.keyLen += OVS_ICMPV6_KEY_SIZE;
+        } else {
+            dst->l2.keyLen += OVS_IPV6_KEY_SIZE;
+        }
+        break;
+    }
+    case ETH_TYPE_ARP:
+    case ETH_TYPE_RARP: {
+        ArpKey *arpKey = &dst->arpKey;
+        arpKey->nwSrc = src->nw_src;
+        arpKey->nwDst = src->nw_dst;
+        memcpy(arpKey->arpSha, src->arp_sha, ETH_ADDR_LEN);
+        memcpy(arpKey->arpTha, src->arp_tha, ETH_ADDR_LEN);
+        arpKey->nwProto = src->nw_proto;
+        arpKey->pad[0] = 0;
+        arpKey->pad[1] = 0;
+        arpKey->pad[2] = 0;
+        dst->l2.keyLen += OVS_ARP_KEY_SIZE;
+        break;
+    }
+    }
+    return true;
+}
+
+static int
+dpif_windows_flow_get(const struct dpif *dpif_,
+                      const struct nlattr *key, size_t key_len,
+                      struct ofpbuf **actionsp, struct dpif_flow_stats *statsp)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    struct flow flow;
+    OvsFlowInfo info;
+    OvsFlowGetInput getInput;
+    OvsFlowGetOutput *getOutput;
+    size_t getOpLen;
+    size_t actionsLen;
+    int retval;
+
+    getInput.dpNo = dpif->dp_no;
+    if (odp_flow_key_to_flow_verbose(key, key_len, &flow)) {
+        return EINVAL;
+    }
+    if (!convert_to_flow_key(&flow, &getInput.key)) {
+        return ENOENT;
+    }
+    actionsLen = MAX_ACTIONS;
+    getOpLen = sizeof *getOutput + actionsLen;
+    getOutput = xzalloc(getOpLen);
+
+    getInput.getFlags = statsp ? FLOW_GET_STATS : 0;
+    getInput.getFlags |= actionsp ? FLOW_GET_ACTIONS : 0;
+    getInput.actionsLen = actionsLen;
+
+    retval = dpif_windows_ioctl(OVS_IOCTL_FLOW_GET, &getInput, sizeof getInput,
+                                getOutput, getOpLen);
+    if (retval < 0) {
+        goto done;
+    }
+
+    if (actionsp) {
+        *actionsp = ofpbuf_clone_data(getOutput->info.actions,
+                                      getOutput->info.actionsLen);
+    }
+    if (statsp) {
+        output_dpif_flow_stats(statsp, &getOutput->info.stats);
+    }
+
+done:
+    if (getOutput) {
+        free(getOutput);
+    }
+    return retval ? -retval : 0;
+}
+
+static int
+dpif_windows_construct_ovs_flow_put(struct dpif_windows *dpif,
+                                    uint32_t flags,
+                                    const struct nlattr *keyp,
+                                    size_t key_len,
+                                    const struct nlattr *actions,
+                                    size_t actions_len,
+                                    struct dpif_flow_stats *statsp,
+                                    OvsFlowPut *put,
+                                    struct OvsFlowStats *flowStats)
+{
+    struct flow flow;
+
+    if (odp_flow_key_to_flow_verbose(keyp, key_len, &flow)
+        || !convert_to_flow_key(&flow, &put->key)) {
+        return EINVAL;
+    }
+
+    /* Make sure some of the members are word-aligned. */
+    BUILD_ASSERT(offsetof(OvsFlowPut, key) % 4 == 0);
+    BUILD_ASSERT(offsetof(OvsFlowPut, actions) % 4 == 0);
+
+    put->dpNo = dpif->dp_no;
+    put->actionsLen = actions_len;
+    put->flags = flags;
+    if (actions_len) {
+        memcpy(put->actions, actions, actions_len);
+    }
+    return 0;
+}
+
+static int
+do_put(struct dpif *dpif_,
+       uint32_t flags,
+       const struct nlattr *keyp, size_t key_len,
+       const struct nlattr *actions, size_t actions_len,
+       struct dpif_flow_stats *statsp)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    OvsFlowStats stats;
+    OvsFlowPut *put;
+    int retval = 0;
+    size_t putlen = sizeof *put;
+
+    if (actions_len) {
+        putlen += actions_len;
+    }
+
+    put = xzalloc(putlen);
+    retval = dpif_windows_construct_ovs_flow_put(dpif, flags, keyp, key_len,
+                                                 actions, actions_len, statsp,
+                                                 put, &stats);
+    if (retval) {
+        retval = -retval;
+        goto cleanup;
+    }
+
+    retval = dpif_windows_ioctl(OVS_IOCTL_FLOW_PUT, put, putlen,
+                                &stats, sizeof stats);
+    if (retval < 0) {
+        VLOG_ERR("Flow put failed %u\n", retval);
+        goto cleanup;
+    }
+
+    if (statsp) {
+        output_dpif_flow_stats(statsp, &stats);
+    }
+
+cleanup:
+    free(put);
+    return retval < 0 ? -retval : 0;
+}
+
+static int
+dpif_windows_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
+{
+    uint32_t flags;
+
+    flags = 0;
+    if (put->flags & DPIF_FP_CREATE) {
+        flags |= OVSWIN_FLOW_PUT_CREATE;
+    }
+    if (put->flags & DPIF_FP_MODIFY) {
+        flags |= OVSWIN_FLOW_PUT_MODIFY;
+    }
+    if (put->flags & DPIF_FP_ZERO_STATS) {
+        flags |= OVSWIN_FLOW_PUT_CLEAR;
+    }
+
+    return do_put(dpif, flags, put->key, put->key_len,
+                  put->actions, put->actions_len, put->stats);
+}
+
+static int
+dpif_windows_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
+{
+    return do_put(dpif, OVSWIN_FLOW_PUT_DELETE, del->key, del->key_len,
+                  NULL, 0, del->stats);
+}
+
+static int
+dpif_windows_flow_flush(struct dpif *dpif_)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    int retval;
+
+    retval = dpif_windows_ioctl(OVS_IOCTL_FLOW_FLUSH, &dpif->dp_no,
+                                sizeof dpif->dp_no, NULL, 0);
+    return retval < 0 ? -retval : 0;
+}
+
+struct dpif_windows_flow_dump {
+    struct dpif_flow_dump up;
+    int status;
+};
+
+static struct dpif_windows_flow_dump *
+dpif_windows_flow_dump_cast(struct dpif_flow_dump *dump)
+{
+    return CONTAINER_OF(dump, struct dpif_windows_flow_dump, up);
+}
+
+static struct dpif_flow_dump *
+dpif_windows_flow_dump_create(const struct dpif *dpif_)
+{
+    struct dpif_windows_flow_dump *fdump;
+
+    fdump = xmalloc(sizeof *fdump);
+    dpif_flow_dump_init(&fdump->up, dpif_);
+    fdump->status = 0;
+
+    return &fdump->up;
+}
+
+static int
+dpif_windows_flow_dump_destroy(struct dpif_flow_dump *dump_)
+{
+    int status;
+    struct dpif_windows_flow_dump *fdump = dpif_windows_flow_dump_cast(dump_);
+    status = fdump->status;
+    free(fdump);
+    return status;
+}
+
+struct dpif_windows_flow_state {
+    uint32_t dp_position[2];
+    struct ofpbuf key_buf;
+    struct ofpbuf flow_buf;
+};
+
+struct dpif_windows_flow_dump_thread {
+    struct dpif_flow_dump_thread up;
+    struct dpif_windows_flow_dump *dump;
+    struct dpif_windows_flow_state *state;
+};
+
+static struct dpif_flow_dump_thread *
+dpif_windows_flow_dump_thread_create(struct dpif_flow_dump *dump_)
+{
+    enum {FLOW_DUMP_SIZE=4096};
+    struct dpif_windows_flow_dump *fdump = dpif_windows_flow_dump_cast(dump_);
+    struct dpif_windows_flow_dump_thread *fthread;
+
+    fthread = xmalloc(sizeof *fthread);
+    dpif_flow_dump_thread_init(&fthread->up, &fdump->up);
+    fthread->dump = fdump;
+    fthread->state = xzalloc(sizeof *fthread->state);
+    ofpbuf_init(&fthread->state->key_buf, ODPUTIL_FLOW_KEY_BYTES);
+    ofpbuf_init(&fthread->state->flow_buf, FLOW_DUMP_SIZE);
+
+    return &fthread->up;
+}
+
+static struct dpif_windows_flow_dump_thread *
+dpif_windows_flow_dump_thread_cast(struct dpif_flow_dump_thread *thread)
+{
+    return CONTAINER_OF(thread, struct dpif_windows_flow_dump_thread, up);
+}
+
+static void
+dpif_windows_flow_dump_thread_destroy(struct dpif_flow_dump_thread *thread_)
+{
+    struct dpif_windows_flow_dump_thread *fthread =
+                                dpif_windows_flow_dump_thread_cast(thread_);
+
+    ofpbuf_uninit(&fthread->state->flow_buf);
+    ofpbuf_uninit(&fthread->state->key_buf);
+
+    free(fthread->state);
+    free(fthread);
+}
+
+static void
+dpif_windows_ovs_flow_key_to_flow(const OvsFlowKey *src, struct flow *dst)
+{
+    memset(dst,0, sizeof *dst);
+
+    if (src->tunKey.dst) {
+        dst->tunnel.tun_id = src->tunKey.tunnelId;
+        dst->tunnel.ip_dst = src->tunKey.dst;
+        dst->tunnel.ip_src = src->tunKey.src;
+        dst->tunnel.flags = src->tunKey.flags;
+        dst->tunnel.ip_tos = src->tunKey.tos;
+        dst->tunnel.ip_ttl = src->tunKey.ttl;
+    }
+
+    dst->in_port.odp_port = src->l2.inPort;
+    memcpy(dst->dl_src, src->l2.dlSrc, ETH_ADDR_LEN);
+    memcpy(dst->dl_dst, src->l2.dlDst, ETH_ADDR_LEN);
+    BUILD_ASSERT(OVSWIN_VLAN_CFI == VLAN_CFI);
+    BUILD_ASSERT(OVSWIN_DL_TYPE_NONE == FLOW_DL_TYPE_NONE);
+    dst->vlan_tci = src->l2.vlanTci;
+    dst->dl_type = src->l2.dlType;
+    dst->metadata = htonll(0);
+    dst->skb_priority = 0;
+    dst->pkt_mark = 0;
+
+    switch (ntohs(dst->dl_type)) {
+    case ETH_TYPE_IP: {
+        const IpKey *ipKey = &src->ipKey;
+        dst->nw_src = ipKey->nwSrc;
+        dst->nw_dst = ipKey->nwDst;
+        dst->nw_proto = ipKey->nwProto;
+        dst->nw_tos = ipKey->nwTos;
+        dst->nw_ttl = ipKey->nwTtl;
+        dst->nw_frag = ipKey->nwFrag;
+        dst->tp_src = ipKey->l4.tpSrc;
+        dst->tp_dst = ipKey->l4.tpDst;
+
+        dst->ipv6_label = 0;
+        break;
+    }
+    case ETH_TYPE_IPV6: {
+        const Ipv6Key *ipv6Key = &src->ipv6Key;
+        dst->ipv6_src = ipv6Key->ipv6Src;
+        dst->ipv6_dst = ipv6Key->ipv6Dst;
+        dst->nw_proto = ipv6Key->nwProto;
+        dst->nw_tos = ipv6Key->nwTos;
+        dst->nw_ttl = ipv6Key->nwTtl;
+        dst->nw_frag = ipv6Key->nwFrag;
+        dst->ipv6_label = ipv6Key->ipv6Label;
+        dst->tp_src = ipv6Key->l4.tpSrc;
+        dst->tp_dst = ipv6Key->l4.tpDst;
+
+        if (dst->nw_proto == IPPROTO_ICMPV6) {
+            const Icmp6Key *icmp6Key= &src->icmp6Key;
+            dst->nd_target = icmp6Key->ndTarget;
+            memcpy(dst->arp_sha, icmp6Key->arpSha, ETH_ADDR_LEN);
+            memcpy(dst->arp_tha, icmp6Key->arpTha, ETH_ADDR_LEN);
+        }
+        dst->nw_src = 0;
+        dst->nw_dst = 0;
+        break;
+    }
+    default:
+        dst->ipv6_label = 0;
+        if (dst->dl_type == htons(ETH_TYPE_ARP) ||
+            dst->dl_type == htons(ETH_TYPE_RARP)) {
+            const ArpKey *arpKey = &src->arpKey;
+            dst->nw_src = arpKey->nwSrc;
+            dst->nw_dst = arpKey->nwDst;
+            dst->nw_proto = arpKey->nwProto;
+            memcpy(dst->arp_sha, arpKey->arpSha, ETH_ADDR_LEN);
+            memcpy(dst->arp_tha, arpKey->arpTha, ETH_ADDR_LEN);
+        } else {
+            dst->nw_src = 0;
+            dst->nw_dst = 0;
+            dst->nw_proto = 0;
+        }
+        dst->nw_tos = 0;
+        dst->nw_ttl = 0;
+        dst->nw_frag = 0;
+        dst->tp_src = 0;
+        dst->tp_dst = 0;
+    }
+}
+
+static void
+dpif_windows_flow_dump_to_dpif_flow(const OvsFlowDumpOutput *out,
+                                    struct dpif_flow *upFlow,
+                                    struct dpif_windows_flow_state *fstate)
+{
+    struct flow flow;
+
+    ofpbuf_clear(&fstate->key_buf);
+
+    /* Output flow key. */
+    dpif_windows_ovs_flow_key_to_flow(&out->flow.key, &flow);
+    odp_flow_key_from_flow(&fstate->key_buf, &flow, NULL,
+                           flow.in_port.odp_port, false);
+    upFlow->key = ofpbuf_data(&fstate->key_buf);
+    upFlow->key_len = ofpbuf_size(&fstate->key_buf);
+
+    /* Wild card flows, not yet supported. */
+    upFlow->mask = NULL;
+    upFlow->mask_len = 0;
+
+    /* Output actions. */
+    upFlow->actions = out->flow.actions;
+    upFlow->actions_len = out->flow.actionsLen;
+
+    /* Output stats. */
+    output_dpif_flow_stats(&upFlow->stats, &out->flow.stats);
+}
+
+/* Only dumps 1 flow, doesn't batch flows. */
+static int
+dpif_windows_flow_dump_next(struct dpif_flow_dump_thread *thread_,
+                            struct dpif_flow *flows, int max_flows)
+{
+    struct dpif_windows_flow_dump_thread *fthread =
+                                dpif_windows_flow_dump_thread_cast(thread_);
+    struct dpif_windows *dpif = dpif_windows_cast(fthread->up.dpif);
+    struct dpif_windows_flow_state *fstate = fthread->state;
+    bool retry = false;
+    OvsFlowDumpInput dumpInput;
+    OvsFlowDumpOutput *dumpOutput;
+    size_t dumpOutputSize;
+    int retval;
+
+    ovs_assert(dpif->dp_no == OVS_DP_NUMBER);
+    dumpInput.dpNo = dpif->dp_no;
+    dumpInput.position[0] = fstate->dp_position[0];
+    dumpInput.position[1] = fstate->dp_position[1];
+    dumpInput.getFlags = FLOW_GET_KEY | FLOW_GET_STATS | FLOW_GET_ACTIONS;
+
+    for (;;) {
+        ofpbuf_clear(&fstate->flow_buf);
+        dumpOutput = ofpbuf_base(&fstate->flow_buf);
+        dumpOutputSize = fstate->flow_buf.allocated;
+        dumpInput.actionsLen = dumpOutputSize - sizeof(OvsFlowDumpOutput);
+
+        retval = dpif_windows_ioctl(OVS_IOCTL_FLOW_DUMP,
+                                    &dumpInput, sizeof dumpInput,
+                                    dumpOutput, dumpOutputSize);
+        if (!retry && retval == -E2BIG) {
+            ovs_assert(dumpOutput->n > dumpOutputSize);
+            /* 'dumpInput' remains same, since we are retrying flow dump. */
+            ofpbuf_reinit(&fstate->flow_buf, MIN(dumpOutput->n, 65536));
+            retry = true;
+            continue;
+        } else if (retval < 0) {
+            /* XXX Does this need to be atomic? */
+            fthread->dump->status = -retval;
+            return 0;
+        } else if (dumpOutput->n == 0) {
+            /* No more flows to dump. */
+            return 0;
+        }
+        break;
+    }
+
+    fstate->dp_position[0] = dumpOutput->position[0];
+    fstate->dp_position[1] = dumpOutput->position[1];
+
+    dpif_windows_flow_dump_to_dpif_flow(dumpOutput, &flows[0], fstate);
+
+    ovs_assert(dumpOutput->n == 1);
+    return dumpOutput->n;
+}
+
+static int
+dpif_execute_to_packetexecute(struct dpif_windows *dpif,
+                              const struct dpif_execute *execute,
+                              OvsPacketExecute *exe)
+{
+    struct flow flow;
+
+    exe->dpNo = dpif->dp_no;
+    memcpy(exe->packetBuf, ofpbuf_data(execute->packet),
+           ofpbuf_size(execute->packet));
+    exe->packetLen = ofpbuf_size(execute->packet);
+    exe->inPort = execute->md.in_port.odp_port;
+    memcpy((char *)&exe->actions + exe->packetLen, execute->actions,
+           execute->actions_len);
+    exe->actionsLen = execute->actions_len;
+    return 0;
+}
+
+static int
+dpif_windows_execute(struct dpif *dpif_, const struct dpif_execute *execute)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    OvsPacketExecute *exe;
+    int retval;
+    uint32_t executeLen = sizeof *exe + ofpbuf_size(execute->packet) +
+                          execute->actions_len;
+
+    exe = xmalloc(executeLen);
+    if (exe == NULL) {
+        return -1;
+    }
+
+    retval = dpif_execute_to_packetexecute(dpif, execute, exe);
+    if (retval) {
+       free(exe);
+       return EINVAL;
+    }
+
+    retval = dpif_windows_ioctl(OVS_IOCTL_DATAPATH_EXECUTE, exe, executeLen,
+                                NULL, 0);
+    free(exe);
+
+    return retval < 0 ? -retval : 0;
+}
+
+static int
+dpif_windows_subscribe(uint32_t queueId)
+{
+    uint32_t queue = queueId;
+    int retval;
+
+    retval = dpif_windows_ioctl__(ovs_recv_device, OVS_IOCTL_DATAPATH_SUBSCRIBE, &queue,
+                                 sizeof queue, NULL, 0);
+    if (retval < 0) {
+        VLOG_ERR("Fail to subscribe to queue: %u, retval: %d-%s", queueId,
+                 retval, ovs_strerror(retval));
+    }
+    return retval < 0? -retval : 0;
+}
+
+#define DPIF_DEFAULT_QUEUE_ID   1
+static int
+dpif_windows_recv_set(struct dpif *dpif_, bool enable)
+{
+    static int error = -1;
+
+    if (error == 0 || !enable) {
+        return error;
+    }
+
+    /* Since the channels are shared between dpifs, it will
+     * not be destroyed when enable is false.
+     *
+     * XXX: We are going with one descriptor model for both control and
+     * datapath in DPIF since it is lesser code to write. We could easily
+     * change the model to do separate descriptors by updating
+     * dpif_windows_ioctl() and ovs_recv_fd. */
+    if ((error = dpif_windows_subscribe(DPIF_DEFAULT_QUEUE_ID)) != 0) {
+        return error;
+    }
+
+    memset(&ovs_recv_overlapping, 0, sizeof ovs_recv_overlapping);
+    ovs_recv_overlapping.hEvent = ovs_recv_event;
+
+    return 0;
+}
+
+static int
+dpif_windows_handlers_set(struct dpif *dpif, uint32_t n_handlers)
+{
+    /* NOT IMPLEMENTED.*/
+    return 0;
+}
+
+static int
+dpif_windows_recv(struct dpif *dpif_ OVS_UNUSED,
+                  uint32_t handler_id OVS_UNUSED,
+                  struct dpif_upcall *upcall,
+                  struct ofpbuf *buf)
+{
+    int rc;
+    struct ofpbuf key;
+    uint8_t packetBuffer[2048];
+    uint8_t *buf_packet;
+    struct nlattr *reply_user_attr, *buf_user_attr;
+    uint32_t packet_len;
+
+    if (!buf || !ofpbuf_base(buf)) {
+        return EINVAL;
+    }
+
+    /* We use the ofpbuf as follows:
+     * 1. First ODP_UTIL_FLOW_KEY_BYTES (256) are used for flow key
+     * 2. Variable number of bytes to store userdata as nlattr
+     * 3. Remaining buffer is used for packet. */
+    if (ofpbuf_size(buf) <=
+        (sizeof(struct odputil_keybuf) + sizeof(struct nlattr))) {
+        ofpbuf_uninit(buf);
+        ofpbuf_init(buf, 2048);
+    }
+    ofpbuf_use(&key, ofpbuf_base(buf), sizeof(struct odputil_keybuf));
+
+    rc = dpif_windows_ioctl__(ovs_recv_device, OVS_IOCTL_DATAPATH_READ, NULL,
+                              0, packetBuffer, sizeof packetBuffer);
+    if (rc < 0) {
+        VLOG_INFO("Read packet failed with error: %d", -rc);
+        return -rc;
+    }
+
+    if (rc > 0) {
+        POVS_PACKET_INFO reply = (POVS_PACKET_INFO)packetBuffer;
+        struct flow flow;
+        uint32_t reply_user_attr_len;
+        uint32_t buf_user_attr_len;
+
+        /* There's data to read. */
+        if (reply->userDataLen == 0) {
+            reply_user_attr = NULL;
+            reply_user_attr_len = 0;
+        } else {
+            reply_user_attr = (struct nlattr *)&reply->data;
+            reply_user_attr_len = reply_user_attr->nla_len;
+        }
+
+        if (buf->allocated <= sizeof(struct odputil_keybuf) +
+                              reply_user_attr_len + reply->packetLen) {
+            ofpbuf_reinit(buf, sizeof(struct odputil_keybuf) +
+                               reply_user_attr_len + reply->packetLen);
+        }
+
+        ofpbuf_use(&key, ofpbuf_base(buf), sizeof(struct odputil_keybuf));
+
+        buf_packet = (uint8_t *)ofpbuf_base(buf) +
+                                        sizeof(struct odputil_keybuf);
+        packet_len = reply_user_attr_len + reply->packetLen;
+        if (reply_user_attr_len != 0) {
+            buf_user_attr = (struct nlattr *)buf_packet;
+            memcpy(buf_user_attr, reply_user_attr, reply_user_attr->nla_len);
+            buf_user_attr_len = buf_user_attr->nla_len;
+        } else {
+            buf_user_attr = NULL;
+            buf_user_attr_len = 0;
+        }
+
+        /* XXX: Copy the user attributes, either using reply->data or by
+         * walking the netlink chain. */
+        buf_packet += buf_user_attr_len;
+        buf->frame = (uint8_t *)buf_packet;
+        memcpy(buf->frame, ((char *)&reply->data) + reply_user_attr_len,
+               reply->packetLen);
+
+        ofpbuf_set_data(buf, buf->frame);
+        /* This size includes the user data in nlattr. */
+        ofpbuf_set_size(buf, packet_len);
+        upcall->type = reply->cmd == OVS_PACKET_CMD_ACTION ?
+                       DPIF_UC_ACTION : DPIF_UC_MISS;
+
+        ofpbuf_use_stub(&upcall->packet, buf->frame, reply->packetLen);
+        ofpbuf_set_size(&upcall->packet, reply->packetLen);
+
+        upcall->userdata = buf_user_attr;
+        flow_extract(buf, NULL, &flow);
+        flow.in_port.odp_port = reply->inPort;
+
+        if (reply->tunnelKey.dst) {
+            flow.tunnel.tun_id = reply->tunnelKey.tunnelId;
+            flow.tunnel.ip_src = reply->tunnelKey.src;
+            flow.tunnel.ip_dst = reply->tunnelKey.dst;
+            flow.tunnel.flags = reply->tunnelKey.flags;
+            flow.tunnel.ip_tos = reply->tunnelKey.tos;
+            flow.tunnel.ip_ttl = reply->tunnelKey.ttl;
+        }
+        odp_flow_key_from_flow(&key, &flow, NULL, flow.in_port.odp_port,
+                               false);
+        upcall->key = ofpbuf_data(&key);
+        upcall->key_len = ofpbuf_size(&key);
+
+        VLOG_DBG("port %u: %s packt recvd with proto %u, pkt length %u.\n",
+              flow.in_port.odp_port, dpif_upcall_type_to_string(upcall->type),
+              flow.nw_proto, reply->packetLen);
+        return 0;
+    }
+
+    return EAGAIN;
+}
+
+static void
+dpif_windows_recv_wait(struct dpif *dpif_, uint32_t handler_id)
+{
+    struct dpif_windows *dpif = dpif_windows_cast(dpif_);
+    int ret = 0;
+    int error;
+    int bytes;
+
+    if (ovs_recv_overlapping.Internal != STATUS_PENDING) {
+        ret = DeviceIoControl(ovs_recv_device, OVS_IOCTL_DATAPATH_WAIT, NULL,
+                              0, NULL, 0, &bytes, &ovs_recv_overlapping);
+        if (ret == 0) {
+            error = GetLastError();
+            if (error != ERROR_IO_INCOMPLETE && error != ERROR_IO_PENDING) {
+                VLOG_INFO("Recv wait for datapath failed - %s\n",
+                          ovs_format_message(error));
+                return;
+            }
+        } else {
+            poll_immediate_wake();
+        }
+    }
+
+    poll_fd_wait_event((int)ovs_recv_device, ovs_recv_event, POLLIN);
+}
+
+const struct dpif_class dpif_windows_class = {
+    "system",
+    dpif_windows_enumerate,
+    NULL,                               /* port_open_type */
+    dpif_windows_open,
+    dpif_windows_close,
+    NULL,                              /* destroy */
+    NULL,
+    NULL,
+    dpif_windows_get_stats,
+    dpif_windows_port_add,
+    dpif_windows_port_del,
+    dpif_windows_port_query_by_number,
+    dpif_windows_port_query_by_name,
+    dpif_windows_port_get_pid,
+    dpif_windows_port_dump_start,
+    dpif_windows_port_dump_next,
+    dpif_windows_port_dump_done,
+    dpif_windows_port_poll,
+    dpif_windows_port_poll_wait,
+    dpif_windows_flow_get,
+    dpif_windows_flow_put,
+    dpif_windows_flow_del,
+    dpif_windows_flow_flush,
+    dpif_windows_flow_dump_create,
+    dpif_windows_flow_dump_destroy,
+    dpif_windows_flow_dump_thread_create,
+    dpif_windows_flow_dump_thread_destroy,
+    dpif_windows_flow_dump_next,
+    dpif_windows_execute,
+    NULL,                               /* operate - dpif_windows_operate */
+    dpif_windows_recv_set,
+    dpif_windows_handlers_set,
+    NULL,                               /* dpif_windows_queue_to_priority */
+    dpif_windows_recv,
+    dpif_windows_recv_wait,
+    NULL,                               /* purge - dpif_windows_recv_purge */
+};
+
+/* Used by netdev. */
+
+/* Executes 'request' in the kernel datapath.  If the command fails, returns a
+ * positive errno value.  Otherwise, if 'reply' and 'bufp' are null, returns 0
+ * without doing anything else.  If 'reply' and 'bufp' are nonnull, then the
+ * result of the command is expected to be an ovs_vport also, which is decoded
+ * and stored in '*reply' and '*bufp'.  The caller must free '*bufp' when the
+ * reply is no longer needed ('reply' will contain pointers into '*bufp'). */
+int
+dpif_windows_vport_get(const char *name, struct dpif_windows_vport *reply)
+{
+    struct dpif_port dummy_dpif_port;
+    int error;
+
+    error = dpif_windows_port_query__(NULL, 0, name, &dummy_dpif_port,
+                                      reply->stats);
+    if (error == 0) {
+       reply->port_no = dummy_dpif_port.port_no;
+       dpif_port_destroy(&dummy_dpif_port);
+    }
+    return error;
+}
+
+void
+dpif_windows_set_queue(uint32_t port_no, const struct smap *details)
+{
+    /* NOT IMPLEMENTED. */
+}
+
+static void
+output_dpif_flow_stats(struct dpif_flow_stats *dst,
+                       const struct OvsFlowStats *src)
+{
+    dst->n_packets = src->packetCount;
+    dst->n_bytes = src->byteCount;
+    dst->used = src->used;
+    dst->tcp_flags = src->tcpFlags;
+}
diff --git a/lib/dpif-windows.h b/lib/dpif-windows.h
new file mode 100644
index 0000000..c377591
--- /dev/null
+++ b/lib/dpif-windows.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010, 2011 Nicira, Inc.
+ *
+ * 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 DPIF_WINDOWS_H
+#define DPIF_WINDOWS_H 1
+
+#include <stdint.h>
+
+struct ofpbuf;
+typedef struct _OVS_VPORT_EXT_INFO OVS_VPORT_EXT_INFO, *POVS_VPORT_EXT_INFO;
+
+struct dpif_windows_vport {
+    /* Generic Netlink header. */
+    uint8_t cmd;
+
+    /* ovs_vport header. */
+    int dp_ifindex;
+    uint32_t port_no;                      /* UINT32_MAX if unknown. */
+    enum ovs_vport_type type;
+
+    /* Attributes.
+     *
+     * The 'stats' member points to 64-bit data that might only be aligned on
+     * 32-bit boundaries, so use get_unaligned_u64() to access its values.
+     */
+    const char *name;                      /* OVS_VPORT_ATTR_NAME. */
+    const uint32_t *upcall_pid;            /* OVS_VPORT_ATTR_UPCALL_PID. */
+    struct ovs_vport_stats *stats;         /* OVS_VPORT_ATTR_STATS. */
+    const struct nlattr *options;          /* OVS_VPORT_ATTR_OPTIONS. */
+    size_t options_len;
+};
+
+int dpif_windows_port_ext_info(uint32_t port_no, const char *name,
+                               POVS_VPORT_EXT_INFO ext_info);
+int dpif_windows_vport_get(const char *name, struct dpif_windows_vport *reply);
+
+int dpif_windows_ioctl(uint32_t,
+                       const void *request, size_t request_len,
+                       void *reply, size_t reply_len);
+void netdev_win_state_notify(char *name, uint16_t status);
+void dpif_windows_set_queue(uint32_t port_no, const struct smap *details);
+int dpif_windows_dump_numbers(uint32_t command,
+                              const void *request, size_t request_len,
+                              uint32_t **replyp, size_t *n_replyp);
+#endif /* dpif-windows.h */
diff --git a/lib/dpif.c b/lib/dpif.c
index 2b6f36d..02685d5 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -61,6 +61,9 @@ static const struct dpif_class *base_dpif_classes[] = {
 #ifdef __linux__
     &dpif_linux_class,
 #endif
+#ifdef _WIN32
+    &dpif_windows_class,
+#endif
     &dpif_netdev_class,
 };
 
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 6b8160d..e8dc58d 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -692,6 +692,9 @@ int netdev_register_provider(const struct netdev_class *);
 int netdev_unregister_provider(const char *type);
 
 extern const struct netdev_class netdev_linux_class;
+#ifdef _WIN32
+extern const struct netdev_class netdev_win_class;
+#endif
 extern const struct netdev_class netdev_internal_class;
 extern const struct netdev_class netdev_tap_class;
 #if defined(__FreeBSD__) || defined(__NetBSD__)
diff --git a/lib/netdev-windows.c b/lib/netdev-windows.c
new file mode 100644
index 0000000..7f9f69e
--- /dev/null
+++ b/lib/netdev-windows.c
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2013 VMware
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <config.h>
+#include <errno.h>
+
+#include <arpa/inet.h>
+#include <inttypes.h>
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <poll.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "coverage.h"
+#include "dynamic-string.h"
+#include "fatal-signal.h"
+#include "netdev-provider.h"
+#include "OvsPub.h"
+#include "ofpbuf.h"
+#include "openflow/openflow.h"
+#include "packets.h"
+#include "poll-loop.h"
+#include "socket-util.h"
+#include "shash.h"
+#include "svec.h"
+#include "vlog.h"
+#include "dpif-windows.h"
+#include "linux/openvswitch.h"
+
+enum {
+    VALID_IFINDEX           = 1 << 0,
+    VALID_ETHERADDR         = 1 << 1,
+    VALID_MTU               = 1 << 2,
+    VALID_DRVINFO           = 1 << 3,
+    VALID_CARRIER           = 1 << 4,
+    VALID_FEATURES          = 1 << 5,
+    VALID_IFFLAG            = 1 << 6,
+};
+
+VLOG_DEFINE_THIS_MODULE(netdev_windows);
+
+static struct vlog_rate_limit netdev_win_rl = VLOG_RATE_LIMIT_INIT(1, 5);
+
+struct netdev_win {
+    struct netdev up;
+    int32_t dev_type;
+    uint32_t port_no;
+
+    unsigned int change_seq;
+
+    unsigned int cache_valid;
+    int ifindex;
+    uint8_t mac[ETH_ADDR_LEN];
+    uint32_t mtu;
+    unsigned int ifi_flags;
+    int carrier;
+
+    long long int carrier_reset;
+    OVS_VPORT_EXT_INFO ext_info;
+
+    enum netdev_features current;
+    enum netdev_features advertised;
+    enum netdev_features supported;
+    enum netdev_features peer;
+};
+
+static int netdev_win_init(void);
+static int netdev_win_query_port(uint32_t dpNo, const char *name,
+                                 uint32_t *type, uint32_t *portNo,
+                                 uint8_t *macAddr);
+static int netdev_win_init_internal(struct netdev_win *netdev);
+static int netdev_win_refresh(struct netdev_win *netdev);
+static int netdev_win_get_dp_mtu(uint32_t dpNo, uint32_t *mtu);
+static void netdev_win_changed(struct netdev_win *dev);
+static int netdev_win_set_flag(const char *name, uint32_t flags);
+
+static bool
+is_netdev_win_class(const struct netdev_class *netdev_class)
+{
+    return netdev_class->init == netdev_win_init;
+}
+
+static struct netdev_win *
+netdev_win_cast(const struct netdev *netdev_)
+{
+    ovs_assert(is_netdev_win_class(netdev_get_class(netdev_)));
+    return CONTAINER_OF(netdev_, struct netdev_win, up);
+}
+
+/* Please see netdev-provider.h for eack callback functions descriptions. */
+
+static int
+netdev_win_init(void)
+{
+    return 0;
+}
+
+static void
+netdev_win_run(void)
+{}
+
+static void
+netdev_win_wait(void)
+{}
+
+static struct netdev *
+netdev_win_alloc(void)
+{
+    struct netdev_win *netdev = xzalloc(sizeof *netdev);
+    return &netdev->up;
+}
+
+static int
+netdev_win_system_construct(struct netdev *netdev_)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+    uint8_t mac[ETH_ADDR_LEN];
+    uint32_t type, portNo;
+
+    int ret;
+
+    ret = netdev_win_query_port(0, netdev_get_name(&netdev->up), &type,
+                                &portNo, mac);
+    if (ret) {
+        return ret;
+    }
+
+    netdev->change_seq = 1;
+    netdev->carrier_reset = 0;
+    netdev->dev_type = type;
+    netdev->port_no = portNo;
+
+    memcpy(netdev->mac, mac, ETH_ADDR_LEN);
+    netdev->cache_valid = VALID_ETHERADDR;
+
+    netdev_win_refresh(netdev);
+
+    netdev->ifindex = 0;
+    netdev->cache_valid |= VALID_IFINDEX;
+
+    VLOG_DBG("construct device %s, type: %u.", netdev_get_name(&netdev->up),
+             type);
+    return 0;
+}
+
+static int
+netdev_win_init_internal(struct netdev_win *netdev)
+{
+    int error = 0;
+
+    error = netdev_win_get_dp_mtu(0, &netdev->mtu);
+    if (error) {
+        netdev->mtu = 1500;
+    }
+    netdev->carrier = true;
+    netdev->ifindex = 0;
+    netdev->ifi_flags = IFF_UP | IFF_RUNNING | IFF_PROMISC;
+    netdev->current = NETDEV_F_1GB_FD;
+    netdev->advertised = NETDEV_F_1GB_FD;
+    netdev->supported = NETDEV_F_1GB_FD;
+
+    netdev->cache_valid = (VALID_IFINDEX | VALID_ETHERADDR |
+                           VALID_MTU | VALID_CARRIER |
+                           VALID_FEATURES | VALID_IFFLAG |
+                           VALID_DRVINFO);
+    return 0;
+
+}
+
+static int
+netdev_win_internal_construct(struct netdev *netdev_)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+
+    netdev->change_seq = 1;
+    netdev->carrier_reset = 0;
+    netdev->dev_type = OVSWIN_VPORT_TYPE_INTERNAL;
+    netdev->port_no = 0;
+
+    memset(netdev->mac, 0, ETH_ADDR_LEN);
+    netdev->cache_valid = VALID_ETHERADDR;
+
+    netdev_win_init_internal(netdev);
+
+    VLOG_DBG("Create device %s, type: INTERNAL.",
+             netdev_get_name(&netdev->up));
+    return 0;
+}
+
+
+static int
+netdev_win_refresh(struct netdev_win *netdev)
+{
+    const char *devname = netdev_get_name(&netdev->up);
+    POVS_VPORT_EXT_INFO ext_info;
+    bool oldCarrier;
+    int error = 0;
+
+    netdev->carrier = true;
+    netdev->cache_valid |= VALID_CARRIER | VALID_FEATURES;
+
+
+    error = dpif_windows_port_ext_info(0, devname, &netdev->ext_info);
+
+    if (error == 0) {
+        VLOG_WARN("Fail to get vport ext info: %s.", devname);
+        return GetLastError();
+    }
+
+    ext_info  = &netdev->ext_info;
+
+    netdev->mtu = ext_info->mtu;
+    netdev->cache_valid |= VALID_MTU;
+
+    /* IFF_UP reflects administrative state, IFF_RUNNING reflects current
+     * link state.
+     *
+     * dpif_win_link_get does an ioctl which is handled by OVS kernel module.
+     * This ioctl handler currently cannot distinguish between admin state
+     * and link state.
+     *
+     * If we return IFF_UP = 0 if interface is administratively up but link is
+     * down, netdev_get_carrier will not call get_carrier of netdev_class for
+     * interfaces that are administratively down, hence the switch will never
+     * detect link coming back up.
+     *
+     * Hence, for now, we always return IFF_UP = 1. If link is down because of
+     * the interface being administratively down, we return IFF_RUNNING = 0,
+     * but let the switch think that the interface is administratively up. This
+     * allows link state detection and corresponding change in forwarding
+     * logic to work properly for now.
+     *
+     * IFF_UP changes are handled in linux via netlink notifier, which we
+     * don't have on WIN. Updating IFF_UP based on admin state on WIN is to
+     * be figured out. */
+    netdev->ifi_flags = 0;
+
+    if (netdev->dev_type == OVSWIN_VPORT_TYPE_EXTERNAL) {
+        netdev->ifi_flags |= IFF_UP | IFF_RUNNING;
+        if (ext_info->status & OVS_EVENT_LINK_UP) {
+            netdev->ifi_flags |= IFF_RUNNING;
+        }
+        /* Promisc should be always set for uplink. */
+        netdev->ifi_flags |= IFF_PROMISC;
+    } else {
+        netdev->ifi_flags = IFF_UP;
+        if (ext_info->status & OVS_EVENT_LINK_UP) {
+            netdev->ifi_flags |= IFF_RUNNING;
+        }
+    }
+    netdev->cache_valid |= VALID_IFFLAG;
+
+    return 0;
+}
+
+static void
+netdev_win_destruct(struct netdev *netdev_)
+{
+    ovs_assert(is_netdev_win_class(netdev_get_class(netdev_)));
+}
+
+
+static void
+netdev_win_dealloc(struct netdev *netdev_)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+    free(netdev);
+}
+
+static int
+netdev_win_get_etheraddr(const struct netdev *netdev_,
+                         uint8_t mac[ETH_ADDR_LEN])
+{
+    struct netdev_win *netdev =
+             netdev_win_cast(netdev_);
+
+    if ((netdev->cache_valid & VALID_ETHERADDR) == 0) {
+        const char *devname = netdev_get_name(&netdev->up);
+        int error;
+        uint8_t macAddr[ETH_ADDR_LEN];
+        uint32_t type, portNo;
+        error = netdev_win_query_port(0, devname, &type, &portNo, macAddr);
+        if (error == 0) {
+            memcpy(netdev->mac, macAddr, ETH_ADDR_LEN);
+            netdev->cache_valid |= VALID_ETHERADDR;
+        }
+    }
+    if (netdev->cache_valid & VALID_ETHERADDR) {
+        memcpy(mac, netdev->mac, ETH_ADDR_LEN);
+    } else {
+        return EINVAL;
+    }
+    return 0;
+}
+
+static int
+netdev_win_get_mtu(const struct netdev *netdev_, int *mtup)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+    if ((netdev->cache_valid & VALID_MTU) == 0) {
+        netdev_win_refresh(netdev);
+    }
+    if (netdev->cache_valid & VALID_MTU) {
+        *mtup = netdev->mtu;
+    } else {
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+static int
+netdev_win_get_ifindex(const struct netdev *netdev_)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+    return netdev->ifindex;
+}
+
+static int
+netdev_win_get_carrier(const struct netdev *netdev_, bool *carrier)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+
+    if ((netdev->cache_valid & VALID_CARRIER) == 0) {
+        netdev_win_refresh(netdev);
+    }
+    if (netdev->cache_valid & VALID_CARRIER) {
+        *carrier = netdev->carrier;
+    } else {
+        return EINVAL;
+    }
+    return 0;
+}
+
+
+static long long int
+netdev_win_get_carrier_resets(const struct netdev *netdev_)
+{
+   struct netdev_win *netdev = netdev_win_cast(netdev_);
+   return netdev->carrier_reset;
+}
+
+static void
+netdev_win_stats_from_ovs_vport_stats(struct netdev_stats *dst,
+                                      const struct ovs_vport_stats *src)
+{
+    dst->rx_packets = src->rx_packets;
+    dst->tx_packets = src->tx_packets;
+    dst->rx_bytes = src->rx_bytes;
+    dst->tx_bytes = src->tx_bytes;
+    dst->rx_errors = src->rx_errors;
+    dst->tx_errors = src->tx_errors;
+    dst->rx_dropped = src->rx_dropped;
+    dst->tx_dropped = src->tx_dropped;
+    dst->multicast = 0;
+    dst->collisions = 0;
+    dst->rx_length_errors = 0;
+    dst->rx_over_errors = 0;
+    dst->rx_crc_errors = 0;
+    dst->rx_frame_errors = 0;
+    dst->rx_fifo_errors = 0;
+    dst->rx_missed_errors = 0;
+    dst->tx_aborted_errors = 0;
+    dst->tx_carrier_errors = 0;
+    dst->tx_fifo_errors = 0;
+    dst->tx_heartbeat_errors = 0;
+    dst->tx_window_errors = 0;
+}
+
+/* Retrieves current device stats for 'netdev'. */
+static int
+netdev_win_get_stats_system(const struct netdev *netdev_,
+                            struct netdev_stats *stats)
+{
+    struct dpif_windows_vport vport;
+    struct ovs_vport_stats vport_stats;
+    int error;
+
+    if (stats) {
+        vport.stats = &vport_stats;
+        error = dpif_windows_vport_get(netdev_get_name(netdev_), &vport);
+        if (error != 0) {
+            VLOG_WARN_RL(&netdev_win_rl, "Error %d in getting vport stats.",
+                         error);
+            return error;
+        }
+        netdev_win_stats_from_ovs_vport_stats(stats, &vport_stats);
+    } else {
+        VLOG_INFO_RL(&netdev_win_rl, "NULL netdev_stats, not populating.");
+    }
+    return 0;
+}
+
+static int
+netdev_win_get_stats_internal(const struct netdev *netdev_ OVS_UNUSED,
+                              struct netdev_stats *stats)
+{
+    memset(stats, 0, sizeof *stats);
+    return 0;
+}
+
+/* Stores the features supported by 'netdev' into each of '*current',
+ * '*advertised', '*supported', and '*peer' that are non-null.  Each value is a
+ * bitmap of "enum ofp_port_features" bits, in host byte order.  Returns 0 if
+ * successful, otherwise a positive errno value.  On failure, all of the
+ * passed-in values are set to 0. */
+static int
+netdev_win_get_features(const struct netdev *netdev_,
+                        enum netdev_features *current,
+                        enum netdev_features *advertised,
+                        enum netdev_features *supported,
+                        enum netdev_features *peer)
+{
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+
+    if (netdev->dev_type == OVSWIN_VPORT_TYPE_INTERNAL) {
+        return EOPNOTSUPP;
+    }
+
+    if ((netdev->cache_valid & VALID_FEATURES) == 0) {
+        netdev_win_refresh(netdev);
+    }
+
+    if (netdev->cache_valid & VALID_FEATURES) {
+        *current = netdev->current;
+        *advertised = netdev->advertised;
+        *supported = netdev->supported;
+        *peer = netdev->peer;
+    } else {
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+
+static int
+netdev_win_set_queue_system(struct netdev *netdev_,
+                            unsigned int queue_id OVS_UNUSED,
+                            const struct smap *details)
+{
+    struct dpif_windows_vport vport;
+    struct ovs_vport_stats vport_stats;
+    int error;
+
+    vport.stats = &vport_stats;
+    error = dpif_windows_vport_get(netdev_get_name(netdev_), &vport);
+    if (error == 0) {
+        dpif_windows_set_queue(vport.port_no, details);
+    }
+    return error;
+}
+
+
+static int
+netdev_win_get_status(const struct netdev *netdev_, struct smap *smap)
+{
+    int error = 0;
+    struct netdev_win *netdev = netdev_win_cast(netdev_);
+
+    switch (netdev->dev_type) {
+    case OVSWIN_VPORT_TYPE_EXTERNAL:
+        smap_add(smap, "driver_name", "openvswitch");
+        break;
+    case OVSWIN_VPORT_TYPE_SYNTHETIC:
+    case OVSWIN_VPORT_TYPE_EMULATED:
+    case OVSWIN_VPORT_TYPE_INTERNAL:
+        smap_add(smap, "driver_name", "openvswitch");
+        break;
+    default:
+        error = EOPNOTSUPP;
+    }
+
+    return error;
+}
+
+static int
+nd_to_iff_flags(enum netdev_flags nd)
+{
+    int iff = 0;
+    if (nd & NETDEV_UP) {
+        iff |= IFF_UP;
+    }
+    if (nd & NETDEV_PROMISC) {
+        iff |= IFF_PROMISC;
+    }
+    return iff;
+}
+
+static int
+iff_to_nd_flags(int iff)
+{
+    enum netdev_flags nd = 0;
+    if (iff & IFF_UP) {
+        nd |= NETDEV_UP;
+    }
+
+    if (iff & IFF_PROMISC) {
+        nd |= NETDEV_PROMISC;
+    }
+    return nd;
+}
+
+static int
+netdev_win_update_flags_system(struct netdev *netdev_,
+                               enum netdev_flags off,
+                               enum netdev_flags on,
+                               enum netdev_flags *old_flagsp)
+{
+    struct netdev_win *netdev;
+    int old_flags, new_flags;
+    int error = 0;
+
+    netdev = netdev_win_cast(netdev_);
+
+    old_flags = netdev->ifi_flags;
+    *old_flagsp = iff_to_nd_flags(old_flags);
+    new_flags = (old_flags & ~nd_to_iff_flags(off)) | nd_to_iff_flags(on);
+
+    /* Set netdev flags. */
+    if (new_flags != old_flags) {
+        const char *devname = netdev_get_name(&netdev->up);
+        error = netdev_win_set_flag(devname, new_flags);
+        if (error) {
+            VLOG_WARN_RL(&netdev_win_rl, "Fail to set flag for %s.", devname);
+        }
+    }
+    return error;
+}
+
+static int
+netdev_win_update_flags_internal(struct netdev *netdev_ OVS_UNUSED,
+                                 enum netdev_flags off OVS_UNUSED,
+                                 enum netdev_flags on OVS_UNUSED,
+                                 enum netdev_flags *old_flagsp)
+{
+   *old_flagsp = IFF_UP | IFF_RUNNING | IFF_PROMISC;
+   return 0;
+}
+
+void
+netdev_win_state_notify(char *name, uint16_t status)
+{
+   /* This is used to update netdev state when kernel notify any state change
+    * (mtu, mac, link status etc.) */
+    struct netdev_win *netdev;
+    const struct netdev *netdev_;
+
+    VLOG_INFO("Event notification: %s, status:%x.", name, status);
+    netdev_ = netdev_from_name(name);
+    if (netdev_ == NULL) {
+        return;
+    }
+    netdev = netdev_win_cast(netdev_);
+
+    /* Invalidate relevant cache before update changed seq.*/
+    netdev->cache_valid &= ~(VALID_CARRIER | VALID_FEATURES | VALID_MTU |
+                                 VALID_IFFLAG);
+    netdev_win_changed(netdev);
+}
+
+static void
+netdev_win_changed(struct netdev_win *dev)
+{
+    dev->change_seq++;
+    if (!dev->change_seq) {
+        dev->change_seq++;
+    }
+}
+
+
+static int
+netdev_win_get_dp_mtu(uint32_t dpNo, uint32_t *mtu)
+{
+   uint32_t dp_no = OVS_DP_NUMBER;
+   int error;
+
+   *mtu = 1500;
+   return 0;
+}
+
+
+static int
+netdev_win_set_flag(const char *name, uint32_t flags)
+{
+    return 0;
+}
+
+int
+netdev_win_query_port(uint32_t dpNo,
+                      const char *name,
+                      uint32_t *type,
+                      uint32_t *portNo,
+                      uint8_t *macAddr)
+{
+    OVS_VPORT_INFO info;
+    OVS_VPORT_GET get;
+    int ret;
+
+    memset(&get, 0, sizeof get);
+
+    get.dpNo = OVS_DP_NUMBER;
+    get.portNo = 0;
+
+    if (strnlen(name, sizeof get.name) >= sizeof get.name) {
+        return ENODEV;
+    }
+    ovs_strlcpy(get.name, name, OVSWIN_DEVICE_NAME_MAX_LENGTH);
+    ret = dpif_windows_ioctl(OVS_IOCTL_VPORT_GET, &get,
+                               sizeof get, &info, sizeof info);
+    if (ret < 0) {
+        return -ret == ENOENT ? ENODEV : -ret;
+    }
+    *type = info.type;
+    *portNo = info.portNo;
+    memcpy(macAddr, info.macAddress, ETH_ADDR_LEN);
+    return 0;
+}
+
+#define NETDEV_WIN_CLASS(NAME, CONSTRUCT, GET_STATS, SET_QUEUE,    \
+                           UPDATE_FLAG)                         \
+{                                                               \
+    NAME,                                                       \
+                                                                \
+    netdev_win_init,         /* init */                         \
+    netdev_win_run,          /* run */                          \
+    netdev_win_wait,         /* wait */                         \
+    netdev_win_alloc,                                           \
+    CONSTRUCT,                                                  \
+    netdev_win_destruct,                                        \
+    netdev_win_dealloc,                                         \
+    NULL,                   /* get_config */                    \
+    NULL,                   /* set_config */                    \
+    NULL,                   /* get_tunnel_config */             \
+    NULL,                   /* send */                          \
+    NULL,                   /* send_wait */                     \
+    NULL,                   /* set_etheraddr */                 \
+    netdev_win_get_etheraddr,                                   \
+    netdev_win_get_mtu,                                         \
+    NULL,                   /* set_mtu */                       \
+    netdev_win_get_ifindex,                                     \
+    netdev_win_get_carrier,                                     \
+    netdev_win_get_carrier_resets,                              \
+    NULL,                   /* set_miimon_interval */           \
+    GET_STATS,                                                  \
+    NULL,                   /* set_stats */                     \
+    netdev_win_get_features,                                    \
+    NULL,                   /* set_advertisements */            \
+    NULL,                   /* set_policing */                  \
+    NULL,                   /* get_qos_types */                 \
+    NULL,                   /* get_qos_capabilities */          \
+    NULL,                   /* get_qos */                       \
+    NULL,                   /* set_qos */                       \
+    NULL,                   /* get_queue */                     \
+    SET_QUEUE,                                                  \
+    NULL,                   /* delete_queue */                  \
+    NULL,                   /* get_queue_stats */               \
+    NULL,                   /* queue_dump_start */              \
+    NULL,                   /* queue_dump_next */               \
+    NULL,                   /* queue_dump_done */               \
+    NULL,                   /* dump_queue_stats */              \
+    NULL,                   /* get_in4 */                       \
+    NULL,                   /* set_in4 */                       \
+    NULL,                   /* get_in6 */                       \
+    NULL,                   /* add_router */                    \
+    NULL,                   /* get_next_hop */                  \
+    netdev_win_get_status,                                      \
+    NULL,                   /* arp_lookup */                    \
+    UPDATE_FLAG,                                                \
+    NULL,                   /* rx_alloc */                      \
+    NULL,                   /* rx_construct */                  \
+    NULL,                   /* rx_destruct */                   \
+    NULL,                   /* rx_dealloc */                    \
+    NULL,                   /* rx_recv */                       \
+    NULL,                   /* rx_wait */                       \
+    NULL,                   /* rx_drain */                      \
+}
+
+const struct netdev_class netdev_win_class =
+    NETDEV_WIN_CLASS(
+        "system",
+        netdev_win_system_construct,
+        netdev_win_get_stats_system,
+        netdev_win_set_queue_system,
+        netdev_win_update_flags_system);
+
+const struct netdev_class netdev_internal_class =
+    NETDEV_WIN_CLASS(
+        "internal",
+        netdev_win_internal_construct,
+        netdev_win_get_stats_internal,
+        NULL,
+        netdev_win_update_flags_internal);
diff --git a/lib/netdev.c b/lib/netdev.c
index 25edc16..2185022 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -135,6 +135,11 @@ netdev_initialize(void)
         netdev_register_provider(&netdev_tap_class);
         netdev_register_provider(&netdev_bsd_class);
 #endif
+#ifdef _WIN32
+        netdev_register_provider(&netdev_win_class);
+        netdev_register_provider(&netdev_internal_class);
+        netdev_vport_tunnel_register();
+#endif
         netdev_dpdk_register();
 
         ovsthread_once_done(&once);
diff --git a/lib/netlink-protocol.h b/lib/netlink-protocol.h
index 3009fc5..db2761d 100644
--- a/lib/netlink-protocol.h
+++ b/lib/netlink-protocol.h
@@ -29,9 +29,11 @@
  * on other platforms it directly defines the structures and macros itself.
  */
 
+#ifndef OVS_WIN_DP
 #include <stdint.h>
 #include <sys/socket.h>
 #include "util.h"
+#endif
 
 #ifdef HAVE_NETLINK
 #include <linux/netlink.h>
@@ -40,6 +42,8 @@
 #else
 #define NETLINK_GENERIC         16
 
+#ifndef OVS_WIN_DP
+/* Has been deleted upstream, will go away once we rebase. */
 struct sockaddr_nl {
     sa_family_t nl_family;
     unsigned short int nl_pad;
@@ -47,6 +51,7 @@ struct sockaddr_nl {
     uint32_t nl_groups;
 };
 BUILD_ASSERT_DECL(sizeof(struct sockaddr_nl) == 12);
+#endif
 
 /* nlmsg_flags bits. */
 #define NLM_F_REQUEST           0x001
diff --git a/lib/util.c b/lib/util.c
index 01ba6bc..e96dbe5 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -1817,4 +1817,20 @@ OVS_CONSTRUCTOR(winsock_start) {
         VLOG_FATAL("WSAStartup failed: %s", sock_strerror(sock_errno()));
    }
 }
+
+/* Converts the Windows error number to the POSIX errno. */
+int
+win_error_to_errno(DWORD win_errno)
+{
+    switch (win_errno) {
+    case ERROR_DEV_NOT_EXIST:
+        return ENOENT;
+    case ERROR_NOT_SUPPORTED:
+        return EOPNOTSUPP;
+    default:
+        break;
+    }
+    return EINVAL;
+}
+
 #endif
diff --git a/lib/util.h b/lib/util.h
index b626c0b..0c640af 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -509,6 +509,7 @@ void xsleep(unsigned int seconds);
 char *ovs_format_message(int error);
 char *ovs_lasterror_to_string(void);
 int ftruncate(int fd, off_t length);
+int win_error_to_errno(DWORD win_errno);
 #endif
 
 #ifdef  __cplusplus
-- 
1.7.9.5




More information about the dev mailing list