[ovs-dev] [PATCH v2] Windows: Add support for handling protocol (netlink family)

Sairam Venugopal vsairam at vmware.com
Mon Jul 11 18:35:31 UTC 2016


Windows datapath currently has no notion of netlink family.
It assumes all netlink messages to belong to NETLINK_GENERIC family.
This patch adds support for handling other protocols if the userspace sends it down to kernel.

This patch introduces a new NETLINK_CMD - OVS_CTRL_CMD_SOCK_PROP to manage
all properties associated with a socket. The properties are passed down as
netlink message attributes. This makes it easier to introduce other
properties in the future.

Signed-off-by: Sairam Venugopal <vsairam at vmware.com>
Acked-by: Nithin Raju <nithin at vmware.com>
---
 datapath-windows/include/OvsDpInterfaceExt.h |  17 ++++-
 datapath-windows/ovsext/Datapath.c           | 104 ++++++++++++++++++++++++++-
 datapath-windows/ovsext/Datapath.h           |   1 +
 lib/netlink-socket.c                         |  75 +++++++++++++++++++
 4 files changed, 194 insertions(+), 3 deletions(-)

diff --git a/datapath-windows/include/OvsDpInterfaceExt.h b/datapath-windows/include/OvsDpInterfaceExt.h
index 8850535..db91c3e 100644
--- a/datapath-windows/include/OvsDpInterfaceExt.h
+++ b/datapath-windows/include/OvsDpInterfaceExt.h
@@ -92,9 +92,12 @@ enum ovs_win_control_cmd {
     OVS_CTRL_CMD_MC_SUBSCRIBE_REQ,
     OVS_CTRL_CMD_PACKET_SUBSCRIBE_REQ,
 
-    /* This command is logically belong to the Vport family */
+    /* This command logically belongs to the Vport family */
     OVS_CTRL_CMD_EVENT_NOTIFY,
-    OVS_CTRL_CMD_READ_NOTIFY
+    OVS_CTRL_CMD_READ_NOTIFY,
+
+    /* Used for Socket property */
+    OVS_CTRL_CMD_SOCK_PROP
 };
 
 /* NL Attributes for joining/unjoining an MC group */
@@ -163,4 +166,14 @@ enum ovs_win_netdev_attr {
 typedef struct ovs_dp_stats OVS_DP_STATS;
 typedef enum ovs_vport_type OVS_VPORT_TYPE;
 
+/* NL Attributes for setting socket attributes */
+enum ovs_nl_sock_attr {
+    /* (UINT32) Netlink Protocol set in Userspace and read in Kernel */
+    OVS_NL_ATTR_SOCK_PROTO,
+    /* (UINT32) Instance PID set in Kernel and read in Userspace */
+    OVS_NL_ATTR_SOCK_PID,
+    __OVS_NL_ATTR_SOCK_MAX
+};
+#define OVS_WIN_SOCK_ATTR_MAX (__OVS_NL_ATTR_SOCK_MAX - 1)
+
 #endif /* __OVS_DP_INTERFACE_EXT_H_ */
diff --git a/datapath-windows/ovsext/Datapath.c b/datapath-windows/ovsext/Datapath.c
index 16d58ef..4f47be5 100644
--- a/datapath-windows/ovsext/Datapath.c
+++ b/datapath-windows/ovsext/Datapath.c
@@ -87,7 +87,8 @@ static NetlinkCmdHandler OvsPendEventCmdHandler,
                          OvsReadEventCmdHandler,
                          OvsNewDpCmdHandler,
                          OvsGetDpCmdHandler,
-                         OvsSetDpCmdHandler;
+                         OvsSetDpCmdHandler,
+                         OvsSockPropCmdHandler;
 
 NetlinkCmdHandler        OvsGetNetdevCmdHandler,
                          OvsGetVportCmdHandler,
@@ -147,6 +148,11 @@ NETLINK_CMD nlControlFamilyCmdOps[] = {
       .handler = OvsReadPacketCmdHandler,
       .supportedDevOp = OVS_READ_DEV_OP,
       .validateDpIndex = FALSE,
+    },
+    { .cmd = OVS_CTRL_CMD_SOCK_PROP,
+      .handler = OvsSockPropCmdHandler,
+      .supportedDevOp = OVS_TRANSACTION_DEV_OP,
+      .validateDpIndex = FALSE,
     }
 };
 
@@ -1685,3 +1691,99 @@ OvsReadEventCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
 cleanup:
     return status;
 }
+
+/*
+ * --------------------------------------------------------------------------
+ *  Command Handler for 'OVS_CTRL_CMD_SOCK_PROP'.
+ *
+ *  Handler to set and verify socket properties between userspace and kernel.
+ *
+ *  Protocol is passed down by the userspace. It refers to the NETLINK family
+ *  and could be of different types (NETLINK_GENERIC/NETLINK_NETFILTER etc.,)
+ *  This function parses out the protocol and adds it to the open instance.
+ *
+ *  PID is generated by the kernel and is set in userspace after querying the
+ *  kernel for it. This function does not modify PID set in the kernel,
+ *  instead it verifies if it was sent down correctly.
+ *
+ *  XXX -This method can be modified to handle all Socket properties thereby
+ *  eliminating the use of OVS_IOCTL_GET_PID
+ *
+ * --------------------------------------------------------------------------
+ */
+static NTSTATUS
+OvsSockPropCmdHandler(POVS_USER_PARAMS_CONTEXT usrParamsCtx,
+                      UINT32 *replyLen)
+{
+    static const NL_POLICY ovsSocketPolicy[] = {
+        [OVS_NL_ATTR_SOCK_PROTO] = { .type = NL_A_U32, .optional = TRUE },
+        [OVS_NL_ATTR_SOCK_PID] = { .type = NL_A_U32, .optional = TRUE }
+    };
+    PNL_ATTR attrs[ARRAY_SIZE(ovsSocketPolicy)];
+
+    if (usrParamsCtx->outputLength < sizeof(OVS_MESSAGE)) {
+        return STATUS_NDIS_INVALID_LENGTH;
+    }
+
+    NL_BUFFER nlBuf;
+    POVS_MESSAGE msgIn = (POVS_MESSAGE)usrParamsCtx->inputBuffer;
+    POVS_MESSAGE msgOut = (POVS_MESSAGE)usrParamsCtx->outputBuffer;
+    POVS_OPEN_INSTANCE instance = (POVS_OPEN_INSTANCE)usrParamsCtx->ovsInstance;
+    UINT32 protocol;
+    PNL_MSG_HDR nlMsg;
+    UINT32 pid;
+
+    /* Parse the input */
+    if (!NlAttrParse((PNL_MSG_HDR)msgIn,
+                     NLMSG_HDRLEN + GENL_HDRLEN + OVS_HDRLEN,
+                     NlMsgAttrsLen((PNL_MSG_HDR)msgIn),
+                     ovsSocketPolicy,
+                     ARRAY_SIZE(ovsSocketPolicy),
+                     attrs,
+                     ARRAY_SIZE(attrs))) {
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Set the Protocol if it was passed down */
+    if (attrs[OVS_NL_ATTR_SOCK_PROTO]) {
+        protocol = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PROTO]);
+        if (protocol) {
+            instance->protocol = protocol;
+        }
+    }
+
+    /* Verify if the PID sent down matches the kernel */
+    if (attrs[OVS_NL_ATTR_SOCK_PID]) {
+        pid = NlAttrGetU32(attrs[OVS_NL_ATTR_SOCK_PID]);
+        if (pid != instance->pid) {
+            OVS_LOG_ERROR("Received invalid pid:%d expected:%d",
+                          pid, instance->pid);
+            return STATUS_INVALID_PARAMETER;
+        }
+    }
+
+    /* Prepare the output */
+    NlBufInit(&nlBuf, usrParamsCtx->outputBuffer, usrParamsCtx->outputLength);
+    if(!NlFillOvsMsg(&nlBuf, msgIn->nlMsg.nlmsgType, NLM_F_MULTI,
+                      msgIn->nlMsg.nlmsgSeq, msgIn->nlMsg.nlmsgPid,
+                      msgIn->genlMsg.cmd, msgIn->genlMsg.version,
+                      gOvsSwitchContext->dpNo)){
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PID,
+                         instance->pid)) {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    if (!NlMsgPutTailU32(&nlBuf, OVS_NL_ATTR_SOCK_PROTO,
+                         instance->protocol)) {
+        return STATUS_INVALID_BUFFER_SIZE;
+    }
+
+    nlMsg = (PNL_MSG_HDR)NlBufAt(&nlBuf, 0, 0);
+    nlMsg->nlmsgLen = NlBufSize(&nlBuf);
+    *replyLen = msgOut->nlMsg.nlmsgLen;
+
+    return STATUS_SUCCESS;
+}
diff --git a/datapath-windows/ovsext/Datapath.h b/datapath-windows/ovsext/Datapath.h
index 09e233f..2b41d82 100644
--- a/datapath-windows/ovsext/Datapath.h
+++ b/datapath-windows/ovsext/Datapath.h
@@ -51,6 +51,7 @@ typedef struct _OVS_OPEN_INSTANCE {
     PVOID eventQueue;
     POVS_USER_PACKET_QUEUE packetQueue;
     UINT32 pid;
+    UINT32 protocol; /* Refers to NETLINK Family (eg. NETLINK_GENERIC)*/
 
     struct {
         POVS_MESSAGE ovsMsg;    /* OVS message passed during dump start. */
diff --git a/lib/netlink-socket.c b/lib/netlink-socket.c
index 32b0cc3..26d909b 100644
--- a/lib/netlink-socket.c
+++ b/lib/netlink-socket.c
@@ -59,6 +59,7 @@ static void log_nlmsg(const char *function, int error,
                       const void *message, size_t size, int protocol);
 #ifdef _WIN32
 static int get_sock_pid_from_kernel(struct nl_sock *sock);
+static int set_sock_property(struct nl_sock *sock);
 #endif
 
 /* Netlink sockets. */
@@ -165,6 +166,10 @@ nl_sock_create(int protocol, struct nl_sock **sockp)
     if (retval != 0) {
         goto error;
     }
+    retval = set_sock_property(sock);
+    if (retval != 0) {
+        goto error;
+    }
 #else
     if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUFFORCE,
                    &rcvbuf, sizeof rcvbuf)) {
@@ -284,6 +289,76 @@ get_sock_pid_from_kernel(struct nl_sock *sock)
 
     return retval;
 }
+
+/* Used for setting and managing socket properties in userspace and kernel.
+ * Currently two attributes are tracked - pid and protocol
+ * protocol - supplied by userspace based on the netlink family. Windows uses
+ *            this property to set the value in kernel datapath.
+ *            eg: (NETLINK_GENERIC/ NETLINK_NETFILTER)
+ * pid -      generated by windows kernel and set in userspace. The property
+ *            is not modified.
+ * Also verify if Protocol and PID in Kernel reflects the values in userspace
+ * */
+static int
+set_sock_property(struct nl_sock *sock)
+{
+    static const struct nl_policy ovs_socket_policy[] = {
+        [OVS_NL_ATTR_SOCK_PROTO] = { .type = NL_A_BE32, .optional = true },
+        [OVS_NL_ATTR_SOCK_PID] = { .type = NL_A_BE32, .optional = true }
+    };
+
+    struct ofpbuf request, *reply;
+    struct ovs_header *ovs_header;
+    struct nlattr *attrs[ARRAY_SIZE(ovs_socket_policy)];
+    int retval = 0;
+    int error;
+
+    ofpbuf_init(&request, 0);
+    nl_msg_put_genlmsghdr(&request, 0, OVS_WIN_NL_CTRL_FAMILY_ID, 0,
+                          OVS_CTRL_CMD_SOCK_PROP, OVS_WIN_CONTROL_VERSION);
+    ovs_header = ofpbuf_put_uninit(&request, sizeof *ovs_header);
+    ovs_header->dp_ifindex = 0;
+
+    nl_msg_put_be32(&request, OVS_NL_ATTR_SOCK_PROTO, sock->protocol);
+    /* pid is already set as part of get_sock_pid_from_kernel()
+     * This is added to maintain consistency
+     */
+    nl_msg_put_be32(&request, OVS_NL_ATTR_SOCK_PID, sock->pid);
+
+    error = nl_sock_transact(sock, &request, &reply);
+    ofpbuf_uninit(&request);
+    if (error) {
+        retval = EINVAL;
+    }
+
+    if (!nl_policy_parse(reply,
+                         NLMSG_HDRLEN + GENL_HDRLEN + sizeof *ovs_header,
+                         ovs_socket_policy, attrs,
+                         ARRAY_SIZE(ovs_socket_policy))) {
+        ofpbuf_delete(reply);
+        retval = EINVAL;
+    }
+    /* Verify if the properties are setup properly */
+    if (attrs[OVS_NL_ATTR_SOCK_PROTO]) {
+        int protocol = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PROTO]);
+        if (protocol != sock->protocol) {
+            VLOG_ERR("Invalid protocol returned:%d expected:%d",
+                     protocol, sock->protocol);
+            retval = EINVAL;
+        }
+    }
+
+    if (attrs[OVS_NL_ATTR_SOCK_PID]) {
+        int pid = nl_attr_get_be32(attrs[OVS_NL_ATTR_SOCK_PID]);
+        if (pid != sock->pid) {
+            VLOG_ERR("Invalid pid returned:%d expected:%d",
+                     pid, sock->pid);
+            retval = EINVAL;
+        }
+    }
+
+    return retval;
+}
 #endif  /* _WIN32 */
 
 #ifdef _WIN32
-- 
2.9.0.windows.1




More information about the dev mailing list